summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Rivera <rivera@joel.mx>2016-03-02 03:42:28 -0600
committerJoel Rivera <rivera@joel.mx>2016-03-02 03:42:28 -0600
commit305e8cd9c2cac57a2c1b9556f1ecddcdd67004ce (patch)
tree9a999a91982788eae5e8d483b7d927c4a5842858
parenta466ab7f4dacd8601c1441be63abf88db1a33781 (diff)
downloadcherrypy-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.py46
-rw-r--r--cherrypy/test/test_config.py28
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)