[Python-checkins] r59031 - peps/trunk/pep-0362.txt
brett.cannon
python-checkins at python.org
Sat Nov 17 05:20:22 CET 2007
Author: brett.cannon
Date: Sat Nov 17 05:20:22 2007
New Revision: 59031
Modified:
peps/trunk/pep-0362.txt
Log:
Answer two open issues and add a good-sized example.
Modified: peps/trunk/pep-0362.txt
==============================================================================
--- peps/trunk/pep-0362.txt (original)
+++ peps/trunk/pep-0362.txt Sat Nov 17 05:20:22 2007
@@ -79,10 +79,7 @@
The keys are of the variable parameter with values of the
annotation. If an annotation does not exist for a variable
parameter then the key does not exist in the dict.
-* has_annotation : bool
- Signifies whether the function has an annotation for the return
- type.
-* annotation : object
+* return_annotation : object
If present, the attribute is set to the annotation for the return
type of the function.
* parameters : list(Parameter)
@@ -95,6 +92,14 @@
being the value the parameter would have if this function was
called with the given arguments.
+Signature objects also have the following methods:
+
+* __getitem__(self, key : str) -> Parameter
+ Returns the Parameter object for the named parameter.
+* __iter__(self)
+ Returns an iterator that returns Parameter objects in their
+ sequential order based on their 'position' attribute.
+
The Signature object is stored in the ``__signature__`` attribute of
a function. When it is to be created is discussed in
`Open Issues`_.
@@ -129,17 +134,11 @@
to represent keyword-only parameters was rejected to prevent
variable type usage and as a possible point of errors,
respectively.
-* has_default : bool
- True if the parameter has a default value, else False.
* default_value : object
The default value for the parameter, if present, else the
- attribute does not exist. This is done so that the attribute is
- not accidentally used if no default value is set as any default
- value could be a legitimate default value itself.
+ attribute does not exist.
* keyword_only : bool
True if the parameter is keyword-only, else False.
-* has_annotation : bool
- True if the parameter has an annotation, else False.
* annotation
Set to the annotation for the parameter. If ``has_annotation`` is
False then the attribute does not exist to prevent accidental use.
@@ -157,6 +156,118 @@
work with.
+Examples
+========
+
+Annotation Checker
+------------------
+::
+
+ 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
+
+
Open Issues
===========
@@ -180,33 +291,6 @@
key (and the name would be used as the hash for a Parameter object).
-Provide a mapping of parameter name to Parameter object?
---------------------------------------------------------
-
-While providing access to the parameters in order is handy, it might
-also be beneficial to provide a way to retrieve Parameter objects from
-a Signature object based on the parameter's name. Which style of
-access (sequential/iteration or mapping) will influence how the
-parameters are stored internally and whether __getitem__ accepts
-strings or integers.
-
-One possible compromise is to have ``__getitem__`` provide mapping
-support and have ``__iter__`` return Parameter objects based on their
-``position`` attribute. This allows for getting the sequence of
-Parameter objects easily by using the ``__iter__`` method on Signature
-object along with the sequence constructor (e.g., ``list`` or
-``tuple``).
-
-
-Remove ``has_*`` attributes?
-----------------------------
-
-If an EAFP approach to the API is taken, both ``has_annotation`` and
-``has_default`` are unneeded as the respective ``annotation`` and
-``default_value`` attributes are simply not set. It's simply a
-question of whether to have a EAFP or LBYL interface.
-
-
Have ``var_args`` and ``_var_kw_args`` default to ``None``?
------------------------------------------------------------
More information about the Python-checkins
mailing list