##// END OF EJS Templates
Merge branch 'issue-129'...
Thomas Kluyver -
r3359:26fb9558 merge
parent child Browse files
Show More
@@ -115,3 +115,34 b' class Tests (unittest.TestCase):'
115 show_all=True).keys()
115 show_all=True).keys()
116 a.sort()
116 a.sort()
117 self.assertEqual(a,res)
117 self.assertEqual(a,res)
118
119 def test_dict_attributes(self):
120 """Dictionaries should be indexed by attributes, not by keys. This was
121 causing Github issue 129."""
122 ns = {"az":{"king":55}, "pq":{1:0}}
123 tests = [
124 ("a*", ["az"]),
125 ("az.k*", ["az.keys"]),
126 ("pq.k*", ["pq.keys"])
127 ]
128 for pat, res in tests:
129 res.sort()
130 a = wildcard.list_namespace(ns, "all", pat, ignore_case=False,
131 show_all=True).keys()
132 a.sort()
133 self.assertEqual(a, res)
134
135 def test_dict_dir(self):
136 class A(object):
137 def __init__(self):
138 self.a = 1
139 self.b = 2
140 def __getattribute__(self, name):
141 if name=="a":
142 raise AttributeError
143 return object.__getattribute__(self, name)
144
145 a = A()
146 adict = wildcard.dict_dir(a)
147 assert "a" not in adict # change to assertNotIn method in >= 2.7
148 self.assertEqual(adict["b"], 2)
@@ -4,6 +4,7 b''
4 Authors
4 Authors
5 -------
5 -------
6 - JΓΆrgen Stenarson <jorgen.stenarson@bostream.nu>
6 - JΓΆrgen Stenarson <jorgen.stenarson@bostream.nu>
7 - Thomas Kluyver
7 """
8 """
8
9
9 #*****************************************************************************
10 #*****************************************************************************
@@ -13,134 +14,98 b' Authors'
13 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
14 #*****************************************************************************
15 #*****************************************************************************
15
16
16 import __builtin__
17 import re
17 import re
18 import types
18 import types
19
19
20 from IPython.utils.dir2 import dir2
20 from IPython.utils.dir2 import dir2
21
21
22 def create_typestr2type_dicts(dont_include_in_type2type2str=["lambda"]):
22 def create_typestr2type_dicts(dont_include_in_type2typestr=["lambda"]):
23 """Return dictionaries mapping lower case typename to type objects, from
23 """Return dictionaries mapping lower case typename (e.g. 'tuple') to type
24 the types package, and vice versa."""
24 objects from the types package, and vice versa."""
25 typenamelist=[]
25 typenamelist = [tname for tname in dir(types) if tname.endswith("Type")]
26 for tname in dir(types):
26 typestr2type, type2typestr = {}, {}
27 if tname[-4:]=="Type":
27
28 typenamelist.append(tname)
29 typestr2type={}
30 type2typestr={}
31 for tname in typenamelist:
28 for tname in typenamelist:
32 name=tname[:-4].lower()
29 name = tname[:-4].lower() # Cut 'Type' off the end of the name
33 obj=getattr(types,tname)
30 obj = getattr(types, tname)
34 typestr2type[name]=getattr(types,tname)
31 typestr2type[name] = obj
35 if name in dont_include_in_type2type2str:
32 if name not in dont_include_in_type2typestr:
36 type2typestr[obj]=name
33 type2typestr[obj] = name
37 return typestr2type,type2typestr
34 return typestr2type, type2typestr
38
35
39 typestr2type,type2typestr=create_typestr2type_dicts()
36 typestr2type, type2typestr = create_typestr2type_dicts()
40
37
41 def is_type(obj,typestr_or_type):
38 def is_type(obj, typestr_or_type):
42 """is_type(obj,typestr_or_type) verifies if obj is of a certain type or
39 """is_type(obj, typestr_or_type) verifies if obj is of a certain type. It
43 group of types takes strings as parameters of the for 'tuple'<->TupleType
40 can take strings or actual python types for the second argument, i.e.
44 'all' matches all types. TODO: Should be extended for choosing more than
41 'tuple'<->TupleType. 'all' matches all types.
45 one type
42
46 """
43 TODO: Should be extended for choosing more than one type."""
47 if typestr_or_type=="all":
44 if typestr_or_type == "all":
48 return True
45 return True
49 if type(typestr_or_type)==types.TypeType:
46 if type(typestr_or_type) == types.TypeType:
50 test_type=typestr_or_type
47 test_type = typestr_or_type
51 else:
48 else:
52 test_type=typestr2type.get(typestr_or_type,False)
49 test_type = typestr2type.get(typestr_or_type, False)
53 if test_type:
50 if test_type:
54 return isinstance(obj,test_type)
51 return isinstance(obj, test_type)
55 else:
52 return False
56 return False
57
53
58 def show_hidden(str,show_all=False):
54 def show_hidden(str, show_all=False):
59 """Return true for strings starting with single _ if show_all is true."""
55 """Return true for strings starting with single _ if show_all is true."""
60 return show_all or str.startswith("__") or not str.startswith("_")
56 return show_all or str.startswith("__") or not str.startswith("_")
61
57
62 class NameSpace(object):
58 def dict_dir(obj):
63 """NameSpace holds the dictionary for a namespace and implements filtering
59 """Produce a dictionary of an object's attributes. Builds on dir2 by
64 on name and types"""
60 checking that a getattr() call actually succeeds."""
65 def __init__(self,obj,name_pattern="*",type_pattern="all",ignore_case=True,
61 ns = {}
66 show_all=True):
62 for key in dir2(obj):
67 self.show_all = show_all #Hide names beginning with single _
63 # This seemingly unnecessary try/except is actually needed
68 self.object = obj
64 # because there is code out there with metaclasses that
69 self.name_pattern = name_pattern
65 # create 'write only' attributes, where a getattr() call
70 self.type_pattern = type_pattern
66 # will fail even if the attribute appears listed in the
71 self.ignore_case = ignore_case
67 # object's dictionary. Properties can actually do the same
72
68 # thing. In particular, Traits use this pattern
73 # We should only match EXACT dicts here, so DON'T use isinstance()
69 try:
74 if type(obj) == types.DictType:
70 ns[key] = getattr(obj, key)
75 self._ns = obj
71 except AttributeError:
76 else:
72 pass
77 kv = []
73 return ns
78 for key in dir2(obj):
79 if isinstance(key, basestring):
80 # This seemingly unnecessary try/except is actually needed
81 # because there is code out there with metaclasses that
82 # create 'write only' attributes, where a getattr() call
83 # will fail even if the attribute appears listed in the
84 # object's dictionary. Properties can actually do the same
85 # thing. In particular, Traits use this pattern
86 try:
87 kv.append((key,getattr(obj,key)))
88 except AttributeError:
89 pass
90 self._ns = dict(kv)
91
92 def get_ns(self):
93 """Return name space dictionary with objects matching type and name patterns."""
94 return self.filter(self.name_pattern,self.type_pattern)
95 ns=property(get_ns)
96
97 def get_ns_names(self):
98 """Return list of object names in namespace that match the patterns."""
99 return self.ns.keys()
100 ns_names=property(get_ns_names,doc="List of objects in name space that "
101 "match the type and name patterns.")
102
74
103 def filter(self,name_pattern,type_pattern):
75 def filter_ns(ns, name_pattern="*", type_pattern="all", ignore_case=True,
104 """Return dictionary of filtered namespace."""
76 show_all=True):
105 def glob_filter(lista,name_pattern,hidehidden,ignore_case):
77 """Filter a namespace dictionary by name pattern and item type."""
106 """Return list of elements in lista that match pattern."""
78 pattern = name_pattern.replace("*",".*").replace("?",".")
107 pattern=name_pattern.replace("*",".*").replace("?",".")
79 if ignore_case:
108 if ignore_case:
80 reg = re.compile(pattern+"$", re.I)
109 reg=re.compile(pattern+"$",re.I)
81 else:
110 else:
82 reg = re.compile(pattern+"$")
111 reg=re.compile(pattern+"$")
83
112 result=[x for x in lista if reg.match(x) and show_hidden(x,hidehidden)]
84 # Check each one matches regex; shouldn't be hidden; of correct type.
113 return result
85 return dict((key,obj) for key, obj in ns.iteritems() if reg.match(key) \
114 ns=self._ns
86 and show_hidden(key, show_all) \
115 #Filter namespace by the name_pattern
87 and is_type(obj, type_pattern) )
116 all=[(x,ns[x]) for x in glob_filter(ns.keys(),name_pattern,
117 self.show_all,self.ignore_case)]
118 #Filter namespace by type_pattern
119 all=[(key,obj) for key,obj in all if is_type(obj,type_pattern)]
120 all=dict(all)
121 return all
122
123 #TODO: Implement dictionary like access to filtered name space?
124
88
125 def list_namespace(namespace,type_pattern,filter,ignore_case=False,show_all=False):
89 def list_namespace(namespace, type_pattern, filter, ignore_case=False, show_all=False):
126 """Return dictionary of all objects in namespace that matches type_pattern
90 """Return dictionary of all objects in a namespace dictionary that match
127 and filter."""
91 type_pattern and filter."""
128 pattern_list=filter.split(".")
92 pattern_list=filter.split(".")
129 if len(pattern_list)==1:
93 if len(pattern_list) == 1:
130 ns=NameSpace(namespace,name_pattern=pattern_list[0],type_pattern=type_pattern,
94 return filter_ns(namespace, name_pattern=pattern_list[0],
131 ignore_case=ignore_case,show_all=show_all)
95 type_pattern=type_pattern,
132 return ns.ns
96 ignore_case=ignore_case, show_all=show_all)
133 else:
97 else:
134 # This is where we can change if all objects should be searched or
98 # This is where we can change if all objects should be searched or
135 # only modules. Just change the type_pattern to module to search only
99 # only modules. Just change the type_pattern to module to search only
136 # modules
100 # modules
137 ns=NameSpace(namespace,name_pattern=pattern_list[0],type_pattern="all",
101 filtered = filter_ns(namespace, name_pattern=pattern_list[0],
138 ignore_case=ignore_case,show_all=show_all)
102 type_pattern="all",
139 res={}
103 ignore_case=ignore_case, show_all=show_all)
140 nsdict=ns.ns
104 results = {}
141 for name,obj in nsdict.iteritems():
105 for name, obj in filtered.iteritems():
142 ns=list_namespace(obj,type_pattern,".".join(pattern_list[1:]),
106 ns = list_namespace(dict_dir(obj), type_pattern,
143 ignore_case=ignore_case,show_all=show_all)
107 ".".join(pattern_list[1:]),
144 for inner_name,inner_obj in ns.iteritems():
108 ignore_case=ignore_case, show_all=show_all)
145 res["%s.%s"%(name,inner_name)]=inner_obj
109 for inner_name, inner_obj in ns.iteritems():
146 return res
110 results["%s.%s"%(name,inner_name)] = inner_obj
111 return results
General Comments 0
You need to be logged in to leave comments. Login now