1- from pyvba .viewer import Viewer , FunctionViewer , IterableFunctionViewer
1+ from pyvba .viewer import Viewer , FunctionViewer , CollectionViewer
22
3+ # used to skip predetermined objects by exact name
4+ # fixme: remove extra parameters
5+ skip = ['Application' , 'Parent' , 'Units' , 'Parameters' ]
36
7+
8+ # TODO: fix infinite recursion issue
49class Browser (Viewer ):
5- def __init__ (self , app , ** kwargs ):
10+ def __init__ (self , app , name : str , parent : Viewer = None ):
611 """Create a browser from an application string or win32com object.
712
813 The Browser object used to iterate through and explore COM objects from external
@@ -13,27 +18,44 @@ def __init__(self, app, **kwargs):
1318 app
1419 The application string (e.g. "Excel.Application") or win32com object.
1520 """
16- super ().__init__ (app , ** kwargs )
17-
18- # define filters
19- self ._skip = kwargs .get ('skip' , ["Application" , "Parent" ]) # user-defined skips
20- self ._checked = kwargs .get ('checked' , {}) # checked items
21- self ._max_checks = kwargs .get ('max_checks' , 1 ) # maximum allowable instances of an object
22-
21+ super ().__init__ (app , name , parent )
2322 self ._all = {}
2423
2524 def __str__ (self ):
26- return super ().__str__ ().replace (" Viewer" , " Browser" )
25+ return super ().__str__ ().replace (' Viewer' , ' Browser' )
2726
2827 def __getattr__ (self , item ):
2928 if self ._all == {}:
3029 self ._generate ()
3130
32- try :
33- obj = self ._all [item ]
34- except AttributeError :
35- obj = getattr (self ._com , item )
36- return obj
31+ obj = super ().getattr (item )
32+ return obj if isinstance (obj , FunctionViewer ) or not isinstance (obj , Viewer ) else self .from_viewer (obj )
33+
34+ @staticmethod
35+ def from_viewer (viewer , parent = None ):
36+ """Turn a Viewer object into a Browser object."""
37+ return CollectionBrowser (viewer ) if isinstance (viewer , CollectionViewer ) \
38+ else Browser (viewer .com , viewer .name , viewer .parent if parent is None else parent )
39+
40+ @staticmethod
41+ def skip (item : str ):
42+ """Adds a keyword to the skip list."""
43+ global skip
44+ if item not in skip :
45+ skip .append (item )
46+
47+ @staticmethod
48+ def rm_skip (item : str ):
49+ """Remove a keyword from the skip list."""
50+ global skip
51+ if item in skip :
52+ skip .remove (item )
53+
54+ @staticmethod
55+ def clr_skip ():
56+ """Resets the skip list to its original state."""
57+ global skip
58+ skip = ['Application' , 'Parent' ]
3759
3860 @property
3961 def all (self ) -> dict :
@@ -43,87 +65,25 @@ def all(self) -> dict:
4365 return self ._all
4466
4567 def _generate (self ):
46- """Iterates through all instances of COM objects when called upon.
47-
48- See Also
49- --------
50- Viewer.__getattr___
51- """
68+ """Iterates through all objects when called upon."""
69+ global skip
5270
53- for attr in self :
54- # skip if checked or user opts to skip it
55- if attr in self ._skip or self ._checked .get (attr , self ._max_checks ) <= 0 :
71+ for name in self ._objects + [i .name for i in self ._methods ]:
72+ if name in skip :
5673 continue
5774
58- # attempt to collect and observe the attribute
5975 try :
60- obj = getattr (self ._com , attr )
61-
62- # sort by type
63- if '<bound method' in repr (obj ):
64- # check for Item array
65- if "Item" == attr :
66- # create the IterableFunctionBrowser
67- # TODO infinite item issue
68- try :
69- count = getattr (self ._com , 'Count' )
70- self ._all [attr ] = IterableFunctionBrowser (
71- obj , attr , count ,
72- parent_name = self ._name ,
73- parent = self ,
74- skip = self ._skip ,
75- checked = self ._checked ,
76- max_checks = self ._max_checks
77- )
78- except Exception :
79- self ._all [attr ] = FunctionViewer (obj , attr )
80- else :
81- self ._all [attr ] = FunctionViewer (obj , attr )
82- elif 'win32com' in repr (obj ) or 'COMObject' in repr (obj ):
83- self ._checked [attr ] = self ._checked .get (attr , self ._max_checks ) - 1
84- self ._all [attr ] = Browser (
85- obj ,
86- parent = self ,
87- name = attr ,
88- skip = self ._skip ,
89- checked = self ._checked ,
90- max_checks = self ._max_checks
91- )
76+ obj = super ().getattr (name )
77+
78+ if isinstance (obj , Viewer ):
79+ self ._all [name ] = self .from_viewer (obj , self )
9280 else :
93- self ._all [attr ] = obj
81+ self ._all [name ] = obj
9482 except BaseException as e :
95- self ._errors [attr ] = e .args
96- self ._all [attr ] = e
83+ self ._errors [name ] = e .args
9784 continue
9885
99- def print_browser (self , ** kwargs ):
100- """Prints out `all` in a readable way."""
101- item = kwargs .get ('item' , self )
102- tabs = kwargs .get ('tabs' , 0 )
103- name = ''
104-
105- # attach a name if not self describing
106- if 'class' not in str (item ):
107- name = kwargs .get ('name' ) + ': '
108-
109- print (" " * tabs + name + str (item ))
110-
111- # iterate through the corresponding browser
112- if isinstance (item , (Browser , IterableFunctionBrowser )):
113- for i in list (item .all .keys ()):
114- self .print_browser (item = item .all [i ], name = i , tabs = (tabs + 1 ))
115-
116- def skip (self , item : str ):
117- """Adds a keyword to the skip list."""
118- if item not in self ._skip :
119- self ._skip .append (item )
120-
121- def rm_skip (self , item : str ):
122- """Remove a keyword from the skip list."""
123- if item in self ._skip :
124- self ._skip .remove (item )
125-
126- def search (self , name : str , exact : bool = False , ** kwargs ):
86+ def search (self , name : str , exact : bool = False ):
12787 """Return a dictionary in format {path: item} matching the name.
12888
12989 Search for all instances of a method or object containing a name.
@@ -140,28 +100,7 @@ def search(self, name: str, exact: bool = False, **kwargs):
140100 dict
141101 The results of the search in format {path: item}.
142102 """
143-
144- item = kwargs .get ('item' , self )
145- paths = []
146- path = kwargs .get ('path' , self ._name )
147-
148- # add to list if found
149- if type (item ) == FunctionViewer and name in item .name :
150- if not exact or (exact and name == item .name ):
151- paths .append (path + '/' + item .name )
152-
153- # search
154- if isinstance (item , (Browser , IterableFunctionBrowser )):
155- for i in item .all :
156- if name in i :
157- if not exact or (exact and i == name ):
158- paths .append (path + '/' + i )
159-
160- value = item .all [i ]
161- if isinstance (value , (Browser , IterableFunctionBrowser )):
162- paths += self .search (name , exact , item = value , path = (path + '/' + i ))
163-
164- return paths
103+ ...
165104
166105 def goto (self , path : str ):
167106 """Retrieve an object at a given location.
@@ -176,56 +115,22 @@ def goto(self, path: str):
176115 `goto('Bodies/Item/1/HybridShapes/GetItem')` yields the 'GetItem' function.
177116
178117 """
179- item = self
180- path = path .split ('/' )
181-
182- for loc in path [1 :]:
183- if isinstance (item , IterableFunctionBrowser ):
184- item = item (int (loc ))
185- else :
186- item = getattr (item , loc )
187- return item
188-
189- def reset (self ):
190- """Clear the `all` property and the checked list."""
191- self ._checked = {}
192- self ._all = {}
193-
194- def reset_all (self ):
195- """Clear the `all` property and all empties the skip list."""
196- self ._skip = []
197- self .reset ()
118+ ...
198119
199120 def regen (self ):
200121 """Regenerate the `all` property."""
201- self .reset ()
122+ self ._all = {}
202123 self ._generate ()
203124
204125
205- class IterableFunctionBrowser (IterableFunctionViewer ):
206- def __init__ (self , func , name , count , ** kwargs ):
207- """Create a browser for an iterable function to view its components."""
208- super ().__init__ (func , name , count , ** kwargs )
209-
210- self ._all = {
211- str (i ): Browser (func (i ), name = (kwargs .get ('parent_name' )), ** kwargs )
212- for i in range (1 , count + 1 )
213- }
126+ class CollectionBrowser (Browser , CollectionViewer ):
127+ def __init__ (self , obj : CollectionViewer ):
128+ super ().__init__ (obj .com , obj .name , obj .parent )
129+ self ._items = [self .from_viewer (i ) for i in self ._items ]
214130
215131 def __str__ (self ):
216- return super (). __str__ (). replace ( 'FunctionViewer' , "FunctionBrowser" )
132+ return "<class 'CollectionBrowser'>: " + self . _name
217133
218- def __getattr__ (self , item ):
219- if self ._all == {}:
220- self ._generate ()
221-
222- try :
223- obj = self ._all [item ]
224- except AttributeError :
225- obj = getattr (self ._com , item )
226- return obj
227-
228- @property
229- def all (self ):
230- """Return a dict of objects in the form `{name: item}`."""
231- return self ._all
134+ def _generate (self ):
135+ super ()._generate ()
136+ self ._all ['Item' ] = self ._items
0 commit comments