diff options
author | Joel Rivera <rivera@joel.mx> | 2016-03-02 03:42:28 -0600 |
---|---|---|
committer | Joel Rivera <rivera@joel.mx> | 2016-03-02 03:42:28 -0600 |
commit | 305e8cd9c2cac57a2c1b9556f1ecddcdd67004ce (patch) | |
tree | 9a999a91982788eae5e8d483b7d927c4a5842858 | |
parent | a466ab7f4dacd8601c1441be63abf88db1a33781 (diff) | |
download | cherrypy-305e8cd9c2cac57a2c1b9556f1ecddcdd67004ce.tar.gz |
Reimplementation and bufixes on the buildCall for python3.5.
Add test case to account for the keywords arguments on the config file.
-rw-r--r-- | cherrypy/lib/reprconf.py | 46 | ||||
-rw-r--r-- | cherrypy/test/test_config.py | 28 |
2 files changed, 50 insertions, 24 deletions
diff --git a/cherrypy/lib/reprconf.py b/cherrypy/lib/reprconf.py index be1aacb4..4b6111f9 100644 --- a/cherrypy/lib/reprconf.py +++ b/cherrypy/lib/reprconf.py @@ -281,6 +281,7 @@ class _Builder2: # Everything else becomes args else : args.append(self.build(child)) + return callee(*args, **kwargs) def build_Keyword(self, o): @@ -377,40 +378,38 @@ class _Builder3: def build_Index(self, o): return self.build(o.value) - def build_Call35(self, o): + def _build_call35(self, o): """ Workaround for python 3.5 _ast.Call signature, docs found here https://greentreesnakes.readthedocs.org/en/latest/nodes.html """ + import ast callee = self.build(o.func) - - args = () - kwargs = dict() + args = [] if o.args is not None: - import _ast - args = [] for a in o.args: - if _ast.Starred is not type(a): - args.append(self.build(a)) - else: + if isinstance(a, ast.Starred): args.append(self.build(a.value)) - args = tuple(args) - - for a in o.keywords: - if a.arg: - kwargs[a.arg] = self.build(a.value) - else: - if _ast.Dict is type(a.value): - for k, v in zip(a.value.keys, a.value.values): - kwargs[self.build(k)] = self.build(v) else: - kwargs[a.value.id] = self.build(a.value) - - return callee(*(args), **kwargs) + args.append(self.build(a)) + kwargs = {} + for kw in o.keywords: + if kw.arg is None: # double asterix `**` + rst = self.build(kw.value) + if not isinstance(rst, dict): + raise TypeError("Invalid argument for call." + "Must be a mapping object.") + # give preference to the keys set directly from arg=value + for k, v in rst.items(): + if k not in kwargs: + kwargs[k] = v + else: # defined on the call as: arg=value + kwargs[kw.arg] = self.build(kw.value) + return callee(*args, **kwargs) def build_Call(self, o): if sys.version_info >= (3, 5): - return self.build_Call35(o) + return self._build_call35(o) callee = self.build(o.func) @@ -422,13 +421,12 @@ class _Builder3: if o.starargs is None: starargs = () else: - starargs = self.build(o.starargs) + starargs = tuple(self.build(o.starargs)) if o.kwargs is None: kwargs = {} else: kwargs = self.build(o.kwargs) - return callee(*(args + starargs), **kwargs) def build_List(self, o): diff --git a/cherrypy/test/test_config.py b/cherrypy/test/test_config.py index f9831b12..491321dd 100644 --- a/cherrypy/test/test_config.py +++ b/cherrypy/test/test_config.py @@ -269,3 +269,31 @@ class VariableSubstitutionTests(unittest.TestCase): self.assertEqual(cherrypy.config["my"]["my.dir"], "/some/dir/my/dir") self.assertEqual(cherrypy.config["my"] ["my.dir2"], "/some/dir/my/dir/dir2") + + +class CallablesInConfigTest(unittest.TestCase): + setup_server = staticmethod(setup_server) + + + def test_call_with_literal_dict(self): + from textwrap import dedent + conf = dedent(""" + [my] + value = dict(**{'foo': 'bar'}) + """) + fp = compat.StringIO(conf) + cherrypy.config.update(fp) + self.assertEqual(cherrypy.config['my']['value'], {'foo': 'bar'}) + + def test_call_with_kwargs(self): + from textwrap import dedent + conf = dedent(""" + [my] + value = dict(test_suite="OVERRIDE", **cherrypy.config.environments) + """) + fp = compat.StringIO(conf) + cherrypy.config.update(fp) + env = cherrypy.config.environments.copy() + env['test_suite'] = 'OVERRIDE' + self.assertEqual(cherrypy.config['my']['value']['test_suite'], 'OVERRIDE') + self.assertEqual(cherrypy.config['my']['value'], env) |