comparison configmix/config.py @ 320:98490375d90c

Allow variable name quoting to be used in .getvar() and .getvar_s() and references
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 06 May 2021 09:45:51 +0200
parents 043a6412be3c
children 7a0f3c256cf4
comparison
equal deleted inserted replaced
319:5427ca342c1e 320:98490375d90c
26 from urllib.parse import urlsplit 26 from urllib.parse import urlsplit
27 except ImportError: 27 except ImportError:
28 from urlparse import urlsplit 28 from urlparse import urlsplit
29 29
30 from .variables import lookup_varns, lookup_filter 30 from .variables import lookup_varns, lookup_filter
31 from .compat import u 31 from .compat import u, uchr
32 from .constants import REF_NAMESPACE 32 from .constants import REF_NAMESPACE
33 33
34 34
35 _MARKER = object() 35 _MARKER = object()
36 36
68 _NS_SEPARATOR = u(b':') 68 _NS_SEPARATOR = u(b':')
69 _FILTER_SEPARATOR = u(b'|') 69 _FILTER_SEPARATOR = u(b'|')
70 _STARTTOK_REF = _STARTTOK + REF_NAMESPACE + _NS_SEPARATOR 70 _STARTTOK_REF = _STARTTOK + REF_NAMESPACE + _NS_SEPARATOR
71 _ENDTOK_REF = _ENDTOK 71 _ENDTOK_REF = _ENDTOK
72 _DOT = u(b'.') 72 _DOT = u(b'.')
73 _QUOTE = u(b'%')
73 74
74 def getvarl(self, *names, default=_MARKER, namespace=None): 75 def getvarl(self, *names, default=_MARKER, namespace=None):
75 """Get a variable where the hierarchy is given in `names` as sequence 76 """Get a variable where the hierarchy is given in `names` as sequence
76 and the namespace is given in `namespace`. 77 and the namespace is given in `namespace`.
77 78
102 No variable interpolation is done and no filters are applied. 103 No variable interpolation is done and no filters are applied.
103 104
104 """ 105 """
105 varns, varname = self._split_ns(varname) 106 varns, varname = self._split_ns(varname)
106 if not varns: 107 if not varns:
107 varnameparts = varname.split(self._HIER_SEPARATOR) 108 varnameparts = [self.unquote(vp) for vp in varname.split(self._HIER_SEPARATOR)]
108 else: 109 else:
109 varnameparts = (varname,) 110 varnameparts = (varname,)
110 return self.getvarl(*varnameparts, namespace=varns) 111 return self.getvarl(*varnameparts, namespace=varns)
111 112
112 def getvarl_s(self, *names, default=_MARKER, namespace=None): 113 def getvarl_s(self, *names, default=_MARKER, namespace=None):
363 # 364 #
364 raise NameError("Filter %r not found" % name) 365 raise NameError("Filter %r not found" % name)
365 else: 366 else:
366 value = filterfn(self, value) 367 value = filterfn(self, value)
367 return value 368 return value
369
370 @classmethod
371 def quote(klass, s):
372 """Quote a key to protect all dangerous chars: ``%``, ``.``, ``:``
373 and ``|``
374
375 """
376 qc = klass._QUOTE
377 s = s.replace(qc, qc + "x25")
378 s = s.replace(klass._DOT, qc + "x2e")
379 s = s.replace(klass._NS_SEPARATOR, qc + "x3a")
380 return s.replace(klass._FILTER_SEPARATOR, qc + "x7c")
381
382 @classmethod
383 def unquote(klass, s):
384 """Unquote the content of `s`: handle all patterns ``%xXX``,
385 ``%uXXXX`` or `%UXXXXXXXX``
386
387 """
388 if klass._QUOTE not in s:
389 return s
390 res = []
391 parts = s.split(klass._QUOTE)
392 res.append(parts[0])
393 for p in parts[1:]:
394 if p.startswith(u(b'x')):
395 if len(p) < 3:
396 raise ValueError("quote syntax: length too small")
397 res.append(uchr(int(p[1:3], 16)))
398 res.append(p[3:])
399 elif p.startswith(u(b'u')):
400 if len(p) < 5:
401 raise ValueError("quote syntax: length too small")
402 res.append(uchr(int(p[1:5], 16)))
403 res.append(p[5:])
404 elif p.startswith(u(b'U')):
405 if len(p) < 9:
406 raise ValueError("quote syntax: length too small")
407 res.append(uchr(int(p[1:9], 16)))
408 res.append(p[9:])
409 else:
410 raise ValueError("unknown quote syntax string: {}".format(s))
411 return ''.join(res)