1 #!/usr/bin/env python 2 3 """ 4 Annotate program node structures. The code in this module operates upon nodes 5 which are produced when simplifying AST node trees originating from the compiler 6 module. 7 8 Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk> 9 10 This software is free software; you can redistribute it and/or 11 modify it under the terms of the GNU General Public License as 12 published by the Free Software Foundation; either version 2 of 13 the License, or (at your option) any later version. 14 15 This software is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public 21 License along with this library; see the file LICENCE.txt 22 If not, write to the Free Software Foundation, Inc., 23 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 24 25 -------- 26 27 To use this module, the easiest approach is to use the load function: 28 29 load(filename, builtins) 30 31 To control module importing, an importer should be constructed and employed. 32 Here, the standard path for module searching is used: 33 34 importer = Importer(sys.path) 35 load(filename, builtins, importer) 36 37 Underneath the load function, the annotate function provides support for 38 annotating modules already processed by simplify and fixnames: 39 40 annotate(module, builtins) 41 42 And at the most basic level, the most intricate approach involves obtaining an 43 Annotator object: 44 45 annotator = Annotator() 46 47 Then, processing an existing module with it: 48 49 annotator.process(module) 50 51 If a module containing built-in classes and functions has already been 52 annotated, such a module should be passed in as an additional argument: 53 54 annotator.process(module, builtins) 55 """ 56 57 from simplified import * 58 import simplify, fixnames # for the load function 59 import compiler 60 import os 61 62 class System: 63 64 """ 65 A class maintaining the state of the annotation system. When the system 66 counter can no longer be incremented by any annotation operation, the 67 system may be considered stable and fully annotated. 68 """ 69 70 def __init__(self): 71 self.count = 0 72 73 def init(self, node, attr="types"): 74 75 "Initialise a 'node' for annotation." 76 77 if not hasattr(node, attr): 78 setattr(node, attr, set()) 79 80 def annotate(self, node, types, attr="types"): 81 82 "Annotate the given 'node' with the given 'types'." 83 84 self.init(node, attr) 85 self.combine(getattr(node, attr), types) 86 87 def combine(self, target, types): 88 89 """ 90 Combine the 'target' list with the given 'types', counting new members. 91 """ 92 93 for type in types: 94 if type not in target: 95 target.add(type) 96 self.count += 1 97 98 system = System() 99 100 # Exceptions. 101 102 class AnnotationError(SimplifiedError): 103 104 "An error in the annotation process." 105 106 pass 107 108 class AnnotationMessage(Exception): 109 110 "A lesser annotation error." 111 112 pass 113 114 # Annotation. 115 116 class Annotator(Visitor): 117 118 """ 119 The type annotator which traverses the program nodes, typically depth-first, 120 and maintains a record of the current set of types applying to the currently 121 considered operation. Such types are also recorded on the nodes, and a 122 special "system" record is maintained to monitor the level of annotation 123 activity with a view to recognising when no more annotations are possible. 124 125 Throughout the annotation activity, type information consists of lists of 126 Attribute objects where such objects retain information about the context of 127 the type (since a value in the program may be associated with an object or 128 class) and the actual type of the value being manipulated. Upon accessing 129 attribute information on namespaces, additional accessor information is also 130 exchanged - this provides a means of distinguishing between the different 131 types possible when the means of constructing the namespace may depend on 132 run-time behaviour. 133 134 Covered: Assign, CheckType, Conditional, Global, Import, InvokeRef, 135 InvokeFunction, LoadAttr, LoadExc, LoadName, LoadRef, LoadTemp, 136 Module, Not, Pass, Raise, ReleaseTemp, ReturnFromBlock, 137 ReturnFromFunction, StoreAttr, StoreName, StoreTemp, Subprogram, 138 Try. 139 """ 140 141 def __init__(self, importer=None): 142 143 "Initialise the visitor with an optional 'importer'." 144 145 Visitor.__init__(self) 146 self.system = system 147 self.importer = importer or Importer() 148 149 # Satisfy visitor issues. 150 151 self.visitor = self 152 153 def process(self, module, builtins=None): 154 155 """ 156 Process the given 'module', using the optional 'builtins' to access 157 built-in classes and functions. 158 """ 159 160 self.subprograms = [] 161 self.current_subprograms = [] 162 self.current_namespaces = [] 163 self.rerun_subprograms = {} 164 self.namespace = None 165 self.module = module 166 167 # Process the module, supplying builtins if possible. 168 169 self.builtins = builtins 170 self.global_namespace = Namespace() 171 172 if builtins is not None: 173 self.builtins_namespace = builtins.namespace 174 else: 175 self.builtins_namespace = self.global_namespace 176 177 # NOTE: Not declaring module namespace usage, even though it is used. 178 179 self.process_node(module, self.global_namespace, 0) 180 181 def process_node(self, node, locals, using_module_namespace): 182 183 """ 184 Process a subprogram or module 'node', indicating the initial 'locals'. 185 Note that this method may mutate nodes in the original program. 186 """ 187 188 # Recursion test. 189 190 if node in self.current_subprograms: 191 if not self.rerun_subprograms.has_key(node): 192 self.rerun_subprograms[node] = [] 193 self.rerun_subprograms[node].append(locals) 194 return 195 196 # Record the current subprogram and namespace. 197 198 self.current_subprograms.append(node) 199 200 # Determine the namespace. 201 202 self.current_namespaces.append(self.namespace) 203 self.namespace = locals 204 205 # Add namespace details to any structure involved. 206 207 if getattr(node, "structure", None) is not None: 208 node.structure.namespace = Namespace() 209 210 # Initialise bases where appropriate. 211 212 if hasattr(node.structure, "bases"): 213 base_refs = [] 214 for base in node.structure.bases: 215 self.dispatch(base) 216 base_refs.append(self.namespace.types) 217 node.structure.base_refs = base_refs 218 219 # Dispatch to the code itself. 220 221 node.namespace = self.namespace 222 self.set_module_namespace(using_module_namespace) 223 224 self.dispatch(node) 225 self.extract_results(node) 226 227 while self.rerun_subprograms.has_key(node): 228 all_rerun_locals = self.rerun_subprograms[node] 229 del self.rerun_subprograms[node] 230 for rerun_locals in all_rerun_locals: 231 #print "Re-running", node, "with", rerun_locals 232 233 self.namespace = rerun_locals 234 node.namespace = rerun_locals 235 self.set_module_namespace(using_module_namespace) 236 237 self.dispatch(node) 238 self.extract_results(node) 239 240 # Restore the previous subprogram and namespace. 241 242 self.namespace = self.current_namespaces.pop() 243 self.current_subprograms.pop() 244 self.reset_module_namespace(using_module_namespace) 245 246 def set_module_namespace(self, using_module_namespace): 247 248 """ 249 In order to keep global accesses working, the module namespace must be 250 adjusted. 251 """ 252 253 if using_module_namespace: 254 self.module.namespace = self.namespace 255 256 def reset_module_namespace(self, using_module_namespace): 257 258 """ 259 In order to keep global accesses working, the module namespace must be 260 reset. 261 """ 262 263 if using_module_namespace: 264 self.module.namespace = self.namespace 265 266 def extract_results(self, node): 267 268 "Extract results from the namespace." 269 270 node.namespace = self.namespace 271 self.system.annotate(node, self.namespace.raises, "raises") 272 self.system.annotate(node, self.namespace.returns, "returns") 273 if hasattr(node, "return_locals"): 274 node.return_locals.update(self.namespace.return_locals) 275 276 def annotate(self, node, types=None): 277 278 """ 279 Annotate the given 'node' in the system, using either the optional 280 'types' or the namespace's current type information. 281 """ 282 283 if types is None: 284 self.system.annotate(node, self.namespace.types) 285 else: 286 self.system.annotate(node, types) 287 288 def annotate_parameters(self, node, items): 289 290 """ 291 Annotate the given 'node' using the given 'items' and updating the 292 system's annotation counter. 293 """ 294 295 if not hasattr(node, "paramtypes"): 296 node.paramtypes = {} 297 298 for param, types in items: 299 if not node.paramtypes.has_key(param): 300 node.paramtypes[param] = set() 301 self.system.combine(node.paramtypes[param], types) 302 303 # Visitor methods. 304 305 def default(self, node): 306 307 """ 308 Process the given 'node', given that it does not have a specific 309 handler. 310 """ 311 312 raise AnnotationMessage, "Node '%s' not supported." % node 313 314 def dispatch(self, node, *args): 315 try: 316 Visitor.dispatch(self, node, *args) 317 except AnnotationError, exc: 318 exc.add(node) 319 raise 320 except AnnotationMessage, exc: 321 raise AnnotationError(exc, node) 322 323 # Specific node methods. 324 325 def visitAssign(self, assign): 326 327 """ 328 Process the 'assign' node and its contents. 329 """ 330 331 self.dispatches(assign.code) 332 333 def visitCheckType(self, checktype): 334 335 """ 336 Process the 'checktype' node, finding the possible types of the 337 exception, and processing each choice to build a list of checked types 338 for the exception. 339 """ 340 341 inverted = getattr(checktype, "inverted", 0) 342 self.dispatch(checktype.expr) 343 344 expr_types = self.namespace.types 345 choice_types = set() 346 choices = [] 347 348 for choice in checktype.choices: 349 choices.append(self.dispatch(choice)) 350 choice_types.update(self.namespace.types) 351 352 for expr_type in expr_types: 353 in_choices = expr_type.type.get_class() in choice_types 354 355 # Filter out types not in the choices list unless the operation is 356 # inverted; in which case, filter out types in the choices list. 357 358 if not inverted and not in_choices or inverted and in_choices: 359 self._prune_non_accesses(checktype.expr, expr_type) 360 361 def visitConditional(self, conditional): 362 363 """ 364 Process the 'conditional' node, processing the test, body and else 365 clauses and recording their processed forms. The body and else clauses 366 are processed within their own namespaces, and the test is also 367 processed in its own namespace if 'isolate_test' is set on the 368 'conditional' node. 369 """ 370 371 # Conditionals keep local namespace changes isolated. 372 # With Return nodes inside the body/else sections, the changes are 373 # communicated to the caller. 374 375 is_module = self.namespace is self.module.namespace 376 377 # Where the test is closely associated with the body, save the namespace 378 # before entering the test. 379 380 if conditional.isolate_test: 381 saved_namespace = self.namespace 382 self.namespace = Namespace() 383 if is_module: 384 self.module.namespace = self.namespace 385 self.namespace.merge_namespace(saved_namespace) 386 387 self.dispatch(conditional.test) 388 389 # Where the test may affect the body and the else clause, save the 390 # namespace after processing the test. 391 392 if not conditional.isolate_test: 393 saved_namespace = self.namespace 394 self.namespace = Namespace() 395 if is_module: 396 self.module.namespace = self.namespace 397 self.namespace.merge_namespace(saved_namespace) 398 399 # NOTE: Exception recording. 400 401 else: 402 test_raises = set() 403 test_raises.update(self.namespace.raises) 404 405 # Process the body clause. 406 407 self.dispatches(conditional.body) 408 body_namespace = self.namespace 409 410 # Use the saved namespace as a template for the else clause. 411 412 self.namespace = Namespace() 413 if is_module: 414 self.module.namespace = self.namespace 415 self.namespace.merge_namespace(saved_namespace) 416 417 # Process the else clause. 418 419 self.dispatches(conditional.else_) 420 else_namespace = self.namespace 421 422 # Merge the body and else namespaces. 423 424 self.namespace = Namespace() 425 if is_module: 426 self.module.namespace = self.namespace 427 self.namespace.merge_namespace(body_namespace) 428 self.namespace.merge_namespace(else_namespace) 429 430 # NOTE: Test of exception type pruning based on the test/body. 431 # Note that the checked exceptions are tested for re-raising. 432 433 if conditional.isolate_test: 434 for exc_type in test_raises: 435 if exc_type not in body_namespace.raises: 436 self.namespace.revoke_exception_type(exc_type) 437 438 def visitGlobal(self, global_): 439 440 """ 441 Leave the 'global_' node unprocessed since namespaces should have 442 already been altered to take global names into consideration. 443 """ 444 445 pass 446 447 def visitImport(self, import_): 448 449 """ 450 Process the 'import_' node, importing the module with the stated name 451 and storing details on the node. 452 """ 453 454 module = self.importer.load(import_.name, self.builtins, getattr(import_, "alias", None)) 455 if module is not None: 456 self.namespace.set_types(set([module])) 457 else: 458 self.namespace.set_types(set()) 459 self.annotate(import_) # mainly for viewing purposes 460 461 def _visitInvoke(self, invoke, invocation_types, have_args): 462 463 """ 464 Process the 'invoke' node, using the given 'invocation_types' as the 465 list of callables to be investigated for instantiation or for the 466 invocation of functions or blocks. If 'have_args' is a true value, any 467 invocation or instantiation will involve arguments. 468 """ 469 470 # Now locate and invoke the subprogram. This can be complicated because 471 # the target may be a class or object, and there may be many different 472 # related subprograms. 473 474 invocations = [] 475 476 # Visit each callable in turn, finding subprograms. 477 478 for attr in invocation_types: 479 480 # Deal with class invocations by providing instance objects. 481 # Here, each class is queried for the __init__ method, which may 482 # exist for some combinations of classes in a hierarchy but not for 483 # others. 484 485 if isinstance(attr.type, Class): 486 attributes = get_attributes(attr.type, "__init__") 487 488 # Deal with object invocations by using __call__ methods. 489 490 elif isinstance(attr.type, Instance): 491 attributes = get_attributes(attr.type, "__call__") 492 493 # Normal functions or methods are more straightforward. 494 # Here, we model them using an attribute with no context and with 495 # no associated accessor. 496 497 else: 498 attributes = [(attr, None)] 499 500 # Inspect each attribute and extract the subprogram. 501 502 for attribute, accessor in attributes: 503 504 # If a class is involved, presume that it must create a new 505 # object. 506 507 if isinstance(attr.type, Class): 508 509 # Instantiate the class. 510 511 instance = self.new_instance(invoke, attr.type) 512 513 # For instantiations, switch the context. 514 515 if attribute is not None: 516 attribute = Attribute(instance, attribute.type) 517 518 # Request an instance-specific initialiser. 519 520 attribute = attr.type.get_attribute_for_instance(attribute, instance) 521 522 # Skip cases where no callable is found. 523 524 if attribute is not None: 525 526 # If a subprogram is defined, invoke it. 527 528 self.invoke_subprogram(invoke, attribute) 529 if attribute.type not in invocations: 530 invocations.append(attribute.type) 531 532 elif not isinstance(attr.type, Class): 533 print "Invocation type is None for", accessor 534 535 else: 536 537 # Test to see if no arguments were supplied in cases where no 538 # initialiser was found. 539 540 if have_args: 541 raise AnnotationMessage, "No initialiser found for '%s' with arguments." % attr.type 542 543 # Special case: initialisation. 544 545 if isinstance(attr.type, Class): 546 547 # Associate the instance with the result of this invocation. 548 549 self.namespace.set_types(set([Attribute(None, instance)])) 550 self.annotate(invoke) 551 552 # Remember the invocations that were found, along with the return type 553 # information. 554 555 invoke.invocations = invocations 556 self.namespace.set_types(getattr(invoke, "types", set())) 557 558 def visitInvokeRef(self, invoke): 559 560 """ 561 Process the 'invoke' node, first finding the callables indicated by the 562 reference. 563 """ 564 565 # Where the invocation belongs to an instance but the invoked subprogram 566 # does not, request a special copy. 567 568 instance = getattr(invoke, "instance", None) 569 if instance is not None and getattr(invoke.ref, "instance", None) is None: 570 if invoke.ref.copies.has_key(instance): 571 invoke.ref = invoke.ref.copies[instance] 572 else: 573 invoke.ref = invoke.ref.copy(instance) 574 #print "Created", invoke.ref, "for", getattr(invoke.ref, "instance", None) 575 invoke.ref.module.simplifier.subnames[invoke.ref.full_name()] = invoke.ref 576 invocation_types = [Attribute(None, invoke.ref)] 577 self._visitInvoke(invoke, invocation_types, have_args=0) 578 579 def visitInvokeFunction(self, invoke): 580 581 """ 582 Process the 'invoke' node, first finding the callables indicated by the 583 expression. 584 """ 585 586 self.dispatch(invoke.expr) 587 invocation_types = self.namespace.types 588 589 # Invocation processing starts with making sure that the arguments have 590 # been processed. 591 592 self._visitInvoke(invoke, invocation_types, have_args=self.process_args(invoke)) 593 594 def visitLoadAttr(self, loadattr): 595 596 """ 597 Process the 'loadattr' node, processing and storing the expression, and 598 using the expression's types to construct records of accesses and 599 non-accesses using the stated attribute name. 600 """ 601 602 self.dispatch(loadattr.expr) 603 types = set() 604 raises = set() 605 non_accesses = [] 606 accesses = {} 607 608 # For each expression type... 609 610 for attr in self.namespace.types: 611 612 # Find types for the named attribute. 613 614 attributes = get_attributes(attr.type, loadattr.name) 615 616 # Where no attributes exist... 617 618 if not attributes: 619 620 # Register new invalid accesses and mark a possible exception. 621 622 if not attr in non_accesses: 623 non_accesses.append(attr) 624 exc = self.get_builtin_instances(loadattr, "AttributeError") 625 raises.update(exc) 626 self.namespace.raises.update(exc) 627 628 # Revoke this type from any name involved. 629 630 self._prune_non_accesses(loadattr.expr, attr) 631 632 # For each type found... 633 634 for attribute, accessor in attributes: 635 636 # For actual attributes, register the type and remember the 637 # access. 638 639 if attribute is not None: 640 types.add(attribute) 641 if not accesses.has_key(attr.type): 642 accesses[attr.type] = [] 643 if not (attribute, accessor) in accesses[attr.type]: 644 accesses[attr.type].append((attribute, accessor)) 645 646 # Otherwise, register new invalid accesses and note a possible 647 # exception. 648 649 else: 650 if not attr in non_accesses: 651 non_accesses.append(attr) 652 exc = self.get_builtin_instances(loadattr, "AttributeError") 653 raises.update(exc) 654 self.namespace.raises.update(exc) 655 656 # Revoke this type from any name involved. 657 658 self._prune_non_accesses(loadattr.expr, attr) 659 660 if not types: 661 print "No attribute found for", loadattr.name, "given", self.namespace.types 662 663 # Remember the result types. 664 665 self.namespace.set_types(types) 666 loadattr.non_accesses = non_accesses 667 loadattr.accesses = accesses 668 loadattr.raises = raises 669 self.annotate(loadattr) 670 671 def _prune_non_accesses(self, expr, attr): 672 673 """ 674 Prune type information from 'expr' where the given 'attr' has been 675 shown to be a non-access. 676 """ 677 678 if isinstance(expr, LoadName): 679 self.namespace.revoke(expr.name, attr) 680 elif isinstance(expr, LoadExc): 681 self.namespace.revoke_exception_type(attr) 682 elif isinstance(expr, LoadTemp): 683 self.namespace.revoke_temp_type(getattr(expr, "index", None), attr) 684 685 # LoadAttr cannot be pruned since this might unintentionally prune 686 # legitimate types from other applications of the referenced type, it 687 # almost certainly doesn't take "concurrent" mutation into 688 # consideration (where in a running program, the pruned type is actually 689 # reintroduced, making the pruning invalid), and there is no easy way of 690 # preserving the meaning of a namespace without either creating lots of 691 # specialised instances, and even then... 692 693 #elif isinstance(expr, LoadAttr): 694 # for expr_attr in expr.expr.types: 695 # if hasattr(expr_attr.type, "namespace"): 696 # expr_attr.type.namespace.revoke(expr.name, attr) 697 698 def visitLoadExc(self, loadexc): 699 700 """ 701 Process the 'loadexc' node, discovering the possible exception types 702 raised. 703 """ 704 705 self.namespace.set_types(self.namespace.raises) 706 self.annotate(loadexc) 707 708 def visitLoadName(self, loadname): 709 710 """ 711 Process the 'loadname' node, processing the name information on the node 712 to determine which types are involved with the name. 713 """ 714 715 self.namespace.set_types(self.namespace.load(loadname.name)) 716 self.annotate(loadname) 717 718 def visitLoadRef(self, loadref): 719 720 """ 721 Process the 'loadref' node, obtaining type information about the 722 reference stated on the node. 723 """ 724 725 self.namespace.set_types(set([Attribute(None, loadref.ref)])) 726 self.annotate(loadref) 727 728 def visitLoadTemp(self, loadtemp): 729 730 """ 731 Process the 'loadtemp' node, obtaining type information about the 732 temporary variable accessed, and removing variable information where the 733 'release' attribute has been set on the node. 734 """ 735 736 index = getattr(loadtemp, "index", None) 737 try: 738 if getattr(loadtemp, "release", 0): 739 self.namespace.set_types(self.namespace.temp[index].pop()) 740 else: 741 self.namespace.set_types(self.namespace.temp[index][-1]) 742 except KeyError: 743 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 744 self.annotate(loadtemp) 745 746 def visitModule(self, module): 747 748 """ 749 Process the 'module' and its contents. 750 """ 751 752 self.dispatches(module.code) 753 754 def visitNot(self, not_): 755 756 "Process the 'not_' node and its expression." 757 758 self.dispatch(not_.expr) 759 760 def visitPass(self, pass_): 761 762 "Leave the 'pass_' node unprocessed." 763 764 pass 765 766 def visitRaise(self, raise_): 767 768 """ 769 Process the 'raise_' node, processing any traceback information along 770 with the raised exception expression, converting the node into a kind of 771 invocation where the expression is found not to be an invocation itself. 772 This node affects the namespace, adding exception types to the list of 773 those raised in the namespace. 774 """ 775 776 if getattr(raise_, "traceback", None) is not None: 777 self.dispatch(raise_.traceback) 778 self.dispatch(raise_.expr) 779 780 # Handle bare name exceptions by converting any classes to instances. 781 782 if not isinstance(raise_.expr, InvokeFunction): 783 raise_.pos_args = [] 784 raise_.kw_args = {} 785 raise_.star = None 786 raise_.dstar = None 787 types = set() 788 for attr in self.namespace.types: 789 if isinstance(attr.type, Class): 790 self._visitInvoke(raise_, [attr], have_args=0) 791 types.update(self.namespace.types) 792 else: 793 types = self.namespace.types 794 795 self.namespace.raises.update(types) 796 797 def visitReleaseTemp(self, releasetemp): 798 799 """ 800 Process the 'releasetemp' node, removing temporary variable information 801 from the current namespace. 802 """ 803 804 index = getattr(releasetemp, "index", None) 805 try: 806 self.namespace.temp[index].pop() 807 except KeyError: 808 raise AnnotationMessage, "Temporary store index '%s' not defined." % index 809 except IndexError: 810 pass #raise AnnotationMessage, "Temporary store index '%s' is empty." % index 811 812 def visitResetExc(self, resetexc): 813 self.namespace.raises = set() 814 815 def visitReturn(self, return_): 816 817 """ 818 Process the 'return_' node, processing any expression and obtaining type 819 information to be accumulated in the current namespace's list of return 820 types. A snapshot of the namespace is taken for the purposes of 821 reconciling or merging namespaces where subprograms actually share 822 locals with their callers. 823 """ 824 825 if hasattr(return_, "expr"): 826 self.dispatch(return_.expr) 827 self.namespace.returns.update(self.namespace.types) 828 self.annotate(return_) 829 self.namespace.snapshot() 830 831 visitReturnFromBlock = visitReturn 832 visitReturnFromFunction = visitReturn 833 834 def visitStoreAttr(self, storeattr): 835 836 """ 837 Process the 'storeattr' node, processing the expression and target, and 838 using the type information obtained to build records of legitimate 839 writes to the stated attribute, along with "impossible" non-writes to 840 the attribute. 841 """ 842 843 self.dispatch(storeattr.expr) 844 expr = self.namespace.types 845 self.dispatch(storeattr.lvalue) 846 writes = {} 847 non_writes = [] 848 for attr in self.namespace.types: 849 # NOTE: Impose "atomic" constraints on certain types. 850 if attr is None: 851 if not attr in non_writes: 852 non_writes.append(attr) 853 continue 854 attr.type.namespace.add(storeattr.name, expr) 855 writes[attr.type] = attr.type.namespace.load(storeattr.name) 856 if not writes: 857 print "Unable to store attribute", storeattr.name, "given", self.namespace.types 858 storeattr.writes = writes 859 storeattr.non_writes = non_writes 860 861 def visitStoreName(self, storename): 862 863 """ 864 Process the 'storename' node, processing the expression on the node and 865 associating the type information obtained with the stated name in the 866 current namespace. 867 """ 868 869 self.dispatch(storename.expr) 870 self.namespace.store(storename.name, self.namespace.types) 871 self.annotate(storename) 872 873 def visitStoreTemp(self, storetemp): 874 875 """ 876 Process the 'storetemp' node, processing the expression on the node and 877 associating the type information obtained with a temporary variable in 878 the current namespace. 879 """ 880 881 self.dispatch(storetemp.expr) 882 index = getattr(storetemp, "index", None) 883 if not self.namespace.temp.has_key(index): 884 self.namespace.temp[index] = [] 885 self.namespace.temp[index].append(self.namespace.types) 886 887 def visitSubprogram(self, subprogram): 888 889 """ 890 Process the 'subprogram' node, processing its contents (a group of nodes 891 comprising the subprogram). 892 """ 893 894 self.dispatches(subprogram.code) 895 896 def visitTry(self, try_): 897 898 """ 899 Process the 'try_' node, processing the body clause in its own namespace 900 derived from the current namespace, processing any handler clause using 901 the namespace information accumulated in the body, and processing any 902 else and finally clauses, attempting to supply each with appropriate 903 namespace information. 904 """ 905 906 is_module = self.namespace is self.module.namespace 907 908 self.dispatches(try_.body) 909 910 # Save the namespace from the body. 911 912 body_namespace = Namespace() 913 body_namespace.merge_namespace(self.namespace) 914 915 # Process the handler. 916 917 if hasattr(try_, "handler"): 918 self.dispatches(try_.handler) 919 920 # Save the namespace from the handler. 921 922 handler_namespace = Namespace() 923 handler_namespace.merge_namespace(self.namespace) 924 925 # Remember the raised exceptions encountered so far. 926 927 raises = self.namespace.raises 928 929 # Process the else clause. 930 931 if hasattr(try_, "else_"): 932 933 # Restore the body namespace for the else clause. 934 935 self.namespace = body_namespace 936 if is_module: 937 self.module.namespace = self.namespace 938 939 # Empty the raised exceptions for the else clause. 940 941 self.namespace.raises = set() 942 self.dispatches(try_.else_) 943 self.namespace.raises = raises 944 945 # Merge the namespaces. 946 947 self.namespace = Namespace() 948 if is_module: 949 self.module.namespace = self.namespace 950 self.namespace.merge_namespace(body_namespace) 951 self.namespace.merge_namespace(handler_namespace) 952 953 # Process the finally clause, if any. 954 955 self.dispatches(try_.finally_) 956 957 def visitYield(self, yield_): 958 raise NotImplementedError, "The yield statement is not currently supported." 959 960 # Utility methods. 961 962 def get_builtin_instances(self, node, name): 963 return [Attribute(None, self.new_instance(node, attr.type)) for attr in self.builtins.namespace[name]] 964 965 def new_instance(self, node, type): 966 967 "For the given 'node', obtain an instance from the given 'type'." 968 969 if not type.has_instance(node): 970 instance = Instance() 971 instance.namespace = Namespace() 972 instance.namespace.store("__class__", set([Attribute(None, type)])) 973 type.add_instance(node, instance) 974 else: 975 instance = type.get_instance(node) 976 977 return instance 978 979 def invoke_subprogram(self, invoke, attribute): 980 981 """ 982 Invoke using the given 'invoke' node the subprogram represented by the 983 given 'attribute'. 984 """ 985 986 # Test for context information, making it into a real attribute. 987 988 if attribute.context is not None: 989 context = Attribute(None, attribute.context) 990 target = attribute.type 991 else: 992 context = None 993 target = attribute.type 994 995 # Test to see if anything has changed. 996 997 if hasattr(invoke, "syscount") and invoke.syscount.has_key(target) and invoke.syscount[target] == self.system.count: 998 return 999 1000 # Remember the state of the system. 1001 1002 else: 1003 if not hasattr(invoke, "syscount"): 1004 invoke.syscount = {} 1005 invoke.syscount[target] = self.system.count 1006 1007 # Provide the correct namespace for the invocation. 1008 # This may be a "shared" namespace... 1009 1010 if getattr(invoke, "share_locals", 0): 1011 namespace = Namespace() 1012 namespace.merge_namespace(self.namespace, everything=0) 1013 using_module_namespace = self.namespace is self.module.namespace 1014 1015 # Or it may be a structure... 1016 1017 elif getattr(target, "structure", None): 1018 namespace = Namespace() 1019 using_module_namespace = 0 1020 1021 # Or it may be a new namespace populated with the supplied parameters. 1022 1023 else: 1024 items = self.make_items(invoke, target, context) 1025 namespace = Namespace() 1026 namespace.merge_items(items) 1027 using_module_namespace = 0 1028 1029 # NOTE: Avoid PEP 227 (nested scopes) whilst permitting references to a 1030 # NOTE: subprogram within itself. Do not define the name of the function 1031 # NOTE: within a method definition. 1032 1033 if getattr(target, "name", None) is not None and not getattr(target, "is_method", 0): 1034 namespace.store(target.name, set([Attribute(None, target)])) 1035 1036 # Process the subprogram. 1037 1038 self.process_node(target, namespace, using_module_namespace) 1039 1040 # NOTE: Improve and verify this. 1041 # If the invocation returns a value, acquire the return types. 1042 1043 if getattr(target, "returns_value", 0): 1044 self.namespace.set_types(target.returns) 1045 self.annotate(invoke) 1046 1047 # If it is a normal block, merge the locals. 1048 # This can happen in addition to the above because for things like 1049 # logical expressions, the namespace can be modified whilst values are 1050 # returned as results. 1051 1052 if getattr(invoke, "share_locals", 0): 1053 self.namespace.reset() 1054 1055 # Merge the locals snapshots. 1056 1057 for locals in target.return_locals: 1058 1059 # For blocks returning values (such as operations), do not merge 1060 # snapshots or results. 1061 1062 if getattr(target, "returns_value", 0): 1063 self.namespace.merge_namespace(locals, everything=0) 1064 1065 # For blocks not returning values (such as loops), merge 1066 # snapshots and results since they contain details of genuine 1067 # returns. 1068 1069 else: 1070 self.namespace.merge_namespace(locals) 1071 1072 # Incorporate any raised exceptions. 1073 1074 if not hasattr(invoke, "raises"): 1075 invoke.raises = set() 1076 invoke.raises.update(target.raises) 1077 self.namespace.raises.update(target.raises) 1078 1079 def process_args(self, invocation): 1080 1081 """ 1082 Process the arguments associated with an 'invocation'. Return whether 1083 any arguments were processed. 1084 """ 1085 1086 self.dispatches(invocation.pos_args) 1087 self.dispatch_dict(invocation.kw_args) 1088 1089 # Get type information for star and dstar arguments. 1090 1091 if invocation.star is not None: 1092 param, default = invocation.star 1093 self.dispatch(default) 1094 invocation.star = param, default 1095 1096 if invocation.dstar is not None: 1097 param, default = invocation.dstar 1098 self.dispatch(default) 1099 invocation.dstar = param, default 1100 1101 if invocation.pos_args or invocation.kw_args or invocation.star or invocation.dstar: 1102 return 1 1103 else: 1104 return 0 1105 1106 def make_items(self, invocation, subprogram, context): 1107 1108 """ 1109 Make an items mapping for the 'invocation' of the 'subprogram' using the 1110 given 'context' (which may be None). 1111 """ 1112 1113 # NOTE: Support class methods! 1114 1115 if context is not None and isinstance(context.type, Instance): 1116 pos_args = [Self(context)] + invocation.pos_args 1117 else: 1118 pos_args = invocation.pos_args 1119 1120 # Duplicate the keyword arguments - we remove them in processing below. 1121 1122 kw_args = {} 1123 kw_args.update(invocation.kw_args) 1124 1125 # Sort the arguments into positional and keyword arguments. 1126 1127 params = subprogram.params 1128 items = [] 1129 star_args = [] 1130 1131 # Match each positional argument, taking excess arguments as star args. 1132 1133 for arg in pos_args: 1134 if params: 1135 param, default = params[0] 1136 if arg is None: 1137 arg = default 1138 if hasattr(arg, "types"): 1139 items.append((param, arg.types)) 1140 else: 1141 items.append((param, set())) # Annotation has not succeeded. 1142 params = params[1:] 1143 else: 1144 star_args.append(arg) 1145 1146 # Collect the remaining defaults. 1147 1148 while params: 1149 param, default = params[0] 1150 if kw_args.has_key(param): 1151 arg = kw_args[param] 1152 del kw_args[param] 1153 elif default is not None: 1154 self.dispatch(default) 1155 arg = default 1156 else: 1157 raise AnnotationMessage, "No argument supplied in '%s' for parameter '%s'." % (subprogram, param) 1158 if hasattr(arg, "types"): 1159 items.append((param, arg.types)) 1160 else: 1161 items.append((param, set())) # Annotation has not succeeded. 1162 params = params[1:] 1163 1164 dstar_args = kw_args.items() 1165 1166 # Construct temporary objects. 1167 1168 if star_args: 1169 star_invocation = self.make_star_args(invocation, subprogram, star_args) 1170 self.dispatch(star_invocation) 1171 star_types = star_invocation.types 1172 else: 1173 star_types = None 1174 1175 if dstar_args: 1176 dstar_invocation = self.make_dstar_args(invocation, subprogram, dstar_args) 1177 self.dispatch(dstar_invocation) 1178 dstar_types = dstar_invocation.types 1179 else: 1180 dstar_types = None 1181 1182 # NOTE: Merge the objects properly. 1183 1184 star_types = star_types or invocation.star and invocation.star.types 1185 dstar_types = dstar_types or invocation.dstar and invocation.dstar.types 1186 1187 # Add star and dstar. 1188 1189 if star_types is not None: 1190 if subprogram.star is not None: 1191 param, default = subprogram.star 1192 items.append((param, star_types)) 1193 else: 1194 raise AnnotationMessage, "Invocation provides unwanted *args." 1195 elif subprogram.star is not None: 1196 param, default = subprogram.star 1197 if not hasattr(default, "types"): 1198 subprogram.star = param, self.dispatch(default) # NOTE: Review reprocessing. 1199 items.append((param, default.types)) 1200 1201 if dstar_types is not None: 1202 if subprogram.dstar is not None: 1203 param, default = subprogram.dstar 1204 items.append((param, dstar_types)) 1205 else: 1206 raise AnnotationMessage, "Invocation provides unwanted **args." 1207 elif subprogram.dstar is not None: 1208 param, default = subprogram.dstar 1209 if not hasattr(default, "types"): 1210 subprogram.dstar = param, self.dispatch(default) # NOTE: Review reprocessing. 1211 items.append((param, default.types)) 1212 1213 # Record the parameter types. 1214 1215 self.annotate_parameters(subprogram, items) 1216 return subprogram.paramtypes.items() 1217 1218 def make_star_args(self, invocation, subprogram, star_args): 1219 1220 "Make a subprogram which initialises a list containing 'star_args'." 1221 1222 if not hasattr(invocation, "stars"): 1223 invocation.stars = {} 1224 1225 if not invocation.stars.has_key(subprogram.full_name()): 1226 instance = getattr(invocation, "instance", None) 1227 1228 code=[ 1229 StoreTemp( 1230 instance=instance, 1231 expr=InvokeFunction( 1232 invocation.original, 1233 instance=instance, 1234 expr=LoadAttr( 1235 instance=instance, 1236 expr=LoadRef( 1237 instance=instance, 1238 ref=self.builtins 1239 ), 1240 name="list", 1241 nstype="module", 1242 ), 1243 args=[], 1244 star=None, 1245 dstar=None 1246 ) 1247 ) 1248 ] 1249 1250 for arg in star_args: 1251 code.append( 1252 InvokeFunction( 1253 invocation.original, 1254 instance=instance, 1255 expr=LoadAttr( 1256 instance=instance, 1257 expr=LoadTemp( 1258 instance=instance 1259 ), 1260 name="append" 1261 ), 1262 args=[arg], 1263 star=None, 1264 dstar=None 1265 ) 1266 ) 1267 1268 code += [ 1269 Return( 1270 instance=instance, 1271 expr=LoadTemp( 1272 instance=instance, 1273 release=1 1274 ) 1275 ) 1276 ] 1277 1278 new_subprogram = Subprogram( 1279 instance=instance, 1280 name=None, 1281 returns_value=1, 1282 params=[], 1283 star=None, 1284 dstar=None, 1285 code=code 1286 ) 1287 subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram 1288 1289 invocation.stars[subprogram.full_name()] = InvokeRef( 1290 invocation.original, 1291 instance=instance, 1292 produces_result=1, 1293 ref=new_subprogram 1294 ) 1295 1296 return invocation.stars[subprogram.full_name()] 1297 1298 def make_dstar_args(self, invocation, subprogram, dstar_args): 1299 1300 """ 1301 Make a subprogram which initialises a dictionary built from the given 1302 'dstar_args'. 1303 """ 1304 1305 if not hasattr(invocation, "dstars"): 1306 invocation.dstars = {} 1307 1308 if not invocation.dstars.has_key(subprogram.full_name()): 1309 instance = getattr(invocation, "instance", None) 1310 1311 code=[ 1312 StoreTemp( 1313 instance=instance, 1314 expr=InvokeFunction( 1315 invocation.original, 1316 instance=instance, 1317 expr=LoadAttr( 1318 instance=instance, 1319 expr=LoadRef( 1320 instance=instance, 1321 ref=self.builtins 1322 ), 1323 name="dict", 1324 nstype="module", 1325 ) 1326 ) 1327 ) 1328 ] 1329 1330 for arg, value in dstar_args: 1331 1332 # NOTE: Constant not added to table. 1333 1334 constant = Constant(name=repr(arg), value=arg) 1335 code += [ 1336 StoreTemp( 1337 instance=instance, 1338 expr=InvokeFunction( 1339 instance=instance, 1340 expr=LoadName( 1341 instance=instance, 1342 name=constant.typename 1343 ) 1344 ), 1345 index="const" 1346 ), 1347 InvokeFunction( 1348 invocation.original, 1349 instance=instance, 1350 expr=LoadAttr( 1351 instance=instance, 1352 expr=LoadTemp( 1353 instance=instance 1354 ), 1355 name="__setitem__" 1356 ), 1357 args=[ 1358 LoadTemp( 1359 instance=instance, 1360 index="const", 1361 release=1 1362 ), 1363 value 1364 ] 1365 ) 1366 ] 1367 1368 code += [ 1369 Return( 1370 instance=instance, 1371 expr=LoadTemp( 1372 instance=instance, 1373 release=1 1374 ) 1375 ) 1376 ] 1377 1378 new_subprogram = Subprogram( 1379 instance=instance, 1380 name=None, 1381 returns_value=1, 1382 params=[], 1383 star=None, 1384 dstar=None, 1385 code=code 1386 ) 1387 subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram 1388 1389 invocation.dstars[subprogram.full_name()] = InvokeRef( 1390 invocation.original, 1391 instance=instance, 1392 produces_result=1, 1393 ref=new_subprogram 1394 ) 1395 1396 return invocation.dstars[subprogram.full_name()] 1397 1398 # Namespace-related abstractions. 1399 1400 class Namespace: 1401 1402 """ 1403 A local namespace which may either relate to a genuine set of function 1404 locals or the initialisation of a structure or module. 1405 """ 1406 1407 def __init__(self): 1408 1409 """ 1410 Initialise the namespace with a mapping of local names to possible 1411 types, a list of return values and of possible returned local 1412 namespaces. The namespace also tracks the "current" types and a mapping 1413 of temporary value names to types. 1414 """ 1415 1416 self.names = {} 1417 self.returns = set() 1418 self.return_locals = set() 1419 self.raises = set() 1420 self.temp = {} 1421 self.types = set() 1422 1423 def set_types(self, types): 1424 1425 "Set the current collection of 'types'." 1426 1427 self.types = types.copy() 1428 1429 def add(self, name, types): 1430 1431 "Add to the entry with the given 'name' the specified 'types'." 1432 1433 if self.names.has_key(name): 1434 self.names[name].update(types) 1435 else: 1436 self.store(name, types) 1437 1438 def store(self, name, types): 1439 1440 "Store in (or associate with) the given 'name' the specified 'types'." 1441 1442 self.names[name] = types.copy() 1443 1444 __setitem__ = store 1445 1446 def load(self, name): 1447 1448 "Load the types associated with the given 'name'." 1449 1450 return self.names[name] 1451 1452 __getitem__ = load 1453 1454 def has_key(self, name): 1455 return self.names.has_key(name) 1456 1457 def revoke(self, name, type): 1458 1459 "Revoke from the entry for the given 'name' the specified 'type'." 1460 1461 new_types = self.names[name].copy() 1462 new_types.remove(type) 1463 self.names[name] = new_types 1464 1465 def revoke_exception_type(self, type): 1466 1467 "Revoke the given 'type' from the collection of exception types." 1468 1469 self.raises.remove(type) 1470 1471 def revoke_temp_type(self, index, type): 1472 1473 "Revoke from the temporary variable 'index' the given 'type'." 1474 1475 new_types = self.temp[index][-1].copy() 1476 new_types.remove(type) 1477 self.temp[index][-1] = new_types 1478 1479 def merge_namespace(self, namespace, everything=1): 1480 1481 """ 1482 Merge items from the given 'namespace' with this namespace. When the 1483 optional 'everything' parameter is set to a false value (unlike the 1484 default), return values and locals snapshots will not be copied to this 1485 namespace. 1486 """ 1487 1488 self.merge_items(namespace.names.items()) 1489 self.raises.update(namespace.raises) 1490 if everything: 1491 self.returns.update(namespace.returns) 1492 self.return_locals.update(namespace.return_locals) 1493 for name, values in namespace.temp.items(): 1494 if values: 1495 if not self.temp.has_key(name) or not self.temp[name]: 1496 self.temp[name] = [set()] 1497 self.temp[name][-1].update(values[-1]) 1498 1499 def merge_items(self, items): 1500 1501 "Merge the given 'items' with this namespace." 1502 1503 for name, types in items: 1504 self.merge(name, types) 1505 1506 def merge(self, name, types): 1507 1508 "Merge the entry for the given 'name' and 'types' with this namespace." 1509 1510 if not self.names.has_key(name): 1511 self.names[name] = types.copy() 1512 else: 1513 existing = self.names[name] 1514 existing.update(types) 1515 1516 def snapshot(self): 1517 1518 "Make a snapshot of the locals and remember them." 1519 1520 namespace = Namespace() 1521 namespace.merge_namespace(self) 1522 self.return_locals.add(namespace) 1523 1524 def reset(self): 1525 1526 "Reset a namespace in preparation for merging with returned locals." 1527 1528 self.names = {} 1529 1530 def __repr__(self): 1531 return repr(self.names) + " (temp) " + repr(self.temp) 1532 1533 class Importer: 1534 1535 "An import machine, searching for and loading modules." 1536 1537 def __init__(self, path=None): 1538 1539 """ 1540 Initialise the importer with the given search 'path' - a list of 1541 directories to search for Python modules. 1542 """ 1543 1544 self.path = path or [os.getcwd()] 1545 self.path.append(libdir) 1546 self.modules = {} 1547 1548 def find_in_path(self, name): 1549 1550 """ 1551 Find the given module 'name' in the search path, returning None where no 1552 such module could be found, or a 2-tuple from the 'find' method 1553 otherwise. 1554 """ 1555 1556 for d in self.path: 1557 m = self.find(d, name) 1558 if m: return m 1559 return None 1560 1561 def find(self, d, name): 1562 1563 """ 1564 In the directory 'd', find the given module 'name', where 'name' can 1565 either refer to a single file module or to a package. Return None if the 1566 'name' cannot be associated with either a file or a package directory, 1567 or a 2-tuple from '_find_package' or '_find_module' otherwise. 1568 """ 1569 1570 m = self._find_package(d, name) 1571 if m: return m 1572 m = self._find_module(d, name) 1573 if m: return m 1574 return None 1575 1576 def _find_module(self, d, name): 1577 1578 """ 1579 In the directory 'd', find the given module 'name', returning None where 1580 no suitable file exists in the directory, or a 2-tuple consisting of 1581 None (indicating that no package directory is involved) and a filename 1582 indicating the location of the module. 1583 """ 1584 1585 name_py = name + os.extsep + "py" 1586 filename = self._find_file(d, name_py) 1587 if filename: 1588 return None, filename 1589 return None 1590 1591 def _find_package(self, d, name): 1592 1593 """ 1594 In the directory 'd', find the given package 'name', returning None 1595 where no suitable package directory exists, or a 2-tuple consisting of 1596 a directory (indicating the location of the package directory itself) 1597 and a filename indicating the location of the __init__.py module which 1598 declares the package's top-level contents. 1599 """ 1600 1601 filename = self._find_file(d, name) 1602 if filename: 1603 init_py = "__init__" + os.path.extsep + "py" 1604 init_py_filename = self._find_file(filename, init_py) 1605 if init_py_filename: 1606 return filename, init_py_filename 1607 return None 1608 1609 def _find_file(self, d, filename): 1610 1611 """ 1612 Return the filename obtained when searching the directory 'd' for the 1613 given 'filename', or None if no actual file exists for the filename. 1614 """ 1615 1616 filename = os.path.join(d, filename) 1617 if os.path.exists(filename): 1618 return filename 1619 else: 1620 return None 1621 1622 def load(self, name, builtins, alias=None): 1623 1624 """ 1625 Load the module or package with the given 'name' and using the specified 1626 'builtins'. Return an Attribute object referencing the loaded module or 1627 package, or None if no such module or package exists. 1628 """ 1629 1630 if self.modules.has_key(name): 1631 return Attribute(None, self.modules[name]) 1632 1633 path = name.split(".") 1634 m = self.find_in_path(path[0]) 1635 if not m: 1636 return None # NOTE: Import error. 1637 d, filename = m 1638 1639 if self.modules.has_key(path[0]): 1640 top = module = self.modules[path[0]] 1641 else: 1642 top = module = self.modules[path[0]] = load(filename, builtins, path[0], self, no_annotate=1) 1643 annotate(module, builtins, self) 1644 1645 if len(path) > 1: 1646 path_so_far = path[:1] 1647 for p in path[1:]: 1648 path_so_far.append(p) 1649 m = self.find(d, p) 1650 if not m: 1651 return None # NOTE: Import error. 1652 d, filename = m 1653 module_name = ".".join(path_so_far) 1654 1655 if self.modules.has_key(module_name): 1656 submodule = self.modules[module_name] 1657 else: 1658 submodule = self.modules[module_name] = load(filename, builtins, module_name, self, no_annotate=1) 1659 annotate(submodule, builtins, self) 1660 1661 # Store the submodule within its parent module. 1662 1663 module.namespace[p] = [Attribute(None, submodule)] 1664 module = submodule 1665 1666 if alias: 1667 return Attribute(None, module) 1668 else: 1669 return Attribute(None, top) 1670 1671 def combine(target, additions): 1672 1673 """ 1674 Merge into the 'target' sequence the given 'additions', preventing duplicate 1675 items. 1676 """ 1677 1678 for addition in additions: 1679 if addition not in target: 1680 target.append(addition) 1681 1682 def find_attributes(structure, name): 1683 1684 """ 1685 Find for the given 'structure' all attributes for the given 'name', visiting 1686 base classes where appropriate and returning the attributes in order of 1687 descending precedence for all possible base classes. 1688 1689 The elements in the result list are 2-tuples which contain the attribute and 1690 the structure involved in accessing the attribute. 1691 """ 1692 1693 # First attempt to search the instance/class namespace. 1694 1695 try: 1696 l = structure.namespace.load(name) 1697 attributes = [] 1698 for attribute in l: 1699 attributes.append((attribute, structure)) 1700 1701 # If that does not work, attempt to investigate any class or base classes. 1702 1703 except KeyError: 1704 attributes = [] 1705 1706 # Investigate any instance's implementing class. 1707 1708 if isinstance(structure, Instance): 1709 for attr in structure.namespace.load("__class__"): 1710 cls = attr.type 1711 l = get_attributes(cls, name) 1712 combine(attributes, l) 1713 1714 # Investigate any class's base classes. 1715 1716 elif isinstance(structure, Class): 1717 1718 # If no base classes exist, return an indicator that no attribute 1719 # exists. 1720 1721 if not structure.base_refs: 1722 return [(None, structure)] 1723 1724 # Otherwise, find all possible base classes. 1725 1726 for base_refs in structure.base_refs: 1727 base_attributes = [] 1728 1729 # For each base class, find attributes either in the base 1730 # class or its own base classes. 1731 1732 for base_ref in base_refs: 1733 l = get_attributes(base_ref, name) 1734 combine(base_attributes, l) 1735 1736 combine(attributes, base_attributes) 1737 1738 return attributes 1739 1740 def get_attributes(structure, name): 1741 1742 """ 1743 Return all possible attributes for the given 'structure' having the given 1744 'name', wrapping each attribute in an Attribute object which includes 1745 context information for the attribute access. 1746 1747 The elements in the result list are 2-tuples which contain the attribute and 1748 the structure involved in accessing the attribute. 1749 """ 1750 1751 if isinstance(structure, Attribute): 1752 structure = structure.type 1753 results = [] 1754 for attribute, accessor in find_attributes(structure, name): 1755 1756 # Detect class attribute access via instances. 1757 1758 if attribute is not None and isinstance(structure, Instance) and isinstance(accessor, Class): 1759 attribute = accessor.get_attribute_for_instance(attribute, structure) 1760 1761 # Produce an attribute with the appropriate context. 1762 1763 if attribute is not None and isinstance(structure, Structure): 1764 results.append((Attribute(structure, attribute.type), accessor)) 1765 else: 1766 results.append((attribute, accessor)) 1767 1768 return results 1769 1770 def prompt(vars): 1771 try: 1772 while 1: 1773 s = raw_input("> ") 1774 print eval(s, vars) 1775 except EOFError: 1776 pass 1777 1778 # Convenience functions. 1779 1780 def load(name, builtins=None, module_name=None, importer=None, no_annotate=0): 1781 1782 """ 1783 Load the module with the given 'name' (which may be a full module path), 1784 using the optional 'builtins' to resolve built-in names, and using the 1785 optional 'importer' to provide a means of finding and loading modules. 1786 """ 1787 1788 module = simplify.simplify(name, builtins is None, module_name) 1789 fixnames.fix(module, builtins) 1790 if not no_annotate: 1791 annotate(module, builtins, importer) 1792 return module 1793 1794 def annotate(module, builtins=None, importer=None): 1795 1796 """ 1797 Annotate the given 'module', also employing the optional 'builtins' module, 1798 if specified. If the optional 'importer' is given, use that to find and load 1799 modules. 1800 """ 1801 1802 annotator = Annotator(importer) 1803 if builtins is not None: 1804 annotator.process(module, builtins) 1805 else: 1806 annotator.process(module) 1807 1808 # vim: tabstop=4 expandtab shiftwidth=4