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 3603 2008/10/10 05:46:45 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 """
1026 return (self, CLVar(other))
1028 return string.join(self.data)
1029
1030
1031
1032
1033
1038
1042
1044 UserDict.__setitem__(self, key, item)
1045 if key not in self._keys: self._keys.append(key)
1046
1048 UserDict.clear(self)
1049 self._keys = []
1050
1055
1058
1060 return self._keys[:]
1061
1063 try:
1064 key = self._keys[-1]
1065 except IndexError:
1066 raise KeyError('dictionary is empty')
1067
1068 val = self[key]
1069 del self[key]
1070
1071 return (key, val)
1072
1074 UserDict.setdefault(self, key, failobj)
1075 if key not in self._keys: self._keys.append(key)
1076
1080
1082 return map(self.get, self._keys)
1083
1085 """A callable ordered dictionary that maps file suffixes to
1086 dictionary values. We preserve the order in which items are added
1087 so that get_suffix() calls always return the first suffix added."""
1089 try:
1090 ext = source[0].suffix
1091 except IndexError:
1092 ext = ""
1093 try:
1094 return self[ext]
1095 except KeyError:
1096
1097
1098 s_dict = {}
1099 for (k,v) in self.items():
1100 if not k is None:
1101 s_k = env.subst(k)
1102 if s_dict.has_key(s_k):
1103
1104
1105
1106
1107 raise KeyError, (s_dict[s_k][0], k, s_k)
1108 s_dict[s_k] = (k,v)
1109 try:
1110 return s_dict[ext][1]
1111 except KeyError:
1112 try:
1113 return self[None]
1114 except KeyError:
1115 return None
1116
1117
1118 if sys.platform == 'cygwin':
1119
1120
1123 else:
1126
1128 if pre:
1129 path, fn = os.path.split(os.path.normpath(fname))
1130 if fn[:len(pre)] != pre:
1131 fname = os.path.join(path, pre + fn)
1132
1133
1134
1135 if suf and fname[-len(suf):] != suf and \
1136 (ensure_suffix or not splitext(fname)[1]):
1137 fname = fname + suf
1138 return fname
1139
1140
1141
1142
1143
1144
1145
1146
1148 """Return a list of the elements in s, but without duplicates.
1149
1150 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1151 unique("abcabc") some permutation of ["a", "b", "c"], and
1152 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1153 [[2, 3], [1, 2]].
1154
1155 For best speed, all sequence elements should be hashable. Then
1156 unique() will usually work in linear time.
1157
1158 If not possible, the sequence elements should enjoy a total
1159 ordering, and if list(s).sort() doesn't raise TypeError it's
1160 assumed that they do enjoy a total ordering. Then unique() will
1161 usually work in O(N*log2(N)) time.
1162
1163 If that's not possible either, the sequence elements must support
1164 equality-testing. Then unique() will usually work in quadratic
1165 time.
1166 """
1167
1168 n = len(s)
1169 if n == 0:
1170 return []
1171
1172
1173
1174
1175
1176 u = {}
1177 try:
1178 for x in s:
1179 u[x] = 1
1180 except TypeError:
1181 pass
1182 else:
1183 return u.keys()
1184 del u
1185
1186
1187
1188
1189
1190
1191
1192
1193 try:
1194 t = list(s)
1195 t.sort()
1196 except TypeError:
1197 pass
1198 else:
1199 assert n > 0
1200 last = t[0]
1201 lasti = i = 1
1202 while i < n:
1203 if t[i] != last:
1204 t[lasti] = last = t[i]
1205 lasti = lasti + 1
1206 i = i + 1
1207 return t[:lasti]
1208 del t
1209
1210
1211 u = []
1212 for x in s:
1213 if x not in u:
1214 u.append(x)
1215 return u
1216
1217
1218
1219
1220
1221
1222
1223
1224
1226 if idfun is None:
1227 def idfun(x): return x
1228 seen = {}
1229 result = []
1230 for item in seq:
1231 marker = idfun(item)
1232
1233
1234
1235 if marker in seen: continue
1236 seen[marker] = 1
1237 result.append(item)
1238 return result
1239
1240
1241
1242
1243
1253
1254
1255
1256
1257
1259
1261 self.fileobj = fileobj
1262
1275
1284
1285
1286
1292 if not self.unique:
1293 self.data = uniquer_hashables(self.data)
1294 self.unique = True
1370 - def sort(self, *args, **kwds):
1377
1378
1379
1381 """
1382 A proxy class that wraps a file object, flushing after every write,
1383 and delegating everything else to the wrapped object.
1384 """
1388 try:
1389 self.file.write(arg)
1390 self.file.flush()
1391 except IOError:
1392
1393
1394
1395
1396
1397
1398
1399 pass
1401 return getattr(self.file, attr)
1402
1404 """ makes an absolute path name to a relative pathname.
1405 """
1406 if os.path.isabs(path):
1407 drive_s,path = os.path.splitdrive(path)
1408
1409 import re
1410 if not drive_s:
1411 path=re.compile("/*(.*)").findall(path)[0]
1412 else:
1413 path=path[1:]
1414
1415 assert( not os.path.isabs( path ) ), path
1416 return path
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444 -def AddMethod(object, function, name = None):
1445 """
1446 Adds either a bound method to an instance or an unbound method to
1447 a class. If name is ommited the name of the specified function
1448 is used by default.
1449 Example:
1450 a = A()
1451 def f(self, x, y):
1452 self.z = x + y
1453 AddMethod(f, A, "add")
1454 a.add(2, 4)
1455 print a.z
1456 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1457 print a.listIndex(5)
1458 """
1459 import new
1460
1461 if name is None:
1462 name = function.func_name
1463 else:
1464 function = RenameFunction(function, name)
1465
1466 try:
1467 klass = object.__class__
1468 except AttributeError:
1469
1470 object.__dict__[name] = new.instancemethod(function, None, object)
1471 else:
1472
1473 object.__dict__[name] = new.instancemethod(function, object, klass)
1474
1476 """
1477 Returns a function identical to the specified function, but with
1478 the specified name.
1479 """
1480 import new
1481
1482
1483
1484
1485 func_defaults = function.func_defaults
1486 if func_defaults is None:
1487 func_defaults = ()
1488
1489 return new.function(function.func_code,
1490 function.func_globals,
1491 name,
1492 func_defaults)
1493
1494
1495 md5 = False
1498
1504
1505 try:
1506 import hashlib
1507 except ImportError:
1508 pass
1509 else:
1510 if hasattr(hashlib, 'md5'):
1511 md5 = True
1516
1518 m = hashlib.md5()
1519 f = open(fname, "rb")
1520 while 1:
1521 blck = f.read(chunksize)
1522 if not blck:
1523 break
1524 m.update(str(blck))
1525 f.close()
1526 return m.hexdigest()
1527
1529 """
1530 Collects a list of signatures into an aggregate signature.
1531
1532 signatures - a list of signatures
1533 returns - the aggregate signature
1534 """
1535 if len(signatures) == 1:
1536 return signatures[0]
1537 else:
1538 return MD5signature(string.join(signatures, ', '))
1539
1540
1541
1542
1543
1544
1545
1546
1547
1549 """ Null objects always and reliably "do nothging." """
1550
1551 - def __new__(cls, *args, **kwargs):
1552 if not '_inst' in vars(cls):
1553
1554 cls._inst = apply(type.__new__, (cls,) + args, kwargs)
1555 return cls._inst
1570
1571
1572
1573 del __revision__
1574