Package SCons :: Module Util
[hide private]
[frames] | no frames]

Source Code for Module SCons.Util

   1  """SCons.Util 
   2   
   3  Various utility functions go here. 
   4   
   5  """ 
   6   
   7  # 
   8  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation 
   9  # 
  10  # Permission is hereby granted, free of charge, to any person obtaining 
  11  # a copy of this software and associated documentation files (the 
  12  # "Software"), to deal in the Software without restriction, including 
  13  # without limitation the rights to use, copy, modify, merge, publish, 
  14  # distribute, sublicense, and/or sell copies of the Software, and to 
  15  # permit persons to whom the Software is furnished to do so, subject to 
  16  # the following conditions: 
  17  # 
  18  # The above copyright notice and this permission notice shall be included 
  19  # in all copies or substantial portions of the Software. 
  20  # 
  21  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
  22  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
  23  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  24  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
  25  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
  26  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
  27  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  28  # 
  29   
  30  __revision__ = "src/engine/SCons/Util.py 5110 2010/07/25 16:14:38 bdeegan" 
  31   
  32  import copy 
  33  import os 
  34  import os.path 
  35  import re 
  36  import string 
  37  import sys 
  38  import types 
  39   
  40  from UserDict import UserDict 
  41  from UserList import UserList 
  42  from UserString import UserString 
  43   
  44  # Don't "from types import ..." these because we need to get at the 
  45  # types module later to look for UnicodeType. 
  46  DictType        = types.DictType 
  47  InstanceType    = types.InstanceType 
  48  ListType        = types.ListType 
  49  StringType      = types.StringType 
  50  TupleType       = types.TupleType 
  51   
52 -def dictify(keys, values, result={}):
53 for k, v in zip(keys, values): 54 result[k] = v 55 return result
56 57 _altsep = os.altsep 58 if _altsep is None and sys.platform == 'win32': 59 # My ActivePython 2.0.1 doesn't set os.altsep! What gives? 60 _altsep = '/' 61 if _altsep:
62 - def rightmost_separator(path, sep, _altsep=_altsep):
63 rfind = string.rfind 64 return max(rfind(path, sep), rfind(path, _altsep))
65 else: 66 rightmost_separator = string.rfind 67 68 # First two from the Python Cookbook, just for completeness. 69 # (Yeah, yeah, YAGNI...)
70 -def containsAny(str, set):
71 """Check whether sequence str contains ANY of the items in set.""" 72 for c in set: 73 if c in str: return 1 74 return 0
75
76 -def containsAll(str, set):
77 """Check whether sequence str contains ALL of the items in set.""" 78 for c in set: 79 if c not in str: return 0 80 return 1
81
82 -def containsOnly(str, set):
83 """Check whether sequence str contains ONLY items in set.""" 84 for c in str: 85 if c not in set: return 0 86 return 1
87
88 -def splitext(path):
89 "Same as os.path.splitext() but faster." 90 sep = rightmost_separator(path, os.sep) 91 dot = string.rfind(path, '.') 92 # An ext is only real if it has at least one non-digit char 93 if dot > sep and not containsOnly(path[dot:], "0123456789."): 94 return path[:dot],path[dot:] 95 else: 96 return path,""
97
98 -def updrive(path):
99 """ 100 Make the drive letter (if any) upper case. 101 This is useful because Windows is inconsitent on the case 102 of the drive letter, which can cause inconsistencies when 103 calculating command signatures. 104 """ 105 drive, rest = os.path.splitdrive(path) 106 if drive: 107 path = string.upper(drive) + rest 108 return path
109
110 -class NodeList(UserList):
111 """This class is almost exactly like a regular list of Nodes 112 (actually it can hold any object), with one important difference. 113 If you try to get an attribute from this list, it will return that 114 attribute from every item in the list. For example: 115 116 >>> someList = NodeList([ ' foo ', ' bar ' ]) 117 >>> someList.strip() 118 [ 'foo', 'bar' ] 119 """
120 - def __nonzero__(self):
121 return len(self.data) != 0
122
123 - def __str__(self):
124 return string.join(map(str, self.data))
125
126 - def __iter__(self):
127 return iter(self.data)
128
129 - def __call__(self, *args, **kwargs):
130 result = map(lambda x, args=args, kwargs=kwargs: apply(x, 131 args, 132 kwargs), 133 self.data) 134 return self.__class__(result)
135
136 - def __getattr__(self, name):
137 result = map(lambda x, n=name: getattr(x, n), self.data) 138 return self.__class__(result)
139 140 141 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$') 142
143 -def get_environment_var(varstr):
144 """Given a string, first determine if it looks like a reference 145 to a single environment variable, like "$FOO" or "${FOO}". 146 If so, return that variable with no decorations ("FOO"). 147 If not, return None.""" 148 mo=_get_env_var.match(to_String(varstr)) 149 if mo: 150 var = mo.group(1) 151 if var[0] == '{': 152 return var[1:-1] 153 else: 154 return var 155 else: 156 return None
157
158 -class DisplayEngine:
159 - def __init__(self):
160 self.__call__ = self.print_it
161
162 - def print_it(self, text, append_newline=1):
163 if append_newline: text = text + '\n' 164 try: 165 sys.stdout.write(text) 166 except IOError: 167 # Stdout might be connected to a pipe that has been closed 168 # by now. The most likely reason for the pipe being closed 169 # is that the user has press ctrl-c. It this is the case, 170 # then SCons is currently shutdown. We therefore ignore 171 # IOError's here so that SCons can continue and shutdown 172 # properly so that the .sconsign is correctly written 173 # before SCons exits. 174 pass
175
176 - def dont_print(self, text, append_newline=1):
177 pass
178
179 - def set_mode(self, mode):
180 if mode: 181 self.__call__ = self.print_it 182 else: 183 self.__call__ = self.dont_print
184
185 -def render_tree(root, child_func, prune=0, margin=[0], visited={}):
186 """ 187 Render a tree of nodes into an ASCII tree view. 188 root - the root node of the tree 189 child_func - the function called to get the children of a node 190 prune - don't visit the same node twice 191 margin - the format of the left margin to use for children of root. 192 1 results in a pipe, and 0 results in no pipe. 193 visited - a dictionary of visited nodes in the current branch if not prune, 194 or in the whole tree if prune. 195 """ 196 197 rname = str(root) 198 199 children = child_func(root) 200 retval = "" 201 for pipe in margin[:-1]: 202 if pipe: 203 retval = retval + "| " 204 else: 205 retval = retval + " " 206 207 if visited.has_key(rname): 208 return retval + "+-[" + rname + "]\n" 209 210 retval = retval + "+-" + rname + "\n" 211 if not prune: 212 visited = copy.copy(visited) 213 visited[rname] = 1 214 215 for i in range(len(children)): 216 margin.append(i<len(children)-1) 217 retval = retval + render_tree(children[i], child_func, prune, margin, visited 218 ) 219 margin.pop() 220 221 return retval
222 223 IDX = lambda N: N and 1 or 0 224 276 margins = map(MMM, margin[:-1]) 277 278 children = child_func(root) 279 280 if prune and visited.has_key(rname) and children: 281 print string.join(tags + margins + ['+-[', rname, ']'], '') 282 return 283 284 print string.join(tags + margins + ['+-', rname], '') 285 286 visited[rname] = 1 287 288 if children: 289 margin.append(1) 290 idx = IDX(showtags) 291 for C in children[:-1]: 292 print_tree(C, child_func, prune, idx, margin, visited) 293 margin[-1] = 0 294 print_tree(children[-1], child_func, prune, idx, margin, visited) 295 margin.pop() 296 297 298 299 # Functions for deciding if things are like various types, mainly to 300 # handle UserDict, UserList and UserString like their underlying types. 301 # 302 # Yes, all of this manual testing breaks polymorphism, and the real 303 # Pythonic way to do all of this would be to just try it and handle the 304 # exception, but handling the exception when it's not the right type is 305 # often too slow. 306 307 try:
308 - class mystr(str):
309 pass
310 except TypeError: 311 # An older Python version without new-style classes. 312 # 313 # The actual implementations here have been selected after timings 314 # coded up in in bench/is_types.py (from the SCons source tree, 315 # see the scons-src distribution), mostly against Python 1.5.2. 316 # Key results from those timings: 317 # 318 # -- Storing the type of the object in a variable (t = type(obj)) 319 # slows down the case where it's a native type and the first 320 # comparison will match, but nicely speeds up the case where 321 # it's a different native type. Since that's going to be 322 # common, it's a good tradeoff. 323 # 324 # -- The data show that calling isinstance() on an object that's 325 # a native type (dict, list or string) is expensive enough 326 # that checking up front for whether the object is of type 327 # InstanceType is a pretty big win, even though it does slow 328 # down the case where it really *is* an object instance a 329 # little bit.
330 - def is_Dict(obj):
331 t = type(obj) 332 return t is DictType or \ 333 (t is InstanceType and isinstance(obj, UserDict))
334
335 - def is_List(obj):
336 t = type(obj) 337 return t is ListType \ 338 or (t is InstanceType and isinstance(obj, UserList))
339
340 - def is_Sequence(obj):
341 t = type(obj) 342 return t is ListType \ 343 or t is TupleType \ 344 or (t is InstanceType and isinstance(obj, UserList))
345
346 - def is_Tuple(obj):
347 t = type(obj) 348 return t is TupleType
349 350 if hasattr(types, 'UnicodeType'):
351 - def is_String(obj):
352 t = type(obj) 353 return t is StringType \ 354 or t is UnicodeType \ 355 or (t is InstanceType and isinstance(obj, UserString))
356 else:
357 - def is_String(obj):
358 t = type(obj) 359 return t is StringType \ 360 or (t is InstanceType and isinstance(obj, UserString))
361
362 - def is_Scalar(obj):
363 return is_String(obj) or not is_Sequence(obj)
364
365 - def flatten(obj, result=None):
366 """Flatten a sequence to a non-nested list. 367 368 Flatten() converts either a single scalar or a nested sequence 369 to a non-nested list. Note that flatten() considers strings 370 to be scalars instead of sequences like Python would. 371 """ 372 if is_Scalar(obj): 373 return [obj] 374 if result is None: 375 result = [] 376 for item in obj: 377 if is_Scalar(item): 378 result.append(item) 379 else: 380 flatten_sequence(item, result) 381 return result
382
383 - def flatten_sequence(sequence, result=None):
384 """Flatten a sequence to a non-nested list. 385 386 Same as flatten(), but it does not handle the single scalar 387 case. This is slightly more efficient when one knows that 388 the sequence to flatten can not be a scalar. 389 """ 390 if result is None: 391 result = [] 392 for item in sequence: 393 if is_Scalar(item): 394 result.append(item) 395 else: 396 flatten_sequence(item, result) 397 return result
398 399 # 400 # Generic convert-to-string functions that abstract away whether or 401 # not the Python we're executing has Unicode support. The wrapper 402 # to_String_for_signature() will use a for_signature() method if the 403 # specified object has one. 404 # 405 if hasattr(types, 'UnicodeType'): 406 UnicodeType = types.UnicodeType
407 - def to_String(s):
408 if isinstance(s, UserString): 409 t = type(s.data) 410 else: 411 t = type(s) 412 if t is UnicodeType: 413 return unicode(s) 414 else: 415 return str(s)
416 else: 417 to_String = str 418
419 - def to_String_for_signature(obj):
420 try: 421 f = obj.for_signature 422 except AttributeError: 423 return to_String_for_subst(obj) 424 else: 425 return f()
426
427 - def to_String_for_subst(s):
428 if is_Sequence( s ): 429 return string.join( map(to_String_for_subst, s) ) 430 431 return to_String( s )
432 433 else: 434 # A modern Python version with new-style classes, so we can just use 435 # isinstance(). 436 # 437 # We are using the following trick to speed-up these 438 # functions. Default arguments are used to take a snapshot of the 439 # the global functions and constants used by these functions. This 440 # transforms accesses to global variable into local variables 441 # accesses (i.e. LOAD_FAST instead of LOAD_GLOBAL). 442 443 DictTypes = (dict, UserDict) 444 ListTypes = (list, UserList) 445 SequenceTypes = (list, tuple, UserList) 446 447 # Empirically, Python versions with new-style classes all have 448 # unicode. 449 # 450 # Note that profiling data shows a speed-up when comparing 451 # explicitely with str and unicode instead of simply comparing 452 # with basestring. (at least on Python 2.5.1) 453 StringTypes = (str, unicode, UserString) 454 455 # Empirically, it is faster to check explicitely for str and 456 # unicode than for basestring. 457 BaseStringTypes = (str, unicode) 458
459 - def is_Dict(obj, isinstance=isinstance, DictTypes=DictTypes):
460 return isinstance(obj, DictTypes)
461
462 - def is_List(obj, isinstance=isinstance, ListTypes=ListTypes):
463 return isinstance(obj, ListTypes)
464
465 - def is_Sequence(obj, isinstance=isinstance, SequenceTypes=SequenceTypes):
466 return isinstance(obj, SequenceTypes)
467
468 - def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
469 return isinstance(obj, tuple)
470
471 - def is_String(obj, isinstance=isinstance, StringTypes=StringTypes):
472 return isinstance(obj, StringTypes)
473
474 - def is_Scalar(obj, isinstance=isinstance, StringTypes=StringTypes, SequenceTypes=SequenceTypes):
475 # Profiling shows that there is an impressive speed-up of 2x 476 # when explicitely checking for strings instead of just not 477 # sequence when the argument (i.e. obj) is already a string. 478 # But, if obj is a not string than it is twice as fast to 479 # check only for 'not sequence'. The following code therefore 480 # assumes that the obj argument is a string must of the time. 481 return isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes)
482
483 - def do_flatten(sequence, result, isinstance=isinstance, 484 StringTypes=StringTypes, SequenceTypes=SequenceTypes):
485 for item in sequence: 486 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): 487 result.append(item) 488 else: 489 do_flatten(item, result)
490
491 - def flatten(obj, isinstance=isinstance, StringTypes=StringTypes, 492 SequenceTypes=SequenceTypes, do_flatten=do_flatten):
493 """Flatten a sequence to a non-nested list. 494 495 Flatten() converts either a single scalar or a nested sequence 496 to a non-nested list. Note that flatten() considers strings 497 to be scalars instead of sequences like Python would. 498 """ 499 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes): 500 return [obj] 501 result = [] 502 for item in obj: 503 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): 504 result.append(item) 505 else: 506 do_flatten(item, result) 507 return result
508
509 - def flatten_sequence(sequence, isinstance=isinstance, StringTypes=StringTypes, 510 SequenceTypes=SequenceTypes, do_flatten=do_flatten):
511 """Flatten a sequence to a non-nested list. 512 513 Same as flatten(), but it does not handle the single scalar 514 case. This is slightly more efficient when one knows that 515 the sequence to flatten can not be a scalar. 516 """ 517 result = [] 518 for item in sequence: 519 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes): 520 result.append(item) 521 else: 522 do_flatten(item, result) 523 return result
524 525 526 # 527 # Generic convert-to-string functions that abstract away whether or 528 # not the Python we're executing has Unicode support. The wrapper 529 # to_String_for_signature() will use a for_signature() method if the 530 # specified object has one. 531 #
532 - def to_String(s, 533 isinstance=isinstance, str=str, 534 UserString=UserString, BaseStringTypes=BaseStringTypes):
535 if isinstance(s,BaseStringTypes): 536 # Early out when already a string! 537 return s 538 elif isinstance(s, UserString): 539 # s.data can only be either a unicode or a regular 540 # string. Please see the UserString initializer. 541 return s.data 542 else: 543 return str(s)
544
545 - def to_String_for_subst(s, 546 isinstance=isinstance, join=string.join, str=str, to_String=to_String, 547 BaseStringTypes=BaseStringTypes, SequenceTypes=SequenceTypes, 548 UserString=UserString):
549 550 # Note that the test cases are sorted by order of probability. 551 if isinstance(s, BaseStringTypes): 552 return s 553 elif isinstance(s, SequenceTypes): 554 l = [] 555 for e in s: 556 l.append(to_String_for_subst(e)) 557 return join( s ) 558 elif isinstance(s, UserString): 559 # s.data can only be either a unicode or a regular 560 # string. Please see the UserString initializer. 561 return s.data 562 else: 563 return str(s)
564
565 - def to_String_for_signature(obj, to_String_for_subst=to_String_for_subst, 566 AttributeError=AttributeError):
567 try: 568 f = obj.for_signature 569 except AttributeError: 570 return to_String_for_subst(obj) 571 else: 572 return f()
573 574 575 576 # The SCons "semi-deep" copy. 577 # 578 # This makes separate copies of lists (including UserList objects) 579 # dictionaries (including UserDict objects) and tuples, but just copies 580 # references to anything else it finds. 581 # 582 # A special case is any object that has a __semi_deepcopy__() method, 583 # which we invoke to create the copy, which is used by the BuilderDict 584 # class because of its extra initialization argument. 585 # 586 # The dispatch table approach used here is a direct rip-off from the 587 # normal Python copy module. 588 589 _semi_deepcopy_dispatch = d = {} 590
591 -def _semi_deepcopy_dict(x):
592 copy = {} 593 for key, val in x.items(): 594 # The regular Python copy.deepcopy() also deepcopies the key, 595 # as follows: 596 # 597 # copy[semi_deepcopy(key)] = semi_deepcopy(val) 598 # 599 # Doesn't seem like we need to, but we'll comment it just in case. 600 copy[key] = semi_deepcopy(val) 601 return copy
602 d[types.DictionaryType] = _semi_deepcopy_dict 603
604 -def _semi_deepcopy_list(x):
605 return map(semi_deepcopy, x)
606 d[types.ListType] = _semi_deepcopy_list 607
608 -def _semi_deepcopy_tuple(x):
609 return tuple(map(semi_deepcopy, x))
610 d[types.TupleType] = _semi_deepcopy_tuple 611
612 -def semi_deepcopy(x):
613 copier = _semi_deepcopy_dispatch.get(type(x)) 614 if copier: 615 return copier(x) 616 else: 617 if hasattr(x, '__semi_deepcopy__'): 618 return x.__semi_deepcopy__() 619 elif isinstance(x, UserDict): 620 return x.__class__(_semi_deepcopy_dict(x)) 621 elif isinstance(x, UserList): 622 return x.__class__(_semi_deepcopy_list(x)) 623 624 return x
625 626 627
628 -class Proxy:
629 """A simple generic Proxy class, forwarding all calls to 630 subject. So, for the benefit of the python newbie, what does 631 this really mean? Well, it means that you can take an object, let's 632 call it 'objA', and wrap it in this Proxy class, with a statement 633 like this 634 635 proxyObj = Proxy(objA), 636 637 Then, if in the future, you do something like this 638 639 x = proxyObj.var1, 640 641 since Proxy does not have a 'var1' attribute (but presumably objA does), 642 the request actually is equivalent to saying 643 644 x = objA.var1 645 646 Inherit from this class to create a Proxy.""" 647
648 - def __init__(self, subject):
649 """Wrap an object as a Proxy object""" 650 self.__subject = subject
651
652 - def __getattr__(self, name):
653 """Retrieve an attribute from the wrapped object. If the named 654 attribute doesn't exist, AttributeError is raised""" 655 return getattr(self.__subject, name)
656
657 - def get(self):
658 """Retrieve the entire wrapped object""" 659 return self.__subject
660
661 - def __cmp__(self, other):
662 if issubclass(other.__class__, self.__subject.__class__): 663 return cmp(self.__subject, other) 664 return cmp(self.__dict__, other.__dict__)
665 666 # attempt to load the windows registry module: 667 can_read_reg = 0 668 try: 669 import _winreg 670 671 can_read_reg = 1 672 hkey_mod = _winreg 673 674 RegOpenKeyEx = _winreg.OpenKeyEx 675 RegEnumKey = _winreg.EnumKey 676 RegEnumValue = _winreg.EnumValue 677 RegQueryValueEx = _winreg.QueryValueEx 678 RegError = _winreg.error 679 680 except ImportError: 681 try: 682 import win32api 683 import win32con 684 can_read_reg = 1 685 hkey_mod = win32con 686 687 RegOpenKeyEx = win32api.RegOpenKeyEx 688 RegEnumKey = win32api.RegEnumKey 689 RegEnumValue = win32api.RegEnumValue 690 RegQueryValueEx = win32api.RegQueryValueEx 691 RegError = win32api.error 692 693 except ImportError:
694 - class _NoError(Exception):
695 pass
696 RegError = _NoError 697 698 if can_read_reg: 699 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT 700 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE 701 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER 702 HKEY_USERS = hkey_mod.HKEY_USERS 703
704 - def RegGetValue(root, key):
705 """This utility function returns a value in the registry 706 without having to open the key first. Only available on 707 Windows platforms with a version of Python that can read the 708 registry. Returns the same thing as 709 SCons.Util.RegQueryValueEx, except you just specify the entire 710 path to the value, and don't have to bother opening the key 711 first. So: 712 713 Instead of: 714 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, 715 r'SOFTWARE\Microsoft\Windows\CurrentVersion') 716 out = SCons.Util.RegQueryValueEx(k, 717 'ProgramFilesDir') 718 719 You can write: 720 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, 721 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir') 722 """ 723 # I would use os.path.split here, but it's not a filesystem 724 # path... 725 p = key.rfind('\\') + 1 726 keyp = key[:p-1] # -1 to omit trailing slash 727 val = key[p:] 728 k = RegOpenKeyEx(root, keyp) 729 return RegQueryValueEx(k,val)
730 else: 731 try: 732 e = WindowsError 733 except NameError: 734 # Make sure we have a definition of WindowsError so we can 735 # run platform-independent tests of Windows functionality on 736 # platforms other than Windows. (WindowsError is, in fact, an 737 # OSError subclass on Windows.)
738 - class WindowsError(OSError):
739 pass
740 import __builtin__ 741 __builtin__.WindowsError = WindowsError 742 else: 743 del e 744 745 HKEY_CLASSES_ROOT = None 746 HKEY_LOCAL_MACHINE = None 747 HKEY_CURRENT_USER = None 748 HKEY_USERS = None 749
750 - def RegGetValue(root, key):
751 raise WindowsError
752
753 - def RegOpenKeyEx(root, key):
754 raise WindowsError
755 756 if sys.platform == 'win32': 757
758 - def WhereIs(file, path=None, pathext=None, reject=[]):
759 if path is None: 760 try: 761 path = os.environ['PATH'] 762 except KeyError: 763 return None 764 if is_String(path): 765 path = string.split(path, os.pathsep) 766 if pathext is None: 767 try: 768 pathext = os.environ['PATHEXT'] 769 except KeyError: 770 pathext = '.COM;.EXE;.BAT;.CMD' 771 if is_String(pathext): 772 pathext = string.split(pathext, os.pathsep) 773 for ext in pathext: 774 if string.lower(ext) == string.lower(file[-len(ext):]): 775 pathext = [''] 776 break 777 if not is_List(reject) and not is_Tuple(reject): 778 reject = [reject] 779 for dir in path: 780 f = os.path.join(dir, file) 781 for ext in pathext: 782 fext = f + ext 783 if os.path.isfile(fext): 784 try: 785 reject.index(fext) 786 except ValueError: 787 return os.path.normpath(fext) 788 continue 789 return None
790 791 elif os.name == 'os2': 792
793 - def WhereIs(file, path=None, pathext=None, reject=[]):
794 if path is None: 795 try: 796 path = os.environ['PATH'] 797 except KeyError: 798 return None 799 if is_String(path): 800 path = string.split(path, os.pathsep) 801 if pathext is None: 802 pathext = ['.exe', '.cmd'] 803 for ext in pathext: 804 if string.lower(ext) == string.lower(file[-len(ext):]): 805 pathext = [''] 806 break 807 if not is_List(reject) and not is_Tuple(reject): 808 reject = [reject] 809 for dir in path: 810 f = os.path.join(dir, file) 811 for ext in pathext: 812 fext = f + ext 813 if os.path.isfile(fext): 814 try: 815 reject.index(fext) 816 except ValueError: 817 return os.path.normpath(fext) 818 continue 819 return None
820 821 else: 822
823 - def WhereIs(file, path=None, pathext=None, reject=[]):
824 import stat 825 if path is None: 826 try: 827 path = os.environ['PATH'] 828 except KeyError: 829 return None 830 if is_String(path): 831 path = string.split(path, os.pathsep) 832 if not is_List(reject) and not is_Tuple(reject): 833 reject = [reject] 834 for d in path: 835 f = os.path.join(d, file) 836 if os.path.isfile(f): 837 try: 838 st = os.stat(f) 839 except OSError: 840 # os.stat() raises OSError, not IOError if the file 841 # doesn't exist, so in this case we let IOError get 842 # raised so as to not mask possibly serious disk or 843 # network issues. 844 continue 845 if stat.S_IMODE(st[stat.ST_MODE]) & 0111: 846 try: 847 reject.index(f) 848 except ValueError: 849 return os.path.normpath(f) 850 continue 851 return None
852
853 -def PrependPath(oldpath, newpath, sep = os.pathsep, 854 delete_existing=1, canonicalize=None):
855 """This prepends newpath elements to the given oldpath. Will only 856 add any particular path once (leaving the first one it encounters 857 and ignoring the rest, to preserve path order), and will 858 os.path.normpath and os.path.normcase all paths to help assure 859 this. This can also handle the case where the given old path 860 variable is a list instead of a string, in which case a list will 861 be returned instead of a string. 862 863 Example: 864 Old Path: "/foo/bar:/foo" 865 New Path: "/biz/boom:/foo" 866 Result: "/biz/boom:/foo:/foo/bar" 867 868 If delete_existing is 0, then adding a path that exists will 869 not move it to the beginning; it will stay where it is in the 870 list. 871 872 If canonicalize is not None, it is applied to each element of 873 newpath before use. 874 """ 875 876 orig = oldpath 877 is_list = 1 878 paths = orig 879 if not is_List(orig) and not is_Tuple(orig): 880 paths = string.split(paths, sep) 881 is_list = 0 882 883 if is_String(newpath): 884 newpaths = string.split(newpath, sep) 885 elif not is_List(newpath) and not is_Tuple(newpath): 886 newpaths = [ newpath ] # might be a Dir 887 else: 888 newpaths = newpath 889 890 if canonicalize: 891 newpaths=map(canonicalize, newpaths) 892 893 if not delete_existing: 894 # First uniquify the old paths, making sure to 895 # preserve the first instance (in Unix/Linux, 896 # the first one wins), and remembering them in normpaths. 897 # Then insert the new paths at the head of the list 898 # if they're not already in the normpaths list. 899 result = [] 900 normpaths = [] 901 for path in paths: 902 if not path: 903 continue 904 normpath = os.path.normpath(os.path.normcase(path)) 905 if normpath not in normpaths: 906 result.append(path) 907 normpaths.append(normpath) 908 newpaths.reverse() # since we're inserting at the head 909 for path in newpaths: 910 if not path: 911 continue 912 normpath = os.path.normpath(os.path.normcase(path)) 913 if normpath not in normpaths: 914 result.insert(0, path) 915 normpaths.append(normpath) 916 paths = result 917 918 else: 919 newpaths = newpaths + paths # prepend new paths 920 921 normpaths = [] 922 paths = [] 923 # now we add them only if they are unique 924 for path in newpaths: 925 normpath = os.path.normpath(os.path.normcase(path)) 926 if path and not normpath in normpaths: 927 paths.append(path) 928 normpaths.append(normpath) 929 930 if is_list: 931 return paths 932 else: 933 return string.join(paths, sep)
934
935 -def AppendPath(oldpath, newpath, sep = os.pathsep, 936 delete_existing=1, canonicalize=None):
937 """This appends new path elements to the given old path. Will 938 only add any particular path once (leaving the last one it 939 encounters and ignoring the rest, to preserve path order), and 940 will os.path.normpath and os.path.normcase all paths to help 941 assure this. This can also handle the case where the given old 942 path variable is a list instead of a string, in which case a list 943 will be returned instead of a string. 944 945 Example: 946 Old Path: "/foo/bar:/foo" 947 New Path: "/biz/boom:/foo" 948 Result: "/foo/bar:/biz/boom:/foo" 949 950 If delete_existing is 0, then adding a path that exists 951 will not move it to the end; it will stay where it is in the list. 952 953 If canonicalize is not None, it is applied to each element of 954 newpath before use. 955 """ 956 957 orig = oldpath 958 is_list = 1 959 paths = orig 960 if not is_List(orig) and not is_Tuple(orig): 961 paths = string.split(paths, sep) 962 is_list = 0 963 964 if is_String(newpath): 965 newpaths = string.split(newpath, sep) 966 elif not is_List(newpath) and not is_Tuple(newpath): 967 newpaths = [ newpath ] # might be a Dir 968 else: 969 newpaths = newpath 970 971 if canonicalize: 972 newpaths=map(canonicalize, newpaths) 973 974 if not delete_existing: 975 # add old paths to result, then 976 # add new paths if not already present 977 # (I thought about using a dict for normpaths for speed, 978 # but it's not clear hashing the strings would be faster 979 # than linear searching these typically short lists.) 980 result = [] 981 normpaths = [] 982 for path in paths: 983 if not path: 984 continue 985 result.append(path) 986 normpaths.append(os.path.normpath(os.path.normcase(path))) 987 for path in newpaths: 988 if not path: 989 continue 990 normpath = os.path.normpath(os.path.normcase(path)) 991 if normpath not in normpaths: 992 result.append(path) 993 normpaths.append(normpath) 994 paths = result 995 else: 996 # start w/ new paths, add old ones if not present, 997 # then reverse. 998 newpaths = paths + newpaths # append new paths 999 newpaths.reverse() 1000 1001 normpaths = [] 1002 paths = [] 1003 # now we add them only if they are unique 1004 for path in newpaths: 1005 normpath = os.path.normpath(os.path.normcase(path)) 1006 if path and not normpath in normpaths: 1007 paths.append(path) 1008 normpaths.append(normpath) 1009 paths.reverse() 1010 1011 if is_list: 1012 return paths 1013 else: 1014 return string.join(paths, sep)
1015 1016 if sys.platform == 'cygwin':
1017 - def get_native_path(path):
1018 """Transforms an absolute path into a native path for the system. In 1019 Cygwin, this converts from a Cygwin path to a Windows one.""" 1020 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
1021 else:
1022 - def get_native_path(path):
1023 """Transforms an absolute path into a native path for the system. 1024 Non-Cygwin version, just leave the path alone.""" 1025 return path
1026 1027 display = DisplayEngine() 1028
1029 -def Split(arg):
1030 if is_List(arg) or is_Tuple(arg): 1031 return arg 1032 elif is_String(arg): 1033 return string.split(arg) 1034 else: 1035 return [arg]
1036
1037 -class CLVar(UserList):
1038 """A class for command-line construction variables. 1039 1040 This is a list that uses Split() to split an initial string along 1041 white-space arguments, and similarly to split any strings that get 1042 added. This allows us to Do the Right Thing with Append() and 1043 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1 1044 arg2') regardless of whether a user adds a list or a string to a 1045 command-line construction variable. 1046 """
1047 - def __init__(self, seq = []):
1048 UserList.__init__(self, Split(seq))
1049 - def __add__(self, other):
1050 return UserList.__add__(self, CLVar(other))
1051 - def __radd__(self, other):
1052 return UserList.__radd__(self, CLVar(other))
1053 - def __coerce__(self, other):
1054 return (self, CLVar(other))
1055 - def __str__(self):
1056 return string.join(self.data)
1057 1058 # A dictionary that preserves the order in which items are added. 1059 # Submitted by David Benjamin to ActiveState's Python Cookbook web site: 1060 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747 1061 # Including fixes/enhancements from the follow-on discussions.
1062 -class OrderedDict(UserDict):
1063 - def __init__(self, dict = None):
1064 self._keys = [] 1065 UserDict.__init__(self, dict)
1066
1067 - def __delitem__(self, key):
1068 UserDict.__delitem__(self, key) 1069 self._keys.remove(key)
1070
1071 - def __setitem__(self, key, item):
1072 UserDict.__setitem__(self, key, item) 1073 if key not in self._keys: self._keys.append(key)
1074
1075 - def clear(self):
1076 UserDict.clear(self) 1077 self._keys = []
1078
1079 - def copy(self):
1080 dict = OrderedDict() 1081 dict.update(self) 1082 return dict
1083
1084 - def items(self):
1085 return zip(self._keys, self.values())
1086
1087 - def keys(self):
1088 return self._keys[:]
1089
1090 - def popitem(self):
1091 try: 1092 key = self._keys[-1] 1093 except IndexError: 1094 raise KeyError('dictionary is empty') 1095 1096 val = self[key] 1097 del self[key] 1098 1099 return (key, val)
1100
1101 - def setdefault(self, key, failobj = None):
1102 UserDict.setdefault(self, key, failobj) 1103 if key not in self._keys: self._keys.append(key)
1104
1105 - def update(self, dict):
1106 for (key, val) in dict.items(): 1107 self.__setitem__(key, val)
1108
1109 - def values(self):
1110 return map(self.get, self._keys)
1111
1112 -class Selector(OrderedDict):
1113 """A callable ordered dictionary that maps file suffixes to 1114 dictionary values. We preserve the order in which items are added 1115 so that get_suffix() calls always return the first suffix added."""
1116 - def __call__(self, env, source, ext=None):
1117 if ext is None: 1118 try: 1119 ext = source[0].suffix 1120 except IndexError: 1121 ext = "" 1122 try: 1123 return self[ext] 1124 except KeyError: 1125 # Try to perform Environment substitution on the keys of 1126 # the dictionary before giving up. 1127 s_dict = {} 1128 for (k,v) in self.items(): 1129 if k is not None: 1130 s_k = env.subst(k) 1131 if s_dict.has_key(s_k): 1132 # We only raise an error when variables point 1133 # to the same suffix. If one suffix is literal 1134 # and a variable suffix contains this literal, 1135 # the literal wins and we don't raise an error. 1136 raise KeyError, (s_dict[s_k][0], k, s_k) 1137 s_dict[s_k] = (k,v) 1138 try: 1139 return s_dict[ext][1] 1140 except KeyError: 1141 try: 1142 return self[None] 1143 except KeyError: 1144 return None
1145 1146 1147 if sys.platform == 'cygwin': 1148 # On Cygwin, os.path.normcase() lies, so just report back the 1149 # fact that the underlying Windows OS is case-insensitive.
1150 - def case_sensitive_suffixes(s1, s2):
1151 return 0
1152 else:
1153 - def case_sensitive_suffixes(s1, s2):
1154 return (os.path.normcase(s1) != os.path.normcase(s2))
1155
1156 -def adjustixes(fname, pre, suf, ensure_suffix=False):
1157 if pre: 1158 path, fn = os.path.split(os.path.normpath(fname)) 1159 if fn[:len(pre)] != pre: 1160 fname = os.path.join(path, pre + fn) 1161 # Only append a suffix if the suffix we're going to add isn't already 1162 # there, and if either we've been asked to ensure the specific suffix 1163 # is present or there's no suffix on it at all. 1164 if suf and fname[-len(suf):] != suf and \ 1165 (ensure_suffix or not splitext(fname)[1]): 1166 fname = fname + suf 1167 return fname
1168 1169 1170 1171 # From Tim Peters, 1172 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 1173 # ASPN: Python Cookbook: Remove duplicates from a sequence 1174 # (Also in the printed Python Cookbook.) 1175
1176 -def unique(s):
1177 """Return a list of the elements in s, but without duplicates. 1178 1179 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], 1180 unique("abcabc") some permutation of ["a", "b", "c"], and 1181 unique(([1, 2], [2, 3], [1, 2])) some permutation of 1182 [[2, 3], [1, 2]]. 1183 1184 For best speed, all sequence elements should be hashable. Then 1185 unique() will usually work in linear time. 1186 1187 If not possible, the sequence elements should enjoy a total 1188 ordering, and if list(s).sort() doesn't raise TypeError it's 1189 assumed that they do enjoy a total ordering. Then unique() will 1190 usually work in O(N*log2(N)) time. 1191 1192 If that's not possible either, the sequence elements must support 1193 equality-testing. Then unique() will usually work in quadratic 1194 time. 1195 """ 1196 1197 n = len(s) 1198 if n == 0: 1199 return [] 1200 1201 # Try using a dict first, as that's the fastest and will usually 1202 # work. If it doesn't work, it will usually fail quickly, so it 1203 # usually doesn't cost much to *try* it. It requires that all the 1204 # sequence elements be hashable, and support equality comparison. 1205 u = {} 1206 try: 1207 for x in s: 1208 u[x] = 1 1209 except TypeError: 1210 pass # move on to the next method 1211 else: 1212 return u.keys() 1213 del u 1214 1215 # We can't hash all the elements. Second fastest is to sort, 1216 # which brings the equal elements together; then duplicates are 1217 # easy to weed out in a single pass. 1218 # NOTE: Python's list.sort() was designed to be efficient in the 1219 # presence of many duplicate elements. This isn't true of all 1220 # sort functions in all languages or libraries, so this approach 1221 # is more effective in Python than it may be elsewhere. 1222 try: 1223 t = list(s) 1224 t.sort() 1225 except TypeError: 1226 pass # move on to the next method 1227 else: 1228 assert n > 0 1229 last = t[0] 1230 lasti = i = 1 1231 while i < n: 1232 if t[i] != last: 1233 t[lasti] = last = t[i] 1234 lasti = lasti + 1 1235 i = i + 1 1236 return t[:lasti] 1237 del t 1238 1239 # Brute force is all that's left. 1240 u = [] 1241 for x in s: 1242 if x not in u: 1243 u.append(x) 1244 return u
1245 1246 1247 1248 # From Alex Martelli, 1249 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 1250 # ASPN: Python Cookbook: Remove duplicates from a sequence 1251 # First comment, dated 2001/10/13. 1252 # (Also in the printed Python Cookbook.) 1253
1254 -def uniquer(seq, idfun=None):
1255 if idfun is None: 1256 def idfun(x): return x 1257 seen = {} 1258 result = [] 1259 for item in seq: 1260 marker = idfun(item) 1261 # in old Python versions: 1262 # if seen.has_key(marker) 1263 # but in new ones: 1264 if marker in seen: continue 1265 seen[marker] = 1 1266 result.append(item) 1267 return result
1268 1269 # A more efficient implementation of Alex's uniquer(), this avoids the 1270 # idfun() argument and function-call overhead by assuming that all 1271 # items in the sequence are hashable. 1272
1273 -def uniquer_hashables(seq):
1274 seen = {} 1275 result = [] 1276 for item in seq: 1277 #if not item in seen: 1278 if not seen.has_key(item): 1279 seen[item] = 1 1280 result.append(item) 1281 return result
1282 1283 1284 1285 # Much of the logic here was originally based on recipe 4.9 from the 1286 # Python CookBook, but we had to dumb it way down for Python 1.5.2.
1287 -class LogicalLines:
1288
1289 - def __init__(self, fileobj):
1290 self.fileobj = fileobj
1291
1292 - def readline(self):
1293 result = [] 1294 while 1: 1295 line = self.fileobj.readline() 1296 if not line: 1297 break 1298 if line[-2:] == '\\\n': 1299 result.append(line[:-2]) 1300 else: 1301 result.append(line) 1302 break 1303 return string.join(result, '')
1304
1305 - def readlines(self):
1306 result = [] 1307 while 1: 1308 line = self.readline() 1309 if not line: 1310 break 1311 result.append(line) 1312 return result
1313 1314 1315
1316 -class UniqueList(UserList):
1317 - def __init__(self, seq = []):
1318 UserList.__init__(self, seq) 1319 self.unique = True
1320 - def __make_unique(self):
1321 if not self.unique: 1322 self.data = uniquer_hashables(self.data) 1323 self.unique = True
1324 - def __lt__(self, other):
1325 self.__make_unique() 1326 return UserList.__lt__(self, other)
1327 - def __le__(self, other):
1328 self.__make_unique() 1329 return UserList.__le__(self, other)
1330 - def __eq__(self, other):
1331 self.__make_unique() 1332 return UserList.__eq__(self, other)
1333 - def __ne__(self, other):
1334 self.__make_unique() 1335 return UserList.__ne__(self, other)
1336 - def __gt__(self, other):
1337 self.__make_unique() 1338 return UserList.__gt__(self, other)
1339 - def __ge__(self, other):
1340 self.__make_unique() 1341 return UserList.__ge__(self, other)
1342 - def __cmp__(self, other):
1343 self.__make_unique() 1344 return UserList.__cmp__(self, other)
1345 - def __len__(self):
1346 self.__make_unique() 1347 return UserList.__len__(self)
1348 - def __getitem__(self, i):
1349 self.__make_unique() 1350 return UserList.__getitem__(self, i)
1351 - def __setitem__(self, i, item):
1352 UserList.__setitem__(self, i, item) 1353 self.unique = False
1354 - def __getslice__(self, i, j):
1355 self.__make_unique() 1356 return UserList.__getslice__(self, i, j)
1357 - def __setslice__(self, i, j, other):
1358 UserList.__setslice__(self, i, j, other) 1359 self.unique = False
1360 - def __add__(self, other):
1361 result = UserList.__add__(self, other) 1362 result.unique = False 1363 return result
1364 - def __radd__(self, other):
1365 result = UserList.__radd__(self, other) 1366 result.unique = False 1367 return result
1368 - def __iadd__(self, other):
1369 result = UserList.__iadd__(self, other) 1370 result.unique = False 1371 return result
1372 - def __mul__(self, other):
1373 result = UserList.__mul__(self, other) 1374 result.unique = False 1375 return result
1376 - def __rmul__(self, other):
1377 result = UserList.__rmul__(self, other) 1378 result.unique = False 1379 return result
1380 - def __imul__(self, other):
1381 result = UserList.__imul__(self, other) 1382 result.unique = False 1383 return result
1384 - def append(self, item):
1385 UserList.append(self, item) 1386 self.unique = False
1387 - def insert(self, i):
1388 UserList.insert(self, i) 1389 self.unique = False
1390 - def count(self, item):
1391 self.__make_unique() 1392 return UserList.count(self, item)
1393 - def index(self, item):
1394 self.__make_unique() 1395 return UserList.index(self, item)
1396 - def reverse(self):
1397 self.__make_unique() 1398 UserList.reverse(self)
1399 - def sort(self, *args, **kwds):
1400 self.__make_unique() 1401 #return UserList.sort(self, *args, **kwds) 1402 return apply(UserList.sort, (self,)+args, kwds)
1403 - def extend(self, other):
1404 UserList.extend(self, other) 1405 self.unique = False
1406 1407 1408
1409 -class Unbuffered:
1410 """ 1411 A proxy class that wraps a file object, flushing after every write, 1412 and delegating everything else to the wrapped object. 1413 """
1414 - def __init__(self, file):
1415 self.file = file
1416 - def write(self, arg):
1417 try: 1418 self.file.write(arg) 1419 self.file.flush() 1420 except IOError: 1421 # Stdout might be connected to a pipe that has been closed 1422 # by now. The most likely reason for the pipe being closed 1423 # is that the user has press ctrl-c. It this is the case, 1424 # then SCons is currently shutdown. We therefore ignore 1425 # IOError's here so that SCons can continue and shutdown 1426 # properly so that the .sconsign is correctly written 1427 # before SCons exits. 1428 pass
1429 - def __getattr__(self, attr):
1430 return getattr(self.file, attr)
1431
1432 -def make_path_relative(path):
1433 """ makes an absolute path name to a relative pathname. 1434 """ 1435 if os.path.isabs(path): 1436 drive_s,path = os.path.splitdrive(path) 1437 1438 import re 1439 if not drive_s: 1440 path=re.compile("/*(.*)").findall(path)[0] 1441 else: 1442 path=path[1:] 1443 1444 assert( not os.path.isabs( path ) ), path 1445 return path
1446 1447 1448 1449 # The original idea for AddMethod() and RenameFunction() come from the 1450 # following post to the ActiveState Python Cookbook: 1451 # 1452 # ASPN: Python Cookbook : Install bound methods in an instance 1453 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613 1454 # 1455 # That code was a little fragile, though, so the following changes 1456 # have been wrung on it: 1457 # 1458 # * Switched the installmethod() "object" and "function" arguments, 1459 # so the order reflects that the left-hand side is the thing being 1460 # "assigned to" and the right-hand side is the value being assigned. 1461 # 1462 # * Changed explicit type-checking to the "try: klass = object.__class__" 1463 # block in installmethod() below so that it still works with the 1464 # old-style classes that SCons uses. 1465 # 1466 # * Replaced the by-hand creation of methods and functions with use of 1467 # the "new" module, as alluded to in Alex Martelli's response to the 1468 # following Cookbook post: 1469 # 1470 # ASPN: Python Cookbook : Dynamically added methods to a class 1471 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 1472
1473 -def AddMethod(object, function, name = None):
1474 """ 1475 Adds either a bound method to an instance or an unbound method to 1476 a class. If name is ommited the name of the specified function 1477 is used by default. 1478 Example: 1479 a = A() 1480 def f(self, x, y): 1481 self.z = x + y 1482 AddMethod(f, A, "add") 1483 a.add(2, 4) 1484 print a.z 1485 AddMethod(lambda self, i: self.l[i], a, "listIndex") 1486 print a.listIndex(5) 1487 """ 1488 import new 1489 1490 if name is None: 1491 name = function.func_name 1492 else: 1493 function = RenameFunction(function, name) 1494 1495 try: 1496 klass = object.__class__ 1497 except AttributeError: 1498 # "object" is really a class, so it gets an unbound method. 1499 object.__dict__[name] = new.instancemethod(function, None, object) 1500 else: 1501 # "object" is really an instance, so it gets a bound method. 1502 object.__dict__[name] = new.instancemethod(function, object, klass)
1503
1504 -def RenameFunction(function, name):
1505 """ 1506 Returns a function identical to the specified function, but with 1507 the specified name. 1508 """ 1509 import new 1510 1511 # Compatibility for Python 1.5 and 2.1. Can be removed in favor of 1512 # passing function.func_defaults directly to new.function() once 1513 # we base on Python 2.2 or later. 1514 func_defaults = function.func_defaults 1515 if func_defaults is None: 1516 func_defaults = () 1517 1518 return new.function(function.func_code, 1519 function.func_globals, 1520 name, 1521 func_defaults)
1522 1523 1524 md5 = False
1525 -def MD5signature(s):
1526 return str(s)
1527
1528 -def MD5filesignature(fname, chunksize=65536):
1529 f = open(fname, "rb") 1530 result = f.read() 1531 f.close() 1532 return result
1533 1534 try: 1535 import hashlib 1536 except ImportError: 1537 pass 1538 else: 1539 if hasattr(hashlib, 'md5'): 1540 md5 = True
1541 - def MD5signature(s):
1542 m = hashlib.md5() 1543 m.update(str(s)) 1544 return m.hexdigest()
1545
1546 - def MD5filesignature(fname, chunksize=65536):
1547 m = hashlib.md5() 1548 f = open(fname, "rb") 1549 while 1: 1550 blck = f.read(chunksize) 1551 if not blck: 1552 break 1553 m.update(str(blck)) 1554 f.close() 1555 return m.hexdigest()
1556
1557 -def MD5collect(signatures):
1558 """ 1559 Collects a list of signatures into an aggregate signature. 1560 1561 signatures - a list of signatures 1562 returns - the aggregate signature 1563 """ 1564 if len(signatures) == 1: 1565 return signatures[0] 1566 else: 1567 return MD5signature(string.join(signatures, ', '))
1568 1569 1570 1571 # Wrap the intern() function so it doesn't throw exceptions if ineligible 1572 # arguments are passed. The intern() function was moved into the sys module in 1573 # Python 3. 1574 try: 1575 intern 1576 except NameError: 1577 from sys import intern 1578
1579 -def silent_intern(x):
1580 """ 1581 Perform intern() on the passed argument and return the result. 1582 If the input is ineligible (e.g. a unicode string) the original argument is 1583 returned and no exception is thrown. 1584 """ 1585 try: 1586 return intern(x) 1587 except TypeError: 1588 return x
1589 1590 1591 1592 # From Dinu C. Gherman, 1593 # Python Cookbook, second edition, recipe 6.17, p. 277. 1594 # Also: 1595 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 1596 # ASPN: Python Cookbook: Null Object Design Pattern 1597 1598 # TODO(1.5): 1599 #class Null(object):
1600 -class Null:
1601 """ Null objects always and reliably "do nothing." """
1602 - def __new__(cls, *args, **kwargs):
1603 if not '_inst' in vars(cls): 1604 #cls._inst = type.__new__(cls, *args, **kwargs) 1605 cls._inst = apply(type.__new__, (cls,) + args, kwargs) 1606 return cls._inst
1607 - def __init__(self, *args, **kwargs):
1608 pass
1609 - def __call__(self, *args, **kwargs):
1610 return self
1611 - def __repr__(self):
1612 return "Null(0x%08X)" % id(self)
1613 - def __nonzero__(self):
1614 return False
1615 - def __getattr__(self, name):
1616 return self
1617 - def __setattr__(self, name, value):
1618 return self
1619 - def __delattr__(self, name):
1620 return self
1621
1622 -class NullSeq(Null):
1623 - def __len__(self):
1624 return 0
1625 - def __iter__(self):
1626 return iter(())
1627 - def __getitem__(self, i):
1628 return self
1629 - def __delitem__(self, i):
1630 return self
1631 - def __setitem__(self, i, v):
1632 return self
1633 1634 1635 del __revision__ 1636 1637 # Local Variables: 1638 # tab-width:4 1639 # indent-tabs-mode:nil 1640 # End: 1641 # vim: set expandtab tabstop=4 shiftwidth=4: 1642