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.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 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 inconsistent 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=None):
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
185 if visited is None:
186 visited = {}
187
188 children = child_func(root)
189 retval = ""
190 for pipe in margin[:-1]:
191 if pipe:
192 retval = retval + "| "
193 else:
194 retval = retval + " "
195
196 if rname in visited:
197 return retval + "+-[" + rname + "]\n"
198
199 retval = retval + "+-" + rname + "\n"
200 if not prune:
201 visited = copy.copy(visited)
202 visited[rname] = 1
203
204 for i in range(len(children)):
205 margin.append(i<len(children)-1)
206 retval = retval + render_tree(children[i], child_func, prune, margin, visited
207 )
208 margin.pop()
209
210 return retval
211
212 IDX = lambda N: N and 1 or 0
213
214 -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None):
215 """
216 Print a tree of nodes. This is like render_tree, except it prints
217 lines directly instead of creating a string representation in memory,
218 so that huge trees can be printed.
219
220 root - the root node of the tree
221 child_func - the function called to get the children of a node
222 prune - don't visit the same node twice
223 showtags - print status information to the left of each node line
224 margin - the format of the left margin to use for children of root.
225 1 results in a pipe, and 0 results in no pipe.
226 visited - a dictionary of visited nodes in the current branch if not prune,
227 or in the whole tree if prune.
228 """
229
230 rname = str(root)
231
232
233 if visited is None:
234 visited = {}
235
236 if showtags:
237
238 if showtags == 2:
239 legend = (' E = exists\n' +
240 ' R = exists in repository only\n' +
241 ' b = implicit builder\n' +
242 ' B = explicit builder\n' +
243 ' S = side effect\n' +
244 ' P = precious\n' +
245 ' A = always build\n' +
246 ' C = current\n' +
247 ' N = no clean\n' +
248 ' H = no cache\n' +
249 '\n')
250 sys.stdout.write(unicode(legend))
251
252 tags = ['[']
253 tags.append(' E'[IDX(root.exists())])
254 tags.append(' R'[IDX(root.rexists() and not root.exists())])
255 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
256 [0,2][IDX(root.has_builder())]])
257 tags.append(' S'[IDX(root.side_effect)])
258 tags.append(' P'[IDX(root.precious)])
259 tags.append(' A'[IDX(root.always_build)])
260 tags.append(' C'[IDX(root.is_up_to_date())])
261 tags.append(' N'[IDX(root.noclean)])
262 tags.append(' H'[IDX(root.nocache)])
263 tags.append(']')
264
265 else:
266 tags = []
267
268 def MMM(m):
269 return [" ","| "][m]
270 margins = list(map(MMM, margin[:-1]))
271
272 children = child_func(root)
273
274 if prune and rname in visited and children:
275 sys.stdout.write(''.join(tags + margins + ['+-[', rname, ']']) + u'\n')
276 return
277
278 sys.stdout.write(''.join(tags + margins + ['+-', rname]) + u'\n')
279
280 visited[rname] = 1
281
282 if children:
283 margin.append(1)
284 idx = IDX(showtags)
285 for C in children[:-1]:
286 print_tree(C, child_func, prune, idx, margin, visited)
287 margin[-1] = 0
288 print_tree(children[-1], child_func, prune, idx, margin, visited)
289 margin.pop()
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 DictTypes = (dict, UserDict)
308 ListTypes = (list, UserList)
309 SequenceTypes = (list, tuple, UserList)
310
311
312
313
314 StringTypes = (str, unicode, UserString)
315
316
317
318 BaseStringTypes = (str, unicode)
319
322
325
328
329 -def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
330 return isinstance(obj, tuple)
331
334
343
351
354 """Flatten a sequence to a non-nested list.
355
356 Flatten() converts either a single scalar or a nested sequence
357 to a non-nested list. Note that flatten() considers strings
358 to be scalars instead of sequences like Python would.
359 """
360 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
361 return [obj]
362 result = []
363 for item in obj:
364 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
365 result.append(item)
366 else:
367 do_flatten(item, result)
368 return result
369
372 """Flatten a sequence to a non-nested list.
373
374 Same as flatten(), but it does not handle the single scalar
375 case. This is slightly more efficient when one knows that
376 the sequence to flatten can not be a scalar.
377 """
378 result = []
379 for item in sequence:
380 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
381 result.append(item)
382 else:
383 do_flatten(item, result)
384 return result
385
386
387
388
389
390
394 if isinstance(s,BaseStringTypes):
395
396 return s
397 elif isinstance(s, UserString):
398
399
400 return s.data
401 else:
402 return str(s)
403
408
409
410 if isinstance(s, BaseStringTypes):
411 return s
412 elif isinstance(s, SequenceTypes):
413 l = []
414 for e in s:
415 l.append(to_String_for_subst(e))
416 return ' '.join( s )
417 elif isinstance(s, UserString):
418
419
420 return s.data
421 else:
422 return str(s)
423
426 try:
427 f = obj.for_signature
428 except AttributeError:
429 return to_String_for_subst(obj)
430 else:
431 return f()
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447 _semi_deepcopy_dispatch = d = {}
448
450 copy = {}
451 for key, val in x.items():
452
453
454
455
456
457
458 if key not in exclude:
459 copy[key] = semi_deepcopy(val)
460 return copy
461 d[dict] = semi_deepcopy_dict
462
464 return list(map(semi_deepcopy, x))
465 d[list] = _semi_deepcopy_list
466
468 return tuple(map(semi_deepcopy, x))
469 d[tuple] = _semi_deepcopy_tuple
470
472 copier = _semi_deepcopy_dispatch.get(type(x))
473 if copier:
474 return copier(x)
475 else:
476 if hasattr(x, '__semi_deepcopy__') and callable(x.__semi_deepcopy__):
477 return x.__semi_deepcopy__()
478 elif isinstance(x, UserDict):
479 return x.__class__(semi_deepcopy_dict(x))
480 elif isinstance(x, UserList):
481 return x.__class__(_semi_deepcopy_list(x))
482
483 return x
484
485
487 """A simple generic Proxy class, forwarding all calls to
488 subject. So, for the benefit of the python newbie, what does
489 this really mean? Well, it means that you can take an object, let's
490 call it 'objA', and wrap it in this Proxy class, with a statement
491 like this
492
493 proxyObj = Proxy(objA),
494
495 Then, if in the future, you do something like this
496
497 x = proxyObj.var1,
498
499 since Proxy does not have a 'var1' attribute (but presumably objA does),
500 the request actually is equivalent to saying
501
502 x = objA.var1
503
504 Inherit from this class to create a Proxy.
505
506 Note that, with new-style classes, this does *not* work transparently
507 for Proxy subclasses that use special .__*__() method names, because
508 those names are now bound to the class, not the individual instances.
509 You now need to know in advance which .__*__() method names you want
510 to pass on to the underlying Proxy object, and specifically delegate
511 their calls like this:
512
513 class Foo(Proxy):
514 __str__ = Delegate('__str__')
515 """
516
518 """Wrap an object as a Proxy object"""
519 self._subject = subject
520
522 """Retrieve an attribute from the wrapped object. If the named
523 attribute doesn't exist, AttributeError is raised"""
524 return getattr(self._subject, name)
525
527 """Retrieve the entire wrapped object"""
528 return self._subject
529
531 if issubclass(other.__class__, self._subject.__class__):
532 return cmp(self._subject, other)
533 return cmp(self.__dict__, other.__dict__)
534
536 """A Python Descriptor class that delegates attribute fetches
537 to an underlying wrapped subject of a Proxy. Typical use:
538
539 class Foo(Proxy):
540 __str__ = Delegate('__str__')
541 """
543 self.attribute = attribute
545 if isinstance(obj, cls):
546 return getattr(obj._subject, self.attribute)
547 else:
548 return self
549
550
551 can_read_reg = 0
552 try:
553 import winreg
554
555 can_read_reg = 1
556 hkey_mod = winreg
557
558 RegOpenKeyEx = winreg.OpenKeyEx
559 RegEnumKey = winreg.EnumKey
560 RegEnumValue = winreg.EnumValue
561 RegQueryValueEx = winreg.QueryValueEx
562 RegError = winreg.error
563
564 except ImportError:
565 try:
566 import win32api
567 import win32con
568 can_read_reg = 1
569 hkey_mod = win32con
570
571 RegOpenKeyEx = win32api.RegOpenKeyEx
572 RegEnumKey = win32api.RegEnumKey
573 RegEnumValue = win32api.RegEnumValue
574 RegQueryValueEx = win32api.RegQueryValueEx
575 RegError = win32api.error
576
577 except ImportError:
580 RegError = _NoError
581
582 WinError = None
583
584
585
586
589 try:
590 WinError = WindowsError
591 except NameError:
592 WinError = PlainWindowsError
593
594
595 if can_read_reg:
596 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
597 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
598 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
599 HKEY_USERS = hkey_mod.HKEY_USERS
600
602 """This utility function returns a value in the registry
603 without having to open the key first. Only available on
604 Windows platforms with a version of Python that can read the
605 registry. Returns the same thing as
606 SCons.Util.RegQueryValueEx, except you just specify the entire
607 path to the value, and don't have to bother opening the key
608 first. So:
609
610 Instead of:
611 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
612 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
613 out = SCons.Util.RegQueryValueEx(k,
614 'ProgramFilesDir')
615
616 You can write:
617 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
618 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
619 """
620
621
622 p = key.rfind('\\') + 1
623 keyp = key[:p-1]
624 val = key[p:]
625 k = RegOpenKeyEx(root, keyp)
626 return RegQueryValueEx(k,val)
627 else:
628 HKEY_CLASSES_ROOT = None
629 HKEY_LOCAL_MACHINE = None
630 HKEY_CURRENT_USER = None
631 HKEY_USERS = None
632
635
638
639 if sys.platform == 'win32':
640
641 - def WhereIs(file, path=None, pathext=None, reject=[]):
642 if path is None:
643 try:
644 path = os.environ['PATH']
645 except KeyError:
646 return None
647 if is_String(path):
648 path = path.split(os.pathsep)
649 if pathext is None:
650 try:
651 pathext = os.environ['PATHEXT']
652 except KeyError:
653 pathext = '.COM;.EXE;.BAT;.CMD'
654 if is_String(pathext):
655 pathext = pathext.split(os.pathsep)
656 for ext in pathext:
657 if ext.lower() == file[-len(ext):].lower():
658 pathext = ['']
659 break
660 if not is_List(reject) and not is_Tuple(reject):
661 reject = [reject]
662 for dir in path:
663 f = os.path.join(dir, file)
664 for ext in pathext:
665 fext = f + ext
666 if os.path.isfile(fext):
667 try:
668 reject.index(fext)
669 except ValueError:
670 return os.path.normpath(fext)
671 continue
672 return None
673
674 elif os.name == 'os2':
675
676 - def WhereIs(file, path=None, pathext=None, reject=[]):
677 if path is None:
678 try:
679 path = os.environ['PATH']
680 except KeyError:
681 return None
682 if is_String(path):
683 path = path.split(os.pathsep)
684 if pathext is None:
685 pathext = ['.exe', '.cmd']
686 for ext in pathext:
687 if ext.lower() == file[-len(ext):].lower():
688 pathext = ['']
689 break
690 if not is_List(reject) and not is_Tuple(reject):
691 reject = [reject]
692 for dir in path:
693 f = os.path.join(dir, file)
694 for ext in pathext:
695 fext = f + ext
696 if os.path.isfile(fext):
697 try:
698 reject.index(fext)
699 except ValueError:
700 return os.path.normpath(fext)
701 continue
702 return None
703
704 else:
705
706 - def WhereIs(file, path=None, pathext=None, reject=[]):
707 import stat
708 if path is None:
709 try:
710 path = os.environ['PATH']
711 except KeyError:
712 return None
713 if is_String(path):
714 path = path.split(os.pathsep)
715 if not is_List(reject) and not is_Tuple(reject):
716 reject = [reject]
717 for d in path:
718 f = os.path.join(d, file)
719 if os.path.isfile(f):
720 try:
721 st = os.stat(f)
722 except OSError:
723
724
725
726
727 continue
728 if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
729 try:
730 reject.index(f)
731 except ValueError:
732 return os.path.normpath(f)
733 continue
734 return None
735
736 -def PrependPath(oldpath, newpath, sep = os.pathsep,
737 delete_existing=1, canonicalize=None):
738 """This prepends newpath elements to the given oldpath. Will only
739 add any particular path once (leaving the first one it encounters
740 and ignoring the rest, to preserve path order), and will
741 os.path.normpath and os.path.normcase all paths to help assure
742 this. This can also handle the case where the given old path
743 variable is a list instead of a string, in which case a list will
744 be returned instead of a string.
745
746 Example:
747 Old Path: "/foo/bar:/foo"
748 New Path: "/biz/boom:/foo"
749 Result: "/biz/boom:/foo:/foo/bar"
750
751 If delete_existing is 0, then adding a path that exists will
752 not move it to the beginning; it will stay where it is in the
753 list.
754
755 If canonicalize is not None, it is applied to each element of
756 newpath before use.
757 """
758
759 orig = oldpath
760 is_list = 1
761 paths = orig
762 if not is_List(orig) and not is_Tuple(orig):
763 paths = paths.split(sep)
764 is_list = 0
765
766 if is_String(newpath):
767 newpaths = newpath.split(sep)
768 elif not is_List(newpath) and not is_Tuple(newpath):
769 newpaths = [ newpath ]
770 else:
771 newpaths = newpath
772
773 if canonicalize:
774 newpaths=list(map(canonicalize, newpaths))
775
776 if not delete_existing:
777
778
779
780
781
782 result = []
783 normpaths = []
784 for path in paths:
785 if not path:
786 continue
787 normpath = os.path.normpath(os.path.normcase(path))
788 if normpath not in normpaths:
789 result.append(path)
790 normpaths.append(normpath)
791 newpaths.reverse()
792 for path in newpaths:
793 if not path:
794 continue
795 normpath = os.path.normpath(os.path.normcase(path))
796 if normpath not in normpaths:
797 result.insert(0, path)
798 normpaths.append(normpath)
799 paths = result
800
801 else:
802 newpaths = newpaths + paths
803
804 normpaths = []
805 paths = []
806
807 for path in newpaths:
808 normpath = os.path.normpath(os.path.normcase(path))
809 if path and not normpath in normpaths:
810 paths.append(path)
811 normpaths.append(normpath)
812
813 if is_list:
814 return paths
815 else:
816 return sep.join(paths)
817
818 -def AppendPath(oldpath, newpath, sep = os.pathsep,
819 delete_existing=1, canonicalize=None):
820 """This appends new path elements to the given old path. Will
821 only add any particular path once (leaving the last one it
822 encounters and ignoring the rest, to preserve path order), and
823 will os.path.normpath and os.path.normcase all paths to help
824 assure this. This can also handle the case where the given old
825 path variable is a list instead of a string, in which case a list
826 will be returned instead of a string.
827
828 Example:
829 Old Path: "/foo/bar:/foo"
830 New Path: "/biz/boom:/foo"
831 Result: "/foo/bar:/biz/boom:/foo"
832
833 If delete_existing is 0, then adding a path that exists
834 will not move it to the end; it will stay where it is in the list.
835
836 If canonicalize is not None, it is applied to each element of
837 newpath before use.
838 """
839
840 orig = oldpath
841 is_list = 1
842 paths = orig
843 if not is_List(orig) and not is_Tuple(orig):
844 paths = paths.split(sep)
845 is_list = 0
846
847 if is_String(newpath):
848 newpaths = newpath.split(sep)
849 elif not is_List(newpath) and not is_Tuple(newpath):
850 newpaths = [ newpath ]
851 else:
852 newpaths = newpath
853
854 if canonicalize:
855 newpaths=list(map(canonicalize, newpaths))
856
857 if not delete_existing:
858
859
860
861
862
863 result = []
864 normpaths = []
865 for path in paths:
866 if not path:
867 continue
868 result.append(path)
869 normpaths.append(os.path.normpath(os.path.normcase(path)))
870 for path in newpaths:
871 if not path:
872 continue
873 normpath = os.path.normpath(os.path.normcase(path))
874 if normpath not in normpaths:
875 result.append(path)
876 normpaths.append(normpath)
877 paths = result
878 else:
879
880
881 newpaths = paths + newpaths
882 newpaths.reverse()
883
884 normpaths = []
885 paths = []
886
887 for path in newpaths:
888 normpath = os.path.normpath(os.path.normcase(path))
889 if path and not normpath in normpaths:
890 paths.append(path)
891 normpaths.append(normpath)
892 paths.reverse()
893
894 if is_list:
895 return paths
896 else:
897 return sep.join(paths)
898
900 """This function will take 'key' out of the dictionary
901 'env_dict', then add the path 'path' to that key if it is not
902 already there. This treats the value of env_dict[key] as if it
903 has a similar format to the PATH variable...a list of paths
904 separated by tokens. The 'path' will get added to the list if it
905 is not already there."""
906 try:
907 is_list = 1
908 paths = env_dict[key]
909 if not is_List(env_dict[key]):
910 paths = paths.split(sep)
911 is_list = 0
912 if os.path.normcase(path) not in list(map(os.path.normcase, paths)):
913 paths = [ path ] + paths
914 if is_list:
915 env_dict[key] = paths
916 else:
917 env_dict[key] = sep.join(paths)
918 except KeyError:
919 env_dict[key] = path
920
921 if sys.platform == 'cygwin':
923 """Transforms an absolute path into a native path for the system. In
924 Cygwin, this converts from a Cygwin path to a Windows one."""
925 return os.popen('cygpath -w ' + path).read().replace('\n', '')
926 else:
928 """Transforms an absolute path into a native path for the system.
929 Non-Cygwin version, just leave the path alone."""
930 return path
931
932 display = DisplayEngine()
933
935 if is_List(arg) or is_Tuple(arg):
936 return arg
937 elif is_String(arg):
938 return arg.split()
939 else:
940 return [arg]
941
943 """A class for command-line construction variables.
944
945 This is a list that uses Split() to split an initial string along
946 white-space arguments, and similarly to split any strings that get
947 added. This allows us to Do the Right Thing with Append() and
948 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
949 arg2') regardless of whether a user adds a list or a string to a
950 command-line construction variable.
951 """
959 return (self, CLVar(other))
961 return ' '.join(self.data)
962
963
964
965
966
969 self._keys = []
970 UserDict.__init__(self, dict)
971
975
979
981 UserDict.clear(self)
982 self._keys = []
983
988
990 return list(zip(self._keys, list(self.values())))
991
994
996 try:
997 key = self._keys[-1]
998 except IndexError:
999 raise KeyError('dictionary is empty')
1000
1001 val = self[key]
1002 del self[key]
1003
1004 return (key, val)
1005
1009
1013
1015 return list(map(self.get, self._keys))
1016
1018 """A callable ordered dictionary that maps file suffixes to
1019 dictionary values. We preserve the order in which items are added
1020 so that get_suffix() calls always return the first suffix added."""
1021 - def __call__(self, env, source, ext=None):
1022 if ext is None:
1023 try:
1024 ext = source[0].get_suffix()
1025 except IndexError:
1026 ext = ""
1027 try:
1028 return self[ext]
1029 except KeyError:
1030
1031
1032 s_dict = {}
1033 for (k,v) in self.items():
1034 if k is not None:
1035 s_k = env.subst(k)
1036 if s_k in s_dict:
1037
1038
1039
1040
1041 raise KeyError(s_dict[s_k][0], k, s_k)
1042 s_dict[s_k] = (k,v)
1043 try:
1044 return s_dict[ext][1]
1045 except KeyError:
1046 try:
1047 return self[None]
1048 except KeyError:
1049 return None
1050
1051
1052 if sys.platform == 'cygwin':
1053
1054
1057 else:
1059 return (os.path.normcase(s1) != os.path.normcase(s2))
1060
1061 -def adjustixes(fname, pre, suf, ensure_suffix=False):
1062 if pre:
1063 path, fn = os.path.split(os.path.normpath(fname))
1064 if fn[:len(pre)] != pre:
1065 fname = os.path.join(path, pre + fn)
1066
1067
1068
1069 if suf and fname[-len(suf):] != suf and \
1070 (ensure_suffix or not splitext(fname)[1]):
1071 fname = fname + suf
1072 return fname
1073
1074
1075
1076
1077
1078
1079
1080
1082 """Return a list of the elements in s, but without duplicates.
1083
1084 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1085 unique("abcabc") some permutation of ["a", "b", "c"], and
1086 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1087 [[2, 3], [1, 2]].
1088
1089 For best speed, all sequence elements should be hashable. Then
1090 unique() will usually work in linear time.
1091
1092 If not possible, the sequence elements should enjoy a total
1093 ordering, and if list(s).sort() doesn't raise TypeError it's
1094 assumed that they do enjoy a total ordering. Then unique() will
1095 usually work in O(N*log2(N)) time.
1096
1097 If that's not possible either, the sequence elements must support
1098 equality-testing. Then unique() will usually work in quadratic
1099 time.
1100 """
1101
1102 n = len(s)
1103 if n == 0:
1104 return []
1105
1106
1107
1108
1109
1110 u = {}
1111 try:
1112 for x in s:
1113 u[x] = 1
1114 except TypeError:
1115 pass
1116 else:
1117 return list(u.keys())
1118 del u
1119
1120
1121
1122
1123
1124
1125
1126
1127 try:
1128 t = sorted(s)
1129 except TypeError:
1130 pass
1131 else:
1132 assert n > 0
1133 last = t[0]
1134 lasti = i = 1
1135 while i < n:
1136 if t[i] != last:
1137 t[lasti] = last = t[i]
1138 lasti = lasti + 1
1139 i = i + 1
1140 return t[:lasti]
1141 del t
1142
1143
1144 u = []
1145 for x in s:
1146 if x not in u:
1147 u.append(x)
1148 return u
1149
1150
1151
1152
1153
1154
1155
1156
1157
1159 if idfun is None:
1160 def idfun(x): return x
1161 seen = {}
1162 result = []
1163 for item in seq:
1164 marker = idfun(item)
1165
1166
1167
1168 if marker in seen: continue
1169 seen[marker] = 1
1170 result.append(item)
1171 return result
1172
1173
1174
1175
1176
1178 seen = {}
1179 result = []
1180 for item in seq:
1181
1182 if item not in seen:
1183 seen[item] = 1
1184 result.append(item)
1185 return result
1186
1187
1188
1189
1191 logical_line = []
1192 for line in physical_lines:
1193 stripped = line.rstrip()
1194 if stripped.endswith('\\'):
1195
1196 logical_line.append(stripped[:-1])
1197 else:
1198
1199 logical_line.append(line)
1200 yield joiner(logical_line)
1201 logical_line = []
1202 if logical_line:
1203
1204 yield joiner(logical_line)
1205
1206
1208 """ Wrapper class for the logical_lines method.
1209
1210 Allows us to read all "logical" lines at once from a
1211 given file object.
1212 """
1213
1215 self.fileobj = fileobj
1216
1218 result = [l for l in logical_lines(self.fileobj)]
1219 return result
1220
1221
1224 UserList.__init__(self, seq)
1225 self.unique = True
1227 if not self.unique:
1228 self.data = uniquer_hashables(self.data)
1229 self.unique = True
1258 UserList.__setitem__(self, i, item)
1259 self.unique = False
1264 UserList.__setslice__(self, i, j, other)
1265 self.unique = False
1291 UserList.append(self, item)
1292 self.unique = False
1294 UserList.insert(self, i)
1295 self.unique = False
1305 - def sort(self, *args, **kwds):
1309 UserList.extend(self, other)
1310 self.unique = False
1311
1312
1314 """
1315 A proxy class that wraps a file object, flushing after every write,
1316 and delegating everything else to the wrapped object.
1317 """
1319 self.file = file
1320 self.softspace = 0
1322 try:
1323 self.file.write(arg)
1324 self.file.flush()
1325 except IOError:
1326
1327
1328
1329
1330
1331
1332
1333 pass
1335 return getattr(self.file, attr)
1336
1338 """ makes an absolute path name to a relative pathname.
1339 """
1340 if os.path.isabs(path):
1341 drive_s,path = os.path.splitdrive(path)
1342
1343 import re
1344 if not drive_s:
1345 path=re.compile("/*(.*)").findall(path)[0]
1346 else:
1347 path=path[1:]
1348
1349 assert( not os.path.isabs( path ) ), path
1350 return path
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1379 """
1380 Adds either a bound method to an instance or an unbound method to
1381 a class. If name is ommited the name of the specified function
1382 is used by default.
1383 Example:
1384 a = A()
1385 def f(self, x, y):
1386 self.z = x + y
1387 AddMethod(f, A, "add")
1388 a.add(2, 4)
1389 print a.z
1390 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1391 print a.listIndex(5)
1392 """
1393 if name is None:
1394 name = function.func_name
1395 else:
1396 function = RenameFunction(function, name)
1397
1398 if hasattr(obj, '__class__') and obj.__class__ is not type:
1399
1400 setattr(obj, name, MethodType(function, obj, obj.__class__))
1401 else:
1402
1403 setattr(obj, name, MethodType(function, None, obj))
1404
1406 """
1407 Returns a function identical to the specified function, but with
1408 the specified name.
1409 """
1410 return FunctionType(function.func_code,
1411 function.func_globals,
1412 name,
1413 function.func_defaults)
1414
1415
1416 md5 = False
1419
1425
1426 try:
1427 import hashlib
1428 except ImportError:
1429 pass
1430 else:
1431 if hasattr(hashlib, 'md5'):
1432 md5 = True
1434 m = hashlib.md5()
1435 m.update(str(s))
1436 return m.hexdigest()
1437
1439 m = hashlib.md5()
1440 f = open(fname, "rb")
1441 while True:
1442 blck = f.read(chunksize)
1443 if not blck:
1444 break
1445 m.update(str(blck))
1446 f.close()
1447 return m.hexdigest()
1448
1450 """
1451 Collects a list of signatures into an aggregate signature.
1452
1453 signatures - a list of signatures
1454 returns - the aggregate signature
1455 """
1456 if len(signatures) == 1:
1457 return signatures[0]
1458 else:
1459 return MD5signature(', '.join(signatures))
1460
1461
1462
1464 """
1465 Perform sys.intern() on the passed argument and return the result.
1466 If the input is ineligible (e.g. a unicode string) the original argument is
1467 returned and no exception is thrown.
1468 """
1469 try:
1470 return sys.intern(x)
1471 except TypeError:
1472 return x
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483 -class Null(object):
1484 """ Null objects always and reliably "do nothing." """
1485 - def __new__(cls, *args, **kwargs):
1494 return "Null(0x%08X)" % id(self)
1503
1515
1516
1517 del __revision__
1518
1519
1520
1521
1522
1523
1524