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 __revision__ = "src/engine/SCons/Util.py 5023 2010/06/14 22:05:46 scons"
28
29 import os
30 import sys
31 import copy
32 import re
33 import types
34
35 from collections import UserDict, UserList, UserString
36
37
38
39 InstanceType = types.InstanceType
40 MethodType = types.MethodType
41 FunctionType = types.FunctionType
42 try: unicode
43 except NameError: UnicodeType = None
44 else: UnicodeType = unicode
45
46 -def dictify(keys, values, result={}):
50
51 _altsep = os.altsep
52 if _altsep is None and sys.platform == 'win32':
53
54 _altsep = '/'
55 if _altsep:
58 else:
61
62
63
65 """Check whether sequence str contains ANY of the items in set."""
66 for c in set:
67 if c in str: return 1
68 return 0
69
71 """Check whether sequence str contains ALL of the items in set."""
72 for c in set:
73 if c not in str: return 0
74 return 1
75
77 """Check whether sequence str contains ONLY items in set."""
78 for c in str:
79 if c not in set: return 0
80 return 1
81
83 "Same as os.path.splitext() but faster."
84 sep = rightmost_separator(path, os.sep)
85 dot = path.rfind('.')
86
87 if dot > sep and not containsOnly(path[dot:], "0123456789."):
88 return path[:dot],path[dot:]
89 else:
90 return path,""
91
93 """
94 Make the drive letter (if any) upper case.
95 This is useful because Windows is inconsitent on the case
96 of the drive letter, which can cause inconsistencies when
97 calculating command signatures.
98 """
99 drive, rest = os.path.splitdrive(path)
100 if drive:
101 path = drive.upper() + rest
102 return path
103
105 """This class is almost exactly like a regular list of Nodes
106 (actually it can hold any object), with one important difference.
107 If you try to get an attribute from this list, it will return that
108 attribute from every item in the list. For example:
109
110 >>> someList = NodeList([ ' foo ', ' bar ' ])
111 >>> someList.strip()
112 [ 'foo', 'bar' ]
113 """
115 return len(self.data) != 0
116
118 return ' '.join(map(str, self.data))
119
121 return iter(self.data)
122
124 result = [x(*args, **kwargs) for x in self.data]
125 return self.__class__(result)
126
130
131
132 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
133
135 """Given a string, first determine if it looks like a reference
136 to a single environment variable, like "$FOO" or "${FOO}".
137 If so, return that variable with no decorations ("FOO").
138 If not, return None."""
139 mo=_get_env_var.match(to_String(varstr))
140 if mo:
141 var = mo.group(1)
142 if var[0] == '{':
143 return var[1:-1]
144 else:
145 return var
146 else:
147 return None
148
150 print_it = True
151 - def __call__(self, text, append_newline=1):
152 if not self.print_it:
153 return
154 if append_newline: text = text + '\n'
155 try:
156 sys.stdout.write(unicode(text))
157 except IOError:
158
159
160
161
162
163
164
165 pass
166
169
170 -def render_tree(root, child_func, prune=0, margin=[0], visited={}):
171 """
172 Render a tree of nodes into an ASCII tree view.
173 root - the root node of the tree
174 child_func - the function called to get the children of a node
175 prune - don't visit the same node twice
176 margin - the format of the left margin to use for children of root.
177 1 results in a pipe, and 0 results in no pipe.
178 visited - a dictionary of visited nodes in the current branch if not prune,
179 or in the whole tree if prune.
180 """
181
182 rname = str(root)
183
184 children = child_func(root)
185 retval = ""
186 for pipe in margin[:-1]:
187 if pipe:
188 retval = retval + "| "
189 else:
190 retval = retval + " "
191
192 if rname in visited:
193 return retval + "+-[" + rname + "]\n"
194
195 retval = retval + "+-" + rname + "\n"
196 if not prune:
197 visited = copy.copy(visited)
198 visited[rname] = 1
199
200 for i in range(len(children)):
201 margin.append(i<len(children)-1)
202 retval = retval + render_tree(children[i], child_func, prune, margin, visited
203 )
204 margin.pop()
205
206 return retval
207
208 IDX = lambda N: N and 1 or 0
209
210 -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
211 """
212 Print a tree of nodes. This is like render_tree, except it prints
213 lines directly instead of creating a string representation in memory,
214 so that huge trees can be printed.
215
216 root - the root node of the tree
217 child_func - the function called to get the children of a node
218 prune - don't visit the same node twice
219 showtags - print status information to the left of each node line
220 margin - the format of the left margin to use for children of root.
221 1 results in a pipe, and 0 results in no pipe.
222 visited - a dictionary of visited nodes in the current branch if not prune,
223 or in the whole tree if prune.
224 """
225
226 rname = str(root)
227
228 if showtags:
229
230 if showtags == 2:
231 legend = (' E = exists\n' +
232 ' R = exists in repository only\n' +
233 ' b = implicit builder\n' +
234 ' B = explicit builder\n' +
235 ' S = side effect\n' +
236 ' P = precious\n' +
237 ' A = always build\n' +
238 ' C = current\n' +
239 ' N = no clean\n' +
240 ' H = no cache\n' +
241 '\n')
242 sys.stdout.write(unicode(legend))
243
244 tags = ['[']
245 tags.append(' E'[IDX(root.exists())])
246 tags.append(' R'[IDX(root.rexists() and not root.exists())])
247 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
248 [0,2][IDX(root.has_builder())]])
249 tags.append(' S'[IDX(root.side_effect)])
250 tags.append(' P'[IDX(root.precious)])
251 tags.append(' A'[IDX(root.always_build)])
252 tags.append(' C'[IDX(root.is_up_to_date())])
253 tags.append(' N'[IDX(root.noclean)])
254 tags.append(' H'[IDX(root.nocache)])
255 tags.append(']')
256
257 else:
258 tags = []
259
260 def MMM(m):
261 return [" ","| "][m]
262 margins = list(map(MMM, margin[:-1]))
263
264 children = child_func(root)
265
266 if prune and rname in visited and children:
267 sys.stdout.write(''.join(tags + margins + ['+-[', rname, ']']) + u'\n')
268 return
269
270 sys.stdout.write(''.join(tags + margins + ['+-', rname]) + u'\n')
271
272 visited[rname] = 1
273
274 if children:
275 margin.append(1)
276 idx = IDX(showtags)
277 for C in children[:-1]:
278 print_tree(C, child_func, prune, idx, margin, visited)
279 margin[-1] = 0
280 print_tree(children[-1], child_func, prune, idx, margin, visited)
281 margin.pop()
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 DictTypes = (dict, UserDict)
300 ListTypes = (list, UserList)
301 SequenceTypes = (list, tuple, UserList)
302
303
304
305
306 StringTypes = (str, unicode, UserString)
307
308
309
310 BaseStringTypes = (str, unicode)
311
314
317
320
321 -def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
322 return isinstance(obj, tuple)
323
326
335
343
346 """Flatten a sequence to a non-nested list.
347
348 Flatten() converts either a single scalar or a nested sequence
349 to a non-nested list. Note that flatten() considers strings
350 to be scalars instead of sequences like Python would.
351 """
352 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
353 return [obj]
354 result = []
355 for item in obj:
356 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
357 result.append(item)
358 else:
359 do_flatten(item, result)
360 return result
361
364 """Flatten a sequence to a non-nested list.
365
366 Same as flatten(), but it does not handle the single scalar
367 case. This is slightly more efficient when one knows that
368 the sequence to flatten can not be a scalar.
369 """
370 result = []
371 for item in sequence:
372 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
373 result.append(item)
374 else:
375 do_flatten(item, result)
376 return result
377
378
379
380
381
382
386 if isinstance(s,BaseStringTypes):
387
388 return s
389 elif isinstance(s, UserString):
390
391
392 return s.data
393 else:
394 return str(s)
395
400
401
402 if isinstance(s, BaseStringTypes):
403 return s
404 elif isinstance(s, SequenceTypes):
405 l = []
406 for e in s:
407 l.append(to_String_for_subst(e))
408 return ' '.join( s )
409 elif isinstance(s, UserString):
410
411
412 return s.data
413 else:
414 return str(s)
415
418 try:
419 f = obj.for_signature
420 except AttributeError:
421 return to_String_for_subst(obj)
422 else:
423 return f()
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439 _semi_deepcopy_dispatch = d = {}
440
442 copy = {}
443 for key, val in x.items():
444
445
446
447
448
449
450 copy[key] = semi_deepcopy(val)
451 return copy
452 d[dict] = _semi_deepcopy_dict
453
455 return list(map(semi_deepcopy, x))
456 d[list] = _semi_deepcopy_list
457
459 return tuple(map(semi_deepcopy, x))
460 d[tuple] = _semi_deepcopy_tuple
461
463 if hasattr(x, '__semi_deepcopy__'):
464 return x.__semi_deepcopy__()
465 elif isinstance(x, UserDict):
466 return x.__class__(_semi_deepcopy_dict(x))
467 elif isinstance(x, UserList):
468 return x.__class__(_semi_deepcopy_list(x))
469 else:
470 return x
471 d[InstanceType] = _semi_deepcopy_inst
472
479
480
481
483 """A simple generic Proxy class, forwarding all calls to
484 subject. So, for the benefit of the python newbie, what does
485 this really mean? Well, it means that you can take an object, let's
486 call it 'objA', and wrap it in this Proxy class, with a statement
487 like this
488
489 proxyObj = Proxy(objA),
490
491 Then, if in the future, you do something like this
492
493 x = proxyObj.var1,
494
495 since Proxy does not have a 'var1' attribute (but presumably objA does),
496 the request actually is equivalent to saying
497
498 x = objA.var1
499
500 Inherit from this class to create a Proxy.
501
502 Note that, with new-style classes, this does *not* work transparently
503 for Proxy subclasses that use special .__*__() method names, because
504 those names are now bound to the class, not the individual instances.
505 You now need to know in advance which .__*__() method names you want
506 to pass on to the underlying Proxy object, and specifically delegate
507 their calls like this:
508
509 class Foo(Proxy):
510 __str__ = Delegate('__str__')
511 """
512
514 """Wrap an object as a Proxy object"""
515 self._subject = subject
516
518 """Retrieve an attribute from the wrapped object. If the named
519 attribute doesn't exist, AttributeError is raised"""
520 return getattr(self._subject, name)
521
523 """Retrieve the entire wrapped object"""
524 return self._subject
525
527 if issubclass(other.__class__, self._subject.__class__):
528 return cmp(self._subject, other)
529 return cmp(self.__dict__, other.__dict__)
530
532 """A Python Descriptor class that delegates attribute fetches
533 to an underlying wrapped subject of a Proxy. Typical use:
534
535 class Foo(Proxy):
536 __str__ = Delegate('__str__')
537 """
539 self.attribute = attribute
541 if isinstance(obj, cls):
542 return getattr(obj._subject, self.attribute)
543 else:
544 return self
545
546
547 can_read_reg = 0
548 try:
549 import winreg
550
551 can_read_reg = 1
552 hkey_mod = winreg
553
554 RegOpenKeyEx = winreg.OpenKeyEx
555 RegEnumKey = winreg.EnumKey
556 RegEnumValue = winreg.EnumValue
557 RegQueryValueEx = winreg.QueryValueEx
558 RegError = winreg.error
559
560 except ImportError:
561 try:
562 import win32api
563 import win32con
564 can_read_reg = 1
565 hkey_mod = win32con
566
567 RegOpenKeyEx = win32api.RegOpenKeyEx
568 RegEnumKey = win32api.RegEnumKey
569 RegEnumValue = win32api.RegEnumValue
570 RegQueryValueEx = win32api.RegQueryValueEx
571 RegError = win32api.error
572
573 except ImportError:
576 RegError = _NoError
577
578 if can_read_reg:
579 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
580 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
581 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
582 HKEY_USERS = hkey_mod.HKEY_USERS
583
585 """This utility function returns a value in the registry
586 without having to open the key first. Only available on
587 Windows platforms with a version of Python that can read the
588 registry. Returns the same thing as
589 SCons.Util.RegQueryValueEx, except you just specify the entire
590 path to the value, and don't have to bother opening the key
591 first. So:
592
593 Instead of:
594 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
595 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
596 out = SCons.Util.RegQueryValueEx(k,
597 'ProgramFilesDir')
598
599 You can write:
600 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
601 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
602 """
603
604
605 p = key.rfind('\\') + 1
606 keyp = key[:p-1]
607 val = key[p:]
608 k = RegOpenKeyEx(root, keyp)
609 return RegQueryValueEx(k,val)
610 else:
611 try:
612 e = WindowsError
613 except NameError:
614
615
616
617
620 import builtins
621 builtins.WindowsError = WindowsError
622 else:
623 del e
624
625 HKEY_CLASSES_ROOT = None
626 HKEY_LOCAL_MACHINE = None
627 HKEY_CURRENT_USER = None
628 HKEY_USERS = None
629
632
635
636 if sys.platform == 'win32':
637
638 - def WhereIs(file, path=None, pathext=None, reject=[]):
639 if path is None:
640 try:
641 path = os.environ['PATH']
642 except KeyError:
643 return None
644 if is_String(path):
645 path = path.split(os.pathsep)
646 if pathext is None:
647 try:
648 pathext = os.environ['PATHEXT']
649 except KeyError:
650 pathext = '.COM;.EXE;.BAT;.CMD'
651 if is_String(pathext):
652 pathext = pathext.split(os.pathsep)
653 for ext in pathext:
654 if ext.lower() == file[-len(ext):].lower():
655 pathext = ['']
656 break
657 if not is_List(reject) and not is_Tuple(reject):
658 reject = [reject]
659 for dir in path:
660 f = os.path.join(dir, file)
661 for ext in pathext:
662 fext = f + ext
663 if os.path.isfile(fext):
664 try:
665 reject.index(fext)
666 except ValueError:
667 return os.path.normpath(fext)
668 continue
669 return None
670
671 elif os.name == 'os2':
672
673 - def WhereIs(file, path=None, pathext=None, reject=[]):
674 if path is None:
675 try:
676 path = os.environ['PATH']
677 except KeyError:
678 return None
679 if is_String(path):
680 path = path.split(os.pathsep)
681 if pathext is None:
682 pathext = ['.exe', '.cmd']
683 for ext in pathext:
684 if ext.lower() == file[-len(ext):].lower():
685 pathext = ['']
686 break
687 if not is_List(reject) and not is_Tuple(reject):
688 reject = [reject]
689 for dir in path:
690 f = os.path.join(dir, file)
691 for ext in pathext:
692 fext = f + ext
693 if os.path.isfile(fext):
694 try:
695 reject.index(fext)
696 except ValueError:
697 return os.path.normpath(fext)
698 continue
699 return None
700
701 else:
702
703 - def WhereIs(file, path=None, pathext=None, reject=[]):
704 import stat
705 if path is None:
706 try:
707 path = os.environ['PATH']
708 except KeyError:
709 return None
710 if is_String(path):
711 path = path.split(os.pathsep)
712 if not is_List(reject) and not is_Tuple(reject):
713 reject = [reject]
714 for d in path:
715 f = os.path.join(d, file)
716 if os.path.isfile(f):
717 try:
718 st = os.stat(f)
719 except OSError:
720
721
722
723
724 continue
725 if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
726 try:
727 reject.index(f)
728 except ValueError:
729 return os.path.normpath(f)
730 continue
731 return None
732
735 """This prepends newpath elements to the given oldpath. Will only
736 add any particular path once (leaving the first one it encounters
737 and ignoring the rest, to preserve path order), and will
738 os.path.normpath and os.path.normcase all paths to help assure
739 this. This can also handle the case where the given old path
740 variable is a list instead of a string, in which case a list will
741 be returned instead of a string.
742
743 Example:
744 Old Path: "/foo/bar:/foo"
745 New Path: "/biz/boom:/foo"
746 Result: "/biz/boom:/foo:/foo/bar"
747
748 If delete_existing is 0, then adding a path that exists will
749 not move it to the beginning; it will stay where it is in the
750 list.
751
752 If canonicalize is not None, it is applied to each element of
753 newpath before use.
754 """
755
756 orig = oldpath
757 is_list = 1
758 paths = orig
759 if not is_List(orig) and not is_Tuple(orig):
760 paths = paths.split(sep)
761 is_list = 0
762
763 if is_String(newpath):
764 newpaths = newpath.split(sep)
765 elif not is_List(newpath) and not is_Tuple(newpath):
766 newpaths = [ newpath ]
767 else:
768 newpaths = newpath
769
770 if canonicalize:
771 newpaths=list(map(canonicalize, newpaths))
772
773 if not delete_existing:
774
775
776
777
778
779 result = []
780 normpaths = []
781 for path in paths:
782 if not path:
783 continue
784 normpath = os.path.normpath(os.path.normcase(path))
785 if normpath not in normpaths:
786 result.append(path)
787 normpaths.append(normpath)
788 newpaths.reverse()
789 for path in newpaths:
790 if not path:
791 continue
792 normpath = os.path.normpath(os.path.normcase(path))
793 if normpath not in normpaths:
794 result.insert(0, path)
795 normpaths.append(normpath)
796 paths = result
797
798 else:
799 newpaths = newpaths + paths
800
801 normpaths = []
802 paths = []
803
804 for path in newpaths:
805 normpath = os.path.normpath(os.path.normcase(path))
806 if path and not normpath in normpaths:
807 paths.append(path)
808 normpaths.append(normpath)
809
810 if is_list:
811 return paths
812 else:
813 return sep.join(paths)
814
817 """This appends new path elements to the given old path. Will
818 only add any particular path once (leaving the last one it
819 encounters and ignoring the rest, to preserve path order), and
820 will os.path.normpath and os.path.normcase all paths to help
821 assure this. This can also handle the case where the given old
822 path variable is a list instead of a string, in which case a list
823 will be returned instead of a string.
824
825 Example:
826 Old Path: "/foo/bar:/foo"
827 New Path: "/biz/boom:/foo"
828 Result: "/foo/bar:/biz/boom:/foo"
829
830 If delete_existing is 0, then adding a path that exists
831 will not move it to the end; it will stay where it is in the list.
832
833 If canonicalize is not None, it is applied to each element of
834 newpath before use.
835 """
836
837 orig = oldpath
838 is_list = 1
839 paths = orig
840 if not is_List(orig) and not is_Tuple(orig):
841 paths = paths.split(sep)
842 is_list = 0
843
844 if is_String(newpath):
845 newpaths = newpath.split(sep)
846 elif not is_List(newpath) and not is_Tuple(newpath):
847 newpaths = [ newpath ]
848 else:
849 newpaths = newpath
850
851 if canonicalize:
852 newpaths=list(map(canonicalize, newpaths))
853
854 if not delete_existing:
855
856
857
858
859
860 result = []
861 normpaths = []
862 for path in paths:
863 if not path:
864 continue
865 result.append(path)
866 normpaths.append(os.path.normpath(os.path.normcase(path)))
867 for path in newpaths:
868 if not path:
869 continue
870 normpath = os.path.normpath(os.path.normcase(path))
871 if normpath not in normpaths:
872 result.append(path)
873 normpaths.append(normpath)
874 paths = result
875 else:
876
877
878 newpaths = paths + newpaths
879 newpaths.reverse()
880
881 normpaths = []
882 paths = []
883
884 for path in newpaths:
885 normpath = os.path.normpath(os.path.normcase(path))
886 if path and not normpath in normpaths:
887 paths.append(path)
888 normpaths.append(normpath)
889 paths.reverse()
890
891 if is_list:
892 return paths
893 else:
894 return sep.join(paths)
895
896 if sys.platform == 'cygwin':
898 """Transforms an absolute path into a native path for the system. In
899 Cygwin, this converts from a Cygwin path to a Windows one."""
900 return os.popen('cygpath -w ' + path).read().replace('\n', '')
901 else:
903 """Transforms an absolute path into a native path for the system.
904 Non-Cygwin version, just leave the path alone."""
905 return path
906
907 display = DisplayEngine()
908
910 if is_List(arg) or is_Tuple(arg):
911 return arg
912 elif is_String(arg):
913 return arg.split()
914 else:
915 return [arg]
916
918 """A class for command-line construction variables.
919
920 This is a list that uses Split() to split an initial string along
921 white-space arguments, and similarly to split any strings that get
922 added. This allows us to Do the Right Thing with Append() and
923 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
924 arg2') regardless of whether a user adds a list or a string to a
925 command-line construction variable.
926 """
934 return (self, CLVar(other))
936 return ' '.join(self.data)
937
938
939
940
941
944 self._keys = []
945 UserDict.__init__(self, dict)
946
950
952 UserDict.__setitem__(self, key, item)
953 if key not in self._keys: self._keys.append(key)
954
956 UserDict.clear(self)
957 self._keys = []
958
963
965 return list(zip(self._keys, list(self.values())))
966
969
971 try:
972 key = self._keys[-1]
973 except IndexError:
974 raise KeyError('dictionary is empty')
975
976 val = self[key]
977 del self[key]
978
979 return (key, val)
980
982 UserDict.setdefault(self, key, failobj)
983 if key not in self._keys: self._keys.append(key)
984
988
990 return list(map(self.get, self._keys))
991
993 """A callable ordered dictionary that maps file suffixes to
994 dictionary values. We preserve the order in which items are added
995 so that get_suffix() calls always return the first suffix added."""
996 - def __call__(self, env, source, ext=None):
997 if ext is None:
998 try:
999 ext = source[0].suffix
1000 except IndexError:
1001 ext = ""
1002 try:
1003 return self[ext]
1004 except KeyError:
1005
1006
1007 s_dict = {}
1008 for (k,v) in self.items():
1009 if k is not None:
1010 s_k = env.subst(k)
1011 if s_k in s_dict:
1012
1013
1014
1015
1016 raise KeyError(s_dict[s_k][0], k, s_k)
1017 s_dict[s_k] = (k,v)
1018 try:
1019 return s_dict[ext][1]
1020 except KeyError:
1021 try:
1022 return self[None]
1023 except KeyError:
1024 return None
1025
1026
1027 if sys.platform == 'cygwin':
1028
1029
1032 else:
1035
1036 -def adjustixes(fname, pre, suf, ensure_suffix=False):
1037 if pre:
1038 path, fn = os.path.split(os.path.normpath(fname))
1039 if fn[:len(pre)] != pre:
1040 fname = os.path.join(path, pre + fn)
1041
1042
1043
1044 if suf and fname[-len(suf):] != suf and \
1045 (ensure_suffix or not splitext(fname)[1]):
1046 fname = fname + suf
1047 return fname
1048
1049
1050
1051
1052
1053
1054
1055
1057 """Return a list of the elements in s, but without duplicates.
1058
1059 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1060 unique("abcabc") some permutation of ["a", "b", "c"], and
1061 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1062 [[2, 3], [1, 2]].
1063
1064 For best speed, all sequence elements should be hashable. Then
1065 unique() will usually work in linear time.
1066
1067 If not possible, the sequence elements should enjoy a total
1068 ordering, and if list(s).sort() doesn't raise TypeError it's
1069 assumed that they do enjoy a total ordering. Then unique() will
1070 usually work in O(N*log2(N)) time.
1071
1072 If that's not possible either, the sequence elements must support
1073 equality-testing. Then unique() will usually work in quadratic
1074 time.
1075 """
1076
1077 n = len(s)
1078 if n == 0:
1079 return []
1080
1081
1082
1083
1084
1085 u = {}
1086 try:
1087 for x in s:
1088 u[x] = 1
1089 except TypeError:
1090 pass
1091 else:
1092 return list(u.keys())
1093 del u
1094
1095
1096
1097
1098
1099
1100
1101
1102 try:
1103 t = sorted(s)
1104 except TypeError:
1105 pass
1106 else:
1107 assert n > 0
1108 last = t[0]
1109 lasti = i = 1
1110 while i < n:
1111 if t[i] != last:
1112 t[lasti] = last = t[i]
1113 lasti = lasti + 1
1114 i = i + 1
1115 return t[:lasti]
1116 del t
1117
1118
1119 u = []
1120 for x in s:
1121 if x not in u:
1122 u.append(x)
1123 return u
1124
1125
1126
1127
1128
1129
1130
1131
1132
1134 if idfun is None:
1135 def idfun(x): return x
1136 seen = {}
1137 result = []
1138 for item in seq:
1139 marker = idfun(item)
1140
1141
1142
1143 if marker in seen: continue
1144 seen[marker] = 1
1145 result.append(item)
1146 return result
1147
1148
1149
1150
1151
1153 seen = {}
1154 result = []
1155 for item in seq:
1156
1157 if item not in seen:
1158 seen[item] = 1
1159 result.append(item)
1160 return result
1161
1162
1163
1164
1165
1167
1169 self.fileobj = fileobj
1170
1172 result = []
1173 while True:
1174 line = self.fileobj.readline()
1175 if not line:
1176 break
1177 if line[-2:] == '\\\n':
1178 result.append(line[:-2])
1179 else:
1180 result.append(line)
1181 break
1182 return ''.join(result)
1183
1192
1193
1194
1197 UserList.__init__(self, seq)
1198 self.unique = True
1200 if not self.unique:
1201 self.data = uniquer_hashables(self.data)
1202 self.unique = True
1231 UserList.__setitem__(self, i, item)
1232 self.unique = False
1237 UserList.__setslice__(self, i, j, other)
1238 self.unique = False
1264 UserList.append(self, item)
1265 self.unique = False
1267 UserList.insert(self, i)
1268 self.unique = False
1278 - def sort(self, *args, **kwds):
1282 UserList.extend(self, other)
1283 self.unique = False
1284
1285
1287 """
1288 A proxy class that wraps a file object, flushing after every write,
1289 and delegating everything else to the wrapped object.
1290 """
1292 self.file = file
1293 self.softspace = 0
1295 try:
1296 self.file.write(arg)
1297 self.file.flush()
1298 except IOError:
1299
1300
1301
1302
1303
1304
1305
1306 pass
1308 return getattr(self.file, attr)
1309
1311 """ makes an absolute path name to a relative pathname.
1312 """
1313 if os.path.isabs(path):
1314 drive_s,path = os.path.splitdrive(path)
1315
1316 import re
1317 if not drive_s:
1318 path=re.compile("/*(.*)").findall(path)[0]
1319 else:
1320 path=path[1:]
1321
1322 assert( not os.path.isabs( path ) ), path
1323 return path
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1352 """
1353 Adds either a bound method to an instance or an unbound method to
1354 a class. If name is ommited the name of the specified function
1355 is used by default.
1356 Example:
1357 a = A()
1358 def f(self, x, y):
1359 self.z = x + y
1360 AddMethod(f, A, "add")
1361 a.add(2, 4)
1362 print a.z
1363 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1364 print a.listIndex(5)
1365 """
1366 if name is None:
1367 name = function.func_name
1368 else:
1369 function = RenameFunction(function, name)
1370
1371 if hasattr(obj, '__class__') and obj.__class__ is not type:
1372
1373 setattr(obj, name, MethodType(function, obj, obj.__class__))
1374 else:
1375
1376 setattr(obj, name, MethodType(function, None, obj))
1377
1379 """
1380 Returns a function identical to the specified function, but with
1381 the specified name.
1382 """
1383 return FunctionType(function.func_code,
1384 function.func_globals,
1385 name,
1386 function.func_defaults)
1387
1388
1389 md5 = False
1392
1398
1399 try:
1400 import hashlib
1401 except ImportError:
1402 pass
1403 else:
1404 if hasattr(hashlib, 'md5'):
1405 md5 = True
1410
1412 m = hashlib.md5()
1413 f = open(fname, "rb")
1414 while True:
1415 blck = f.read(chunksize)
1416 if not blck:
1417 break
1418 m.update(str(blck))
1419 f.close()
1420 return m.hexdigest()
1421
1423 """
1424 Collects a list of signatures into an aggregate signature.
1425
1426 signatures - a list of signatures
1427 returns - the aggregate signature
1428 """
1429 if len(signatures) == 1:
1430 return signatures[0]
1431 else:
1432 return MD5signature(', '.join(signatures))
1433
1434
1435
1437 """
1438 Perform sys.intern() on the passed argument and return the result.
1439 If the input is ineligible (e.g. a unicode string) the original argument is
1440 returned and no exception is thrown.
1441 """
1442 try:
1443 return sys.intern(x)
1444 except TypeError:
1445 return x
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456 -class Null(object):
1457 """ Null objects always and reliably "do nothing." """
1458 - def __new__(cls, *args, **kwargs):
1467 return "Null(0x%08X)" % id(self)
1476
1488
1489
1490 del __revision__
1491
1492
1493
1494
1495
1496
1497