##// END OF EJS Templates
Further tidying up of IPython.utils.wildcard.
Thomas Kluyver -
Show More
@@ -1,134 +1,125 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Support for wildcard pattern matching in object inspection.
2 """Support for wildcard pattern matching in object inspection.
3
3
4 Authors
4 Authors
5 -------
5 -------
6 - JΓΆrgen Stenarson <jorgen.stenarson@bostream.nu>
6 - JΓΆrgen Stenarson <jorgen.stenarson@bostream.nu>
7 """
7 """
8
8
9 #*****************************************************************************
9 #*****************************************************************************
10 # Copyright (C) 2005 JΓΆrgen Stenarson <jorgen.stenarson@bostream.nu>
10 # Copyright (C) 2005 JΓΆrgen Stenarson <jorgen.stenarson@bostream.nu>
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #*****************************************************************************
14 #*****************************************************************************
15
15
16 import re
16 import re
17 import types
17 import types
18
18
19 from IPython.utils.dir2 import dir2
19 from IPython.utils.dir2 import dir2
20
20
21 def create_typestr2type_dicts(dont_include_in_type2typestr=["lambda"]):
21 def create_typestr2type_dicts(dont_include_in_type2typestr=["lambda"]):
22 """Return dictionaries mapping lower case typename (e.g. 'tuple) to type
22 """Return dictionaries mapping lower case typename (e.g. 'tuple) to type
23 objects from the types package, and vice versa."""
23 objects from the types package, and vice versa."""
24 typenamelist = [tname for tname in dir(types) if tname.endswith("Type")]
24 typenamelist = [tname for tname in dir(types) if tname.endswith("Type")]
25 typestr2type, type2typestr = {}, {}
25 typestr2type, type2typestr = {}, {}
26
26
27 for tname in typenamelist:
27 for tname in typenamelist:
28 name = tname[:-4].lower() # Cut 'Type' off the end of the name
28 name = tname[:-4].lower() # Cut 'Type' off the end of the name
29 obj = getattr(types, tname)
29 obj = getattr(types, tname)
30 typestr2type[name] = obj
30 typestr2type[name] = obj
31 if name not in dont_include_in_type2typestr:
31 if name not in dont_include_in_type2typestr:
32 type2typestr[obj] = name
32 type2typestr[obj] = name
33 return typestr2type, type2typestr
33 return typestr2type, type2typestr
34
34
35 typestr2type, type2typestr = create_typestr2type_dicts()
35 typestr2type, type2typestr = create_typestr2type_dicts()
36
36
37 def is_type(obj, typestr_or_type):
37 def is_type(obj, typestr_or_type):
38 """is_type(obj, typestr_or_type) verifies if obj is of a certain type. It
38 """is_type(obj, typestr_or_type) verifies if obj is of a certain type. It
39 can take strings or actual python types for the second argument, i.e.
39 can take strings or actual python types for the second argument, i.e.
40 'tuple'<->TupleType. 'all' matches all types.
40 'tuple'<->TupleType. 'all' matches all types.
41
41
42 TODO: Should be extended for choosing more than one type."""
42 TODO: Should be extended for choosing more than one type."""
43 if typestr_or_type=="all":
43 if typestr_or_type=="all":
44 return True
44 return True
45 if type(typestr_or_type) == types.TypeType:
45 if type(typestr_or_type) == types.TypeType:
46 test_type = typestr_or_type
46 test_type = typestr_or_type
47 else:
47 else:
48 test_type = typestr2type.get(typestr_or_type, False)
48 test_type = typestr2type.get(typestr_or_type, False)
49 if test_type:
49 if test_type:
50 return isinstance(obj, test_type)
50 return isinstance(obj, test_type)
51 return False
51 return False
52
52
53 def show_hidden(str,show_all=False):
53 def show_hidden(str,show_all=False):
54 """Return true for strings starting with single _ if show_all is true."""
54 """Return true for strings starting with single _ if show_all is true."""
55 return show_all or str.startswith("__") or not str.startswith("_")
55 return show_all or str.startswith("__") or not str.startswith("_")
56
56
57 class NameSpace(dict):
57 class NameSpace(dict):
58 """NameSpace holds the dictionary for a namespace and implements filtering
58 """NameSpace holds the dictionary for a namespace and implements filtering
59 on name and types"""
59 on name and types"""
60
60
61 @classmethod
61 @classmethod
62 def from_object(cls, obj, *args, **kwargs):
62 def from_object(cls, obj, *args, **kwargs):
63 """Instantiate a namespace by constructing a dictionary of an object's
63 """Instantiate a namespace by constructing a dictionary of an object's
64 attributes. A class method, returns a new NameSpace instance."""
64 attributes. A class method, returns a new NameSpace instance."""
65 ns = cls()
65 ns = cls()
66 for key in dir2(obj):
66 for key in dir2(obj):
67 if isinstance(key, basestring):
67 if isinstance(key, basestring):
68 # This seemingly unnecessary try/except is actually needed
68 # This seemingly unnecessary try/except is actually needed
69 # because there is code out there with metaclasses that
69 # because there is code out there with metaclasses that
70 # create 'write only' attributes, where a getattr() call
70 # create 'write only' attributes, where a getattr() call
71 # will fail even if the attribute appears listed in the
71 # will fail even if the attribute appears listed in the
72 # object's dictionary. Properties can actually do the same
72 # object's dictionary. Properties can actually do the same
73 # thing. In particular, Traits use this pattern
73 # thing. In particular, Traits use this pattern
74 try:
74 try:
75 ns[key] = getattr(obj,key)
75 ns[key] = getattr(obj,key)
76 except AttributeError:
76 except AttributeError:
77 pass
77 pass
78 return ns
78 return ns
79
79
80 def filter(self, name_pattern="*", type_pattern="all", ignore_case=True,
80 def filter(self, name_pattern="*", type_pattern="all", ignore_case=True,
81 show_all=True):
81 show_all=True):
82 """Return a dictionary of the namespace filtered by regex pattern and
82 """Return a dictionary of the namespace filtered by regex pattern and
83 item type."""
83 item type."""
84 pattern=name_pattern.replace("*",".*").replace("?",".")
84 pattern=name_pattern.replace("*",".*").replace("?",".")
85 if ignore_case:
85 if ignore_case:
86 reg=re.compile(pattern+"$",re.I)
86 reg=re.compile(pattern+"$",re.I)
87 else:
87 else:
88 reg=re.compile(pattern+"$")
88 reg=re.compile(pattern+"$")
89
89
90 return dict((key,obj) for key,obj in self.iteritems() if all((\
90 # Check each one matches regex; shouldn't be hidden; of correct type.
91 reg.match(key), # Matches pattern
91 return dict((key,obj) for key,obj in self.iteritems() if reg.match(key)\
92 show_hidden(key, show_all), # Not _hidden
92 and show_hidden(key, show_all)\
93 is_type(obj, type_pattern) )) ) # Correct type
93 and is_type(obj, type_pattern))
94
94
95 def list_namespace(namespace,type_pattern,filter,ignore_case=False,show_all=False):
95 def list_namespace(namespace, type_pattern, filter, ignore_case=False, show_all=False):
96 """Return dictionary of all objects in a namespace dictionary that match
96 """Return dictionary of all objects in a namespace dictionary that match
97 type_pattern and filter."""
97 type_pattern and filter."""
98 pattern_list=filter.split(".")
98 pattern_list=filter.split(".")
99 ns = NameSpace(namespace)
99 ns = NameSpace(namespace)
100 return _list_namespace(ns, type_pattern, pattern_list, ignore_case,show_all)
101 # This function is a more convenient wrapper around the recursive one below.
102
103 def _list_namespace(ns, type_pattern, pattern_list, ignore_case=False, show_all=False):
104 """Return dictionary of objects in a namespace which match type_pattern
105 and filter (pattern_list).
106
107 This is a recursive function behind list_namespace, which is intended to be
108 the public interface. Unlike that function, this expects a NameSpace
109 instance as the first argument, and the name pattern split by '.'s."""
100 if len(pattern_list) == 1:
110 if len(pattern_list) == 1:
101 return ns.filter(name_pattern=pattern_list[0], type_pattern=type_pattern,
111 return ns.filter(name_pattern=pattern_list[0], type_pattern=type_pattern,
102 ignore_case=ignore_case, show_all=show_all)
112 ignore_case=ignore_case, show_all=show_all)
103 else:
113 else:
104 # This is where we can change if all objects should be searched or
114 # This is where we can change if all objects should be searched or
105 # only modules. Just change the type_pattern to module to search only
115 # only modules. Just change the type_pattern to module to search only
106 # modules
116 # modules
107 filtered = ns.filter(name_pattern=pattern_list[0], type_pattern="all",
117 filtered = ns.filter(name_pattern=pattern_list[0], type_pattern="all",
108 ignore_case=ignore_case, show_all=show_all)
118 ignore_case=ignore_case, show_all=show_all)
109 results = {}
119 results = {}
110 for name, obj in filtered.iteritems():
120 for name, obj in filtered.iteritems():
111 ns = list_object_namespace(obj, type_pattern, pattern_list[1:],
121 ns = _list_namespace(NameSpace.from_object(obj), type_pattern,
112 ignore_case=ignore_case, show_all=show_all)
122 pattern_list[1:], ignore_case=ignore_case, show_all=show_all)
113 for inner_name, inner_obj in ns.iteritems():
114 results["%s.%s"%(name,inner_name)] = inner_obj
115 return results
116
117 def list_object_namespace(ns_obj, type_pattern, pattern_list, ignore_case=False,
118 show_all=False):
119 """Return dictionary of all attributes of an object which match type_pattern
120 and filter (pattern_list)."""
121 ns = NameSpace.from_object(ns_obj)
122 if len(pattern_list) == 1:
123 return ns.filter(name_pattern=pattern_list[0], type_pattern=type_pattern,
124 ignore_case=ignore_case, show_all=show_all)
125 else:
126 filtered = ns.filter(name_pattern=pattern_list[0], type_pattern="all",
127 ignore_case=ignore_case, show_all=show_all)
128 results = {}
129 for name, obj in filtered.iteritems():
130 ns = list_object_namespace(obj, type_pattern, pattern_list[1:],
131 ignore_case=ignore_case, show_all=show_all)
132 for inner_name,inner_obj in ns.iteritems():
123 for inner_name,inner_obj in ns.iteritems():
133 results["%s.%s"%(name,inner_name)] = inner_obj
124 results["%s.%s"%(name,inner_name)] = inner_obj
134 return results
125 return results
General Comments 0
You need to be logged in to leave comments. Login now