1 #!/usr/bin/env python 2 3 """ 4 Inspect source files, obtaining details of classes and attributes. 5 6 Copyright (C) 2007, 2008 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 21 -------- 22 23 The central classes in this module are the following: 24 25 * Class 26 * Function 27 * Module 28 * InspectedModule (derived from Module) 29 30 All of the above support the Naming interface either explicitly or through 31 general conformance, meaning that all can be asked to provide their 'full_name' 32 using the method of that name. 33 34 Additionally, all of the above also support a dictionary interface in order to 35 access names within their defined scopes. Specific methods also exist in order 36 to distinguish between certain kinds of attributes: 37 38 * Class: (class|all_class|instance|all)_attributes 39 * Function: parameters, locals, all_locals 40 * Module: module_attributes 41 42 These specific methods are useful in certain situations. 43 44 The above classes also provide a 'node' attribute, indicating the AST node where 45 each such object is defined. 46 """ 47 48 import compiler.ast 49 from compiler.visitor import ASTVisitor 50 try: 51 set 52 except NameError: 53 from sets import Set as set 54 55 class InspectError(Exception): 56 57 "An inspection error." 58 59 pass 60 61 class AtLeast: 62 63 "A special representation for numbers of a given value or greater." 64 65 def __init__(self, count): 66 self.count = count 67 68 def __eq__(self, other): 69 return 0 70 71 __lt__ = __le__ = __eq__ 72 73 def __ne__(self, other): 74 return 1 75 76 def __gt__(self, other): 77 if isinstance(other, AtLeast): 78 return 0 79 else: 80 return self.count > other 81 82 def __ge__(self, other): 83 if isinstance(other, AtLeast): 84 return 0 85 else: 86 return self.count >= other 87 88 def __iadd__(self, other): 89 if isinstance(other, AtLeast): 90 self.count += other.count 91 else: 92 self.count += other 93 return self 94 95 def __radd__(self, other): 96 if isinstance(other, AtLeast): 97 return AtLeast(self.count + other.count) 98 else: 99 return AtLeast(self.count + other) 100 101 def __repr__(self): 102 return "AtLeast(%r)" % self.count 103 104 # Mix-ins and abstract classes. 105 106 class NamespaceDict: 107 108 "A mix-in providing dictionary methods." 109 110 def __init__(self, global_namespace=None): 111 self.namespace = {} 112 self.globals = set() 113 self.global_namespace = global_namespace 114 self.attr_position = 0 115 116 def __getitem__(self, name): 117 return self.namespace[name] 118 119 def get(self, name, default=None): 120 return self.namespace.get(name, default) 121 122 def __setitem__(self, name, value): 123 124 # Use a special method to access the namespace. 125 126 if name not in self.globals: 127 self.set(name, value) 128 else: 129 self.global_namespace.set(name, value, 0) 130 131 def set(self, name, value, single_assignment=1): 132 attr = self._set(name, value) 133 134 # NOTE: Insist on assignments with known values. 135 136 if value is not None: 137 attr.update(value, single_assignment) 138 139 def set_module(self, name, value): 140 attr = self._set(name, value) 141 if attr.assignments is None: 142 attr.assignments = 1 143 attr.assignment_values.add(value) 144 145 def _set(self, name, value): 146 if not self.namespace.has_key(name): 147 self.namespace[name] = Attr(self.attr_position, self, name, value) 148 self.attr_position += 1 149 return self.namespace[name] 150 151 def __delitem__(self, name): 152 del self.namespace[name] 153 154 def has_key(self, name): 155 return self.namespace.has_key(name) 156 157 def keys(self): 158 return self.namespace.keys() 159 160 def values(self): 161 return self.namespace.values() 162 163 def items(self): 164 return self.namespace.items() 165 166 def make_global(self, name): 167 if not self.namespace.has_key(name): 168 self.globals.add(name) 169 else: 170 raise InspectError, "Name %r is global and local in %r" % (name, self) 171 172 def get_assignments(self, name): 173 if self.assignments.has_key(name): 174 return max(self.assignments[name], len(self.assignment_values[name])) 175 else: 176 return None 177 178 class Naming: 179 180 "A mix-in providing naming conveniences." 181 182 def full_name(self): 183 if self.name is not None: 184 return self.parent_name + "." + self.name 185 else: 186 return self.parent_name 187 188 # Program data structures. 189 190 class Attr: 191 192 "An attribute entry." 193 194 def __init__(self, position, parent, name, value=None, assignments=None): 195 self.position = position 196 self.parent = parent 197 self.name = name 198 self.value = value 199 200 # Number of assignments per name. 201 202 self.assignments = assignments 203 self.assignment_values = set() 204 205 def update(self, value, single_assignment): 206 if self.assignments is None: 207 if single_assignment: 208 self.assignments = 1 209 else: 210 self.assignments = AtLeast(1) 211 else: 212 if single_assignment: 213 self.assignments += 1 214 else: 215 self.assignments += AtLeast(1) 216 self.assignment_values.add(value) 217 218 def __repr__(self): 219 return "Attr(%r, %r, %r, %r, %r)" % (self.position, self.parent, self.name, self.value, self.assignments) 220 221 class Const: 222 223 "A constant object." 224 225 def __init__(self, value): 226 self.value = value 227 228 # Image generation details. 229 230 self.location = None 231 232 def __repr__(self): 233 return "Const(%r, location=%r)" % (self.value, self.location) 234 235 def __eq__(self, other): 236 return self.value == other.value 237 238 def __hash__(self): 239 return hash(self.value) 240 241 class Class(NamespaceDict, Naming): 242 243 "An inspected class." 244 245 def __init__(self, name, parent_name, global_namespace=None, node=None): 246 NamespaceDict.__init__(self, global_namespace) 247 self.name = name 248 self.parent_name = parent_name 249 self.node = node 250 251 self.bases = [] 252 self.instattr = set() # instance attributes 253 254 self.all_instattr = None # cache for instance_attributes 255 self.all_instattr_names = None # from all_instattr 256 self.all_classattr = None # cache for all_class_attributes 257 self.all_classattr_names = None # from all_classattr 258 self.allattr = None # cache for all_attributes 259 self.allattr_names = None # from allattr 260 261 # Image generation details. 262 263 self.location = None 264 self.code_location = None 265 266 def __repr__(self): 267 return "Class(%r, %r, location=%r)" % (self.name, self.parent_name, self.location) 268 269 def add_base(self, base): 270 self.bases.append(base) 271 272 def add_instance_attribute(self, name): 273 self.instattr.add(name) 274 275 "Return the attribute names provided by this class only." 276 277 class_attribute_names = NamespaceDict.keys 278 279 def class_attributes(self): 280 281 "Return class attributes provided by this class only." 282 283 return self 284 285 def all_class_attribute_names(self): 286 287 "Return the attribute names provided by classes in this hierarchy." 288 289 if self.all_classattr_names is None: 290 self.all_class_attributes() 291 return self.all_classattr_names 292 293 def all_class_attributes(self): 294 295 "Return all class attributes, indicating the class which provides them." 296 297 if self.all_classattr is None: 298 self.all_classattr = {} 299 300 reversed_bases = self.bases[:] 301 reversed_bases.reverse() 302 for cls in reversed_bases: 303 self.all_classattr.update(cls.all_class_attributes()) 304 305 # Record attributes provided by this class, along with their 306 # positions. 307 308 self.all_classattr.update(self.class_attributes()) 309 310 return self.all_classattr 311 312 def instance_attribute_names(self): 313 314 "Return the instance attribute names provided by the class." 315 316 if self.all_instattr_names is None: 317 self.instance_attributes() 318 return self.all_instattr_names 319 320 def instance_attributes(self): 321 322 "Return instance-only attributes for instances of this class." 323 324 if self.all_instattr is None: 325 self.all_instattr = {} 326 instattr = set() 327 328 reversed_bases = self.bases[:] 329 reversed_bases.reverse() 330 for cls in reversed_bases: 331 instattr.update(cls.instance_attributes().keys()) 332 333 # Record instance attributes provided by this class and its bases, 334 # along with their positions. 335 336 instattr.update(self.instattr) 337 338 for i, name in enumerate(instattr): 339 self.all_instattr[name] = Attr(i, None, name) 340 341 self.all_instattr_names = self.all_instattr.keys() 342 343 return self.all_instattr 344 345 def all_attribute_names(self): 346 347 """ 348 Return the names of all attributes provided by instances of this class. 349 """ 350 351 self.allattr_names = self.allattr_names or self.all_attributes().keys() 352 return self.allattr_names 353 354 def all_attributes(self): 355 356 """ 357 Return all attributes for an instance, indicating either the class which 358 provides them or that the instance itself provides them. 359 """ 360 361 if self.allattr is None: 362 self.allattr = {} 363 self.allattr.update(self.all_class_attributes()) 364 for i, name in enumerate(self.instance_attribute_names()): 365 if self.allattr.has_key(name): 366 print "Instance attribute %r in %r overrides class attribute." % (name, self) 367 self.allattr[name] = Attr(i, None, name) 368 return self.allattr 369 370 class Function(NamespaceDict, Naming): 371 372 "An inspected function." 373 374 def __init__(self, name, parent_name, argnames, has_star, has_dstar, global_namespace=None, node=None): 375 NamespaceDict.__init__(self, global_namespace) 376 self.name = name 377 self.parent_name = parent_name 378 self.argnames = argnames 379 self.has_star = has_star 380 self.has_dstar = has_dstar 381 self.node = node 382 383 # Caches. 384 385 self.localnames = None # cache for locals 386 387 # Add parameters to the namespace. 388 389 self._add_parameters(argnames) 390 391 # Image generation details. 392 393 self.location = None 394 self.code_location = None 395 396 def _add_parameters(self, argnames): 397 for name in argnames: 398 if isinstance(name, tuple): 399 self._add_parameters(name) 400 else: 401 self[name] = None 402 403 def __repr__(self): 404 return "Function(%r, %r, %r, %r, %r, location=%r)" % ( 405 self.name, self.parent_name, self.argnames, self.has_star, self.has_dstar, self.location 406 ) 407 408 def make_global(self, name): 409 if name not in self.argnames and not self.has_key(name): 410 self.globals.add(name) 411 else: 412 raise InspectError, "Name %r is global and local in %r" % (name, self) 413 414 def parameters(self): 415 416 """ 417 Return a dictionary mapping parameter names to their position in the 418 parameter list. 419 """ 420 421 parameters = {} 422 for i, name in enumerate(self.argnames): 423 parameters[name] = i 424 return parameters 425 426 def all_locals(self): 427 428 "Return a dictionary mapping names to local and parameter details." 429 430 return self 431 432 def locals(self): 433 434 "Return a dictionary mapping names to local details." 435 436 if self.localnames is None: 437 self.localnames = {} 438 self.localnames.update(self.all_locals()) 439 for name in self.argnames: 440 del self.localnames[name] 441 return self.localnames 442 443 class UnresolvedName(NamespaceDict, Naming): 444 445 "A module, class or function which was mentioned but could not be imported." 446 447 def __init__(self, name, parent_name, global_namespace=None): 448 NamespaceDict.__init__(self, global_namespace) 449 self.name = name 450 self.parent_name = parent_name 451 452 def all_class_attributes(self): 453 return {} 454 455 def instance_attributes(self): 456 return {} 457 458 def __repr__(self): 459 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 460 461 class Module(NamespaceDict): 462 463 "An inspected module's core details." 464 465 def __init__(self, name): 466 NamespaceDict.__init__(self, self) 467 self.name = name 468 469 # Complete lists of classes and functions. 470 471 self.all_objects = set() 472 473 # Constant records. 474 475 self.constant_values = {} 476 self.constant_list = None # cache for constants 477 478 # Image generation details. 479 480 self.location = None 481 self.code_location = None 482 483 # Original location details. 484 485 self.node = None 486 487 def full_name(self): 488 return self.name 489 490 def __repr__(self): 491 return "Module(%r, location=%r)" % (self.name, self.location) 492 493 # Attribute methods. 494 495 "Return the module attribute names provided by the module." 496 497 module_attribute_names = NamespaceDict.keys 498 499 def module_attributes(self): 500 501 "Return a dictionary mapping names to module attributes." 502 503 return self 504 505 def constants(self): 506 507 "Return a list of constants." 508 509 if self.constant_list is None: 510 self.constant_list = list(self.constant_values.values()) 511 512 return self.constant_list 513 514 # Program visitors. 515 516 class InspectedModule(ASTVisitor, Module): 517 518 """ 519 An inspected module, providing core details via the Module superclass, but 520 capable of being used as an AST visitor. 521 """ 522 523 def __init__(self, name, importer=None): 524 ASTVisitor.__init__(self) 525 Module.__init__(self, name) 526 self.visitor = self 527 528 self.importer = importer 529 self.loaded = 0 530 531 # Current expression state. 532 533 self.expr = None 534 535 # Namespace state. 536 537 self.in_init = 0 # Find instance attributes in __init__ methods. 538 self.in_loop = 0 # Note loop "membership", affecting assignments. 539 self.namespaces = [] 540 self.module = None 541 542 def parse(self, filename): 543 544 "Parse the file having the given 'filename'." 545 546 module = compiler.parseFile(filename) 547 self.process(module) 548 549 def process(self, module): 550 551 "Process the given 'module'." 552 553 self.node = self.module = module 554 processed = self.dispatch(module) 555 if self.has_key("__all__"): 556 all = self["__all__"] 557 if isinstance(all, compiler.ast.List): 558 for n in all.nodes: 559 self[n.value] = self.importer.add_module(self.name + "." + n.value) 560 return processed 561 562 def vacuum(self): 563 564 "Vacuum the module namespace, removing unloaded module references." 565 566 for name, value in self.items(): 567 if isinstance(value, Module) and not value.loaded: 568 del self[name] 569 570 # Complain about globals not initialised at the module level. 571 572 if isinstance(value, Global): 573 print "Warning: global %r in module %r not initialised at the module level." % (name, self.name) 574 575 # Namespace methods. 576 577 def store(self, name, obj): 578 579 "Record attribute or local 'name', storing 'obj'." 580 581 if not self.namespaces: 582 self.set(name, obj, not self.in_loop) 583 else: 584 self.namespaces[-1].set(name, obj, not self.in_loop) 585 586 # Record all non-local objects. 587 588 if not (self.namespaces and isinstance(self.namespaces[-1], Function)): 589 self.all_objects.add(obj) 590 591 def store_instance_attr(self, name): 592 593 "Record instance attribute 'name' in the current class." 594 595 if self.in_init: 596 597 # Current namespace is the function. 598 # Previous namespace is the class. 599 600 self.namespaces[-2].add_instance_attribute(name) 601 602 def get_parent(self): 603 return (self.namespaces[-1:] or [self])[0] 604 605 # Visitor methods. 606 607 def default(self, node, *args): 608 raise InspectError, node.__class__ 609 610 def dispatch(self, node, *args): 611 return ASTVisitor.dispatch(self, node, *args) 612 613 def NOP(self, node): 614 for n in node.getChildNodes(): 615 self.dispatch(n) 616 return None 617 618 visitAdd = NOP 619 620 visitAnd = NOP 621 622 visitAssert = NOP 623 624 def visitAssign(self, node): 625 self.expr = self.dispatch(node.expr) 626 for n in node.nodes: 627 self.dispatch(n) 628 return None 629 630 def visitAssAttr(self, node): 631 expr = self.dispatch(node.expr) 632 if isinstance(expr, Attr) and expr.name == "self": 633 self.store_instance_attr(node.attrname) 634 return None 635 636 def visitAssList(self, node): 637 for n in node.nodes: 638 self.dispatch(n) 639 return None 640 641 def visitAssName(self, node): 642 if isinstance(self.expr, Attr): 643 self.store(node.name, self.expr.value) 644 else: 645 self.store(node.name, self.expr) 646 return None 647 648 visitAssTuple = visitAssList 649 650 visitAugAssign = NOP 651 652 visitBackquote = NOP 653 654 visitBitand = NOP 655 656 visitBitor = NOP 657 658 visitBitxor = NOP 659 660 visitBreak = NOP 661 662 visitCallFunc = NOP 663 664 def visitClass(self, node): 665 if self.namespaces: 666 print "Class %r in %r is not global: ignored." % (node.name, self) 667 else: 668 cls = Class(node.name, self.get_parent().full_name(), self, node) 669 for base in node.bases: 670 expr = self.dispatch(base) 671 if isinstance(expr, Attr): 672 if expr.assignments != 1: 673 print "Base class %r for class %r in %r may not be constant." % (base, cls, self) 674 else: 675 cls.add_base(expr.value) 676 else: # if expr is None: 677 raise InspectError, "Base class %r for class %r in %r is not found: it may be hidden in some way." % (base, cls, self) 678 679 # Make a back reference from the node for code generation. 680 681 node.cls = cls 682 683 # Make an entry for the class. 684 685 self.store(node.name, cls) 686 687 self.namespaces.append(cls) 688 self.dispatch(node.code) 689 self.namespaces.pop() 690 691 return None 692 693 visitCompare = NOP 694 695 def visitConst(self, node): 696 const = Const(node.value) 697 self.constant_values[node.value] = const 698 return const 699 700 visitContinue = NOP 701 702 visitDecorators = NOP 703 704 visitDict = NOP 705 706 visitDiscard = NOP 707 708 visitDiv = NOP 709 710 visitEllipsis = NOP 711 712 visitExec = NOP 713 714 visitExpression = NOP 715 716 visitFloorDiv = NOP 717 718 def visitFor(self, node): 719 self.in_loop = 1 720 self.NOP(node) 721 self.in_loop = 0 722 723 def visitFrom(self, node): 724 if self.importer is None: 725 raise InspectError, "Please use the micropython.Importer class for code which uses the 'from' statement." 726 727 module = self.importer.load(node.modname, 1) 728 729 #if module is None: 730 # print "Warning:", node.modname, "not imported." 731 732 for name, alias in node.names: 733 if name != "*": 734 if module is not None and module.namespace.has_key(name): 735 attr = module[name] 736 self.store(alias or name, attr.value) 737 if isinstance(attr, Module) and not attr.loaded: 738 self.importer.load(attr.name) 739 740 # Support the import of names from missing modules. 741 742 else: 743 self.store(alias or name, UnresolvedName(name, node.modname, self)) 744 else: 745 if module is not None: 746 for n in module.namespace.keys(): 747 attr = module[n] 748 self.store(n, attr.value) 749 if isinstance(attr, Module) and not attr.loaded: 750 self.importer.load(attr.name) 751 752 return None 753 754 def visitFunction(self, node): 755 function = Function( 756 node.name, 757 self.get_parent().full_name(), 758 node.argnames, 759 (node.flags & 4 != 0), 760 (node.flags & 8 != 0), 761 self, 762 node 763 ) 764 765 # Make a back reference from the node for code generation. 766 767 node.function = function 768 769 self.namespaces.append(function) 770 771 # Current namespace is the function. 772 # Previous namespace is the class. 773 774 if node.name == "__init__" and isinstance(self.namespaces[-2], Class): 775 self.in_init = 1 776 777 self.dispatch(node.code) 778 self.in_init = 0 779 self.namespaces.pop() 780 781 self.store(node.name, function) 782 return None 783 784 visitGenExpr = NOP 785 786 visitGenExprFor = NOP 787 788 visitGenExprIf = NOP 789 790 visitGenExprInner = NOP 791 792 def visitGetattr(self, node): 793 expr = self.dispatch(node.expr) 794 if isinstance(expr, Attr): 795 value = expr.value 796 if isinstance(value, Module): 797 return value.namespace.get(node.attrname) 798 elif isinstance(value, UnresolvedName): 799 return UnresolvedName(node.attrname, value.full_name(), self) 800 return builtins.get(node.attrname) 801 802 def visitGlobal(self, node): 803 if self.namespaces: 804 for name in node.names: 805 self.namespaces[-1].make_global(name) 806 if not self.has_key(name): 807 self[name] = Global() 808 809 def visitIf(self, node): 810 for test, body in node.tests: 811 self.dispatch(body) 812 if node.else_ is not None: 813 self.dispatch(node.else_) 814 return None 815 816 visitIfExp = NOP 817 818 def visitImport(self, node): 819 if self.importer is None: 820 raise InspectError, "Please use the micropython.Importer class for code which uses the 'import' statement." 821 822 for name, alias in node.names: 823 if alias is not None: 824 self.store(alias, self.importer.load(name, 1) or UnresolvedName(None, name, self)) 825 else: 826 self.store(name.split(".")[0], self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self)) 827 828 return None 829 830 visitInvert = NOP 831 832 visitKeyword = NOP 833 834 visitLambda = NOP 835 836 visitLeftShift = NOP 837 838 visitList = NOP 839 840 visitListComp = NOP 841 842 visitListCompFor = NOP 843 844 visitListCompIf = NOP 845 846 visitMod = NOP 847 848 def visitModule(self, node): 849 return self.dispatch(node.node) 850 851 visitMul = NOP 852 853 def visitName(self, node): 854 name = node.name 855 if self.namespaces and self.namespaces[-1].has_key(name): 856 return self.namespaces[-1][name] 857 elif self.has_key(name): 858 return self[name] 859 elif builtins.has_key(name): 860 return builtins[name] 861 else: 862 return None 863 864 visitNot = NOP 865 866 visitOr = NOP 867 868 visitPass = NOP 869 870 visitPower = NOP 871 872 visitPrint = NOP 873 874 visitPrintnl = NOP 875 876 visitRaise = NOP 877 878 visitReturn = NOP 879 880 visitRightShift = NOP 881 882 visitSlice = NOP 883 884 visitSliceobj = NOP 885 886 def visitStmt(self, node): 887 for n in node.nodes: 888 self.dispatch(n) 889 return None 890 891 visitSub = NOP 892 893 visitSubscript = NOP 894 895 def visitTryExcept(self, node): 896 self.dispatch(node.body) 897 for name, var, n in node.handlers: 898 self.dispatch(n) 899 if node.else_ is not None: 900 self.dispatch(node.else_) 901 return None 902 903 visitTryFinally = NOP 904 905 visitTuple = NOP 906 907 visitUnaryAdd = NOP 908 909 visitUnarySub = NOP 910 911 def visitWhile(self, node): 912 self.in_loop = 1 913 self.NOP(node) 914 self.in_loop = 0 915 916 visitWith = NOP 917 918 visitYield = NOP 919 920 class Global: 921 922 """ 923 A reference to an object assigned to a global from outside the module 924 top-level. 925 """ 926 927 pass 928 929 # Built-in types initialisation. 930 931 class Builtins(Module): 932 933 "The special built-in types module." 934 935 def __init__(self): 936 Module.__init__(self, "__builtins__") 937 938 for key in ['ArithmeticError', 'AssertionError', 'AttributeError', 939 'BaseException', 'DeprecationWarning', 'EOFError', 'Ellipsis', 940 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 941 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 942 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 943 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 944 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 945 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 946 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 947 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 948 'TabError', 'True', 'TypeError', 'UnboundLocalError', 949 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 950 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 951 'ValueError', 'Warning', 'ZeroDivisionError', 952 'basestring', 'bool', 'buffer', 'complex', 'dict', 'file', 'float', 953 'frozenset', 'int', 'list', 'long', 'object', 'set', 'slice', 'str', 954 'tuple', 'type', 'unicode', 'xrange']: 955 self[key] = Class(key, self.full_name(), self) 956 957 # NOTE: Incomplete: some functions have more than one parameter. 958 959 for key in ['__import__', 'abs', 'all', 'any', 'callable', 'chr', 960 'classmethod', 'cmp', 'compile', 'delattr', 'dir', 'divmod', 961 'enumerate', 'eval', 'execfile', 'filter', 'getattr', 'globals', 962 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'isinstance', 963 'issubclass', 'iter', 'len', 'locals', 'map', 'max', 'min', 'oct', 964 'open', 'ord', 'pow', 'property', 'range', 'raw_input', 'reduce', 965 'reload', 'repr', 'reversed', 'round', 'setattr', 'sorted', 966 'staticmethod', 'sum', 'super', 'unichr', 'vars', 'zip']: 967 self[key] = Function(key, self.full_name(), ['arg'], 0, 0, self) 968 969 builtins = Builtins() 970 971 # vim: tabstop=4 expandtab shiftwidth=4