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 rel_2.4.1:3453:73fefd3ea0b0 2015/11/09 03:25:05 bdbaddog"
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:
60 return path.rfind(sep)
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 if key not in exclude:
451 copy[key] = semi_deepcopy(val)
452 return copy
453 d[dict] = semi_deepcopy_dict
454
456 return list(map(semi_deepcopy, x))
457 d[list] = _semi_deepcopy_list
458
460 return tuple(map(semi_deepcopy, x))
461 d[tuple] = _semi_deepcopy_tuple
462
464 copier = _semi_deepcopy_dispatch.get(type(x))
465 if copier:
466 return copier(x)
467 else:
468 if hasattr(x, '__semi_deepcopy__') and callable(x.__semi_deepcopy__):
469 return x.__semi_deepcopy__()
470 elif isinstance(x, UserDict):
471 return x.__class__(semi_deepcopy_dict(x))
472 elif isinstance(x, UserList):
473 return x.__class__(_semi_deepcopy_list(x))
474
475 return x
476
477
479 """A simple generic Proxy class, forwarding all calls to
480 subject. So, for the benefit of the python newbie, what does
481 this really mean? Well, it means that you can take an object, let's
482 call it 'objA', and wrap it in this Proxy class, with a statement
483 like this
484
485 proxyObj = Proxy(objA),
486
487 Then, if in the future, you do something like this
488
489 x = proxyObj.var1,
490
491 since Proxy does not have a 'var1' attribute (but presumably objA does),
492 the request actually is equivalent to saying
493
494 x = objA.var1
495
496 Inherit from this class to create a Proxy.
497
498 Note that, with new-style classes, this does *not* work transparently
499 for Proxy subclasses that use special .__*__() method names, because
500 those names are now bound to the class, not the individual instances.
501 You now need to know in advance which .__*__() method names you want
502 to pass on to the underlying Proxy object, and specifically delegate
503 their calls like this:
504
505 class Foo(Proxy):
506 __str__ = Delegate('__str__')
507 """
508
510 """Wrap an object as a Proxy object"""
511 self._subject = subject
512
514 """Retrieve an attribute from the wrapped object. If the named
515 attribute doesn't exist, AttributeError is raised"""
516 return getattr(self._subject, name)
517
519 """Retrieve the entire wrapped object"""
520 return self._subject
521
523 if issubclass(other.__class__, self._subject.__class__):
524 return cmp(self._subject, other)
525 return cmp(self.__dict__, other.__dict__)
526
528 """A Python Descriptor class that delegates attribute fetches
529 to an underlying wrapped subject of a Proxy. Typical use:
530
531 class Foo(Proxy):
532 __str__ = Delegate('__str__')
533 """
535 self.attribute = attribute
537 if isinstance(obj, cls):
538 return getattr(obj._subject, self.attribute)
539 else:
540 return self
541
542
543 can_read_reg = 0
544 try:
545 import winreg
546
547 can_read_reg = 1
548 hkey_mod = winreg
549
550 RegOpenKeyEx = winreg.OpenKeyEx
551 RegEnumKey = winreg.EnumKey
552 RegEnumValue = winreg.EnumValue
553 RegQueryValueEx = winreg.QueryValueEx
554 RegError = winreg.error
555
556 except ImportError:
557 try:
558 import win32api
559 import win32con
560 can_read_reg = 1
561 hkey_mod = win32con
562
563 RegOpenKeyEx = win32api.RegOpenKeyEx
564 RegEnumKey = win32api.RegEnumKey
565 RegEnumValue = win32api.RegEnumValue
566 RegQueryValueEx = win32api.RegQueryValueEx
567 RegError = win32api.error
568
569 except ImportError:
572 RegError = _NoError
573
574 if can_read_reg:
575 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
576 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
577 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
578 HKEY_USERS = hkey_mod.HKEY_USERS
579
581 """This utility function returns a value in the registry
582 without having to open the key first. Only available on
583 Windows platforms with a version of Python that can read the
584 registry. Returns the same thing as
585 SCons.Util.RegQueryValueEx, except you just specify the entire
586 path to the value, and don't have to bother opening the key
587 first. So:
588
589 Instead of:
590 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
591 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
592 out = SCons.Util.RegQueryValueEx(k,
593 'ProgramFilesDir')
594
595 You can write:
596 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
597 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
598 """
599
600
601 p = key.rfind('\\') + 1
602 keyp = key[:p-1]
603 val = key[p:]
604 k = RegOpenKeyEx(root, keyp)
605 return RegQueryValueEx(k,val)
606 else:
607 try:
608 e = WindowsError
609 except NameError:
610
611
612
613
616 import builtins
617 builtins.WindowsError = WindowsError
618 else:
619 del e
620
621 HKEY_CLASSES_ROOT = None
622 HKEY_LOCAL_MACHINE = None
623 HKEY_CURRENT_USER = None
624 HKEY_USERS = None
625
628
631
632 if sys.platform == 'win32':
633
634 - def WhereIs(file, path=None, pathext=None, reject=[]):
635 if path is None:
636 try:
637 path = os.environ['PATH']
638 except KeyError:
639 return None
640 if is_String(path):
641 path = path.split(os.pathsep)
642 if pathext is None:
643 try:
644 pathext = os.environ['PATHEXT']
645 except KeyError:
646 pathext = '.COM;.EXE;.BAT;.CMD'
647 if is_String(pathext):
648 pathext = pathext.split(os.pathsep)
649 for ext in pathext:
650 if ext.lower() == file[-len(ext):].lower():
651 pathext = ['']
652 break
653 if not is_List(reject) and not is_Tuple(reject):
654 reject = [reject]
655 for dir in path:
656 f = os.path.join(dir, file)
657 for ext in pathext:
658 fext = f + ext
659 if os.path.isfile(fext):
660 try:
661 reject.index(fext)
662 except ValueError:
663 return os.path.normpath(fext)
664 continue
665 return None
666
667 elif os.name == 'os2':
668
669 - def WhereIs(file, path=None, pathext=None, reject=[]):
670 if path is None:
671 try:
672 path = os.environ['PATH']
673 except KeyError:
674 return None
675 if is_String(path):
676 path = path.split(os.pathsep)
677 if pathext is None:
678 pathext = ['.exe', '.cmd']
679 for ext in pathext:
680 if ext.lower() == file[-len(ext):].lower():
681 pathext = ['']
682 break
683 if not is_List(reject) and not is_Tuple(reject):
684 reject = [reject]
685 for dir in path:
686 f = os.path.join(dir, file)
687 for ext in pathext:
688 fext = f + ext
689 if os.path.isfile(fext):
690 try:
691 reject.index(fext)
692 except ValueError:
693 return os.path.normpath(fext)
694 continue
695 return None
696
697 else:
698
699 - def WhereIs(file, path=None, pathext=None, reject=[]):
700 import stat
701 if path is None:
702 try:
703 path = os.environ['PATH']
704 except KeyError:
705 return None
706 if is_String(path):
707 path = path.split(os.pathsep)
708 if not is_List(reject) and not is_Tuple(reject):
709 reject = [reject]
710 for d in path:
711 f = os.path.join(d, file)
712 if os.path.isfile(f):
713 try:
714 st = os.stat(f)
715 except OSError:
716
717
718
719
720 continue
721 if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
722 try:
723 reject.index(f)
724 except ValueError:
725 return os.path.normpath(f)
726 continue
727 return None
728
729 -def PrependPath(oldpath, newpath, sep = os.pathsep,
730 delete_existing=1, canonicalize=None):
731 """This prepends newpath elements to the given oldpath. Will only
732 add any particular path once (leaving the first one it encounters
733 and ignoring the rest, to preserve path order), and will
734 os.path.normpath and os.path.normcase all paths to help assure
735 this. This can also handle the case where the given old path
736 variable is a list instead of a string, in which case a list will
737 be returned instead of a string.
738
739 Example:
740 Old Path: "/foo/bar:/foo"
741 New Path: "/biz/boom:/foo"
742 Result: "/biz/boom:/foo:/foo/bar"
743
744 If delete_existing is 0, then adding a path that exists will
745 not move it to the beginning; it will stay where it is in the
746 list.
747
748 If canonicalize is not None, it is applied to each element of
749 newpath before use.
750 """
751
752 orig = oldpath
753 is_list = 1
754 paths = orig
755 if not is_List(orig) and not is_Tuple(orig):
756 paths = paths.split(sep)
757 is_list = 0
758
759 if is_String(newpath):
760 newpaths = newpath.split(sep)
761 elif not is_List(newpath) and not is_Tuple(newpath):
762 newpaths = [ newpath ]
763 else:
764 newpaths = newpath
765
766 if canonicalize:
767 newpaths=list(map(canonicalize, newpaths))
768
769 if not delete_existing:
770
771
772
773
774
775 result = []
776 normpaths = []
777 for path in paths:
778 if not path:
779 continue
780 normpath = os.path.normpath(os.path.normcase(path))
781 if normpath not in normpaths:
782 result.append(path)
783 normpaths.append(normpath)
784 newpaths.reverse()
785 for path in newpaths:
786 if not path:
787 continue
788 normpath = os.path.normpath(os.path.normcase(path))
789 if normpath not in normpaths:
790 result.insert(0, path)
791 normpaths.append(normpath)
792 paths = result
793
794 else:
795 newpaths = newpaths + paths
796
797 normpaths = []
798 paths = []
799
800 for path in newpaths:
801 normpath = os.path.normpath(os.path.normcase(path))
802 if path and not normpath in normpaths:
803 paths.append(path)
804 normpaths.append(normpath)
805
806 if is_list:
807 return paths
808 else:
809 return sep.join(paths)
810
811 -def AppendPath(oldpath, newpath, sep = os.pathsep,
812 delete_existing=1, canonicalize=None):
813 """This appends new path elements to the given old path. Will
814 only add any particular path once (leaving the last one it
815 encounters and ignoring the rest, to preserve path order), and
816 will os.path.normpath and os.path.normcase all paths to help
817 assure this. This can also handle the case where the given old
818 path variable is a list instead of a string, in which case a list
819 will be returned instead of a string.
820
821 Example:
822 Old Path: "/foo/bar:/foo"
823 New Path: "/biz/boom:/foo"
824 Result: "/foo/bar:/biz/boom:/foo"
825
826 If delete_existing is 0, then adding a path that exists
827 will not move it to the end; it will stay where it is in the list.
828
829 If canonicalize is not None, it is applied to each element of
830 newpath before use.
831 """
832
833 orig = oldpath
834 is_list = 1
835 paths = orig
836 if not is_List(orig) and not is_Tuple(orig):
837 paths = paths.split(sep)
838 is_list = 0
839
840 if is_String(newpath):
841 newpaths = newpath.split(sep)
842 elif not is_List(newpath) and not is_Tuple(newpath):
843 newpaths = [ newpath ]
844 else:
845 newpaths = newpath
846
847 if canonicalize:
848 newpaths=list(map(canonicalize, newpaths))
849
850 if not delete_existing:
851
852
853
854
855
856 result = []
857 normpaths = []
858 for path in paths:
859 if not path:
860 continue
861 result.append(path)
862 normpaths.append(os.path.normpath(os.path.normcase(path)))
863 for path in newpaths:
864 if not path:
865 continue
866 normpath = os.path.normpath(os.path.normcase(path))
867 if normpath not in normpaths:
868 result.append(path)
869 normpaths.append(normpath)
870 paths = result
871 else:
872
873
874 newpaths = paths + newpaths
875 newpaths.reverse()
876
877 normpaths = []
878 paths = []
879
880 for path in newpaths:
881 normpath = os.path.normpath(os.path.normcase(path))
882 if path and not normpath in normpaths:
883 paths.append(path)
884 normpaths.append(normpath)
885 paths.reverse()
886
887 if is_list:
888 return paths
889 else:
890 return sep.join(paths)
891
892 if sys.platform == 'cygwin':
894 """Transforms an absolute path into a native path for the system. In
895 Cygwin, this converts from a Cygwin path to a Windows one."""
896 return os.popen('cygpath -w ' + path).read().replace('\n', '')
897 else:
899 """Transforms an absolute path into a native path for the system.
900 Non-Cygwin version, just leave the path alone."""
901 return path
902
903 display = DisplayEngine()
904
906 if is_List(arg) or is_Tuple(arg):
907 return arg
908 elif is_String(arg):
909 return arg.split()
910 else:
911 return [arg]
912
914 """A class for command-line construction variables.
915
916 This is a list that uses Split() to split an initial string along
917 white-space arguments, and similarly to split any strings that get
918 added. This allows us to Do the Right Thing with Append() and
919 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
920 arg2') regardless of whether a user adds a list or a string to a
921 command-line construction variable.
922 """
930 return (self, CLVar(other))
932 return ' '.join(self.data)
933
934
935
936
937
940 self._keys = []
941 UserDict.__init__(self, dict)
942
946
950
952 UserDict.clear(self)
953 self._keys = []
954
959
961 return list(zip(self._keys, list(self.values())))
962
965
967 try:
968 key = self._keys[-1]
969 except IndexError:
970 raise KeyError('dictionary is empty')
971
972 val = self[key]
973 del self[key]
974
975 return (key, val)
976
980
984
986 return list(map(self.get, self._keys))
987
989 """A callable ordered dictionary that maps file suffixes to
990 dictionary values. We preserve the order in which items are added
991 so that get_suffix() calls always return the first suffix added."""
992 - def __call__(self, env, source, ext=None):
993 if ext is None:
994 try:
995 ext = source[0].get_suffix()
996 except IndexError:
997 ext = ""
998 try:
999 return self[ext]
1000 except KeyError:
1001
1002
1003 s_dict = {}
1004 for (k,v) in self.items():
1005 if k is not None:
1006 s_k = env.subst(k)
1007 if s_k in s_dict:
1008
1009
1010
1011
1012 raise KeyError(s_dict[s_k][0], k, s_k)
1013 s_dict[s_k] = (k,v)
1014 try:
1015 return s_dict[ext][1]
1016 except KeyError:
1017 try:
1018 return self[None]
1019 except KeyError:
1020 return None
1021
1022
1023 if sys.platform == 'cygwin':
1024
1025
1028 else:
1030 return (os.path.normcase(s1) != os.path.normcase(s2))
1031
1032 -def adjustixes(fname, pre, suf, ensure_suffix=False):
1033 if pre:
1034 path, fn = os.path.split(os.path.normpath(fname))
1035 if fn[:len(pre)] != pre:
1036 fname = os.path.join(path, pre + fn)
1037
1038
1039
1040 if suf and fname[-len(suf):] != suf and \
1041 (ensure_suffix or not splitext(fname)[1]):
1042 fname = fname + suf
1043 return fname
1044
1045
1046
1047
1048
1049
1050
1051
1053 """Return a list of the elements in s, but without duplicates.
1054
1055 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1056 unique("abcabc") some permutation of ["a", "b", "c"], and
1057 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1058 [[2, 3], [1, 2]].
1059
1060 For best speed, all sequence elements should be hashable. Then
1061 unique() will usually work in linear time.
1062
1063 If not possible, the sequence elements should enjoy a total
1064 ordering, and if list(s).sort() doesn't raise TypeError it's
1065 assumed that they do enjoy a total ordering. Then unique() will
1066 usually work in O(N*log2(N)) time.
1067
1068 If that's not possible either, the sequence elements must support
1069 equality-testing. Then unique() will usually work in quadratic
1070 time.
1071 """
1072
1073 n = len(s)
1074 if n == 0:
1075 return []
1076
1077
1078
1079
1080
1081 u = {}
1082 try:
1083 for x in s:
1084 u[x] = 1
1085 except TypeError:
1086 pass
1087 else:
1088 return list(u.keys())
1089 del u
1090
1091
1092
1093
1094
1095
1096
1097
1098 try:
1099 t = sorted(s)
1100 except TypeError:
1101 pass
1102 else:
1103 assert n > 0
1104 last = t[0]
1105 lasti = i = 1
1106 while i < n:
1107 if t[i] != last:
1108 t[lasti] = last = t[i]
1109 lasti = lasti + 1
1110 i = i + 1
1111 return t[:lasti]
1112 del t
1113
1114
1115 u = []
1116 for x in s:
1117 if x not in u:
1118 u.append(x)
1119 return u
1120
1121
1122
1123
1124
1125
1126
1127
1128
1130 if idfun is None:
1131 def idfun(x): return x
1132 seen = {}
1133 result = []
1134 for item in seq:
1135 marker = idfun(item)
1136
1137
1138
1139 if marker in seen: continue
1140 seen[marker] = 1
1141 result.append(item)
1142 return result
1143
1144
1145
1146
1147
1149 seen = {}
1150 result = []
1151 for item in seq:
1152
1153 if item not in seen:
1154 seen[item] = 1
1155 result.append(item)
1156 return result
1157
1158
1159
1160
1161
1163
1165 self.fileobj = fileobj
1166
1168 result = []
1169 while True:
1170 line = self.fileobj.readline()
1171 if not line:
1172 break
1173 if line[-2:] == '\\\n':
1174 result.append(line[:-2])
1175 else:
1176 result.append(line)
1177 break
1178 return ''.join(result)
1179
1188
1189
1190
1193 UserList.__init__(self, seq)
1194 self.unique = True
1196 if not self.unique:
1197 self.data = uniquer_hashables(self.data)
1198 self.unique = True
1227 UserList.__setitem__(self, i, item)
1228 self.unique = False
1233 UserList.__setslice__(self, i, j, other)
1234 self.unique = False
1260 UserList.append(self, item)
1261 self.unique = False
1263 UserList.insert(self, i)
1264 self.unique = False
1274 - def sort(self, *args, **kwds):
1278 UserList.extend(self, other)
1279 self.unique = False
1280
1281
1283 """
1284 A proxy class that wraps a file object, flushing after every write,
1285 and delegating everything else to the wrapped object.
1286 """
1288 self.file = file
1289 self.softspace = 0
1291 try:
1292 self.file.write(arg)
1293 self.file.flush()
1294 except IOError:
1295
1296
1297
1298
1299
1300
1301
1302 pass
1304 return getattr(self.file, attr)
1305
1307 """ makes an absolute path name to a relative pathname.
1308 """
1309 if os.path.isabs(path):
1310 drive_s,path = os.path.splitdrive(path)
1311
1312 import re
1313 if not drive_s:
1314 path=re.compile("/*(.*)").findall(path)[0]
1315 else:
1316 path=path[1:]
1317
1318 assert( not os.path.isabs( path ) ), path
1319 return path
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1348 """
1349 Adds either a bound method to an instance or an unbound method to
1350 a class. If name is ommited the name of the specified function
1351 is used by default.
1352 Example:
1353 a = A()
1354 def f(self, x, y):
1355 self.z = x + y
1356 AddMethod(f, A, "add")
1357 a.add(2, 4)
1358 print a.z
1359 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1360 print a.listIndex(5)
1361 """
1362 if name is None:
1363 name = function.func_name
1364 else:
1365 function = RenameFunction(function, name)
1366
1367 if hasattr(obj, '__class__') and obj.__class__ is not type:
1368
1369 setattr(obj, name, MethodType(function, obj, obj.__class__))
1370 else:
1371
1372 setattr(obj, name, MethodType(function, None, obj))
1373
1375 """
1376 Returns a function identical to the specified function, but with
1377 the specified name.
1378 """
1379 return FunctionType(function.func_code,
1380 function.func_globals,
1381 name,
1382 function.func_defaults)
1383
1384
1385 md5 = False
1388
1394
1395 try:
1396 import hashlib
1397 except ImportError:
1398 pass
1399 else:
1400 if hasattr(hashlib, 'md5'):
1401 md5 = True
1403 m = hashlib.md5()
1404 m.update(str(s))
1405 return m.hexdigest()
1406
1408 m = hashlib.md5()
1409 f = open(fname, "rb")
1410 while True:
1411 blck = f.read(chunksize)
1412 if not blck:
1413 break
1414 m.update(str(blck))
1415 f.close()
1416 return m.hexdigest()
1417
1419 """
1420 Collects a list of signatures into an aggregate signature.
1421
1422 signatures - a list of signatures
1423 returns - the aggregate signature
1424 """
1425 if len(signatures) == 1:
1426 return signatures[0]
1427 else:
1428 return MD5signature(', '.join(signatures))
1429
1430
1431
1433 """
1434 Perform sys.intern() on the passed argument and return the result.
1435 If the input is ineligible (e.g. a unicode string) the original argument is
1436 returned and no exception is thrown.
1437 """
1438 try:
1439 return sys.intern(x)
1440 except TypeError:
1441 return x
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452 -class Null(object):
1453 """ Null objects always and reliably "do nothing." """
1454 - def __new__(cls, *args, **kwargs):
1463 return "Null(0x%08X)" % id(self)
1472
1484
1485
1486 del __revision__
1487
1488
1489
1490
1491
1492
1493