From e7fcb190cc0a6bf5631cee7dad78ff8c0490403d Mon Sep 17 00:00:00 2001
From: Michael Merickel <michael@merickel.org>
Date: Mon, 10 Jul 2017 07:08:52 +0200
Subject: [PATCH] Merge pull request #3124 from mmerickel/circular-import

---
 pyramid/config/util.py                 |   64 +------
 pyramid/tests/test_util.py             |  194 +++++++++++++++++++++
 pyramid/util.py                        |   52 +++++
 CHANGES.txt                            |    4 
 pyramid/tests/test_config/test_util.py |  194 ---------------------
 pyramid/viewderivers.py                |   15 
 6 files changed, 268 insertions(+), 255 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index a5e1035..0108cef 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -12,6 +12,10 @@
   decorators. See https://github.com/Pylons/pyramid/pull/3121 and
   https://github.com/Pylons/pyramid/pull/3123
 
+- Fix a circular import which made it impossible to import
+  ``pyramid.viewderivers`` before ``pyramid.config``.
+  See https://github.com/Pylons/pyramid/pull/3124
+
 1.9 (2017-06-26)
 ================
 
diff --git a/pyramid/config/util.py b/pyramid/config/util.py
index 63f06ff..b899592 100644
--- a/pyramid/config/util.py
+++ b/pyramid/config/util.py
@@ -1,13 +1,10 @@
 from hashlib import md5
-import inspect
 
 from pyramid.compat import (
     bytes_,
-    getargspec,
     is_nonstr_iter
     )
 
-from pyramid.compat import im_func
 from pyramid.exceptions import ConfigurationError
 from pyramid.registry import predvalseq
 
@@ -15,13 +12,21 @@
     TopologicalSorter,
     action_method,
     ActionInfo,
+    takes_one_arg,
     )
+
+from pyramid.viewderivers import (
+    MAX_ORDER,
+    DEFAULT_PHASH,
+)
 
 action_method = action_method # support bw compat imports
 ActionInfo = ActionInfo # support bw compat imports
 
-MAX_ORDER = 1 << 30
-DEFAULT_PHASH = md5().hexdigest()
+MAX_ORDER = MAX_ORDER  # support bw compat imports
+DEFAULT_PHASH = DEFAULT_PHASH  # support bw compat imports
+
+takes_one_arg = takes_one_arg  # support bw compat imports
 
 class not_(object):
     """
@@ -189,52 +194,3 @@
             score = score | bit
         order = (MAX_ORDER - score) / (len(preds) + 1)
         return order, preds, phash.hexdigest()
-
-def takes_one_arg(callee, attr=None, argname=None):
-    ismethod = False
-    if attr is None:
-        attr = '__call__'
-    if inspect.isroutine(callee):
-        fn = callee
-    elif inspect.isclass(callee):
-        try:
-            fn = callee.__init__
-        except AttributeError:
-            return False
-        ismethod = hasattr(fn, '__call__')
-    else:
-        try:
-            fn = getattr(callee, attr)
-        except AttributeError:
-            return False
-
-    try:
-        argspec = getargspec(fn)
-    except TypeError:
-        return False
-
-    args = argspec[0]
-
-    if hasattr(fn, im_func) or ismethod:
-        # it's an instance method (or unbound method on py2)
-        if not args:
-            return False
-        args = args[1:]
-
-    if not args:
-        return False
-
-    if len(args) == 1:
-        return True
-
-    if argname:
-
-        defaults = argspec[3]
-        if defaults is None:
-            defaults = ()
-
-        if args[0] == argname:
-            if len(args) - len(defaults) == 1:
-                return True
-
-    return False
diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py
index bb86a1f..f1a3df5 100644
--- a/pyramid/tests/test_config/test_util.py
+++ b/pyramid/tests/test_config/test_util.py
@@ -391,200 +391,6 @@
         self.assertEqual(predicates[1](None, request), True)
         self.assertEqual(predicates[2](None, request), True)
 
-
-class Test_takes_one_arg(unittest.TestCase):
-    def _callFUT(self, view, attr=None, argname=None):
-        from pyramid.config.util import takes_one_arg
-        return takes_one_arg(view, attr=attr, argname=argname)
-
-    def test_requestonly_newstyle_class_no_init(self):
-        class foo(object):
-            """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_requestonly_newstyle_class_init_toomanyargs(self):
-        class foo(object):
-            def __init__(self, context, request):
-                """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_requestonly_newstyle_class_init_onearg_named_request(self):
-        class foo(object):
-            def __init__(self, request):
-                """ """
-        self.assertTrue(self._callFUT(foo))
-
-    def test_newstyle_class_init_onearg_named_somethingelse(self):
-        class foo(object):
-            def __init__(self, req):
-                """ """
-        self.assertTrue(self._callFUT(foo))
-
-    def test_newstyle_class_init_defaultargs_firstname_not_request(self):
-        class foo(object):
-            def __init__(self, context, request=None):
-                """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_newstyle_class_init_defaultargs_firstname_request(self):
-        class foo(object):
-            def __init__(self, request, foo=1, bar=2):
-                """ """
-        self.assertTrue(self._callFUT(foo, argname='request'))
-
-    def test_newstyle_class_init_firstname_request_with_secondname(self):
-        class foo(object):
-            def __init__(self, request, two):
-                """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_newstyle_class_init_noargs(self):
-        class foo(object):
-            def __init__():
-                """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_oldstyle_class_no_init(self):
-        class foo:
-            """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_oldstyle_class_init_toomanyargs(self):
-        class foo:
-            def __init__(self, context, request):
-                """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_oldstyle_class_init_onearg_named_request(self):
-        class foo:
-            def __init__(self, request):
-                """ """
-        self.assertTrue(self._callFUT(foo))
-
-    def test_oldstyle_class_init_onearg_named_somethingelse(self):
-        class foo:
-            def __init__(self, req):
-                """ """
-        self.assertTrue(self._callFUT(foo))
-
-    def test_oldstyle_class_init_defaultargs_firstname_not_request(self):
-        class foo:
-            def __init__(self, context, request=None):
-                """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_oldstyle_class_init_defaultargs_firstname_request(self):
-        class foo:
-            def __init__(self, request, foo=1, bar=2):
-                """ """
-        self.assertTrue(self._callFUT(foo, argname='request'), True)
-
-    def test_oldstyle_class_init_noargs(self):
-        class foo:
-            def __init__():
-                """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_function_toomanyargs(self):
-        def foo(context, request):
-            """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_function_with_attr_false(self):
-        def bar(context, request):
-            """ """
-        def foo(context, request):
-            """ """
-        foo.bar = bar
-        self.assertFalse(self._callFUT(foo, 'bar'))
-
-    def test_function_with_attr_true(self):
-        def bar(context, request):
-            """ """
-        def foo(request):
-            """ """
-        foo.bar = bar
-        self.assertTrue(self._callFUT(foo, 'bar'))
-
-    def test_function_onearg_named_request(self):
-        def foo(request):
-            """ """
-        self.assertTrue(self._callFUT(foo))
-
-    def test_function_onearg_named_somethingelse(self):
-        def foo(req):
-            """ """
-        self.assertTrue(self._callFUT(foo))
-
-    def test_function_defaultargs_firstname_not_request(self):
-        def foo(context, request=None):
-            """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_function_defaultargs_firstname_request(self):
-        def foo(request, foo=1, bar=2):
-            """ """
-        self.assertTrue(self._callFUT(foo, argname='request'))
-
-    def test_function_noargs(self):
-        def foo():
-            """ """
-        self.assertFalse(self._callFUT(foo))
-
-    def test_instance_toomanyargs(self):
-        class Foo:
-            def __call__(self, context, request):
-                """ """
-        foo = Foo()
-        self.assertFalse(self._callFUT(foo))
-
-    def test_instance_defaultargs_onearg_named_request(self):
-        class Foo:
-            def __call__(self, request):
-                """ """
-        foo = Foo()
-        self.assertTrue(self._callFUT(foo))
-
-    def test_instance_defaultargs_onearg_named_somethingelse(self):
-        class Foo:
-            def __call__(self, req):
-                """ """
-        foo = Foo()
-        self.assertTrue(self._callFUT(foo))
-
-    def test_instance_defaultargs_firstname_not_request(self):
-        class Foo:
-            def __call__(self, context, request=None):
-                """ """
-        foo = Foo()
-        self.assertFalse(self._callFUT(foo))
-
-    def test_instance_defaultargs_firstname_request(self):
-        class Foo:
-            def __call__(self, request, foo=1, bar=2):
-                """ """
-        foo = Foo()
-        self.assertTrue(self._callFUT(foo, argname='request'), True)
-
-    def test_instance_nocall(self):
-        class Foo: pass
-        foo = Foo()
-        self.assertFalse(self._callFUT(foo))
-
-    def test_method_onearg_named_request(self):
-        class Foo:
-            def method(self, request):
-                """ """
-        foo = Foo()
-        self.assertTrue(self._callFUT(foo.method))
-
-    def test_function_annotations(self):
-        def foo(bar):
-            """ """
-        # avoid SyntaxErrors in python2, this if effectively nop
-        getattr(foo, '__annotations__', {}).update({'bar': 'baz'})
-        self.assertTrue(self._callFUT(foo))
-
 class TestNotted(unittest.TestCase):
     def _makeOne(self, predicate):
         from pyramid.config.util import Notted
diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py
index d64f0a7..6059c68 100644
--- a/pyramid/tests/test_util.py
+++ b/pyramid/tests/test_util.py
@@ -855,6 +855,200 @@
         self.assertTrue('foo' not in obj.__dict__)
 
 
+class Test_takes_one_arg(unittest.TestCase):
+    def _callFUT(self, view, attr=None, argname=None):
+        from pyramid.config.util import takes_one_arg
+        return takes_one_arg(view, attr=attr, argname=argname)
+
+    def test_requestonly_newstyle_class_no_init(self):
+        class foo(object):
+            """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_requestonly_newstyle_class_init_toomanyargs(self):
+        class foo(object):
+            def __init__(self, context, request):
+                """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_requestonly_newstyle_class_init_onearg_named_request(self):
+        class foo(object):
+            def __init__(self, request):
+                """ """
+        self.assertTrue(self._callFUT(foo))
+
+    def test_newstyle_class_init_onearg_named_somethingelse(self):
+        class foo(object):
+            def __init__(self, req):
+                """ """
+        self.assertTrue(self._callFUT(foo))
+
+    def test_newstyle_class_init_defaultargs_firstname_not_request(self):
+        class foo(object):
+            def __init__(self, context, request=None):
+                """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_newstyle_class_init_defaultargs_firstname_request(self):
+        class foo(object):
+            def __init__(self, request, foo=1, bar=2):
+                """ """
+        self.assertTrue(self._callFUT(foo, argname='request'))
+
+    def test_newstyle_class_init_firstname_request_with_secondname(self):
+        class foo(object):
+            def __init__(self, request, two):
+                """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_newstyle_class_init_noargs(self):
+        class foo(object):
+            def __init__():
+                """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_oldstyle_class_no_init(self):
+        class foo:
+            """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_oldstyle_class_init_toomanyargs(self):
+        class foo:
+            def __init__(self, context, request):
+                """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_oldstyle_class_init_onearg_named_request(self):
+        class foo:
+            def __init__(self, request):
+                """ """
+        self.assertTrue(self._callFUT(foo))
+
+    def test_oldstyle_class_init_onearg_named_somethingelse(self):
+        class foo:
+            def __init__(self, req):
+                """ """
+        self.assertTrue(self._callFUT(foo))
+
+    def test_oldstyle_class_init_defaultargs_firstname_not_request(self):
+        class foo:
+            def __init__(self, context, request=None):
+                """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_oldstyle_class_init_defaultargs_firstname_request(self):
+        class foo:
+            def __init__(self, request, foo=1, bar=2):
+                """ """
+        self.assertTrue(self._callFUT(foo, argname='request'), True)
+
+    def test_oldstyle_class_init_noargs(self):
+        class foo:
+            def __init__():
+                """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_function_toomanyargs(self):
+        def foo(context, request):
+            """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_function_with_attr_false(self):
+        def bar(context, request):
+            """ """
+        def foo(context, request):
+            """ """
+        foo.bar = bar
+        self.assertFalse(self._callFUT(foo, 'bar'))
+
+    def test_function_with_attr_true(self):
+        def bar(context, request):
+            """ """
+        def foo(request):
+            """ """
+        foo.bar = bar
+        self.assertTrue(self._callFUT(foo, 'bar'))
+
+    def test_function_onearg_named_request(self):
+        def foo(request):
+            """ """
+        self.assertTrue(self._callFUT(foo))
+
+    def test_function_onearg_named_somethingelse(self):
+        def foo(req):
+            """ """
+        self.assertTrue(self._callFUT(foo))
+
+    def test_function_defaultargs_firstname_not_request(self):
+        def foo(context, request=None):
+            """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_function_defaultargs_firstname_request(self):
+        def foo(request, foo=1, bar=2):
+            """ """
+        self.assertTrue(self._callFUT(foo, argname='request'))
+
+    def test_function_noargs(self):
+        def foo():
+            """ """
+        self.assertFalse(self._callFUT(foo))
+
+    def test_instance_toomanyargs(self):
+        class Foo:
+            def __call__(self, context, request):
+                """ """
+        foo = Foo()
+        self.assertFalse(self._callFUT(foo))
+
+    def test_instance_defaultargs_onearg_named_request(self):
+        class Foo:
+            def __call__(self, request):
+                """ """
+        foo = Foo()
+        self.assertTrue(self._callFUT(foo))
+
+    def test_instance_defaultargs_onearg_named_somethingelse(self):
+        class Foo:
+            def __call__(self, req):
+                """ """
+        foo = Foo()
+        self.assertTrue(self._callFUT(foo))
+
+    def test_instance_defaultargs_firstname_not_request(self):
+        class Foo:
+            def __call__(self, context, request=None):
+                """ """
+        foo = Foo()
+        self.assertFalse(self._callFUT(foo))
+
+    def test_instance_defaultargs_firstname_request(self):
+        class Foo:
+            def __call__(self, request, foo=1, bar=2):
+                """ """
+        foo = Foo()
+        self.assertTrue(self._callFUT(foo, argname='request'), True)
+
+    def test_instance_nocall(self):
+        class Foo: pass
+        foo = Foo()
+        self.assertFalse(self._callFUT(foo))
+
+    def test_method_onearg_named_request(self):
+        class Foo:
+            def method(self, request):
+                """ """
+        foo = Foo()
+        self.assertTrue(self._callFUT(foo.method))
+
+    def test_function_annotations(self):
+        def foo(bar):
+            """ """
+        # avoid SyntaxErrors in python2, this if effectively nop
+        getattr(foo, '__annotations__', {}).update({'bar': 'baz'})
+        self.assertTrue(self._callFUT(foo))
+
+
 def dummyfunc(): pass
 
 
diff --git a/pyramid/util.py b/pyramid/util.py
index 2827884..97e761c 100644
--- a/pyramid/util.py
+++ b/pyramid/util.py
@@ -17,6 +17,8 @@
     )
 
 from pyramid.compat import (
+    getargspec,
+    im_func,
     is_nonstr_iter,
     integer_types,
     string_types,
@@ -645,3 +647,53 @@
     return (pattern[0] == "." and
             (host.endswith(pattern) or host == pattern[1:]) or
             pattern == host)
+
+
+def takes_one_arg(callee, attr=None, argname=None):
+    ismethod = False
+    if attr is None:
+        attr = '__call__'
+    if inspect.isroutine(callee):
+        fn = callee
+    elif inspect.isclass(callee):
+        try:
+            fn = callee.__init__
+        except AttributeError:
+            return False
+        ismethod = hasattr(fn, '__call__')
+    else:
+        try:
+            fn = getattr(callee, attr)
+        except AttributeError:
+            return False
+
+    try:
+        argspec = getargspec(fn)
+    except TypeError:
+        return False
+
+    args = argspec[0]
+
+    if hasattr(fn, im_func) or ismethod:
+        # it's an instance method (or unbound method on py2)
+        if not args:
+            return False
+        args = args[1:]
+
+    if not args:
+        return False
+
+    if len(args) == 1:
+        return True
+
+    if argname:
+
+        defaults = argspec[3]
+        if defaults is None:
+            defaults = ()
+
+        if args[0] == argname:
+            if len(args) - len(defaults) == 1:
+                return True
+
+    return False
diff --git a/pyramid/viewderivers.py b/pyramid/viewderivers.py
index d2869b1..e048d47 100644
--- a/pyramid/viewderivers.py
+++ b/pyramid/viewderivers.py
@@ -1,3 +1,4 @@
+from hashlib import md5
 import inspect
 
 from zope.interface import (
@@ -28,22 +29,22 @@
     is_unbound_method,
     )
 
-from pyramid.config.util import (
-    DEFAULT_PHASH,
-    MAX_ORDER,
-    takes_one_arg,
-    )
-
 from pyramid.exceptions import (
     ConfigurationError,
     PredicateMismatch,
     )
 from pyramid.httpexceptions import HTTPForbidden
-from pyramid.util import object_description
+from pyramid.util import (
+    object_description,
+    takes_one_arg,
+    )
 from pyramid.view import render_view_to_response
 from pyramid import renderers
 
 
+MAX_ORDER = 1 << 30
+DEFAULT_PHASH = md5().hexdigest()
+
 def view_description(view):
     try:
         return view.__text__

--
Gitblit v1.9.3