##// 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,37 +14,33 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:
@@ -52,31 +49,17 b' def is_type(obj,typestr_or_type):'
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:
56 return False
52 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):
67 self.show_all = show_all #Hide names beginning with single _
68 self.object = obj
69 self.name_pattern = name_pattern
70 self.type_pattern = type_pattern
71 self.ignore_case = ignore_case
72
73 # We should only match EXACT dicts here, so DON'T use isinstance()
74 if type(obj) == types.DictType:
75 self._ns = obj
76 else:
77 kv = []
78 for key in dir2(obj):
62 for key in dir2(obj):
79 if isinstance(key, basestring):
80 # This seemingly unnecessary try/except is actually needed
63 # This seemingly unnecessary try/except is actually needed
81 # because there is code out there with metaclasses that
64 # because there is code out there with metaclasses that
82 # create 'write only' attributes, where a getattr() call
65 # create 'write only' attributes, where a getattr() call
@@ -84,63 +67,45 b' class NameSpace(object):'
84 # object's dictionary. Properties can actually do the same
67 # object's dictionary. Properties can actually do the same
85 # thing. In particular, Traits use this pattern
68 # thing. In particular, Traits use this pattern
86 try:
69 try:
87 kv.append((key,getattr(obj,key)))
70 ns[key] = getattr(obj, key)
88 except AttributeError:
71 except AttributeError:
89 pass
72 pass
90 self._ns = dict(kv)
73 return ns
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
74
97 def get_ns_names(self):
75 def filter_ns(ns, name_pattern="*", type_pattern="all", ignore_case=True,
98 """Return list of object names in namespace that match the patterns."""
76 show_all=True):
99 return self.ns.keys()
77 """Filter a namespace dictionary by name pattern and item type."""
100 ns_names=property(get_ns_names,doc="List of objects in name space that "
101 "match the type and name patterns.")
102
103 def filter(self,name_pattern,type_pattern):
104 """Return dictionary of filtered namespace."""
105 def glob_filter(lista,name_pattern,hidehidden,ignore_case):
106 """Return list of elements in lista that match pattern."""
107 pattern=name_pattern.replace("*",".*").replace("?",".")
78 pattern = name_pattern.replace("*",".*").replace("?",".")
108 if ignore_case:
79 if ignore_case:
109 reg=re.compile(pattern+"$",re.I)
80 reg = re.compile(pattern+"$", re.I)
110 else:
81 else:
111 reg=re.compile(pattern+"$")
82 reg = re.compile(pattern+"$")
112 result=[x for x in lista if reg.match(x) and show_hidden(x,hidehidden)]
113 return result
114 ns=self._ns
115 #Filter namespace by the name_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
83
123 #TODO: Implement dictionary like access to filtered name space?
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) )
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],
95 type_pattern=type_pattern,
131 ignore_case=ignore_case,show_all=show_all)
96 ignore_case=ignore_case, show_all=show_all)
132 return ns.ns
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],
102 type_pattern="all",
138 ignore_case=ignore_case,show_all=show_all)
103 ignore_case=ignore_case, show_all=show_all)
139 res={}
104 results = {}
140 nsdict=ns.ns
105 for name, obj in filtered.iteritems():
141 for name,obj in nsdict.iteritems():
106 ns = list_namespace(dict_dir(obj), type_pattern,
142 ns=list_namespace(obj,type_pattern,".".join(pattern_list[1:]),
107 ".".join(pattern_list[1:]),
143 ignore_case=ignore_case,show_all=show_all)
108 ignore_case=ignore_case, show_all=show_all)
144 for inner_name,inner_obj in ns.iteritems():
109 for inner_name, inner_obj in ns.iteritems():
145 res["%s.%s"%(name,inner_name)]=inner_obj
110 results["%s.%s"%(name,inner_name)] = inner_obj
146 return res
111 return results
General Comments 0
You need to be logged in to leave comments. Login now