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
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()
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