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 4720 2010/03/24 03:14:11 jars" 
  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_inst(x):
613 if hasattr(x, '__semi_deepcopy__'): 614 return x.__semi_deepcopy__() 615 elif isinstance(x, UserDict): 616 return x.__class__(_semi_deepcopy_dict(x)) 617 elif isinstance(x, UserList): 618 return x.__class__(_semi_deepcopy_list(x)) 619 else: 620 return x
621 d[types.InstanceType] = _semi_deepcopy_inst 622
623 -def semi_deepcopy(x):
624 copier = _semi_deepcopy_dispatch.get(type(x)) 625 if copier: 626 return copier(x) 627 else: 628 return x
629 630 631
632 -class Proxy:
633 """A simple generic Proxy class, forwarding all calls to 634 subject. So, for the benefit of the python newbie, what does 635 this really mean? Well, it means that you can take an object, let's 636 call it 'objA', and wrap it in this Proxy class, with a statement 637 like this 638 639 proxyObj = Proxy(objA), 640 641 Then, if in the future, you do something like this 642 643 x = proxyObj.var1, 644 645 since Proxy does not have a 'var1' attribute (but presumably objA does), 646 the request actually is equivalent to saying 647 648 x = objA.var1 649 650 Inherit from this class to create a Proxy.""" 651
652 - def __init__(self, subject):
653 """Wrap an object as a Proxy object""" 654 self.__subject = subject
655
656 - def __getattr__(self, name):
657 """Retrieve an attribute from the wrapped object. If the named 658 attribute doesn't exist, AttributeError is raised""" 659 return getattr(self.__subject, name)
660
661 - def get(self):
662 """Retrieve the entire wrapped object""" 663 return self.__subject
664
665 - def __cmp__(self, other):
666 if issubclass(other.__class__, self.__subject.__class__): 667 return cmp(self.__subject, other) 668 return cmp(self.__dict__, other.__dict__)
669 670 # attempt to load the windows registry module: 671 can_read_reg = 0 672 try: 673 import _winreg 674 675 can_read_reg = 1 676 hkey_mod = _winreg 677 678 RegOpenKeyEx = _winreg.OpenKeyEx 679 RegEnumKey = _winreg.EnumKey 680 RegEnumValue = _winreg.EnumValue 681 RegQueryValueEx = _winreg.QueryValueEx 682 RegError = _winreg.error 683 684 except ImportError: 685 try: 686 import win32api 687 import win32con 688 can_read_reg = 1 689 hkey_mod = win32con 690 691 RegOpenKeyEx = win32api.RegOpenKeyEx 692 RegEnumKey = win32api.RegEnumKey 693 RegEnumValue = win32api.RegEnumValue 694 RegQueryValueEx = win32api.RegQueryValueEx 695 RegError = win32api.error 696 697 except ImportError:
698 - class _NoError(Exception):
699 pass
700 RegError = _NoError 701 702 if can_read_reg: 703 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT 704 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE 705 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER 706 HKEY_USERS = hkey_mod.HKEY_USERS 707
708 - def RegGetValue(root, key):
709 """This utility function returns a value in the registry 710 without having to open the key first. Only available on 711 Windows platforms with a version of Python that can read the 712 registry. Returns the same thing as 713 SCons.Util.RegQueryValueEx, except you just specify the entire 714 path to the value, and don't have to bother opening the key 715 first. So: 716 717 Instead of: 718 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, 719 r'SOFTWARE\Microsoft\Windows\CurrentVersion') 720 out = SCons.Util.RegQueryValueEx(k, 721 'ProgramFilesDir') 722 723 You can write: 724 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, 725 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir') 726 """ 727 # I would use os.path.split here, but it's not a filesystem 728 # path... 729 p = key.rfind('\\') + 1 730 keyp = key[:p-1] # -1 to omit trailing slash 731 val = key[p:] 732 k = RegOpenKeyEx(root, keyp) 733 return RegQueryValueEx(k,val)
734 else: 735 try: 736 e = WindowsError 737 except NameError: 738 # Make sure we have a definition of WindowsError so we can 739 # run platform-independent tests of Windows functionality on 740 # platforms other than Windows. (WindowsError is, in fact, an 741 # OSError subclass on Windows.)
742 - class WindowsError(OSError):
743 pass
744 import __builtin__ 745 __builtin__.WindowsError = WindowsError 746 else: 747 del e 748 749 HKEY_CLASSES_ROOT = None 750 HKEY_LOCAL_MACHINE = None 751 HKEY_CURRENT_USER = None 752 HKEY_USERS = None 753
754 - def RegGetValue(root, key):
755 raise WindowsError
756
757 - def RegOpenKeyEx(root, key):
758 raise WindowsError
759 760 if sys.platform == 'win32': 761
762 - def WhereIs(file, path=None, pathext=None, reject=[]):
763 if path is None: 764 try: 765 path = os.environ['PATH'] 766 except KeyError: 767 return None 768 if is_String(path): 769 path = string.split(path, os.pathsep) 770 if pathext is None: 771 try: 772 pathext = os.environ['PATHEXT'] 773 except KeyError: 774 pathext = '.COM;.EXE;.BAT;.CMD' 775 if is_String(pathext): 776 pathext = string.split(pathext, os.pathsep) 777 for ext in pathext: 778 if string.lower(ext) == string.lower(file[-len(ext):]): 779 pathext = [''] 780 break 781 if not is_List(reject) and not is_Tuple(reject): 782 reject = [reject] 783 for dir in path: 784 f = os.path.join(dir, file) 785 for ext in pathext: 786 fext = f + ext 787 if os.path.isfile(fext): 788 try: 789 reject.index(fext) 790 except ValueError: 791 return os.path.normpath(fext) 792 continue 793 return None
794 795 elif os.name == 'os2': 796
797 - def WhereIs(file, path=None, pathext=None, reject=[]):
798 if path is None: 799 try: 800 path = os.environ['PATH'] 801 except KeyError: 802 return None 803 if is_String(path): 804 path = string.split(path, os.pathsep) 805 if pathext is None: 806 pathext = ['.exe', '.cmd'] 807 for ext in pathext: 808 if string.lower(ext) == string.lower(file[-len(ext):]): 809 pathext = [''] 810 break 811 if not is_List(reject) and not is_Tuple(reject): 812 reject = [reject] 813 for dir in path: 814 f = os.path.join(dir, file) 815 for ext in pathext: 816 fext = f + ext 817 if os.path.isfile(fext): 818 try: 819 reject.index(fext) 820 except ValueError: 821 return os.path.normpath(fext) 822 continue 823 return None
824 825 else: 826
827 - def WhereIs(file, path=None, pathext=None, reject=[]):
828 import stat 829 if path is None: 830 try: 831 path = os.environ['PATH'] 832 except KeyError: 833 return None 834 if is_String(path): 835 path = string.split(path, os.pathsep) 836 if not is_List(reject) and not is_Tuple(reject): 837 reject = [reject] 838 for d in path: 839 f = os.path.join(d, file) 840 if os.path.isfile(f): 841 try: 842 st = os.stat(f) 843 except OSError: 844 # os.stat() raises OSError, not IOError if the file 845 # doesn't exist, so in this case we let IOError get 846 # raised so as to not mask possibly serious disk or 847 # network issues. 848 continue 849 if stat.S_IMODE(st[stat.ST_MODE]) & 0111: 850 try: 851 reject.index(f) 852 except ValueError: 853 return os.path.normpath(f) 854 continue 855 return None
856
857 -def PrependPath(oldpath, newpath, sep = os.pathsep, 858 delete_existing=1, canonicalize=None):
859 """This prepends newpath elements to the given oldpath. Will only 860 add any particular path once (leaving the first one it encounters 861 and ignoring the rest, to preserve path order), and will 862 os.path.normpath and os.path.normcase all paths to help assure 863 this. This can also handle the case where the given old path 864 variable is a list instead of a string, in which case a list will 865 be returned instead of a string. 866 867 Example: 868 Old Path: "/foo/bar:/foo" 869 New Path: "/biz/boom:/foo" 870 Result: "/biz/boom:/foo:/foo/bar" 871 872 If delete_existing is 0, then adding a path that exists will 873 not move it to the beginning; it will stay where it is in the 874 list. 875 876 If canonicalize is not None, it is applied to each element of 877 newpath before use. 878 """ 879 880 orig = oldpath 881 is_list = 1 882 paths = orig 883 if not is_List(orig) and not is_Tuple(orig): 884 paths = string.split(paths, sep) 885 is_list = 0 886 887 if is_String(newpath): 888 newpaths = string.split(newpath, sep) 889 elif not is_List(newpath) and not is_Tuple(newpath): 890 newpaths = [ newpath ] # might be a Dir 891 else: 892 newpaths = newpath 893 894 if canonicalize: 895 newpaths=map(canonicalize, newpaths) 896 897 if not delete_existing: 898 # First uniquify the old paths, making sure to 899 # preserve the first instance (in Unix/Linux, 900 # the first one wins), and remembering them in normpaths. 901 # Then insert the new paths at the head of the list 902 # if they're not already in the normpaths list. 903 result = [] 904 normpaths = [] 905 for path in paths: 906 if not path: 907 continue 908 normpath = os.path.normpath(os.path.normcase(path)) 909 if normpath not in normpaths: 910 result.append(path) 911 normpaths.append(normpath) 912 newpaths.reverse() # since we're inserting at the head 913 for path in newpaths: 914 if not path: 915 continue 916 normpath = os.path.normpath(os.path.normcase(path)) 917 if normpath not in normpaths: 918 result.insert(0, path) 919 normpaths.append(normpath) 920 paths = result 921 922 else: 923 newpaths = newpaths + paths # prepend new paths 924 925 normpaths = [] 926 paths = [] 927 # now we add them only if they are unique 928 for path in newpaths: 929 normpath = os.path.normpath(os.path.normcase(path)) 930 if path and not normpath in normpaths: 931 paths.append(path) 932 normpaths.append(normpath) 933 934 if is_list: 935 return paths 936 else: 937 return string.join(paths, sep)
938
939 -def AppendPath(oldpath, newpath, sep = os.pathsep, 940 delete_existing=1, canonicalize=None):
941 """This appends new path elements to the given old path. Will 942 only add any particular path once (leaving the last one it 943 encounters and ignoring the rest, to preserve path order), and 944 will os.path.normpath and os.path.normcase all paths to help 945 assure this. This can also handle the case where the given old 946 path variable is a list instead of a string, in which case a list 947 will be returned instead of a string. 948 949 Example: 950 Old Path: "/foo/bar:/foo" 951 New Path: "/biz/boom:/foo" 952 Result: "/foo/bar:/biz/boom:/foo" 953 954 If delete_existing is 0, then adding a path that exists 955 will not move it to the end; it will stay where it is in the list. 956 957 If canonicalize is not None, it is applied to each element of 958 newpath before use. 959 """ 960 961 orig = oldpath 962 is_list = 1 963 paths = orig 964 if not is_List(orig) and not is_Tuple(orig): 965 paths = string.split(paths, sep) 966 is_list = 0 967 968 if is_String(newpath): 969 newpaths = string.split(newpath, sep) 970 elif not is_List(newpath) and not is_Tuple(newpath): 971 newpaths = [ newpath ] # might be a Dir 972 else: 973 newpaths = newpath 974 975 if canonicalize: 976 newpaths=map(canonicalize, newpaths) 977 978 if not delete_existing: 979 # add old paths to result, then 980 # add new paths if not already present 981 # (I thought about using a dict for normpaths for speed, 982 # but it's not clear hashing the strings would be faster 983 # than linear searching these typically short lists.) 984 result = [] 985 normpaths = [] 986 for path in paths: 987 if not path: 988 continue 989 result.append(path) 990 normpaths.append(os.path.normpath(os.path.normcase(path))) 991 for path in newpaths: 992 if not path: 993 continue 994 normpath = os.path.normpath(os.path.normcase(path)) 995 if normpath not in normpaths: 996 result.append(path) 997 normpaths.append(normpath) 998 paths = result 999 else: 1000 # start w/ new paths, add old ones if not present, 1001 # then reverse. 1002 newpaths = paths + newpaths # append new paths 1003 newpaths.reverse() 1004 1005 normpaths = [] 1006 paths = [] 1007 # now we add them only if they are unique 1008 for path in newpaths: 1009 normpath = os.path.normpath(os.path.normcase(path)) 1010 if path and not normpath in normpaths: 1011 paths.append(path) 1012 normpaths.append(normpath) 1013 paths.reverse() 1014 1015 if is_list: 1016 return paths 1017 else: 1018 return string.join(paths, sep)
1019 1020 if sys.platform == 'cygwin':
1021 - def get_native_path(path):
1022 """Transforms an absolute path into a native path for the system. In 1023 Cygwin, this converts from a Cygwin path to a Windows one.""" 1024 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
1025 else:
1026 - def get_native_path(path):
1027 """Transforms an absolute path into a native path for the system. 1028 Non-Cygwin version, just leave the path alone.""" 1029 return path
1030 1031 display = DisplayEngine() 1032
1033 -def Split(arg):
1034 if is_List(arg) or is_Tuple(arg): 1035 return arg 1036 elif is_String(arg): 1037 return string.split(arg) 1038 else: 1039 return [arg]
1040
1041 -class CLVar(UserList):
1042 """A class for command-line construction variables. 1043 1044 This is a list that uses Split() to split an initial string along 1045 white-space arguments, and similarly to split any strings that get 1046 added. This allows us to Do the Right Thing with Append() and 1047 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1 1048 arg2') regardless of whether a user adds a list or a string to a 1049 command-line construction variable. 1050 """
1051 - def __init__(self, seq = []):
1052 UserList.__init__(self, Split(seq))
1053 - def __add__(self, other):
1054 return UserList.__add__(self, CLVar(other))
1055 - def __radd__(self, other):
1056 return UserList.__radd__(self, CLVar(other))
1057 - def __coerce__(self, other):
1058 return (self, CLVar(other))
1059 - def __str__(self):
1060 return string.join(self.data)
1061 1062 # A dictionary that preserves the order in which items are added. 1063 # Submitted by David Benjamin to ActiveState's Python Cookbook web site: 1064 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747 1065 # Including fixes/enhancements from the follow-on discussions.
1066 -class OrderedDict(UserDict):
1067 - def __init__(self, dict = None):
1068 self._keys = [] 1069 UserDict.__init__(self, dict)
1070
1071 - def __delitem__(self, key):
1072 UserDict.__delitem__(self, key) 1073 self._keys.remove(key)
1074
1075 - def __setitem__(self, key, item):
1076 UserDict.__setitem__(self, key, item) 1077 if key not in self._keys: self._keys.append(key)
1078
1079 - def clear(self):
1080 UserDict.clear(self) 1081 self._keys = []
1082
1083 - def copy(self):
1084 dict = OrderedDict() 1085 dict.update(self) 1086 return dict
1087
1088 - def items(self):
1089 return zip(self._keys, self.values())
1090
1091 - def keys(self):
1092 return self._keys[:]
1093
1094 - def popitem(self):
1095 try: 1096 key = self._keys[-1] 1097 except IndexError: 1098 raise KeyError('dictionary is empty') 1099 1100 val = self[key] 1101 del self[key] 1102 1103 return (key, val)
1104
1105 - def setdefault(self, key, failobj = None):
1106 UserDict.setdefault(self, key, failobj) 1107 if key not in self._keys: self._keys.append(key)
1108
1109 - def update(self, dict):
1110 for (key, val) in dict.items(): 1111 self.__setitem__(key, val)
1112
1113 - def values(self):
1114 return map(self.get, self._keys)
1115
1116 -class Selector(OrderedDict):
1117 """A callable ordered dictionary that maps file suffixes to 1118 dictionary values. We preserve the order in which items are added 1119 so that get_suffix() calls always return the first suffix added."""
1120 - def __call__(self, env, source, ext=None):
1121 if ext is None: 1122 try: 1123 ext = source[0].suffix 1124 except IndexError: 1125 ext = "" 1126 try: 1127 return self[ext] 1128 except KeyError: 1129 # Try to perform Environment substitution on the keys of 1130 # the dictionary before giving up. 1131 s_dict = {} 1132 for (k,v) in self.items(): 1133 if k is not None: 1134 s_k = env.subst(k) 1135 if s_dict.has_key(s_k): 1136 # We only raise an error when variables point 1137 # to the same suffix. If one suffix is literal 1138 # and a variable suffix contains this literal, 1139 # the literal wins and we don't raise an error. 1140 raise KeyError, (s_dict[s_k][0], k, s_k) 1141 s_dict[s_k] = (k,v) 1142 try: 1143 return s_dict[ext][1] 1144 except KeyError: 1145 try: 1146 return self[None] 1147 except KeyError: 1148 return None
1149 1150 1151 if sys.platform == 'cygwin': 1152 # On Cygwin, os.path.normcase() lies, so just report back the 1153 # fact that the underlying Windows OS is case-insensitive.
1154 - def case_sensitive_suffixes(s1, s2):
1155 return 0
1156 else:
1157 - def case_sensitive_suffixes(s1, s2):
1158 return (os.path.normcase(s1) != os.path.normcase(s2))
1159
1160 -def adjustixes(fname, pre, suf, ensure_suffix=False):
1161 if pre: 1162 path, fn = os.path.split(os.path.normpath(fname)) 1163 if fn[:len(pre)] != pre: 1164 fname = os.path.join(path, pre + fn) 1165 # Only append a suffix if the suffix we're going to add isn't already 1166 # there, and if either we've been asked to ensure the specific suffix 1167 # is present or there's no suffix on it at all. 1168 if suf and fname[-len(suf):] != suf and \ 1169 (ensure_suffix or not splitext(fname)[1]): 1170 fname = fname + suf 1171 return fname
1172 1173 1174 1175 # From Tim Peters, 1176 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 1177 # ASPN: Python Cookbook: Remove duplicates from a sequence 1178 # (Also in the printed Python Cookbook.) 1179
1180 -def unique(s):
1181 """Return a list of the elements in s, but without duplicates. 1182 1183 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], 1184 unique("abcabc") some permutation of ["a", "b", "c"], and 1185 unique(([1, 2], [2, 3], [1, 2])) some permutation of 1186 [[2, 3], [1, 2]]. 1187 1188 For best speed, all sequence elements should be hashable. Then 1189 unique() will usually work in linear time. 1190 1191 If not possible, the sequence elements should enjoy a total 1192 ordering, and if list(s).sort() doesn't raise TypeError it's 1193 assumed that they do enjoy a total ordering. Then unique() will 1194 usually work in O(N*log2(N)) time. 1195 1196 If that's not possible either, the sequence elements must support 1197 equality-testing. Then unique() will usually work in quadratic 1198 time. 1199 """ 1200 1201 n = len(s) 1202 if n == 0: 1203 return [] 1204 1205 # Try using a dict first, as that's the fastest and will usually 1206 # work. If it doesn't work, it will usually fail quickly, so it 1207 # usually doesn't cost much to *try* it. It requires that all the 1208 # sequence elements be hashable, and support equality comparison. 1209 u = {} 1210 try: 1211 for x in s: 1212 u[x] = 1 1213 except TypeError: 1214 pass # move on to the next method 1215 else: 1216 return u.keys() 1217 del u 1218 1219 # We can't hash all the elements. Second fastest is to sort, 1220 # which brings the equal elements together; then duplicates are 1221 # easy to weed out in a single pass. 1222 # NOTE: Python's list.sort() was designed to be efficient in the 1223 # presence of many duplicate elements. This isn't true of all 1224 # sort functions in all languages or libraries, so this approach 1225 # is more effective in Python than it may be elsewhere. 1226 try: 1227 t = list(s) 1228 t.sort() 1229 except TypeError: 1230 pass # move on to the next method 1231 else: 1232 assert n > 0 1233 last = t[0] 1234 lasti = i = 1 1235 while i < n: 1236 if t[i] != last: 1237 t[lasti] = last = t[i] 1238 lasti = lasti + 1 1239 i = i + 1 1240 return t[:lasti] 1241 del t 1242 1243 # Brute force is all that's left. 1244 u = [] 1245 for x in s: 1246 if x not in u: 1247 u.append(x) 1248 return u
1249 1250 1251 1252 # From Alex Martelli, 1253 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560 1254 # ASPN: Python Cookbook: Remove duplicates from a sequence 1255 # First comment, dated 2001/10/13. 1256 # (Also in the printed Python Cookbook.) 1257
1258 -def uniquer(seq, idfun=None):
1259 if idfun is None: 1260 def idfun(x): return x 1261 seen = {} 1262 result = [] 1263 for item in seq: 1264 marker = idfun(item) 1265 # in old Python versions: 1266 # if seen.has_key(marker) 1267 # but in new ones: 1268 if marker in seen: continue 1269 seen[marker] = 1 1270 result.append(item) 1271 return result
1272 1273 # A more efficient implementation of Alex's uniquer(), this avoids the 1274 # idfun() argument and function-call overhead by assuming that all 1275 # items in the sequence are hashable. 1276
1277 -def uniquer_hashables(seq):
1278 seen = {} 1279 result = [] 1280 for item in seq: 1281 #if not item in seen: 1282 if not seen.has_key(item): 1283 seen[item] = 1 1284 result.append(item) 1285 return result
1286 1287 1288 1289 # Much of the logic here was originally based on recipe 4.9 from the 1290 # Python CookBook, but we had to dumb it way down for Python 1.5.2.
1291 -class LogicalLines:
1292
1293 - def __init__(self, fileobj):
1294 self.fileobj = fileobj
1295
1296 - def readline(self):
1297 result = [] 1298 while 1: 1299 line = self.fileobj.readline() 1300 if not line: 1301 break 1302 if line[-2:] == '\\\n': 1303 result.append(line[:-2]) 1304 else: 1305 result.append(line) 1306 break 1307 return string.join(result, '')
1308
1309 - def readlines(self):
1310 result = [] 1311 while 1: 1312 line = self.readline() 1313 if not line: 1314 break 1315 result.append(line) 1316 return result
1317 1318 1319
1320 -class UniqueList(UserList):
1321 - def __init__(self, seq = []):
1322 UserList.__init__(self, seq) 1323 self.unique = True
1324 - def __make_unique(self):
1325 if not self.unique: 1326 self.data = uniquer_hashables(self.data) 1327 self.unique = True
1328 - def __lt__(self, other):
1329 self.__make_unique() 1330 return UserList.__lt__(self, other)
1331 - def __le__(self, other):
1332 self.__make_unique() 1333 return UserList.__le__(self, other)
1334 - def __eq__(self, other):
1335 self.__make_unique() 1336 return UserList.__eq__(self, other)
1337 - def __ne__(self, other):
1338 self.__make_unique() 1339 return UserList.__ne__(self, other)
1340 - def __gt__(self, other):
1341 self.__make_unique() 1342 return UserList.__gt__(self, other)
1343 - def __ge__(self, other):
1344 self.__make_unique() 1345 return UserList.__ge__(self, other)
1346 - def __cmp__(self, other):
1347 self.__make_unique() 1348 return UserList.__cmp__(self, other)
1349 - def __len__(self):
1350 self.__make_unique() 1351 return UserList.__len__(self)
1352 - def __getitem__(self, i):
1353 self.__make_unique() 1354 return UserList.__getitem__(self, i)
1355 - def __setitem__(self, i, item):
1356 UserList.__setitem__(self, i, item) 1357 self.unique = False
1358 - def __getslice__(self, i, j):
1359 self.__make_unique() 1360 return UserList.__getslice__(self, i, j)
1361 - def __setslice__(self, i, j, other):
1362 UserList.__setslice__(self, i, j, other) 1363 self.unique = False
1364 - def __add__(self, other):
1365 result = UserList.__add__(self, other) 1366 result.unique = False 1367 return result
1368 - def __radd__(self, other):
1369 result = UserList.__radd__(self, other) 1370 result.unique = False 1371 return result
1372 - def __iadd__(self, other):
1373 result = UserList.__iadd__(self, other) 1374 result.unique = False 1375 return result
1376 - def __mul__(self, other):
1377 result = UserList.__mul__(self, other) 1378 result.unique = False 1379 return result
1380 - def __rmul__(self, other):
1381 result = UserList.__rmul__(self, other) 1382 result.unique = False 1383 return result
1384 - def __imul__(self, other):
1385 result = UserList.__imul__(self, other) 1386 result.unique = False 1387 return result
1388 - def append(self, item):
1389 UserList.append(self, item) 1390 self.unique = False
1391 - def insert(self, i):
1392 UserList.insert(self, i) 1393 self.unique = False
1394 - def count(self, item):
1395 self.__make_unique() 1396 return UserList.count(self, item)
1397 - def index(self, item):
1398 self.__make_unique() 1399 return UserList.index(self, item)
1400 - def reverse(self):
1401 self.__make_unique() 1402 UserList.reverse(self)
1403 - def sort(self, *args, **kwds):
1404 self.__make_unique() 1405 #return UserList.sort(self, *args, **kwds) 1406 return apply(UserList.sort, (self,)+args, kwds)
1407 - def extend(self, other):
1408 UserList.extend(self, other) 1409 self.unique = False
1410 1411 1412
1413 -class Unbuffered:
1414 """ 1415 A proxy class that wraps a file object, flushing after every write, 1416 and delegating everything else to the wrapped object. 1417 """
1418 - def __init__(self, file):
1419 self.file = file
1420 - def write(self, arg):
1421 try: 1422 self.file.write(arg) 1423 self.file.flush() 1424 except IOError: 1425 # Stdout might be connected to a pipe that has been closed 1426 # by now. The most likely reason for the pipe being closed 1427 # is that the user has press ctrl-c. It this is the case, 1428 # then SCons is currently shutdown. We therefore ignore 1429 # IOError's here so that SCons can continue and shutdown 1430 # properly so that the .sconsign is correctly written 1431 # before SCons exits. 1432 pass
1433 - def __getattr__(self, attr):
1434 return getattr(self.file, attr)
1435
1436 -def make_path_relative(path):
1437 """ makes an absolute path name to a relative pathname. 1438 """ 1439 if os.path.isabs(path): 1440 drive_s,path = os.path.splitdrive(path) 1441 1442 import re 1443 if not drive_s: 1444 path=re.compile("/*(.*)").findall(path)[0] 1445 else: 1446 path=path[1:] 1447 1448 assert( not os.path.isabs( path ) ), path 1449 return path
1450 1451 1452 1453 # The original idea for AddMethod() and RenameFunction() come from the 1454 # following post to the ActiveState Python Cookbook: 1455 # 1456 # ASPN: Python Cookbook : Install bound methods in an instance 1457 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/223613 1458 # 1459 # That code was a little fragile, though, so the following changes 1460 # have been wrung on it: 1461 # 1462 # * Switched the installmethod() "object" and "function" arguments, 1463 # so the order reflects that the left-hand side is the thing being 1464 # "assigned to" and the right-hand side is the value being assigned. 1465 # 1466 # * Changed explicit type-checking to the "try: klass = object.__class__" 1467 # block in installmethod() below so that it still works with the 1468 # old-style classes that SCons uses. 1469 # 1470 # * Replaced the by-hand creation of methods and functions with use of 1471 # the "new" module, as alluded to in Alex Martelli's response to the 1472 # following Cookbook post: 1473 # 1474 # ASPN: Python Cookbook : Dynamically added methods to a class 1475 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 1476
1477 -def AddMethod(object, function, name = None):
1478 """ 1479 Adds either a bound method to an instance or an unbound method to 1480 a class. If name is ommited the name of the specified function 1481 is used by default. 1482 Example: 1483 a = A() 1484 def f(self, x, y): 1485 self.z = x + y 1486 AddMethod(f, A, "add") 1487 a.add(2, 4) 1488 print a.z 1489 AddMethod(lambda self, i: self.l[i], a, "listIndex") 1490 print a.listIndex(5) 1491 """ 1492 import new 1493 1494 if name is None: 1495 name = function.func_name 1496 else: 1497 function = RenameFunction(function, name) 1498 1499 try: 1500 klass = object.__class__ 1501 except AttributeError: 1502 # "object" is really a class, so it gets an unbound method. 1503 object.__dict__[name] = new.instancemethod(function, None, object) 1504 else: 1505 # "object" is really an instance, so it gets a bound method. 1506 object.__dict__[name] = new.instancemethod(function, object, klass)
1507
1508 -def RenameFunction(function, name):
1509 """ 1510 Returns a function identical to the specified function, but with 1511 the specified name. 1512 """ 1513 import new 1514 1515 # Compatibility for Python 1.5 and 2.1. Can be removed in favor of 1516 # passing function.func_defaults directly to new.function() once 1517 # we base on Python 2.2 or later. 1518 func_defaults = function.func_defaults 1519 if func_defaults is None: 1520 func_defaults = () 1521 1522 return new.function(function.func_code, 1523 function.func_globals, 1524 name, 1525 func_defaults)
1526 1527 1528 md5 = False
1529 -def MD5signature(s):
1530 return str(s)
1531
1532 -def MD5filesignature(fname, chunksize=65536):
1533 f = open(fname, "rb") 1534 result = f.read() 1535 f.close() 1536 return result
1537 1538 try: 1539 import hashlib 1540 except ImportError: 1541 pass 1542 else: 1543 if hasattr(hashlib, 'md5'): 1544 md5 = True
1545 - def MD5signature(s):
1546 m = hashlib.md5() 1547 m.update(str(s)) 1548 return m.hexdigest()
1549
1550 - def MD5filesignature(fname, chunksize=65536):
1551 m = hashlib.md5() 1552 f = open(fname, "rb") 1553 while 1: 1554 blck = f.read(chunksize) 1555 if not blck: 1556 break 1557 m.update(str(blck)) 1558 f.close() 1559 return m.hexdigest()
1560
1561 -def MD5collect(signatures):
1562 """ 1563 Collects a list of signatures into an aggregate signature. 1564 1565 signatures - a list of signatures 1566 returns - the aggregate signature 1567 """ 1568 if len(signatures) == 1: 1569 return signatures[0] 1570 else: 1571 return MD5signature(string.join(signatures, ', '))
1572 1573 1574 1575 # Wrap the intern() function so it doesn't throw exceptions if ineligible 1576 # arguments are passed. The intern() function was moved into the sys module in 1577 # Python 3. 1578 try: 1579 intern 1580 except NameError: 1581 from sys import intern 1582
1583 -def silent_intern(x):
1584 """ 1585 Perform intern() on the passed argument and return the result. 1586 If the input is ineligible (e.g. a unicode string) the original argument is 1587 returned and no exception is thrown. 1588 """ 1589 try: 1590 return intern(x) 1591 except TypeError: 1592 return x
1593 1594 1595 1596 # From Dinu C. Gherman, 1597 # Python Cookbook, second edition, recipe 6.17, p. 277. 1598 # Also: 1599 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 1600 # ASPN: Python Cookbook: Null Object Design Pattern 1601 1602 # TODO(1.5): 1603 #class Null(object):
1604 -class Null:
1605 """ Null objects always and reliably "do nothing." """
1606 - def __new__(cls, *args, **kwargs):
1607 if not '_inst' in vars(cls): 1608 #cls._inst = type.__new__(cls, *args, **kwargs) 1609 cls._inst = apply(type.__new__, (cls,) + args, kwargs) 1610 return cls._inst
1611 - def __init__(self, *args, **kwargs):
1612 pass
1613 - def __call__(self, *args, **kwargs):
1614 return self
1615 - def __repr__(self):
1616 return "Null(0x%08X)" % id(self)
1617 - def __nonzero__(self):
1618 return False
1619 - def __getattr__(self, name):
1620 return self
1621 - def __setattr__(self, name, value):
1622 return self
1623 - def __delattr__(self, name):
1624 return self
1625
1626 -class NullSeq(Null):
1627 - def __len__(self):
1628 return 0
1629 - def __iter__(self):
1630 return iter(())
1631 - def __getitem__(self, i):
1632 return self
1633 - def __delitem__(self, i):
1634 return self
1635 - def __setitem__(self, i, v):
1636 return self
1637 1638 1639 del __revision__ 1640 1641 # Local Variables: 1642 # tab-width:4 1643 # indent-tabs-mode:nil 1644 # End: 1645 # vim: set expandtab tabstop=4 shiftwidth=4: 1646