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