comparison configmix/config.py @ 539:9546d38cd3f8

Refactor: the parsing of the quoted and dot-separated path string is put into a function that handles also empty inputs properly
author Franz Glasner <fzglas.hg@dom66.de>
date Tue, 28 Dec 2021 17:28:19 +0100
parents be740ed67d16
children 33856ae1cc0b
comparison
equal deleted inserted replaced
538:e85d1eddf539 539:9546d38cd3f8
315 else: 315 else:
316 raise ValueError("unknown quote syntax string: {}".format(s)) 316 raise ValueError("unknown quote syntax string: {}".format(s))
317 return _EMPTY_STR.join(res) 317 return _EMPTY_STR.join(res)
318 318
319 319
320 def pathstr2path(varname):
321 """Parse a dot-separated path string `varname` into a tuple of
322 unquoted path items
323
324 :param str varname: The quoted and dot-separated path string
325 :return: The unquoted and parsed path items
326 :rtype: tuple
327
328 Used e.g. by :meth:`~.Configuration.getvar`,
329 :meth:`~.Configuration.getvar_s` and :meth:`~.Configuration.jailed`.
330
331 The returned value is suitable as input for
332 :meth:`~.Configuration.getvarl`, :meth:`~.Configuration.getvarl_s` and
333 friends.
334
335 An empty `varname` returns an empty tuple.
336
337 """
338 #
339 # Because str.split yields a non-empty list for an empty string handle
340 # the empty string separately.
341 #
342 if varname:
343 return tuple([unquote(p) for p in varname.split(_HIER_SEPARATOR)])
344 else:
345 return tuple()
346
347
320 class Configuration(CoercingMethodsMixin, _AttributeDict): 348 class Configuration(CoercingMethodsMixin, _AttributeDict):
321 349
322 """The configuration dictionary with attribute support or 350 """The configuration dictionary with attribute support or
323 variable substitution. 351 variable substitution.
324 352
495 See also :func:`.quote`. 523 See also :func:`.quote`.
496 524
497 """ 525 """
498 varns, varname = self._split_ns(varname) 526 varns, varname = self._split_ns(varname)
499 if not varns: 527 if not varns:
500 if varname: 528 return self.getvarl(*pathstr2path(varname), default=default)
501 varnameparts = tuple([unquote(vp) 529 else:
502 for vp in varname.split(_HIER_SEPARATOR)]) 530 return self.getvarl(varname, namespace=varns, default=default)
503 else:
504 varnameparts = tuple()
505 else:
506 varnameparts = (varname,)
507 return self.getvarl(*varnameparts, namespace=varns, default=default)
508 531
509 def getkeys(self, varname): 532 def getkeys(self, varname):
510 """Yield all the keys of a variable value. 533 """Yield all the keys of a variable value.
511 534
512 :rtype: A generator 535 :rtype: A generator
612 635
613 For more details see chapter :ref:`variable-interpolation`. 636 For more details see chapter :ref:`variable-interpolation`.
614 637
615 """ 638 """
616 varns, varname = self._split_ns(varname) 639 varns, varname = self._split_ns(varname)
617 if not varns:
618 if varname:
619 varnameparts = tuple([unquote(vp)
620 for vp in varname.split(_HIER_SEPARATOR)])
621 else:
622 varnameparts = tuple()
623 else:
624 varnameparts = (varname,)
625 try: 640 try:
626 obj = self.getvarl(*varnameparts, namespace=varns) 641 if not varns:
627 return self.substitute_variables_in_obj(obj) 642 return self.substitute_variables_in_obj(
643 self.getvarl(*pathstr2path(varname)))
644 else:
645 return self.substitute_variables_in_obj(
646 self.getvarl(varname, namespace=varns))
628 except KeyError: 647 except KeyError:
629 if default is _MARKER: 648 if default is _MARKER:
630 raise 649 raise
631 else: 650 else:
632 return default 651 return default
640 Currently used by :meth:`~.interpolate_variables`. 659 Currently used by :meth:`~.interpolate_variables`.
641 660
642 """ 661 """
643 varns, varname = self._split_ns(varname) 662 varns, varname = self._split_ns(varname)
644 if not varns: 663 if not varns:
645 cacheable = True 664 # no namespace -> cacheable
646 if varname: 665 return (
647 varnameparts = tuple([unquote(vp) 666 self.substitute_variables_in_obj(
648 for vp in varname.split(_HIER_SEPARATOR)]) 667 self.getvarl(*pathstr2path(varname))),
649 else: 668 True
650 varnameparts = tuple() 669 )
651 else: 670 else:
652 cacheable = False 671 # results from namespaced lookups are currently not cacheable
653 varnameparts = (varname,) 672 return (
654 obj = self.getvarl(*varnameparts, namespace=varns) 673 self.substitute_variables_in_obj(
655 return (self.substitute_variables_in_obj(obj), cacheable) 674 self.getvarl(varname, namespace=varns)),
675 False
676 )
656 677
657 def getfirstvar_s(self, *varnames, **kwds): 678 def getfirstvar_s(self, *varnames, **kwds):
658 """A variant of :meth:`~.getvar_s` that returns the first found 679 """A variant of :meth:`~.getvar_s` that returns the first found
659 variable in the list of given variables in `varnames`. 680 variable in the list of given variables in `varnames`.
660 681
818 end = s.find(_ENDTOK, start) 839 end = s.find(_ENDTOK, start)
819 if end < 0: 840 if end < 0:
820 rest = start 841 rest = start
821 break 842 break
822 varname, filters = self._split_filters( 843 varname, filters = self._split_filters(
823 s[start+2:end]) 844 s[start+2:end]) # noqa: E226
824 try: 845 try:
825 varvalue, cacheable = self._getvar_s_with_cache_info(varname) 846 varvalue, cacheable = self._getvar_s_with_cache_info(varname)
826 except KeyError: 847 except KeyError:
827 cacheable = True 848 cacheable = True
828 if NONE_FILTER in filters: 849 if NONE_FILTER in filters:
903 # convert to path 924 # convert to path
904 varns, varname = self._split_ns(root) 925 varns, varname = self._split_ns(root)
905 if varns: 926 if varns:
906 raise ValueError( 927 raise ValueError(
907 "jailed configurations do not support namespaces") 928 "jailed configurations do not support namespaces")
908 if varname: 929 rootpath = pathstr2path(root)
909 rootpath = tuple([unquote(p)
910 for p in root.split(_HIER_SEPARATOR)])
911 else:
912 rootpath = tuple()
913 jc = _JailedConfiguration(*rootpath) 930 jc = _JailedConfiguration(*rootpath)
914 if bind_root: 931 if bind_root:
915 jc.rebind(self) 932 jc.rebind(self)
916 return jc 933 return jc
917 934
1069 else: 1086 else:
1070 raise TypeError("a paths item must be a list or tuple") 1087 raise TypeError("a paths item must be a list or tuple")
1071 return self._base.getfirstvarl_s(*real_paths, **kwds) 1088 return self._base.getfirstvarl_s(*real_paths, **kwds)
1072 1089
1073 def getvar(self, varname, **kwds): 1090 def getvar(self, varname, **kwds):
1074 if varname: 1091 return self._base.getvarl(*(self._path + pathstr2path(varname)),
1075 varnameparts = self._path \ 1092 **kwds)
1076 + tuple([unquote(vp)
1077 for vp in varname.split(_HIER_SEPARATOR)])
1078 else:
1079 varnameparts = self._path
1080 return self._base.getvarl(*varnameparts, **kwds)
1081 1093
1082 def getkeys(self, varname): 1094 def getkeys(self, varname):
1083 if varname: 1095 for k in self._base.getkeysl(*(self._path + pathstr2path(varname))):
1084 varnameparts = self._path \
1085 + tuple([unquote(vp)
1086 for vp in varname.split(_HIER_SEPARATOR)])
1087 else:
1088 varnameparts = self._path
1089 for k in self._base.getkeysl(*varnameparts):
1090 yield k 1096 yield k
1091 1097
1092 def getfirstvar(self, *varnames, **kwds): 1098 def getfirstvar(self, *varnames, **kwds):
1093 real_varnames = [self._pathstr + vn for vn in varnames] 1099 real_varnames = [self._pathstr + vn for vn in varnames]
1094 return self._base.getfirstvar(*real_varnames, **kwds) 1100 return self._base.getfirstvar(*real_varnames, **kwds)
1095 1101
1096 def getvar_s(self, varname, **kwds): 1102 def getvar_s(self, varname, **kwds):
1097 if varname: 1103 return self._base.getvarl_s(*(self._path + pathstr2path(varname)),
1098 varnameparts = self._path \ 1104 **kwds)
1099 + tuple([unquote(vp)
1100 for vp in varname.split(_HIER_SEPARATOR)])
1101 else:
1102 varnameparts = self._path
1103 return self._base.getvarl_s(*varnameparts, **kwds)
1104 1105
1105 def getfirstvar_s(self, *varnames, **kwds): 1106 def getfirstvar_s(self, *varnames, **kwds):
1106 real_varnames = [self._pathstr + vn for vn in varnames] 1107 real_varnames = [self._pathstr + vn for vn in varnames]
1107 return self._base.getfirstvar_s(*real_varnames, **kwds) 1108 return self._base.getfirstvar_s(*real_varnames, **kwds)
1108 1109
1143 # convert to path 1144 # convert to path
1144 varns, varname = self._base._split_ns(root) 1145 varns, varname = self._base._split_ns(root)
1145 if varns: 1146 if varns:
1146 raise ValueError( 1147 raise ValueError(
1147 "sub-jails do not support namespaces") 1148 "sub-jails do not support namespaces")
1148 if varname: 1149 rootpath = pathstr2path(varname)
1149 rootpath = tuple([unquote(p)
1150 for p in varname.split(_HIER_SEPARATOR)])
1151 else:
1152 rootpath = tuple()
1153 if self._path: 1150 if self._path:
1154 new_rootpath = self._path + tuple(rootpath) 1151 new_rootpath = self._path + tuple(rootpath)
1155 else: 1152 else:
1156 new_rootpath = tuple(rootpath) 1153 new_rootpath = tuple(rootpath)
1157 sjc = _JailedConfiguration(*new_rootpath) 1154 sjc = _JailedConfiguration(*new_rootpath)