Commits

1st1 committed 835890b

pep 362: No more AttributeErrors for missng attrs -> now they are 'empty'

Comments (0)

Files changed (2)

 
     empty = _empty
 
-    def __init__(self, name, kind, *, default=_void, annotation=_void,
+    def __init__(self, name, kind, *, default=_empty, annotation=_empty,
                  _partial_kwarg=False):
 
         if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD,
             raise ValueError("invalid value for 'Parameter.kind' attribute")
         self._kind = kind
 
-        if default is not _void:
+        if default is not _empty:
             if kind in (_VAR_POSITIONAL, _VAR_KEYWORD):
                 msg = '{} parameters cannot have default values'.format(kind)
                 raise ValueError(msg)
-            self._default = default
-        if annotation is not _void:
-            self._annotation = annotation
+        self._default = default
+        self._annotation = annotation
 
         if name is None:
             if kind != _POSITIONAL_ONLY:
 
     @property
     def default(self):
-        try:
-            return self._default
-        except AttributeError:
-            msg = 'parameter does not have a default value'
-            raise AttributeError(msg) from None
+        return self._default
 
     @property
     def annotation(self):
-        try:
-            return self._annotation
-        except AttributeError:
-            msg = 'parameter does not have an annotation'
-            raise AttributeError(msg) from None
+        return self._annotation
 
     @property
     def kind(self):
 
         if name is _void:
             name = self._name
+
         if kind is _void:
             kind = self._kind
 
-        if annotation is _empty:
-            annotation = _void
-        elif annotation is _void:
-            annotation = getattr(self, '_annotation', _void)
+        if annotation is _void:
+            annotation = self._annotation
 
-        if default is _empty:
-            default = _void
-        elif default is _void:
-            default = getattr(self, '_default', _void)
+        if default is _void:
+            default = self._default
 
         if _partial_kwarg is _void:
             _partial_kwarg = self._partial_kwarg
             formatted = '<{}>'.format(formatted)
 
         # Add annotation and default value
-        try:
-            annotatation = self._annotation
-        except AttributeError:
-            pass
-        else:
+        if self._annotation is not _empty:
             formatted = '{}:{}'.format(formatted,
-                                       formatannotation(annotatation))
-        try:
-            default = self._default
-        except AttributeError:
-            pass
-        else:
-            formatted = '{}={}'.format(formatted, repr(default))
+                                       formatannotation(self._annotation))
+
+        if self._default is not _empty:
+            formatted = '{}={}'.format(formatted, repr(self._default))
 
         if kind == _VAR_POSITIONAL:
             formatted = '*' + formatted
 
     def __eq__(self, other):
         return (issubclass(other.__class__, Parameter) and
-                self.name == other.name and
-                self.kind == other.kind and
-                getattr(self, 'default', _void) ==
-                                    getattr(other, 'default', _void) and
-                getattr(self, 'annotation', _void) ==
-                                    getattr(other, 'annotation', _void))
+                self._name == other._name and
+                self._kind == other._kind and
+                self._default == other._default and
+                self._annotation == other._annotation)
 
     def __ne__(self, other):
         return not self.__eq__(other)
 
     empty = _empty
 
-    def __init__(self, parameters=None, *, return_annotation=_void,
+    def __init__(self, parameters=None, *, return_annotation=_empty,
                  __validate_parameters__=True):
         '''Constructs Signature from the given list of Parameter
         objects and 'return_annotation'.  All arguments are optional.
                                                 for param in parameters))
 
         self._parameters = types.MappingProxyType(params)
-
-        if return_annotation is not _void:
-            self._return_annotation = return_annotation
+        self._return_annotation = return_annotation
 
     @classmethod
     def from_function(cls, func):
         # Non-keyword-only parameters w/o defaults.
         non_default_count = pos_count - pos_default_count
         for name in positional[:non_default_count]:
-            annotation = annotations.get(name, _void)
+            annotation = annotations.get(name, _empty)
             parameters.append(Parameter(name, annotation=annotation,
                                         kind=_POSITIONAL_OR_KEYWORD))
 
         # ... w/ defaults.
         for offset, name in enumerate(positional[non_default_count:]):
-            annotation = annotations.get(name, _void)
+            annotation = annotations.get(name, _empty)
             parameters.append(Parameter(name, annotation=annotation,
                                         kind=_POSITIONAL_OR_KEYWORD,
                                         default=defaults[offset]))
         # *args
         if func_code.co_flags & 0x04:
             name = arg_names[pos_count + keyword_only_count]
-            annotation = annotations.get(name, _void)
+            annotation = annotations.get(name, _empty)
             parameters.append(Parameter(name, annotation=annotation,
                                         kind=_VAR_POSITIONAL))
 
         # Keyword-only parameters.
         for name in keyword_only:
-            default = _void
+            default = _empty
             if kwdefaults is not None:
-                default = kwdefaults.get(name, _void)
+                default = kwdefaults.get(name, _empty)
 
-            annotation = annotations.get(name, _void)
+            annotation = annotations.get(name, _empty)
             parameters.append(Parameter(name, annotation=annotation,
                                         kind=_KEYWORD_ONLY,
                                         default=default))
                 index += 1
 
             name = arg_names[index]
-            annotation = annotations.get(name, _void)
+            annotation = annotations.get(name, _empty)
             parameters.append(Parameter(name, annotation=annotation,
                                         kind=_VAR_KEYWORD))
 
         return cls(parameters,
-                   return_annotation=annotations.get('return', _void),
+                   return_annotation=annotations.get('return', _empty),
                    __validate_parameters__=False)
 
     @property
 
     @property
     def return_annotation(self):
-        try:
-            return self._return_annotation
-        except AttributeError:
-            raise AttributeError('return_annotation is missing') from None
+        return self._return_annotation
 
     def replace(self, *, parameters=_void, return_annotation=_void):
         '''Creates a customized copy of the Signature.
         if parameters is _void:
             parameters = self.parameters.values()
 
-        if return_annotation is _empty:
-            return_annotation = _void
-        elif return_annotation is _void:
-            return_annotation = getattr(self, '_return_annotation', _void)
+        if return_annotation is _void:
+            return_annotation = self._return_annotation
 
         return type(self)(parameters,
                           return_annotation=return_annotation)
 
     def __eq__(self, other):
         if (not issubclass(type(other), Signature) or
-                    getattr(self, 'return_annotation', _void) !=
-                                getattr(other, 'return_annotation', _void) or
+                    self.return_annotation != other.return_annotation or
                     len(self.parameters) != len(other.parameters)):
             return False
 
                         parameters_ex = (param,)
                         break
                     elif (param.kind == _VAR_KEYWORD or
-                                                hasattr(param, 'default')):
+                                                param.default is not _empty):
                         # That's fine too - we have a default value for this
                         # parameter.  So, lets start parsing `kwargs`, starting
                         # with the current parameter
                 # parameter, left alone by the processing of positional
                 # arguments.
                 if (not partial and param.kind != _VAR_POSITIONAL and
-                                                not hasattr(param, 'default')):
+                                                    param.default is _empty):
                     raise TypeError('{arg!r} parameter lacking default value'. \
                                     format(arg=param_name)) from None
 
 
         rendered = '({})'.format(', '.join(result))
 
-        try:
-            ra = self.return_annotation
-        except AttributeError:
-            pass
-        else:
-            rendered += ' -> {}'.format(formatannotation(ra))
+        if self.return_annotation is not _empty:
+            anno = formatannotation(self.return_annotation)
+            rendered += ' -> {}'.format(anno)
 
         return rendered

Lib/test/test_inspect.py

     def signature(func):
         sig = inspect.signature(func)
         return (tuple((param.name,
-                       getattr(param, 'value', getattr(param, 'default', ...)),
-                       getattr(param, 'annotation', ...),
+                       (... if param.default is param.empty else param.default),
+                       (... if param.annotation is param.empty
+                                                        else param.annotation),
                        str(param.kind).lower())
                                     for param in sig.parameters.values()),
-                getattr(sig, 'return_annotation', ...))
+                (... if sig.return_annotation is sig.empty
+                                            else sig.return_annotation))
 
     def test_signature_object(self):
         S = inspect.Signature
         sig = sig.replace(return_annotation=None)
         self.assertIs(sig.return_annotation, None)
         sig = sig.replace(return_annotation=sig.empty)
-        self.assertFalse(hasattr(sig, 'return_annotation'))
+        self.assertIs(sig.return_annotation, sig.empty)
         sig = sig.replace(return_annotation=42)
         self.assertEqual(sig.return_annotation, 42)
         self.assertEqual(sig, inspect.signature(test))
                               kind=inspect.Parameter.POSITIONAL_ONLY)
         self.assertEqual(p.name, 'foo')
         self.assertEqual(p.default, 10)
-        self.assertIs(getattr(p, 'annotation', ...), ...)
+        self.assertIs(p.annotation, p.empty)
         self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
 
         with self.assertRaisesRegexp(ValueError, 'invalid value'):
         self.assertNotEqual(p2, p)
 
         p2 = p2.replace(name='foo', default=p2.empty)
-        self.assertFalse(hasattr(p2, 'default'))
+        self.assertIs(p2.default, p2.empty)
 
 
         p2 = p2.replace(default=42, kind=p2.POSITIONAL_OR_KEYWORD)