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 3266 2008/08/12 07:31:01 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
113 """A simple composite callable class that, when called, will invoke all
114 of its contained callables with the same arguments."""
116 retvals = map(lambda x, args=args, kwargs=kwargs: apply(x,
117 args,
118 kwargs),
119 self.data)
120 if self.data and (len(self.data) == len(filter(callable, retvals))):
121 return self.__class__(retvals)
122 return NodeList(retvals)
123
125 """This class is almost exactly like a regular list of Nodes
126 (actually it can hold any object), with one important difference.
127 If you try to get an attribute from this list, it will return that
128 attribute from every item in the list. For example:
129
130 >>> someList = NodeList([ ' foo ', ' bar ' ])
131 >>> someList.strip()
132 [ 'foo', 'bar' ]
133 """
135 return len(self.data) != 0
136
138 return string.join(map(str, self.data))
139
141 if not self.data:
142
143
144 raise AttributeError, "NodeList has no attribute: %s" % name
145
146
147
148 attrList = map(lambda x, n=name: getattr(x, n), self.data)
149
150
151
152
153
154 if self.data and (len(self.data) == len(filter(callable, attrList))):
155 return CallableComposite(attrList)
156 return self.__class__(attrList)
157
158 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
159
161 """Given a string, first determine if it looks like a reference
162 to a single environment variable, like "$FOO" or "${FOO}".
163 If so, return that variable with no decorations ("FOO").
164 If not, return None."""
165 mo=_get_env_var.match(to_String(varstr))
166 if mo:
167 var = mo.group(1)
168 if var[0] == '{':
169 return var[1:-1]
170 else:
171 return var
172 else:
173 return None
174
178
179 - def print_it(self, text, append_newline=1):
180 if append_newline: text = text + '\n'
181 try:
182 sys.stdout.write(text)
183 except IOError:
184
185
186
187
188
189
190
191 pass
192
195
201
202 -def render_tree(root, child_func, prune=0, margin=[0], visited={}):
203 """
204 Render a tree of nodes into an ASCII tree view.
205 root - the root node of the tree
206 child_func - the function called to get the children of a node
207 prune - don't visit the same node twice
208 margin - the format of the left margin to use for children of root.
209 1 results in a pipe, and 0 results in no pipe.
210 visited - a dictionary of visited nodes in the current branch if not prune,
211 or in the whole tree if prune.
212 """
213
214 rname = str(root)
215
216 children = child_func(root)
217 retval = ""
218 for pipe in margin[:-1]:
219 if pipe:
220 retval = retval + "| "
221 else:
222 retval = retval + " "
223
224 if visited.has_key(rname):
225 return retval + "+-[" + rname + "]\n"
226
227 retval = retval + "+-" + rname + "\n"
228 if not prune:
229 visited = copy.copy(visited)
230 visited[rname] = 1
231
232 for i in range(len(children)):
233 margin.append(i<len(children)-1)
234 retval = retval + render_tree(children[i], child_func, prune, margin, visited
235 )
236 margin.pop()
237
238 return retval
239
240 IDX = lambda N: N and 1 or 0
241
242 -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
243 """
244 Print a tree of nodes. This is like render_tree, except it prints
245 lines directly instead of creating a string representation in memory,
246 so that huge trees can be printed.
247
248 root - the root node of the tree
249 child_func - the function called to get the children of a node
250 prune - don't visit the same node twice
251 showtags - print status information to the left of each node line
252 margin - the format of the left margin to use for children of root.
253 1 results in a pipe, and 0 results in no pipe.
254 visited - a dictionary of visited nodes in the current branch if not prune,
255 or in the whole tree if prune.
256 """
257
258 rname = str(root)
259
260 if showtags:
261
262 if showtags == 2:
263 print ' E = exists'
264 print ' R = exists in repository only'
265 print ' b = implicit builder'
266 print ' B = explicit builder'
267 print ' S = side effect'
268 print ' P = precious'
269 print ' A = always build'
270 print ' C = current'
271 print ' N = no clean'
272 print ' H = no cache'
273 print ''
274
275 tags = ['[']
276 tags.append(' E'[IDX(root.exists())])
277 tags.append(' R'[IDX(root.rexists() and not root.exists())])
278 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
279 [0,2][IDX(root.has_builder())]])
280 tags.append(' S'[IDX(root.side_effect)])
281 tags.append(' P'[IDX(root.precious)])
282 tags.append(' A'[IDX(root.always_build)])
283 tags.append(' C'[IDX(root.is_up_to_date())])
284 tags.append(' N'[IDX(root.noclean)])
285 tags.append(' H'[IDX(root.nocache)])
286 tags.append(']')
287
288 else:
289 tags = []
290
291 def MMM(m):
292 return [" ","| "][m]
293 margins = map(MMM, margin[:-1])
294
295 children = child_func(root)
296
297 if prune and visited.has_key(rname) and children:
298 print string.join(tags + margins + ['+-[', rname, ']'], '')
299 return
300
301 print string.join(tags + margins + ['+-', rname], '')
302
303 visited[rname] = 1
304
305 if children:
306 margin.append(1)
307 map(lambda C, cf=child_func, p=prune, i=IDX(showtags), m=margin, v=visited:
308 print_tree(C, cf, p, i, m, v),
309 children[:-1])
310 margin[-1] = 0
311 print_tree(children[-1], child_func, prune, IDX(showtags), margin, visited)
312 margin.pop()
313
314
315
316
317
318
319
320
321
322
323
324 try:
327 except TypeError:
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
348 t = type(obj)
349 return t is DictType or \
350 (t is InstanceType and isinstance(obj, UserDict))
351
353 t = type(obj)
354 return t is ListType \
355 or (t is InstanceType and isinstance(obj, UserList))
356
358 t = type(obj)
359 return t is ListType \
360 or t is TupleType \
361 or (t is InstanceType and isinstance(obj, UserList))
362
364 t = type(obj)
365 return t is TupleType
366
367 if hasattr(types, 'UnicodeType'):
369 t = type(obj)
370 return t is StringType \
371 or t is UnicodeType \
372 or (t is InstanceType and isinstance(obj, UserString))
373 else:
375 t = type(obj)
376 return t is StringType \
377 or (t is InstanceType and isinstance(obj, UserString))
378
380 return is_String(obj) or not is_Sequence(obj)
381
383 """Flatten a sequence to a non-nested list.
384
385 Flatten() converts either a single scalar or a nested sequence
386 to a non-nested list. Note that flatten() considers strings
387 to be scalars instead of sequences like Python would.
388 """
389 if is_Scalar(obj):
390 return [obj]
391 if result is None:
392 result = []
393 for item in obj:
394 if is_Scalar(item):
395 result.append(item)
396 else:
397 flatten_sequence(item, result)
398 return result
399
401 """Flatten a sequence to a non-nested list.
402
403 Same as flatten(), but it does not handle the single scalar
404 case. This is slightly more efficient when one knows that
405 the sequence to flatten can not be a scalar.
406 """
407 if result is None:
408 result = []
409 for item in sequence:
410 if is_Scalar(item):
411 result.append(item)
412 else:
413 flatten_sequence(item, result)
414 return result
415
416
417
418
419
420
421
422 if hasattr(types, 'UnicodeType'):
423 UnicodeType = types.UnicodeType
425 if isinstance(s, UserString):
426 t = type(s.data)
427 else:
428 t = type(s)
429 if t is UnicodeType:
430 return unicode(s)
431 else:
432 return str(s)
433 else:
434 to_String = str
435
437 try:
438 f = obj.for_signature
439 except AttributeError:
440 return to_String_for_subst(obj)
441 else:
442 return f()
443
445 if is_Sequence( s ):
446 return string.join( map(to_String_for_subst, s) )
447
448 return to_String( s )
449
450 else:
451
452
453
454
455
456
457
458
459
460 DictTypes = (dict, UserDict)
461 ListTypes = (list, UserList)
462 SequenceTypes = (list, tuple, UserList)
463
464
465
466
467
468
469
470 StringTypes = (str, unicode, UserString)
471
472
473
474 BaseStringTypes = (str, unicode)
475
478
481
484
485 - def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
486 return isinstance(obj, tuple)
487
490
499
507
510 """Flatten a sequence to a non-nested list.
511
512 Flatten() converts either a single scalar or a nested sequence
513 to a non-nested list. Note that flatten() considers strings
514 to be scalars instead of sequences like Python would.
515 """
516 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
517 return [obj]
518 result = []
519 for item in obj:
520 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
521 result.append(item)
522 else:
523 do_flatten(item, result)
524 return result
525
528 """Flatten a sequence to a non-nested list.
529
530 Same as flatten(), but it does not handle the single scalar
531 case. This is slightly more efficient when one knows that
532 the sequence to flatten can not be a scalar.
533 """
534 result = []
535 for item in sequence:
536 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
537 result.append(item)
538 else:
539 do_flatten(item, result)
540 return result
541
542
543
544
545
546
547
548
552 if isinstance(s,BaseStringTypes):
553
554 return s
555 elif isinstance(s, UserString):
556
557
558 return s.data
559 else:
560 return str(s)
561
566
567
568 if isinstance(s, BaseStringTypes):
569 return s
570 elif isinstance(s, SequenceTypes):
571 l = []
572 for e in s:
573 l.append(to_String_for_subst(e))
574 return join( s )
575 elif isinstance(s, UserString):
576
577
578 return s.data
579 else:
580 return str(s)
581
584 try:
585 f = obj.for_signature
586 except AttributeError:
587 return to_String_for_subst(obj)
588 else:
589 return f()
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606 _semi_deepcopy_dispatch = d = {}
607
609 copy = {}
610 for key, val in x.items():
611
612
613
614
615
616
617 copy[key] = semi_deepcopy(val)
618 return copy
619 d[types.DictionaryType] = _semi_deepcopy_dict
620
622 return map(semi_deepcopy, x)
623 d[types.ListType] = _semi_deepcopy_list
624
626 return tuple(map(semi_deepcopy, x))
627 d[types.TupleType] = _semi_deepcopy_tuple
628
630 if hasattr(x, '__semi_deepcopy__'):
631 return x.__semi_deepcopy__()
632 elif isinstance(x, UserDict):
633 return x.__class__(_semi_deepcopy_dict(x))
634 elif isinstance(x, UserList):
635 return x.__class__(_semi_deepcopy_list(x))
636 else:
637 return x
638 d[types.InstanceType] = _semi_deepcopy_inst
639
646
647
648
650 """A simple generic Proxy class, forwarding all calls to
651 subject. So, for the benefit of the python newbie, what does
652 this really mean? Well, it means that you can take an object, let's
653 call it 'objA', and wrap it in this Proxy class, with a statement
654 like this
655
656 proxyObj = Proxy(objA),
657
658 Then, if in the future, you do something like this
659
660 x = proxyObj.var1,
661
662 since Proxy does not have a 'var1' attribute (but presumably objA does),
663 the request actually is equivalent to saying
664
665 x = objA.var1
666
667 Inherit from this class to create a Proxy."""
668
670 """Wrap an object as a Proxy object"""
671 self.__subject = subject
672
674 """Retrieve an attribute from the wrapped object. If the named
675 attribute doesn't exist, AttributeError is raised"""
676 return getattr(self.__subject, name)
677
679 """Retrieve the entire wrapped object"""
680 return self.__subject
681
683 if issubclass(other.__class__, self.__subject.__class__):
684 return cmp(self.__subject, other)
685 return cmp(self.__dict__, other.__dict__)
686
687
688 can_read_reg = 0
689 try:
690 import _winreg
691
692 can_read_reg = 1
693 hkey_mod = _winreg
694
695 RegOpenKeyEx = _winreg.OpenKeyEx
696 RegEnumKey = _winreg.EnumKey
697 RegEnumValue = _winreg.EnumValue
698 RegQueryValueEx = _winreg.QueryValueEx
699 RegError = _winreg.error
700
701 except ImportError:
702 try:
703 import win32api
704 import win32con
705 can_read_reg = 1
706 hkey_mod = win32con
707
708 RegOpenKeyEx = win32api.RegOpenKeyEx
709 RegEnumKey = win32api.RegEnumKey
710 RegEnumValue = win32api.RegEnumValue
711 RegQueryValueEx = win32api.RegQueryValueEx
712 RegError = win32api.error
713
714 except ImportError:
717 RegError = _NoError
718
719 if can_read_reg:
720 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
721 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
722 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
723 HKEY_USERS = hkey_mod.HKEY_USERS
724
726 """This utility function returns a value in the registry
727 without having to open the key first. Only available on
728 Windows platforms with a version of Python that can read the
729 registry. Returns the same thing as
730 SCons.Util.RegQueryValueEx, except you just specify the entire
731 path to the value, and don't have to bother opening the key
732 first. So:
733
734 Instead of:
735 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
736 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
737 out = SCons.Util.RegQueryValueEx(k,
738 'ProgramFilesDir')
739
740 You can write:
741 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
742 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
743 """
744
745
746 p = key.rfind('\\') + 1
747 keyp = key[:p]
748 val = key[p:]
749 k = RegOpenKeyEx(root, keyp)
750 return RegQueryValueEx(k,val)
751
752 if sys.platform == 'win32':
753
754 - def WhereIs(file, path=None, pathext=None, reject=[]):
755 if path is None:
756 try:
757 path = os.environ['PATH']
758 except KeyError:
759 return None
760 if is_String(path):
761 path = string.split(path, os.pathsep)
762 if pathext is None:
763 try:
764 pathext = os.environ['PATHEXT']
765 except KeyError:
766 pathext = '.COM;.EXE;.BAT;.CMD'
767 if is_String(pathext):
768 pathext = string.split(pathext, os.pathsep)
769 for ext in pathext:
770 if string.lower(ext) == string.lower(file[-len(ext):]):
771 pathext = ['']
772 break
773 if not is_List(reject) and not is_Tuple(reject):
774 reject = [reject]
775 for dir in path:
776 f = os.path.join(dir, file)
777 for ext in pathext:
778 fext = f + ext
779 if os.path.isfile(fext):
780 try:
781 reject.index(fext)
782 except ValueError:
783 return os.path.normpath(fext)
784 continue
785 return None
786
787 elif os.name == 'os2':
788
789 - def WhereIs(file, path=None, pathext=None, reject=[]):
790 if path is None:
791 try:
792 path = os.environ['PATH']
793 except KeyError:
794 return None
795 if is_String(path):
796 path = string.split(path, os.pathsep)
797 if pathext is None:
798 pathext = ['.exe', '.cmd']
799 for ext in pathext:
800 if string.lower(ext) == string.lower(file[-len(ext):]):
801 pathext = ['']
802 break
803 if not is_List(reject) and not is_Tuple(reject):
804 reject = [reject]
805 for dir in path:
806 f = os.path.join(dir, file)
807 for ext in pathext:
808 fext = f + ext
809 if os.path.isfile(fext):
810 try:
811 reject.index(fext)
812 except ValueError:
813 return os.path.normpath(fext)
814 continue
815 return None
816
817 else:
818
819 - def WhereIs(file, path=None, pathext=None, reject=[]):
848
850 """This prepends newpath elements to the given oldpath. Will only
851 add any particular path once (leaving the first one it encounters
852 and ignoring the rest, to preserve path order), and will
853 os.path.normpath and os.path.normcase all paths to help assure
854 this. This can also handle the case where the given old path
855 variable is a list instead of a string, in which case a list will
856 be returned instead of a string.
857
858 Example:
859 Old Path: "/foo/bar:/foo"
860 New Path: "/biz/boom:/foo"
861 Result: "/biz/boom:/foo:/foo/bar"
862 """
863
864 orig = oldpath
865 is_list = 1
866 paths = orig
867 if not is_List(orig) and not is_Tuple(orig):
868 paths = string.split(paths, sep)
869 is_list = 0
870
871 if is_List(newpath) or is_Tuple(newpath):
872 newpaths = newpath
873 else:
874 newpaths = string.split(newpath, sep)
875
876 newpaths = newpaths + paths
877
878 normpaths = []
879 paths = []
880
881 for path in newpaths:
882 normpath = os.path.normpath(os.path.normcase(path))
883 if path and not normpath in normpaths:
884 paths.append(path)
885 normpaths.append(normpath)
886
887 if is_list:
888 return paths
889 else:
890 return string.join(paths, sep)
891
893 """This appends new path elements to the given old path. Will
894 only add any particular path once (leaving the last one it
895 encounters and ignoring the rest, to preserve path order), and
896 will os.path.normpath and os.path.normcase all paths to help
897 assure this. This can also handle the case where the given old
898 path variable is a list instead of a string, in which case a list
899 will be returned instead of a string.
900
901 Example:
902 Old Path: "/foo/bar:/foo"
903 New Path: "/biz/boom:/foo"
904 Result: "/foo/bar:/biz/boom:/foo"
905 """
906
907 orig = oldpath
908 is_list = 1
909 paths = orig
910 if not is_List(orig) and not is_Tuple(orig):
911 paths = string.split(paths, sep)
912 is_list = 0
913
914 if is_List(newpath) or is_Tuple(newpath):
915 newpaths = newpath
916 else:
917 newpaths = string.split(newpath, sep)
918
919 newpaths = paths + newpaths
920 newpaths.reverse()
921
922 normpaths = []
923 paths = []
924
925 for path in newpaths:
926 normpath = os.path.normpath(os.path.normcase(path))
927 if path and not normpath in normpaths:
928 paths.append(path)
929 normpaths.append(normpath)
930
931 paths.reverse()
932
933 if is_list:
934 return paths
935 else:
936 return string.join(paths, sep)
937
938 if sys.platform == 'cygwin':
940 """Transforms an absolute path into a native path for the system. In
941 Cygwin, this converts from a Cygwin path to a Windows one."""
942 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
943 else:
945 """Transforms an absolute path into a native path for the system.
946 Non-Cygwin version, just leave the path alone."""
947 return path
948
949 display = DisplayEngine()
950
952 if is_List(arg) or is_Tuple(arg):
953 return arg
954 elif is_String(arg):
955 return string.split(arg)
956 else:
957 return [arg]
958
960 """A class for command-line construction variables.
961
962 This is a list that uses Split() to split an initial string along
963 white-space arguments, and similarly to split any strings that get
964 added. This allows us to Do the Right Thing with Append() and
965 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
966 arg2') regardless of whether a user adds a list or a string to a
967 command-line construction variable.
968 """
972 return (self, CLVar(other))
974 return string.join(self.data)
975
976
977
978
979
984
988
990 UserDict.__setitem__(self, key, item)
991 if key not in self._keys: self._keys.append(key)
992
994 UserDict.clear(self)
995 self._keys = []
996
1001
1004
1006 return self._keys[:]
1007
1009 try:
1010 key = self._keys[-1]
1011 except IndexError:
1012 raise KeyError('dictionary is empty')
1013
1014 val = self[key]
1015 del self[key]
1016
1017 return (key, val)
1018
1020 UserDict.setdefault(self, key, failobj)
1021 if key not in self._keys: self._keys.append(key)
1022
1026
1028 return map(self.get, self._keys)
1029
1031 """A callable ordered dictionary that maps file suffixes to
1032 dictionary values. We preserve the order in which items are added
1033 so that get_suffix() calls always return the first suffix added."""
1035 try:
1036 ext = source[0].suffix
1037 except IndexError:
1038 ext = ""
1039 try:
1040 return self[ext]
1041 except KeyError:
1042
1043
1044 s_dict = {}
1045 for (k,v) in self.items():
1046 if not k is None:
1047 s_k = env.subst(k)
1048 if s_dict.has_key(s_k):
1049
1050
1051
1052
1053 raise KeyError, (s_dict[s_k][0], k, s_k)
1054 s_dict[s_k] = (k,v)
1055 try:
1056 return s_dict[ext][1]
1057 except KeyError:
1058 try:
1059 return self[None]
1060 except KeyError:
1061 return None
1062
1063
1064 if sys.platform == 'cygwin':
1065
1066
1069 else:
1072
1074 if pre:
1075 path, fn = os.path.split(os.path.normpath(fname))
1076 if fn[:len(pre)] != pre:
1077 fname = os.path.join(path, pre + fn)
1078
1079
1080
1081 if suf and fname[-len(suf):] != suf and \
1082 (ensure_suffix or not splitext(fname)[1]):
1083 fname = fname + suf
1084 return fname
1085
1086
1087
1088
1089
1090
1091
1092
1094 """Return a list of the elements in s, but without duplicates.
1095
1096 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1097 unique("abcabc") some permutation of ["a", "b", "c"], and
1098 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1099 [[2, 3], [1, 2]].
1100
1101 For best speed, all sequence elements should be hashable. Then
1102 unique() will usually work in linear time.
1103
1104 If not possible, the sequence elements should enjoy a total
1105 ordering, and if list(s).sort() doesn't raise TypeError it's
1106 assumed that they do enjoy a total ordering. Then unique() will
1107 usually work in O(N*log2(N)) time.
1108
1109 If that's not possible either, the sequence elements must support
1110 equality-testing. Then unique() will usually work in quadratic
1111 time.
1112 """
1113
1114 n = len(s)
1115 if n == 0:
1116 return []
1117
1118
1119
1120
1121
1122 u = {}
1123 try:
1124 for x in s:
1125 u[x] = 1
1126 except TypeError:
1127 pass
1128 else:
1129 return u.keys()
1130 del u
1131
1132
1133
1134
1135
1136
1137
1138
1139 try:
1140 t = list(s)
1141 t.sort()
1142 except TypeError:
1143 pass
1144 else:
1145 assert n > 0
1146 last = t[0]
1147 lasti = i = 1
1148 while i < n:
1149 if t[i] != last:
1150 t[lasti] = last = t[i]
1151 lasti = lasti + 1
1152 i = i + 1
1153 return t[:lasti]
1154 del t
1155
1156
1157 u = []
1158 for x in s:
1159 if x not in u:
1160 u.append(x)
1161 return u
1162
1163
1164
1165
1166
1167
1168
1169
1170
1172 if idfun is None:
1173 def idfun(x): return x
1174 seen = {}
1175 result = []
1176 for item in seq:
1177 marker = idfun(item)
1178
1179
1180
1181 if marker in seen: continue
1182 seen[marker] = 1
1183 result.append(item)
1184 return result
1185
1186
1187
1188
1189
1199
1200
1201
1202
1203
1205
1207 self.fileobj = fileobj
1208
1221
1230
1231
1232
1238 if not self.unique:
1239 self.data = uniquer_hashables(self.data)
1240 self.unique = True
1316 - def sort(self, *args, **kwds):
1323
1324
1325
1327 """
1328 A proxy class that wraps a file object, flushing after every write,
1329 and delegating everything else to the wrapped object.
1330 """
1334 try:
1335 self.file.write(arg)
1336 self.file.flush()
1337 except IOError:
1338
1339
1340
1341
1342
1343
1344
1345 pass
1347 return getattr(self.file, attr)
1348
1350 """ makes an absolute path name to a relative pathname.
1351 """
1352 if os.path.isabs(path):
1353 drive_s,path = os.path.splitdrive(path)
1354
1355 import re
1356 if not drive_s:
1357 path=re.compile("/*(.*)").findall(path)[0]
1358 else:
1359 path=path[1:]
1360
1361 assert( not os.path.isabs( path ) ), path
1362 return path
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390 -def AddMethod(object, function, name = None):
1391 """
1392 Adds either a bound method to an instance or an unbound method to
1393 a class. If name is ommited the name of the specified function
1394 is used by default.
1395 Example:
1396 a = A()
1397 def f(self, x, y):
1398 self.z = x + y
1399 AddMethod(f, A, "add")
1400 a.add(2, 4)
1401 print a.z
1402 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1403 print a.listIndex(5)
1404 """
1405 import new
1406
1407 if name is None:
1408 name = function.func_name
1409 else:
1410 function = RenameFunction(function, name)
1411
1412 try:
1413 klass = object.__class__
1414 except AttributeError:
1415
1416 object.__dict__[name] = new.instancemethod(function, None, object)
1417 else:
1418
1419 object.__dict__[name] = new.instancemethod(function, object, klass)
1420
1422 """
1423 Returns a function identical to the specified function, but with
1424 the specified name.
1425 """
1426 import new
1427
1428
1429
1430
1431 func_defaults = function.func_defaults
1432 if func_defaults is None:
1433 func_defaults = ()
1434
1435 return new.function(function.func_code,
1436 function.func_globals,
1437 name,
1438 func_defaults)
1439
1440
1441 md5 = False
1444
1445 try:
1446 import hashlib
1447 except ImportError:
1448 pass
1449 else:
1450 if hasattr(hashlib, 'md5'):
1451 md5 = True
1456
1458 """
1459 Collects a list of signatures into an aggregate signature.
1460
1461 signatures - a list of signatures
1462 returns - the aggregate signature
1463 """
1464 if len(signatures) == 1:
1465 return signatures[0]
1466 else:
1467 return MD5signature(string.join(signatures, ', '))
1468
1469
1470
1471
1472
1473
1474
1475
1476
1478 """ Null objects always and reliably "do nothging." """
1479
1480 - def __new__(cls, *args, **kwargs):
1481 if not '_inst' in vars(cls):
1482
1483 cls._inst = apply(type.__new__, (cls,) + args, kwargs)
1484 return cls._inst
1499
1500
1501
1502 del __revision__
1503