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 5110 2010/07/25 16:14:38 bdeegan"
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 """This class is almost exactly like a regular list of Nodes
112 (actually it can hold any object), with one important difference.
113 If you try to get an attribute from this list, it will return that
114 attribute from every item in the list. For example:
115
116 >>> someList = NodeList([ ' foo ', ' bar ' ])
117 >>> someList.strip()
118 [ 'foo', 'bar' ]
119 """
121 return len(self.data) != 0
122
124 return string.join(map(str, self.data))
125
127 return iter(self.data)
128
130 result = map(lambda x, args=args, kwargs=kwargs: apply(x,
131 args,
132 kwargs),
133 self.data)
134 return self.__class__(result)
135
137 result = map(lambda x, n=name: getattr(x, n), self.data)
138 return self.__class__(result)
139
140
141 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
142
144 """Given a string, first determine if it looks like a reference
145 to a single environment variable, like "$FOO" or "${FOO}".
146 If so, return that variable with no decorations ("FOO").
147 If not, return None."""
148 mo=_get_env_var.match(to_String(varstr))
149 if mo:
150 var = mo.group(1)
151 if var[0] == '{':
152 return var[1:-1]
153 else:
154 return var
155 else:
156 return None
157
161
162 - def print_it(self, text, append_newline=1):
163 if append_newline: text = text + '\n'
164 try:
165 sys.stdout.write(text)
166 except IOError:
167
168
169
170
171
172
173
174 pass
175
178
184
185 -def render_tree(root, child_func, prune=0, margin=[0], visited={}):
186 """
187 Render a tree of nodes into an ASCII tree view.
188 root - the root node of the tree
189 child_func - the function called to get the children of a node
190 prune - don't visit the same node twice
191 margin - the format of the left margin to use for children of root.
192 1 results in a pipe, and 0 results in no pipe.
193 visited - a dictionary of visited nodes in the current branch if not prune,
194 or in the whole tree if prune.
195 """
196
197 rname = str(root)
198
199 children = child_func(root)
200 retval = ""
201 for pipe in margin[:-1]:
202 if pipe:
203 retval = retval + "| "
204 else:
205 retval = retval + " "
206
207 if visited.has_key(rname):
208 return retval + "+-[" + rname + "]\n"
209
210 retval = retval + "+-" + rname + "\n"
211 if not prune:
212 visited = copy.copy(visited)
213 visited[rname] = 1
214
215 for i in range(len(children)):
216 margin.append(i<len(children)-1)
217 retval = retval + render_tree(children[i], child_func, prune, margin, visited
218 )
219 margin.pop()
220
221 return retval
222
223 IDX = lambda N: N and 1 or 0
224
225 -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
226 """
227 Print a tree of nodes. This is like render_tree, except it prints
228 lines directly instead of creating a string representation in memory,
229 so that huge trees can be printed.
230
231 root - the root node of the tree
232 child_func - the function called to get the children of a node
233 prune - don't visit the same node twice
234 showtags - print status information to the left of each node line
235 margin - the format of the left margin to use for children of root.
236 1 results in a pipe, and 0 results in no pipe.
237 visited - a dictionary of visited nodes in the current branch if not prune,
238 or in the whole tree if prune.
239 """
240
241 rname = str(root)
242
243 if showtags:
244
245 if showtags == 2:
246 print ' E = exists'
247 print ' R = exists in repository only'
248 print ' b = implicit builder'
249 print ' B = explicit builder'
250 print ' S = side effect'
251 print ' P = precious'
252 print ' A = always build'
253 print ' C = current'
254 print ' N = no clean'
255 print ' H = no cache'
256 print ''
257
258 tags = ['[']
259 tags.append(' E'[IDX(root.exists())])
260 tags.append(' R'[IDX(root.rexists() and not root.exists())])
261 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
262 [0,2][IDX(root.has_builder())]])
263 tags.append(' S'[IDX(root.side_effect)])
264 tags.append(' P'[IDX(root.precious)])
265 tags.append(' A'[IDX(root.always_build)])
266 tags.append(' C'[IDX(root.is_up_to_date())])
267 tags.append(' N'[IDX(root.noclean)])
268 tags.append(' H'[IDX(root.nocache)])
269 tags.append(']')
270
271 else:
272 tags = []
273
274 def MMM(m):
275 return [" ","| "][m]
276 margins = map(MMM, margin[:-1])
277
278 children = child_func(root)
279
280 if prune and visited.has_key(rname) and children:
281 print string.join(tags + margins + ['+-[', rname, ']'], '')
282 return
283
284 print string.join(tags + margins + ['+-', rname], '')
285
286 visited[rname] = 1
287
288 if children:
289 margin.append(1)
290 idx = IDX(showtags)
291 for C in children[:-1]:
292 print_tree(C, child_func, prune, idx, margin, visited)
293 margin[-1] = 0
294 print_tree(children[-1], child_func, prune, idx, margin, visited)
295 margin.pop()
296
297
298
299
300
301
302
303
304
305
306
307 try:
310 except TypeError:
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
331 t = type(obj)
332 return t is DictType or \
333 (t is InstanceType and isinstance(obj, UserDict))
334
336 t = type(obj)
337 return t is ListType \
338 or (t is InstanceType and isinstance(obj, UserList))
339
341 t = type(obj)
342 return t is ListType \
343 or t is TupleType \
344 or (t is InstanceType and isinstance(obj, UserList))
345
347 t = type(obj)
348 return t is TupleType
349
350 if hasattr(types, 'UnicodeType'):
352 t = type(obj)
353 return t is StringType \
354 or t is UnicodeType \
355 or (t is InstanceType and isinstance(obj, UserString))
356 else:
358 t = type(obj)
359 return t is StringType \
360 or (t is InstanceType and isinstance(obj, UserString))
361
363 return is_String(obj) or not is_Sequence(obj)
364
366 """Flatten a sequence to a non-nested list.
367
368 Flatten() converts either a single scalar or a nested sequence
369 to a non-nested list. Note that flatten() considers strings
370 to be scalars instead of sequences like Python would.
371 """
372 if is_Scalar(obj):
373 return [obj]
374 if result is None:
375 result = []
376 for item in obj:
377 if is_Scalar(item):
378 result.append(item)
379 else:
380 flatten_sequence(item, result)
381 return result
382
384 """Flatten a sequence to a non-nested list.
385
386 Same as flatten(), but it does not handle the single scalar
387 case. This is slightly more efficient when one knows that
388 the sequence to flatten can not be a scalar.
389 """
390 if result is None:
391 result = []
392 for item in sequence:
393 if is_Scalar(item):
394 result.append(item)
395 else:
396 flatten_sequence(item, result)
397 return result
398
399
400
401
402
403
404
405 if hasattr(types, 'UnicodeType'):
406 UnicodeType = types.UnicodeType
408 if isinstance(s, UserString):
409 t = type(s.data)
410 else:
411 t = type(s)
412 if t is UnicodeType:
413 return unicode(s)
414 else:
415 return str(s)
416 else:
417 to_String = str
418
420 try:
421 f = obj.for_signature
422 except AttributeError:
423 return to_String_for_subst(obj)
424 else:
425 return f()
426
428 if is_Sequence( s ):
429 return string.join( map(to_String_for_subst, s) )
430
431 return to_String( s )
432
433 else:
434
435
436
437
438
439
440
441
442
443 DictTypes = (dict, UserDict)
444 ListTypes = (list, UserList)
445 SequenceTypes = (list, tuple, UserList)
446
447
448
449
450
451
452
453 StringTypes = (str, unicode, UserString)
454
455
456
457 BaseStringTypes = (str, unicode)
458
461
464
467
468 - def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
469 return isinstance(obj, tuple)
470
473
482
490
493 """Flatten a sequence to a non-nested list.
494
495 Flatten() converts either a single scalar or a nested sequence
496 to a non-nested list. Note that flatten() considers strings
497 to be scalars instead of sequences like Python would.
498 """
499 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
500 return [obj]
501 result = []
502 for item in obj:
503 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
504 result.append(item)
505 else:
506 do_flatten(item, result)
507 return result
508
511 """Flatten a sequence to a non-nested list.
512
513 Same as flatten(), but it does not handle the single scalar
514 case. This is slightly more efficient when one knows that
515 the sequence to flatten can not be a scalar.
516 """
517 result = []
518 for item in sequence:
519 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
520 result.append(item)
521 else:
522 do_flatten(item, result)
523 return result
524
525
526
527
528
529
530
531
535 if isinstance(s,BaseStringTypes):
536
537 return s
538 elif isinstance(s, UserString):
539
540
541 return s.data
542 else:
543 return str(s)
544
549
550
551 if isinstance(s, BaseStringTypes):
552 return s
553 elif isinstance(s, SequenceTypes):
554 l = []
555 for e in s:
556 l.append(to_String_for_subst(e))
557 return join( s )
558 elif isinstance(s, UserString):
559
560
561 return s.data
562 else:
563 return str(s)
564
567 try:
568 f = obj.for_signature
569 except AttributeError:
570 return to_String_for_subst(obj)
571 else:
572 return f()
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589 _semi_deepcopy_dispatch = d = {}
590
592 copy = {}
593 for key, val in x.items():
594
595
596
597
598
599
600 copy[key] = semi_deepcopy(val)
601 return copy
602 d[types.DictionaryType] = _semi_deepcopy_dict
603
605 return map(semi_deepcopy, x)
606 d[types.ListType] = _semi_deepcopy_list
607
609 return tuple(map(semi_deepcopy, x))
610 d[types.TupleType] = _semi_deepcopy_tuple
611
613 copier = _semi_deepcopy_dispatch.get(type(x))
614 if copier:
615 return copier(x)
616 else:
617 if hasattr(x, '__semi_deepcopy__'):
618 return x.__semi_deepcopy__()
619 elif isinstance(x, UserDict):
620 return x.__class__(_semi_deepcopy_dict(x))
621 elif isinstance(x, UserList):
622 return x.__class__(_semi_deepcopy_list(x))
623
624 return x
625
626
627
629 """A simple generic Proxy class, forwarding all calls to
630 subject. So, for the benefit of the python newbie, what does
631 this really mean? Well, it means that you can take an object, let's
632 call it 'objA', and wrap it in this Proxy class, with a statement
633 like this
634
635 proxyObj = Proxy(objA),
636
637 Then, if in the future, you do something like this
638
639 x = proxyObj.var1,
640
641 since Proxy does not have a 'var1' attribute (but presumably objA does),
642 the request actually is equivalent to saying
643
644 x = objA.var1
645
646 Inherit from this class to create a Proxy."""
647
649 """Wrap an object as a Proxy object"""
650 self.__subject = subject
651
653 """Retrieve an attribute from the wrapped object. If the named
654 attribute doesn't exist, AttributeError is raised"""
655 return getattr(self.__subject, name)
656
658 """Retrieve the entire wrapped object"""
659 return self.__subject
660
662 if issubclass(other.__class__, self.__subject.__class__):
663 return cmp(self.__subject, other)
664 return cmp(self.__dict__, other.__dict__)
665
666
667 can_read_reg = 0
668 try:
669 import _winreg
670
671 can_read_reg = 1
672 hkey_mod = _winreg
673
674 RegOpenKeyEx = _winreg.OpenKeyEx
675 RegEnumKey = _winreg.EnumKey
676 RegEnumValue = _winreg.EnumValue
677 RegQueryValueEx = _winreg.QueryValueEx
678 RegError = _winreg.error
679
680 except ImportError:
681 try:
682 import win32api
683 import win32con
684 can_read_reg = 1
685 hkey_mod = win32con
686
687 RegOpenKeyEx = win32api.RegOpenKeyEx
688 RegEnumKey = win32api.RegEnumKey
689 RegEnumValue = win32api.RegEnumValue
690 RegQueryValueEx = win32api.RegQueryValueEx
691 RegError = win32api.error
692
693 except ImportError:
696 RegError = _NoError
697
698 if can_read_reg:
699 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
700 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
701 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
702 HKEY_USERS = hkey_mod.HKEY_USERS
703
705 """This utility function returns a value in the registry
706 without having to open the key first. Only available on
707 Windows platforms with a version of Python that can read the
708 registry. Returns the same thing as
709 SCons.Util.RegQueryValueEx, except you just specify the entire
710 path to the value, and don't have to bother opening the key
711 first. So:
712
713 Instead of:
714 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
715 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
716 out = SCons.Util.RegQueryValueEx(k,
717 'ProgramFilesDir')
718
719 You can write:
720 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
721 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
722 """
723
724
725 p = key.rfind('\\') + 1
726 keyp = key[:p-1]
727 val = key[p:]
728 k = RegOpenKeyEx(root, keyp)
729 return RegQueryValueEx(k,val)
730 else:
731 try:
732 e = WindowsError
733 except NameError:
734
735
736
737
740 import __builtin__
741 __builtin__.WindowsError = WindowsError
742 else:
743 del e
744
745 HKEY_CLASSES_ROOT = None
746 HKEY_LOCAL_MACHINE = None
747 HKEY_CURRENT_USER = None
748 HKEY_USERS = None
749
752
755
756 if sys.platform == 'win32':
757
758 - def WhereIs(file, path=None, pathext=None, reject=[]):
759 if path is None:
760 try:
761 path = os.environ['PATH']
762 except KeyError:
763 return None
764 if is_String(path):
765 path = string.split(path, os.pathsep)
766 if pathext is None:
767 try:
768 pathext = os.environ['PATHEXT']
769 except KeyError:
770 pathext = '.COM;.EXE;.BAT;.CMD'
771 if is_String(pathext):
772 pathext = string.split(pathext, os.pathsep)
773 for ext in pathext:
774 if string.lower(ext) == string.lower(file[-len(ext):]):
775 pathext = ['']
776 break
777 if not is_List(reject) and not is_Tuple(reject):
778 reject = [reject]
779 for dir in path:
780 f = os.path.join(dir, file)
781 for ext in pathext:
782 fext = f + ext
783 if os.path.isfile(fext):
784 try:
785 reject.index(fext)
786 except ValueError:
787 return os.path.normpath(fext)
788 continue
789 return None
790
791 elif os.name == 'os2':
792
793 - def WhereIs(file, path=None, pathext=None, reject=[]):
794 if path is None:
795 try:
796 path = os.environ['PATH']
797 except KeyError:
798 return None
799 if is_String(path):
800 path = string.split(path, os.pathsep)
801 if pathext is None:
802 pathext = ['.exe', '.cmd']
803 for ext in pathext:
804 if string.lower(ext) == string.lower(file[-len(ext):]):
805 pathext = ['']
806 break
807 if not is_List(reject) and not is_Tuple(reject):
808 reject = [reject]
809 for dir in path:
810 f = os.path.join(dir, file)
811 for ext in pathext:
812 fext = f + ext
813 if os.path.isfile(fext):
814 try:
815 reject.index(fext)
816 except ValueError:
817 return os.path.normpath(fext)
818 continue
819 return None
820
821 else:
822
823 - def WhereIs(file, path=None, pathext=None, reject=[]):
824 import stat
825 if path is None:
826 try:
827 path = os.environ['PATH']
828 except KeyError:
829 return None
830 if is_String(path):
831 path = string.split(path, os.pathsep)
832 if not is_List(reject) and not is_Tuple(reject):
833 reject = [reject]
834 for d in path:
835 f = os.path.join(d, file)
836 if os.path.isfile(f):
837 try:
838 st = os.stat(f)
839 except OSError:
840
841
842
843
844 continue
845 if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
846 try:
847 reject.index(f)
848 except ValueError:
849 return os.path.normpath(f)
850 continue
851 return None
852
853 -def PrependPath(oldpath, newpath, sep = os.pathsep,
854 delete_existing=1, canonicalize=None):
855 """This prepends newpath elements to the given oldpath. Will only
856 add any particular path once (leaving the first one it encounters
857 and ignoring the rest, to preserve path order), and will
858 os.path.normpath and os.path.normcase all paths to help assure
859 this. This can also handle the case where the given old path
860 variable is a list instead of a string, in which case a list will
861 be returned instead of a string.
862
863 Example:
864 Old Path: "/foo/bar:/foo"
865 New Path: "/biz/boom:/foo"
866 Result: "/biz/boom:/foo:/foo/bar"
867
868 If delete_existing is 0, then adding a path that exists will
869 not move it to the beginning; it will stay where it is in the
870 list.
871
872 If canonicalize is not None, it is applied to each element of
873 newpath before use.
874 """
875
876 orig = oldpath
877 is_list = 1
878 paths = orig
879 if not is_List(orig) and not is_Tuple(orig):
880 paths = string.split(paths, sep)
881 is_list = 0
882
883 if is_String(newpath):
884 newpaths = string.split(newpath, sep)
885 elif not is_List(newpath) and not is_Tuple(newpath):
886 newpaths = [ newpath ]
887 else:
888 newpaths = newpath
889
890 if canonicalize:
891 newpaths=map(canonicalize, newpaths)
892
893 if not delete_existing:
894
895
896
897
898
899 result = []
900 normpaths = []
901 for path in paths:
902 if not path:
903 continue
904 normpath = os.path.normpath(os.path.normcase(path))
905 if normpath not in normpaths:
906 result.append(path)
907 normpaths.append(normpath)
908 newpaths.reverse()
909 for path in newpaths:
910 if not path:
911 continue
912 normpath = os.path.normpath(os.path.normcase(path))
913 if normpath not in normpaths:
914 result.insert(0, path)
915 normpaths.append(normpath)
916 paths = result
917
918 else:
919 newpaths = newpaths + paths
920
921 normpaths = []
922 paths = []
923
924 for path in newpaths:
925 normpath = os.path.normpath(os.path.normcase(path))
926 if path and not normpath in normpaths:
927 paths.append(path)
928 normpaths.append(normpath)
929
930 if is_list:
931 return paths
932 else:
933 return string.join(paths, sep)
934
935 -def AppendPath(oldpath, newpath, sep = os.pathsep,
936 delete_existing=1, canonicalize=None):
937 """This appends new path elements to the given old path. Will
938 only add any particular path once (leaving the last one it
939 encounters and ignoring the rest, to preserve path order), and
940 will os.path.normpath and os.path.normcase all paths to help
941 assure this. This can also handle the case where the given old
942 path variable is a list instead of a string, in which case a list
943 will be returned instead of a string.
944
945 Example:
946 Old Path: "/foo/bar:/foo"
947 New Path: "/biz/boom:/foo"
948 Result: "/foo/bar:/biz/boom:/foo"
949
950 If delete_existing is 0, then adding a path that exists
951 will not move it to the end; it will stay where it is in the list.
952
953 If canonicalize is not None, it is applied to each element of
954 newpath before use.
955 """
956
957 orig = oldpath
958 is_list = 1
959 paths = orig
960 if not is_List(orig) and not is_Tuple(orig):
961 paths = string.split(paths, sep)
962 is_list = 0
963
964 if is_String(newpath):
965 newpaths = string.split(newpath, sep)
966 elif not is_List(newpath) and not is_Tuple(newpath):
967 newpaths = [ newpath ]
968 else:
969 newpaths = newpath
970
971 if canonicalize:
972 newpaths=map(canonicalize, newpaths)
973
974 if not delete_existing:
975
976
977
978
979
980 result = []
981 normpaths = []
982 for path in paths:
983 if not path:
984 continue
985 result.append(path)
986 normpaths.append(os.path.normpath(os.path.normcase(path)))
987 for path in newpaths:
988 if not path:
989 continue
990 normpath = os.path.normpath(os.path.normcase(path))
991 if normpath not in normpaths:
992 result.append(path)
993 normpaths.append(normpath)
994 paths = result
995 else:
996
997
998 newpaths = paths + newpaths
999 newpaths.reverse()
1000
1001 normpaths = []
1002 paths = []
1003
1004 for path in newpaths:
1005 normpath = os.path.normpath(os.path.normcase(path))
1006 if path and not normpath in normpaths:
1007 paths.append(path)
1008 normpaths.append(normpath)
1009 paths.reverse()
1010
1011 if is_list:
1012 return paths
1013 else:
1014 return string.join(paths, sep)
1015
1016 if sys.platform == 'cygwin':
1018 """Transforms an absolute path into a native path for the system. In
1019 Cygwin, this converts from a Cygwin path to a Windows one."""
1020 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
1021 else:
1023 """Transforms an absolute path into a native path for the system.
1024 Non-Cygwin version, just leave the path alone."""
1025 return path
1026
1027 display = DisplayEngine()
1028
1030 if is_List(arg) or is_Tuple(arg):
1031 return arg
1032 elif is_String(arg):
1033 return string.split(arg)
1034 else:
1035 return [arg]
1036
1038 """A class for command-line construction variables.
1039
1040 This is a list that uses Split() to split an initial string along
1041 white-space arguments, and similarly to split any strings that get
1042 added. This allows us to Do the Right Thing with Append() and
1043 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
1044 arg2') regardless of whether a user adds a list or a string to a
1045 command-line construction variable.
1046 """
1054 return (self, CLVar(other))
1056 return string.join(self.data)
1057
1058
1059
1060
1061
1066
1070
1072 UserDict.__setitem__(self, key, item)
1073 if key not in self._keys: self._keys.append(key)
1074
1076 UserDict.clear(self)
1077 self._keys = []
1078
1083
1086
1088 return self._keys[:]
1089
1091 try:
1092 key = self._keys[-1]
1093 except IndexError:
1094 raise KeyError('dictionary is empty')
1095
1096 val = self[key]
1097 del self[key]
1098
1099 return (key, val)
1100
1102 UserDict.setdefault(self, key, failobj)
1103 if key not in self._keys: self._keys.append(key)
1104
1108
1110 return map(self.get, self._keys)
1111
1113 """A callable ordered dictionary that maps file suffixes to
1114 dictionary values. We preserve the order in which items are added
1115 so that get_suffix() calls always return the first suffix added."""
1116 - def __call__(self, env, source, ext=None):
1117 if ext is None:
1118 try:
1119 ext = source[0].suffix
1120 except IndexError:
1121 ext = ""
1122 try:
1123 return self[ext]
1124 except KeyError:
1125
1126
1127 s_dict = {}
1128 for (k,v) in self.items():
1129 if k is not None:
1130 s_k = env.subst(k)
1131 if s_dict.has_key(s_k):
1132
1133
1134
1135
1136 raise KeyError, (s_dict[s_k][0], k, s_k)
1137 s_dict[s_k] = (k,v)
1138 try:
1139 return s_dict[ext][1]
1140 except KeyError:
1141 try:
1142 return self[None]
1143 except KeyError:
1144 return None
1145
1146
1147 if sys.platform == 'cygwin':
1148
1149
1152 else:
1154 return (os.path.normcase(s1) != os.path.normcase(s2))
1155
1157 if pre:
1158 path, fn = os.path.split(os.path.normpath(fname))
1159 if fn[:len(pre)] != pre:
1160 fname = os.path.join(path, pre + fn)
1161
1162
1163
1164 if suf and fname[-len(suf):] != suf and \
1165 (ensure_suffix or not splitext(fname)[1]):
1166 fname = fname + suf
1167 return fname
1168
1169
1170
1171
1172
1173
1174
1175
1177 """Return a list of the elements in s, but without duplicates.
1178
1179 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1180 unique("abcabc") some permutation of ["a", "b", "c"], and
1181 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1182 [[2, 3], [1, 2]].
1183
1184 For best speed, all sequence elements should be hashable. Then
1185 unique() will usually work in linear time.
1186
1187 If not possible, the sequence elements should enjoy a total
1188 ordering, and if list(s).sort() doesn't raise TypeError it's
1189 assumed that they do enjoy a total ordering. Then unique() will
1190 usually work in O(N*log2(N)) time.
1191
1192 If that's not possible either, the sequence elements must support
1193 equality-testing. Then unique() will usually work in quadratic
1194 time.
1195 """
1196
1197 n = len(s)
1198 if n == 0:
1199 return []
1200
1201
1202
1203
1204
1205 u = {}
1206 try:
1207 for x in s:
1208 u[x] = 1
1209 except TypeError:
1210 pass
1211 else:
1212 return u.keys()
1213 del u
1214
1215
1216
1217
1218
1219
1220
1221
1222 try:
1223 t = list(s)
1224 t.sort()
1225 except TypeError:
1226 pass
1227 else:
1228 assert n > 0
1229 last = t[0]
1230 lasti = i = 1
1231 while i < n:
1232 if t[i] != last:
1233 t[lasti] = last = t[i]
1234 lasti = lasti + 1
1235 i = i + 1
1236 return t[:lasti]
1237 del t
1238
1239
1240 u = []
1241 for x in s:
1242 if x not in u:
1243 u.append(x)
1244 return u
1245
1246
1247
1248
1249
1250
1251
1252
1253
1255 if idfun is None:
1256 def idfun(x): return x
1257 seen = {}
1258 result = []
1259 for item in seq:
1260 marker = idfun(item)
1261
1262
1263
1264 if marker in seen: continue
1265 seen[marker] = 1
1266 result.append(item)
1267 return result
1268
1269
1270
1271
1272
1282
1283
1284
1285
1286
1288
1290 self.fileobj = fileobj
1291
1304
1313
1314
1315
1321 if not self.unique:
1322 self.data = uniquer_hashables(self.data)
1323 self.unique = True
1385 UserList.append(self, item)
1386 self.unique = False
1399 - def sort(self, *args, **kwds):
1404 UserList.extend(self, other)
1405 self.unique = False
1406
1407
1408
1410 """
1411 A proxy class that wraps a file object, flushing after every write,
1412 and delegating everything else to the wrapped object.
1413 """
1417 try:
1418 self.file.write(arg)
1419 self.file.flush()
1420 except IOError:
1421
1422
1423
1424
1425
1426
1427
1428 pass
1430 return getattr(self.file, attr)
1431
1433 """ makes an absolute path name to a relative pathname.
1434 """
1435 if os.path.isabs(path):
1436 drive_s,path = os.path.splitdrive(path)
1437
1438 import re
1439 if not drive_s:
1440 path=re.compile("/*(.*)").findall(path)[0]
1441 else:
1442 path=path[1:]
1443
1444 assert( not os.path.isabs( path ) ), path
1445 return path
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473 -def AddMethod(object, function, name = None):
1474 """
1475 Adds either a bound method to an instance or an unbound method to
1476 a class. If name is ommited the name of the specified function
1477 is used by default.
1478 Example:
1479 a = A()
1480 def f(self, x, y):
1481 self.z = x + y
1482 AddMethod(f, A, "add")
1483 a.add(2, 4)
1484 print a.z
1485 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1486 print a.listIndex(5)
1487 """
1488 import new
1489
1490 if name is None:
1491 name = function.func_name
1492 else:
1493 function = RenameFunction(function, name)
1494
1495 try:
1496 klass = object.__class__
1497 except AttributeError:
1498
1499 object.__dict__[name] = new.instancemethod(function, None, object)
1500 else:
1501
1502 object.__dict__[name] = new.instancemethod(function, object, klass)
1503
1505 """
1506 Returns a function identical to the specified function, but with
1507 the specified name.
1508 """
1509 import new
1510
1511
1512
1513
1514 func_defaults = function.func_defaults
1515 if func_defaults is None:
1516 func_defaults = ()
1517
1518 return new.function(function.func_code,
1519 function.func_globals,
1520 name,
1521 func_defaults)
1522
1523
1524 md5 = False
1527
1533
1534 try:
1535 import hashlib
1536 except ImportError:
1537 pass
1538 else:
1539 if hasattr(hashlib, 'md5'):
1540 md5 = True
1545
1547 m = hashlib.md5()
1548 f = open(fname, "rb")
1549 while 1:
1550 blck = f.read(chunksize)
1551 if not blck:
1552 break
1553 m.update(str(blck))
1554 f.close()
1555 return m.hexdigest()
1556
1558 """
1559 Collects a list of signatures into an aggregate signature.
1560
1561 signatures - a list of signatures
1562 returns - the aggregate signature
1563 """
1564 if len(signatures) == 1:
1565 return signatures[0]
1566 else:
1567 return MD5signature(string.join(signatures, ', '))
1568
1569
1570
1571
1572
1573
1574 try:
1575 intern
1576 except NameError:
1577 from sys import intern
1578
1580 """
1581 Perform intern() on the passed argument and return the result.
1582 If the input is ineligible (e.g. a unicode string) the original argument is
1583 returned and no exception is thrown.
1584 """
1585 try:
1586 return intern(x)
1587 except TypeError:
1588 return x
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1601 """ Null objects always and reliably "do nothing." """
1602 - def __new__(cls, *args, **kwargs):
1603 if not '_inst' in vars(cls):
1604
1605 cls._inst = apply(type.__new__, (cls,) + args, kwargs)
1606 return cls._inst
1612 return "Null(0x%08X)" % id(self)
1621
1633
1634
1635 del __revision__
1636
1637
1638
1639
1640
1641
1642