~ipython-dev/ipython/0.10.1

« back to all changes in this revision

Viewing changes to IPython/wildcard.py

  • Committer: Fernando Perez
  • Date: 2008-06-02 01:26:30 UTC
  • mfrom: (0.1.130 ipython-local)
  • Revision ID: fernando.perez@berkeley.edu-20080602012630-m14vezrhydzvahf8
Merge in all development done in bzr since February 16 2008.

At that time, a clean bzr branch was started from the SVN tree, but
without SVN history.  That SVN history has now been used as the basis
of this branch, and the development done on the history-less BZR
branch has been added and is the content of this merge.  

This branch will be the new official main line of development in
Launchpad (equivalent to the old SVN trunk).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""Support for wildcard pattern matching in object inspection.
 
3
 
 
4
$Id: OInspect.py 608 2005-07-06 17:52:32Z fperez $
 
5
"""
 
6
 
 
7
#*****************************************************************************
 
8
#       Copyright (C) 2005 Jörgen Stenarson <jorgen.stenarson@bostream.nu>
 
9
#
 
10
#  Distributed under the terms of the BSD License.  The full license is in
 
11
#  the file COPYING, distributed as part of this software.
 
12
#*****************************************************************************
 
13
 
 
14
from IPython import Release
 
15
__author__  = "Jörgen Stenarson <jorgen.stenarson@bostream.nu>"
 
16
__license__ = Release.license
 
17
 
 
18
import __builtin__
 
19
import exceptions
 
20
import pdb
 
21
import pprint
 
22
import re
 
23
import types
 
24
 
 
25
from IPython.genutils import dir2
 
26
 
 
27
def create_typestr2type_dicts(dont_include_in_type2type2str=["lambda"]):
 
28
    """Return dictionaries mapping lower case typename to type objects, from
 
29
    the types package, and vice versa."""
 
30
    typenamelist=[]
 
31
    for tname in dir(types):
 
32
        if tname[-4:]=="Type":
 
33
            typenamelist.append(tname)
 
34
    typestr2type={}
 
35
    type2typestr={}
 
36
    for tname in typenamelist:
 
37
        name=tname[:-4].lower()
 
38
        obj=getattr(types,tname)
 
39
        typestr2type[name]=getattr(types,tname)
 
40
        if name in dont_include_in_type2type2str:
 
41
            type2typestr[obj]=name
 
42
    return typestr2type,type2typestr
 
43
 
 
44
typestr2type,type2typestr=create_typestr2type_dicts()
 
45
 
 
46
def is_type(obj,typestr_or_type):
 
47
    """is_type(obj,typestr_or_type) verifies if obj is of a certain type or
 
48
    group of types takes strings as parameters of the for 'tuple'<->TupleType
 
49
    'all' matches all types.  TODO: Should be extended for choosing more than
 
50
    one type
 
51
    """
 
52
    if typestr_or_type=="all":
 
53
        return True
 
54
    if type(typestr_or_type)==types.TypeType:
 
55
        test_type=typestr_or_type
 
56
    else:
 
57
        test_type=typestr2type.get(typestr_or_type,False)
 
58
    if test_type:
 
59
        return isinstance(obj,test_type)
 
60
    else:
 
61
        return False
 
62
 
 
63
def show_hidden(str,show_all=False):
 
64
    """Return true for strings starting with single _ if show_all is true."""
 
65
    return show_all or str.startswith("__") or not str.startswith("_")
 
66
 
 
67
class NameSpace(object):
 
68
    """NameSpace holds the dictionary for a namespace and implements filtering
 
69
    on name and types"""
 
70
    def __init__(self,obj,name_pattern="*",type_pattern="all",ignore_case=True,
 
71
                 show_all=True):
 
72
       self.show_all = show_all #Hide names beginning with single _
 
73
       self.object = obj
 
74
       self.name_pattern = name_pattern
 
75
       self.type_pattern = type_pattern
 
76
       self.ignore_case = ignore_case
 
77
       
 
78
       # We should only match EXACT dicts here, so DON'T use isinstance()
 
79
       if type(obj) == types.DictType:
 
80
           self._ns = obj
 
81
       else:
 
82
           kv = []
 
83
           for key in dir2(obj):
 
84
               if isinstance(key, basestring):
 
85
                   # This seemingly unnecessary try/except is actually needed
 
86
                   # because there is code out there with metaclasses that
 
87
                   # create 'write only' attributes, where a getattr() call
 
88
                   # will fail even if the attribute appears listed in the
 
89
                   # object's dictionary.  Properties can actually do the same
 
90
                   # thing.  In particular, Traits use this pattern
 
91
                   try:
 
92
                       kv.append((key,getattr(obj,key)))
 
93
                   except AttributeError:
 
94
                       pass
 
95
           self._ns = dict(kv)
 
96
               
 
97
    def get_ns(self):
 
98
        """Return name space dictionary with objects matching type and name patterns."""
 
99
        return self.filter(self.name_pattern,self.type_pattern)
 
100
    ns=property(get_ns)
 
101
 
 
102
    def get_ns_names(self):
 
103
        """Return list of object names in namespace that match the patterns."""
 
104
        return self.ns.keys()
 
105
    ns_names=property(get_ns_names,doc="List of objects in name space that "
 
106
                      "match the type and name patterns.")
 
107
        
 
108
    def filter(self,name_pattern,type_pattern):
 
109
        """Return dictionary of filtered namespace."""
 
110
        def glob_filter(lista,name_pattern,hidehidden,ignore_case):
 
111
            """Return list of elements in lista that match pattern."""
 
112
            pattern=name_pattern.replace("*",".*").replace("?",".")
 
113
            if ignore_case:
 
114
                reg=re.compile(pattern+"$",re.I)
 
115
            else:
 
116
                reg=re.compile(pattern+"$")
 
117
            result=[x for x in lista if reg.match(x) and show_hidden(x,hidehidden)]
 
118
            return result
 
119
        ns=self._ns
 
120
        #Filter namespace by the name_pattern
 
121
        all=[(x,ns[x]) for x in glob_filter(ns.keys(),name_pattern,
 
122
                                            self.show_all,self.ignore_case)]
 
123
        #Filter namespace by type_pattern
 
124
        all=[(key,obj) for key,obj in all if is_type(obj,type_pattern)]
 
125
        all=dict(all)
 
126
        return all
 
127
 
 
128
    #TODO: Implement dictionary like access to filtered name space?
 
129
 
 
130
def list_namespace(namespace,type_pattern,filter,ignore_case=False,show_all=False):
 
131
    """Return dictionary of all objects in namespace that matches type_pattern
 
132
    and filter."""
 
133
    pattern_list=filter.split(".")
 
134
    if len(pattern_list)==1:
 
135
        ns=NameSpace(namespace,name_pattern=pattern_list[0],type_pattern=type_pattern,
 
136
                     ignore_case=ignore_case,show_all=show_all)
 
137
        return ns.ns
 
138
    else:
 
139
        # This is where we can change if all objects should be searched or
 
140
        # only modules. Just change the type_pattern to module to search only
 
141
        # modules
 
142
        ns=NameSpace(namespace,name_pattern=pattern_list[0],type_pattern="all",
 
143
                     ignore_case=ignore_case,show_all=show_all)
 
144
        res={}
 
145
        nsdict=ns.ns
 
146
        for name,obj in nsdict.iteritems():
 
147
            ns=list_namespace(obj,type_pattern,".".join(pattern_list[1:]),
 
148
                              ignore_case=ignore_case,show_all=show_all)
 
149
            for inner_name,inner_obj in ns.iteritems():
 
150
                res["%s.%s"%(name,inner_name)]=inner_obj
 
151
        return res