Example #1
0
def parse_settings(settings, conversion_map={}, defaults={}, required=(),
                   prefix=None, strip_prefix=True):
    """Convert the values of ``settings``.

    To convert only a subset of the settings, pass ``prefix``; only the
    settings with a key matching ``prefix`` will be returned (see
    :func:`get_items_with_key_prefix` for details).

    Settings passed via ``defaults`` will be added if they're not
    already present in ``settings`` (and they'll be converted too).

    Required fields can be listed in ``required``. If any required
    fields are missing, a ``ValueError`` will be raised.

    For each setting...

        - If the key for the setting specifies a converter via the
          ``(converter)key`` syntax, the specified converter will be
          called to convert its value (the converter must be a builtin
          or a function from :mod:`tangled.converters`).

        - If the key for the setting is in ``conversion_map``, the
          function it maps to will be used to convert its value.

        - If the special key '*' is in ``conversion_map``, the function
          it maps to will be used to convert the setting.

        - Otherwise, the value will be used as is (i.e., as a string).

    The original ``settings`` dict will not be changed.

    """
    parsed_settings = {}
    if prefix is not None:
        settings = get_items_with_key_prefix(settings, prefix, strip_prefix)
    for k, v in defaults.items():
        settings.setdefault(k, v)
    for k, v in settings.items():
        if isinstance(v, str):
            match = CONVERTER_KEY_RE.search(k)
            if match:
                k = match.group('k')
                converter = match.group('converter')
                converter = converters.get_converter(converter)
            elif k in conversion_map:
                converter = converters.get_converter(conversion_map[k])
            elif '*' in conversion_map:
                converter = converters.get_converter(conversion_map['*'])
            else:
                converter = lambda v: v
            v = converter(v)
        parsed_settings[k] = v
    if required:
        check_required(parsed_settings, required)
    return parsed_settings
Example #2
0
    def process_ways(self):
        """Process ways"""
        get_tag = self.get_tag
        normalize_street_name = self.normalize_street_name

        bool_converter = get_converter('bool')

        # TODO: Change oneway from bool to (-1, 0, 1)?
        #        0 => not a one way
        #        1 => one way in node order
        #       -1 => one way in reverse node order
        def oneway_converter(v):
            try:
                return bool_converter(v)
            except ValueError:
                return True

        way_id = 0
        rows = []
        empty_tags = []

        def insert():
            self.engine.execute(STREET_TABLE.insert(), rows)
            rows.clear()

        self.engine.execute(STREET_TABLE.delete())

        for el in self.iter_ways():
            osm_id = el['id']
            node_ids = el['nodes']
            tags = el.get('tags', empty_tags)

            name = get_tag(tags, 'name', normalize_street_name)
            highway = get_tag(tags, 'highway')
            bicycle = get_tag(tags, 'bicycle')
            cycleway = get_tag(tags, 'cycleway')
            foot = get_tag(tags, 'foot')
            sidewalk = get_tag(tags, 'sidewalk')

            oneway = get_tag(tags, 'oneway', oneway_converter, False)
            oneway_bicycle = get_tag(tags, 'oneway:bicycle', oneway_converter)
            if oneway_bicycle is None:
                oneway_bicycle = get_tag(tags, 'bicycle:oneway', oneway_converter)
                if oneway_bicycle is None:
                    oneway_bicycle = oneway

            node_q = NODE_TABLE.select()
            node_q = node_q.where(NODE_TABLE.c.id.in_(node_ids))
            node_map = {n.id: n for n in self.engine.execute(node_q)}
            nodes = [node_map[i] for i in node_ids]

            way = []
            ways = []
            last_i = len(nodes) - 1
            for i, node in enumerate(nodes):
                way.append(node)
                if len(way) > 1 and node.is_intersection:
                    ways.append(way)
                    if i < last_i:
                        way = [node]

            for i, way in enumerate(ways):
                way_id += 1
                start_node_id = way[0].id
                end_node_id = way[-1].id
                geom = LineString((n.geom.coords[0] for n in way))
                rows.append({
                    'id': way_id,
                    'osm_id': osm_id,
                    'osm_seq': i,
                    'geom': geom,
                    'start_node_id': start_node_id,
                    'end_node_id': end_node_id,
                    'name': name,
                    'highway': highway,
                    'bicycle': bicycle,
                    'cycleway': cycleway,
                    'foot': foot,
                    'sidewalk': sidewalk,
                    'oneway': oneway,
                    'oneway_bicycle': oneway_bicycle,
                })

            if len(rows) > 500:
                insert()

        if rows:
            insert()
Example #3
0
    def __init__(self, name, factory, path, methods=(), method_name=None,
                 add_slash=False):
        if not path.startswith('/'):
            path = '/' + path

        if path == '/':
            add_slash = False
        else:
            if path.endswith('/'):
                add_slash = True
            elif add_slash:
                path = '{}/'.format(path)

        self.name = name
        self.factory = factory
        self.path = path  # normalized path
        self.methods = set(as_tuple(methods, sep=','))
        self.method_name = method_name
        self.add_slash = add_slash

        urlvars_info = {}
        path_regex = []
        format_string = []
        i = 0

        for match in re.finditer(self.urlvar_regex, path):
            info = match.groupdict()
            identifier = info['identifier']

            if identifier in urlvars_info:
                raise ValueError('{} already present'.format(identifier))

            regex = info['regex'] or r'[\w-]+'

            converter = info['converter']
            if converter:
                if ':' in converter:
                    converter = load_object(converter)
                else:
                    converter = get_converter(converter)
            else:
                converter = str

            urlvars_info[identifier] = {'regex': regex, 'converter': converter}

            # Get the non-matching part of the string after the previous
            # match and before the current match.
            s, e = match.span()
            if i != s:
                before_match = path[i:s]
                path_regex.append(before_match)
                format_string.append(before_match)
            i = e

            path_regex.append(r'(?P<{}>{})'.format(identifier, regex))
            format_string.extend(('{', identifier, '}'))

        if i != len(path):
            remainder = path[i:]
            path_regex.append(remainder)
            format_string.append(remainder)

        path_regex = ''.join(path_regex)

        self.urlvars_info = urlvars_info
        self.segments = path_regex.strip('/').split('/')
        self.format_string = ''.join(format_string)

        if add_slash:
            path_regex = r'{}(?:/?)'.format(path_regex.rstrip('/'))

        self.path_regex = path_regex