Repository: Pylons/pyramid

Issue:
Circular import in pyramid.viewderivers
Hello, importing `pyramid.viewderivers` trigger a circular import error:

```
>>> import pyramid.viewderivers
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../lib/python2.7/site-packages/pyramid/viewderivers.py", line 31, in <module>
    from pyramid.config.util import (
  File ".../lib/python2.7/site-packages/pyramid/config/__init__.py", line 78, in <module>
    from pyramid.config.views import ViewsConfiguratorMixin
  File ".../lib/python2.7/site-packages/pyramid/config/views.py", line 80, in <module>
    from pyramid.viewderivers import (
ImportError: cannot import name INGRESS
```


Discussion:
I guess that's what happens when you have 2 util files!

Resolving patch:
diff --git a/pyramid/config/util.py b/pyramid/config/util.py
--- 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):
     """
@@ -180,52 +185,3 @@ def make(self, config, **kw):
             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/util.py b/pyramid/util.py
--- 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 @@ def is_same_domain(host, pattern):
     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
--- 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__


Test patch:
diff --git a/pyramid/tests/test_config/test_util.py b/pyramid/tests/test_config/test_util.py
--- a/pyramid/tests/test_config/test_util.py
+++ b/pyramid/tests/test_config/test_util.py
@@ -381,200 +381,6 @@ def test_notted(self):
         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
--- a/pyramid/tests/test_util.py
+++ b/pyramid/tests/test_util.py
@@ -851,6 +851,200 @@ def test_does_not_delete_attr_if_no_attr_to_delete(self):
         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