-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DO NOT MERGE] Preprocessor #19
base: new-feline
Are you sure you want to change the base?
Changes from 6 commits
3157a46
12dc9d2
5233a88
7dd9f79
c4dfb77
812cb1b
e21620c
ec66127
f00051d
3022bf9
333c108
4b9d8db
e967dde
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
from __future__ import print_function | ||
import re | ||
import logging | ||
import logging_config #to configure logging, no calls needed | ||
from CssTree.CssElement import CssElement | ||
|
||
|
||
|
||
MIN_ZOOM = 1 | ||
MAX_ZOOM = 19 | ||
|
||
|
||
BLOCK_SPLITTER = re.compile(r'([^@{]*)\s*\{(.*?)\}', re.DOTALL | re.MULTILINE) | ||
ZOOM = re.compile(r'(.*?)(\|z[\d\-]*?)?(\[.*)?') #deprecated | ||
ONE_ZOOM = re.compile(r'(\d{1,2})$') | ||
ZOOM_RANGE = re.compile(r'(\d{1,2})-(\d{1,2})$') | ||
ZOOM_TO_MAX = re.compile(r'(\d{1,2})-$') | ||
|
||
|
||
TAG_RE = re.compile(r'(^.*?)[\|\[$:]', re.MULTILINE) | ||
ZOOM_RE = re.compile(r'.*?\|z([\d\-]*?)[\[$:]') | ||
SELECTORS_RE = re.compile(r'(\[.*?\])') | ||
SUB_RE = re.compile(r'.*:(.*)$') | ||
ONE_SELECTOR_RE = re.compile(r'\[(.*?)\]') | ||
|
||
|
||
class BlockSplitter: | ||
""" | ||
Should also be initializeable by a preprocessed file | ||
""" | ||
def __init__(self, preprocessed_blocks, write_to_file=False): | ||
print("Num of input blocks is: {}".format(len(preprocessed_blocks))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Разве это не в лог должно идти? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Убрал вообще |
||
self.blocks = preprocessed_blocks | ||
self.split_blocks = {} # selector : list of attributes | ||
self.write_to_file = write_to_file | ||
self.blocks_by_zoom_level = self.init_blocks_by_zoom_level() | ||
print("Will write to file! {}".format(self.write_to_file)) | ||
|
||
|
||
def init_blocks_by_zoom_level(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Название функции не очень соответсвует тому, что она делает, лучше get или make... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Мне кажется, вполне соответствует. Т.к. я из init часть функционала выношу в отдельную функцию, т.е., одну из переменных инициализирую в отдельной функции. Но в новом варианте обошелся без дополнительной функции вообще. |
||
ret = {} | ||
for i in range(MIN_ZOOM, MAX_ZOOM + 1): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. xrange is better, it does not create sequence. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Уже нету |
||
ret[i] = {} #tag with selectors and subclasses to attributes, selectors must be sorted | ||
return ret | ||
|
||
|
||
def process(self): | ||
self.split_commas() | ||
self.process_blocks_by_zoom_level() | ||
|
||
if self.write_to_file: | ||
self.write() | ||
pass | ||
|
||
def process_blocks_by_zoom_level(self): | ||
for zoom in self.blocks_by_zoom_level: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вроде поправлял. Если где-то не поправил, то, когда будут попадаться, буду заменять. |
||
self.process_zoom_level(zoom, self.blocks_by_zoom_level[zoom]) | ||
|
||
def process_zoom_level(self, zoom, block): | ||
clean_block = [] # another list of tuples | ||
block_keys = sorted(block.keys()) | ||
# block.sort(key=lambda x: x[1]) #sort the tuples by the 0th element | ||
old_block = ("", []) | ||
for tag in block_keys: | ||
attrs = block[tag] | ||
if tag == old_block[0] : | ||
old_block[1].extend(attrs) | ||
else: | ||
if old_block[0]: | ||
clean_block.append(old_block) | ||
old_block = (tag, attrs) | ||
self.blocks_by_zoom_level[zoom] = clean_block | ||
|
||
|
||
def clean_split_by(self, string, separator): | ||
return filter(lambda x: x != "", map(lambda x: x.strip(), string.split(separator))) | ||
|
||
|
||
def all_zooms_in_css_range(self, str_range): | ||
min_zoom = -1 | ||
max_zoom = -1 | ||
|
||
if not str_range: | ||
min_zoom = MIN_ZOOM | ||
max_zoom = MAX_ZOOM | ||
|
||
elif ONE_ZOOM.match(str_range): | ||
min_zoom = int(str_range) | ||
max_zoom = min_zoom | ||
|
||
elif ZOOM_TO_MAX.match(str_range): | ||
min_zoom = int(str_range[:-1]) | ||
max_zoom = MAX_ZOOM | ||
|
||
elif ZOOM_RANGE.match(str_range): | ||
found = ZOOM_RANGE.findall(str_range)[0] | ||
(min_zoom, max_zoom) = map(lambda x: int(x), found) | ||
|
||
if max_zoom < 0 or min_zoom < 0 or max_zoom < min_zoom: | ||
raise Exception("Failed to parse the zoom levels") | ||
|
||
max_zoom = MAX_ZOOM if max_zoom > MAX_ZOOM else max_zoom | ||
min_zoom = MIN_ZOOM if min_zoom < MIN_ZOOM else min_zoom | ||
|
||
ret = [i for i in range(min_zoom, max_zoom + 1)] | ||
|
||
return ret | ||
|
||
|
||
|
||
|
||
def split_keys_by_zoom(self, keys): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4 отступа! Жуть как много There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Промахнулся, это должно быть на строке выше. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Отступы со временем тоже будут уходить. |
||
ret = [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. В "длинных" функциях лучше давать более говорящие имена локальным переменным, |
||
for key in keys: | ||
parts_list = ZOOM.findall(key) | ||
if not parts_list: | ||
print("Unparseable key {}".format(key)) | ||
continue | ||
parts = parts_list[0] | ||
if parts: | ||
selector, zoom = parts[0], (parts[1] if not parts else parts[1][2:]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. как так?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Пофиксил |
||
print(">>>> {} : {}".format(selector, zoom)) | ||
all_zooms = self.all_zooms_in_css_range(zoom) | ||
ret.append(map(lambda x: (selector, x), all_zooms)) | ||
else: | ||
print("Got an unparseable node and zoom level: {}".format(key)) | ||
logging.warning("NOTE THAT THIS TAG HAS BEEN IGNORED AND MUST BE PROCESSED IN THE FUTURE!") | ||
return ret | ||
|
||
|
||
# to be refactored | ||
def split_commas(self): | ||
for block, imported_from in self.blocks: | ||
found = BLOCK_SPLITTER.findall(block) | ||
for entry in found: | ||
keys = self.clean_split_by(entry[0], ",") | ||
attributes = sorted(self.clean_split_by(entry[1], ";")) | ||
|
||
last_attr = "" | ||
clean_attributes = [] | ||
for a in attributes: | ||
if a == last_attr: | ||
logging.warning("Duplicate attribute {} for tag/zoom {} imported from {}".format(a, keys, imported_from)) | ||
continue | ||
clean_attributes.append(a) | ||
|
||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Опять куча отступов. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Буду убирать со временем. По-моему, кстати, везде поправил |
||
for key in keys: | ||
elements = self.css_key_factory(key) | ||
|
||
for element in elements: | ||
subclass = "::{}".format(element.subclass) if element.subclass else "" | ||
resulting_tag = "{}{}{}".format(element.tag, "".join(sorted(element.selectors)), subclass) | ||
|
||
if resulting_tag in self.blocks_by_zoom_level[element.zoom]: | ||
filtered_attributes = [] | ||
for a in clean_attributes: | ||
if a in self.blocks_by_zoom_level[element.zoom][resulting_tag]: | ||
print("Duplicate attribute {} for tag {} on zoom {} imported from {}".format(a, resulting_tag, element.zoom, imported_from)) | ||
else: | ||
filtered_attributes.append(a) | ||
|
||
self.blocks_by_zoom_level[element.zoom][resulting_tag].update(self.map_attrs_to_import_source(filtered_attributes, imported_from)) | ||
else: | ||
self.blocks_by_zoom_level[element.zoom][resulting_tag] = self.map_attrs_to_import_source(clean_attributes, imported_from) | ||
|
||
|
||
def map_attrs_to_import_source(self, attributes, imported_from): | ||
return dict(map(lambda x: (x, imported_from), attributes)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Пока не трогал. |
||
|
||
|
||
def write(self): | ||
print("Writing split blocks by zoom, num blocks {}".format(len(self.blocks_by_zoom_level))) | ||
with open("../../out/split_by_commas.mapcss", "w") as out_file: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use os.path.join There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Да, подобные штуки будут заменяться с хардкода на параметры. |
||
for zoom in sorted(self.blocks_by_zoom_level.keys()): | ||
blocks = self.blocks_by_zoom_level[zoom] | ||
# for zoom, blocks in self.blocks_by_zoom_level: | ||
out_file.write(" /* ===== ZOOM {} ===== */\n\n".format(zoom)) | ||
|
||
for tag, attrs in blocks: | ||
out_file.write("{} {{\n".format(tag)) | ||
for attr in attrs: | ||
out_file.write(" {}; /* == {} == */\n".format(attr, attrs[attr])) | ||
# out_file.write(attrs) | ||
out_file.write("}\n\n") | ||
|
||
|
||
def css_key_factory(self, str_key): | ||
# type: (str) -> [CssElement] | ||
tag_list = TAG_RE.findall(str_key) | ||
tag = tag_list[0] if tag_list else str_key | ||
|
||
zoom_list = ZOOM_RE.findall(str_key) | ||
zoom = zoom_list[0] if zoom_list else "" | ||
|
||
# if "][" in str_key: | ||
# print("Str key contains ][") | ||
|
||
selectors_list = SELECTORS_RE.findall(str_key) | ||
# selectors = selectors_list[0] if selectors_list else "" | ||
|
||
str_key = TAG_RE.sub("", str_key) | ||
str_key = ZOOM_RE.sub("", str_key) | ||
str_key = SELECTORS_RE.sub("", str_key) | ||
|
||
subclass_list = SUB_RE.findall(str_key) | ||
subclass = subclass_list[0] if subclass_list else "" | ||
all_zooms = self.all_zooms_in_css_range(zoom) | ||
ret = map(lambda z: CssElement(tag, z, selectors_list, subclass), all_zooms) | ||
return ret | ||
|
||
|
||
|
||
|
||
|
||
|
||
if __name__ == "__main__": | ||
blockSplitter = BlockSplitter([]) | ||
# print(blockSplitter.all_zooms_in_css_range("10")) | ||
# print(blockSplitter.all_zooms_in_css_range("10-")) | ||
# print(blockSplitter.all_zooms_in_css_range("10-12")) | ||
# print(blockSplitter.all_zooms_in_css_range("10-25")) | ||
|
||
# print(blockSplitter.split_key_by_components("*::*")) | ||
# print(blockSplitter.split_key_by_components("*")) | ||
# print(blockSplitter.split_key_by_components("*|z12")) | ||
# print(blockSplitter.split_key_by_components("*::int_name ")) | ||
# print(blockSplitter.split_key_by_components("line|z5[highway=world_level]")) | ||
# print(blockSplitter.css_key_factory("line|z17-18[highway=footway][tunnel?]::tunnelBackground")) | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from __future__ import print_function | ||
|
||
import logging | ||
import logging.config | ||
|
||
|
||
class CssElement: | ||
def __init__(self, tag, zoom, selectors, subclass): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/subclass/css_subclass/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Подумаю |
||
self.tag = tag | ||
self.zoom = zoom | ||
self.selectors = selectors #[] | ||
self.subclass = subclass | ||
|
||
def __repr__(self): | ||
return "{}|z{}::{}".format(self.tag, self.zoom, self.subclass) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add newline |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from __future__ import print_function | ||
|
||
import logging | ||
import CssElement | ||
|
||
|
||
|
||
|
||
class CssTree: | ||
def __init__(self, min_zoom=1, max_zoom=19): | ||
self.subtrees_by_zoom = {} | ||
for i in range(min_zoom, max_zoom + 1): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. xrange There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. По-моему, поменял на какой-то однострочник |
||
self.subtrees_by_zoom[i] = CssSubtree() | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. отступ, кажется, не нужен, да и pass тоже |
||
pass | ||
|
||
def add(self, csselement): | ||
self.subtrees_by_zoom[csselement.zoom].add(csselement) | ||
a = CssElement("a", "b", "c", "d") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a is unused There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Делался для дебага, по-моему, убрал |
||
|
||
|
||
|
||
|
||
class CssSubtree: | ||
def __init__(self): | ||
self.branches_by_tag = {} | ||
pass | ||
|
||
def add(self, csselement): | ||
pass | ||
|
||
|
||
class CssNode: | ||
def __init__(self): | ||
pass | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. newline There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ок |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
В докстрингах хорошо писать документацию к классу, а это больше похоже на коммент.