[Python-checkins] r59030 - sandbox/trunk/pep362/examples.py

brett.cannon python-checkins at python.org
Sat Nov 17 05:17:41 CET 2007


Author: brett.cannon
Date: Sat Nov 17 05:17:41 2007
New Revision: 59030

Added:
   sandbox/trunk/pep362/examples.py   (contents, props changed)
Log:
An examples file.


Added: sandbox/trunk/pep362/examples.py
==============================================================================
--- (empty file)
+++ sandbox/trunk/pep362/examples.py	Sat Nov 17 05:17:41 2007
@@ -0,0 +1,110 @@
+from pep362 import Signature
+
+def quack_check(fxn):
+    """Decorator to verify arguments and return value quack as they should.
+
+    Positional arguments.
+    >>> @quack_check
+    ... def one_arg(x:int): pass
+    ... 
+    >>> one_arg(42)
+    >>> one_arg('a')
+    Traceback (most recent call last):
+        ...
+    TypeError: 'a' does not quack like a <type 'int'>
+
+
+    *args
+    >>> @quack_check
+    ... def var_args(*args:int): pass
+    ... 
+    >>> var_args(*[1,2,3])
+    >>> var_args(*[1,'b',3])
+    Traceback (most recent call last):
+        ...
+    TypeError: *args contains a a value that does not quack like a <type 'int'>
+
+    **kwargs
+    >>> @quack_check
+    ... def var_kw_args(**kwargs:int): pass
+    ... 
+    >>> var_kw_args(**{'a': 1})
+    >>> var_kw_args(**{'a': 'A'})
+    Traceback (most recent call last):
+        ...
+    TypeError: **kwargs contains a value that does not quack like a <type 'int'>
+
+    Return annotations.
+    >>> @quack_check
+    ... def returned(x) -> int: return x
+    ... 
+    >>> returned(42)
+    42
+    >>> returned('a')
+    Traceback (most recent call last):
+        ...
+    TypeError: the return value 'a' does not quack like a <type 'int'>
+
+    """
+    # Get the signature; only needs to be calculated once.
+    sig = Signature(fxn)
+    def check(*args, **kwargs):
+        # Find out the variable -> value bindings.
+        bindings = sig.bind(*args, **kwargs)
+        # Check *args for the proper quack.
+        try:
+            duck = sig.var_annotations[sig.var_args]
+        except KeyError:
+            pass
+        else:
+            # Check every value in *args.
+            for value in bindings[sig.var_args]:
+                if not isinstance(value, duck):
+                    raise TypeError("*%s contains a a value that does not "
+                                    "quack like a %r" %
+                                    (sig.var_args, duck))
+            # Remove it from the bindings so as to not check it again.
+            del bindings[sig.var_args]
+        # **kwargs.
+        try:
+            duck = sig.var_annotations[sig.var_kw_args]
+        except (KeyError, AttributeError):
+            pass
+        else:
+            # Check every value in **kwargs.
+            for value in bindings[sig.var_kw_args].values():
+                if not isinstance(value, duck):
+                    raise TypeError("**%s contains a value that does not "
+                                    "quack like a %r" %
+                                    (sig.var_kw_args, duck))
+            # Remove from bindings so as to not check again.
+            del bindings[sig.var_kw_args]
+        # For each remaining variable ...
+        for var, value in bindings.items():
+            # See if an annotation was set.
+            try:
+                duck = sig[var].annotation
+            except AttributeError:
+                continue
+            # Check that the value quacks like it should.
+            if not isinstance(value, duck):
+                raise TypeError('%r does not quack like a %s' % (value, duck))
+        else:
+            # All the ducks quack fine; let the call proceed.
+            returned = fxn(*args, **kwargs)
+            # Check the return value.
+            try:
+                if not isinstance(returned, sig.return_annotation):
+                    raise TypeError('the return value %r does not quack like '
+                                    'a %r' % (returned,
+                                        sig.return_annotation))
+            except AttributeError:
+                pass
+            return returned
+    # Full-featured version would set function metadata.
+    return check
+
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod()


More information about the Python-checkins mailing list