PyForTool
Python-fortran-tool
Loading...
Searching...
No Matches
scope.py
1#!/usr/bin/env python3
2
3"""
4Scope-level operations for FORTRAN code.
5
6Provides PYFTscope class for navigating and manipulating FORTRAN scopes
7(modules, subroutines, functions, types) with integrated support for
8variables, statements, cosmetics, applications, C++ directives, and OpenACC.
9
10Key Features
11------------
12- Scope path navigation (e.g., 'module:MOD/sub:SUB')
13- XML tree traversal with CONTAINS section filtering
14- Parent/sibling element lookup with caching
15- Integration of Variables, Statements, Cosmetics, Applications, Cpp, Openacc
16
17Classes
18-------
19PYFTscope : Core scope wrapper extending ElementView
20ElementView : XML tree view with optional CONTAINS exclusion
21
22Examples
23--------
24>>> pft = PYFT('input.F90')
25>>> scopes = pft.getScopes() # Get all scopes
26>>> sub = pft.getScopeNode('module:MOD/sub:SUB') # Get specific scope
27>>> for scope in pft.getScopes(excludeKinds=['type']):
28... print(scope.path)
29"""
30
31import copy
32import os
33
34from pyfortool.variables import Variables, updateVarList
35from pyfortool.cosmetics import Cosmetics
36from pyfortool.applications import Applications
37from pyfortool.statements import Statements
38from pyfortool.cpp import Cpp
39from pyfortool.openacc import Openacc
40from pyfortool.util import PYFTError, debugDecor, n2name, tag
41from pyfortool.tree import Tree, updateTree
42from pyfortool.expressions import createElem, createExpr
43
44
46 """
47 View of an ElementTree exposing a subset of subelements.
48
49 Provides filtering capabilities for XML trees, particularly for
50 excluding CONTAINS sections from scope traversal.
51 """
52
53 def __init__(self, xml, excludeContains=False):
54 """
55 Initialize ElementView.
56
57 Parameters
58 ----------
59 xml : xml element
60 Root XML element for this view.
61 excludeContains : bool, optional
62 If True, ignore elements after CONTAINS statement.
63 """
64 super().__init__()
65 self._excludeContains = excludeContains
66 self._xml = xml
67
68 @property
69 def _virtual(self):
70 """
71 :param xml: xml corresponding to a scope
72 :return: a node (possibly the xml node) containing only the relevant subelements
73 """
74 if self._excludeContains:
75 contains = self._xml.find('./{*}contains-stmt')
76 if contains is None:
77 return self._xml
78 indexContains = list(self._xml).index(contains)
79 childNode = createElem('virtual')
80 childNode.extend(self._xml[:indexContains] + [self._xml[-1]])
81 return childNode
82 return self._xml
83
84 # PROPERTIES
85
86 @property
87 def tag(self):
88 """
89 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.tag
90 """
91 return self._xml.tag
92
93 @property
94 def tail(self):
95 """
96 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.tail
97 """
98 return self._xml.tail
99
100 @property
101 def text(self):
102 """
103 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.text
104 """
105 return self._xml.text
106
107 # READ-ONLY METHODS, they can always use the virtual approach
108
109 def findtext(self, *args, **kwargs):
110 """
111 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.findtext
112 """
113 return self._virtual_virtual.findtext(*args, **kwargs)
114
115 def iterfind(self, *args, **kwargs):
116 """
117 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.iterfind
118 """
119 return self._virtual_virtual.iterfind(*args, **kwargs)
120
121 def itertext(self, *args, **kwargs):
122 """
123 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.itertext
124 """
125 return self._virtual_virtual.itertext(*args, **kwargs)
126
127 def __getitem__(self, *args, **kwargs):
128 return self._virtual_virtual.__getitem__(*args, **kwargs)
129
130 def __len__(self, *args, **kwargs):
131 return self._virtual_virtual.__len__(*args, **kwargs)
132
133 def __iter__(self):
134 return list(self._virtual_virtual).__iter__()
135
136 def find(self, *args, **kwargs):
137 """
138 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.find
139 """
140 return self._virtual_virtual.find(*args, **kwargs)
141
142 def findall(self, *args, **kwargs):
143 """
144 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.findall
145 """
146 return self._virtual_virtual.findall(*args, **kwargs)
147
148 def iter(self, *args, **kwargs):
149 """
150 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.iter
151 """
152 return self._virtual_virtual.iter(*args, **kwargs)
153
154 def items(self, *args, **kwargs):
155 """
156 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.items
157 """
158 return self._virtual_virtual.items(*args, **kwargs)
159
160 # WRITE METHODS
161
162 @updateVarList
163 def clear(self):
164 """
165 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.clear
166 """
167 for item in self:
168 self.remove(item)
169 self.texttext = None
170 self.tailtail = None
171
172 def append(self, *args, **kwargs):
173 """
174 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.append
175 """
176 # Append after the 'END SUBROUTINE' statement
177 return self._xml.append(*args, **kwargs)
178
179 def extend(self, *args, **kwargs):
180 """
181 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.extend
182 """
183 # Extend after the 'END SUBROUTINE' statement
184 return self._xml.extend(*args, **kwargs)
185
186 def _getIndex(self, index):
187 """
188 :param index: index in the virtual node
189 :return: index in the _xml node
190 """
191 if not self._excludeContains:
192 return index
193 contains = self._xml.find('./{*}contains-stmt')
194 if contains is None:
195 return index
196 indexContains = list(self._xml).index(contains)
197 # Checks
198 if index > indexContains or index < -indexContains - 1:
199 raise IndexError('list index out of range')
200 # Converts negative index into positive index
201 if index == -1:
202 # END SUBROUTINE
203 return index
204 if index < -1:
205 index = indexContains + index + 1
206
207 return len(self._xml) if index == indexContains else index
208
209 def __setitem__(self, index, item):
210 return self._xml.__setitem__(self._getIndex(index), item)
211
212 @updateVarList
213 def __delitem__(self, index):
214 return self._xml.__delitem__(self._getIndex(index))
215
216 def insert(self, index, item):
217 """
218 https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.insert
219 """
220 return self._xml.insert(0 if index == 0 else (self._getIndex(index - 1) + 1), item)
221
222 @updateVarList
223 def remove(self, node):
224 """
225 Remove node from the xml
226 """
227 if isinstance(node, ElementView):
228 node = node._xml # pylint: disable=protected-access
229 self.getParent(node).remove(node)
230
231
233 """
234 Wrap an XML node representing a FORTRAN scope.
235
236 PYFTscope provides methods to navigate, query, and modify FORTRAN
237 source code at the scope level (modules, subroutines, functions, types).
238
239 Scope Path Format
240 -----------------
241 Scope paths are '/' separated strings identifying the location in the
242 source tree. Examples:
243 - 'module:MODULE' - a module
244 - 'module:MOD/sub:SUB' - subroutine SUB in module MODULE
245 - 'module:MOD/type:TYPE' - type TYPE in module MODULE
246 - 'module:MOD/sub:SUB/func:FUNC' - function FUNC in subroutine SUB
247
248 Examples
249 --------
250 >>> pft = PYFT('myfile.F90')
251 >>> scopes = pft.getScopes() # Get all scopes
252 >>> sub = pft.getScopeNode('module:MOD/sub:SUB') # Get specific scope
253 >>> for scope in pft.getScopes(excludeKinds=['type']):
254 ... print(scope.path)
255 """
256 SCOPE_STMT = {'module': 'module-stmt',
257 'func': 'function-stmt',
258 'sub': 'subroutine-stmt',
259 'type': 'T-stmt',
260 'prog': 'program-stmt',
261 'interface': 'interface-stmt',
262 'submodule': 'submodule-stmt'}
263 SCOPE_CONSTRUCT = {'module': 'program-unit',
264 'func': 'program-unit',
265 'sub': 'program-unit',
266 'type': 'T-construct',
267 'prog': 'program-unit',
268 'interface': 'interface-construct',
269 'submodule': 'program-unit'}
270
271 def __init__(self, xml, scopePath='/', parentScope=None,
272 enableCache=False, tree=None, excludeContains=False):
273 """
274 Initialize a PYFTscope instance.
275
276 Parameters
277 ----------
278 xml : xml element
279 XML element representing the scope.
280 scopePath : str, optional
281 Path string identifying this scope (e.g., 'module:MOD/sub:SUB').
282 parentScope : PYFTscope, optional
283 Parent scope instance.
284 enableCache : bool, optional
285 If True, cache parent nodes for faster traversal.
286 tree : Tree, optional
287 Tree instance for cross-file analysis.
288 excludeContains : bool, optional
289 If True, ignore CONTAINS sections in scope traversal.
290 """
291 super().__init__(xml=xml, excludeContains=excludeContains)
292 self._mainScope = self if parentScope is None else parentScope._mainScope
293 self._path = scopePath
294 self._parentScope = parentScope
295 self.tree = Tree() if tree is None else tree
296 self._cacheParent = {}
297
298 if enableCache and parentScope is None:
299 # parent cache associated to the main scope
300 for node in self.iter():
301 for subNode in node:
302 self._cacheParent[id(subNode)] = node
303
304 def __copy__(self):
305 cls = self.__class__
306 result = cls.__new__(cls)
307 result.__dict__.update(self.__dict__)
308 return result
309
310 def __deepcopy__(self, memo):
311 cls = self.__class__
312 result = cls.__new__(cls)
313 memo[id(self)] = result
314 for key, val in self.__dict__.items():
315 setattr(result, key, copy.deepcopy(val, memo))
316 return result
317
318 def __getattr__(self, attr):
319 """
320 Get some attributes defined in the PYFT class
321 """
322 if attr in ('SHARED_TREE', 'NO_PARALLEL_LOCK', 'PARALLEL_FILE_LOCKS '):
323 return getattr(self._parentScope, attr)
324 raise AttributeError(f"{attr} doesn't exist")
325
326 @property
327 def path(self):
328 """
329 Get the scope path.
330
331 Returns
332 -------
333 str
334 Scope path string (e.g., 'module:MOD/sub:SUB').
335 """
336 return self._path
337
338 @property
339 def mainScope(self):
340 """
341 Get the main (root) scope.
342
343 Returns
344 -------
345 PYFTscope
346 The top-level scope in the file.
347 """
348 return self._mainScope
349
350 @property
351 def parentScope(self):
352 """
353 Get the parent scope.
354
355 Returns
356 -------
357 PYFTscope or None
358 Parent scope, or None if this is the root scope.
359 """
360 return self._parentScope
361
362 # No @debugDecor for this low-level method
363 def getParent(self, item, level=1):
364 """
365 Get the parent element of an XML node.
366
367 Parameters
368 ----------
369 item : xml element
370 Element whose parent to find.
371 level : int, optional
372 Number of levels to traverse (1 = direct parent, 2 = grandparent, etc.).
373
374 Returns
375 -------
376 xml element or None
377 Parent element at the specified level.
378 """
379 # pylint: disable=protected-access
380 def check(node):
381 # We check if the registered parent is still the right one
382 # node must be in its parent, and the parent chain must go to the root node
383 return node in self.mainScope._cacheParent.get(id(node), []) and \
384 (self.mainScope._cacheParent[id(node)] == self.mainScope._xml or
385 check(self.mainScope._cacheParent[id(node)]))
386
387 assert level >= 1
388 parent = None
389 if check(item):
390 parent = self.mainScope._cacheParent[id(item)]
391 else:
392 for node in self.mainScope.iter():
393 if item in list(node):
394 parent = node
395 if self.mainScope._cacheParent:
396 # _cacheParent not empty means that we want to use the caching system
397 self.mainScope._cacheParent[id(item)] = node
398 break
399 return parent if level == 1 else self.getParent(parent, level - 1)
400
401 def getSiblings(self, item, before=True, after=True):
402 """
403 Get sibling elements.
404
405 Parameters
406 ----------
407 item : xml element
408 Element whose siblings to find.
409 before : bool, optional
410 If True, include siblings before the item. Default is True.
411 after : bool, optional
412 If True, include siblings after the item. Default is True.
413
414 Returns
415 -------
416 list
417 List of sibling elements.
418
419 Examples
420 --------
421 >>> siblings = scope.getSiblings(node) # All siblings
422 >>> before = scope.getSiblings(node, after=False) # Only before
423 """
424
425 siblings = self.getParent(item).findall('./{*}*')
426 if not after:
427 siblings = siblings[:siblings.index(item)]
428 if not before:
429 siblings = siblings[siblings.index(item) + 1:]
430 return [s for s in siblings if s != item]
431
432 # No @debugDecor for this low-level method
433 @staticmethod
434 def _getNodeName(node):
435 """
436 Internal methode to compute the name of a scope
437 :param node: program-unit node
438 :return: name
439 """
440 if tag(node) == 'T-stmt':
441 # To not capture the extension name in "TYPE, EXTENDS(FOO) :: FOO2"
442 nodeN = node.find('./{*}T-N/{*}N')
443 elif tag(node) == 'submodule-stmt':
444 nodeN = node.find('./{*}submodule-module-N')
445 else:
446 nodeN = node.find('.//{*}N')
447 if nodeN is not None and nodeN.find('.//{*}N') is not None:
448 # As of 7 Jul 2023, this is the case for interface statements
449 nodeN = nodeN.find('.//{*}N')
450 if nodeN is not None:
451 name = n2name(nodeN).upper()
452 else:
453 name = '--UNKNOWN--'
454 return name
455
456 # No @debugDecor for this low-level method
457 def _getNodePath(self, node):
458 """
459 Internal methode to compute a path part from a node
460 :param node: program-unit node
461 :return: path part (e.g. module:MODU)
462 """
463 stmt = tag(node[0])
464 name = self._getNodeName(node[0])
465 return {v: k for (k, v) in self.SCOPE_STMT.items()}[stmt] + ':' + name
466
467 # No @debugDecor for this low-level method
468 @staticmethod
469 def normalizeScope(scopePath):
470 """
471 Normalize a scope path to standard format.
472
473 Converts scope path to lowercase prefix and uppercase names.
474
475 Parameters
476 ----------
477 scopePath : str
478 Scope path to normalize.
479
480 Returns
481 -------
482 str
483 Normalized scope path.
484
485 Examples
486 --------
487 >>> PYFTscope.normalizeScope('module:Test/sub:Sub')
488 'module:TEST/sub:SUB'
489 """
490 return '/'.join([(k.lower() + ':' + w.upper())
491 for (k, w) in [component.split(':')
492 for component in scopePath.split('/')]])
493
494 @debugDecor
495 def showScopesList(self, includeItself=False):
496 """
497 Display all scopes found in the source code.
498
499 Parameters
500 ----------
501 includeItself : bool, optional
502 If True, include the current scope in the output.
503 Default is False.
504
505 Examples
506 --------
507 >>> pft = PYFT('myfile.F90')
508 >>> pft.showScopesList()
509 These scopes have been found in the source code:
510 - /module:MOD
511 - /module:MOD/sub:SUB
512 - /module:MOD/func:FUNC
513 """
514 print("These scopes have been found in the source code:")
515 print("\n".join([' - ' + scope.path
516 for scope in self.getScopes(includeItself=includeItself)]))
517
518 @debugDecor
519 def getScopes(self, level=-1, excludeContains=True, excludeKinds=None, includeItself=True):
520 """
521 Get child scopes from the current scope.
522
523 Parameters
524 ----------
525 level : int, optional
526 Depth of scope traversal:
527 - -1 (default): All child scopes recursively.
528 - 1: Direct children only.
529 - 2: Children and grandchildren, etc.
530 excludeContains : bool, optional
531 If True (default), exclude scopes from CONTAINS sections
532 (nested subroutines/functions).
533 excludeKinds : list of str, optional
534 Scope kinds to exclude. Options: 'module', 'sub', 'func',
535 'type', 'prog', 'interface', 'submodule'.
536 includeItself : bool, optional
537 If True (default), include the current scope in results.
538
539 Returns
540 -------
541 list of PYFTscope
542 List of scope instances matching the criteria.
543
544 Examples
545 --------
546 >>> pft = PYFT('myfile.F90')
547 >>> all_scopes = pft.getScopes() # All scopes
548 >>> subs = pft.getScopes(excludeKinds=['module', 'func', 'type'])
549 >>> direct = pft.getScopes(level=1)
550 """
551 assert level == -1 or level > 0, 'level must be -1 or a positive int'
552
553 def _getRecur(node, level, basePath=''):
554 # If node is the entire xml
555 if tag(node) == 'object':
556 usenode = node.find('./{*}file')
557 else:
558 usenode = node
559 results = []
560 for child in [child for child in usenode
561 if tag(child) in self.SCOPE_CONSTRUCT.values()]:
562 nodePath = self._getNodePath(child)
563 if excludeKinds is None or nodePath.split(':')[0] not in excludeKinds:
564 scopePath = nodePath if basePath in ('', '/') \
565 else basePath + '/' + nodePath
566 results.append(PYFTscope(child,
567 scopePath=scopePath, parentScope=self,
568 enableCache=False, tree=self.tree,
569 excludeContains=excludeContains))
570 if level != 1:
571 results.extend(_getRecur(child, level - 1, scopePath))
572 return results
573
574 if includeItself and tag(self) in self.SCOPE_CONSTRUCT.values():
575 itself = [self]
576 else:
577 itself = []
578
579 return _getRecur(self, level, self.pathpathpath) + itself
580
581 @debugDecor
582 def getScopeNode(self, scopePath, excludeContains=True, includeItself=True):
583 """
584 Get a specific scope by path.
585
586 Parameters
587 ----------
588 scopePath : str
589 Scope path to search for (e.g., 'module:MOD/sub:SUB').
590 excludeContains : bool, optional
591 See getScopes. Default is True.
592 includeItself : bool, optional
593 See getScopes. Default is True.
594
595 Returns
596 -------
597 PYFTscope
598 Scope instance matching the path.
599
600 Raises
601 ------
602 PYFTError
603 If scope not found or found multiple times.
604
605 Examples
606 --------
607 >>> pft = PYFT('myfile.F90')
608 >>> sub = pft.getScopeNode('module:MOD/sub:SUB')
609 >>> func = pft.getScopeNode('/module:MOD/func:FUNC')
610 """
611 scope = [scope for scope in self.getScopes(excludeContains=excludeContains,
612 includeItself=includeItself)
613 if scope.path == scopePath]
614 if len(scope) == 0:
615 raise PYFTError(f'{scopePath} not found')
616 if len(scope) > 1:
617 raise PYFTError(f'{scopePath} found several times')
618 return scope[0]
619
620 @debugDecor
621 def isScopeNode(self, node):
622 """
623 Check if a node is a scope-level construct.
624
625 Parameters
626 ----------
627 node : xml element
628 Node to check.
629
630 Returns
631 -------
632 bool
633 True if node is a scope construct (program-unit, interface-construct,
634 or T-construct).
635
636 Examples
637 --------
638 >>> node = pft.find('.//{*}subroutine-stmt/..')
639 >>> pft.isScopeNode(node)
640 True
641 """
642 return tag(node) in self.SCOPE_CONSTRUCT.values()
643
644 @debugDecor
645 def getParentScopeNode(self, item, mustRaise=True):
646 """
647 Get the scope containing an element.
648
649 Parameters
650 ----------
651 item : xml element
652 Element whose containing scope to find.
653 mustRaise : bool, optional
654 If True (default), raise PYFTError if scope not found.
655
656 Returns
657 -------
658 xml element or None
659 The scope node containing the item.
660
661 Examples
662 --------
663 >>> call = pft.find('.//{*}call-stmt')
664 >>> scope = pft.getParentScopeNode(call)
665 """
666 result = self.getParent(item)
667 while result is not None and not self.isScopeNode(result):
668 result = self.getParent(result)
669 if result is None and mustRaise:
670 raise PYFTError("The scope parent has not been found.")
671 return result
672
673 @debugDecor
674 def getScopePath(self, item, includeItself=True):
675 """
676 Get the scope path for an element.
677
678 Parameters
679 ----------
680 item : xml element
681 Element whose scope path to determine.
682 includeItself : bool, optional
683 If True (default) and item is a scope node, include it.
684
685 Returns
686 -------
687 str
688 Full scope path of the element's containing scope.
689
690 Examples
691 --------
692 >>> node = pft.find('.//{*}a-stmt')
693 >>> pft.getScopePath(node)
694 '/module:MOD/sub:SUB'
695 """
696 if includeItself and self.isScopeNode(item):
697 result = [self._getNodePath(item)]
698 else:
699 result = []
700 item = self.getParentScopeNode(item, mustRaise=False)
701 while item is not None:
702 result = [self._getNodePath(item)] + result
703 item = self.getParentScopeNode(item, mustRaise=False)
704 return '/'.join(result)
705
706 def getFileName(self):
707 """
708 Get the source filename.
709
710 Returns
711 -------
712 str
713 Normalized path to the source file.
714
715 Examples
716 --------
717 >>> pft = PYFT('/path/to/file.F90')
718 >>> pft.getFileName()
719 '/path/to/file.F90'
720 """
721 return os.path.normpath(self.mainScope.find('.//{*}file').attrib['name'])
722
723 @updateTree()
724 @updateVarList
725 def empty(self, addStmt=None, simplify=False):
726 """
727 Remove all statements from scopes.
728
729 Removes all executable statements from scopes while preserving:
730 - Dummy argument declarations
731 - USE statements
732 - Scope declarations and endings
733
734 Parameters
735 ----------
736 addStmt : str or list, optional
737 Statement(s) to insert into the body of emptied scopes.
738 simplify : bool, optional
739 If True, also remove unused local variables.
740
741 Examples
742 --------
743 >>> pft = PYFT('myfile.F90')
744 >>> pft.empty() # Remove all statements
745
746 Empty and add a comment:
747 >>> pft.empty(addStmt='! TODO: Implement')
748 """
749 scopes = [] # list of scopes to empty
750 for scope in self.getScopes(level=1, excludeContains=False):
751 if scope.path.split('/')[-1].split(':')[0] == 'module':
752 scopes.extend(scope.getScopes(level=1, excludeContains=False, includeItself=False))
753 else:
754 scopes.append(scope)
755 tagExcluded = (list(self.SCOPE_STMT.values()) +
756 ['end-' + decl for decl in self.SCOPE_STMT.values()] +
757 ['T-decl-stmt', 'use-stmt', 'C'])
758 for scope in scopes:
759 for node in list(scope):
760 if tag(node) not in tagExcluded:
761 scope.remove(node)
762 scope.removeUnusedLocalVar(simplify=simplify)
763 if addStmt is not None:
764 if isinstance(addStmt, str):
765 addStmt = createExpr(addStmt)
766 elif not isinstance(addStmt, list):
767 addStmt = [addStmt]
768 for stmt in addStmt:
769 scope.insertStatement(stmt, False)
770 if simplify:
771 # Apllied on self (and not scope) to remove lines before the first scope
772 # in case self represents an entire file
773 self.removeComments()
774 self.removeEmptyLines()
removeComments(self, exclDirectives=None, pattern=None)
Definition cosmetics.py:220
iterfind(self, *args, **kwargs)
Definition scope.py:115
iter(self, *args, **kwargs)
Definition scope.py:148
itertext(self, *args, **kwargs)
Definition scope.py:121
findall(self, *args, **kwargs)
Definition scope.py:142
find(self, *args, **kwargs)
Definition scope.py:136
append(self, *args, **kwargs)
Definition scope.py:172
__init__(self, xml, excludeContains=False)
Definition scope.py:53
_getIndex(self, index)
Definition scope.py:186
extend(self, *args, **kwargs)
Definition scope.py:179
insert(self, index, item)
Definition scope.py:216
findtext(self, *args, **kwargs)
Definition scope.py:109
items(self, *args, **kwargs)
Definition scope.py:154
getScopeNode(self, scopePath, excludeContains=True, includeItself=True)
Definition scope.py:582
empty(self, addStmt=None, simplify=False)
Definition scope.py:725
__init__(self, xml, scopePath='/', parentScope=None, enableCache=False, tree=None, excludeContains=False)
Definition scope.py:272
getScopes(self, level=-1, excludeContains=True, excludeKinds=None, includeItself=True)
Definition scope.py:519
getScopePath(self, item, includeItself=True)
Definition scope.py:674
isScopeNode(self, node)
Definition scope.py:621
normalizeScope(scopePath)
Definition scope.py:469
getParent(self, item, level=1)
Definition scope.py:363
getSiblings(self, item, before=True, after=True)
Definition scope.py:401
_getNodePath(self, node)
Definition scope.py:457
getParentScopeNode(self, item, mustRaise=True)
Definition scope.py:645
showScopesList(self, includeItself=False)
Definition scope.py:495
__getattr__(self, attr)
Definition scope.py:318