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

Delta Between Two Patch Sets: Lib/abc.py

Issue 11610: Improving property to accept abstract methods
Left Patch Set: Created 8 years, 8 months ago
Right Patch Set: Created 8 years 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Include/object.h ('k') | Lib/numbers.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 The abstract methods can be called using any of the normal
15 'super' call mechanisms. 15 'super' call mechanisms.
16 16
17 Usage: 17 Usage:
18 18
19 class C(metaclass=ABCMeta): 19 class C(metaclass=ABCMeta):
20 @abstractmethod 20 @abstractmethod
21 def my_abstract_method(self, ...): 21 def my_abstract_method(self, ...):
22 ... 22 ...
23 """ 23 """
24 funcobj.__isabstractmethod__ = True 24 funcobj.__isabstractmethod__ = True
25 return funcobj 25 return funcobj
26 26
27 27
28 class abstractclassmethod(classmethod): 28 class abstractclassmethod(classmethod):
29 """A decorator indicating abstract classmethods. 29 """
30 A decorator indicating abstract classmethods.
30 31
31 Similar to abstractmethod. 32 Similar to abstractmethod.
32 33
33 Usage: 34 Usage:
34 35
35 class C(metaclass=ABCMeta): 36 class C(metaclass=ABCMeta):
36 @abstractclassmethod 37 @abstractclassmethod
37 def my_abstract_classmethod(cls, ...): 38 def my_abstract_classmethod(cls, ...):
38 ... 39 ...
40
41 'abstractclassmethod' is deprecated. Use 'classmethod' with
42 'abstractmethod' instead.
39 """ 43 """
40 44
41 __isabstractmethod__ = True 45 __isabstractmethod__ = True
42 46
43 def __init__(self, callable): 47 def __init__(self, callable):
44 callable.__isabstractmethod__ = True 48 callable.__isabstractmethod__ = True
45 super().__init__(callable) 49 super().__init__(callable)
46 50
47 51
48 class abstractstaticmethod(staticmethod): 52 class abstractstaticmethod(staticmethod):
49 """A decorator indicating abstract staticmethods. 53 """
54 A decorator indicating abstract staticmethods.
50 55
51 Similar to abstractmethod. 56 Similar to abstractmethod.
52 57
53 Usage: 58 Usage:
54 59
55 class C(metaclass=ABCMeta): 60 class C(metaclass=ABCMeta):
56 @abstractstaticmethod 61 @abstractstaticmethod
57 def my_abstract_staticmethod(...): 62 def my_abstract_staticmethod(...):
58 ... 63 ...
64
65 'abstractstaticmethod' is deprecated. Use 'staticmethod' with
66 'abstractmethod' instead.
59 """ 67 """
60 68
61 __isabstractmethod__ = True 69 __isabstractmethod__ = True
62 70
63 def __init__(self, callable): 71 def __init__(self, callable):
64 callable.__isabstractmethod__ = True 72 callable.__isabstractmethod__ = True
65 super().__init__(callable) 73 super().__init__(callable)
66 74
67 75
68 class abstractproperty(property): 76 class abstractproperty(property):
69 """A decorator indicating abstract properties. 77 """
78 A decorator indicating abstract properties.
70 79
71 Requires that the metaclass is ABCMeta or derived from it. A 80 Requires that the metaclass is ABCMeta or derived from it. A
72 class that has a metaclass derived from ABCMeta cannot be 81 class that has a metaclass derived from ABCMeta cannot be
73 instantiated unless all of its abstract properties are overridden. 82 instantiated unless all of its abstract properties are overridden.
74 The abstract properties can be called using any of the normal 83 The abstract properties can be called using any of the normal
75 'super' call mechanisms. 84 'super' call mechanisms.
76 85
77 Usage: 86 Usage:
78 87
79 class A(metaclass=ABCMeta): 88 class C(metaclass=ABCMeta):
89 @abstractproperty
90 def my_abstract_property(self):
91 ...
92
93 This defines a read-only property; you can also define a read-write
94 abstract property using the 'long' form of property declaration:
95
96 class C(metaclass=ABCMeta):
80 def getx(self): ... 97 def getx(self): ...
81 x = abstractproperty(getx) 98 def setx(self, value): ...
82
83 However, this example does not make a lot of sense, because
84 the abstractproperty has been passed a concrete method:
85
86 class B(A):
87 x = property(A.getx)
88
89 To improve the situation, methods that should be overridden
90 with concrete implementations should be decorated with
91 abstractmethod before they are passed to abstractproperty:
92
93 class C(metaclass=ABCMeta):
94 @abstractmethod
95 def getx(self):
96 ...
97 @abstractmethod
98 def setx(self, value):
99 ...
100 x = abstractproperty(getx, setx) 99 x = abstractproperty(getx, setx)
101 100
102 You can also define an abstract property using the decorator form 101 'abstractproperty' is deprecated. Use 'property' with 'abstractmethod'
103 of property declaration: 102 instead.
104
105 class D(metaclass=ABCMeta):
106 @abstractproperty
107 @abstractmethod
108 def x(self):
109 ...
110 @x.setter
111 @abstractmethod
112 def x(self, val):
113 ...
114
115 Subclasses will not be instantiable until the property definition
116 is fully concrete:
117
118 class E(D):
119 @D.x.getter
120 def x(self):
121 ...
122
123 class F(D):
124 @D.x.getter
125 def x(self):
126 ...
127 @x.setter
128 def x(self, val):
129 ...
130
131 In this example, 'E' is not instantiable, because the 'x' setter
132 is abstract. 'F' has provided concrete implementations for all of
133 the abstract methods associated with 'x', so 'x' is now a regular
134 property , and 'F' is instantiable.
135 """ 103 """
136 104
137 __isabstractmethod__ = True 105 __isabstractmethod__ = True
138
139 def getter(self, fun):
140 """Descriptor to change the getter on a property
141
142 This method calls the create_property class method.
143 """
144 return self.create_property(fun, self.fset, self.fdel, self.__doc__)
145
146 def setter(self, fun):
147 """Descriptor to change the setter on a property
148
149 This method calls the create_property class method.
150 """
151 return self.create_property(self.fget, fun, self.fdel, self.__doc__)
152
153 def deleter(self, fun):
154 """Descriptor to change the deleter on a property
155
156 This method calls the create_property class method.
157 """
158 return self.create_property(self.fget, self.fset, fun, self.__doc__)
159
160 @classmethod
161 def create_property(cls, fget=None, fset=None, fdel=None, doc=None):
162 """Create a new property
163
164 'create_property' is a factory function that returns a new
165 instance of 'cls' if any of 'fget', 'fset', or 'fdel' are
166 abstract methods, otherwise it returns a concrete property.
167
168 This method is called by 'getter', 'setter', and 'deleter'.
169 """
170 for f in (fget, fset, fdel):
171 if (f is not None) and getattr(f, '__isabstractmethod__', False):
172 # has abstract methods, return an abstract property
173 return cls(fget, fset, fdel, doc)
174 # does not have abstract methods, return a concrete property
175 return property(fget, fset, fdel, doc)
176 106
177 107
178 class ABCMeta(type): 108 class ABCMeta(type):
179 109
180 """Metaclass for defining Abstract Base Classes (ABCs). 110 """Metaclass for defining Abstract Base Classes (ABCs).
181 111
182 Use this metaclass to create an ABC. An ABC can be subclassed 112 Use this metaclass to create an ABC. An ABC can be subclassed
183 directly, and then acts as a mix-in class. You can also register 113 directly, and then acts as a mix-in class. You can also register
184 unrelated concrete classes (even built-in classes) and unrelated 114 unrelated concrete classes (even built-in classes) and unrelated
185 ABCs as 'virtual subclasses' -- these and their descendants will 115 ABCs as 'virtual subclasses' -- these and their descendants will
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 cls._abc_cache.add(subclass) 219 cls._abc_cache.add(subclass)
290 return True 220 return True
291 # Check if it's a subclass of a subclass (recursive) 221 # Check if it's a subclass of a subclass (recursive)
292 for scls in cls.__subclasses__(): 222 for scls in cls.__subclasses__():
293 if issubclass(subclass, scls): 223 if issubclass(subclass, scls):
294 cls._abc_cache.add(subclass) 224 cls._abc_cache.add(subclass)
295 return True 225 return True
296 # No dice; update negative cache 226 # No dice; update negative cache
297 cls._abc_negative_cache.add(subclass) 227 cls._abc_negative_cache.add(subclass)
298 return False 228 return False
LEFTRIGHT

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