Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
bfebb7b5
Commit
bfebb7b5
authored
13 years ago
by
Benjamin Peterson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
improve abstract property support (closes #11610)
Thanks to Darren Dale for patch.
parent
a8ff01ca
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
396 additions
and
36 deletions
+396
-36
Doc/library/abc.rst
Doc/library/abc.rst
+60
-15
Doc/whatsnew/3.3.rst
Doc/whatsnew/3.3.rst
+17
-0
Include/object.h
Include/object.h
+1
-0
Lib/abc.py
Lib/abc.py
+16
-3
Lib/numbers.py
Lib/numbers.py
+9
-5
Lib/test/test_abc.py
Lib/test/test_abc.py
+162
-10
Lib/test/test_property.py
Lib/test/test_property.py
+23
-0
Misc/ACKS
Misc/ACKS
+1
-0
Misc/NEWS
Misc/NEWS
+2
-0
Objects/descrobject.c
Objects/descrobject.c
+38
-1
Objects/funcobject.c
Objects/funcobject.c
+44
-2
Objects/object.c
Objects/object.c
+23
-0
No files found.
Doc/library/abc.rst
View file @
bfebb7b5
...
@@ -127,19 +127,18 @@ This module provides the following class:
...
@@ -127,19 +127,18 @@ This module provides the following class:
available as a method of ``Foo``, so it is provided separately.
available as a method of ``Foo``, so it is provided separately.
It
also provides the following decorators:
The :mod:`abc` module
also provides the following decorators:
.. decorator:: abstractmethod(function)
.. decorator:: abstractmethod(function)
A decorator indicating abstract methods.
A decorator indicating abstract methods.
Using this decorator requires that the class's metaclass is :class:`ABCMeta` or
Using this decorator requires that the class's metaclass is :class:`ABCMeta`
is derived from it.
or is derived from it. A class that has a metaclass derived from
A class that has a metaclass derived from :class:`ABCMeta`
:class:`ABCMeta` cannot be instantiated unless all of its abstract methods
cannot be instantiated unless all of its abstract methods and
and properties are overridden. The abstract methods can be called using any
properties are overridden.
of the normal 'super' call mechanisms. :func:`abstractmethod` may be used
The abstract methods can be called using any of the normal 'super' call
to declare abstract methods for properties and descriptors.
mechanisms.
Dynamically adding abstract methods to a class, or attempting to modify the
Dynamically adding abstract methods to a class, or attempting to modify the
abstraction status of a method or class once it is created, are not
abstraction status of a method or class once it is created, are not
...
@@ -147,12 +146,52 @@ It also provides the following decorators:
...
@@ -147,12 +146,52 @@ It also provides the following decorators:
regular inheritance; "virtual subclasses" registered with the ABC's
regular inheritance; "virtual subclasses" registered with the ABC's
:meth:`register` method are not affected.
:meth:`register` method are not affected.
Usage::
When :func:`abstractmethod` is applied in combination with other method
descriptors, it should be applied as the innermost decorator, as shown in
the following usage examples::
class C(metaclass=ABCMeta):
class C(metaclass=ABCMeta):
@abstractmethod
@abstractmethod
def my_abstract_method(self, ...):
def my_abstract_method(self, ...):
...
...
@classmethod
@abstractmethod
def my_abstract_classmethod(cls, ...):
...
@staticmethod
@abstractmethod
def my_abstract_staticmethod(...):
...
@property
@abstractmethod
def my_abstract_property(self):
...
@my_abstract_property.setter
@abstractmethod
def my_abstract_property(self, val):
...
@abstractmethod
def _get_x(self):
...
@abstractmethod
def _set_x(self, val):
...
x = property(_get_x, _set_x)
In order to correctly interoperate with the abstract base class machinery,
the descriptor must identify itself as abstract using
:attr:`__isabstractmethod__`. In general, this attribute should be ``True``
if any of the methods used to compose the descriptor are abstract. For
example, Python's built-in property does the equivalent of::
class Descriptor:
...
@property
def __isabstractmethod__(self):
return any(getattr(f, '__isabstractmethod__', False) for
f in (self._fget, self._fset, self._fdel))
.. note::
.. note::
...
@@ -177,6 +216,8 @@ It also provides the following decorators:
...
@@ -177,6 +216,8 @@ It also provides the following decorators:
...
...
.. versionadded:: 3.2
.. versionadded:: 3.2
.. deprecated:: 3.3
Use :class:`classmethod` with :func:`abstractmethod` instead
.. decorator:: abstractstaticmethod(function)
.. decorator:: abstractstaticmethod(function)
...
@@ -192,18 +233,19 @@ It also provides the following decorators:
...
@@ -192,18 +233,19 @@ It also provides the following decorators:
...
...
.. versionadded:: 3.2
.. versionadded:: 3.2
.. deprecated:: 3.3
Use :class:`staticmethod` with :func:`abstractmethod` instead
.. decorator:: abstractproperty(fget=None, fset=None, fdel=None, doc=None)
.. decorator:: abstractproperty(fget=None, fset=None, fdel=None, doc=None)
A subclass of the built-in :func:`property`, indicating an abstract property.
A subclass of the built-in :func:`property`, indicating an abstract property.
Using this function requires that the class's metaclass is :class:`ABCMeta` or
Using this function requires that the class's metaclass is :class:`ABCMeta`
is derived from it.
or is derived from it. A class that has a metaclass derived from
A class that has a metaclass derived from :class:`ABCMeta` cannot be
:class:`ABCMeta` cannot be instantiated unless all of its abstract methods
instantiated unless all of its abstract methods and properties are overridden.
and properties are overridden. The abstract properties can be called using
The abstract properties can be called using any of the normal
any of the normal 'super' call mechanisms.
'super' call mechanisms.
Usage::
Usage::
...
@@ -220,6 +262,9 @@ It also provides the following decorators:
...
@@ -220,6 +262,9 @@ It also provides the following decorators:
def setx(self, value): ...
def setx(self, value): ...
x = abstractproperty(getx, setx)
x = abstractproperty(getx, setx)
.. deprecated:: 3.3
Use :class:`property` with :func:`abstractmethod` instead
.. rubric:: Footnotes
.. rubric:: Footnotes
...
...
This diff is collapsed.
Click to expand it.
Doc/whatsnew/3.3.rst
View file @
bfebb7b5
...
@@ -352,6 +352,23 @@ curses
...
@@ -352,6 +352,23 @@ curses
(Contributed by Iñigo Serna in :issue:`6755`)
(Contributed by Iñigo Serna in :issue:`6755`)
abc
---
Improved support for abstract base classes containing descriptors composed with
abstract methods. The recommended approach to declaring abstract descriptors is
now to provide :attr:`__isabstractmethod__` as a dynamically updated
property. The built-in descriptors have been updated accordingly.
* :class:`abc.abstractproperty` has been deprecated, use :class:`property`
with :func:`abc.abstractmethod` instead.
* :class:`abc.abstractclassmethod` has been deprecated, use
:class:`classmethod` with :func:`abc.abstractmethod` instead.
* :class:`abc.abstractstaticmethod` has been deprecated, use
:class:`property` with :func:`abc.abstractmethod` instead.
(Contributed by Darren Dale in :issue:`11610`)
faulthandler
faulthandler
------------
------------
...
...
This diff is collapsed.
Click to expand it.
Include/object.h
View file @
bfebb7b5
...
@@ -473,6 +473,7 @@ PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *);
...
@@ -473,6 +473,7 @@ PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *);
PyAPI_FUNC
(
PyObject
*
)
PyObject_GetAttr
(
PyObject
*
,
PyObject
*
);
PyAPI_FUNC
(
PyObject
*
)
PyObject_GetAttr
(
PyObject
*
,
PyObject
*
);
PyAPI_FUNC
(
int
)
PyObject_SetAttr
(
PyObject
*
,
PyObject
*
,
PyObject
*
);
PyAPI_FUNC
(
int
)
PyObject_SetAttr
(
PyObject
*
,
PyObject
*
,
PyObject
*
);
PyAPI_FUNC
(
int
)
PyObject_HasAttr
(
PyObject
*
,
PyObject
*
);
PyAPI_FUNC
(
int
)
PyObject_HasAttr
(
PyObject
*
,
PyObject
*
);
PyAPI_FUNC
(
int
)
_PyObject_IsAbstract
(
PyObject
*
);
PyAPI_FUNC
(
PyObject
*
)
_PyObject_GetAttrId
(
PyObject
*
,
struct
_Py_Identifier
*
);
PyAPI_FUNC
(
PyObject
*
)
_PyObject_GetAttrId
(
PyObject
*
,
struct
_Py_Identifier
*
);
PyAPI_FUNC
(
int
)
_PyObject_SetAttrId
(
PyObject
*
,
struct
_Py_Identifier
*
,
PyObject
*
);
PyAPI_FUNC
(
int
)
_PyObject_SetAttrId
(
PyObject
*
,
struct
_Py_Identifier
*
,
PyObject
*
);
PyAPI_FUNC
(
int
)
_PyObject_HasAttrId
(
PyObject
*
,
struct
_Py_Identifier
*
);
PyAPI_FUNC
(
int
)
_PyObject_HasAttrId
(
PyObject
*
,
struct
_Py_Identifier
*
);
...
...
This diff is collapsed.
Click to expand it.
Lib/abc.py
View file @
bfebb7b5
...
@@ -26,7 +26,8 @@ def abstractmethod(funcobj):
...
@@ -26,7 +26,8 @@ def abstractmethod(funcobj):
class
abstractclassmethod
(
classmethod
):
class
abstractclassmethod
(
classmethod
):
"""A decorator indicating abstract classmethods.
"""
A decorator indicating abstract classmethods.
Similar to abstractmethod.
Similar to abstractmethod.
...
@@ -36,6 +37,9 @@ class abstractclassmethod(classmethod):
...
@@ -36,6 +37,9 @@ class abstractclassmethod(classmethod):
@abstractclassmethod
@abstractclassmethod
def my_abstract_classmethod(cls, ...):
def my_abstract_classmethod(cls, ...):
...
...
'abstractclassmethod' is deprecated. Use 'classmethod' with
'abstractmethod' instead.
"""
"""
__isabstractmethod__
=
True
__isabstractmethod__
=
True
...
@@ -46,7 +50,8 @@ class abstractclassmethod(classmethod):
...
@@ -46,7 +50,8 @@ class abstractclassmethod(classmethod):
class
abstractstaticmethod
(
staticmethod
):
class
abstractstaticmethod
(
staticmethod
):
"""A decorator indicating abstract staticmethods.
"""
A decorator indicating abstract staticmethods.
Similar to abstractmethod.
Similar to abstractmethod.
...
@@ -56,6 +61,9 @@ class abstractstaticmethod(staticmethod):
...
@@ -56,6 +61,9 @@ class abstractstaticmethod(staticmethod):
@abstractstaticmethod
@abstractstaticmethod
def my_abstract_staticmethod(...):
def my_abstract_staticmethod(...):
...
...
'abstractstaticmethod' is deprecated. Use 'staticmethod' with
'abstractmethod' instead.
"""
"""
__isabstractmethod__
=
True
__isabstractmethod__
=
True
...
@@ -66,7 +74,8 @@ class abstractstaticmethod(staticmethod):
...
@@ -66,7 +74,8 @@ class abstractstaticmethod(staticmethod):
class
abstractproperty
(
property
):
class
abstractproperty
(
property
):
"""A decorator indicating abstract properties.
"""
A decorator indicating abstract properties.
Requires that the metaclass is ABCMeta or derived from it. A
Requires that the metaclass is ABCMeta or derived from it. A
class that has a metaclass derived from ABCMeta cannot be
class that has a metaclass derived from ABCMeta cannot be
...
@@ -88,7 +97,11 @@ class abstractproperty(property):
...
@@ -88,7 +97,11 @@ class abstractproperty(property):
def getx(self): ...
def getx(self): ...
def setx(self, value): ...
def setx(self, value): ...
x = abstractproperty(getx, setx)
x = abstractproperty(getx, setx)
'abstractproperty' is deprecated. Use 'property' with 'abstractmethod'
instead.
"""
"""
__isabstractmethod__
=
True
__isabstractmethod__
=
True
...
...
This diff is collapsed.
Click to expand it.
Lib/numbers.py
View file @
bfebb7b5
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
TODO: Fill out more detailed documentation on the operators."""
TODO: Fill out more detailed documentation on the operators."""
from
abc
import
ABCMeta
,
abstractmethod
,
abstractproperty
from
abc
import
ABCMeta
,
abstractmethod
__all__
=
[
"Number"
,
"Complex"
,
"Real"
,
"Rational"
,
"Integral"
]
__all__
=
[
"Number"
,
"Complex"
,
"Real"
,
"Rational"
,
"Integral"
]
...
@@ -50,7 +50,8 @@ class Complex(Number):
...
@@ -50,7 +50,8 @@ class Complex(Number):
"""True if self != 0. Called for bool(self)."""
"""True if self != 0. Called for bool(self)."""
return
self
!=
0
return
self
!=
0
@
abstractproperty
@
property
@
abstractmethod
def
real
(
self
):
def
real
(
self
):
"""Retrieve the real component of this number.
"""Retrieve the real component of this number.
...
@@ -58,7 +59,8 @@ class Complex(Number):
...
@@ -58,7 +59,8 @@ class Complex(Number):
"""
"""
raise
NotImplementedError
raise
NotImplementedError
@
abstractproperty
@
property
@
abstractmethod
def
imag
(
self
):
def
imag
(
self
):
"""Retrieve the imaginary component of this number.
"""Retrieve the imaginary component of this number.
...
@@ -272,11 +274,13 @@ class Rational(Real):
...
@@ -272,11 +274,13 @@ class Rational(Real):
__slots__
=
()
__slots__
=
()
@
abstractproperty
@
property
@
abstractmethod
def
numerator
(
self
):
def
numerator
(
self
):
raise
NotImplementedError
raise
NotImplementedError
@
abstractproperty
@
property
@
abstractmethod
def
denominator
(
self
):
def
denominator
(
self
):
raise
NotImplementedError
raise
NotImplementedError
...
...
This diff is collapsed.
Click to expand it.
Lib/test/test_abc.py
View file @
bfebb7b5
...
@@ -10,14 +10,7 @@ import abc
...
@@ -10,14 +10,7 @@ import abc
from
inspect
import
isabstract
from
inspect
import
isabstract
class
TestABC
(
unittest
.
TestCase
):
class
TestLegacyAPI
(
unittest
.
TestCase
):
def
test_abstractmethod_basics
(
self
):
@
abc
.
abstractmethod
def
foo
(
self
):
pass
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
def
bar
(
self
):
pass
self
.
assertFalse
(
hasattr
(
bar
,
"__isabstractmethod__"
))
def
test_abstractproperty_basics
(
self
):
def
test_abstractproperty_basics
(
self
):
@
abc
.
abstractproperty
@
abc
.
abstractproperty
...
@@ -29,10 +22,12 @@ class TestABC(unittest.TestCase):
...
@@ -29,10 +22,12 @@ class TestABC(unittest.TestCase):
class
C
(
metaclass
=
abc
.
ABCMeta
):
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
abc
.
abstractproperty
@
abc
.
abstractproperty
def
foo
(
self
):
return
3
def
foo
(
self
):
return
3
self
.
assertRaises
(
TypeError
,
C
)
class
D
(
C
):
class
D
(
C
):
@
property
@
property
def
foo
(
self
):
return
super
().
foo
def
foo
(
self
):
return
super
().
foo
self
.
assertEqual
(
D
().
foo
,
3
)
self
.
assertEqual
(
D
().
foo
,
3
)
self
.
assertFalse
(
getattr
(
D
.
foo
,
"__isabstractmethod__"
,
False
))
def
test_abstractclassmethod_basics
(
self
):
def
test_abstractclassmethod_basics
(
self
):
@
abc
.
abstractclassmethod
@
abc
.
abstractclassmethod
...
@@ -40,7 +35,7 @@ class TestABC(unittest.TestCase):
...
@@ -40,7 +35,7 @@ class TestABC(unittest.TestCase):
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
@
classmethod
@
classmethod
def
bar
(
cls
):
pass
def
bar
(
cls
):
pass
self
.
assertFalse
(
hasattr
(
bar
,
"__isabstractmethod__"
))
self
.
assertFalse
(
getattr
(
bar
,
"__isabstractmethod__"
,
False
))
class
C
(
metaclass
=
abc
.
ABCMeta
):
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
abc
.
abstractclassmethod
@
abc
.
abstractclassmethod
...
@@ -58,7 +53,7 @@ class TestABC(unittest.TestCase):
...
@@ -58,7 +53,7 @@ class TestABC(unittest.TestCase):
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
@
staticmethod
@
staticmethod
def
bar
():
pass
def
bar
():
pass
self
.
assertFalse
(
hasattr
(
bar
,
"__isabstractmethod__"
))
self
.
assertFalse
(
getattr
(
bar
,
"__isabstractmethod__"
,
False
))
class
C
(
metaclass
=
abc
.
ABCMeta
):
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
abc
.
abstractstaticmethod
@
abc
.
abstractstaticmethod
...
@@ -98,6 +93,163 @@ class TestABC(unittest.TestCase):
...
@@ -98,6 +93,163 @@ class TestABC(unittest.TestCase):
self
.
assertRaises
(
TypeError
,
F
)
# because bar is abstract now
self
.
assertRaises
(
TypeError
,
F
)
# because bar is abstract now
self
.
assertTrue
(
isabstract
(
F
))
self
.
assertTrue
(
isabstract
(
F
))
class
TestABC
(
unittest
.
TestCase
):
def
test_abstractmethod_basics
(
self
):
@
abc
.
abstractmethod
def
foo
(
self
):
pass
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
def
bar
(
self
):
pass
self
.
assertFalse
(
hasattr
(
bar
,
"__isabstractmethod__"
))
def
test_abstractproperty_basics
(
self
):
@
property
@
abc
.
abstractmethod
def
foo
(
self
):
pass
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
def
bar
(
self
):
pass
self
.
assertFalse
(
getattr
(
bar
,
"__isabstractmethod__"
,
False
))
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
property
@
abc
.
abstractmethod
def
foo
(
self
):
return
3
self
.
assertRaises
(
TypeError
,
C
)
class
D
(
C
):
@
C
.
foo
.
getter
def
foo
(
self
):
return
super
().
foo
self
.
assertEqual
(
D
().
foo
,
3
)
def
test_abstractclassmethod_basics
(
self
):
@
classmethod
@
abc
.
abstractmethod
def
foo
(
cls
):
pass
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
@
classmethod
def
bar
(
cls
):
pass
self
.
assertFalse
(
getattr
(
bar
,
"__isabstractmethod__"
,
False
))
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
classmethod
@
abc
.
abstractmethod
def
foo
(
cls
):
return
cls
.
__name__
self
.
assertRaises
(
TypeError
,
C
)
class
D
(
C
):
@
classmethod
def
foo
(
cls
):
return
super
().
foo
()
self
.
assertEqual
(
D
.
foo
(),
'D'
)
self
.
assertEqual
(
D
().
foo
(),
'D'
)
def
test_abstractstaticmethod_basics
(
self
):
@
staticmethod
@
abc
.
abstractmethod
def
foo
():
pass
self
.
assertTrue
(
foo
.
__isabstractmethod__
)
@
staticmethod
def
bar
():
pass
self
.
assertFalse
(
getattr
(
bar
,
"__isabstractmethod__"
,
False
))
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
staticmethod
@
abc
.
abstractmethod
def
foo
():
return
3
self
.
assertRaises
(
TypeError
,
C
)
class
D
(
C
):
@
staticmethod
def
foo
():
return
4
self
.
assertEqual
(
D
.
foo
(),
4
)
self
.
assertEqual
(
D
().
foo
(),
4
)
def
test_abstractmethod_integration
(
self
):
for
abstractthing
in
[
abc
.
abstractmethod
,
abc
.
abstractproperty
,
abc
.
abstractclassmethod
,
abc
.
abstractstaticmethod
]:
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
abstractthing
def
foo
(
self
):
pass
# abstract
def
bar
(
self
):
pass
# concrete
self
.
assertEqual
(
C
.
__abstractmethods__
,
{
"foo"
})
self
.
assertRaises
(
TypeError
,
C
)
# because foo is abstract
self
.
assertTrue
(
isabstract
(
C
))
class
D
(
C
):
def
bar
(
self
):
pass
# concrete override of concrete
self
.
assertEqual
(
D
.
__abstractmethods__
,
{
"foo"
})
self
.
assertRaises
(
TypeError
,
D
)
# because foo is still abstract
self
.
assertTrue
(
isabstract
(
D
))
class
E
(
D
):
def
foo
(
self
):
pass
self
.
assertEqual
(
E
.
__abstractmethods__
,
set
())
E
()
# now foo is concrete, too
self
.
assertFalse
(
isabstract
(
E
))
class
F
(
E
):
@
abstractthing
def
bar
(
self
):
pass
# abstract override of concrete
self
.
assertEqual
(
F
.
__abstractmethods__
,
{
"bar"
})
self
.
assertRaises
(
TypeError
,
F
)
# because bar is abstract now
self
.
assertTrue
(
isabstract
(
F
))
def
test_descriptors_with_abstractmethod
(
self
):
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
property
@
abc
.
abstractmethod
def
foo
(
self
):
return
3
@
foo
.
setter
@
abc
.
abstractmethod
def
foo
(
self
,
val
):
pass
self
.
assertRaises
(
TypeError
,
C
)
class
D
(
C
):
@
C
.
foo
.
getter
def
foo
(
self
):
return
super
().
foo
self
.
assertRaises
(
TypeError
,
D
)
class
E
(
D
):
@
D
.
foo
.
setter
def
foo
(
self
,
val
):
pass
self
.
assertEqual
(
E
().
foo
,
3
)
# check that the property's __isabstractmethod__ descriptor does the
# right thing when presented with a value that fails truth testing:
class
NotBool
(
object
):
def
__nonzero__
(
self
):
raise
ValueError
()
__len__
=
__nonzero__
with
self
.
assertRaises
(
ValueError
):
class
F
(
C
):
def
bar
(
self
):
pass
bar
.
__isabstractmethod__
=
NotBool
()
foo
=
property
(
bar
)
def
test_customdescriptors_with_abstractmethod
(
self
):
class
Descriptor
:
def
__init__
(
self
,
fget
,
fset
=
None
):
self
.
_fget
=
fget
self
.
_fset
=
fset
def
getter
(
self
,
callable
):
return
Descriptor
(
callable
,
self
.
_fget
)
def
setter
(
self
,
callable
):
return
Descriptor
(
self
.
_fget
,
callable
)
@
property
def
__isabstractmethod__
(
self
):
return
(
getattr
(
self
.
_fget
,
'__isabstractmethod__'
,
False
)
or
getattr
(
self
.
_fset
,
'__isabstractmethod__'
,
False
))
class
C
(
metaclass
=
abc
.
ABCMeta
):
@
Descriptor
@
abc
.
abstractmethod
def
foo
(
self
):
return
3
@
foo
.
setter
@
abc
.
abstractmethod
def
foo
(
self
,
val
):
pass
self
.
assertRaises
(
TypeError
,
C
)
class
D
(
C
):
@
C
.
foo
.
getter
def
foo
(
self
):
return
super
().
foo
self
.
assertRaises
(
TypeError
,
D
)
class
E
(
D
):
@
D
.
foo
.
setter
def
foo
(
self
,
val
):
pass
self
.
assertFalse
(
E
.
foo
.
__isabstractmethod__
)
def
test_metaclass_abc
(
self
):
def
test_metaclass_abc
(
self
):
# Metaclasses can be ABCs, too.
# Metaclasses can be ABCs, too.
class
A
(
metaclass
=
abc
.
ABCMeta
):
class
A
(
metaclass
=
abc
.
ABCMeta
):
...
...
This diff is collapsed.
Click to expand it.
Lib/test/test_property.py
View file @
bfebb7b5
...
@@ -128,6 +128,29 @@ class PropertyTests(unittest.TestCase):
...
@@ -128,6 +128,29 @@ class PropertyTests(unittest.TestCase):
self
.
assertEqual
(
newgetter
.
spam
,
8
)
self
.
assertEqual
(
newgetter
.
spam
,
8
)
self
.
assertEqual
(
newgetter
.
__class__
.
spam
.
__doc__
,
"new docstring"
)
self
.
assertEqual
(
newgetter
.
__class__
.
spam
.
__doc__
,
"new docstring"
)
def
test_property___isabstractmethod__descriptor
(
self
):
for
val
in
(
True
,
False
,
[],
[
1
],
''
,
'1'
):
class
C
(
object
):
def
foo
(
self
):
pass
foo
.
__isabstractmethod__
=
val
foo
=
property
(
foo
)
self
.
assertIs
(
C
.
foo
.
__isabstractmethod__
,
bool
(
val
))
# check that the property's __isabstractmethod__ descriptor does the
# right thing when presented with a value that fails truth testing:
class
NotBool
(
object
):
def
__nonzero__
(
self
):
raise
ValueError
()
__len__
=
__nonzero__
with
self
.
assertRaises
(
ValueError
):
class
C
(
object
):
def
foo
(
self
):
pass
foo
.
__isabstractmethod__
=
NotBool
()
foo
=
property
(
foo
)
C
.
foo
.
__isabstractmethod__
# Issue 5890: subclasses of property do not preserve method __doc__ strings
# Issue 5890: subclasses of property do not preserve method __doc__ strings
class
PropertySub
(
property
):
class
PropertySub
(
property
):
...
...
This diff is collapsed.
Click to expand it.
Misc/ACKS
View file @
bfebb7b5
...
@@ -220,6 +220,7 @@ Tom Culliton
...
@@ -220,6 +220,7 @@ Tom Culliton
Antonio Cuni
Antonio Cuni
Brian Curtin
Brian Curtin
Lisandro Dalcin
Lisandro Dalcin
Darren Dale
Andrew Dalke
Andrew Dalke
Lars Damerow
Lars Damerow
Evan Dandrea
Evan Dandrea
...
...
This diff is collapsed.
Click to expand it.
Misc/NEWS
View file @
bfebb7b5
...
@@ -416,6 +416,8 @@ Core and Builtins
...
@@ -416,6 +416,8 @@ Core and Builtins
Library
Library
-------
-------
-
Issue
#
11610
:
Introduce
a
more
general
way
to
declare
abstract
properties
.
-
Issue
#
13591
:
A
bug
in
importlib
has
been
fixed
that
caused
import_module
-
Issue
#
13591
:
A
bug
in
importlib
has
been
fixed
that
caused
import_module
to
load
a
module
twice
.
to
load
a
module
twice
.
...
...
This diff is collapsed.
Click to expand it.
Objects/descrobject.c
View file @
bfebb7b5
...
@@ -1380,6 +1380,43 @@ property_init(PyObject *self, PyObject *args, PyObject *kwds)
...
@@ -1380,6 +1380,43 @@ property_init(PyObject *self, PyObject *args, PyObject *kwds)
return
0
;
return
0
;
}
}
static
PyObject
*
property_get___isabstractmethod__
(
propertyobject
*
prop
,
void
*
closure
)
{
int
res
=
_PyObject_IsAbstract
(
prop
->
prop_get
);
if
(
res
==
-
1
)
{
return
NULL
;
}
else
if
(
res
)
{
Py_RETURN_TRUE
;
}
res
=
_PyObject_IsAbstract
(
prop
->
prop_set
);
if
(
res
==
-
1
)
{
return
NULL
;
}
else
if
(
res
)
{
Py_RETURN_TRUE
;
}
res
=
_PyObject_IsAbstract
(
prop
->
prop_del
);
if
(
res
==
-
1
)
{
return
NULL
;
}
else
if
(
res
)
{
Py_RETURN_TRUE
;
}
Py_RETURN_FALSE
;
}
static
PyGetSetDef
property_getsetlist
[]
=
{
{
"__isabstractmethod__"
,
(
getter
)
property_get___isabstractmethod__
,
NULL
,
NULL
,
NULL
},
{
NULL
}
/* Sentinel */
};
PyDoc_STRVAR
(
property_doc
,
PyDoc_STRVAR
(
property_doc
,
"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
\n
"
"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
\n
"
"
\n
"
"
\n
"
...
@@ -1445,7 +1482,7 @@ PyTypeObject PyProperty_Type = {
...
@@ -1445,7 +1482,7 @@ PyTypeObject PyProperty_Type = {
0
,
/* tp_iternext */
0
,
/* tp_iternext */
property_methods
,
/* tp_methods */
property_methods
,
/* tp_methods */
property_members
,
/* tp_members */
property_members
,
/* tp_members */
0
,
/* tp_getset */
property_getsetlist
,
/* tp_getset */
0
,
/* tp_base */
0
,
/* tp_base */
0
,
/* tp_dict */
0
,
/* tp_dict */
property_descr_get
,
/* tp_descr_get */
property_descr_get
,
/* tp_descr_get */
...
...
This diff is collapsed.
Click to expand it.
Objects/funcobject.c
View file @
bfebb7b5
...
@@ -814,6 +814,27 @@ static PyMemberDef cm_memberlist[] = {
...
@@ -814,6 +814,27 @@ static PyMemberDef cm_memberlist[] = {
{
NULL
}
/* Sentinel */
{
NULL
}
/* Sentinel */
};
};
static
PyObject
*
cm_get___isabstractmethod__
(
classmethod
*
cm
,
void
*
closure
)
{
int
res
=
_PyObject_IsAbstract
(
cm
->
cm_callable
);
if
(
res
==
-
1
)
{
return
NULL
;
}
else
if
(
res
)
{
Py_RETURN_TRUE
;
}
Py_RETURN_FALSE
;
}
static
PyGetSetDef
cm_getsetlist
[]
=
{
{
"__isabstractmethod__"
,
(
getter
)
cm_get___isabstractmethod__
,
NULL
,
NULL
,
NULL
},
{
NULL
}
/* Sentinel */
};
PyDoc_STRVAR
(
classmethod_doc
,
PyDoc_STRVAR
(
classmethod_doc
,
"classmethod(function) -> method
\n
\
"classmethod(function) -> method
\n
\
\n
\
\n
\
...
@@ -865,7 +886,7 @@ PyTypeObject PyClassMethod_Type = {
...
@@ -865,7 +886,7 @@ PyTypeObject PyClassMethod_Type = {
0
,
/* tp_iternext */
0
,
/* tp_iternext */
0
,
/* tp_methods */
0
,
/* tp_methods */
cm_memberlist
,
/* tp_members */
cm_memberlist
,
/* tp_members */
0
,
/* tp_getset */
cm_getsetlist
,
/* tp_getset */
0
,
/* tp_base */
0
,
/* tp_base */
0
,
/* tp_dict */
0
,
/* tp_dict */
cm_descr_get
,
/* tp_descr_get */
cm_descr_get
,
/* tp_descr_get */
...
@@ -969,6 +990,27 @@ static PyMemberDef sm_memberlist[] = {
...
@@ -969,6 +990,27 @@ static PyMemberDef sm_memberlist[] = {
{
NULL
}
/* Sentinel */
{
NULL
}
/* Sentinel */
};
};
static
PyObject
*
sm_get___isabstractmethod__
(
staticmethod
*
sm
,
void
*
closure
)
{
int
res
=
_PyObject_IsAbstract
(
sm
->
sm_callable
);
if
(
res
==
-
1
)
{
return
NULL
;
}
else
if
(
res
)
{
Py_RETURN_TRUE
;
}
Py_RETURN_FALSE
;
}
static
PyGetSetDef
sm_getsetlist
[]
=
{
{
"__isabstractmethod__"
,
(
getter
)
sm_get___isabstractmethod__
,
NULL
,
NULL
,
NULL
},
{
NULL
}
/* Sentinel */
};
PyDoc_STRVAR
(
staticmethod_doc
,
PyDoc_STRVAR
(
staticmethod_doc
,
"staticmethod(function) -> method
\n
\
"staticmethod(function) -> method
\n
\
\n
\
\n
\
...
@@ -1017,7 +1059,7 @@ PyTypeObject PyStaticMethod_Type = {
...
@@ -1017,7 +1059,7 @@ PyTypeObject PyStaticMethod_Type = {
0
,
/* tp_iternext */
0
,
/* tp_iternext */
0
,
/* tp_methods */
0
,
/* tp_methods */
sm_memberlist
,
/* tp_members */
sm_memberlist
,
/* tp_members */
0
,
/* tp_getset */
sm_getsetlist
,
/* tp_getset */
0
,
/* tp_base */
0
,
/* tp_base */
0
,
/* tp_dict */
0
,
/* tp_dict */
sm_descr_get
,
/* tp_descr_get */
sm_descr_get
,
/* tp_descr_get */
...
...
This diff is collapsed.
Click to expand it.
Objects/object.c
View file @
bfebb7b5
...
@@ -840,6 +840,29 @@ PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w)
...
@@ -840,6 +840,29 @@ PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w)
return
res
;
return
res
;
}
}
int
_PyObject_IsAbstract
(
PyObject
*
obj
)
{
int
res
;
PyObject
*
isabstract
;
_Py_IDENTIFIER
(
__isabstractmethod__
);
if
(
obj
==
NULL
)
return
0
;
isabstract
=
_PyObject_GetAttrId
(
obj
,
&
PyId___isabstractmethod__
);
if
(
isabstract
==
NULL
)
{
if
(
PyErr_ExceptionMatches
(
PyExc_AttributeError
))
{
PyErr_Clear
();
return
0
;
}
return
-
1
;
}
res
=
PyObject_IsTrue
(
isabstract
);
Py_DECREF
(
isabstract
);
return
res
;
}
PyObject
*
PyObject
*
_PyObject_GetAttrId
(
PyObject
*
v
,
_Py_Identifier
*
name
)
_PyObject_GetAttrId
(
PyObject
*
v
,
_Py_Identifier
*
name
)
{
{
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment