heavy profilign + autopep8

This commit is contained in:
Darafei Praliaskouski 2013-02-27 23:51:10 +03:00
parent c82f301853
commit 506426b376
6 changed files with 856 additions and 851 deletions

View file

@ -20,210 +20,210 @@ import re
INVERSIONS = {"eq":"ne", "true":"false", "set":"unset", "<":">=", ">":"<="}
in2 = {}
for a,b in INVERSIONS.iteritems():
in2[b] = a
in2[b] = a
INVERSIONS.update(in2)
del in2
class Condition:
def __init__(self, typez, params):
self.type=typez # eq, regex, lt, gt etc.
if type(params) == type(str()):
params = (params,)
self.params=params # e.g. ('highway','primary')
if typez == "regex":
self.regex = re.compile(self.params[0], re.I)
def __init__(self, typez, params):
self.type=typez # eq, regex, lt, gt etc.
if type(params) == type(str()):
params = (params,)
self.params=params # e.g. ('highway','primary')
if typez == "regex":
self.regex = re.compile(self.params[0], re.I)
self.compiled_regex = ""
self.compiled_regex = ""
def get_interesting_tags(self):
if self.params[0][:2] == "::":
return []
return set([self.params[0]])
def get_interesting_tags(self):
if self.params[0][:2] == "::":
return []
return set([self.params[0]])
def get_numerics(self):
if self.type in ("<", ">", ">=", "<="):
return self.params[0]
else:
return False
def get_numerics(self):
if self.type in ("<", ">", ">=", "<="):
return self.params[0]
else:
return False
def test(self, tags):
"""
Test a hash against this condition
"""
t = self.type
params = self.params
if t == 'eq': # don't compare tags against sublayers
if params[0][:2] == "::":
return params[1]
try:
if t == 'eq':
return tags[params[0]]==params[1]
if t == 'ne':
return tags.get(params[0], "")!=params[1]
if t == 'regex':
return bool(self.regex.match(tags[params[0]]))
if t == 'true':
return tags.get(params[0]) == 'yes'
if t == 'untrue':
return tags.get(params[0]) == 'no'
if t == 'set':
if params[0] in tags:
return tags[params[0]] != ''
return False
if t == 'unset':
if params[0] in tags:
return tags[params[0]] == ''
return True
def test(self, tags):
"""
Test a hash against this condition
"""
t = self.type
params = self.params
if t == 'eq': # don't compare tags against sublayers
if params[0][:2] == "::":
return params[1]
try:
if t == 'eq':
return tags[params[0]]==params[1]
if t == 'ne':
return tags.get(params[0], "")!=params[1]
if t == 'regex':
return bool(self.regex.match(tags[params[0]]))
if t == 'true':
return tags.get(params[0]) == 'yes'
if t == 'untrue':
return tags.get(params[0]) == 'no'
if t == 'set':
if params[0] in tags:
return tags[params[0]] != ''
return False
if t == 'unset':
if params[0] in tags:
return tags[params[0]] == ''
return True
if t == '<':
return (Number(tags[params[0]])< Number(params[1]))
if t == '<=':
return (Number(tags[params[0]])<=Number(params[1]))
if t == '>':
return (Number(tags[params[0]])> Number(params[1]))
if t == '>=':
return (Number(tags[params[0]])>=Number(params[1]))
except KeyError:
pass
return False;
def inverse(self):
"""
Get a not-A for condition A
"""
t = self.type
params = self.params
try:
return Condition(INVERSIONS[t], params)
if t == 'regex':
### FIXME: learn how to invert regexes
return Condition("regex", params)
except KeyError:
pass
return self;
if t == '<':
return (Number(tags[params[0]])< Number(params[1]))
if t == '<=':
return (Number(tags[params[0]])<=Number(params[1]))
if t == '>':
return (Number(tags[params[0]])> Number(params[1]))
if t == '>=':
return (Number(tags[params[0]])>=Number(params[1]))
except KeyError:
pass
return False;
def inverse(self):
"""
Get a not-A for condition A
"""
t = self.type
params = self.params
try:
return Condition(INVERSIONS[t], params)
if t == 'regex':
### FIXME: learn how to invert regexes
return Condition("regex", params)
except KeyError:
pass
return self;
def get_sql(self):
#params = [re.escape(x) for x in self.params]
params = self.params
t = self.type
if t == 'eq': # don't compare tags against sublayers
if params[0][:2] == "::":
return ("","")
try:
if t == 'eq':
return params[0], '"%s" = \'%s\''%(params[0], params[1])
if t == 'ne':
return params[0], '("%s" != \'%s\' or "%s" IS NULL)'%(params[0], params[1],params[0])
if t == 'regex':
return params[0], '"%s" ~ \'%s\''%(params[0],params[1].replace("'","\\'"))
if t == 'true':
return params[0], '"%s" = \'yes\''%(params[0])
if t == 'untrue':
return params[0], '"%s" = \'no\''%(params[0])
if t == 'set':
return params[0], '"%s" IS NOT NULL'%(params[0])
if t == 'unset':
return params[0], '"%s" IS NULL'%(params[0])
if t == '<':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) &lt; %s ELSE false END) """%(params[0],params[0],params[1])
if t == '<=':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) &lt;= %s ELSE false END)"""%(params[0],params[0],params[1])
if t == '>':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) > %s ELSE false END) """%(params[0],params[0],params[1])
if t == '>=':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) >= %s ELSE false END) """%(params[0],params[0],params[1])
except KeyError:
pass
def get_mapnik_filter(self):
#params = [re.escape(x) for x in self.params]
params = self.params
t = self.type
if t == 'eq': # don't compare tags against sublayers
if params[0][:2] == "::":
return ''
try:
if t == 'eq':
return '[%s] = \'%s\''%(params[0], params[1])
if t == 'ne':
return 'not([%s] = \'%s\')'%(params[0], params[1])
if t == 'regex':
return '[%s].match(\'%s\')'%(params[0], params[1].replace("'","\\'"))
if t == 'true':
return '[%s] = \'yes\''%(params[0])
if t == 'untrue':
return '[%s] = \'no\''%(params[0])
if t == 'set':
return '[%s] != \'\''%(params[0])
if t == 'unset':
return 'not([%s] != \'\')'%(params[0])
def get_sql(self):
#params = [re.escape(x) for x in self.params]
params = self.params
t = self.type
if t == 'eq': # don't compare tags against sublayers
if params[0][:2] == "::":
return ("","")
try:
if t == 'eq':
return params[0], '"%s" = \'%s\''%(params[0], params[1])
if t == 'ne':
return params[0], '("%s" != \'%s\' or "%s" IS NULL)'%(params[0], params[1],params[0])
if t == 'regex':
return params[0], '"%s" ~ \'%s\''%(params[0],params[1].replace("'","\\'"))
if t == 'true':
return params[0], '"%s" = \'yes\''%(params[0])
if t == 'untrue':
return params[0], '"%s" = \'no\''%(params[0])
if t == 'set':
return params[0], '"%s" IS NOT NULL'%(params[0])
if t == 'unset':
return params[0], '"%s" IS NULL'%(params[0])
if t == '<':
return '[%s__num] &lt; %s'%(params[0], float(params[1]))
if t == '<=':
return '[%s__num] &lt;= %s'%(params[0], float(params[1]))
if t == '>':
return '[%s__num] &gt; %s'%(params[0], float(params[1]))
if t == '>=':
return '[%s__num] &gt;= %s'%(params[0], float(params[1]))
#return ""
except KeyError:
pass
def __repr__(self):
return "%s %s "%(self.type, repr(self.params))
def __eq__(self, a):
return (self.params == a.params) and (self.type == a.type)
if t == '<':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) &lt; %s ELSE false END) """%(params[0],params[0],params[1])
if t == '<=':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) &lt;= %s ELSE false END)"""%(params[0],params[0],params[1])
if t == '>':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) > %s ELSE false END) """%(params[0],params[0],params[1])
if t == '>=':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) >= %s ELSE false END) """%(params[0],params[0],params[1])
except KeyError:
pass
def get_mapnik_filter(self):
#params = [re.escape(x) for x in self.params]
params = self.params
t = self.type
if t == 'eq': # don't compare tags against sublayers
if params[0][:2] == "::":
return ''
try:
if t == 'eq':
return '[%s] = \'%s\''%(params[0], params[1])
if t == 'ne':
return 'not([%s] = \'%s\')'%(params[0], params[1])
if t == 'regex':
return '[%s].match(\'%s\')'%(params[0], params[1].replace("'","\\'"))
if t == 'true':
return '[%s] = \'yes\''%(params[0])
if t == 'untrue':
return '[%s] = \'no\''%(params[0])
if t == 'set':
return '[%s] != \'\''%(params[0])
if t == 'unset':
return 'not([%s] != \'\')'%(params[0])
def and_with(self, c2):
"""
merges two rules with AND.
"""
#TODO: possible other minimizations
if c2.params[0] == self.params[0]:
if c2.params == self.params:
if c2.type == INVERSIONS[self.type]: # for example, eq AND ne = 0
return False
if c2.type == self.type:
return (self,)
if t == '<':
return '[%s__num] &lt; %s'%(params[0], float(params[1]))
if t == '<=':
return '[%s__num] &lt;= %s'%(params[0], float(params[1]))
if t == '>':
return '[%s__num] &gt; %s'%(params[0], float(params[1]))
if t == '>=':
return '[%s__num] &gt;= %s'%(params[0], float(params[1]))
#return ""
except KeyError:
pass
def __repr__(self):
return "%s %s "%(self.type, repr(self.params))
def __eq__(self, a):
return (self.params == a.params) and (self.type == a.type)
if self.type == ">=" and c2.type == "<=": # a<=2 and a>=2 --> a=2
return (Condition ("eq", self.params),)
if self.type == "<=" and c2.type == ">=":
return (Condition ("eq", self.params),)
if self.type == ">" and c2.type == "<":
return False
if self.type == "<" and c2.type == ">":
return False
def and_with(self, c2):
"""
merges two rules with AND.
"""
#TODO: possible other minimizations
if c2.params[0] == self.params[0]:
if c2.params == self.params:
if c2.type == INVERSIONS[self.type]: # for example, eq AND ne = 0
return False
if c2.type == self.type:
return (self,)
if c2.type == "eq" and self.type in ("ne", "<", ">"):
if c2.params[1] != self.params[1]:
return (c2,)
if self.type == "eq" and c2.type in ("ne", "<", ">"):
if c2.params[1] != self.params[1]:
return (self,)
if self.type == "eq" and c2.type == "eq":
if c2.params[1] != self.params[1]:
return False
if c2.type == "set" and self.type in ("eq","ne","regex", "<", "<=", ">", ">="): # a is set and a == b -> a == b
return (self,)
if c2.type == "unset" and self.type in ("eq","ne","regex", "<", "<=", ">", ">="): # a is unset and a == b -> impossible
return False
if self.type == "set" and c2.type in ("eq","ne","regex", "<", "<=", ">", ">="):
return (c2,)
if self.type == "unset" and c2.type in ("eq","ne","regex", "<", "<=", ">", ">="):
return False
if self.type == ">=" and c2.type == "<=": # a<=2 and a>=2 --> a=2
return (Condition ("eq", self.params),)
if self.type == "<=" and c2.type == ">=":
return (Condition ("eq", self.params),)
if self.type == ">" and c2.type == "<":
return False
if self.type == "<" and c2.type == ">":
return False
if c2.type == "eq" and self.type in ("ne", "<", ">"):
if c2.params[1] != self.params[1]:
return (c2,)
if self.type == "eq" and c2.type in ("ne", "<", ">"):
if c2.params[1] != self.params[1]:
return (self,)
if self.type == "eq" and c2.type == "eq":
if c2.params[1] != self.params[1]:
return False
if c2.type == "set" and self.type in ("eq","ne","regex", "<", "<=", ">", ">="): # a is set and a == b -> a == b
return (self,)
if c2.type == "unset" and self.type in ("eq","ne","regex", "<", "<=", ">", ">="): # a is unset and a == b -> impossible
return False
if self.type == "set" and c2.type in ("eq","ne","regex", "<", "<=", ">", ">="):
return (c2,)
if self.type == "unset" and c2.type in ("eq","ne","regex", "<", "<=", ">", ">="):
return False
return self, c2
return self, c2
def Number(tt):
"""
Wrap float() not to produce exceptions
"""
try:
return float(tt)
except ValueError:
return 0
"""
Wrap float() not to produce exceptions
"""
try:
return float(tt)
except ValueError:
return 0

View file

@ -18,157 +18,157 @@
NONE = ""
class Eval():
def __init__(self, s='eval()'):
"""
Parse expression and convert it into Python
"""
s = s.strip()[5:-1].strip()
self.expr_text = s
try:
self.expr = compile (s, "MapCSS expression", "eval")
except:
#print "Can't compile %s" % s
self.expr = compile ("0", "MapCSS expression", "eval")
def __init__(self, s='eval()'):
"""
Parse expression and convert it into Python
"""
s = s.strip()[5:-1].strip()
self.expr_text = s
try:
self.expr = compile (s, "MapCSS expression", "eval")
except:
#print "Can't compile %s" % s
self.expr = compile ("0", "MapCSS expression", "eval")
def extract_tags(self):
"""
Extracts list of tags that might be used in calculation
"""
def fake_compute(*x):
"""
Perform a fake computation. Always computes all the parameters, always returns 0.
WARNING: Might not cope with complex statements.
"""
for t in x:
q = x
return 0
tags = set([])
#print self.expr_text
def extract_tags(self):
"""
Extracts list of tags that might be used in calculation
"""
def fake_compute(*x):
"""
Perform a fake computation. Always computes all the parameters, always returns 0.
WARNING: Might not cope with complex statements.
"""
for t in x:
q = x
return 0
tags = set([])
#print self.expr_text
a = eval(self.expr,{},{
"tag":lambda x: max([tags.add(x), " "]),
"prop": lambda x: "",
"num": lambda x: 0,
"metric": fake_compute,
"zmetric": fake_compute,
"str": lambda x: "",
"any": fake_compute,
"min": fake_compute,
"max": fake_compute,
})
a = eval(self.expr,{},{
"tag":lambda x: max([tags.add(x), " "]),
"prop": lambda x: "",
"num": lambda x: 0,
"metric": fake_compute,
"zmetric": fake_compute,
"str": lambda x: "",
"any": fake_compute,
"min": fake_compute,
"max": fake_compute,
})
return tags
return tags
def compute(self, tags={}, props = {}, xscale = 1., zscale = 0.5 ):
"""
Compute this eval()
"""
for k,v in tags.iteritems():
try:
tag[k] = float(v)
except:
pass
try:
return str(eval(self.expr, {}, {
"tag":lambda x: tags.get(x,""),
"prop":lambda x: props.get(x,""),
"num": m_num,
"metric": lambda x: m_metric(x, xscale),
"zmetric": lambda x: m_metric(x, zscale),
"str": str,
"any": m_any,
"min": m_min,
"max": m_max,
"cond": m_cond,
"boolean": m_boolean
}))
except:
return ""
def __repr__(self):
return "eval(%s)"%repr(self.expr)
def compute(self, tags={}, props = {}, xscale = 1., zscale = 0.5 ):
"""
Compute this eval()
"""
for k,v in tags.iteritems():
try:
tag[k] = float(v)
except:
pass
try:
return str(eval(self.expr, {}, {
"tag":lambda x: tags.get(x,""),
"prop":lambda x: props.get(x,""),
"num": m_num,
"metric": lambda x: m_metric(x, xscale),
"zmetric": lambda x: m_metric(x, zscale),
"str": str,
"any": m_any,
"min": m_min,
"max": m_max,
"cond": m_cond,
"boolean": m_boolean
}))
except:
return ""
def __repr__(self):
return "eval(%s)"%self.expr_text
def m_boolean(expr):
expr = str(expr)
if expr in ("", "0", "no", "false", "False"):
return False
else:
return True
expr = str(expr)
if expr in ("", "0", "no", "false", "False"):
return False
else:
return True
def m_cond(why, yes, no):
if m_boolean(why):
return yes
else:
return no
if m_boolean(why):
return yes
else:
return no
def m_min(*x):
"""
min() MapCSS Feature
"""
try:
return min([m_num(t) for t in x])
except:
return 0
"""
min() MapCSS Feature
"""
try:
return min([m_num(t) for t in x])
except:
return 0
def m_max(*x):
"""
max() MapCSS Feature
"""
try:
return max([m_num(t) for t in x])
except:
return 0
"""
max() MapCSS Feature
"""
try:
return max([m_num(t) for t in x])
except:
return 0
def m_any(*x):
"""
any() MapCSS feature
"""
for t in x:
if t:
return t
else:
return ""
"""
any() MapCSS feature
"""
for t in x:
if t:
return t
else:
return ""
def m_num(x):
"""
num() MapCSS feature
"""
try:
return float(str(x))
except ValueError:
return 0
def m_metric(x, t):
"""
metric() and zmetric() function.
"""
x = str(x)
try:
return float(x)*float(t)
except:
"Heuristics."
# FIXME: add ft, m and friends
x = x.strip()
"""
num() MapCSS feature
"""
try:
if x[-2:] in ("cm", "CM", "см"):
return float(x[0:-2])*float(t)/100
if x[-2:] in ("mm", "MM", "мм"):
return float(x[0:-2])*float(t)/1000
if x[-1] in ("m", "M", "м"):
return float(x[0:-1])*float(t)
return float(str(x))
except ValueError:
return 0
def m_metric(x, t):
"""
metric() and zmetric() function.
"""
x = str(x)
try:
return float(x)*float(t)
except:
return ""
"Heuristics."
# FIXME: add ft, m and friends
x = x.strip()
try:
if x[-2:] in ("cm", "CM", "см"):
return float(x[0:-2])*float(t)/100
if x[-2:] in ("mm", "MM", "мм"):
return float(x[0:-2])*float(t)/1000
if x[-1] in ("m", "M", "м"):
return float(x[0:-1])*float(t)
except:
return ""
#def str(x):
#"""
#str() MapCSS feature
#"""
#return __builtins__.str(x)
#"""
#str() MapCSS feature
#"""
#return __builtins__.str(x)
if __name__ == "__main__":
a = Eval(""" eval( any( metric(tag("height")), metric ( num(tag("building:levels")) * 3), metric("1m"))) """)
print repr(a)
print a.compute({"building:levels":"3"})
print a.extract_tags()
a = Eval(""" eval( any( metric(tag("height")), metric ( num(tag("building:levels")) * 3), metric("1m"))) """)
print repr(a)
print a.compute({"building:levels":"3"})
print a.extract_tags()

View file

@ -18,92 +18,92 @@
class Rule():
def __init__(self, s=''):
self.conditions = []
#self.isAnd = True
self.minZoom = 0
self.maxZoom = 19
if s == "*":
s = ""
self.subject = s # "", "way", "node" or "relation"
def __init__(self, s=''):
self.conditions = []
#self.isAnd = True
self.minZoom = 0
self.maxZoom = 19
if s == "*":
s = ""
self.subject = s # "", "way", "node" or "relation"
def __repr__(self):
return "%s|z%s-%s %s"%(self.subject, self.minZoom, self.maxZoom, self.conditions)
def __repr__(self):
return "%s|z%s-%s %s"%(self.subject, self.minZoom, self.maxZoom, self.conditions)
def test(self, obj, tags, zoom):
if not self.test_zoom(zoom):
return False
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, tags):
return False
subpart = "::default"
for condition in self.conditions:
res = condition.test(tags)
if not res:
def test(self, obj, tags, zoom):
if not ((zoom >= self.minZoom) and (zoom <= self.maxZoom)):
return False
if type(res) != bool:
subpart = res
return subpart
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, tags):
return False
subpart = "::default"
for condition in self.conditions:
res = condition.test(tags)
if not res:
return False
if type(res) != bool:
subpart = res
return subpart
def test_zoom(self, zoom):
return (zoom >= self.minZoom) and (zoom <= self.maxZoom)
def test_zoom(self, zoom):
return (zoom >= self.minZoom) and (zoom <= self.maxZoom)
def get_interesting_tags(self, obj, zoom):
if obj:
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, {}):
return set()
def get_interesting_tags(self, obj, zoom):
if obj:
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, {}):
return set()
if zoom and not self.test_zoom(zoom):
return set()
if zoom and not self.test_zoom(zoom):
return set()
a = set()
for condition in self.conditions:
a.update(condition.get_interesting_tags())
return a
a = set()
for condition in self.conditions:
a.update(condition.get_interesting_tags())
return a
def get_numerics(self):
a = set()
for condition in self.conditions:
a.add(condition.get_numerics())
a.discard(False)
return a
def get_numerics(self):
a = set()
for condition in self.conditions:
a.add(condition.get_numerics())
a.discard(False)
return a
def get_sql_hints(self, obj, zoom):
if obj:
if (self.subject!='') and not _test_feature_compatibility(obj, self.subject, {":area":"yes"}):
return set()
if not self.test_zoom(zoom):
return set()
a = set()
b = set()
for condition in self.conditions:
q = condition.get_sql()
if q:
if q[1]:
a.add(q[0])
b.add(q[1])
b = " AND ".join(b)
return a,b
def get_sql_hints(self, obj, zoom):
if obj:
if (self.subject!='') and not _test_feature_compatibility(obj, self.subject, {":area":"yes"}):
return set()
if not self.test_zoom(zoom):
return set()
a = set()
b = set()
for condition in self.conditions:
q = condition.get_sql()
if q:
if q[1]:
a.add(q[0])
b.add(q[1])
b = " AND ".join(b)
return a,b
def _test_feature_compatibility (f1, f2, tags={}):
"""
Checks if feature of type f1 is compatible with f2.
"""
if f2 == f1:
return True
return True
if f2 not in ("way", "area", "line"):
return False
elif f2 == "way" and f1 == "line":
return True
return True
elif f2 == "way" and f1 == "area":
return True
elif f2 == "area" and f1 in ("way", "area", "POLYGON"):
return True
elif f2 == "area" and f1 in ("way", "area"):
# if ":area" in tags:
return True
# else:
# return False
elif f2 == "line" and f1 in ("way", "line", "LINESTRING"):
return True
elif f2 == "point" and f1 in ("node", "POINT"):
return True
elif f2 == "line" and f1 in ("way", "line"):
return True
else:
return False
return False
#print f1, f2, True
return True
return True

View file

@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
from Rule import Rule
from webcolors.webcolors import whatever_to_cairo as colorparser
@ -22,225 +22,233 @@ from webcolors.webcolors import cairo_to_hex
from Eval import Eval
class StyleChooser:
"""
A StyleChooser object is equivalent to one CSS selector+declaration.
Its ruleChains property is an array of all the selectors, which would
traditionally be comma-separated. For example:
h1, h2, h3 em
is three ruleChains.
Each ruleChain is itself an array of nested selectors. So the above
example would roughly be encoded as:
[[h1],[h2],[h3,em]]
^^ ^^ ^^ ^^ each of these is a Rule
The styles property is an array of all the style objects to be drawn
if any of the ruleChains evaluate to true.
"""
def __repr__(self):
return "{(%s) : [%s] }\n"%(self.ruleChains, self.styles)
def __init__(self, scalepair):
self.ruleChains = [[],]
self.styles = []
self.eval_type = type(Eval())
self.scalepair = scalepair
self.rcpos=0
self.stylepos=0
def get_numerics(self):
"""
Returns a set of number-compared values.
"""
a = set()
for c in self.ruleChains:
for r in c:
a.update(r.get_numerics())
a.discard(False)
return a
A StyleChooser object is equivalent to one CSS selector+declaration.
def get_interesting_tags(self, type, zoom):
"""
Returns a set of tags that were used in here.
"""
### FIXME
a = set()
for c in self.ruleChains:
for r in c:
a.update(r.get_interesting_tags(type, zoom))
if a: ## FIXME: semi-illegal optimization, may wreck in future on tagless matches
for r in self.styles:
for c,b in r.iteritems():
if __builtins__["type"](b) == self.eval_type:
a.update(b.extract_tags())
return a
Its ruleChains property is an array of all the selectors, which would
traditionally be comma-separated. For example:
h1, h2, h3 em
is three ruleChains.
def get_sql_hints(self, type, zoom):
"""
Returns a set of tags that were used in here in form of SQL-hints.
"""
a = set()
b = ""
needed = set(["width", "casing-width", "fill-color", "fill-image", "icon-image", "text", "extrude", "background-image", "background-color", "pattern-image", "shield-text"])
if not needed.isdisjoint(set(self.styles[0].keys())):
for c in self.ruleChains:
for r in c:
p = r.get_sql_hints(type, zoom)
if p:
q = "("+p[1] + ")"#[t[1] for t in p]
if q == "()":
q = ""
if b and q:
b += " OR "+ q
else:
b = q
a.update(p[0])
# no need to check for eval's
return a,b
# // Update the current StyleList from this StyleChooser
Each ruleChain is itself an array of nested selectors. So the above
example would roughly be encoded as:
[[h1],[h2],[h3,em]]
^^ ^^ ^^ ^^ each of these is a Rule
def updateStyles(self, sl, ftype, tags, zoom, scale, zscale):
# Are any of the ruleChains fulfilled?
object_id = False
for c in self.ruleChains:
object_id = self.testChain(c,ftype,tags,zoom)
if object_id:
break
else:
return sl
w = 0
for r in self.styles:
ra = {}
for a,b in r.iteritems():
"calculating eval()'s"
if type(b) == self.eval_type:
combined_style = {}
for t in sl:
combined_style.update(t)
for p,q in combined_style.iteritems():
if "color" in p:
The styles property is an array of all the style objects to be drawn
if any of the ruleChains evaluate to true.
"""
def __repr__(self):
return "{(%s) : [%s] }\n"%(self.ruleChains, self.styles)
def __init__(self, scalepair):
self.ruleChains = [[],]
self.styles = []
self.eval_type = type(Eval())
self.scalepair = scalepair
self.selzooms = None
self.rcpos=0
self.stylepos=0
def get_numerics(self):
"""
Returns a set of number-compared values.
"""
a = set()
for c in self.ruleChains:
for r in c:
a.update(r.get_numerics())
a.discard(False)
return a
def get_interesting_tags(self, ztype, zoom):
"""
Returns a set of tags that were used in here.
"""
### FIXME
a = set()
for c in self.ruleChains:
for r in c:
a.update(r.get_interesting_tags(ztype, zoom))
if a: ## FIXME: semi-illegal optimization, may wreck in future on tagless matches
for r in self.styles:
for c,b in r.iteritems():
if type(b) == self.eval_type:
a.update(b.extract_tags())
return a
def get_sql_hints(self, type, zoom):
"""
Returns a set of tags that were used in here in form of SQL-hints.
"""
a = set()
b = ""
needed = set(["width", "casing-width", "fill-color", "fill-image", "icon-image", "text", "extrude", "background-image", "background-color", "pattern-image", "shield-text"])
if not needed.isdisjoint(set(self.styles[0].keys())):
for c in self.ruleChains:
for r in c:
p = r.get_sql_hints(type, zoom)
if p:
q = "("+p[1] + ")"#[t[1] for t in p]
if q == "()":
q = ""
if b and q:
b += " OR "+ q
else:
b = q
a.update(p[0])
# no need to check for eval's
return a,b
# // Update the current StyleList from this StyleChooser
def updateStyles(self, sl, ftype, tags, zoom, scale, zscale):
# Are any of the ruleChains fulfilled?
if self.selzooms:
if zoom < self.selzooms[0] or zoom > self.selzooms[1]:
return sl
object_id = False
for c in self.ruleChains:
object_id = self.testChain(c,ftype,tags,zoom)
if object_id:
break
else:
return sl
w = 0
for r in self.styles:
ra = {}
for a,b in r.iteritems():
"calculating eval()'s"
if type(b) == self.eval_type:
combined_style = {}
for t in sl:
combined_style.update(t)
for p,q in combined_style.iteritems():
if "color" in p:
combined_style[p] = cairo_to_hex(q)
b = b.compute(tags, combined_style, scale, zscale)
ra[a] = b
r = ra
ra = {}
for a, b in r.iteritems():
"checking and nicifying style table"
if "color" in a:
"parsing color value to 3-tuple"
ra[a] = colorparser(b)
elif any(x in a for x in ("width", "z-index", "opacity", "offset", "radius", "extrude")):
"these things are float's or not in table at all"
b = b.compute(tags, combined_style, scale, zscale)
ra[a] = b
r = ra
ra = {}
for a, b in r.iteritems():
"checking and nicifying style table"
if "color" in a:
"parsing color value to 3-tuple"
ra[a] = colorparser(b)
elif any(x in a for x in ("width", "z-index", "opacity", "offset", "radius", "extrude")):
"these things are float's or not in table at all"
try:
ra[a] = float(b)
except ValueError:
pass
elif "dashes" in a:
"these things are arrays of float's or not in table at all"
try:
b = b.split(",")
b = [float(x) for x in b]
ra[a] = b
except ValueError:
ra[a] = []
else:
ra[a]=b
ra["layer"] = float(tags.get("layer",0))*2000+ra.get("z-index",1) # calculating z-index
#for k,v in ra.items(): # if a value is empty, we don't need it - renderer will do as default.
# if not v:
# del ra[k]
ra["object-id"] = str(object_id)
hasall = False
allinit = {}
for x in sl:
if x.get("object-id") == "::*":
allinit = x.copy()
if ra["object-id"] == "::*":
oid = x.get("object-id")
x.update(ra)
x["object-id"] = oid
if oid == "::*":
hasall = True
if x.get("object-id") == ra["object-id"]:
x.update(ra)
break
else:
if not hasall:
allinit.update(ra)
sl.append(allinit)
#
return sl
def testChain(self,chain, obj, tags, zoom):
"""
Tests an object against a chain
"""
for r in chain:
tt = r.test(obj,tags,zoom)
if tt:
return tt
return False
def newGroup(self):
"""
starts a new ruleChain in this.ruleChains
"""
if self.ruleChains[self.rcpos]:
self.ruleChains.append([])
def newObject(self,e=''):
"""
adds into the current ruleChain (starting a new Rule)
"""
rule = Rule(e)
rule.minZoom=float(self.scalepair[0])
rule.maxZoom=float(self.scalepair[1])
self.ruleChains[self.rcpos].append(rule)
def addZoom(self,z):
"""
adds into the current ruleChain (existing Rule)
"""
self.ruleChains[self.rcpos][-1].minZoom=float(z[0])
self.ruleChains[self.rcpos][-1].maxZoom=float(z[1])
if not self.selzooms:
self.selzooms = list(z)
else:
self.selzooms[0] = min(self.selzooms[0], z[0])
self.selzooms[1] = min(self.selzooms[1], z[1])
def addCondition(self,c):
"""
adds into the current ruleChain (existing Rule)
"""
self.ruleChains[self.rcpos][-1].conditions.append(c)
def addStyles(self, a):
"""
adds to this.styles
"""
rb = []
for r in a:
ra = {}
for a,b in r.iteritems():
a = a.strip()
b = b.strip()
if a == "casing-width":
"josm support"
if b[0] == "+":
try:
ra[a] = float(b)
except ValueError:
pass
elif "dashes" in a:
"these things are arrays of float's or not in table at all"
try:
b = b.split(",")
b = [float(x) for x in b]
ra[a]= b
except ValueError:
pass
else:
ra[a]=b
ra["layer"] = float(tags.get("layer",0))*2000+ra.get("z-index",1) # calculating z-index
for k,v in ra.items(): # if a value is empty, we don't need it - renderer will do as default.
if not v:
del ra[k]
ra["object-id"] = str(object_id)
hasall = False
allinit = {}
for x in sl:
if x.get("object-id") == "::*":
allinit = x.copy()
if ra["object-id"] == "::*":
oid = x.get("object-id")
x.update(ra)
x["object-id"] = oid
if oid == "::*":
hasall = True
if x.get("object-id") == ra["object-id"]:
x.update(ra)
break
else:
if not hasall:
allinit.update(ra)
sl.append(allinit)
#
return sl
def testChain(self,chain, obj, tags, zoom):
"""
Tests an object against a chain
"""
### FIXME: total MapCSS misreading
for r in chain:
return r.test(obj,tags,zoom)
return False
def newGroup(self):
"""
starts a new ruleChain in this.ruleChains
"""
if self.ruleChains[self.rcpos]:
self.ruleChains.append([])
def newObject(self,e=''):
"""
adds into the current ruleChain (starting a new Rule)
"""
rule = Rule(e)
rule.minZoom=float(self.scalepair[0])
rule.maxZoom=float(self.scalepair[1])
self.ruleChains[self.rcpos].append(rule)
def addZoom(self,z):
"""
adds into the current ruleChain (existing Rule)
"""
self.ruleChains[self.rcpos][-1].minZoom=float(z[0])
self.ruleChains[self.rcpos][-1].maxZoom=float(z[1])
def addCondition(self,c):
"""
adds into the current ruleChain (existing Rule)
"""
self.ruleChains[self.rcpos][-1].conditions.append(c)
def addStyles(self, a):
"""
adds to this.styles
"""
rb = []
for r in a:
ra = {}
for a,b in r.iteritems():
a = a.strip()
b = b.strip()
if a == "casing-width":
"josm support"
if b[0] == "+":
try:
b = str(float(b)/2)
except:
pass
if "text" == a[-4:]:
if b[:5] != "eval(":
b = "eval(tag(\""+b+"\"))"
if b[:5] == "eval(":
b = Eval(b)
ra[a] = b
rb.append(ra)
# print rb
self.styles = self.styles + rb
b = str(float(b)/2)
except:
pass
if "text" == a[-4:]:
if b[:5] != "eval(":
b = "eval(tag(\""+b+"\"))"
if b[:5] == "eval(":
b = Eval(b)
ra[a] = b
rb.append(ra)
# print rb
self.styles = self.styles + rb

View file

@ -90,33 +90,33 @@ way {width: 1; casing-width:1; casing-color: white}
class MapCSS():
def __init__(self,minscale=0,maxscale=19):
"""
"""
self.cache = {}
self.cache["style"] = {}
self.minscale=minscale
self.maxscale=maxscale
self.scalepair = (minscale, maxscale)
self.choosers = []
self.style_loaded = False
self.parse(builtin_style)
self.style_loaded = False #override one after loading
"""
"""
self.cache = {}
self.cache["style"] = {}
self.minscale=minscale
self.maxscale=maxscale
self.scalepair = (minscale, maxscale)
self.choosers = []
self.style_loaded = False
self.parse(builtin_style)
self.style_loaded = False #override one after loading
def parseZoom(self, s):
if ZOOM_MINMAX.match(s):
return tuple([float(i) for i in ZOOM_MINMAX.match(s).groups()])
elif ZOOM_MIN.match(s):
return float(ZOOM_MIN.match(s).groups()[0]), self.maxscale
elif ZOOM_MAX.match(s):
return float(self.minscale),float(ZOOM_MAX.match(s).groups()[0])
elif ZOOM_SINGLE.match(s):
return float(ZOOM_SINGLE.match(s).groups()[0]),float(ZOOM_SINGLE.match(s).groups()[0])
else:
logging.error("unparsed zoom: %s" %s)
if ZOOM_MINMAX.match(s):
return tuple([float(i) for i in ZOOM_MINMAX.match(s).groups()])
elif ZOOM_MIN.match(s):
return float(ZOOM_MIN.match(s).groups()[0]), self.maxscale
elif ZOOM_MAX.match(s):
return float(self.minscale),float(ZOOM_MAX.match(s).groups()[0])
elif ZOOM_SINGLE.match(s):
return float(ZOOM_SINGLE.match(s).groups()[0]),float(ZOOM_SINGLE.match(s).groups()[0])
else:
logging.error("unparsed zoom: %s" %s)
def precompile_style (self):
# TODO: styleshees precompilation
# TODO: styleshees precompilation
subjs = {"canvas": ("canvas",),"way": ("Polygon","LineString"), "line":("Polygon","LineString"), "area": ("Polygon",), "node": ("Point",), "*":("Point","Polygon","LineString") }
mfile.write("function restyle (prop, zoom, type){")
mfile.write("style = new Object;")
@ -166,7 +166,7 @@ class MapCSS():
#if subclass != "default":
#styles = 'if(!("%s" in style)){style["%s"] = new Object;}'%(subclass,subclass)
#for k, v in chooser.styles[0].iteritems():
if type(v) == str:
try:
v = str(float(v))
@ -178,73 +178,70 @@ class MapCSS():
mfile.write("return style;}")
def get_style (self, type, tags={}, zoom=0, scale=1, zscale=.5):
"""
Kothic styling API
"""
shash = md5(repr(type)+repr(tags)+repr(zoom)).digest()
if shash in self.cache["style"]:
return self.cache["style"][shash]
style = []
dbg = False
if tags.get('highway') == 'footway' and zoom == 17:
dbg = True
for chooser in self.choosers:
style = chooser.updateStyles(style, type, tags, zoom, scale, zscale)
style = [x for x in style if x["object-id"] != "::*"]
self.cache["style"][shash] = style
return style
"""
Kothic styling API
"""
shash = md5(repr(type)+repr(tags)+repr(zoom)).digest()
if shash in self.cache["style"]:
return self.cache["style"][shash]
style = []
for chooser in self.choosers:
style = chooser.updateStyles(style, type, tags, zoom, scale, zscale)
style = [x for x in style if x["object-id"] != "::*"]
self.cache["style"][shash] = style
return style
def get_interesting_tags(self, type=None, zoom=None):
"""
Get set of interesting tags.
"""
tags = set()
for chooser in self.choosers:
tags.update(chooser.get_interesting_tags(type, zoom))
return tags
"""
Get set of interesting tags.
"""
tags = set()
for chooser in self.choosers:
tags.update(chooser.get_interesting_tags(type, zoom))
return tags
def get_sql_hints(self, type=None, zoom=None):
"""
Get set of interesting tags.
"""
hints = []
for chooser in self.choosers:
p = chooser.get_sql_hints(type, zoom)
if p:
if p[0] and p[1]:
hints.append(p)
return hints
"""
Get set of interesting tags.
"""
hints = []
for chooser in self.choosers:
p = chooser.get_sql_hints(type, zoom)
if p:
if p[0] and p[1]:
hints.append(p)
return hints
def parse(self, css):
"""
Parses MapCSS given as string
"""
if not self.style_loaded:
self.choosers = []
log = logging.getLogger('mapcss.parser')
previous = 0 # what was the previous CSS word?
sc=StyleChooser(self.scalepair) #currently being assembled
#choosers=[]
#o = []
while (css):
"""
Parses MapCSS given as string
"""
if not self.style_loaded:
self.choosers = []
log = logging.getLogger('mapcss.parser')
previous = 0 # what was the previous CSS word?
sc=StyleChooser(self.scalepair) #currently being assembled
#choosers=[]
#o = []
while (css):
# CSS comment
if COMMENT.match(css):
# CSS comment
if COMMENT.match(css):
log.debug("comment found")
css=COMMENT.sub("", css)
#// Whitespace (probably only at beginning of file)
elif WHITESPACE.match(css):
#// Whitespace (probably only at beginning of file)
elif WHITESPACE.match(css):
log.debug("whitespace found")
css=WHITESPACE.sub("",css)
#// Class - .motorway, .builtup, :hover
elif CLASS.match(css):
#// Class - .motorway, .builtup, :hover
elif CLASS.match(css):
if previous==oDECLARATION:
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
cond = CLASS.match(css).groups()[0]
log.debug("class found: %s"% (cond))
css = CLASS.sub("", css)
@ -252,11 +249,11 @@ class MapCSS():
sc.addCondition(Condition('eq',("::class",cond)))
previous=oCONDITION;
#// Not class - !.motorway, !.builtup, !:hover
elif NOT_CLASS.match(css):
#// Not class - !.motorway, !.builtup, !:hover
elif NOT_CLASS.match(css):
if (previous==oDECLARATION):
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
cond = NOT_CLASS.match(css).groups()[0]
log.debug("not_class found: %s"% (cond))
@ -267,10 +264,10 @@ class MapCSS():
#sc.addCondition(new Condition('unset',o[1]));
#previous=oCONDITION;
#// Zoom
elif ZOOM.match(css):
#// Zoom
elif ZOOM.match(css):
if (previous!=oOBJECT & previous!=oCONDITION):
sc.newObject()
sc.newObject()
cond = ZOOM.match(css).groups()[0]
log.debug("zoom found: %s"% (cond))
@ -278,144 +275,144 @@ class MapCSS():
sc.addZoom(self.parseZoom(cond))
previous=oZOOM;
#// Grouping - just a comma
elif GROUP.match(css):
#// Grouping - just a comma
elif GROUP.match(css):
css=GROUP.sub("",css)
sc.newGroup()
previous=oGROUP
#// Condition - [highway=primary]
elif CONDITION.match(css):
#// Condition - [highway=primary]
elif CONDITION.match(css):
if (previous==oDECLARATION):
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
if (previous!=oOBJECT) and (previous!=oZOOM) and (previous!=oCONDITION):
sc.newObject()
sc.newObject()
cond = CONDITION.match(css).groups()[0]
log.debug("condition found: %s"% (cond))
css=CONDITION.sub("",css)
sc.addCondition(parseCondition(cond))
previous=oCONDITION;
#// Object - way, node, relation
elif OBJECT.match(css):
#// Object - way, node, relation
elif OBJECT.match(css):
if (previous==oDECLARATION):
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
obj = OBJECT.match(css).groups()[0]
log.debug("object found: %s"% (obj))
css=OBJECT.sub("",css)
sc.newObject(obj)
previous=oOBJECT
#// Declaration - {...}
elif DECLARATION.match(css):
#// Declaration - {...}
elif DECLARATION.match(css):
decl = DECLARATION.match(css).groups()[0]
log.debug("declaration found: %s"% (decl))
sc.addStyles(parseDeclaration(decl))
css=DECLARATION.sub("",css)
previous=oDECLARATION
#// Unknown pattern
elif UNKNOWN.match(css):
#// Unknown pattern
elif UNKNOWN.match(css):
log.warning("unknown thing found: %s"%(UNKNOWN.match(css).group()))
css=UNKNOWN.sub("",css)
else:
else:
log.warning("choked on: %s"%(css))
return
return
if (previous==oDECLARATION):
self.choosers.append(sc)
sc= StyleChooser(self.scalepair)
if (previous==oDECLARATION):
self.choosers.append(sc)
sc= StyleChooser(self.scalepair)
def parseCondition(s):
log = logging.getLogger('mapcss.parser.condition')
if CONDITION_TRUE.match(s):
a = CONDITION_TRUE.match(s).groups()
log.debug("condition true: %s"%(a[0]))
return Condition('true' ,a)
if CONDITION_invTRUE.match(s):
a = CONDITION_invTRUE.match(s).groups()
log.debug("condition invtrue: %s"%(a[0]))
return Condition('ne' ,(a[0],"yes"))
log = logging.getLogger('mapcss.parser.condition')
if CONDITION_TRUE.match(s):
a = CONDITION_TRUE.match(s).groups()
log.debug("condition true: %s"%(a[0]))
return Condition('true' ,a)
if CONDITION_invTRUE.match(s):
a = CONDITION_invTRUE.match(s).groups()
log.debug("condition invtrue: %s"%(a[0]))
return Condition('ne' ,(a[0],"yes"))
if CONDITION_FALSE.match(s):
a = CONDITION_FALSE.match(s).groups()
log.debug("condition false: %s"%(a[0]))
return Condition('false' ,a)
if CONDITION_FALSE.match(s):
a = CONDITION_FALSE.match(s).groups()
log.debug("condition false: %s"%(a[0]))
return Condition('false' ,a)
if CONDITION_SET.match(s):
a = CONDITION_SET.match(s).groups()
log.debug("condition set: %s"%(a))
return Condition('set' ,a)
if CONDITION_SET.match(s):
a = CONDITION_SET.match(s).groups()
log.debug("condition set: %s"%(a))
return Condition('set' ,a)
if CONDITION_UNSET.match(s):
a = CONDITION_UNSET.match(s).groups()
log.debug("condition unset: %s"%(a))
return Condition('unset' ,a)
if CONDITION_UNSET.match(s):
a = CONDITION_UNSET.match(s).groups()
log.debug("condition unset: %s"%(a))
return Condition('unset' ,a)
if CONDITION_NE.match(s):
a = CONDITION_NE.match(s).groups()
log.debug("condition NE: %s = %s"%(a[0], a[1]))
return Condition('ne' ,a)
## FIXME: convert other conditions to python
if CONDITION_NE.match(s):
a = CONDITION_NE.match(s).groups()
log.debug("condition NE: %s = %s"%(a[0], a[1]))
return Condition('ne' ,a)
## FIXME: convert other conditions to python
if CONDITION_LE.match(s):
a = CONDITION_LE.match(s).groups()
log.debug("condition LE: %s <= %s"%(a[0], a[1]))
return Condition('<=' ,a)
if CONDITION_LE.match(s):
a = CONDITION_LE.match(s).groups()
log.debug("condition LE: %s <= %s"%(a[0], a[1]))
return Condition('<=' ,a)
if CONDITION_GE.match(s):
a = CONDITION_GE.match(s).groups()
log.debug("condition GE: %s >= %s"%(a[0], a[1]))
return Condition('>=' ,a)
if CONDITION_GE.match(s):
a = CONDITION_GE.match(s).groups()
log.debug("condition GE: %s >= %s"%(a[0], a[1]))
return Condition('>=' ,a)
if CONDITION_LT.match(s):
a = CONDITION_LT.match(s).groups()
log.debug("condition LT: %s < %s"%(a[0], a[1]))
return Condition('<' ,a)
if CONDITION_LT.match(s):
a = CONDITION_LT.match(s).groups()
log.debug("condition LT: %s < %s"%(a[0], a[1]))
return Condition('<' ,a)
if CONDITION_GT.match(s):
a = CONDITION_GT.match(s).groups()
log.debug("condition GT: %s > %s"%(a[0], a[1]))
return Condition('>' ,a)
if CONDITION_GT.match(s):
a = CONDITION_GT.match(s).groups()
log.debug("condition GT: %s > %s"%(a[0], a[1]))
return Condition('>' ,a)
if CONDITION_REGEX.match(s):
a = CONDITION_REGEX.match(s).groups()
log.debug("condition REGEX: %s = %s"%(a[0], a[1]))
return Condition('regex' ,a)
if CONDITION_REGEX.match(s):
a = CONDITION_REGEX.match(s).groups()
log.debug("condition REGEX: %s = %s"%(a[0], a[1]))
return Condition('regex' ,a)
if CONDITION_EQ.match(s):
a = CONDITION_EQ.match(s).groups()
log.debug("condition EQ: %s = %s"%(a[0], a[1]))
return Condition('eq' ,a)
if CONDITION_EQ.match(s):
a = CONDITION_EQ.match(s).groups()
log.debug("condition EQ: %s = %s"%(a[0], a[1]))
return Condition('eq' ,a)
else:
log.warning("condition UNKNOWN: %s"%(s))
else:
log.warning("condition UNKNOWN: %s"%(s))
def parseDeclaration(s):
"""
Parse declaration string into list of styles
"""
styles=[]
t = {}
"""
Parse declaration string into list of styles
"""
styles=[]
t = {}
for a in s.split(';'):
#if ((o=ASSIGNMENT_EVAL.exec(a))) { t[o[1].replace(DASH,'_')]=new Eval(o[2]); }
if ASSIGNMENT.match(a):
tzz = ASSIGNMENT.match(a).groups()
t[tzz[0]]=tzz[1].strip().strip('"')
logging.debug("%s == %s" % (tzz[0],tzz[1]) )
else:
logging.debug("unknown %s" % (a) )
return [t]
for a in s.split(';'):
#if ((o=ASSIGNMENT_EVAL.exec(a))) { t[o[1].replace(DASH,'_')]=new Eval(o[2]); }
if ASSIGNMENT.match(a):
tzz = ASSIGNMENT.match(a).groups()
t[tzz[0]]=tzz[1].strip().strip('"')
logging.debug("%s == %s" % (tzz[0],tzz[1]) )
else:
logging.debug("unknown %s" % (a) )
return [t]
if __name__ == "__main__":
logging.basicConfig(level=logging.WARNING)
mc = MapCSS(0,19)
logging.basicConfig(level=logging.WARNING)
mc = MapCSS(0,19)

View file

@ -196,7 +196,7 @@ def _reversedict(d):
"""
Internal helper for generating reverse mappings; given a
dictionary, returns a new dictionary with keys and values swapped.
"""
return dict(zip(d.values(), d.keys()))
@ -407,22 +407,22 @@ def normalize_hex(hex_value):
"""
Normalize a hexadecimal color value to the following form and
return the result::
#[a-f0-9]{6}
In other words, the following transformations are applied as
needed:
* If the value contains only three hexadecimal digits, it is
expanded to six.
* The value is normalized to lower-case.
If the supplied value cannot be interpreted as a hexadecimal color
value, ``ValueError`` is raised.
Examples:
>>> normalize_hex('#09c')
'#0099cc'
>>> normalize_hex('#0099cc')
@ -447,7 +447,7 @@ def normalize_hex(hex_value):
Traceback (most recent call last):
...
ValueError: '#0' is not a valid hexadecimal color value.
"""
try:
hex_digits = HEX_COLOR_RE.match(hex_value).groups()[0]
@ -466,18 +466,18 @@ def normalize_hex(hex_value):
def name_to_hex(name, spec='css3'):
"""
Convert a color name to a normalized hexadecimal color value.
The optional keyword argument ``spec`` determines which
specification's list of color names will be used; valid values are
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
``css3``.
The color name will be normalized to lower-case before being
looked up, and when no color of that name exists in the given
specification, ``ValueError`` is raised.
Examples:
>>> name_to_hex('deepskyblue')
'#00bfff'
>>> name_to_hex('DeepSkyBlue')
@ -498,7 +498,7 @@ def name_to_hex(name, spec='css3'):
Traceback (most recent call last):
...
ValueError: 'deepskyblue' is not defined as a named color in css2.
"""
if spec not in SUPPORTED_SPECIFICATIONS:
raise TypeError("'%s' is not a supported specification for color name lookups; supported specifications are: %s." % (spec,
@ -514,18 +514,18 @@ def name_to_rgb(name, spec='css3'):
"""
Convert a color name to a 3-tuple of integers suitable for use in
an ``rgb()`` triplet specifying that color.
The optional keyword argument ``spec`` determines which
specification's list of color names will be used; valid values are
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
``css3``.
The color name will be normalized to lower-case before being
looked up, and when no color of that name exists in the given
specification, ``ValueError`` is raised.
Examples:
>>> name_to_rgb('navy')
(0, 0, 128)
>>> name_to_rgb('cadetblue')
@ -534,7 +534,7 @@ def name_to_rgb(name, spec='css3'):
Traceback (most recent call last):
...
ValueError: 'cadetblue' is not defined as a named color in html4.
"""
return hex_to_rgb(name_to_hex(name, spec=spec))
@ -542,25 +542,25 @@ def name_to_rgb_percent(name, spec='css3'):
"""
Convert a color name to a 3-tuple of percentages suitable for use
in an ``rgb()`` triplet specifying that color.
The optional keyword argument ``spec`` determines which
specification's list of color names will be used; valid values are
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
``css3``.
The color name will be normalized to lower-case before being
looked up, and when no color of that name exists in the given
specification, ``ValueError`` is raised.
Examples:
>>> name_to_rgb_percent('white')
('100%', '100%', '100%')
>>> name_to_rgb_percent('navy')
('0%', '0%', '50%')
>>> name_to_rgb_percent('goldenrod')
('85.49%', '64.71%', '12.5%')
"""
return rgb_to_rgb_percent(name_to_rgb(name, spec=spec))
@ -569,23 +569,23 @@ def name_to_rgb_percent(name, spec='css3'):
# Conversions from hexadecimal color values to various formats.
######################################################################
def hex_to_name(hex_value, spec='css3'):
"""
Convert a hexadecimal color value to its corresponding normalized
color name, if any such name exists.
The optional keyword argument ``spec`` determines which
specification's list of color names will be used; valid values are
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
``css3``.
The hexadecimal value will be normalized before being looked up,
and when no color name for the value is found in the given
specification, ``ValueError`` is raised.
Examples:
>>> hex_to_name('#000080')
'navy'
>>> hex_to_name('#000080', spec='html4')
@ -604,7 +604,7 @@ def hex_to_name(hex_value, spec='css3'):
Traceback (most recent call last):
...
TypeError: 'css4' is not a supported specification for color name lookups; supported specifications are: html4, css2, css21, css3.
"""
if spec not in SUPPORTED_SPECIFICATIONS:
raise TypeError("'%s' is not a supported specification for color name lookups; supported specifications are: %s." % (spec,
@ -627,11 +627,11 @@ def hex_to_rgb(hex_value):
"""
Convert a hexadecimal color value to a 3-tuple of integers
suitable for use in an ``rgb()`` triplet specifying that color.
The hexadecimal value will be normalized before being converted.
Examples:
>>> hex_to_rgb('#000080')
(0, 0, 128)
>>> hex_to_rgb('#ffff00')
@ -640,7 +640,7 @@ def hex_to_rgb(hex_value):
(255, 0, 0)
>>> hex_to_rgb('#deb887')
(222, 184, 135)
"""
hex_digits = normalize_hex(hex_value)
return tuple(map(lambda s: int(s, 16),
@ -650,16 +650,16 @@ def hex_to_rgb_percent(hex_value):
"""
Convert a hexadecimal color value to a 3-tuple of percentages
suitable for use in an ``rgb()`` triplet representing that color.
The hexadecimal value will be normalized before converting.
Examples:
>>> hex_to_rgb_percent('#ffffff')
('100%', '100%', '100%')
>>> hex_to_rgb_percent('#000080')
('0%', '0%', '50%')
"""
return rgb_to_rgb_percent(hex_to_rgb(hex_value))
@ -674,23 +674,23 @@ def rgb_to_name(rgb_triplet, spec='css3'):
Convert a 3-tuple of integers, suitable for use in an ``rgb()``
color triplet, to its corresponding normalized color name, if any
such name exists.
The optional keyword argument ``spec`` determines which
specification's list of color names will be used; valid values are
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
``css3``.
If there is no matching name, ``ValueError`` is raised.
Examples:
>>> rgb_to_name((0, 0, 0))
'black'
>>> rgb_to_name((0, 0, 128))
'navy'
>>> rgb_to_name((95, 158, 160))
'cadetblue'
"""
return hex_to_name(rgb_to_hex(rgb_triplet), spec=spec)
@ -698,16 +698,16 @@ def rgb_to_hex(rgb_triplet):
"""
Convert a 3-tuple of integers, suitable for use in an ``rgb()``
color triplet, to a normalized hexadecimal value for that color.
Examples:
>>> rgb_to_hex((255, 255, 255))
'#ffffff'
>>> rgb_to_hex((0, 0, 128))
'#000080'
>>> rgb_to_hex((33, 56, 192))
'#2138c0'
"""
return '#%02x%02x%02x' % rgb_triplet
@ -716,7 +716,7 @@ def rgb_to_rgb_percent(rgb_triplet):
Convert a 3-tuple of integers, suitable for use in an ``rgb()``
color triplet, to a 3-tuple of percentages suitable for use in
representing that color.
This function makes some trade-offs in terms of the accuracy of
the final representation; for some common integer values,
special-case logic is used to ensure a precise result (e.g.,
@ -724,9 +724,9 @@ def rgb_to_rgb_percent(rgb_triplet):
convert to '12.5%'), but for all other values a standard Python
``float`` is used and rounded to two decimal places, which may
result in a loss of precision for some values.
Examples:
>>> rgb_to_rgb_percent((255, 255, 255))
('100%', '100%', '100%')
>>> rgb_to_rgb_percent((0, 0, 128))
@ -735,7 +735,7 @@ def rgb_to_rgb_percent(rgb_triplet):
('12.94%', '21.96%', '75.29%')
>>> rgb_to_rgb_percent((64, 32, 16))
('25%', '12.5%', '6.25%')
"""
# In order to maintain precision for common values,
# 256 / 2**n is special-cased for values of n
@ -756,23 +756,23 @@ def rgb_percent_to_name(rgb_percent_triplet, spec='css3'):
Convert a 3-tuple of percentages, suitable for use in an ``rgb()``
color triplet, to its corresponding normalized color name, if any
such name exists.
The optional keyword argument ``spec`` determines which
specification's list of color names will be used; valid values are
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
``css3``.
If there is no matching name, ``ValueError`` is raised.
Examples:
>>> rgb_percent_to_name(('0%', '0%', '0%'))
'black'
>>> rgb_percent_to_name(('0%', '0%', '50%'))
'navy'
>>> rgb_percent_to_name(('85.49%', '64.71%', '12.5%'))
'goldenrod'
"""
return rgb_to_name(rgb_percent_to_rgb(rgb_percent_triplet), spec=spec)
@ -781,7 +781,7 @@ def rgb_percent_to_hex(rgb_percent_triplet):
Convert a 3-tuple of percentages, suitable for use in an ``rgb()``
color triplet, to a normalized hexadecimal color value for that
color.
Examples:
>>> rgb_percent_to_hex(('100%', '100%', '0%'))
@ -790,7 +790,7 @@ def rgb_percent_to_hex(rgb_percent_triplet):
'#000080'
>>> rgb_percent_to_hex(('85.49%', '64.71%', '12.5%'))
'#daa520'
"""
return rgb_to_hex(rgb_percent_to_rgb(rgb_percent_triplet))
@ -798,7 +798,7 @@ def _percent_to_integer(percent):
"""
Internal helper for converting a percentage value to an integer
between 0 and 255 inclusive.
"""
num = float(percent.split('%')[0]) / 100.0 * 255
e = num - math.floor(num)
@ -809,16 +809,16 @@ def rgb_percent_to_rgb(rgb_percent_triplet):
Convert a 3-tuple of percentages, suitable for use in an ``rgb()``
color triplet, to a 3-tuple of integers suitable for use in
representing that color.
Some precision may be lost in this conversion. See the note
regarding precision for ``rgb_to_rgb_percent()`` for details;
generally speaking, the following is true for any 3-tuple ``t`` of
integers in the range 0...255 inclusive::
t == rgb_percent_to_rgb(rgb_to_rgb_percent(t))
Examples:
>>> rgb_percent_to_rgb(('100%', '100%', '100%'))
(255, 255, 255)
>>> rgb_percent_to_rgb(('0%', '0%', '50%'))
@ -827,39 +827,39 @@ def rgb_percent_to_rgb(rgb_percent_triplet):
(64, 32, 16)
>>> rgb_percent_to_rgb(('12.94%', '21.96%', '75.29%'))
(33, 56, 192)
"""
return tuple(map(_percent_to_integer, rgb_percent_triplet))
def whatever_to_rgb(string):
"""
Converts CSS3 color or a hex into rgb triplet; hash of string if fails.
"""
string = string.strip().lower()
try:
return name_to_rgb(string)
except ValueError:
"""
Converts CSS3 color or a hex into rgb triplet; hash of string if fails.
"""
string = string.strip().lower()
try:
return hex_to_rgb(string)
return name_to_rgb(string)
except ValueError:
try:
if string[:3] == "rgb":
return tuple([float(i) for i in string[4:-1].split(",")][0:3])
except:
return hex_to_rgb("#"+md5(string).hexdigest()[:6])
try:
return hex_to_rgb(string)
except ValueError:
try:
if string[:3] == "rgb":
return tuple([float(i) for i in string[4:-1].split(",")][0:3])
except:
return hex_to_rgb("#"+md5(string).hexdigest()[:6])
def whatever_to_hex(string):
if type(string) == tuple:
return cairo_to_hex(string).upper()
return rgb_to_hex(whatever_to_rgb(string)).upper()
if type(string) == tuple:
return cairo_to_hex(string).upper()
return rgb_to_hex(whatever_to_rgb(string)).upper()
def whatever_to_cairo(string):
a = whatever_to_rgb(string)
return a[0]/255.,a[1]/255.,a[2]/255.,
a = whatever_to_rgb(string)
return a[0]/255.,a[1]/255.,a[2]/255.,
def cairo_to_hex (cairo):
return rgb_to_hex((cairo[0]*255,cairo[1]*255,cairo[2]*255,))
return rgb_to_hex((cairo[0]*255,cairo[1]*255,cairo[2]*255,))