##// END OF EJS Templates
don't rely on hasattr in utils.dir2...
Jörgen Stenarson -
Show More
@@ -1,82 +1,94 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A fancy version of Python's builtin :func:`dir` function.
2 """A fancy version of Python's builtin :func:`dir` function.
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2008-2009 The IPython Development Team
6 # Copyright (C) 2008-2009 The IPython Development Team
7 #
7 #
8 # Distributed under the terms of the BSD License. The full license is in
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
9 # the file COPYING, distributed as part of this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Code
17 # Code
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 def get_class_members(cls):
20 def get_class_members(cls):
21 ret = dir(cls)
21 ret = dir(cls)
22 if hasattr(cls,'__bases__'):
22 if hasattr(cls,'__bases__'):
23 for base in cls.__bases__:
23 try:
24 ret.extend(get_class_members(base))
24 bases = cls.__bases__
25 except AttributeError:
26 # `obj` lied to hasattr (e.g. Pyro), ignore
27 pass
28 else:
29 for base in bases:
30 ret.extend(get_class_members(base))
25 return ret
31 return ret
26
32
27
33
28 def dir2(obj):
34 def dir2(obj):
29 """dir2(obj) -> list of strings
35 """dir2(obj) -> list of strings
30
36
31 Extended version of the Python builtin dir(), which does a few extra
37 Extended version of the Python builtin dir(), which does a few extra
32 checks, and supports common objects with unusual internals that confuse
38 checks, and supports common objects with unusual internals that confuse
33 dir(), such as Traits and PyCrust.
39 dir(), such as Traits and PyCrust.
34
40
35 This version is guaranteed to return only a list of true strings, whereas
41 This version is guaranteed to return only a list of true strings, whereas
36 dir() returns anything that objects inject into themselves, even if they
42 dir() returns anything that objects inject into themselves, even if they
37 are later not really valid for attribute access (many extension libraries
43 are later not really valid for attribute access (many extension libraries
38 have such bugs).
44 have such bugs).
39 """
45 """
40
46
41 # Start building the attribute list via dir(), and then complete it
47 # Start building the attribute list via dir(), and then complete it
42 # with a few extra special-purpose calls.
48 # with a few extra special-purpose calls.
43 words = dir(obj)
49 words = dir(obj)
44
50
45 if hasattr(obj,'__class__'):
51 if hasattr(obj,'__class__'):
46 words.append('__class__')
52 words.append('__class__')
47 words.extend(get_class_members(obj.__class__))
53 words.extend(get_class_members(obj.__class__))
48 #if '__base__' in words: 1/0
54 #if '__base__' in words: 1/0
49
55
50 # Some libraries (such as traits) may introduce duplicates, we want to
56 # Some libraries (such as traits) may introduce duplicates, we want to
51 # track and clean this up if it happens
57 # track and clean this up if it happens
52 may_have_dupes = False
58 may_have_dupes = False
53
59
54 # this is the 'dir' function for objects with Enthought's traits
60 # this is the 'dir' function for objects with Enthought's traits
55 if hasattr(obj, 'trait_names'):
61 if hasattr(obj, 'trait_names'):
56 try:
62 try:
57 words.extend(obj.trait_names())
63 words.extend(obj.trait_names())
58 may_have_dupes = True
64 may_have_dupes = True
59 except TypeError:
65 except TypeError:
60 # This will happen if `obj` is a class and not an instance.
66 # This will happen if `obj` is a class and not an instance.
61 pass
67 pass
68 except AttributeError:
69 # `obj` lied to hasatter (e.g. Pyro), ignore
70 pass
62
71
63 # Support for PyCrust-style _getAttributeNames magic method.
72 # Support for PyCrust-style _getAttributeNames magic method.
64 if hasattr(obj, '_getAttributeNames'):
73 if hasattr(obj, '_getAttributeNames'):
65 try:
74 try:
66 words.extend(obj._getAttributeNames())
75 words.extend(obj._getAttributeNames())
67 may_have_dupes = True
76 may_have_dupes = True
68 except TypeError:
77 except TypeError:
69 # `obj` is a class and not an instance. Ignore
78 # `obj` is a class and not an instance. Ignore
70 # this error.
79 # this error.
71 pass
80 pass
81 except AttributeError:
82 # `obj` lied to hasatter (e.g. Pyro), ignore
83 pass
72
84
73 if may_have_dupes:
85 if may_have_dupes:
74 # eliminate possible duplicates, as some traits may also
86 # eliminate possible duplicates, as some traits may also
75 # appear as normal attributes in the dir() call.
87 # appear as normal attributes in the dir() call.
76 words = list(set(words))
88 words = list(set(words))
77 words.sort()
89 words.sort()
78
90
79 # filter out non-string attributes which may be stuffed by dir() calls
91 # filter out non-string attributes which may be stuffed by dir() calls
80 # and poor coding in third-party modules
92 # and poor coding in third-party modules
81 return [w for w in words if isinstance(w, basestring)]
93 return [w for w in words if isinstance(w, basestring)]
82
94
General Comments 0
You need to be logged in to leave comments. Login now