Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(2)

Side by Side Diff: Lib/abc.py

Issue 11610: Improving property to accept abstract methods
Patch Set: Created 8 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Doc/whatsnew/3.3.rst ('k') | Lib/numbers.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2007 Google, Inc. All Rights Reserved. 1 # Copyright 2007 Google, Inc. All Rights Reserved.
2 # Licensed to PSF under a Contributor Agreement. 2 # Licensed to PSF under a Contributor Agreement.
3 3
4 """Abstract Base Classes (ABCs) according to PEP 3119.""" 4 """Abstract Base Classes (ABCs) according to PEP 3119."""
5 5
6 from _weakrefset import WeakSet 6 from _weakrefset import WeakSet
7 7
8 def abstractmethod(funcobj): 8 def abstractmethod(funcobj):
9 """A decorator indicating abstract methods. 9 """A decorator indicating abstract methods.
10 10
11 Requires that the metaclass is ABCMeta or derived from it. A 11 Requires that the metaclass is ABCMeta or derived from it. A
12 class that has a metaclass derived from ABCMeta cannot be 12 class that has a metaclass derived from ABCMeta cannot be
13 instantiated unless all of its abstract methods are overridden. 13 instantiated unless all of its abstract methods are overridden.
14 The abstract methods can be called using any of the normal 14 abstractmethod can be used to specify abstract methods for
15 'super' call mechanisms. 15 properties and descriptors. The abstract methods can be called
16 using any of the normal 'super' call mechanisms.
16 17
17 Usage: 18 Usage:
18 19
19 class C(metaclass=ABCMeta): 20 class C(metaclass=ABCMeta):
20 @abstractmethod 21 @abstractmethod
21 def my_abstract_method(self, ...): 22 def my_abstract_method(self, ...):
22 ... 23 ...
24
25 @property
26 @abstractmethod
27 def my_abstract_property(self):
28 ...
29 @my_abstract_property.setter
30 @abstractmethod
31 def my_abstract_property(self, val):
32 ...
33
34 @abstractmethod
35 def _get_x(self):
36 ...
37 @abstractmethod
38 def _set_x(self, val):
39 ...
40 x = property(_get_x, _set_x)
41
23 """ 42 """
24 funcobj.__isabstractmethod__ = True 43 funcobj.__isabstractmethod__ = True
25 return funcobj 44 return funcobj
26 45
27 46
28 class abstractclassmethod(classmethod): 47 class abstractclassmethod(classmethod):
29 """A decorator indicating abstract classmethods. 48 """A decorator indicating abstract classmethods.
30 49
31 Similar to abstractmethod. 50 Similar to abstractmethod.
32 51
(...skipping 26 matching lines...) Expand all
59 """ 78 """
60 79
61 __isabstractmethod__ = True 80 __isabstractmethod__ = True
62 81
63 def __init__(self, callable): 82 def __init__(self, callable):
64 callable.__isabstractmethod__ = True 83 callable.__isabstractmethod__ = True
65 super().__init__(callable) 84 super().__init__(callable)
66 85
67 86
68 class abstractproperty(property): 87 class abstractproperty(property):
69 """A decorator indicating abstract properties. 88 """
89 .. deprecated:: 3.3
90 Use :class:`property` and :func:`abstractmethod` instead.
91
92 A decorator indicating abstract properties.
70 93
71 Requires that the metaclass is ABCMeta or derived from it. A 94 Requires that the metaclass is ABCMeta or derived from it. A
72 class that has a metaclass derived from ABCMeta cannot be 95 class that has a metaclass derived from ABCMeta cannot be
73 instantiated unless all of its abstract properties are overridden. 96 instantiated unless all of its abstract properties are overridden.
74 The abstract properties can be called using any of the normal 97 The abstract properties can be called using any of the normal
75 'super' call mechanisms. 98 'super' call mechanisms.
76 99
77 Usage: 100 Usage:
78 101
79 class C(metaclass=ABCMeta): 102 class C(metaclass=ABCMeta):
80 @abstractproperty 103 @abstractproperty
81 def my_abstract_property(self): 104 def my_abstract_property(self):
82 ... 105 ...
83 106
84 This defines a read-only property; you can also define a read-write 107 This defines a read-only property; you can also define a read-write
85 abstract property using the 'long' form of property declaration: 108 abstract property using the 'long' form of property declaration:
86 109
87 class C(metaclass=ABCMeta): 110 class C(metaclass=ABCMeta):
88 def getx(self): ... 111 def getx(self): ...
89 def setx(self, value): ... 112 def setx(self, value): ...
90 x = abstractproperty(getx, setx) 113 x = abstractproperty(getx, setx)
114
91 """ 115 """
92 __isabstractmethod__ = True 116 __isabstractmethod__ = True
117
118 def __init__(self, *args, **kwargs):
119 import warnings
120 warnings.warn("abstractproperty is deprecated", DeprecationWarning, 2)
121 super().__init__(*args, **kwargs)
93 122
94 123
95 class ABCMeta(type): 124 class ABCMeta(type):
96 125
97 """Metaclass for defining Abstract Base Classes (ABCs). 126 """Metaclass for defining Abstract Base Classes (ABCs).
98 127
99 Use this metaclass to create an ABC. An ABC can be subclassed 128 Use this metaclass to create an ABC. An ABC can be subclassed
100 directly, and then acts as a mix-in class. You can also register 129 directly, and then acts as a mix-in class. You can also register
101 unrelated concrete classes (even built-in classes) and unrelated 130 unrelated concrete classes (even built-in classes) and unrelated
102 ABCs as 'virtual subclasses' -- these and their descendants will 131 ABCs as 'virtual subclasses' -- these and their descendants will
103 be considered subclasses of the registering ABC by the built-in 132 be considered subclasses of the registering ABC by the built-in
104 issubclass() function, but the registering ABC won't show up in 133 issubclass() function, but the registering ABC won't show up in
105 their MRO (Method Resolution Order) nor will method 134 their MRO (Method Resolution Order) nor will method
106 implementations defined by the registering ABC be callable (not 135 implementations defined by the registering ABC be callable (not
107 even via super()). 136 even via super()).
108 137
109 """ 138 """
110 139
111 # A global counter that is incremented each time a class is 140 # A global counter that is incremented each time a class is
112 # registered as a virtual subclass of anything. It forces the 141 # registered as a virtual subclass of anything. It forces the
113 # negative cache to be cleared before its next use. 142 # negative cache to be cleared before its next use.
114 _abc_invalidation_counter = 0 143 _abc_invalidation_counter = 0
115 144
116 def __new__(mcls, name, bases, namespace): 145 def __new__(mcls, name, bases, namespace):
117 cls = super().__new__(mcls, name, bases, namespace) 146 cls = super().__new__(mcls, name, bases, namespace)
147
118 # Compute set of abstract method names 148 # Compute set of abstract method names
119 abstracts = {name 149 def is_descriptor(value):
120 for name, value in namespace.items() 150 return (hasattr(value, '__get__') or hasattr(value, '__set__')
121 if getattr(value, "__isabstractmethod__", False)} 151 or hasattr(value, '__delete__'))
152 def is_abstract(value):
153 return getattr(value, "__isabstractmethod__", False)
154 def get_abstract_names_for_item(item):
155 name, value = item
156 if is_abstract(value):
157 return [name]
158 elif is_descriptor(value):
159 return ['{}.{}'.format(name, attr) for attr in dir(value)
160 if is_abstract(getattr(value, attr))]
161 return []
162
163 abstract_names = []
164 for item in namespace.items():
165 abstract_names.extend(get_abstract_names_for_item(item))
166
122 for base in bases: 167 for base in bases:
123 for name in getattr(base, "__abstractmethods__", set()): 168 for name in getattr(base, "__abstractmethods__", ()):
124 value = getattr(cls, name, None) 169 descr_name, is_descr, attr = name.rpartition('.')
125 if getattr(value, "__isabstractmethod__", False): 170 if is_descr:
126 abstracts.add(name) 171 # base class identified a descriptor abstract method:
127 cls.__abstractmethods__ = frozenset(abstracts) 172 descr = getattr(cls, descr_name, None)
173 val = getattr(descr, attr, None)
174 else:
175 val = getattr(cls, name, None)
176 if val is None or is_abstract(val):
177 abstract_names.append(name)
178
179 cls.__abstractmethods__ = frozenset(abstract_names)
180
128 # Set up inheritance registry 181 # Set up inheritance registry
129 cls._abc_registry = WeakSet() 182 cls._abc_registry = WeakSet()
130 cls._abc_cache = WeakSet() 183 cls._abc_cache = WeakSet()
131 cls._abc_negative_cache = WeakSet() 184 cls._abc_negative_cache = WeakSet()
132 cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter 185 cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
133 return cls 186 return cls
134 187
135 def register(cls, subclass): 188 def register(cls, subclass):
136 """Register a virtual subclass of an ABC. 189 """Register a virtual subclass of an ABC.
137 190
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 cls._abc_cache.add(subclass) 259 cls._abc_cache.add(subclass)
207 return True 260 return True
208 # Check if it's a subclass of a subclass (recursive) 261 # Check if it's a subclass of a subclass (recursive)
209 for scls in cls.__subclasses__(): 262 for scls in cls.__subclasses__():
210 if issubclass(subclass, scls): 263 if issubclass(subclass, scls):
211 cls._abc_cache.add(subclass) 264 cls._abc_cache.add(subclass)
212 return True 265 return True
213 # No dice; update negative cache 266 # No dice; update negative cache
214 cls._abc_negative_cache.add(subclass) 267 cls._abc_negative_cache.add(subclass)
215 return False 268 return False
OLDNEW
« no previous file with comments | « Doc/whatsnew/3.3.rst ('k') | Lib/numbers.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+