Commits

Andriy Kornatskyy  committed 401c62b

Added support for notice in looks-like checks.

  • Participants
  • Parent commits ca5b902

Comments (0)

Files changed (2)

File src/wheezy/core/introspection.py

             assert looks(IFoo, ignore_argspec=['pex']).like(Foo)
     """
 
-    def __init__(self, cls, ignore_funcs=None, ignore_argspec=None):
+    def __init__(self, cls):
         """
             *cls* - a class to be checked
+        """
+        self.cls = cls
+
+    def like(self, cls, notice=None, ignore_funcs=None, ignore_argspec=None):
+        """ Check if `self.cls` can be used as duck typing for `cls`.
+
+            *cls* - class to be checked for duck typing.
             *ignore_funcs* - a list of functions to ignore
             *ignore_argspec* - a list of functions to ignore arguments spec.
         """
-        self.declarations = declarations(cls)
-        self.ignore_funcs = ignore_funcs or []
-        self.ignore_argspec = ignore_argspec or []
-
-    def like(self, cls):
-        """ Check if `self.cls` can be used as duck typing for `cls`.
-
-            *cls* - class to be checked for duck typing.
-        """
-        for n, t in declarations(cls).items():
-            if n in self.ignore_funcs:
+        notice = notice or []
+        ignore_funcs = ignore_funcs or []
+        ignore_argspec = ignore_argspec or []
+        contestee = declarations(self.cls, notice=notice)
+        for name, t in declarations(cls, notice=notice).items():
+            if name in ignore_funcs:
                 continue
-            if n not in self.declarations:
-                warn("'%s': is missing." % n)
+            if name not in contestee:
+                warn("'%s': is missing." % name)
                 return False
             else:
-                t2 = self.declarations[n]
+                t2 = contestee[name]
                 if isfunction(t) and isfunction(t2):
-                    if n in self.ignore_argspec:
+                    if name in ignore_argspec:
                         continue
                     if getargspec(t) != getargspec(t2):
                         warn("'%s': argument names or defaults "
-                             "have no match." % n)
+                             "have no match." % name)
                         return False
                 elif t2.__class__ is not t.__class__:
                     warn("'%s': is not %s." % (n, t.__class__.__name__))
 
 # region: internal details
 
-def declarations(cls):
-    return dict((n, v) for n, v in cls.__dict__.items()
-                if not n.startswith('_'))
+def declarations(cls, notice):
+    return dict((name, t) for name, t in cls.__dict__.items()
+                if name in notice or not name.startswith('_'))
 
 
 def warn(message):

File src/wheezy/core/tests/test_introspection.py

                 def bar(self):
                     pass
 
-            assert looks(Foo, ignore_funcs='foo').like(IFoo)
+            assert looks(Foo).like(IFoo, ignore_funcs='foo')
 
         def test_args(self):
             """ Tests if there any function args corresponds.
                 def foo(self, a, b):
                     pass
 
-            assert looks(Foo, ignore_argspec='foo').like(IFoo)
+            assert looks(Foo).like(IFoo, ignore_argspec='foo')
 
         def test_decorator(self):
             """ Tests if there any method decorators corresponds.
             assert not looks(Foo).like(IFoo)
             self.assert_warning("'foo': is not property.")
 
+        def test_inheritance(self):
+            """ Test inheritance use case.
+            """
+            from wheezy.core.introspection import looks
+
+            class IFoo(object):
+                def foo(self):
+                    pass
+
+            class IBar(IFoo):
+                def bar(self):
+                    pass
+
+            class Bar(IBar):
+                def foo(self):
+                    pass
+
+                def bar(self):
+                    pass
+
+            assert looks(Bar).like(IBar)
+            assert looks(Bar).like(IFoo)
+
+        def test_special_method(self):
+            """ Test if __?__ are checked
+            """
+            from wheezy.core.introspection import looks
+
+            class IFoo(object):
+                def __len__(self):
+                    pass
+
+            class Foo(IFoo):
+                pass
+
+            assert looks(Foo).like(IFoo)
+            assert not looks(Foo).like(IFoo, notice=['__len__'])
+            self.assert_warning("'__len__': is missing.")
+
+            class Foo(IFoo):
+                def __len__(self):
+                    pass
+
+            assert looks(Foo).like(IFoo)
+            assert looks(Foo).like(IFoo, notice=['__len__'])
+
+        def test_decorator(self):
+            """
+            """
+            from wheezy.core.introspection import looks
+
+            def bar():
+                def decorate(m):
+                    def x(*args, **kwargs):
+                        pass
+                    return x
+                return decorate
+
+            class IFoo(object):
+                def foo(self, a):
+                    pass
+
+            class Foo(object):
+                @bar()
+                def foo(self, a):
+                    pass
+
+            assert not looks(Foo).like(IFoo)
+            self.assert_warning("'foo': argument names or defaults "
+                                "have no match.")
+
         def test_various(self):
             """ Tests if there are no errors.
             """