Mercurial > hgrepos > Python > libs > ConfigMix
changeset 495:3f0c932588fc
Performance: module-level variable lookup is much faster (similar to local) than class-level (either via CLASS.VARIABLE or self.VARIABLE).
See tests/_perf_lookups.py
| author | Franz Glasner <f.glasner@feldmann-mg.com> |
|---|---|
| date | Fri, 17 Dec 2021 19:34:38 +0100 |
| parents | 60683361ebed |
| children | 36ab39e3de53 |
| files | configmix/config.py |
| diffstat | 1 files changed, 77 insertions(+), 76 deletions(-) [+] |
line wrap: on
line diff
--- a/configmix/config.py Fri Dec 17 19:24:54 2021 +0100 +++ b/configmix/config.py Fri Dec 17 19:34:38 2021 +0100 @@ -67,7 +67,7 @@ """ s = self.getvarl_s(*path, **kwds) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): return int(s, 0) else: return s @@ -78,7 +78,7 @@ """ s = self.getfirstvarl_s(*paths, **kwds) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): return int(s, 0) else: return s @@ -89,7 +89,7 @@ """ s = self.getvar_s(varname, default=default) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): return int(s, 0) else: return s @@ -100,7 +100,7 @@ """ s = self.getfirstvar_s(*varnames, **kwds) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): return int(s, 0) else: return s @@ -111,7 +111,7 @@ """ s = self.getvarl_s(*path, **kwds) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): sl = s.strip().lower() if sl not in self._BOOL_CVT: raise ValueError("Not a boolean: %r" % (s, )) @@ -125,7 +125,7 @@ """ s = self.getfirstvarl_s(*paths, **kwds) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): sl = s.strip().lower() if sl not in self._BOOL_CVT: raise ValueError("Not a boolean: %r" % (s, )) @@ -139,7 +139,7 @@ """ s = self.getvar_s(varname, default=default) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): sl = s.strip().lower() if sl not in self._BOOL_CVT: raise ValueError("Not a boolean: %r" % (s, )) @@ -153,7 +153,7 @@ """ s = self.getfirstvar_s(*varnames, **kwds) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): sl = s.strip().lower() if sl not in self._BOOL_CVT: raise ValueError("Not a boolean: %r" % (s, )) @@ -173,7 +173,7 @@ """ s = self.getvarl_s(*path, **kwds) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): return float(s) else: return s @@ -184,7 +184,7 @@ """ s = self.getfirstvarl_s(*path, **kwds) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): return float(s) else: return s @@ -195,7 +195,7 @@ """ s = self.getvar_s(varname, default) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): return float(s) else: return s @@ -206,12 +206,50 @@ """ s = self.getfirstvar_s(varname, default) - if isinstance(s, Configuration._TEXTTYPE): + if isinstance(s, _TEXTTYPE): return float(s) else: return s +# Speed +_EMPTY_STR = u("") +_TEXTTYPE = type(_EMPTY_STR) +_STARTTOK = u(b"{{") +_ENDTOK = u(b"}}") +_HIER_SEPARATOR = u(b'.') +_NS_SEPARATOR = u(b':') +_FILTER_SEPARATOR = u(b'|') +_STARTTOK_REF = _STARTTOK + REF_NAMESPACE + _NS_SEPARATOR +_ENDTOK_REF = _ENDTOK +_DOT = u(b'.') +_QUOTE = u(b'%') +_QUOTE_x = u(b'x') +_QUOTE_u = u(b'u') +_QUOTE_U = u(b'U') +_COMMENT = u(b'#') +_QUOTE_MAP = { + 0x25: u(b'%x25'), # _QUOTE + 0x2e: u(b'%x2e'), # _DOT + 0x3a: u(b'%x3a'), # _NS_SEPARATOR + 0x23: u(b'%x23'), # _COMMENT / anchor + 0x7c: u(b'%x7c'), # _FILTER_SEPARATOR + 0x22: u(b'%x22'), + 0x27: u(b'%x27'), + 0x7b: u(b'%x7b'), + 0x7d: u(b'%x7d'), + 0x5b: u(b'%x5b'), + 0x5d: u(b'%x5d'), +} +_QUOTE_SAFE = u(b'abcdefghijklmnopqrstuvwxyz' + b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + b'0123456789' + b'-_@!$&/\\()=?*+~;,<>^') +"""Mostly used configuration key characters that do not need any quoting + +""" + + class Configuration(CoercingMethodsMixin, _AttributeDict): """The configuration dictionary with attribute support or @@ -222,43 +260,6 @@ """ - # Speed - _EMPTY_STR = u("") - _TEXTTYPE = type(_EMPTY_STR) - _STARTTOK = u(b"{{") - _ENDTOK = u(b"}}") - _HIER_SEPARATOR = u(b'.') - _NS_SEPARATOR = u(b':') - _FILTER_SEPARATOR = u(b'|') - _STARTTOK_REF = _STARTTOK + REF_NAMESPACE + _NS_SEPARATOR - _ENDTOK_REF = _ENDTOK - _DOT = u(b'.') - _QUOTE = u(b'%') - _QUOTE_x = u(b'x') - _QUOTE_u = u(b'u') - _QUOTE_U = u(b'U') - _COMMENT = u(b'#') - _QUOTE_MAP = { - 0x25: u(b'%x25'), # _QUOTE - 0x2e: u(b'%x2e'), # _DOT - 0x3a: u(b'%x3a'), # _NS_SEPARATOR - 0x23: u(b'%x23'), # _COMMENT / anchor - 0x7c: u(b'%x7c'), # _FILTER_SEPARATOR - 0x22: u(b'%x22'), - 0x27: u(b'%x27'), - 0x7b: u(b'%x7b'), - 0x7d: u(b'%x7d'), - 0x5b: u(b'%x5b'), - 0x5d: u(b'%x5d'), - } - _QUOTE_SAFE = u(b'abcdefghijklmnopqrstuvwxyz' - b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - b'0123456789' - b'-_@!$&/\\()=?*+~;,<>^') - """Mostly used configuration key characters that do not need any quoting - - """ - is_jail = False """Flag to show that this is not a jail for another configuration""" @@ -409,7 +410,7 @@ if varname: varnameparts = [ self.unquote(vp) - for vp in varname.split(self._HIER_SEPARATOR) + for vp in varname.split(_HIER_SEPARATOR) ] else: varnameparts = tuple() @@ -553,19 +554,19 @@ return default def _split_ns(self, s): - ns, sep, rest = s.partition(self._NS_SEPARATOR) + ns, sep, rest = s.partition(_NS_SEPARATOR) if sep: return (self.unquote(ns), rest) else: return (None, ns) def _split_filters(self, s): - name, sep, filters = s.partition(self._FILTER_SEPARATOR) + name, sep, filters = s.partition(_FILTER_SEPARATOR) if sep: filters = filters.strip() if filters: return (name.rstrip(), - filters.split(self._FILTER_SEPARATOR)) + filters.split(_FILTER_SEPARATOR)) else: return (name.rstrip(), []) else: @@ -611,11 +612,11 @@ :raise KeyError: If the reverence cannot found """ - if not isinstance(v, self._TEXTTYPE): + if not isinstance(v, _TEXTTYPE): return v - if v.startswith(self._STARTTOK_REF) and v.endswith(self._ENDTOK_REF): + if v.startswith(_STARTTOK_REF) and v.endswith(_ENDTOK_REF): return self.expand_ref_uri( - v[len(self._STARTTOK_REF):-len(self._ENDTOK_REF)]) + v[len(_STARTTOK_REF):-len(_ENDTOK_REF)]) else: return v @@ -625,14 +626,14 @@ raise ValueError("only fragment-only URIs are supported") if not pu.fragment: return self - if pu.fragment.startswith(self._DOT): + if pu.fragment.startswith(_DOT): raise ValueError("relative refs not supported") return self.getvar(pu.fragment, default=default) def substitute_variables_in_obj(self, obj): """Recursively expand variables in the object tree `obj`.""" ty = type(obj) - if issubclass(ty, self._TEXTTYPE): + if issubclass(ty, _TEXTTYPE): # a string - really replace the value return self.expand_variable(obj) elif issubclass(ty, dict): @@ -654,7 +655,7 @@ def expand_variable(self, s): """Expand variables in the single string `s`""" - start = s.find(self._STARTTOK, 0) + start = s.find(_STARTTOK, 0) if start < 0: return s res = [] @@ -662,7 +663,7 @@ rest = 0 while start != -1: res_append(s[rest:start]) - end = s.find(self._ENDTOK, start) + end = s.find(_ENDTOK, start) if end < 0: rest = start break @@ -674,7 +675,7 @@ elif EMPTY_FILTER in filters: varvalue = self._apply_filters( filters, self.getvar_s(varname, - default=self._EMPTY_STR)) + default=_EMPTY_STR)) else: varvalue = self._apply_filters( filters, self.getvar_s(varname)) @@ -697,9 +698,9 @@ res_append(str_and_u(varvalue)) # don't re-evaluate because `self.getvar_s()` expands already rest = end + 2 - start = s.find(self._STARTTOK, rest) + start = s.find(_STARTTOK, rest) res_append(s[rest:]) - return self._EMPTY_STR.join(res) + return _EMPTY_STR.join(res) def _apply_filters(self, filters, value): for name in filters: @@ -728,7 +729,7 @@ """ # Quick check whether all of the chars are in _QUOTE_SAFE - if not s.rstrip(klass._QUOTE_SAFE): + if not s.rstrip(_QUOTE_SAFE): return s # Slow path @@ -738,7 +739,7 @@ if isinstance(s, str): s = s.decode("latin1") re_encode = True - s = s.translate(klass._QUOTE_MAP) + s = s.translate(_QUOTE_MAP) if re_encode: return s.encode("latin1") else: @@ -752,9 +753,9 @@ This is the inverse of :meth:`~.quote`. """ - if klass._QUOTE not in s: + if _QUOTE not in s: return s - parts = s.split(klass._QUOTE) + parts = s.split(_QUOTE) res = [parts[0]] res_append = res.append for p in parts[1:]: @@ -762,24 +763,24 @@ qc = p[0] except IndexError: raise ValueError("unknown quote syntax string: {}".format(s)) - if qc == klass._QUOTE_x: + if qc == _QUOTE_x: if len(p) < 3: raise ValueError("quote syntax: length too small") res_append(uchr(int(p[1:3], 16))) res_append(p[3:]) - elif qc == klass._QUOTE_u: + elif qc == _QUOTE_u: if len(p) < 5: raise ValueError("quote syntax: length too small") res_append(uchr(int(p[1:5], 16))) res_append(p[5:]) - elif qc == klass._QUOTE_U: + elif qc == _QUOTE_U: if len(p) < 9: raise ValueError("quote syntax: length too small") res_append(uchr(int(p[1:9], 16))) res_append(p[9:]) else: raise ValueError("unknown quote syntax string: {}".format(s)) - return klass._EMPTY_STR.join(res) + return _EMPTY_STR.join(res) def jailed(self, rootpath=None, root=None, bind_root=True): """Return a "jailed" configuration of the current configuration. @@ -815,7 +816,7 @@ if varname: rootpath = [ self.unquote(p) for p in root.split( - self._HIER_SEPARATOR) + _HIER_SEPARATOR) ] else: rootpath = tuple() @@ -857,11 +858,11 @@ self._path = path if path: self._pathstr = \ - Configuration._HIER_SEPARATOR.join( + _HIER_SEPARATOR.join( [Configuration.quote(p) for p in path]) \ - + Configuration._HIER_SEPARATOR + + _HIER_SEPARATOR else: - self._pathstr = Configuration._EMPTY_STR + self._pathstr = _EMPTY_STR @property def base(self): @@ -1033,7 +1034,7 @@ if varname: rootpath = [ self._base.unquote(p) for p in varname.split( - self._base._HIER_SEPARATOR) + _HIER_SEPARATOR) ] else: rootpath = tuple()
