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 3842 2008/12/20 22:59:52 scons"
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
45
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={}):
56
57 _altsep = os.altsep
58 if _altsep is None and sys.platform == 'win32':
59
60 _altsep = '/'
61 if _altsep:
65 else:
66 rightmost_separator = string.rfind
67
68
69
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
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
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
89 "Same as os.path.splitext() but faster."
90 sep = rightmost_separator(path, os.sep)
91 dot = string.rfind(path, '.')
92
93 if dot > sep and not containsOnly(path[dot:], "0123456789."):
94 return path[:dot],path[dot:]
95 else:
96 return path,""
97
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
111 """A simple composite callable class that, when called, will invoke all
112 of its contained callables with the same arguments."""
114 retvals = map(lambda x, args=args, kwargs=kwargs: apply(x,
115 args,
116 kwargs),
117 self.data)
118 if self.data and (len(self.data) == len(filter(callable, retvals))):
119 return self.__class__(retvals)
120 return NodeList(retvals)
121
123 """This class is almost exactly like a regular list of Nodes
124 (actually it can hold any object), with one important difference.
125 If you try to get an attribute from this list, it will return that
126 attribute from every item in the list. For example:
127
128 >>> someList = NodeList([ ' foo ', ' bar ' ])
129 >>> someList.strip()
130 [ 'foo', 'bar' ]
131 """
133 return len(self.data) != 0
134
136 return string.join(map(str, self.data))
137
139 if not self.data:
140
141
142 raise AttributeError, "NodeList has no attribute: %s" % name
143
144
145
146 attrList = map(lambda x, n=name: getattr(x, n), self.data)
147
148
149
150
151
152 if self.data and (len(self.data) == len(filter(callable, attrList))):
153 return CallableComposite(attrList)
154 return self.__class__(attrList)
155
156 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
157
159 """Given a string, first determine if it looks like a reference
160 to a single environment variable, like "$FOO" or "${FOO}".
161 If so, return that variable with no decorations ("FOO").
162 If not, return None."""
163 mo=_get_env_var.match(to_String(varstr))
164 if mo:
165 var = mo.group(1)
166 if var[0] == '{':
167 return var[1:-1]
168 else:
169 return var
170 else:
171 return None
172
176
177 - def print_it(self, text, append_newline=1):
178 if append_newline: text = text + '\n'
179 try:
180 sys.stdout.write(text)
181 except IOError:
182
183
184
185
186
187
188
189 pass
190
193
199
200 -def render_tree(root, child_func, prune=0, margin=[0], visited={}):
201 """
202 Render a tree of nodes into an ASCII tree view.
203 root - the root node of the tree
204 child_func - the function called to get the children of a node
205 prune - don't visit the same node twice
206 margin - the format of the left margin to use for children of root.
207 1 results in a pipe, and 0 results in no pipe.
208 visited - a dictionary of visited nodes in the current branch if not prune,
209 or in the whole tree if prune.
210 """
211
212 rname = str(root)
213
214 children = child_func(root)
215 retval = ""
216 for pipe in margin[:-1]:
217 if pipe:
218 retval = retval + "| "
219 else:
220 retval = retval + " "
221
222 if visited.has_key(rname):
223 return retval + "+-[" + rname + "]\n"
224
225 retval = retval + "+-" + rname + "\n"
226 if not prune:
227 visited = copy.copy(visited)
228 visited[rname] = 1
229
230 for i in range(len(children)):
231 margin.append(i<len(children)-1)
232 retval = retval + render_tree(children[i], child_func, prune, margin, visited
233 )
234 margin.pop()
235
236 return retval
237
238 IDX = lambda N: N and 1 or 0
239
240 -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
241 """
242 Print a tree of nodes. This is like render_tree, except it prints
243 lines directly instead of creating a string representation in memory,
244 so that huge trees can be printed.
245
246 root - the root node of the tree
247 child_func - the function called to get the children of a node
248 prune - don't visit the same node twice
249 showtags - print status information to the left of each node line
250 margin - the format of the left margin to use for children of root.
251 1 results in a pipe, and 0 results in no pipe.
252 visited - a dictionary of visited nodes in the current branch if not prune,
253 or in the whole tree if prune.
254 """
255
256 rname = str(root)
257
258 if showtags:
259
260 if showtags == 2:
261 print ' E = exists'
262 print ' R = exists in repository only'
263 print ' b = implicit builder'
264 print ' B = explicit builder'
265 print ' S = side effect'
266 print ' P = precious'
267 print ' A = always build'
268 print ' C = current'
269 print ' N = no clean'
270 print ' H = no cache'
271 print ''
272
273 tags = ['[']
274 tags.append(' E'[IDX(root.exists())])
275 tags.append(' R'[IDX(root.rexists() and not root.exists())])
276 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
277 [0,2][IDX(root.has_builder())]])
278 tags.append(' S'[IDX(root.side_effect)])
279 tags.append(' P'[IDX(root.precious)])
280 tags.append(' A'[IDX(root.always_build)])
281 tags.append(' C'[IDX(root.is_up_to_date())])
282 tags.append(' N'[IDX(root.noclean)])
283 tags.append(' H'[IDX(root.nocache)])
284 tags.append(']')
285
286 else:
287 tags = []
288
289 def MMM(m):
290 return [" ","| "][m]
291 margins = map(MMM, margin[:-1])
292
293 children = child_func(root)
294
295 if prune and visited.has_key(rname) and children:
296 print string.join(tags + margins + ['+-[', rname, ']'], '')
297 return
298
299 print string.join(tags + margins + ['+-', rname], '')
300
301 visited[rname] = 1
302
303 if children:
304 margin.append(1)
305 map(lambda C, cf=child_func, p=prune, i=IDX(showtags), m=margin, v=visited:
306 print_tree(C, cf, p, i, m, v),
307 children[:-1])
308 margin[-1] = 0
309 print_tree(children[-1], child_func, prune, IDX(showtags), margin, visited)
310 margin.pop()
311
312
313
314
315
316
317
318
319
320
321
322 try:
325 except TypeError:
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
346 t = type(obj)
347 return t is DictType or \
348 (t is InstanceType and isinstance(obj, UserDict))
349
351 t = type(obj)
352 return t is ListType \
353 or (t is InstanceType and isinstance(obj, UserList))
354
356 t = type(obj)
357 return t is ListType \
358 or t is TupleType \
359 or (t is InstanceType and isinstance(obj, UserList))
360
362 t = type(obj)
363 return t is TupleType
364
365 if hasattr(types, 'UnicodeType'):
367 t = type(obj)
368 return t is StringType \
369 or t is UnicodeType \
370 or (t is InstanceType and isinstance(obj, UserString))
371 else:
373 t = type(obj)
374 return t is StringType \
375 or (t is InstanceType and isinstance(obj, UserString))
376
378 return is_String(obj) or not is_Sequence(obj)
379
381 """Flatten a sequence to a non-nested list.
382
383 Flatten() converts either a single scalar or a nested sequence
384 to a non-nested list. Note that flatten() considers strings
385 to be scalars instead of sequences like Python would.
386 """
387 if is_Scalar(obj):
388 return [obj]
389 if result is None:
390 result = []
391 for item in obj:
392 if is_Scalar(item):
393 result.append(item)
394 else:
395 flatten_sequence(item, result)
396 return result
397
399 """Flatten a sequence to a non-nested list.
400
401 Same as flatten(), but it does not handle the single scalar
402 case. This is slightly more efficient when one knows that
403 the sequence to flatten can not be a scalar.
404 """
405 if result is None:
406 result = []
407 for item in sequence:
408 if is_Scalar(item):
409 result.append(item)
410 else:
411 flatten_sequence(item, result)
412 return result
413
414
415
416
417
418
419
420 if hasattr(types, 'UnicodeType'):
421 UnicodeType = types.UnicodeType
423 if isinstance(s, UserString):
424 t = type(s.data)
425 else:
426 t = type(s)
427 if t is UnicodeType:
428 return unicode(s)
429 else:
430 return str(s)
431 else:
432 to_String = str
433
435 try:
436 f = obj.for_signature
437 except AttributeError:
438 return to_String_for_subst(obj)
439 else:
440 return f()
441
443 if is_Sequence( s ):
444 return string.join( map(to_String_for_subst, s) )
445
446 return to_String( s )
447
448 else:
449
450
451
452
453
454
455
456
457
458 DictTypes = (dict, UserDict)
459 ListTypes = (list, UserList)
460 SequenceTypes = (list, tuple, UserList)
461
462
463
464
465
466
467
468 StringTypes = (str, unicode, UserString)
469
470
471
472 BaseStringTypes = (str, unicode)
473
476
479
482
483 - def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
484 return isinstance(obj, tuple)
485
488
497
505
508 """Flatten a sequence to a non-nested list.
509
510 Flatten() converts either a single scalar or a nested sequence
511 to a non-nested list. Note that flatten() considers strings
512 to be scalars instead of sequences like Python would.
513 """
514 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
515 return [obj]
516 result = []
517 for item in obj:
518 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
519 result.append(item)
520 else:
521 do_flatten(item, result)
522 return result
523
526 """Flatten a sequence to a non-nested list.
527
528 Same as flatten(), but it does not handle the single scalar
529 case. This is slightly more efficient when one knows that
530 the sequence to flatten can not be a scalar.
531 """
532 result = []
533 for item in sequence:
534 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
535 result.append(item)
536 else:
537 do_flatten(item, result)
538 return result
539
540
541
542
543
544
545
546
550 if isinstance(s,BaseStringTypes):
551
552 return s
553 elif isinstance(s, UserString):
554
555
556 return s.data
557 else:
558 return str(s)
559
564
565
566 if isinstance(s, BaseStringTypes):
567 return s
568 elif isinstance(s, SequenceTypes):
569 l = []
570 for e in s:
571 l.append(to_String_for_subst(e))
572 return join( s )
573 elif isinstance(s, UserString):
574
575
576 return s.data
577 else:
578 return str(s)
579
582 try:
583 f = obj.for_signature
584 except AttributeError:
585 return to_String_for_subst(obj)
586 else:
587 return f()
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604 _semi_deepcopy_dispatch = d = {}
605
607 copy = {}
608 for key, val in x.items():
609
610
611
612
613
614
615 copy[key] = semi_deepcopy(val)
616 return copy
617 d[types.DictionaryType] = _semi_deepcopy_dict
618
620 return map(semi_deepcopy, x)
621 d[types.ListType] = _semi_deepcopy_list
622
624 return tuple(map(semi_deepcopy, x))
625 d[types.TupleType] = _semi_deepcopy_tuple
626
628 if hasattr(x, '__semi_deepcopy__'):
629 return x.__semi_deepcopy__()
630 elif isinstance(x, UserDict):
631 return x.__class__(_semi_deepcopy_dict(x))
632 elif isinstance(x, UserList):
633 return x.__class__(_semi_deepcopy_list(x))
634 else:
635 return x
636 d[types.InstanceType] = _semi_deepcopy_inst
637
644
645
646
648 """A simple generic Proxy class, forwarding all calls to
649 subject. So, for the benefit of the python newbie, what does
650 this really mean? Well, it means that you can take an object, let's
651 call it 'objA', and wrap it in this Proxy class, with a statement
652 like this
653
654 proxyObj = Proxy(objA),
655
656 Then, if in the future, you do something like this
657
658 x = proxyObj.var1,
659
660 since Proxy does not have a 'var1' attribute (but presumably objA does),
661 the request actually is equivalent to saying
662
663 x = objA.var1
664
665 Inherit from this class to create a Proxy."""
666
668 """Wrap an object as a Proxy object"""
669 self.__subject = subject
670
672 """Retrieve an attribute from the wrapped object. If the named
673 attribute doesn't exist, AttributeError is raised"""
674 return getattr(self.__subject, name)
675
677 """Retrieve the entire wrapped object"""
678 return self.__subject
679
681 if issubclass(other.__class__, self.__subject.__class__):
682 return cmp(self.__subject, other)
683 return cmp(self.__dict__, other.__dict__)
684
685
686 can_read_reg = 0
687 try:
688 import _winreg
689
690 can_read_reg = 1
691 hkey_mod = _winreg
692
693 RegOpenKeyEx = _winreg.OpenKeyEx
694 RegEnumKey = _winreg.EnumKey
695 RegEnumValue = _winreg.EnumValue
696 RegQueryValueEx = _winreg.QueryValueEx
697 RegError = _winreg.error
698
699 except ImportError:
700 try:
701 import win32api
702 import win32con
703 can_read_reg = 1
704 hkey_mod = win32con
705
706 RegOpenKeyEx = win32api.RegOpenKeyEx
707 RegEnumKey = win32api.RegEnumKey
708 RegEnumValue = win32api.RegEnumValue
709 RegQueryValueEx = win32api.RegQueryValueEx
710 RegError = win32api.error
711
712 except ImportError:
715 RegError = _NoError
716
717 if can_read_reg:
718 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
719 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
720 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
721 HKEY_USERS = hkey_mod.HKEY_USERS
722
724 """This utility function returns a value in the registry
725 without having to open the key first. Only available on
726 Windows platforms with a version of Python that can read the
727 registry. Returns the same thing as
728 SCons.Util.RegQueryValueEx, except you just specify the entire
729 path to the value, and don't have to bother opening the key
730 first. So:
731
732 Instead of:
733 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
734 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
735 out = SCons.Util.RegQueryValueEx(k,
736 'ProgramFilesDir')
737
738 You can write:
739 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
740 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
741 """
742
743
744 p = key.rfind('\\') + 1
745 keyp = key[:p]
746 val = key[p:]
747 k = RegOpenKeyEx(root, keyp)
748 return RegQueryValueEx(k,val)
749
750 if sys.platform == 'win32':
751
752 - def WhereIs(file, path=None, pathext=None, reject=[]):
753 if path is None:
754 try:
755 path = os.environ['PATH']
756 except KeyError:
757 return None
758 if is_String(path):
759 path = string.split(path, os.pathsep)
760 if pathext is None:
761 try:
762 pathext = os.environ['PATHEXT']
763 except KeyError:
764 pathext = '.COM;.EXE;.BAT;.CMD'
765 if is_String(pathext):
766 pathext = string.split(pathext, os.pathsep)
767 for ext in pathext:
768 if string.lower(ext) == string.lower(file[-len(ext):]):
769 pathext = ['']
770 break
771 if not is_List(reject) and not is_Tuple(reject):
772 reject = [reject]
773 for dir in path:
774 f = os.path.join(dir, file)
775 for ext in pathext:
776 fext = f + ext
777 if os.path.isfile(fext):
778 try:
779 reject.index(fext)
780 except ValueError:
781 return os.path.normpath(fext)
782 continue
783 return None
784
785 elif os.name == 'os2':
786
787 - def WhereIs(file, path=None, pathext=None, reject=[]):
788 if path is None:
789 try:
790 path = os.environ['PATH']
791 except KeyError:
792 return None
793 if is_String(path):
794 path = string.split(path, os.pathsep)
795 if pathext is None:
796 pathext = ['.exe', '.cmd']
797 for ext in pathext:
798 if string.lower(ext) == string.lower(file[-len(ext):]):
799 pathext = ['']
800 break
801 if not is_List(reject) and not is_Tuple(reject):
802 reject = [reject]
803 for dir in path:
804 f = os.path.join(dir, file)
805 for ext in pathext:
806 fext = f + ext
807 if os.path.isfile(fext):
808 try:
809 reject.index(fext)
810 except ValueError:
811 return os.path.normpath(fext)
812 continue
813 return None
814
815 else:
816
817 - def WhereIs(file, path=None, pathext=None, reject=[]):
846
848 """This prepends newpath elements to the given oldpath. Will only
849 add any particular path once (leaving the first one it encounters
850 and ignoring the rest, to preserve path order), and will
851 os.path.normpath and os.path.normcase all paths to help assure
852 this. This can also handle the case where the given old path
853 variable is a list instead of a string, in which case a list will
854 be returned instead of a string.
855
856 Example:
857 Old Path: "/foo/bar:/foo"
858 New Path: "/biz/boom:/foo"
859 Result: "/biz/boom:/foo:/foo/bar"
860
861 If delete_existing is 0, then adding a path that exists will
862 not move it to the beginning; it will stay where it is in the
863 list.
864 """
865
866 orig = oldpath
867 is_list = 1
868 paths = orig
869 if not is_List(orig) and not is_Tuple(orig):
870 paths = string.split(paths, sep)
871 is_list = 0
872
873 if is_List(newpath) or is_Tuple(newpath):
874 newpaths = newpath
875 else:
876 newpaths = string.split(newpath, sep)
877
878 if not delete_existing:
879
880
881
882
883
884 result = []
885 normpaths = []
886 for path in paths:
887 if not path:
888 continue
889 normpath = os.path.normpath(os.path.normcase(path))
890 if normpath not in normpaths:
891 result.append(path)
892 normpaths.append(normpath)
893 newpaths.reverse()
894 for path in newpaths:
895 if not path:
896 continue
897 normpath = os.path.normpath(os.path.normcase(path))
898 if normpath not in normpaths:
899 result.insert(0, path)
900 normpaths.append(normpath)
901 paths = result
902
903 else:
904 newpaths = newpaths + paths
905
906 normpaths = []
907 paths = []
908
909 for path in newpaths:
910 normpath = os.path.normpath(os.path.normcase(path))
911 if path and not normpath in normpaths:
912 paths.append(path)
913 normpaths.append(normpath)
914
915 if is_list:
916 return paths
917 else:
918 return string.join(paths, sep)
919
921 """This appends new path elements to the given old path. Will
922 only add any particular path once (leaving the last one it
923 encounters and ignoring the rest, to preserve path order), and
924 will os.path.normpath and os.path.normcase all paths to help
925 assure this. This can also handle the case where the given old
926 path variable is a list instead of a string, in which case a list
927 will be returned instead of a string.
928
929 Example:
930 Old Path: "/foo/bar:/foo"
931 New Path: "/biz/boom:/foo"
932 Result: "/foo/bar:/biz/boom:/foo"
933
934 If delete_existing is 0, then adding a path that exists
935 will not move it to the end; it will stay where it is in the list.
936 """
937
938 orig = oldpath
939 is_list = 1
940 paths = orig
941 if not is_List(orig) and not is_Tuple(orig):
942 paths = string.split(paths, sep)
943 is_list = 0
944
945 if is_List(newpath) or is_Tuple(newpath):
946 newpaths = newpath
947 else:
948 newpaths = string.split(newpath, sep)
949
950 if not delete_existing:
951
952
953
954
955
956 result = []
957 normpaths = []
958 for path in paths:
959 if not path:
960 continue
961 result.append(path)
962 normpaths.append(os.path.normpath(os.path.normcase(path)))
963 for path in newpaths:
964 if not path:
965 continue
966 normpath = os.path.normpath(os.path.normcase(path))
967 if normpath not in normpaths:
968 result.append(path)
969 normpaths.append(normpath)
970 paths = result
971 else:
972
973
974 newpaths = paths + newpaths
975 newpaths.reverse()
976
977 normpaths = []
978 paths = []
979
980 for path in newpaths:
981 normpath = os.path.normpath(os.path.normcase(path))
982 if path and not normpath in normpaths:
983 paths.append(path)
984 normpaths.append(normpath)
985 paths.reverse()
986
987 if is_list:
988 return paths
989 else:
990 return string.join(paths, sep)
991
992 if sys.platform == 'cygwin':
994 """Transforms an absolute path into a native path for the system. In
995 Cygwin, this converts from a Cygwin path to a Windows one."""
996 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
997 else:
999 """Transforms an absolute path into a native path for the system.
1000 Non-Cygwin version, just leave the path alone."""
1001 return path
1002
1003 display = DisplayEngine()
1004
1006 if is_List(arg) or is_Tuple(arg):
1007 return arg
1008 elif is_String(arg):
1009 return string.split(arg)
1010 else:
1011 return [arg]
1012
1014 """A class for command-line construction variables.
1015
1016 This is a list that uses Split() to split an initial string along
1017 white-space arguments, and similarly to split any strings that get
1018 added. This allows us to Do the Right Thing with Append() and
1019 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
1020 arg2') regardless of whether a user adds a list or a string to a
1021 command-line construction variable.
1022 """
1030 return (self, CLVar(other))
1032 return string.join(self.data)
1033
1034
1035
1036
1037
1042
1046
1048 UserDict.__setitem__(self, key, item)
1049 if key not in self._keys: self._keys.append(key)
1050
1052 UserDict.clear(self)
1053 self._keys = []
1054
1059
1062
1064 return self._keys[:]
1065
1067 try:
1068 key = self._keys[-1]
1069 except IndexError:
1070 raise KeyError('dictionary is empty')
1071
1072 val = self[key]
1073 del self[key]
1074
1075 return (key, val)
1076
1078 UserDict.setdefault(self, key, failobj)
1079 if key not in self._keys: self._keys.append(key)
1080
1084
1086 return map(self.get, self._keys)
1087
1089 """A callable ordered dictionary that maps file suffixes to
1090 dictionary values. We preserve the order in which items are added
1091 so that get_suffix() calls always return the first suffix added."""
1093 try:
1094 ext = source[0].suffix
1095 except IndexError:
1096 ext = ""
1097 try:
1098 return self[ext]
1099 except KeyError:
1100
1101
1102 s_dict = {}
1103 for (k,v) in self.items():
1104 if not k is None:
1105 s_k = env.subst(k)
1106 if s_dict.has_key(s_k):
1107
1108
1109
1110
1111 raise KeyError, (s_dict[s_k][0], k, s_k)
1112 s_dict[s_k] = (k,v)
1113 try:
1114 return s_dict[ext][1]
1115 except KeyError:
1116 try:
1117 return self[None]
1118 except KeyError:
1119 return None
1120
1121
1122 if sys.platform == 'cygwin':
1123
1124
1127 else:
1130
1132 if pre:
1133 path, fn = os.path.split(os.path.normpath(fname))
1134 if fn[:len(pre)] != pre:
1135 fname = os.path.join(path, pre + fn)
1136
1137
1138
1139 if suf and fname[-len(suf):] != suf and \
1140 (ensure_suffix or not splitext(fname)[1]):
1141 fname = fname + suf
1142 return fname
1143
1144
1145
1146
1147
1148
1149
1150
1152 """Return a list of the elements in s, but without duplicates.
1153
1154 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1155 unique("abcabc") some permutation of ["a", "b", "c"], and
1156 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1157 [[2, 3], [1, 2]].
1158
1159 For best speed, all sequence elements should be hashable. Then
1160 unique() will usually work in linear time.
1161
1162 If not possible, the sequence elements should enjoy a total
1163 ordering, and if list(s).sort() doesn't raise TypeError it's
1164 assumed that they do enjoy a total ordering. Then unique() will
1165 usually work in O(N*log2(N)) time.
1166
1167 If that's not possible either, the sequence elements must support
1168 equality-testing. Then unique() will usually work in quadratic
1169 time.
1170 """
1171
1172 n = len(s)
1173 if n == 0:
1174 return []
1175
1176
1177
1178
1179
1180 u = {}
1181 try:
1182 for x in s:
1183 u[x] = 1
1184 except TypeError:
1185 pass
1186 else:
1187 return u.keys()
1188 del u
1189
1190
1191
1192
1193
1194
1195
1196
1197 try:
1198 t = list(s)
1199 t.sort()
1200 except TypeError:
1201 pass
1202 else:
1203 assert n > 0
1204 last = t[0]
1205 lasti = i = 1
1206 while i < n:
1207 if t[i] != last:
1208 t[lasti] = last = t[i]
1209 lasti = lasti + 1
1210 i = i + 1
1211 return t[:lasti]
1212 del t
1213
1214
1215 u = []
1216 for x in s:
1217 if x not in u:
1218 u.append(x)
1219 return u
1220
1221
1222
1223
1224
1225
1226
1227
1228
1230 if idfun is None:
1231 def idfun(x): return x
1232 seen = {}
1233 result = []
1234 for item in seq:
1235 marker = idfun(item)
1236
1237
1238
1239 if marker in seen: continue
1240 seen[marker] = 1
1241 result.append(item)
1242 return result
1243
1244
1245
1246
1247
1257
1258
1259
1260
1261
1263
1265 self.fileobj = fileobj
1266
1279
1288
1289
1290
1296 if not self.unique:
1297 self.data = uniquer_hashables(self.data)
1298 self.unique = True
1374 - def sort(self, *args, **kwds):
1381
1382
1383
1385 """
1386 A proxy class that wraps a file object, flushing after every write,
1387 and delegating everything else to the wrapped object.
1388 """
1392 try:
1393 self.file.write(arg)
1394 self.file.flush()
1395 except IOError:
1396
1397
1398
1399
1400
1401
1402
1403 pass
1405 return getattr(self.file, attr)
1406
1408 """ makes an absolute path name to a relative pathname.
1409 """
1410 if os.path.isabs(path):
1411 drive_s,path = os.path.splitdrive(path)
1412
1413 import re
1414 if not drive_s:
1415 path=re.compile("/*(.*)").findall(path)[0]
1416 else:
1417 path=path[1:]
1418
1419 assert( not os.path.isabs( path ) ), path
1420 return path
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448 -def AddMethod(object, function, name = None):
1449 """
1450 Adds either a bound method to an instance or an unbound method to
1451 a class. If name is ommited the name of the specified function
1452 is used by default.
1453 Example:
1454 a = A()
1455 def f(self, x, y):
1456 self.z = x + y
1457 AddMethod(f, A, "add")
1458 a.add(2, 4)
1459 print a.z
1460 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1461 print a.listIndex(5)
1462 """
1463 import new
1464
1465 if name is None:
1466 name = function.func_name
1467 else:
1468 function = RenameFunction(function, name)
1469
1470 try:
1471 klass = object.__class__
1472 except AttributeError:
1473
1474 object.__dict__[name] = new.instancemethod(function, None, object)
1475 else:
1476
1477 object.__dict__[name] = new.instancemethod(function, object, klass)
1478
1480 """
1481 Returns a function identical to the specified function, but with
1482 the specified name.
1483 """
1484 import new
1485
1486
1487
1488
1489 func_defaults = function.func_defaults
1490 if func_defaults is None:
1491 func_defaults = ()
1492
1493 return new.function(function.func_code,
1494 function.func_globals,
1495 name,
1496 func_defaults)
1497
1498
1499 md5 = False
1502
1508
1509 try:
1510 import hashlib
1511 except ImportError:
1512 pass
1513 else:
1514 if hasattr(hashlib, 'md5'):
1515 md5 = True
1520
1522 m = hashlib.md5()
1523 f = open(fname, "rb")
1524 while 1:
1525 blck = f.read(chunksize)
1526 if not blck:
1527 break
1528 m.update(str(blck))
1529 f.close()
1530 return m.hexdigest()
1531
1533 """
1534 Collects a list of signatures into an aggregate signature.
1535
1536 signatures - a list of signatures
1537 returns - the aggregate signature
1538 """
1539 if len(signatures) == 1:
1540 return signatures[0]
1541 else:
1542 return MD5signature(string.join(signatures, ', '))
1543
1544
1545
1546
1547
1548
1549
1550
1551
1553 """ Null objects always and reliably "do nothging." """
1554
1555 - def __new__(cls, *args, **kwargs):
1556 if not '_inst' in vars(cls):
1557
1558 cls._inst = apply(type.__new__, (cls,) + args, kwargs)
1559 return cls._inst
1574
1575
1576
1577 del __revision__
1578