1 """SCons.Util
2
3 Various utility functions go here.
4
5 """
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 __revision__ = "src/engine/SCons/Util.py 2725 2008/03/31 12:52:02 knight"
31
32 import SCons.compat
33
34 import copy
35 import os
36 import os.path
37 import re
38 import string
39 import sys
40 import types
41
42 from UserDict import UserDict
43 from UserList import UserList
44 from UserString import UserString
45
46
47
48 DictType = types.DictType
49 InstanceType = types.InstanceType
50 ListType = types.ListType
51 StringType = types.StringType
52 TupleType = types.TupleType
53
54 -def dictify(keys, values, result={}):
58
59 _altsep = os.altsep
60 if _altsep is None and sys.platform == 'win32':
61
62 _altsep = '/'
63 if _altsep:
67 else:
68 rightmost_separator = string.rfind
69
70
71
73 """Check whether sequence str contains ANY of the items in set."""
74 for c in set:
75 if c in str: return 1
76 return 0
77
79 """Check whether sequence str contains ALL of the items in set."""
80 for c in set:
81 if c not in str: return 0
82 return 1
83
85 """Check whether sequence str contains ONLY items in set."""
86 for c in str:
87 if c not in set: return 0
88 return 1
89
91 "Same as os.path.splitext() but faster."
92 sep = rightmost_separator(path, os.sep)
93 dot = string.rfind(path, '.')
94
95 if dot > sep and not containsOnly(path[dot:], "0123456789."):
96 return path[:dot],path[dot:]
97 else:
98 return path,""
99
101 """
102 Make the drive letter (if any) upper case.
103 This is useful because Windows is inconsitent on the case
104 of the drive letter, which can cause inconsistencies when
105 calculating command signatures.
106 """
107 drive, rest = os.path.splitdrive(path)
108 if drive:
109 path = string.upper(drive) + rest
110 return path
111
112
113
114
115
116
117
118 if hasattr(types, 'UnicodeType'):
119 UnicodeType = types.UnicodeType
121 if isinstance(s, UserString):
122 t = type(s.data)
123 else:
124 t = type(s)
125 if t is UnicodeType:
126 return unicode(s)
127 else:
128 return str(s)
129 else:
130 to_String = str
131
133 try:
134 f = obj.for_signature
135 except AttributeError:
136 return to_String_for_subst(obj)
137 else:
138 return f()
139
141 if is_Sequence( s ):
142 return string.join( map(to_String_for_subst, s) )
143
144 return to_String( s )
145
146
148 """A simple composite callable class that, when called, will invoke all
149 of its contained callables with the same arguments."""
151 retvals = map(lambda x, args=args, kwargs=kwargs: apply(x,
152 args,
153 kwargs),
154 self.data)
155 if self.data and (len(self.data) == len(filter(callable, retvals))):
156 return self.__class__(retvals)
157 return NodeList(retvals)
158
160 """This class is almost exactly like a regular list of Nodes
161 (actually it can hold any object), with one important difference.
162 If you try to get an attribute from this list, it will return that
163 attribute from every item in the list. For example:
164
165 >>> someList = NodeList([ ' foo ', ' bar ' ])
166 >>> someList.strip()
167 [ 'foo', 'bar' ]
168 """
170 return len(self.data) != 0
171
173 return string.join(map(str, self.data))
174
176 if not self.data:
177
178
179 raise AttributeError, "NodeList has no attribute: %s" % name
180
181
182
183 attrList = map(lambda x, n=name: getattr(x, n), self.data)
184
185
186
187
188
189 if self.data and (len(self.data) == len(filter(callable, attrList))):
190 return CallableComposite(attrList)
191 return self.__class__(attrList)
192
193 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
194
196 """Given a string, first determine if it looks like a reference
197 to a single environment variable, like "$FOO" or "${FOO}".
198 If so, return that variable with no decorations ("FOO").
199 If not, return None."""
200 mo=_get_env_var.match(to_String(varstr))
201 if mo:
202 var = mo.group(1)
203 if var[0] == '{':
204 return var[1:-1]
205 else:
206 return var
207 else:
208 return None
209
213
214 - def print_it(self, text, append_newline=1):
215 if append_newline: text = text + '\n'
216 sys.stdout.write(text)
217
220
226
227 -def render_tree(root, child_func, prune=0, margin=[0], visited={}):
228 """
229 Render a tree of nodes into an ASCII tree view.
230 root - the root node of the tree
231 child_func - the function called to get the children of a node
232 prune - don't visit the same node twice
233 margin - the format of the left margin to use for children of root.
234 1 results in a pipe, and 0 results in no pipe.
235 visited - a dictionary of visited nodes in the current branch if not prune,
236 or in the whole tree if prune.
237 """
238
239 rname = str(root)
240
241 children = child_func(root)
242 retval = ""
243 for pipe in margin[:-1]:
244 if pipe:
245 retval = retval + "| "
246 else:
247 retval = retval + " "
248
249 if visited.has_key(rname):
250 return retval + "+-[" + rname + "]\n"
251
252 retval = retval + "+-" + rname + "\n"
253 if not prune:
254 visited = copy.copy(visited)
255 visited[rname] = 1
256
257 for i in range(len(children)):
258 margin.append(i<len(children)-1)
259 retval = retval + render_tree(children[i], child_func, prune, margin, visited
260 )
261 margin.pop()
262
263 return retval
264
265 IDX = lambda N: N and 1 or 0
266
267 -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
268 """
269 Print a tree of nodes. This is like render_tree, except it prints
270 lines directly instead of creating a string representation in memory,
271 so that huge trees can be printed.
272
273 root - the root node of the tree
274 child_func - the function called to get the children of a node
275 prune - don't visit the same node twice
276 showtags - print status information to the left of each node line
277 margin - the format of the left margin to use for children of root.
278 1 results in a pipe, and 0 results in no pipe.
279 visited - a dictionary of visited nodes in the current branch if not prune,
280 or in the whole tree if prune.
281 """
282
283 rname = str(root)
284
285 if showtags:
286
287 if showtags == 2:
288 print ' E = exists'
289 print ' R = exists in repository only'
290 print ' b = implicit builder'
291 print ' B = explicit builder'
292 print ' S = side effect'
293 print ' P = precious'
294 print ' A = always build'
295 print ' C = current'
296 print ' N = no clean'
297 print ' H = no cache'
298 print ''
299
300 tags = ['[']
301 tags.append(' E'[IDX(root.exists())])
302 tags.append(' R'[IDX(root.rexists() and not root.exists())])
303 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
304 [0,2][IDX(root.has_builder())]])
305 tags.append(' S'[IDX(root.side_effect)])
306 tags.append(' P'[IDX(root.precious)])
307 tags.append(' A'[IDX(root.always_build)])
308 tags.append(' C'[IDX(root.is_up_to_date())])
309 tags.append(' N'[IDX(root.noclean)])
310 tags.append(' H'[IDX(root.nocache)])
311 tags.append(']')
312
313 else:
314 tags = []
315
316 def MMM(m):
317 return [" ","| "][m]
318 margins = map(MMM, margin[:-1])
319
320 children = child_func(root)
321
322 if prune and visited.has_key(rname) and children:
323 print string.join(tags + margins + ['+-[', rname, ']'], '')
324 return
325
326 print string.join(tags + margins + ['+-', rname], '')
327
328 visited[rname] = 1
329
330 if children:
331 margin.append(1)
332 map(lambda C, cf=child_func, p=prune, i=IDX(showtags), m=margin, v=visited:
333 print_tree(C, cf, p, i, m, v),
334 children[:-1])
335 margin[-1] = 0
336 print_tree(children[-1], child_func, prune, IDX(showtags), margin, visited)
337 margin.pop()
338
339
340
341
342
343
344
345
346
347
348
349 try:
352 except TypeError:
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
373 t = type(obj)
374 return t is DictType or \
375 (t is InstanceType and isinstance(obj, UserDict))
376
378 t = type(obj)
379 return t is ListType \
380 or (t is InstanceType and isinstance(obj, UserList))
381
383 t = type(obj)
384 return t is ListType \
385 or t is TupleType \
386 or (t is InstanceType and isinstance(obj, UserList))
387
389 t = type(obj)
390 return t is TupleType
391
392 if hasattr(types, 'UnicodeType'):
394 t = type(obj)
395 return t is StringType \
396 or t is UnicodeType \
397 or (t is InstanceType and isinstance(obj, UserString))
398 else:
400 t = type(obj)
401 return t is StringType \
402 or (t is InstanceType and isinstance(obj, UserString))
403
405 return is_String(obj) or not is_Sequence(obj)
406
408 """Flatten a sequence to a non-nested list.
409
410 Flatten() converts either a single scalar or a nested sequence
411 to a non-nested list. Note that flatten() considers strings
412 to be scalars instead of sequences like Python would.
413 """
414 if is_Scalar(obj):
415 return [obj]
416 if result is None:
417 result = []
418 for item in obj:
419 if is_Scalar(item):
420 result.append(item)
421 else:
422 flatten_sequence(item, result)
423 return result
424
426 """Flatten a sequence to a non-nested list.
427
428 Same as flatten(), but it does not handle the single scalar
429 case. This is slightly more efficient when one knows that
430 the sequence to flatten can not be a scalar.
431 """
432 if result is None:
433 result = []
434 for item in sequence:
435 if is_Scalar(item):
436 result.append(item)
437 else:
438 flatten_sequence(item, result)
439 return result
440 else:
441
442
443
444
445
446
447
448
449
450 DictTypes = (dict, UserDict)
451 ListTypes = (list, UserList)
452 SequenceTypes = (list, tuple, UserList)
453
454
455
456
457
458
459
460 StringTypes = (str, unicode, UserString)
461
464
467
470
471 - def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
472 return isinstance(obj, tuple)
473
476
485
493
496 """Flatten a sequence to a non-nested list.
497
498 Flatten() converts either a single scalar or a nested sequence
499 to a non-nested list. Note that flatten() considers strings
500 to be scalars instead of sequences like Python would.
501 """
502 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
503 return [obj]
504 result = []
505 for item in obj:
506 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
507 result.append(item)
508 else:
509 do_flatten(item, result)
510 return result
511
514 """Flatten a sequence to a non-nested list.
515
516 Same as flatten(), but it does not handle the single scalar
517 case. This is slightly more efficient when one knows that
518 the sequence to flatten can not be a scalar.
519 """
520 result = []
521 for item in sequence:
522 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
523 result.append(item)
524 else:
525 do_flatten(item, result)
526 return result
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 _semi_deepcopy_dispatch = d = {}
543
545 copy = {}
546 for key, val in x.items():
547
548
549
550
551
552
553 copy[key] = semi_deepcopy(val)
554 return copy
555 d[types.DictionaryType] = _semi_deepcopy_dict
556
558 return map(semi_deepcopy, x)
559 d[types.ListType] = _semi_deepcopy_list
560
562 return tuple(map(semi_deepcopy, x))
563 d[types.TupleType] = _semi_deepcopy_tuple
564
566 if hasattr(x, '__semi_deepcopy__'):
567 return x.__semi_deepcopy__()
568 elif isinstance(x, UserDict):
569 return x.__class__(_semi_deepcopy_dict(x))
570 elif isinstance(x, UserList):
571 return x.__class__(_semi_deepcopy_list(x))
572 else:
573 return x
574 d[types.InstanceType] = _semi_deepcopy_inst
575
582
583
584
586 """A simple generic Proxy class, forwarding all calls to
587 subject. So, for the benefit of the python newbie, what does
588 this really mean? Well, it means that you can take an object, let's
589 call it 'objA', and wrap it in this Proxy class, with a statement
590 like this
591
592 proxyObj = Proxy(objA),
593
594 Then, if in the future, you do something like this
595
596 x = proxyObj.var1,
597
598 since Proxy does not have a 'var1' attribute (but presumably objA does),
599 the request actually is equivalent to saying
600
601 x = objA.var1
602
603 Inherit from this class to create a Proxy."""
604
606 """Wrap an object as a Proxy object"""
607 self.__subject = subject
608
610 """Retrieve an attribute from the wrapped object. If the named
611 attribute doesn't exist, AttributeError is raised"""
612 return getattr(self.__subject, name)
613
615 """Retrieve the entire wrapped object"""
616 return self.__subject
617
619 if issubclass(other.__class__, self.__subject.__class__):
620 return cmp(self.__subject, other)
621 return cmp(self.__dict__, other.__dict__)
622
623
624 can_read_reg = 0
625 try:
626 import _winreg
627
628 can_read_reg = 1
629 hkey_mod = _winreg
630
631 RegOpenKeyEx = _winreg.OpenKeyEx
632 RegEnumKey = _winreg.EnumKey
633 RegEnumValue = _winreg.EnumValue
634 RegQueryValueEx = _winreg.QueryValueEx
635 RegError = _winreg.error
636
637 except ImportError:
638 try:
639 import win32api
640 import win32con
641 can_read_reg = 1
642 hkey_mod = win32con
643
644 RegOpenKeyEx = win32api.RegOpenKeyEx
645 RegEnumKey = win32api.RegEnumKey
646 RegEnumValue = win32api.RegEnumValue
647 RegQueryValueEx = win32api.RegQueryValueEx
648 RegError = win32api.error
649
650 except ImportError:
653 RegError = _NoError
654
655 if can_read_reg:
656 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
657 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
658 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
659 HKEY_USERS = hkey_mod.HKEY_USERS
660
662 """This utility function returns a value in the registry
663 without having to open the key first. Only available on
664 Windows platforms with a version of Python that can read the
665 registry. Returns the same thing as
666 SCons.Util.RegQueryValueEx, except you just specify the entire
667 path to the value, and don't have to bother opening the key
668 first. So:
669
670 Instead of:
671 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
672 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
673 out = SCons.Util.RegQueryValueEx(k,
674 'ProgramFilesDir')
675
676 You can write:
677 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
678 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
679 """
680
681
682 p = key.rfind('\\') + 1
683 keyp = key[:p]
684 val = key[p:]
685 k = RegOpenKeyEx(root, keyp)
686 return RegQueryValueEx(k,val)
687
688 if sys.platform == 'win32':
689
690 - def WhereIs(file, path=None, pathext=None, reject=[]):
691 if path is None:
692 try:
693 path = os.environ['PATH']
694 except KeyError:
695 return None
696 if is_String(path):
697 path = string.split(path, os.pathsep)
698 if pathext is None:
699 try:
700 pathext = os.environ['PATHEXT']
701 except KeyError:
702 pathext = '.COM;.EXE;.BAT;.CMD'
703 if is_String(pathext):
704 pathext = string.split(pathext, os.pathsep)
705 for ext in pathext:
706 if string.lower(ext) == string.lower(file[-len(ext):]):
707 pathext = ['']
708 break
709 if not is_List(reject) and not is_Tuple(reject):
710 reject = [reject]
711 for dir in path:
712 f = os.path.join(dir, file)
713 for ext in pathext:
714 fext = f + ext
715 if os.path.isfile(fext):
716 try:
717 reject.index(fext)
718 except ValueError:
719 return os.path.normpath(fext)
720 continue
721 return None
722
723 elif os.name == 'os2':
724
725 - def WhereIs(file, path=None, pathext=None, reject=[]):
726 if path is None:
727 try:
728 path = os.environ['PATH']
729 except KeyError:
730 return None
731 if is_String(path):
732 path = string.split(path, os.pathsep)
733 if pathext is None:
734 pathext = ['.exe', '.cmd']
735 for ext in pathext:
736 if string.lower(ext) == string.lower(file[-len(ext):]):
737 pathext = ['']
738 break
739 if not is_List(reject) and not is_Tuple(reject):
740 reject = [reject]
741 for dir in path:
742 f = os.path.join(dir, file)
743 for ext in pathext:
744 fext = f + ext
745 if os.path.isfile(fext):
746 try:
747 reject.index(fext)
748 except ValueError:
749 return os.path.normpath(fext)
750 continue
751 return None
752
753 else:
754
755 - def WhereIs(file, path=None, pathext=None, reject=[]):
756 import stat
757 if path is None:
758 try:
759 path = os.environ['PATH']
760 except KeyError:
761 return None
762 if is_String(path):
763 path = string.split(path, os.pathsep)
764 if not is_List(reject) and not is_Tuple(reject):
765 reject = [reject]
766 for d in path:
767 f = os.path.join(d, file)
768 if os.path.isfile(f):
769 try:
770 st = os.stat(f)
771 except OSError:
772
773
774
775
776 continue
777 if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
778 try:
779 reject.index(f)
780 except ValueError:
781 return os.path.normpath(f)
782 continue
783 return None
784
786 """This prepends newpath elements to the given oldpath. Will only
787 add any particular path once (leaving the first one it encounters
788 and ignoring the rest, to preserve path order), and will
789 os.path.normpath and os.path.normcase all paths to help assure
790 this. This can also handle the case where the given old path
791 variable is a list instead of a string, in which case a list will
792 be returned instead of a string.
793
794 Example:
795 Old Path: "/foo/bar:/foo"
796 New Path: "/biz/boom:/foo"
797 Result: "/biz/boom:/foo:/foo/bar"
798 """
799
800 orig = oldpath
801 is_list = 1
802 paths = orig
803 if not is_List(orig) and not is_Tuple(orig):
804 paths = string.split(paths, sep)
805 is_list = 0
806
807 if is_List(newpath) or is_Tuple(newpath):
808 newpaths = newpath
809 else:
810 newpaths = string.split(newpath, sep)
811
812 newpaths = newpaths + paths
813
814 normpaths = []
815 paths = []
816
817 for path in newpaths:
818 normpath = os.path.normpath(os.path.normcase(path))
819 if path and not normpath in normpaths:
820 paths.append(path)
821 normpaths.append(normpath)
822
823 if is_list:
824 return paths
825 else:
826 return string.join(paths, sep)
827
828 -def AppendPath(oldpath, newpath, sep = os.pathsep):
829 """This appends new path elements to the given old path. Will
830 only add any particular path once (leaving the last one it
831 encounters and ignoring the rest, to preserve path order), and
832 will os.path.normpath and os.path.normcase all paths to help
833 assure this. This can also handle the case where the given old
834 path variable is a list instead of a string, in which case a list
835 will be returned instead of a string.
836
837 Example:
838 Old Path: "/foo/bar:/foo"
839 New Path: "/biz/boom:/foo"
840 Result: "/foo/bar:/biz/boom:/foo"
841 """
842
843 orig = oldpath
844 is_list = 1
845 paths = orig
846 if not is_List(orig) and not is_Tuple(orig):
847 paths = string.split(paths, sep)
848 is_list = 0
849
850 if is_List(newpath) or is_Tuple(newpath):
851 newpaths = newpath
852 else:
853 newpaths = string.split(newpath, sep)
854
855 newpaths = paths + newpaths
856 newpaths.reverse()
857
858 normpaths = []
859 paths = []
860
861 for path in newpaths:
862 normpath = os.path.normpath(os.path.normcase(path))
863 if path and not normpath in normpaths:
864 paths.append(path)
865 normpaths.append(normpath)
866
867 paths.reverse()
868
869 if is_list:
870 return paths
871 else:
872 return string.join(paths, sep)
873
874 if sys.platform == 'cygwin':
876 """Transforms an absolute path into a native path for the system. In
877 Cygwin, this converts from a Cygwin path to a Windows one."""
878 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
879 else:
881 """Transforms an absolute path into a native path for the system.
882 Non-Cygwin version, just leave the path alone."""
883 return path
884
885 display = DisplayEngine()
886
888 if is_List(arg) or is_Tuple(arg):
889 return arg
890 elif is_String(arg):
891 return string.split(arg)
892 else:
893 return [arg]
894
896 """A class for command-line construction variables.
897
898 This is a list that uses Split() to split an initial string along
899 white-space arguments, and similarly to split any strings that get
900 added. This allows us to Do the Right Thing with Append() and
901 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
902 arg2') regardless of whether a user adds a list or a string to a
903 command-line construction variable.
904 """
908 return (self, CLVar(other))
910 return string.join(self.data)
911
912
913
914
915
920
924
926 UserDict.__setitem__(self, key, item)
927 if key not in self._keys: self._keys.append(key)
928
930 UserDict.clear(self)
931 self._keys = []
932
937
940
943
945 try:
946 key = self._keys[-1]
947 except IndexError:
948 raise KeyError('dictionary is empty')
949
950 val = self[key]
951 del self[key]
952
953 return (key, val)
954
956 UserDict.setdefault(self, key, failobj)
957 if key not in self._keys: self._keys.append(key)
958
962
964 return map(self.get, self._keys)
965
967 """A callable ordered dictionary that maps file suffixes to
968 dictionary values. We preserve the order in which items are added
969 so that get_suffix() calls always return the first suffix added."""
971 try:
972 ext = source[0].suffix
973 except IndexError:
974 ext = ""
975 try:
976 return self[ext]
977 except KeyError:
978
979
980 s_dict = {}
981 for (k,v) in self.items():
982 if not k is None:
983 s_k = env.subst(k)
984 if s_dict.has_key(s_k):
985
986
987
988
989 raise KeyError, (s_dict[s_k][0], k, s_k)
990 s_dict[s_k] = (k,v)
991 try:
992 return s_dict[ext][1]
993 except KeyError:
994 try:
995 return self[None]
996 except KeyError:
997 return None
998
999
1000 if sys.platform == 'cygwin':
1001
1002
1005 else:
1007 return (os.path.normcase(s1) != os.path.normcase(s2))
1008
1010 if pre:
1011 path, fn = os.path.split(os.path.normpath(fname))
1012 if fn[:len(pre)] != pre:
1013 fname = os.path.join(path, pre + fn)
1014
1015
1016
1017 if suf and fname[-len(suf):] != suf and \
1018 (ensure_suffix or not splitext(fname)[1]):
1019 fname = fname + suf
1020 return fname
1021
1022
1023
1024
1025
1026
1027
1028
1030 """Return a list of the elements in s, but without duplicates.
1031
1032 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1033 unique("abcabc") some permutation of ["a", "b", "c"], and
1034 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1035 [[2, 3], [1, 2]].
1036
1037 For best speed, all sequence elements should be hashable. Then
1038 unique() will usually work in linear time.
1039
1040 If not possible, the sequence elements should enjoy a total
1041 ordering, and if list(s).sort() doesn't raise TypeError it's
1042 assumed that they do enjoy a total ordering. Then unique() will
1043 usually work in O(N*log2(N)) time.
1044
1045 If that's not possible either, the sequence elements must support
1046 equality-testing. Then unique() will usually work in quadratic
1047 time.
1048 """
1049
1050 n = len(s)
1051 if n == 0:
1052 return []
1053
1054
1055
1056
1057
1058 u = {}
1059 try:
1060 for x in s:
1061 u[x] = 1
1062 except TypeError:
1063 pass
1064 else:
1065 return u.keys()
1066 del u
1067
1068
1069
1070
1071
1072
1073
1074
1075 try:
1076 t = list(s)
1077 t.sort()
1078 except TypeError:
1079 pass
1080 else:
1081 assert n > 0
1082 last = t[0]
1083 lasti = i = 1
1084 while i < n:
1085 if t[i] != last:
1086 t[lasti] = last = t[i]
1087 lasti = lasti + 1
1088 i = i + 1
1089 return t[:lasti]
1090 del t
1091
1092
1093 u = []
1094 for x in s:
1095 if x not in u:
1096 u.append(x)
1097 return u
1098
1099
1100
1101
1102
1103
1104
1105
1106
1108 if idfun is None:
1109 def idfun(x): return x
1110 seen = {}
1111 result = []
1112 for item in seq:
1113 marker = idfun(item)
1114
1115
1116
1117 if marker in seen: continue
1118 seen[marker] = 1
1119 result.append(item)
1120 return result
1121
1122
1123
1124
1125
1135
1136
1137
1138
1139
1141
1143 self.fileobj = fileobj
1144
1157
1166
1167
1168
1174 if not self.unique:
1175 self.data = uniquer_hashables(self.data)
1176 self.unique = True
1238 UserList.append(self, item)
1239 self.unique = False
1252 - def sort(self, *args, **kwds):
1257 UserList.extend(self, other)
1258 self.unique = False
1259
1260
1261
1263 """
1264 A proxy class that wraps a file object, flushing after every write,
1265 and delegating everything else to the wrapped object.
1266 """
1273 return getattr(self.file, attr)
1274
1276 """ makes an absolute path name to a relative pathname.
1277 """
1278 if os.path.isabs(path):
1279 drive_s,path = os.path.splitdrive(path)
1280
1281 import re
1282 if not drive_s:
1283 path=re.compile("/*(.*)").findall(path)[0]
1284 else:
1285 path=path[1:]
1286
1287 assert( not os.path.isabs( path ) ), path
1288 return path
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316 -def AddMethod(object, function, name = None):
1317 """
1318 Adds either a bound method to an instance or an unbound method to
1319 a class. If name is ommited the name of the specified function
1320 is used by default.
1321 Example:
1322 a = A()
1323 def f(self, x, y):
1324 self.z = x + y
1325 AddMethod(f, A, "add")
1326 a.add(2, 4)
1327 print a.z
1328 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1329 print a.listIndex(5)
1330 """
1331 import new
1332
1333 if name is None:
1334 name = function.func_name
1335 else:
1336 function = RenameFunction(function, name)
1337
1338 try:
1339 klass = object.__class__
1340 except AttributeError:
1341
1342 object.__dict__[name] = new.instancemethod(function, None, object)
1343 else:
1344
1345 object.__dict__[name] = new.instancemethod(function, object, klass)
1346
1348 """
1349 Returns a function identical to the specified function, but with
1350 the specified name.
1351 """
1352 import new
1353
1354
1355
1356
1357 func_defaults = function.func_defaults
1358 if func_defaults is None:
1359 func_defaults = ()
1360
1361 return new.function(function.func_code,
1362 function.func_globals,
1363 name,
1364 func_defaults)
1365
1366
1367 md5 = False
1370
1371 try:
1372 import hashlib
1373 except ImportError:
1374 pass
1375 else:
1376 if hasattr(hashlib, 'md5'):
1377 md5 = True
1382
1384 """
1385 Collects a list of signatures into an aggregate signature.
1386
1387 signatures - a list of signatures
1388 returns - the aggregate signature
1389 """
1390 if len(signatures) == 1:
1391 return signatures[0]
1392 else:
1393 return MD5signature(string.join(signatures, ', '))
1394
1395
1396
1397
1398
1399
1400
1401
1402
1404 """ Null objects always and reliably "do nothging." """
1405
1406 - def __new__(cls, *args, **kwargs):
1407 if not '_inst' in vars(cls):
1408
1409 cls._inst = apply(type.__new__, (cls,) + args, kwargs)
1410 return cls._inst
1425
1426
1427
1428 del __revision__
1429