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

Delta Between Two Patch Sets: Lib/inspect.py

Issue 18929: inspect.classify_class_attrs ignores metaclass
Left Patch Set: Created 6 years, 3 months ago
Right Patch Set: Created 6 years, 3 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Doc/library/inspect.rst ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 """Get useful information from live Python objects. 1 """Get useful information from live Python objects.
2 2
3 This module encapsulates the interface provided by the internal special 3 This module encapsulates the interface provided by the internal special
4 attributes (co_*, im_*, tb_*, etc.) in a friendlier fashion. 4 attributes (co_*, im_*, tb_*, etc.) in a friendlier fashion.
5 It also provides some help for examining source code and class layout. 5 It also provides some help for examining source code and class layout.
6 6
7 Here are some of the useful functions provided by this module: 7 Here are some of the useful functions provided by this module:
8 8
9 ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(), 9 ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
10 isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(), 10 isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 'method' any other flavor of method 301 'method' any other flavor of method
302 'data' not a method 302 'data' not a method
303 303
304 2. The class which defined this attribute (a class). 304 2. The class which defined this attribute (a class).
305 305
306 3. The object as obtained directly from the defining class's 306 3. The object as obtained directly from the defining class's
307 __dict__, not via getattr. This is especially important for 307 __dict__, not via getattr. This is especially important for
308 data attributes: C.data is just a data object, but 308 data attributes: C.data is just a data object, but
309 C.__dict__['data'] may be a data descriptor with additional 309 C.__dict__['data'] may be a data descriptor with additional
310 info, like a __doc__ string. 310 info, like a __doc__ string.
311
312 If one of the items in dir(cls) is stored in the metaclass it will now
313 be discovered and not have None be listed as the class in which it was
314 defined.
311 """ 315 """
312 316
313 mro = getmro(cls) 317 mro = getmro(cls)
318 metamro = getmro(type(cls)) # for attributes stored in the metaclass
314 names = dir(cls) 319 names = dir(cls)
315 result = [] 320 result = []
316 for name in names: 321 for name in names:
317 # Get the object associated with the name, and where it was defined. 322 # Get the object associated with the name, and where it was defined.
318 # Getting an obj from the __dict__ sometimes reveals more than 323 # Getting an obj from the __dict__ sometimes reveals more than
319 # using getattr. Static and class methods are dramatic examples. 324 # using getattr. Static and class methods are dramatic examples.
320 # Furthermore, some objects may raise an Exception when fetched with 325 # Furthermore, some objects may raise an Exception when fetched with
321 # getattr(). This is the case with some descriptors (bug #1785). 326 # getattr(). This is the case with some descriptors (bug #1785).
322 # Thus, we only use getattr() as a last resort. 327 # Thus, we only use getattr() as a last resort.
323 homecls = None 328 homecls = None
324 for base in (cls,) + mro: 329 for base in (cls,) + mro + metamro:
325 if name in base.__dict__: 330 if name in base.__dict__:
326 obj = base.__dict__[name] 331 obj = base.__dict__[name]
327 homecls = base 332 homecls = base
328 break 333 break
329 else: 334 else:
330 obj = getattr(cls, name) 335 obj = getattr(cls, name)
331 homecls = getattr(obj, "__objclass__", homecls) 336 homecls = getattr(obj, "__objclass__", homecls)
332 337
333 # Classify the object. 338 # Classify the object.
334 if isinstance(obj, staticmethod): 339 if isinstance(obj, staticmethod):
(...skipping 15 matching lines...) Expand all
350 kind = "data" 355 kind = "data"
351 obj = obj_via_getattr 356 obj = obj_via_getattr
352 357
353 result.append(Attribute(name, kind, homecls, obj)) 358 result.append(Attribute(name, kind, homecls, obj))
354 359
355 return result 360 return result
356 361
357 # ----------------------------------------------------------- class helpers 362 # ----------------------------------------------------------- class helpers
358 363
359 def getmro(cls): 364 def getmro(cls):
360 "Return tuple of base classes (including cls and metaclass) in method resolu tion order." 365 "Return tuple of base classes (including cls) in method resolution order."
361 return cls.__mro__ + (type(cls), ) 366 return cls.__mro__
362 367
363 # -------------------------------------------------------- function helpers 368 # -------------------------------------------------------- function helpers
364 369
365 def unwrap(func, *, stop=None): 370 def unwrap(func, *, stop=None):
366 """Get the object wrapped by *func*. 371 """Get the object wrapped by *func*.
367 372
368 Follows the chain of :attr:`__wrapped__` attributes returning the last 373 Follows the chain of :attr:`__wrapped__` attributes returning the last
369 object in the chain. 374 object in the chain.
370 375
371 *stop* is an optional callback accepting an object in the wrapper chain 376 *stop* is an optional callback accepting an object in the wrapper chain
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after
782 argument is true, exactly one entry appears in the returned structure 787 argument is true, exactly one entry appears in the returned structure
783 for each class in the given list. Otherwise, classes using multiple 788 for each class in the given list. Otherwise, classes using multiple
784 inheritance and their descendants will appear multiple times.""" 789 inheritance and their descendants will appear multiple times."""
785 children = {} 790 children = {}
786 roots = [] 791 roots = []
787 for c in classes: 792 for c in classes:
788 if c.__bases__: 793 if c.__bases__:
789 for parent in c.__bases__: 794 for parent in c.__bases__:
790 if not parent in children: 795 if not parent in children:
791 children[parent] = [] 796 children[parent] = []
792 children[parent].append(c) 797 if c not in children[parent]:
798 children[parent].append(c)
793 if unique and parent in classes: break 799 if unique and parent in classes: break
794 elif c not in roots: 800 elif c not in roots:
795 roots.append(c) 801 roots.append(c)
796 for parent in children: 802 for parent in children:
797 if parent not in classes: 803 if parent not in classes:
798 roots.append(parent) 804 roots.append(parent)
799 return walktree(roots, children, None) 805 return walktree(roots, children, None)
800 806
801 # ------------------------------------------------ argument list extraction 807 # ------------------------------------------------ argument list extraction
802 Arguments = namedtuple('Arguments', 'args, varargs, varkw') 808 Arguments = namedtuple('Arguments', 'args, varargs, varkw')
(...skipping 1293 matching lines...) Expand 10 before | Expand all | Expand 10 after
2096 2102
2097 result.append(formatted) 2103 result.append(formatted)
2098 2104
2099 rendered = '({})'.format(', '.join(result)) 2105 rendered = '({})'.format(', '.join(result))
2100 2106
2101 if self.return_annotation is not _empty: 2107 if self.return_annotation is not _empty:
2102 anno = formatannotation(self.return_annotation) 2108 anno = formatannotation(self.return_annotation)
2103 rendered += ' -> {}'.format(anno) 2109 rendered += ' -> {}'.format(anno)
2104 2110
2105 return rendered 2111 return rendered
LEFTRIGHT

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