<commit_before>#!/usr/bin/env python2
# Copyright 2016 The Fontbakery Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

def pretty_print_list(values):
  if len(values) == 1:
    return str(values[0])
  else:
    return "{} or {}".format(", ".join(map(str, values[:-1])),
                             str(values[-1]))

def get_bounding_box(font):
    """ Returns max and min bbox of given truetype font """
    ymin = 0
    ymax = 0
    if font.sfntVersion == 'OTTO':
        ymin = font['head'].yMin
        ymax = font['head'].yMax
    else:
        for g in font['glyf'].glyphs:
            char = font['glyf'][g]
            if hasattr(char, 'yMin') and ymin > char.yMin:
                ymin = char.yMin
            if hasattr(char, 'yMax') and ymax < char.yMax:
                ymax = char.yMax
    return ymin, ymax

def get_name_entries(font,
                     nameID,
                     platformID=None,
                     encodingID=None,
                     langID=None):
  results = []
  for entry in font['name'].names:
    if entry.nameID == nameID and \
       (platformID is None or entry.platformID == platformID) and \
       (encodingID is None or entry.platEncID == encodingID) and \
       (langID is None or entry.langID == langID):
      results.append(entry)
  return results

def get_name_entry_strings(font,
                           nameID,
                           platformID=None,
                           encodingID=None,
                           langID=None):
  entries = get_name_entries(font, nameID, platformID, encodingID, langID)
  return list(map(lambda e: e.string.decode(e.getEncoding()), entries))

def name_entry_id(name):
  from fontbakery.constants import (NAMEID_STR,
                                    PLATID_STR)
  return "[{}({}):{}({})]".format(NAMEID_STR[name.nameID],
                                  name.nameID,
                                  PLATID_STR[name.platformID],
                                  name.platformID)

def getGlyph(font, uchar):
    from fontbakery.constants import (PLATFORM_ID__WINDOWS,
                                      PLAT_ENC_ID__UCS2,
                                      PLAT_ENC_ID__UCS4)
    for table in font['cmap'].tables:
        if table.platformID == PLATFORM_ID__WINDOWS and\
           table.platEncID in [PLAT_ENC_ID__UCS2,
                               PLAT_ENC_ID__UCS4]:
          if uchar in table.cmap:
              return table.cmap[uchar]

def glyph_contour_count(font, name):
    """Contour count for specified glyph.
    This implementation will also return contour count for
    composite glyphs.
    """
    contour_count = 0
    items = [font['glyf'][name]]

    while items:
        g = items.pop(0)
        if g.isComposite():
            for comp in g.components:
                items.append(font['glyf'][comp.glyphName])
        if g.numberOfContours != -1:
            contour_count += g.numberOfContours
    return contour_count

def get_font_glyph_data(font):
    """Return information for each glyph in a font"""
    from fontbakery.constants import (PLATFORM_ID__WINDOWS,
                                      PLAT_ENC_ID__UCS2)
    font_data = []

    try:
        subtable = font['cmap'].getcmap(PLATFORM_ID__WINDOWS,
                                        PLAT_ENC_ID__UCS2)
        if not subtable:
          # Well... Give it a chance here...
          # It may be using a different Encoding_ID value
          subtable = font['cmap'].tables[0]

        cmap = subtable.cmap
    except:
        return None

    cmap_reversed = dict(zip(cmap.values(), cmap.keys()))

    for glyph_name in font.getGlyphSet().keys():
        if glyph_name in cmap_reversed:
            uni_glyph = cmap_reversed[glyph_name]
            contours = glyph_contour_count(font, glyph_name)
            font_data.append({
                'unicode': uni_glyph,
                'name': glyph_name,
                'contours': set([contours])
            })
    return font_data

def get_FamilyProto_Message(path):
  from fontbakery.fonts_public_pb2 import FamilyProto
  from google.protobuf import text_format
  message = FamilyProto()
  text_data = open(path, "rb").read()
  text_format.Merge(text_data, message)
  return message

def check_bit_entry(ttFont, table, attr, expected, bitmask, bitname):
  from fontbakery.checkrunner import (PASS, FAIL)
  value = getattr(ttFont[table], attr)
  name_str = "{} {} {} bit".format(table, attr, bitname)
  if bool(value & bitmask) == expected:
    return PASS, "{} is properly set.".format(name_str)
  else:
    if expected:
      expected_str = "set"
    else:
      expected_str = "reset"
    return FAIL, "{} should be {}.".format(name_str, expected_str)

def download_file(url):
  from StringIO import StringIO
  from urllib import urlopen
  request = urlopen(url)
  return StringIO(request.read())
<commit_msg>utils.py: import StringIO from io in Python 3<commit_after>#!/usr/bin/env python2
# Copyright 2016 The Fontbakery Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

def pretty_print_list(values):
  if len(values) == 1:
    return str(values[0])
  else:
    return "{} or {}".format(", ".join(map(str, values[:-1])),
                             str(values[-1]))

def get_bounding_box(font):
    """ Returns max and min bbox of given truetype font """
    ymin = 0
    ymax = 0
    if font.sfntVersion == 'OTTO':
        ymin = font['head'].yMin
        ymax = font['head'].yMax
    else:
        for g in font['glyf'].glyphs:
            char = font['glyf'][g]
            if hasattr(char, 'yMin') and ymin > char.yMin:
                ymin = char.yMin
            if hasattr(char, 'yMax') and ymax < char.yMax:
                ymax = char.yMax
    return ymin, ymax

def get_name_entries(font,
                     nameID,
                     platformID=None,
                     encodingID=None,
                     langID=None):
  results = []
  for entry in font['name'].names:
    if entry.nameID == nameID and \
       (platformID is None or entry.platformID == platformID) and \
       (encodingID is None or entry.platEncID == encodingID) and \
       (langID is None or entry.langID == langID):
      results.append(entry)
  return results

def get_name_entry_strings(font,
                           nameID,
                           platformID=None,
                           encodingID=None,
                           langID=None):
  entries = get_name_entries(font, nameID, platformID, encodingID, langID)
  return list(map(lambda e: e.string.decode(e.getEncoding()), entries))

def name_entry_id(name):
  from fontbakery.constants import (NAMEID_STR,
                                    PLATID_STR)
  return "[{}({}):{}({})]".format(NAMEID_STR[name.nameID],
                                  name.nameID,
                                  PLATID_STR[name.platformID],
                                  name.platformID)

def getGlyph(font, uchar):
    from fontbakery.constants import (PLATFORM_ID__WINDOWS,
                                      PLAT_ENC_ID__UCS2,
                                      PLAT_ENC_ID__UCS4)
    for table in font['cmap'].tables:
        if table.platformID == PLATFORM_ID__WINDOWS and\
           table.platEncID in [PLAT_ENC_ID__UCS2,
                               PLAT_ENC_ID__UCS4]:
          if uchar in table.cmap:
              return table.cmap[uchar]

def glyph_contour_count(font, name):
    """Contour count for specified glyph.
    This implementation will also return contour count for
    composite glyphs.
    """
    contour_count = 0
    items = [font['glyf'][name]]

    while items:
        g = items.pop(0)
        if g.isComposite():
            for comp in g.components:
                items.append(font['glyf'][comp.glyphName])
        if g.numberOfContours != -1:
            contour_count += g.numberOfContours
    return contour_count

def get_font_glyph_data(font):
    """Return information for each glyph in a font"""
    from fontbakery.constants import (PLATFORM_ID__WINDOWS,
                                      PLAT_ENC_ID__UCS2)
    font_data = []

    try:
        subtable = font['cmap'].getcmap(PLATFORM_ID__WINDOWS,
                                        PLAT_ENC_ID__UCS2)
        if not subtable:
          # Well... Give it a chance here...
          # It may be using a different Encoding_ID value
          subtable = font['cmap'].tables[0]

        cmap = subtable.cmap
    except:
        return None

    cmap_reversed = dict(zip(cmap.values(), cmap.keys()))

    for glyph_name in font.getGlyphSet().keys():
        if glyph_name in cmap_reversed:
            uni_glyph = cmap_reversed[glyph_name]
            contours = glyph_contour_count(font, glyph_name)
            font_data.append({
                'unicode': uni_glyph,
                'name': glyph_name,
                'contours': set([contours])
            })
    return font_data

def get_FamilyProto_Message(path):
  from fontbakery.fonts_public_pb2 import FamilyProto
  from google.protobuf import text_format
  message = FamilyProto()
  text_data = open(path, "rb").read()
  text_format.Merge(text_data, message)
  return message

def check_bit_entry(ttFont, table, attr, expected, bitmask, bitname):
  from fontbakery.checkrunner import (PASS, FAIL)
  value = getattr(ttFont[table], attr)
  name_str = "{} {} {} bit".format(table, attr, bitname)
  if bool(value & bitmask) == expected:
    return PASS, "{} is properly set.".format(name_str)
  else:
    if expected:
      expected_str = "set"
    else:
      expected_str = "reset"
    return FAIL, "{} should be {}.".format(name_str, expected_str)

def download_file(url):
  try:
    from StringIO import StringIO
  except ImportError:  # Python 3 uses the io module instead.
    from io import StringIO
  from urllib import urlopen
  request = urlopen(url)
  return StringIO(request.read())
<|endoftext|>


<commit_before>import bpy
from array import array
from struct import pack

def process_mesh(original, triangulated):
    import bmesh
    bm = bmesh.new()
    bm.from_mesh(original)
    bmesh.ops.triangulate(bm, faces = bm.faces)
    bm.to_mesh(triangulated)
    bm.free()

def write(context, filepath, options):

    scene = context.scene
    obj = context.active_object

    if obj.type != 'MESH': return False

    # Create a new mesh we can edit
    mesh_data = bpy.data.meshes.new(obj.data.name)

    # Triangulate mesh copy
    process_mesh(obj.data, mesh_data)

    # Get vertex color and texture coordinate layer counts
    vert_color_count = len(mesh_data.vertex_colors)
    tex_coord_count = len(mesh_data.uv_layers)

    # Decide which vertex data components to save
    save_normal = options['save_normal']
    save_vert_color = options['save_vert_color'] and vert_color_count > 0
    save_tex_coord = options['save_tex_coord'] and tex_coord_count > 0

    # Vertex data components
    vert_position_comp = 1 << 0 # 1 position
    vert_normal_comp = 1 << 1 # [0,1] normals
    vert_color_comp = 1 << 2 # [0,1] colors
    vert_texcoord_comp = 1 << 3 # [0,1] texture coords

    # Combine vertex data components to one integer
    vert_comps = vert_position_comp
    if save_normal: vert_comps = vert_comps | vert_normal_comp
    if save_vert_color: vert_comps = vert_comps | vert_color_comp
    if save_tex_coord: vert_comps = vert_comps | vert_texcoord_comp

    vert_count = len(mesh_data.vertices)

    #epsilon = 1 / (2 ** 20)

    vert_col_data = array('f')

    if save_vert_color:
        # Create an empty array of required size
        for i in range(0, vert_count * 3):
            vert_col_data.append(0.0)

        # Shorter name for vertex color data
        mesh_vert_col = mesh_data.vertex_colors.active

        # Get the vertex color for each corner of each polygon
        # Write colors to the corresponding vertex index in the array
        for i in range(0, len(mesh_data.loops)):
            v_index = mesh_data.loops[i].vertex_index
            v_color = mesh_vert_col.data[i].color
            vert_col_data[v_index * 3 + 0] = v_color[0]
            vert_col_data[v_index * 3 + 1] = v_color[1]
            vert_col_data[v_index * 3 + 2] = v_color[2]

    # Shorter name for mesh vertices
    verts = mesh_data.vertices

    # 'f' for 4-byte floating point
    vertex_data = array('f')

    # Put vertex data in the array

    # Just vertex position
    if vert_comps == vert_position_comp:
        for v in verts:
            vertex_data.extend([v.co.x, v.co.y, v.co.z])

    # Vertex position and normal
    elif vert_comps == (vert_position_comp | vert_normal_comp):
        for v in verts:
            vertex_data.extend([v.co.x, v.co.y, v.co.z])
            vertex_data.extend([v.normal.x, v.normal.y, v.normal.z])

    # Vertex position and color
    elif vert_comps == (vert_position_comp | vert_color_comp):
        for i in range(0, vert_count):
            vertex_data.append(verts[i].co.x)
            vertex_data.append(verts[i].co.y)
            vertex_data.append(verts[i].co.z)
            vertex_data.append(vert_col_data[i * 3 + 0])
            vertex_data.append(vert_col_data[i * 3 + 1])
            vertex_data.append(vert_col_data[i * 3 + 2])

    # Vertex position, normal and color
    elif vert_comps == (vert_position_comp | vert_normal_comp | vert_color_comp):
        for i in range(0, vert_count):
            vertex_data.append(verts[i].co.x)
            vertex_data.append(verts[i].co.y)
            vertex_data.append(verts[i].co.z)
            vertex_data.append(verts[i].normal.x)
            vertex_data.append(verts[i].normal.y)
            vertex_data.append(verts[i].normal.z)
            vertex_data.append(vert_col_data[i * 3 + 0])
            vertex_data.append(vert_col_data[i * 3 + 1])
            vertex_data.append(vert_col_data[i * 3 + 2])

    # 'H': unsigned 2-byte int, 'I': unsigned 4-byte int
    if vert_count <= (1 << 16):
        index_data = array('H')
    else:
        index_data = array('I')

    # Get index data
    for p in mesh_data.polygons:
        index_data.extend([p.vertices[0], p.vertices[1], p.vertices[2]])

    # Prepare data for the header
    index_count = len(index_data)

    # '=': native byte-order, standard packing
    # 'I': unsigned 4-byte integer
    header = pack('=III', vert_comps, vert_count, index_count)

    # Remove the mesh we created earlier
    bpy.data.meshes.remove(mesh_data)

    # Open output file
    with open(filepath, 'wb') as outfile:

        # Start with file type magic number
        outfile.write(b'\x10\x10\x19\x91');

        # Write header data
        outfile.write(header)

        # Write vertex data
        vertex_data.tofile(outfile)

        # Write index data
        index_data.tofile(outfile)

    return True
<commit_msg>Transform mesh from Blender to OpenGL coordinate system<commit_after>import bpy
from array import array
from struct import pack

def process_mesh(original, triangulated):
    import bmesh
    bm = bmesh.new()
    bm.from_mesh(original)
    bmesh.ops.triangulate(bm, faces = bm.faces)
    bm.to_mesh(triangulated)
    bm.free()

def write(context, filepath, options):

    scene = context.scene
    obj = context.active_object

    if obj.type != 'MESH': return False

    # Create a new mesh we can edit
    mesh_data = bpy.data.meshes.new(obj.data.name)

    # Triangulate mesh copy
    process_mesh(obj.data, mesh_data)

    # Get vertex color and texture coordinate layer counts
    vert_color_count = len(mesh_data.vertex_colors)
    tex_coord_count = len(mesh_data.uv_layers)

    # Decide which vertex data components to save
    save_normal = options['save_normal']
    save_vert_color = options['save_vert_color'] and vert_color_count > 0
    save_tex_coord = options['save_tex_coord'] and tex_coord_count > 0

    # Vertex data components
    vert_position_comp = 1 << 0 # 1 position
    vert_normal_comp = 1 << 1 # [0,1] normals
    vert_color_comp = 1 << 2 # [0,1] colors
    vert_texcoord_comp = 1 << 3 # [0,1] texture coords

    # Combine vertex data components to one integer
    vert_comps = vert_position_comp
    if save_normal: vert_comps = vert_comps | vert_normal_comp
    if save_vert_color: vert_comps = vert_comps | vert_color_comp
    if save_tex_coord: vert_comps = vert_comps | vert_texcoord_comp

    vert_count = len(mesh_data.vertices)

    #epsilon = 1 / (2 ** 20)

    vert_col_data = array('f')

    if save_vert_color:
        # Create an empty array of required size
        for i in range(0, vert_count * 3):
            vert_col_data.append(0.0)

        # Shorter name for vertex color data
        mesh_vert_col = mesh_data.vertex_colors.active

        # Get the vertex color for each corner of each polygon
        # Write colors to the corresponding vertex index in the array
        for i in range(0, len(mesh_data.loops)):
            v_index = mesh_data.loops[i].vertex_index
            v_color = mesh_vert_col.data[i].color
            vert_col_data[v_index * 3 + 0] = v_color[0]
            vert_col_data[v_index * 3 + 1] = v_color[1]
            vert_col_data[v_index * 3 + 2] = v_color[2]

    # Shorter name for mesh vertices
    verts = mesh_data.vertices

    # 'f' for 4-byte floating point
    vertex_data = array('f')

    # Put vertex data in the array

    # Just vertex position
    if vert_comps == vert_position_comp:
        for v in verts:
            vertex_data.extend([v.co.x, v.co.z, -v.co.y])

    # Vertex position and normal
    elif vert_comps == (vert_position_comp | vert_normal_comp):
        for v in verts:
            vertex_data.extend([v.co.x, v.co.z, -v.co.y])
            vertex_data.extend([v.normal.x, v.normal.z, -v.normal.y])

    # Vertex position and color
    elif vert_comps == (vert_position_comp | vert_color_comp):
        for i in range(0, vert_count):
            vertex_data.append(verts[i].co.x)
            vertex_data.append(verts[i].co.z)
            vertex_data.append(-verts[i].co.y)
            vertex_data.append(vert_col_data[i * 3 + 0])
            vertex_data.append(vert_col_data[i * 3 + 1])
            vertex_data.append(vert_col_data[i * 3 + 2])

    # Vertex position, normal and color
    elif vert_comps == (vert_position_comp | vert_normal_comp | vert_color_comp):
        for i in range(0, vert_count):
            vertex_data.append(verts[i].co.x)
            vertex_data.append(verts[i].co.z)
            vertex_data.append(-verts[i].co.y)
            vertex_data.append(verts[i].normal.x)
            vertex_data.append(verts[i].normal.z)
            vertex_data.append(-verts[i].normal.y)
            vertex_data.append(vert_col_data[i * 3 + 0])
            vertex_data.append(vert_col_data[i * 3 + 1])
            vertex_data.append(vert_col_data[i * 3 + 2])

    # 'H': unsigned 2-byte int, 'I': unsigned 4-byte int
    if vert_count <= (1 << 16):
        index_data = array('H')
    else:
        index_data = array('I')

    # Get index data
    for p in mesh_data.polygons:
        index_data.extend([p.vertices[0], p.vertices[1], p.vertices[2]])

    # Prepare data for the header
    index_count = len(index_data)

    # '=': native byte-order, standard packing
    # 'I': unsigned 4-byte integer
    header = pack('=III', vert_comps, vert_count, index_count)

    # Remove the mesh we created earlier
    bpy.data.meshes.remove(mesh_data)

    # Open output file
    with open(filepath, 'wb') as outfile:

        # Start with file type magic number
        outfile.write(b'\x10\x10\x19\x91');

        # Write header data
        outfile.write(header)

        # Write vertex data
        vertex_data.tofile(outfile)

        # Write index data
        index_data.tofile(outfile)

    return True
<|endoftext|>


<commit_before>from fontFeatures import FontFeatures, Routine, Substitution
from fontFeatures.feaLib import FeaParser
from pathlib import Path
import logging

logger = logging.getLogger("ufomerge")
logging.basicConfig(level=logging.INFO)

def merge_ufos(
    ufo1,
    ufo2,
    glyphs=None,
    exclude_glyphs=None,
    codepoints=None,
    layout_handling="subset",
    existing_handling="replace",
):
    if glyphs is None:
        glyphs = []

    glyphs = set(glyphs)

    if codepoints:
        cp2glyph = {}
        for g in ufo2:
            for u in g.unicodes:
                cp2glyph[u] = g.name
        glyphs |= set(cp2glyph[c] for c in codepoints if c in cp2glyph)

    if exclude_glyphs:
        glyphs = set(glyphs) - set(exclude_glyphs)

    # Check those glyphs actually are in UFO 2
    not_there = glyphs - set(ufo2.keys())
    if len(not_there):
        logger.warn("The following glyphs were not in UFO 2: %s" % ", ".join(not_there))
        glyphs = glyphs - not_there

    if not glyphs:
        logger.info("No glyphs selected, nothing to do")
        exit(0)

    newglyphset = set(ufo1.keys()) | set(glyphs)

    # Handle layout subsetting here, in case closure is needed
    new_layout_rules = FontFeatures()
    if layout_handling == "ignore":
        pass
    else:
        path = getattr(ufo2, "_path", None)
        includeDir = Path(ufo2._path).parent if path else None
        ff = FeaParser(ufo2.features.text, includeDir=includeDir).parse()
        for routine in ff.routines:
            newroutine = Routine(name=routine.name, flags=routine.flags)
            for rule in routine.rules:
                if not isinstance(rule, Substitution):
                    continue
                flat_outputs = [
                    item for sublist in rule.replacement for item in sublist
                ]
                rule.input = [list(set(r) & newglyphset) for r in rule.input]
                rule.precontext = [list(set(r) & newglyphset) for r in rule.precontext]
                rule.postcontext = [
                    list(set(r) & newglyphset) for r in rule.postcontext
                ]
                if (
                    any(not g for g in rule.input)
                    or any(not g for g in rule.precontext)
                    or any(not g for g in rule.postcontext)
                ):
                    continue
                if layout_handling == "closure":
                    # Any glyphs from "glyphs" substituted or generated by rules need to be added to the glyph set
                    if not any(g in glyphs for g in rule.involved_glyphs):
                        continue
                    glyphs |= set(flat_outputs)
                else:
                    # Any rules with new glyphs on the right hand side and glyphs
                    # we have on the left hand side need to be copied into UFO1
                    if not any(g in glyphs for g in flat_outputs):
                        continue
                    logging.debug("Adding rule '%s'", rule.asFea())
                newroutine.rules.append(rule)
            if newroutine.rules:
                # Was it in a feature?
                add_to = []
                for feature_name, routines in ff.features.items():
                    for routine_ref in routines:
                        if routine_ref.routine == routine:
                            add_to.append(feature_name)
                for feature_name in add_to:
                    new_layout_rules.addFeature(feature_name, [newroutine])

    # Kerning!!
    # # Create a list of flat kerning pairs for UFO 1
    # ufo1_kerns = set()
    # for l,r in ufo1.kerning.keys():
    #     l = ufo1.groups.get(l,[l])
    #     r = ufo1.groups.get(r,[r])
    #     for lg in l:
    #         for rg in r:
    #             ufo1_kerns.add((lg,rg))

    # Slim down the groups to only those in the glyph set
    for g in ufo2.groups.keys():
        ufo2.groups[g] = [g for g in ufo2.groups[g] if g in newglyphset]

    for (l, r), value in ufo2.kerning.items():
        lg = ufo2.groups.get(l, [l])
        rg = ufo2.groups.get(r, [r])
        if not lg or not rg:
            continue
        if any(lglyph not in newglyphset for lglyph in lg) or any(
            rglyph not in newglyphset for rglyph in rg
        ):
            continue
        # Just add for now. We should get fancy later
        ufo1.kerning[(l, r)] = value
        if l.startswith("public.kern"):
            if l not in ufo1.groups:
                ufo1.groups[l] = ufo2.groups[l]
            else:
                ufo1.groups[l] = list(set(ufo1.groups[l] + ufo2.groups[l]))
        if r.startswith("public.kern"):
            if r not in ufo1.groups:
                ufo1.groups[r] = ufo2.groups[r]
            else:
                ufo1.groups[r] = list(set(ufo1.groups[r] + ufo2.groups[r]))

    # Routines for merging font lib keys
    def merge_set(ufo1, ufo2, name, g, create_if_not_in_ufo1=False):
        if name not in ufo2.lib or g not in ufo2.lib[name]:
            return
        if name not in ufo1.lib:
            if create_if_not_in_ufo1:
                ufo1.lib[name] = []
            else:
                return
        if g not in ufo1.lib[name]:
            ufo1.lib[name].append(g)

    def merge_dict(ufo1, ufo2, name, g, create_if_not_in_ufo1=False):
        if name not in ufo2.lib or g not in ufo2.lib[name]:
            return
        if name not in ufo1.lib:
            if create_if_not_in_ufo1:
                ufo1.lib[name] = {}
            else:
                return
        ufo1.lib[name][g] = ufo2.lib[name][g]

    # Check the glyphs for components
    def close_components(glyphs, g):
        if not ufo2[g].components:
            return
        for comp in ufo2[g].components:
            if comp.baseGlyph not in newglyphset:
                # Well, this is the easy case
                glyphs.add(comp.baseGlyph)
                close_components(glyphs, comp.baseGlyph)
            elif existing_handling == "replace":
                # Also not a problem
                glyphs.add(comp.baseGlyph)
                close_components(glyphs, comp.baseGlyph)
            elif comp.baseGlyph in ufo1:
                # Oh bother.
                logger.warning(
                    f"New glyph {g} used component {comp.baseGlyph} which already exists in font; not replacing it, as you have not specified --replace-existing"
                )

    for g in list(glyphs):  # list() avoids "Set changed size during iteration" error
        close_components(glyphs, g)

    # Now do the add
    for g in glyphs:
        if existing_handling == "skip" and g in ufo1:
            logger.info("Skipping glyph '%s' already present in target file" % g)
            continue

        merge_set(ufo1, ufo2, "public.glyphOrder", g, create_if_not_in_ufo1=False)
        merge_set(ufo1, ufo2, "public.skipExportGlyphs", g, create_if_not_in_ufo1=True)
        merge_dict(ufo1, ufo2, "public.postscriptNames", g, create_if_not_in_ufo1=True)
        merge_dict(
            ufo1, ufo2, "public.openTypeCategories", g, create_if_not_in_ufo1=True
        )

        if g in ufo1:
            ufo1[g] = ufo2[g]
        else:
            ufo1.addGlyph(ufo2[g])

    if new_layout_rules.routines:
        ufo1.features.text += new_layout_rules.asFea(do_gdef=False)
<commit_msg>Attempt to subset "sub @foo by @bar"<commit_after>from fontFeatures import FontFeatures, Routine, Substitution
from fontFeatures.feaLib import FeaParser
from pathlib import Path
import logging

logger = logging.getLogger("ufomerge")
logging.basicConfig(level=logging.INFO)

def merge_ufos(
    ufo1,
    ufo2,
    glyphs=None,
    exclude_glyphs=None,
    codepoints=None,
    layout_handling="subset",
    existing_handling="replace",
):
    if glyphs is None:
        glyphs = []

    glyphs = set(glyphs)

    if codepoints:
        cp2glyph = {}
        for g in ufo2:
            for u in g.unicodes:
                cp2glyph[u] = g.name
        glyphs |= set(cp2glyph[c] for c in codepoints if c in cp2glyph)

    if exclude_glyphs:
        glyphs = set(glyphs) - set(exclude_glyphs)

    # Check those glyphs actually are in UFO 2
    not_there = glyphs - set(ufo2.keys())
    if len(not_there):
        logger.warn("The following glyphs were not in UFO 2: %s" % ", ".join(not_there))
        glyphs = glyphs - not_there

    if not glyphs:
        logger.info("No glyphs selected, nothing to do")
        exit(0)

    newglyphset = set(ufo1.keys()) | set(glyphs)

    # Handle layout subsetting here, in case closure is needed
    new_layout_rules = FontFeatures()
    if layout_handling == "ignore":
        pass
    else:
        path = getattr(ufo2, "_path", None)
        includeDir = Path(ufo2._path).parent if path else None
        ff = FeaParser(ufo2.features.text, includeDir=includeDir).parse()
        for routine in ff.routines:
            newroutine = Routine(name=routine.name, flags=routine.flags)
            for rule in routine.rules:
                if not isinstance(rule, Substitution):
                    continue
                flat_outputs = [
                    item for sublist in rule.replacement for item in sublist
                ]
                true_inputs = [list(set(r) & newglyphset) for r in rule.input]
                rule.precontext = [list(set(r) & newglyphset) for r in rule.precontext]
                rule.postcontext = [
                    list(set(r) & newglyphset) for r in rule.postcontext
                ]
                if (
                    any(not g for g in true_inputs)
                    or any(not g for g in rule.precontext)
                    or any(not g for g in rule.postcontext)
                ):
                    continue
                if layout_handling == "closure":
                    # Any glyphs from "glyphs" substituted or generated by rules need to be added to the glyph set
                    if not any(g in glyphs for g in rule.involved_glyphs):
                        continue
                    rule.input = true_inputs
                    glyphs |= set(flat_outputs)
                else:
                    # Any rules with new glyphs on the right hand side and glyphs
                    # we have on the left hand side need to be copied into UFO1
                    if not any(g in glyphs for g in flat_outputs):
                        continue
                    if len(rule.input) == 1 and len(rule.replacement) == 1:  # GSUB1
                        mapping = zip(rule.input[0], rule.replacement[0])
                        mapping = [(a,b) for a,b in mapping if a in newglyphset and b in newglyphset]
                        if not mapping:
                            continue
                        rule.input[0] = [r[0] for r in mapping]
                        rule.replacement[0] = [r[1] for r in mapping]
                    else:
                        rule.input = true_inputs
                        rule.replacement = [list(set(r) & newglyphset) for r in rule.replacement]
                    logging.debug("Adding rule '%s'", rule.asFea())
                newroutine.rules.append(rule)
            if newroutine.rules:
                # Was it in a feature?
                add_to = []
                for feature_name, routines in ff.features.items():
                    for routine_ref in routines:
                        if routine_ref.routine == routine:
                            add_to.append(feature_name)
                for feature_name in add_to:
                    new_layout_rules.addFeature(feature_name, [newroutine])

    # Kerning!!
    # # Create a list of flat kerning pairs for UFO 1
    # ufo1_kerns = set()
    # for l,r in ufo1.kerning.keys():
    #     l = ufo1.groups.get(l,[l])
    #     r = ufo1.groups.get(r,[r])
    #     for lg in l:
    #         for rg in r:
    #             ufo1_kerns.add((lg,rg))

    # Slim down the groups to only those in the glyph set
    for g in ufo2.groups.keys():
        ufo2.groups[g] = [g for g in ufo2.groups[g] if g in newglyphset]

    for (l, r), value in ufo2.kerning.items():
        lg = ufo2.groups.get(l, [l])
        rg = ufo2.groups.get(r, [r])
        if not lg or not rg:
            continue
        if any(lglyph not in newglyphset for lglyph in lg) or any(
            rglyph not in newglyphset for rglyph in rg
        ):
            continue
        # Just add for now. We should get fancy later
        ufo1.kerning[(l, r)] = value
        if l.startswith("public.kern"):
            if l not in ufo1.groups:
                ufo1.groups[l] = ufo2.groups[l]
            else:
                ufo1.groups[l] = list(set(ufo1.groups[l] + ufo2.groups[l]))
        if r.startswith("public.kern"):
            if r not in ufo1.groups:
                ufo1.groups[r] = ufo2.groups[r]
            else:
                ufo1.groups[r] = list(set(ufo1.groups[r] + ufo2.groups[r]))

    # Routines for merging font lib keys
    def merge_set(ufo1, ufo2, name, g, create_if_not_in_ufo1=False):
        if name not in ufo2.lib or g not in ufo2.lib[name]:
            return
        if name not in ufo1.lib:
            if create_if_not_in_ufo1:
                ufo1.lib[name] = []
            else:
                return
        if g not in ufo1.lib[name]:
            ufo1.lib[name].append(g)

    def merge_dict(ufo1, ufo2, name, g, create_if_not_in_ufo1=False):
        if name not in ufo2.lib or g not in ufo2.lib[name]:
            return
        if name not in ufo1.lib:
            if create_if_not_in_ufo1:
                ufo1.lib[name] = {}
            else:
                return
        ufo1.lib[name][g] = ufo2.lib[name][g]

    # Check the glyphs for components
    def close_components(glyphs, g):
        if not ufo2[g].components:
            return
        for comp in ufo2[g].components:
            if comp.baseGlyph not in newglyphset:
                # Well, this is the easy case
                glyphs.add(comp.baseGlyph)
                close_components(glyphs, comp.baseGlyph)
            elif existing_handling == "replace":
                # Also not a problem
                glyphs.add(comp.baseGlyph)
                close_components(glyphs, comp.baseGlyph)
            elif comp.baseGlyph in ufo1:
                # Oh bother.
                logger.warning(
                    f"New glyph {g} used component {comp.baseGlyph} which already exists in font; not replacing it, as you have not specified --replace-existing"
                )

    for g in list(glyphs):  # list() avoids "Set changed size during iteration" error
        close_components(glyphs, g)

    # Now do the add
    for g in glyphs:
        if existing_handling == "skip" and g in ufo1:
            logger.info("Skipping glyph '%s' already present in target file" % g)
            continue

        merge_set(ufo1, ufo2, "public.glyphOrder", g, create_if_not_in_ufo1=False)
        merge_set(ufo1, ufo2, "public.skipExportGlyphs", g, create_if_not_in_ufo1=True)
        merge_dict(ufo1, ufo2, "public.postscriptNames", g, create_if_not_in_ufo1=True)
        merge_dict(
            ufo1, ufo2, "public.openTypeCategories", g, create_if_not_in_ufo1=True
        )

        if g in ufo1:
            ufo1[g] = ufo2[g]
        else:
            ufo1.addGlyph(ufo2[g])

    if new_layout_rules.routines:
        ufo1.features.text += new_layout_rules.asFea(do_gdef=False)
<|endoftext|>


<commit_before># CallTips.py - An IDLE extension that provides "Call Tips" - ie, a floating window that
# displays parameter information as you open parens.

import string
import sys
import types

class CallTips:

    menudefs = [
    ]

    keydefs = {
        '<<paren-open>>': ['<Key-parenleft>'],
        '<<paren-close>>': ['<Key-parenright>'],
        '<<check-calltip-cancel>>': ['<KeyRelease>'],
        '<<calltip-cancel>>': ['<ButtonPress>', '<Key-Escape>'],
    }

    windows_keydefs = {
    }

    unix_keydefs = {
    }

    def __init__(self, editwin):
        self.editwin = editwin
        self.text = editwin.text
        self.calltip = None
        if hasattr(self.text, "make_calltip_window"):
            self._make_calltip_window = self.text.make_calltip_window
        else:
            self._make_calltip_window = self._make_tk_calltip_window

    def close(self):
        self._make_calltip_window = None

    # Makes a Tk based calltip window.  Used by IDLE, but not Pythonwin.
    # See __init__ above for how this is used.
    def _make_tk_calltip_window(self):
        import CallTipWindow
        return CallTipWindow.CallTip(self.text)

    def _remove_calltip_window(self):
        if self.calltip:
            self.calltip.hidetip()
            self.calltip = None

    def paren_open_event(self, event):
        self._remove_calltip_window()
        arg_text = get_arg_text(self.get_object_at_cursor())
        if arg_text:
            self.calltip_start = self.text.index("insert")
            self.calltip = self._make_calltip_window()
            self.calltip.showtip(arg_text)
        return "" #so the event is handled normally.

    def paren_close_event(self, event):
        # Now just hides, but later we should check if other
        # paren'd expressions remain open.
        self._remove_calltip_window()
        return "" #so the event is handled normally.

    def check_calltip_cancel_event(self, event):
        if self.calltip:
            # If we have moved before the start of the calltip,
            # or off the calltip line, then cancel the tip.
            # (Later need to be smarter about multi-line, etc)
            if self.text.compare("insert", "<=", self.calltip_start) or \
               self.text.compare("insert", ">", self.calltip_start + " lineend"):
                self._remove_calltip_window()
        return "" #so the event is handled normally.

    def calltip_cancel_event(self, event):
        self._remove_calltip_window()
        return "" #so the event is handled normally.

    def get_object_at_cursor(self,
                             wordchars="._" + string.uppercase + string.lowercase + string.digits):
        # XXX - This needs to be moved to a better place
        # so the "." attribute lookup code can also use it.
        text = self.text
        chars = text.get("insert linestart", "insert")
        i = len(chars)
        while i and chars[i-1] in wordchars:
            i = i-1
        word = chars[i:]
        if word:
            # How is this for a hack!
            import sys, __main__
            namespace = sys.modules.copy()
            namespace.update(__main__.__dict__)
            try:
                    return eval(word, namespace)
            except:
                    pass
        return None # Can't find an object.

def _find_constructor(class_ob):
    # Given a class object, return a function object used for the
    # constructor (ie, __init__() ) or None if we can't find one.
    try:
        return class_ob.__init__.im_func
    except AttributeError:
        for base in class_ob.__bases__:
            rc = _find_constructor(base)
            if rc is not None: return rc
    return None

def get_arg_text(ob):
    # Get a string describing the arguments for the given object.
    argText = ""
    if ob is not None:
        argOffset = 0
        if type(ob)==types.ClassType:
            # Look for the highest __init__ in the class chain.
            fob = _find_constructor(ob)
            if fob is None:
                fob = lambda: None
            else:
                argOffset = 1
        elif type(ob)==types.MethodType:
            # bit of a hack for methods - turn it into a function
            # but we drop the "self" param.
            fob = ob.im_func
            argOffset = 1
        else:
            fob = ob
        # Try and build one for Python defined functions
        if type(fob) in [types.FunctionType, types.LambdaType]:
            try:
                realArgs = fob.func_code.co_varnames[argOffset:fob.func_code.co_argcount]
                defaults = fob.func_defaults or []
                defaults = list(map(lambda name: "=%s" % name, defaults))
                defaults = [""] * (len(realArgs)-len(defaults)) + defaults
                items = map(lambda arg, dflt: arg+dflt, realArgs, defaults)
                if fob.func_code.co_flags & 0x4:
                    items.append("...")
                if fob.func_code.co_flags & 0x8:
                    items.append("***")
                argText = string.join(items , ", ")
                argText = "(%s)" % argText
            except:
                pass
        # See if we can use the docstring
        if hasattr(ob, "__doc__") and ob.__doc__:
            pos = string.find(ob.__doc__, "\n")
            if pos<0 or pos>70: pos=70
            if argText: argText = argText + "\n"
            argText = argText + ob.__doc__[:pos]

    return argText

#################################################
#
# Test code
#
if __name__=='__main__':

    def t1(): "()"
    def t2(a, b=None): "(a, b=None)"
    def t3(a, *args): "(a, ...)"
    def t4(*args): "(...)"
    def t5(a, *args): "(a, ...)"
    def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"

    class TC:
        "(a=None, ...)"
        def __init__(self, a=None, *b): "(a=None, ...)"
        def t1(self): "()"
        def t2(self, a, b=None): "(a, b=None)"
        def t3(self, a, *args): "(a, ...)"
        def t4(self, *args): "(...)"
        def t5(self, a, *args): "(a, ...)"
        def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)"

    def test( tests ):
        failed=[]
        for t in tests:
            expected = t.__doc__ + "\n" + t.__doc__
            if get_arg_text(t) != expected:
                failed.append(t)
                print "%s - expected %s, but got %s" % (t, `expected`, `get_arg_text(t)`)
        print "%d of %d tests failed" % (len(failed), len(tests))

    tc = TC()
    tests = t1, t2, t3, t4, t5, t6, \
            TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6

    test(tests)
<commit_msg>py-cvs-rel2_1 (Rev 1.8) merge - whitespace normalization<commit_after># CallTips.py - An IDLE extension that provides "Call Tips" - ie, a floating window that
# displays parameter information as you open parens.

import string
import sys
import types

class CallTips:

    menudefs = [
    ]

    keydefs = {
        '<<paren-open>>': ['<Key-parenleft>'],
        '<<paren-close>>': ['<Key-parenright>'],
        '<<check-calltip-cancel>>': ['<KeyRelease>'],
        '<<calltip-cancel>>': ['<ButtonPress>', '<Key-Escape>'],
    }

    windows_keydefs = {
    }

    unix_keydefs = {
    }

    def __init__(self, editwin):
        self.editwin = editwin
        self.text = editwin.text
        self.calltip = None
        if hasattr(self.text, "make_calltip_window"):
            self._make_calltip_window = self.text.make_calltip_window
        else:
            self._make_calltip_window = self._make_tk_calltip_window

    def close(self):
        self._make_calltip_window = None

    # Makes a Tk based calltip window.  Used by IDLE, but not Pythonwin.
    # See __init__ above for how this is used.
    def _make_tk_calltip_window(self):
        import CallTipWindow
        return CallTipWindow.CallTip(self.text)

    def _remove_calltip_window(self):
        if self.calltip:
            self.calltip.hidetip()
            self.calltip = None

    def paren_open_event(self, event):
        self._remove_calltip_window()
        arg_text = get_arg_text(self.get_object_at_cursor())
        if arg_text:
            self.calltip_start = self.text.index("insert")
            self.calltip = self._make_calltip_window()
            self.calltip.showtip(arg_text)
        return "" #so the event is handled normally.

    def paren_close_event(self, event):
        # Now just hides, but later we should check if other
        # paren'd expressions remain open.
        self._remove_calltip_window()
        return "" #so the event is handled normally.

    def check_calltip_cancel_event(self, event):
        if self.calltip:
            # If we have moved before the start of the calltip,
            # or off the calltip line, then cancel the tip.
            # (Later need to be smarter about multi-line, etc)
            if self.text.compare("insert", "<=", self.calltip_start) or \
               self.text.compare("insert", ">", self.calltip_start + " lineend"):
                self._remove_calltip_window()
        return "" #so the event is handled normally.

    def calltip_cancel_event(self, event):
        self._remove_calltip_window()
        return "" #so the event is handled normally.

    def get_object_at_cursor(self,
                             wordchars="._" + string.uppercase + string.lowercase + string.digits):
        # XXX - This needs to be moved to a better place
        # so the "." attribute lookup code can also use it.
        text = self.text
        chars = text.get("insert linestart", "insert")
        i = len(chars)
        while i and chars[i-1] in wordchars:
            i = i-1
        word = chars[i:]
        if word:
            # How is this for a hack!
            import sys, __main__
            namespace = sys.modules.copy()
            namespace.update(__main__.__dict__)
            try:
                return eval(word, namespace)
            except:
                pass
        return None # Can't find an object.

def _find_constructor(class_ob):
    # Given a class object, return a function object used for the
    # constructor (ie, __init__() ) or None if we can't find one.
    try:
        return class_ob.__init__.im_func
    except AttributeError:
        for base in class_ob.__bases__:
            rc = _find_constructor(base)
            if rc is not None: return rc
    return None

def get_arg_text(ob):
    # Get a string describing the arguments for the given object.
    argText = ""
    if ob is not None:
        argOffset = 0
        if type(ob)==types.ClassType:
            # Look for the highest __init__ in the class chain.
            fob = _find_constructor(ob)
            if fob is None:
                fob = lambda: None
            else:
                argOffset = 1
        elif type(ob)==types.MethodType:
            # bit of a hack for methods - turn it into a function
            # but we drop the "self" param.
            fob = ob.im_func
            argOffset = 1
        else:
            fob = ob
        # Try and build one for Python defined functions
        if type(fob) in [types.FunctionType, types.LambdaType]:
            try:
                realArgs = fob.func_code.co_varnames[argOffset:fob.func_code.co_argcount]
                defaults = fob.func_defaults or []
                defaults = list(map(lambda name: "=%s" % name, defaults))
                defaults = [""] * (len(realArgs)-len(defaults)) + defaults
                items = map(lambda arg, dflt: arg+dflt, realArgs, defaults)
                if fob.func_code.co_flags & 0x4:
                    items.append("...")
                if fob.func_code.co_flags & 0x8:
                    items.append("***")
                argText = string.join(items , ", ")
                argText = "(%s)" % argText
            except:
                pass
        # See if we can use the docstring
        if hasattr(ob, "__doc__") and ob.__doc__:
            pos = string.find(ob.__doc__, "\n")
            if pos<0 or pos>70: pos=70
            if argText: argText = argText + "\n"
            argText = argText + ob.__doc__[:pos]

    return argText

#################################################
#
# Test code
#
if __name__=='__main__':

    def t1(): "()"
    def t2(a, b=None): "(a, b=None)"
    def t3(a, *args): "(a, ...)"
    def t4(*args): "(...)"
    def t5(a, *args): "(a, ...)"
    def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"

    class TC:
        "(a=None, ...)"
        def __init__(self, a=None, *b): "(a=None, ...)"
        def t1(self): "()"
        def t2(self, a, b=None): "(a, b=None)"
        def t3(self, a, *args): "(a, ...)"
        def t4(self, *args): "(...)"
        def t5(self, a, *args): "(a, ...)"
        def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)"

    def test( tests ):
        failed=[]
        for t in tests:
            expected = t.__doc__ + "\n" + t.__doc__
            if get_arg_text(t) != expected:
                failed.append(t)
                print "%s - expected %s, but got %s" % (t, `expected`, `get_arg_text(t)`)
        print "%d of %d tests failed" % (len(failed), len(tests))

    tc = TC()
    tests = t1, t2, t3, t4, t5, t6, \
            TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6

    test(tests)
<|endoftext|>


<commit_before>import scipy_base as sb
import scipy
pi = scipy.pi

# fast discrete cosine transforms of real sequences (using the fft)
#  These implement the DCT-II and inverse DCT-II (DCT-III)
#  described at http://en.wikipedia.org/wiki/Discrete_cosine_transform

def dct(x,axis=-1):
    n = len(x.shape)
    N = x.shape[axis]
    if (N%2 != 0):
        raise ValueError, "Length of sequence must be even."
    xtilde = 0.0*x
    slices = [None]*4
    for k in range(4):
        slices[k] = []
        for j in range(n):
            slices[k].append(slice(None))
    slices[0][axis] = slice(None,N/2)
    slices[1][axis] = slice(None,None,2)
    slices[2][axis] = slice(N/2,None)
    slices[3][axis] = slice(N,None,-2)
    for k in range(4):
        slices[k] = tuple(slices[k])
    xtilde[slices[0]] = x[slices[1]]
    xtilde[slices[2]] = x[slices[3]]
    Xt = scipy.fft(xtilde,axis=axis)
    pk = exp(-1j*pi*arange(N)/(2*N))
    newshape = ones(n)
    newshape[axis] = N
    pk.shape = newshape
    return squeeze(real(Xt*pk))

def idct(v,axis=-1):
    n = len(v.shape)
    N = v.shape[axis]
    if (N%2 != 0):
        raise ValueError, "Length of sequence must be even."
    k = arange(N)
    ak = sb.r_[1.0,[2]*(N-1)]*exp(1j*pi*k/(2*N))
    newshape = ones(n)
    newshape[axis] = N
    ak.shape = newshape
    xhat = real(scipy.ifft(v*ak,axis=axis))
    x = 0.0*v
    slices = [None]*4
    for k in range(4):
        slices[k] = []
        for j in range(n):
            slices[k].append(slice(None))
    slices[0][axis] = slice(None,None,2)
    slices[1][axis] = slice(None,N/2)
    slices[2][axis] = slice(N,None,-2)
    slices[3][axis] = slice(N/2,None)
    for k in range(4):
        slices[k] = tuple(slices[k])
    x[slices[0]] = xhat[slices[1]]
    x[slices[2]] = xhat[slices[3]]
    return x

def dct2(x,axes=(-1,-2)):
    return dct(dct(x,axis=axes[0]),axis=axes[1])

def idct2(v,axes=(-1,-2)):
    return idct(idct(v,axis=axes[0]),axis=axes[1])

def dctn(x,axes=None):
    if axes is None:
        axes = arange(len(x.shape))
    res = x
    for k in axes:
        res = dct(res,axis=k)
    return res

def idctn(v,axes=None):
    if axes is None:
        axes = arange(len(v.shape))
    res = v
    for k in axes:
        res = idct(res,axis=k)
    return res

def makeC(N):
    n,l = ogrid[:N,:N]
    C = cos(pi*(2*n+1)*l/(2*N))
    return C

def dct2raw(x):
    M,N = x.shape
    CM = makeC(M)
    CN = makeC(N)
    return dot(transpose(CM),dot(x,CN))

def idct2raw(v):
    M,N = v.shape
    iCM = linalg.inv(makeC(M))
    iCN = linalg.inv(makeC(N))
    return dot(transpose(iCM),dot(v,iCN))
<commit_msg>Added Discrete sine transform and fixed DCT to handle odd-length vectors as well.<commit_after>import scipy_base as sb
import scipy
pi = scipy.pi

# fast discrete cosine transforms of real sequences (using the fft)
#  These implement the DCT-II and inverse DCT-II (DCT-III)
#  described at http://en.wikipedia.org/wiki/Discrete_cosine_transform

def dct(x,axis=-1):
    """Discrete cosine transform based on the FFT.

    For even-length signals it uses an N-point FFT
    For odd-length signals it uses a 2N-point FFT.
    """
    n = len(x.shape)
    N = x.shape[axis]
    even = (N%2 == 0)
    slices = [None]*4
    for k in range(4):
        slices[k] = []
        for j in range(n):
            slices[k].append(slice(None))
    if even:
        xtilde = 0.0*x
        slices[0][axis] = slice(None,N/2)
        slices[1][axis] = slice(None,None,2)
        slices[2][axis] = slice(N/2,None)
        slices[3][axis] = slice(N,None,-2)
    else:
        newshape = list(x.shape)
        newshape[axis] = 2*N
        xtilde = sb.empty(newshape,sb.Float)
        slices[0][axis] = slice(None,N)
        slices[2][axis] = slice(N,None)
        slices[3][axis] = slice(None,None,-1)

    for k in range(4):
        slices[k] = tuple(slices[k])
    xtilde[slices[0]] = x[slices[1]]
    xtilde[slices[2]] = x[slices[3]]
    Xt = scipy.fft(xtilde,axis=axis)
    pk = sb.exp(-1j*pi*sb.arange(N)/(2*N))
    newshape = sb.ones(n)
    newshape[axis] = N
    pk.shape = newshape

    if not even:
        pk /= 2;
        Xt = Xt[slices[0]]

    return sb.real(Xt*pk)

def idct(v,axis=-1):
    n = len(v.shape)
    N = v.shape[axis]
    even = (N%2 == 0)
    slices = [None]*4
    for k in range(4):
        slices[k] = []
        for j in range(n):
            slices[k].append(slice(None))
    k = arange(N)
    if even:
        ak = sb.r_[1.0,[2]*(N-1)]*exp(1j*pi*k/(2*N))
        newshape = ones(n)
        newshape[axis] = N
        ak.shape = newshape
        xhat = real(scipy.ifft(v*ak,axis=axis))
        x = 0.0*v
        slices[0][axis] = slice(None,None,2)
        slices[1][axis] = slice(None,N/2)
        slices[2][axis] = slice(N,None,-2)
        slices[3][axis] = slice(N/2,None)
        for k in range(4):
            slices[k] = tuple(slices[k])
        x[slices[0]] = xhat[slices[1]]
        x[slices[2]] = xhat[slices[3]]
        return x
    else:
        ak = 2*sb.exp(1j*pi*k/(2*N))
        newshape = ones(n)
        newshape[axis] = N
        ak.shape = newshape
        newshape = list(v.shape)
        newshape[axis] = 2*N
        Y = zeros(newshape,sb.Complex)
        #Y[:N] = ak*v
        #Y[(N+1):] = conj(Y[N:0:-1])
        slices[0][axis] = slice(None,N)
        slices[1][axis] = slice(None,None)
        slices[2][axis] = slice(N+1,None)
        slices[3][axis] = slice((N-1),0,-1)
        Y[slices[0]] = ak*v
        Y[slices[2]] = conj(Y[slices[3]])
        x = real(scipy.ifft(Y,axis=axis))[slices[0]]
        return x

def dct2(x,axes=(-1,-2)):
    return dct(dct(x,axis=axes[0]),axis=axes[1])

def idct2(v,axes=(-1,-2)):
    return idct(idct(v,axis=axes[0]),axis=axes[1])

def dctn(x,axes=None):
    if axes is None:
        axes = arange(len(x.shape))
    res = x
    for k in axes:
        res = dct(res,axis=k)
    return res

def idctn(v,axes=None):
    if axes is None:
        axes = arange(len(v.shape))
    res = v
    for k in axes:
        res = idct(res,axis=k)
    return res

def makeC(N):
    n,l = ogrid[:N,:N]
    C = cos(pi*(2*n+1)*l/(2*N))
    return C

def dct2raw(x):
    M,N = x.shape
    CM = makeC(M)
    CN = makeC(N)
    return dot(transpose(CM),dot(x,CN))

def idct2raw(v):
    M,N = v.shape
    iCM = linalg.inv(makeC(M))
    iCN = linalg.inv(makeC(N))
    return dot(transpose(iCM),dot(v,iCN))

def makeS(N):
    n,k = ogrid[:N,:N]
    C = sin(pi*(k+1)*(n+1)/(N+1))
    return C

def dst(x,axis=-1):
    """Discrete Sine Transform (DST-I)

    Implemented using 2(N+1)-point FFT
    xsym = r_[0,x,0,-x[::-1]]
    DST = (-imag(fft(xsym))/2)[1:(N+1)]

    adjusted to work over an arbitrary axis for entire n-dim array
    """
    n = len(x.shape)
    N = x.shape[axis]
    slices = [None]*3
    for k in range(3):
        slices[k] = []
        for j in range(n):
            slices[k].append(slice(None))
    newshape = list(x.shape)
    newshape[axis] = 2*(N+1)
    xtilde = sb.zeros(newshape,sb.Float)
    slices[0][axis] = slice(1,N+1)
    slices[1][axis] = slice(N+2,None)
    slices[2][axis] = slice(None,None,-1)
    for k in range(3):
        slices[k] = tuple(slices[k])
    xtilde[slices[0]] = x
    xtilde[slices[1]] = -x[slices[2]]
    Xt = scipy.fft(xtilde,axis=axis)
    return (-sb.imag(Xt)/2)[slices[0]]

def idst(v,axis=-1):
    n = len(v.shape)
    N = v.shape[axis]
    slices = [None]*3
    for k in range(3):
        slices[k] = []
        for j in range(n):
            slices[k].append(slice(None))
    newshape = list(v.shape)
    newshape[axis] = 2*(N+1)
    Xt = sb.zeros(newshape,sb.Complex)
    slices[0][axis] = slice(1,N+1)
    slices[1][axis] = slice(N+2,None)
    slices[2][axis] = slice(None,None,-1)
    val = 2j*v
    for k in range(3):
        slices[k] = tuple(slices[k])
    Xt[slices[0]] = -val
    Xt[slices[1]] = val[slices[2]]
    xhat = real(scipy.ifft(Xt,axis=axis))
    return xhat[slices[0]]

def dst2(x,axes=(-1,-2)):
    return dst(dst(x,axis=axes[0]),axis=axes[1])

def idst2(v,axes=(-1,-2)):
    return idst(idst(v,axis=axes[0]),axis=axes[1])

def dstn(x,axes=None):
    if axes is None:
        axes = arange(len(x.shape))
    res = x
    for k in axes:
        res = dst(res,axis=k)
    return res

def idstn(v,axes=None):
    if axes is None:
        axes = arange(len(v.shape))
    res = v
    for k in axes:
        res = idst(res,axis=k)
    return res

def digitrevorder(x,base):
    x = asarray(x)
    rem = N = len(x)
    L = 0
    while 1:
        if rem < base:
            break
        intd = rem // base
        if base*intd != rem:
            raise ValueError, "Length of data must be power of base."
        rem = intd
        L += 1
    vec = r_[[base**n for n in range(L)]]
    newx = x[NewAxis,:]*vec[:,NewAxis]
    # compute digits
    for k in range(L-1,-1,-1):
        newx[k] = x // vec[k]
        x = x - newx[k]*vec[k]
    # reverse digits
    newx = newx[::-1,:]
    x = 0*x
    # construct new result from reversed digts
    for k in range(L):
        x += newx[k]*vec[k]
    return x

def bitrevorder(x):
    return digitrevorder(x,2)

# needs to be fixed
def wht(data):
    """Walsh-Hadamaard Transform (sequency ordered)

    adapted from MATLAB algorithm published on the web by
    Author: Gylson Thomas
    e-mail: gylson_thomas@yahoo.com
    Asst. Professor, Electrical and Electronics Engineering Dept.
    MES College of Engineering Kuttippuram,
    Kerala, India, February 2005.
    copyright 2005.
    Reference: N.Ahmed, K.R. Rao, "Orthogonal Transformations for
    Digital Signal Processing" Spring Verlag, New York 1975. page-111.
    """
    N = len(data)
    L=log2(N);
    if ((L-floor(L)) > 0.0):
        raise ValueError, "Length must be power of 2"
    x=bitrevorder(data);

    k1=N; k2=1; k3=N/2;
    for i1 in range(1,L+1):  #Iteration stage
        L1=1;
        for i2 in range(1,k2+1):
            for i3 in range(1,k3+1):
                i=i3+L1-1; j=i+k3;
                temp1= x[i-1]; temp2 = x[j-1];
                if (i2 % 2) == 0:
                  x[i-1] = temp1 - temp2;
                  x[j-1] = temp1 + temp2;
                  x[i-1] = temp1 + temp2;
                  x[j-1] = temp1 - temp2;
                L1=L1+k1;
            k1 = k1/2;  k2 = k2*2;  k3 = k3/2;
    x = x*1.0/N; # Delete this line for inverse wht
    return x

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Akvo RSR is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.

# python 2.5 compatibilty
from __future__ import with_statement

import os

from fabric.api import env, run
from fabric.context_managers import cd

from fabfiles.deployer_config import load_deployment_config

from helpers.files import delete_directory_with_sudo, delete_file_with_sudo
from helpers.paths import ensure_path_exists, ensure_path_exists_with_akvo_group_permissions
from helpers.permissions import ensure_user_is_member_of_group, set_akvo_ownership_on_path
from helpers.urls import file_name_at_url, url_file_exists_at_path
from helpers.virtualenv import rebuild_virtualenv

def ensure_user_is_member_of_akvo_permissions_group():
    print "\n>> Checking that user [%s] is a member of group [%s]" % (env.user,
        env.akvo_permissions_group) + " (required later for setting directory permissions)"
    ensure_user_is_member_of_group(env.akvo_permissions_group)

def ensure_required_paths_exist():
    ensure_user_is_member_of_akvo_permissions_group()
    ensure_path_exists_with_akvo_group_permissions(env.repo_checkout_root)
    ensure_path_exists(env.rsr_snapshots_dir)
    ensure_path_exists_with_akvo_group_permissions(env.virtualenvs_root)

def clean_deployment_directories():
    delete_directory_with_sudo(env.rsr_src_root, "\n>> Deleting previous deployment directory")

def download_rsr_archive():
    if not url_file_exists_at_path(env.rsr_archive_url, env.rsr_snapshots_dir):
        print "\n>> Fetching akvo-rsr archive for the [%s] branch from Github" % env.rsr_branch
        run("wget -nv -P %s %s" % (env.rsr_snapshots_dir, env.rsr_archive_url))
    else:
        archive_file_name = file_name_at_url(env.rsr_archive_url)
        print "\n>> Latest archive already exists at: %s" % os.path.join(env.rsr_snapshots_dir, archive_file_name)

def unpack_rsr_archive():
    print "\n>> Unpacking akvo-rsr archive in %s" % env.repo_checkout_root
    with cd(env.rsr_snapshots_dir):
        run("unzip -q %s -d %s -x */.gitignore" % (file_name_at_url(env.rsr_archive_url), env.repo_checkout_root))
    run("mv %s %s" % (env.rsr_unpacked_archive_match, env.rsr_src_root))
    set_akvo_ownership_on_path(env.rsr_src_root)

def download_and_unpack_rsr_archive():
    clean_deployment_directories()
    download_rsr_archive()
    unpack_rsr_archive()

def deploy_rsr():
    print "\n>> Starting RSR deployment"
    load_deployment_config()
    ensure_required_paths_exist()
    download_and_unpack_rsr_archive()
    rebuild_virtualenv(env.pip_requirements_file, env.pip_install_log_file)
<commit_msg>[#6699037] Removed old pre Fabric 1.1 deployment/fabfiles/deployer.py script, which has been replaced by the new fab.tasks modules.<commit_after><|endoftext|>


<commit_before># Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from django.db import models
from django.utils.translation import ugettext_lazy as _

def calculate_document_path(instance, filename):
    return 'documents/{filename}'.format(filename=filename)

class Document(models.Model):
    subject = models.CharField(null=False, blank=False, max_length=256,
                               verbose_name=_("subject"))
    author = models.CharField(null=False, blank=False, max_length=256,
                              verbose_name=_("author"))
    creation_date = models.DateTimeField(null=True, blanck=True,
                                         verbose_name=_("creation date"))
    description =models.TextField(null=True, blanck=True,
                                  verbose_name=_("sdescription"))
    file = models.FileField(null=False, blank-False, upload_to=calculate_document_patch,
                            verbose_name=_("file"))

    class Meta:
        verbose_name = "document"
        verbose_name_plural = "documents"
<commit_msg>WIP model<commit_after># Copyright (C) 2015 David Barragán <bameda@dbarragan.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from django.db import models
from django.utils.translation import ugettext_lazy as _

def calculate_document_path(instance, filename):
    return 'documents/{filename}'.format(filename=filename)

class Document(models.Model):
    subject = models.CharField(null=False, blank=False, max_length=256,
                               verbose_name=_("subject"))
    author = models.CharField(null=False, blank=False, max_length=256,
                              verbose_name=_("author"))
    creation_date = models.DateTimeField(null=True, blank=True,
                                         verbose_name=_("creation date"))
    description =models.TextField(null=True, blank=True,
                                  verbose_name=_("sdescription"))
    file = models.FileField(null=False, blank=False, upload_to=calculate_document_path,
                            verbose_name=_("file"))

    class Meta:
        verbose_name = "document"
        verbose_name_plural = "documents"
<|endoftext|>


<commit_before>#!/usr/bin/env python

VIRUSTOTAL_APIKEY = None

from contextlib import closing
from argparse import ArgumentParser
from colorama import init, Fore
from os.path import join
from config import *
from time import time
from vt import VirusTotal
import sqlite3
import signal

init(autoreset=True)

create = ('CREATE TABLE IF NOT EXISTS virus (pkg PRIMARY KEY, id, uploaded, detected)')
select1 = 'SELECT pkg, path FROM download WHERE pkg NOT IN (SELECT pkg FROM virus) LIMIT 1'
select2 = 'SELECT pkg, id FROM virus WHERE detected = -1 AND uploaded < ? LIMIT 1'
insert = 'INSERT INTO virus VALUES (?, ?, ?, -1)'
update = 'UPDATE virus SET detected = ? WHERE pkg = ?'

def exit():
    raise SystemExit

class Checker():

    def __init__(self, basepath):
        self.api = VirusTotal(VIRUSTOTAL_APIKEY)
        self.basepath = basepath

    def scan(self, db):
        with closing(db.cursor()) as cursor:
            selected = cursor.execute(select1).fetchall()
            for pkg, path in selected:
                print Fore.BLUE + 'Uploading %s for scan ...' % pkg
                id = self.api.scan(join(self.basepath, path))
                cursor.execute(insert, (pkg, id, time()))
                db.commit()
        return len(selected)

    def result(self, db):
        with closing(db.cursor()) as cursor:
            selected = cursor.execute(select2, [time() - 3600]).fetchall()
            for pkg, id in selected:
                detected = self.api.get_percent_detected(id)
                cursor.execute(update, (detected, pkg))
                print '{} [{} --> {:.0%} virus]'.format(Fore.GREEN
                    if not detected else Fore.YELLOW, pkg, detected)
        return len(selected)

    def createtable(self, db):
        with closing(db.cursor()) as cursor:
            cursor.execute(create)
            db.commit()

    def checkall(self, dbname):
        with sqlite3.connect(dbname, timeout=10) as db:
            self.createtable(db)
            while True:
                scanned = self.scan(db)
                resulted = self.result(db)
                if not scanned and not resulted:
                    print 'Everything done for now'
                    break
        exit()

if __name__ == '__main__':
    parser = ArgumentParser(description='Check apks with VirusTotal')
    parser.add_argument('DB', help='sqlite3 apps db')
    parser.add_argument('-b', '--basedir', default='.', help='base apk dir')
    args = parser.parse_args()
    signal.signal(signal.SIGINT, exit)
    Checker(args.basedir).checkall(args.DB)

<commit_msg>Scan only files smaller than 32MB<commit_after>#!/usr/bin/env python

VIRUSTOTAL_APIKEY = None

from contextlib import closing
from argparse import ArgumentParser
from colorama import init, Fore
from os.path import join
from config import *
from time import time
from vt import VirusTotal
import sqlite3
import signal

init(autoreset=True)

create = ('CREATE TABLE IF NOT EXISTS virus (pkg PRIMARY KEY, id, uploaded, detected)')
select1 = 'SELECT pkg, path FROM download WHERE pkg NOT IN (SELECT pkg FROM virus) LIMIT 1'
select2 = 'SELECT pkg, id FROM virus WHERE detected = -1 AND uploaded < ? LIMIT 1'
insert = 'INSERT INTO virus VALUES (?, ?, ?, -1)'
update = 'UPDATE virus SET detected = ? WHERE pkg = ?'

def exit():
    raise SystemExit

class Checker():

    def __init__(self, basepath):
        self.api = VirusTotal(VIRUSTOTAL_APIKEY)
        self.basepath = basepath

    def scan(self, db):
        with closing(db.cursor()) as cursor:
            selected = cursor.execute(select1).fetchall()
            for pkg, path in selected:
                print Fore.BLUE + 'Uploading %s for scan ...' % pkg
                path = os.path.abspath(os.path.join(self.basepath, path))
                if os.path.getsize(path) >= 32 * (2 ** 6)
                    print Fore.RED + 'File too big for VirusTotal'
                    continue
                id = self.api.scan()
                cursor.execute(insert, (pkg, id, time()))
                db.commit()
        return len(selected)

    def result(self, db):
        with closing(db.cursor()) as cursor:
            selected = cursor.execute(select2, [time() - 3600]).fetchall()
            for pkg, id in selected:
                detected = self.api.get_percent_detected(id)
                cursor.execute(update, (detected, pkg))
                print '{} [{} --> {:.0%} virus]'.format(Fore.GREEN
                    if not detected else Fore.YELLOW, pkg, detected)
        return len(selected)

    def createtable(self, db):
        with closing(db.cursor()) as cursor:
            cursor.execute(create)
            db.commit()

    def checkall(self, dbname):
        with sqlite3.connect(dbname, timeout=10) as db:
            self.createtable(db)
            while True:
                scanned = self.scan(db)
                resulted = self.result(db)
                if not scanned and not resulted:
                    print 'Everything done for now'
                    break
        exit()

if __name__ == '__main__':
    parser = ArgumentParser(description='Check apks with VirusTotal')
    parser.add_argument('DB', help='sqlite3 apps db')
    parser.add_argument('-b', '--basedir', default='.', help='base apk dir')
    args = parser.parse_args()
    signal.signal(signal.SIGINT, exit)
    Checker(args.basedir).checkall(args.DB)

<|endoftext|>


<commit_before># Test the frozen module defined in frozen.c.
# Currently test_frozen fails:
#   Implementing pep3102(keyword only argument) needs changes in
#   code object, which needs modification to marshal.
#   However, to regenerate hard-coded marshal data in frozen.c,
#   we need to run Tools/freeze/freeze.py, which currently doesn't work
#   because Lib/modulefinder.py cannot handle relative module import
#   This test will keep failing until Lib/modulefinder.py is fixed

from test.test_support import TestFailed
import sys, os

try:
    import __hello__
except ImportError as x:
    raise TestFailed, "import __hello__ failed:" + str(x)

try:
    import __phello__
except ImportError as x:
    raise TestFailed, "import __phello__ failed:" + str(x)

try:
    import __phello__.spam
except ImportError as x:
    raise TestFailed, "import __phello__.spam failed:" + str(x)

if sys.platform != "mac":  # On the Mac this import does succeed.
    try:
        import __phello__.foo
    except ImportError:
        pass
    else:
        raise TestFailed, "import __phello__.foo should have failed"
<commit_msg>Duh.  Delete the outdated comment too.<commit_after># Test the frozen module defined in frozen.c.

from test.test_support import TestFailed
import sys, os

try:
    import __hello__
except ImportError as x:
    raise TestFailed, "import __hello__ failed:" + str(x)

try:
    import __phello__
except ImportError as x:
    raise TestFailed, "import __phello__ failed:" + str(x)

try:
    import __phello__.spam
except ImportError as x:
    raise TestFailed, "import __phello__.spam failed:" + str(x)

if sys.platform != "mac":  # On the Mac this import does succeed.
    try:
        import __phello__.foo
    except ImportError:
        pass
    else:
        raise TestFailed, "import __phello__.foo should have failed"
<|endoftext|>


<commit_before>#coding:utf-8
'''
    PyRESTRedis A Python REST Interface to Redis key/value storage server

 Licensed with Apache Public License
 by AAAI Research Group
 Department of Information Engineering and Computer Science and Mathematics
 University of L'Aquila, ITALY
 http://www.disim.univaq.it

'''

__author__ = 'giodegas'

from flask import Flask, request
from flask_restful import *
from flask_restful import reqparse, abort, Api, Resource
from json import dumps
from redis import StrictRedis

SERVICE_PORT = 8379
REDIS_IP = 'localhost'
HOST_IP = 'localhost'

app = Flask(__name__)
api = Api(app)

parser = reqparse.RequestParser()
# parser.add_argument('task')

class ServiceDiscovery(Resource):
    def get(self):
        return {'REDIS SERVICES': 'INFO, GET, SET, DEL, EXISTS, PUBLISH, KEYS, SADD, SMEMBERS, SREM, HSET, HGET, HGETALL, LPOP, SELECT, /redis....'}

class SetKey(Resource):
    def get(self, key_id, value):
        global R
        out = R.set(key_id, value)
        return {'SET': out}

class SetKeyPost(Resource):
    def post(self):
        parser.add_argument('key_id', type=str)
        parser.add_argument('data', type=str)
        args = parser.parse_args()
        out = R.set(args[0], args[1])
        return {'SET': out}

class GetKey(Resource):
    def get(self, key_id):
        global R
        out = R.get(key_id)
        return {'GET': out}

class DelKey(Resource):
    def get(self, key_id):
        global R
        out = R.delete(key_id)
        return {'DEL': out}

class Info(Resource):
    def get(self):
        global R
        out = R.info()
        return {'INFO': out}

class Keys(Resource):
    def get(self, keyPattern):
        global R
        out = R.keys(keyPattern)
        return {'KEYS': out}

class ExistsKey(Resource):
    def get(self, key_id):
        global R
        out = R.exists(key_id)
        return {'EXISTS': out}

class Sadd(Resource):
    def get(self, key_id, member):
        global R
        out = R.sadd(key_id, member)
        return {'SADD': out}

class Smembers(Resource):
    def get(self, key_id):
        global R
        out = list(R.smembers(key_id))
        return {'SMEMBERS': out}

class Publish(Resource):
    def get(self, channel_id, message):
        global R
        out = R.publish(channel_id, message)
        return dumps({'PUBLISH': out})

class LIndex(Resource):
    def get(self, key_id, index):
        global R
        out = R.lindex(key_id, index)
        return {'LINDEX': out}

class HSet(Resource):
    def get(self, key_id, field, value):
        global R
        out = R.hset(key_id, field, value)
        return {'HSET': out}

class HGet(Resource):
    def get(self, key_id, field):
        global R
        out = R.hget(key_id, field)
        if out and len(out)>4000000:
            out = False
        return {'HGET': out}

class HDel(Resource):
    def get(self, key_id, field):
        global R
        out = R.hdel(key_id, field)
        return {'HDEL': out}

class HExists(Resource):
    def get(self, key_id, field):
        global R
        out = R.hexists(key_id, field)
        return {'HEXISTS': out}

class HGetAll(Resource):
    def get(self, key_id):
        global R
        out = R.hgetall(key_id)
        return {'HGETALL': out}

class SetMemberRemove(Resource):
    def get(self, set_name, member):
        global R
        out = R.srem(set_name, member)
        return {'SREM': out}

class LPop(Resource):
    def get(self, listName):
        global R
        out = R.lpop(listName)
        return {'LPOP': out}

class Generic(Resource):
    def get(self, cmd, param1=None, param2=None, param3=None):
        global R
        cmdStr = 'R.'+ cmd +'('
        if param1:
            cmdStr += "'"+param1+"'"
            if param2:
                cmdStr += ",'"+param2+"'"
                if param3:
                    cmdStr += ",'"+param3+"'"
        cmdStr += ')'
        out = eval(cmdStr)
        return {cmd.upper(): out}

class DBSelect(Resource):
    def get(self, dbNum):
        global R
        R = None
        R = StrictRedis(db=dbNum)
        out = 'ok'
        return {'SELECT': out}

class FlushDB(Resource):
    def get(self, password):
        global R
        if password=='_password_':
            out = R.flushdb()
            return {'FLUSHDB': out}
        else:
            return {'FLUSHDB': False}

# ------------------------------------------------------------

@app.after_request
def after_request(response):
    # to allow to serve pages from the same server, different  port
    response.headers['Access-Control-Allow-Origin'] = 'http://localhost:5000'
    response.headers['Access-Control-Allow-Headers'] = "Origin, X-Requested-With,Content-Type, Accept"
    response.headers['Cache-Control'] = 'no-cache'
    return response

def addCommand(function, command, arguments=None):
    # add a service twice , lower and upper case
    global api
    urlStrUC = command.upper()
    urlStrLC = command.lower()
    if arguments:
        urlStrUC += '/' + arguments
        urlStrLC += '/' + arguments
    api.add_resource(function, urlStrLC, urlStrUC)

@app.route('/set/<string:key_id>', methods=['POST']) #GET requests will be blocked
def json_set(key_id):
    global R
    req_data = request.get_json()
    out = R.set(key_id, dumps(req_data))
    return dumps(out)

if __name__ == '__main__':
    R = StrictRedis(REDIS_IP, 6379, charset="utf-8", decode_responses=True)
    addCommand(ServiceDiscovery, '/')
    # addCommand(SetKey, '/set', '<string:key_id>/<string:value>')
    addCommand(GetKey, '/get','<string:key_id>')
    addCommand(Publish, '/publish','<string:channel_id>/<string:message>')
    addCommand(Info, '/info')
    addCommand(Keys, '/keys','<string:keyPattern>')
    addCommand(ExistsKey, '/exists','<string:key_id>')
    addCommand(Sadd, '/sadd','<string:key_id>/<string:member>')
    addCommand(Smembers, '/smembers','<string:key_id>')
    addCommand(LIndex, '/lindex', '<string:key_id>/<string:index>')
    addCommand(HSet, '/hset', '<string:key_id>/<string:field>/<string:value>')
    addCommand(HGet, '/hget', '<string:key_id>/<string:field>')
    addCommand(HDel, '/hdel', '<string:key_id>/<string:field>')
    addCommand(HGetAll, '/hgetall', '<string:key_id>')
    addCommand(HExists, '/hexists', '<string:key_id>/<string:field>')
    addCommand(DelKey, '/del', '<string:key_id>')
    addCommand(SetMemberRemove, '/srem', '<string:set_name>/<string:member>')
    addCommand(LPop, '/lpop', '<string:listName>')
    addCommand(DBSelect, '/select', '<int:dbNum>')
    addCommand(FlushDB, '/flushdb', '<string:password>')

    #api.add_resource(SetKeyPost, '/set')

    # All other Redis command with up to 3 arguments, all lower case
    api.add_resource(Generic, '/redis/<string:cmd>',
                     '/redis/<string:cmd>/<string:param1>',
                     '/redis/<string:cmd>/<string:param1>/<string:param2>',
                     '/redis/<string:cmd>/<string:param1>/<string:param2>/<string:param3>')

    app.run(debug=True, port=SERVICE_PORT, host=HOST_IP)
<commit_msg>refactor SET as a POST method<commit_after>#coding:utf-8
'''
    PyRESTRedis A Python REST Interface to Redis key/value storage server

 Licensed with Apache Public License
 by AAAI Research Group
 Department of Information Engineering and Computer Science and Mathematics
 University of L'Aquila, ITALY
 http://www.disim.univaq.it

'''

__author__ = 'giodegas'

from flask import Flask, request
from flask_restful import reqparse, Api, Resource
from json import dumps
from redis import StrictRedis

SERVICE_PORT = 8379
REDIS_IP = 'localhost'
HOST_IP = 'localhost'

app = Flask(__name__)
api = Api(app)

class ServiceDiscovery(Resource):
    def get(self):
        return {'REDIS SERVICES': 'INFO, GET, SET, DEL, EXISTS, PUBLISH, KEYS, SADD, SMEMBERS, SREM, HSET, HGET, HGETALL, LPOP, SELECT, /redis....'}

class SetKey(Resource):
    def get(self, key_id, value):
        global R
        out = R.set(key_id, value)
        return {'SET': out}

class GetKey(Resource):
    def get(self, key_id):
        global R
        out = R.get(key_id)
        return {'GET': out}

class DelKey(Resource):
    def get(self, key_id):
        global R
        out = R.delete(key_id)
        return {'DEL': out}

class Info(Resource):
    def get(self):
        global R
        out = R.info()
        return {'INFO': out}

class Keys(Resource):
    def get(self, keyPattern):
        global R
        out = R.keys(keyPattern)
        return {'KEYS': out}

class ExistsKey(Resource):
    def get(self, key_id):
        global R
        out = R.exists(key_id)
        return {'EXISTS': out}

class Sadd(Resource):
    def get(self, key_id, member):
        global R
        out = R.sadd(key_id, member)
        return {'SADD': out}

class Smembers(Resource):
    def get(self, key_id):
        global R
        out = list(R.smembers(key_id))
        return {'SMEMBERS': out}

class Publish(Resource):
    def get(self, channel_id, message):
        global R
        out = R.publish(channel_id, message)
        return dumps({'PUBLISH': out})

class LIndex(Resource):
    def get(self, key_id, index):
        global R
        out = R.lindex(key_id, index)
        return {'LINDEX': out}

class HSet(Resource):
    def get(self, key_id, field, value):
        global R
        out = R.hset(key_id, field, value)
        return {'HSET': out}

class HGet(Resource):
    def get(self, key_id, field):
        global R
        out = R.hget(key_id, field)
        if out and len(out)>4000000:
            out = False
        return {'HGET': out}

class HDel(Resource):
    def get(self, key_id, field):
        global R
        out = R.hdel(key_id, field)
        return {'HDEL': out}

class HExists(Resource):
    def get(self, key_id, field):
        global R
        out = R.hexists(key_id, field)
        return {'HEXISTS': out}

class HGetAll(Resource):
    def get(self, key_id):
        global R
        out = R.hgetall(key_id)
        return {'HGETALL': out}

class SetMemberRemove(Resource):
    def get(self, set_name, member):
        global R
        out = R.srem(set_name, member)
        return {'SREM': out}

class LPop(Resource):
    def get(self, listName):
        global R
        out = R.lpop(listName)
        return {'LPOP': out}

class Generic(Resource):
    def get(self, cmd, param1=None, param2=None, param3=None):
        global R
        cmdStr = 'R.'+ cmd +'('
        if param1:
            cmdStr += "'"+param1+"'"
            if param2:
                cmdStr += ",'"+param2+"'"
                if param3:
                    cmdStr += ",'"+param3+"'"
        cmdStr += ')'
        out = eval(cmdStr)
        return {cmd.upper(): out}

class DBSelect(Resource):
    def get(self, dbNum):
        global R
        R = None
        R = StrictRedis(db=dbNum)
        out = 'ok'
        return {'SELECT': out}

class FlushDB(Resource):
    def get(self, password):
        global R
        if password=='_password_':
            out = R.flushdb()
            return {'FLUSHDB': out}
        else:
            return {'FLUSHDB': False}

# ------------------------------------------------------------

@app.after_request
def after_request(response):
    # to allow to serve pages from the same server, different  port
    response.headers['Access-Control-Allow-Origin'] = 'http://localhost:5000'
    response.headers['Access-Control-Allow-Headers'] = "Origin, X-Requested-With,Content-Type, Accept"
    response.headers['Cache-Control'] = 'no-cache'
    return response

def addCommand(function, command, arguments=None):
    # add a service twice , lower and upper case
    global api
    urlStrUC = command.upper()
    urlStrLC = command.lower()
    if arguments:
        urlStrUC += '/' + arguments
        urlStrLC += '/' + arguments
    api.add_resource(function, urlStrLC, urlStrUC)

@app.route('/set/<string:key_id>', methods=['POST']) #GET requests will be blocked
def json_set(key_id):
    global R
    req_data = request.get_json()
    out = R.set(key_id, dumps(req_data))
    return dumps(out)

if __name__ == '__main__':
    R = StrictRedis(REDIS_IP, 6379, charset="utf-8", decode_responses=True)
    addCommand(ServiceDiscovery, '/')
    # addCommand(SetKey, '/set', '<string:key_id>/<string:value>')
    addCommand(GetKey, '/get','<string:key_id>')
    addCommand(Publish, '/publish','<string:channel_id>/<string:message>')
    addCommand(Info, '/info')
    addCommand(Keys, '/keys','<string:keyPattern>')
    addCommand(ExistsKey, '/exists','<string:key_id>')
    addCommand(Sadd, '/sadd','<string:key_id>/<string:member>')
    addCommand(Smembers, '/smembers','<string:key_id>')
    addCommand(LIndex, '/lindex', '<string:key_id>/<string:index>')
    addCommand(HSet, '/hset', '<string:key_id>/<string:field>/<string:value>')
    addCommand(HGet, '/hget', '<string:key_id>/<string:field>')
    addCommand(HDel, '/hdel', '<string:key_id>/<string:field>')
    addCommand(HGetAll, '/hgetall', '<string:key_id>')
    addCommand(HExists, '/hexists', '<string:key_id>/<string:field>')
    addCommand(DelKey, '/del', '<string:key_id>')
    addCommand(SetMemberRemove, '/srem', '<string:set_name>/<string:member>')
    addCommand(LPop, '/lpop', '<string:listName>')
    addCommand(DBSelect, '/select', '<int:dbNum>')
    addCommand(FlushDB, '/flushdb', '<string:password>')

    #api.add_resource(SetKeyPost, '/set')

    # All other Redis command with up to 3 arguments, all lower case
    api.add_resource(Generic, '/redis/<string:cmd>',
                     '/redis/<string:cmd>/<string:param1>',
                     '/redis/<string:cmd>/<string:param1>/<string:param2>',
                     '/redis/<string:cmd>/<string:param1>/<string:param2>/<string:param3>')

    app.run(debug=True, port=SERVICE_PORT, host=HOST_IP)
<|endoftext|>