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_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
28
29 import os
30 import sys
31 import copy
32 import re
33 import types
34 import codecs
35 import pprint
36
37 PY3 = sys.version_info[0] == 3
38
39 try:
40 from UserDict import UserDict
41 except ImportError as e:
42 from collections import UserDict
43
44 try:
45 from UserList import UserList
46 except ImportError as e:
47 from collections import UserList
48
49 from collections import Iterable
50
51 try:
52 from UserString import UserString
53 except ImportError as e:
54 from collections import UserString
55
56
57
58
59
60
61
62 MethodType = types.MethodType
63 FunctionType = types.FunctionType
64
65 try:
66 unicode
67 except NameError:
68 UnicodeType = str
69 else:
70 UnicodeType = unicode
71
72 -def dictify(keys, values, result={}):
76
77 _altsep = os.altsep
78 if _altsep is None and sys.platform == 'win32':
79
80 _altsep = '/'
81 if _altsep:
84 else:
86 return path.rfind(sep)
87
88
89
91 """Check whether sequence str contains ANY of the items in set."""
92 for c in set:
93 if c in str: return 1
94 return 0
95
97 """Check whether sequence str contains ALL of the items in set."""
98 for c in set:
99 if c not in str: return 0
100 return 1
101
103 """Check whether sequence str contains ONLY items in set."""
104 for c in str:
105 if c not in set: return 0
106 return 1
107
109 "Same as os.path.splitext() but faster."
110 sep = rightmost_separator(path, os.sep)
111 dot = path.rfind('.')
112
113 if dot > sep and not containsOnly(path[dot:], "0123456789."):
114 return path[:dot],path[dot:]
115 else:
116 return path,""
117
119 """
120 Make the drive letter (if any) upper case.
121 This is useful because Windows is inconsistent on the case
122 of the drive letter, which can cause inconsistencies when
123 calculating command signatures.
124 """
125 drive, rest = os.path.splitdrive(path)
126 if drive:
127 path = drive.upper() + rest
128 return path
129
131 """This class is almost exactly like a regular list of Nodes
132 (actually it can hold any object), with one important difference.
133 If you try to get an attribute from this list, it will return that
134 attribute from every item in the list. For example:
135
136 >>> someList = NodeList([ ' foo ', ' bar ' ])
137 >>> someList.strip()
138 [ 'foo', 'bar' ]
139 """
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
157 return len(self.data) != 0
158
161
163 return ' '.join(map(str, self.data))
164
166 return iter(self.data)
167
169 result = [x(*args, **kwargs) for x in self.data]
170 return self.__class__(result)
171
175
177 """
178 This comes for free on py2,
179 but py3 slices of NodeList are returning a list
180 breaking slicing nodelist and refering to
181 properties and methods on contained object
182 """
183
184
185 if isinstance(index, slice):
186
187
188 indices = index.indices(len(self.data))
189 return self.__class__([self[x] for x in
190 range(*indices)])
191 else:
192
193 return self.data[index]
194
195
196 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
197
199 """Given a string, first determine if it looks like a reference
200 to a single environment variable, like "$FOO" or "${FOO}".
201 If so, return that variable with no decorations ("FOO").
202 If not, return None."""
203 mo=_get_env_var.match(to_String(varstr))
204 if mo:
205 var = mo.group(1)
206 if var[0] == '{':
207 return var[1:-1]
208 else:
209 return var
210 else:
211 return None
212
214 print_it = True
215 - def __call__(self, text, append_newline=1):
216 if not self.print_it:
217 return
218 if append_newline: text = text + '\n'
219 try:
220 sys.stdout.write(UnicodeType(text))
221 except IOError:
222
223
224
225
226
227
228
229 pass
230
233
234
235 -def render_tree(root, child_func, prune=0, margin=[0], visited=None):
236 """
237 Render a tree of nodes into an ASCII tree view.
238
239 :Parameters:
240 - `root`: the root node of the tree
241 - `child_func`: the function called to get the children of a node
242 - `prune`: don't visit the same node twice
243 - `margin`: the format of the left margin to use for children of root. 1 results in a pipe, and 0 results in no pipe.
244 - `visited`: a dictionary of visited nodes in the current branch if not prune, or in the whole tree if prune.
245 """
246
247 rname = str(root)
248
249
250 if visited is None:
251 visited = {}
252
253 children = child_func(root)
254 retval = ""
255 for pipe in margin[:-1]:
256 if pipe:
257 retval = retval + "| "
258 else:
259 retval = retval + " "
260
261 if rname in visited:
262 return retval + "+-[" + rname + "]\n"
263
264 retval = retval + "+-" + rname + "\n"
265 if not prune:
266 visited = copy.copy(visited)
267 visited[rname] = 1
268
269 for i in range(len(children)):
270 margin.append(i < len(children)-1)
271 retval = retval + render_tree(children[i], child_func, prune, margin, visited)
272 margin.pop()
273
274 return retval
275
276 IDX = lambda N: N and 1 or 0
277
278
279 -def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited=None):
280 """
281 Print a tree of nodes. This is like render_tree, except it prints
282 lines directly instead of creating a string representation in memory,
283 so that huge trees can be printed.
284
285 :Parameters:
286 - `root` - the root node of the tree
287 - `child_func` - the function called to get the children of a node
288 - `prune` - don't visit the same node twice
289 - `showtags` - print status information to the left of each node line
290 - `margin` - the format of the left margin to use for children of root. 1 results in a pipe, and 0 results in no pipe.
291 - `visited` - a dictionary of visited nodes in the current branch if not prune, or in the whole tree if prune.
292 """
293
294 rname = str(root)
295
296
297
298 if visited is None:
299 visited = {}
300
301 if showtags:
302
303 if showtags == 2:
304 legend = (' E = exists\n' +
305 ' R = exists in repository only\n' +
306 ' b = implicit builder\n' +
307 ' B = explicit builder\n' +
308 ' S = side effect\n' +
309 ' P = precious\n' +
310 ' A = always build\n' +
311 ' C = current\n' +
312 ' N = no clean\n' +
313 ' H = no cache\n' +
314 '\n')
315 sys.stdout.write(legend)
316
317 tags = ['[']
318 tags.append(' E'[IDX(root.exists())])
319 tags.append(' R'[IDX(root.rexists() and not root.exists())])
320 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
321 [0,2][IDX(root.has_builder())]])
322 tags.append(' S'[IDX(root.side_effect)])
323 tags.append(' P'[IDX(root.precious)])
324 tags.append(' A'[IDX(root.always_build)])
325 tags.append(' C'[IDX(root.is_up_to_date())])
326 tags.append(' N'[IDX(root.noclean)])
327 tags.append(' H'[IDX(root.nocache)])
328 tags.append(']')
329
330 else:
331 tags = []
332
333 def MMM(m):
334 return [" ","| "][m]
335 margins = list(map(MMM, margin[:-1]))
336
337 children = child_func(root)
338
339 if prune and rname in visited and children:
340 sys.stdout.write(''.join(tags + margins + ['+-[', rname, ']']) + '\n')
341 return
342
343 sys.stdout.write(''.join(tags + margins + ['+-', rname]) + '\n')
344
345 visited[rname] = 1
346
347 if children:
348 margin.append(1)
349 idx = IDX(showtags)
350 for C in children[:-1]:
351 print_tree(C, child_func, prune, idx, margin, visited)
352 margin[-1] = 0
353 print_tree(children[-1], child_func, prune, idx, margin, visited)
354 margin.pop()
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 DictTypes = (dict, UserDict)
373 ListTypes = (list, UserList)
374 SequenceTypes = (list, tuple, UserList)
375
376
377
378
379 try:
380 StringTypes = (str, unicode, UserString)
381 except NameError:
382 StringTypes = (str, UserString)
383
384
385
386 try:
387 BaseStringTypes = (str, unicode)
388 except NameError:
389 BaseStringTypes = (str)
390
393
396
399
400 -def is_Tuple(obj, isinstance=isinstance, tuple=tuple):
401 return isinstance(obj, tuple)
402
405
414
422
425 """Flatten a sequence to a non-nested list.
426
427 Flatten() converts either a single scalar or a nested sequence
428 to a non-nested list. Note that flatten() considers strings
429 to be scalars instead of sequences like Python would.
430 """
431 if isinstance(obj, StringTypes) or not isinstance(obj, SequenceTypes):
432 return [obj]
433 result = []
434 for item in obj:
435 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
436 result.append(item)
437 else:
438 do_flatten(item, result)
439 return result
440
443 """Flatten a sequence to a non-nested list.
444
445 Same as flatten(), but it does not handle the single scalar
446 case. This is slightly more efficient when one knows that
447 the sequence to flatten can not be a scalar.
448 """
449 result = []
450 for item in sequence:
451 if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes):
452 result.append(item)
453 else:
454 do_flatten(item, result)
455 return result
456
457
458
459
460
461
465 if isinstance(s,BaseStringTypes):
466
467 return s
468 elif isinstance(s, UserString):
469
470
471 return s.data
472 else:
473 return str(s)
474
479
480
481 if isinstance(s, BaseStringTypes):
482 return s
483 elif isinstance(s, SequenceTypes):
484 l = []
485 for e in s:
486 l.append(to_String_for_subst(e))
487 return ' '.join( s )
488 elif isinstance(s, UserString):
489
490
491 return s.data
492 else:
493 return str(s)
494
497 try:
498 f = obj.for_signature
499 except AttributeError:
500 if isinstance(obj, dict):
501
502
503
504 return pprint.pformat(obj, width=1000000)
505 else:
506 return to_String_for_subst(obj)
507 else:
508 return f()
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524 _semi_deepcopy_dispatch = d = {}
525
527 copy = {}
528 for key, val in x.items():
529
530
531
532
533
534
535 if key not in exclude:
536 copy[key] = semi_deepcopy(val)
537 return copy
538 d[dict] = semi_deepcopy_dict
539
541 return list(map(semi_deepcopy, x))
542 d[list] = _semi_deepcopy_list
543
545 return tuple(map(semi_deepcopy, x))
546 d[tuple] = _semi_deepcopy_tuple
547
549 copier = _semi_deepcopy_dispatch.get(type(x))
550 if copier:
551 return copier(x)
552 else:
553 if hasattr(x, '__semi_deepcopy__') and callable(x.__semi_deepcopy__):
554 return x.__semi_deepcopy__()
555 elif isinstance(x, UserDict):
556 return x.__class__(semi_deepcopy_dict(x))
557 elif isinstance(x, UserList):
558 return x.__class__(_semi_deepcopy_list(x))
559
560 return x
561
562
564 """A simple generic Proxy class, forwarding all calls to
565 subject. So, for the benefit of the python newbie, what does
566 this really mean? Well, it means that you can take an object, let's
567 call it 'objA', and wrap it in this Proxy class, with a statement
568 like this
569
570 proxyObj = Proxy(objA),
571
572 Then, if in the future, you do something like this
573
574 x = proxyObj.var1,
575
576 since Proxy does not have a 'var1' attribute (but presumably objA does),
577 the request actually is equivalent to saying
578
579 x = objA.var1
580
581 Inherit from this class to create a Proxy.
582
583 Note that, with new-style classes, this does *not* work transparently
584 for Proxy subclasses that use special .__*__() method names, because
585 those names are now bound to the class, not the individual instances.
586 You now need to know in advance which .__*__() method names you want
587 to pass on to the underlying Proxy object, and specifically delegate
588 their calls like this:
589
590 class Foo(Proxy):
591 __str__ = Delegate('__str__')
592 """
593
595 """Wrap an object as a Proxy object"""
596 self._subject = subject
597
599 """Retrieve an attribute from the wrapped object. If the named
600 attribute doesn't exist, AttributeError is raised"""
601 return getattr(self._subject, name)
602
604 """Retrieve the entire wrapped object"""
605 return self._subject
606
608 if issubclass(other.__class__, self._subject.__class__):
609 return self._subject == other
610 return self.__dict__ == other.__dict__
611
613 """A Python Descriptor class that delegates attribute fetches
614 to an underlying wrapped subject of a Proxy. Typical use:
615
616 class Foo(Proxy):
617 __str__ = Delegate('__str__')
618 """
620 self.attribute = attribute
622 if isinstance(obj, cls):
623 return getattr(obj._subject, self.attribute)
624 else:
625 return self
626
627
628 can_read_reg = 0
629 try:
630 import winreg
631
632 can_read_reg = 1
633 hkey_mod = winreg
634
635 RegOpenKeyEx = winreg.OpenKeyEx
636 RegEnumKey = winreg.EnumKey
637 RegEnumValue = winreg.EnumValue
638 RegQueryValueEx = winreg.QueryValueEx
639 RegError = winreg.error
640
641 except ImportError:
642 try:
643 import win32api
644 import win32con
645 can_read_reg = 1
646 hkey_mod = win32con
647
648 RegOpenKeyEx = win32api.RegOpenKeyEx
649 RegEnumKey = win32api.RegEnumKey
650 RegEnumValue = win32api.RegEnumValue
651 RegQueryValueEx = win32api.RegQueryValueEx
652 RegError = win32api.error
653
654 except ImportError:
657 RegError = _NoError
658
659 WinError = None
660
661
662
663
666 try:
667 WinError = WindowsError
668 except NameError:
669 WinError = PlainWindowsError
670
671
672 if can_read_reg:
673 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
674 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
675 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
676 HKEY_USERS = hkey_mod.HKEY_USERS
677
679 """This utility function returns a value in the registry
680 without having to open the key first. Only available on
681 Windows platforms with a version of Python that can read the
682 registry. Returns the same thing as
683 SCons.Util.RegQueryValueEx, except you just specify the entire
684 path to the value, and don't have to bother opening the key
685 first. So:
686
687 Instead of:
688 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
689 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
690 out = SCons.Util.RegQueryValueEx(k,
691 'ProgramFilesDir')
692
693 You can write:
694 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
695 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
696 """
697
698
699 p = key.rfind('\\') + 1
700 keyp = key[:p-1]
701 val = key[p:]
702 k = RegOpenKeyEx(root, keyp)
703 return RegQueryValueEx(k,val)
704 else:
705 HKEY_CLASSES_ROOT = None
706 HKEY_LOCAL_MACHINE = None
707 HKEY_CURRENT_USER = None
708 HKEY_USERS = None
709
712
715
716 if sys.platform == 'win32':
717
718 - def WhereIs(file, path=None, pathext=None, reject=[]):
719 if path is None:
720 try:
721 path = os.environ['PATH']
722 except KeyError:
723 return None
724 if is_String(path):
725 path = path.split(os.pathsep)
726 if pathext is None:
727 try:
728 pathext = os.environ['PATHEXT']
729 except KeyError:
730 pathext = '.COM;.EXE;.BAT;.CMD'
731 if is_String(pathext):
732 pathext = pathext.split(os.pathsep)
733 for ext in pathext:
734 if ext.lower() == file[-len(ext):].lower():
735 pathext = ['']
736 break
737 if not is_List(reject) and not is_Tuple(reject):
738 reject = [reject]
739 for dir in path:
740 f = os.path.join(dir, file)
741 for ext in pathext:
742 fext = f + ext
743 if os.path.isfile(fext):
744 try:
745 reject.index(fext)
746 except ValueError:
747 return os.path.normpath(fext)
748 continue
749 return None
750
751 elif os.name == 'os2':
752
753 - def WhereIs(file, path=None, pathext=None, reject=[]):
754 if path is None:
755 try:
756 path = os.environ['PATH']
757 except KeyError:
758 return None
759 if is_String(path):
760 path = path.split(os.pathsep)
761 if pathext is None:
762 pathext = ['.exe', '.cmd']
763 for ext in pathext:
764 if ext.lower() == file[-len(ext):].lower():
765 pathext = ['']
766 break
767 if not is_List(reject) and not is_Tuple(reject):
768 reject = [reject]
769 for dir in path:
770 f = os.path.join(dir, file)
771 for ext in pathext:
772 fext = f + ext
773 if os.path.isfile(fext):
774 try:
775 reject.index(fext)
776 except ValueError:
777 return os.path.normpath(fext)
778 continue
779 return None
780
781 else:
782
783 - def WhereIs(file, path=None, pathext=None, reject=[]):
784 import stat
785 if path is None:
786 try:
787 path = os.environ['PATH']
788 except KeyError:
789 return None
790 if is_String(path):
791 path = path.split(os.pathsep)
792 if not is_List(reject) and not is_Tuple(reject):
793 reject = [reject]
794 for d in path:
795 f = os.path.join(d, file)
796 if os.path.isfile(f):
797 try:
798 st = os.stat(f)
799 except OSError:
800
801
802
803
804 continue
805 if stat.S_IMODE(st[stat.ST_MODE]) & 0o111:
806 try:
807 reject.index(f)
808 except ValueError:
809 return os.path.normpath(f)
810 continue
811 return None
812
813 -def PrependPath(oldpath, newpath, sep = os.pathsep,
814 delete_existing=1, canonicalize=None):
815 """This prepends newpath elements to the given oldpath. Will only
816 add any particular path once (leaving the first one it encounters
817 and ignoring the rest, to preserve path order), and will
818 os.path.normpath and os.path.normcase all paths to help assure
819 this. This can also handle the case where the given old path
820 variable is a list instead of a string, in which case a list will
821 be returned instead of a string.
822
823 Example:
824 Old Path: "/foo/bar:/foo"
825 New Path: "/biz/boom:/foo"
826 Result: "/biz/boom:/foo:/foo/bar"
827
828 If delete_existing is 0, then adding a path that exists will
829 not move it to the beginning; it will stay where it is in the
830 list.
831
832 If canonicalize is not None, it is applied to each element of
833 newpath before use.
834 """
835
836 orig = oldpath
837 is_list = 1
838 paths = orig
839 if not is_List(orig) and not is_Tuple(orig):
840 paths = paths.split(sep)
841 is_list = 0
842
843 if is_String(newpath):
844 newpaths = newpath.split(sep)
845 elif not is_List(newpath) and not is_Tuple(newpath):
846 newpaths = [ newpath ]
847 else:
848 newpaths = newpath
849
850 if canonicalize:
851 newpaths=list(map(canonicalize, newpaths))
852
853 if not delete_existing:
854
855
856
857
858
859 result = []
860 normpaths = []
861 for path in paths:
862 if not path:
863 continue
864 normpath = os.path.normpath(os.path.normcase(path))
865 if normpath not in normpaths:
866 result.append(path)
867 normpaths.append(normpath)
868 newpaths.reverse()
869 for path in newpaths:
870 if not path:
871 continue
872 normpath = os.path.normpath(os.path.normcase(path))
873 if normpath not in normpaths:
874 result.insert(0, path)
875 normpaths.append(normpath)
876 paths = result
877
878 else:
879 newpaths = newpaths + paths
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
890 if is_list:
891 return paths
892 else:
893 return sep.join(paths)
894
895 -def AppendPath(oldpath, newpath, sep = os.pathsep,
896 delete_existing=1, canonicalize=None):
897 """This appends new path elements to the given old path. Will
898 only add any particular path once (leaving the last one it
899 encounters and ignoring the rest, to preserve path order), and
900 will os.path.normpath and os.path.normcase all paths to help
901 assure this. This can also handle the case where the given old
902 path variable is a list instead of a string, in which case a list
903 will be returned instead of a string.
904
905 Example:
906 Old Path: "/foo/bar:/foo"
907 New Path: "/biz/boom:/foo"
908 Result: "/foo/bar:/biz/boom:/foo"
909
910 If delete_existing is 0, then adding a path that exists
911 will not move it to the end; it will stay where it is in the list.
912
913 If canonicalize is not None, it is applied to each element of
914 newpath before use.
915 """
916
917 orig = oldpath
918 is_list = 1
919 paths = orig
920 if not is_List(orig) and not is_Tuple(orig):
921 paths = paths.split(sep)
922 is_list = 0
923
924 if is_String(newpath):
925 newpaths = newpath.split(sep)
926 elif not is_List(newpath) and not is_Tuple(newpath):
927 newpaths = [ newpath ]
928 else:
929 newpaths = newpath
930
931 if canonicalize:
932 newpaths=list(map(canonicalize, newpaths))
933
934 if not delete_existing:
935
936
937
938
939
940 result = []
941 normpaths = []
942 for path in paths:
943 if not path:
944 continue
945 result.append(path)
946 normpaths.append(os.path.normpath(os.path.normcase(path)))
947 for path in newpaths:
948 if not path:
949 continue
950 normpath = os.path.normpath(os.path.normcase(path))
951 if normpath not in normpaths:
952 result.append(path)
953 normpaths.append(normpath)
954 paths = result
955 else:
956
957
958 newpaths = paths + newpaths
959 newpaths.reverse()
960
961 normpaths = []
962 paths = []
963
964 for path in newpaths:
965 normpath = os.path.normpath(os.path.normcase(path))
966 if path and not normpath in normpaths:
967 paths.append(path)
968 normpaths.append(normpath)
969 paths.reverse()
970
971 if is_list:
972 return paths
973 else:
974 return sep.join(paths)
975
977 """This function will take 'key' out of the dictionary
978 'env_dict', then add the path 'path' to that key if it is not
979 already there. This treats the value of env_dict[key] as if it
980 has a similar format to the PATH variable...a list of paths
981 separated by tokens. The 'path' will get added to the list if it
982 is not already there."""
983 try:
984 is_list = 1
985 paths = env_dict[key]
986 if not is_List(env_dict[key]):
987 paths = paths.split(sep)
988 is_list = 0
989 if os.path.normcase(path) not in list(map(os.path.normcase, paths)):
990 paths = [ path ] + paths
991 if is_list:
992 env_dict[key] = paths
993 else:
994 env_dict[key] = sep.join(paths)
995 except KeyError:
996 env_dict[key] = path
997
998 if sys.platform == 'cygwin':
1000 """Transforms an absolute path into a native path for the system. In
1001 Cygwin, this converts from a Cygwin path to a Windows one."""
1002 return os.popen('cygpath -w ' + path).read().replace('\n', '')
1003 else:
1005 """Transforms an absolute path into a native path for the system.
1006 Non-Cygwin version, just leave the path alone."""
1007 return path
1008
1009 display = DisplayEngine()
1010
1012 if is_List(arg) or is_Tuple(arg):
1013 return arg
1014 elif is_String(arg):
1015 return arg.split()
1016 else:
1017 return [arg]
1018
1020 """A class for command-line construction variables.
1021
1022 This is a list that uses Split() to split an initial string along
1023 white-space arguments, and similarly to split any strings that get
1024 added. This allows us to Do the Right Thing with Append() and
1025 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
1026 arg2') regardless of whether a user adds a list or a string to a
1027 command-line construction variable.
1028 """
1036 return (self, CLVar(other))
1038 return ' '.join(self.data)
1039
1040
1041
1042
1043
1046 self._keys = []
1047 UserDict.__init__(self, dict)
1048
1052
1056
1058 UserDict.clear(self)
1059 self._keys = []
1060
1065
1067 return list(zip(self._keys, list(self.values())))
1068
1070 return self._keys[:]
1071
1073 try:
1074 key = self._keys[-1]
1075 except IndexError:
1076 raise KeyError('dictionary is empty')
1077
1078 val = self[key]
1079 del self[key]
1080
1081 return (key, val)
1082
1086
1090
1092 return list(map(self.get, self._keys))
1093
1095 """A callable ordered dictionary that maps file suffixes to
1096 dictionary values. We preserve the order in which items are added
1097 so that get_suffix() calls always return the first suffix added."""
1098 - def __call__(self, env, source, ext=None):
1099 if ext is None:
1100 try:
1101 ext = source[0].get_suffix()
1102 except IndexError:
1103 ext = ""
1104 try:
1105 return self[ext]
1106 except KeyError:
1107
1108
1109 s_dict = {}
1110 for (k,v) in self.items():
1111 if k is not None:
1112 s_k = env.subst(k)
1113 if s_k in s_dict:
1114
1115
1116
1117
1118 raise KeyError(s_dict[s_k][0], k, s_k)
1119 s_dict[s_k] = (k,v)
1120 try:
1121 return s_dict[ext][1]
1122 except KeyError:
1123 try:
1124 return self[None]
1125 except KeyError:
1126 return None
1127
1128
1129 if sys.platform == 'cygwin':
1130
1131
1134 else:
1136 return (os.path.normcase(s1) != os.path.normcase(s2))
1137
1138 -def adjustixes(fname, pre, suf, ensure_suffix=False):
1139 if pre:
1140 path, fn = os.path.split(os.path.normpath(fname))
1141 if fn[:len(pre)] != pre:
1142 fname = os.path.join(path, pre + fn)
1143
1144
1145
1146 if suf and fname[-len(suf):] != suf and \
1147 (ensure_suffix or not splitext(fname)[1]):
1148 fname = fname + suf
1149 return fname
1150
1151
1152
1153
1154
1155
1156
1157
1159 """Return a list of the elements in s, but without duplicates.
1160
1161 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1162 unique("abcabc") some permutation of ["a", "b", "c"], and
1163 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1164 [[2, 3], [1, 2]].
1165
1166 For best speed, all sequence elements should be hashable. Then
1167 unique() will usually work in linear time.
1168
1169 If not possible, the sequence elements should enjoy a total
1170 ordering, and if list(s).sort() doesn't raise TypeError it's
1171 assumed that they do enjoy a total ordering. Then unique() will
1172 usually work in O(N*log2(N)) time.
1173
1174 If that's not possible either, the sequence elements must support
1175 equality-testing. Then unique() will usually work in quadratic
1176 time.
1177 """
1178
1179 n = len(s)
1180 if n == 0:
1181 return []
1182
1183
1184
1185
1186
1187 u = {}
1188 try:
1189 for x in s:
1190 u[x] = 1
1191 except TypeError:
1192 pass
1193 else:
1194 return list(u.keys())
1195 del u
1196
1197
1198
1199
1200
1201
1202
1203
1204 try:
1205 t = sorted(s)
1206 except TypeError:
1207 pass
1208 else:
1209 assert n > 0
1210 last = t[0]
1211 lasti = i = 1
1212 while i < n:
1213 if t[i] != last:
1214 t[lasti] = last = t[i]
1215 lasti = lasti + 1
1216 i = i + 1
1217 return t[:lasti]
1218 del t
1219
1220
1221 u = []
1222 for x in s:
1223 if x not in u:
1224 u.append(x)
1225 return u
1226
1227
1228
1229
1230
1231
1232
1233
1234
1236 if idfun is None:
1237 def idfun(x): return x
1238 seen = {}
1239 result = []
1240 for item in seq:
1241 marker = idfun(item)
1242
1243
1244
1245 if marker in seen: continue
1246 seen[marker] = 1
1247 result.append(item)
1248 return result
1249
1250
1251
1252
1253
1255 seen = {}
1256 result = []
1257 for item in seq:
1258
1259 if item not in seen:
1260 seen[item] = 1
1261 result.append(item)
1262 return result
1263
1264
1265
1266
1268 logical_line = []
1269 for line in physical_lines:
1270 stripped = line.rstrip()
1271 if stripped.endswith('\\'):
1272
1273 logical_line.append(stripped[:-1])
1274 else:
1275
1276 logical_line.append(line)
1277 yield joiner(logical_line)
1278 logical_line = []
1279 if logical_line:
1280
1281 yield joiner(logical_line)
1282
1283
1285 """ Wrapper class for the logical_lines method.
1286
1287 Allows us to read all "logical" lines at once from a
1288 given file object.
1289 """
1290
1292 self.fileobj = fileobj
1293
1295 result = [l for l in logical_lines(self.fileobj)]
1296 return result
1297
1298
1301 UserList.__init__(self, seq)
1302 self.unique = True
1304 if not self.unique:
1305 self.data = uniquer_hashables(self.data)
1306 self.unique = True
1335 UserList.__setitem__(self, i, item)
1336 self.unique = False
1341 UserList.__setslice__(self, i, j, other)
1342 self.unique = False
1368 UserList.append(self, item)
1369 self.unique = False
1371 UserList.insert(self, i)
1372 self.unique = False
1382 - def sort(self, *args, **kwds):
1386 UserList.extend(self, other)
1387 self.unique = False
1388
1389
1391 """
1392 A proxy class that wraps a file object, flushing after every write,
1393 and delegating everything else to the wrapped object.
1394 """
1396 self.file = file
1397 self.softspace = 0
1399 try:
1400 self.file.write(arg)
1401 self.file.flush()
1402 except IOError:
1403
1404
1405
1406
1407
1408
1409
1410 pass
1412 return getattr(self.file, attr)
1413
1415 """ makes an absolute path name to a relative pathname.
1416 """
1417 if os.path.isabs(path):
1418 drive_s,path = os.path.splitdrive(path)
1419
1420 import re
1421 if not drive_s:
1422 path=re.compile("/*(.*)").findall(path)[0]
1423 else:
1424 path=path[1:]
1425
1426 assert( not os.path.isabs( path ) ), path
1427 return path
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1456 """
1457 Adds either a bound method to an instance or the function itself (or an unbound method in Python 2) to a class.
1458 If name is ommited the name of the specified function
1459 is used by default.
1460
1461 Example::
1462
1463 a = A()
1464 def f(self, x, y):
1465 self.z = x + y
1466 AddMethod(f, A, "add")
1467 a.add(2, 4)
1468 print(a.z)
1469 AddMethod(lambda self, i: self.l[i], a, "listIndex")
1470 print(a.listIndex(5))
1471 """
1472 if name is None:
1473 name = function.__name__
1474 else:
1475 function = RenameFunction(function, name)
1476
1477
1478
1479 if hasattr(obj, '__class__') and obj.__class__ is not type:
1480
1481 if sys.version_info[:2] > (3, 2):
1482 method = MethodType(function, obj)
1483 else:
1484 method = MethodType(function, obj, obj.__class__)
1485 else:
1486
1487 method = function
1488
1489 setattr(obj, name, method)
1490
1492 """
1493 Returns a function identical to the specified function, but with
1494 the specified name.
1495 """
1496 return FunctionType(function.__code__,
1497 function.__globals__,
1498 name,
1499 function.__defaults__)
1500
1501
1502 md5 = False
1503
1504
1507
1508
1513
1514 try:
1515 import hashlib
1516 except ImportError:
1517 pass
1518 else:
1519 if hasattr(hashlib, 'md5'):
1520 md5 = True
1521
1523 m = hashlib.md5()
1524
1525 try:
1526 m.update(to_bytes(s))
1527 except TypeError as e:
1528 m.update(to_bytes(str(s)))
1529
1530 return m.hexdigest()
1531
1533 m = hashlib.md5()
1534 f = open(fname, "rb")
1535 while True:
1536 blck = f.read(chunksize)
1537 if not blck:
1538 break
1539 m.update(to_bytes(blck))
1540 f.close()
1541 return m.hexdigest()
1542
1544 """
1545 Collects a list of signatures into an aggregate signature.
1546
1547 signatures - a list of signatures
1548 returns - the aggregate signature
1549 """
1550 if len(signatures) == 1:
1551 return signatures[0]
1552 else:
1553 return MD5signature(', '.join(signatures))
1554
1555
1556
1558 """
1559 Perform sys.intern() on the passed argument and return the result.
1560 If the input is ineligible (e.g. a unicode string) the original argument is
1561 returned and no exception is thrown.
1562 """
1563 try:
1564 return sys.intern(x)
1565 except TypeError:
1566 return x
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577 -class Null(object):
1578 """ Null objects always and reliably "do nothing." """
1579 - def __new__(cls, *args, **kwargs):
1588 return "Null(0x%08X)" % id(self)
1599
1611
1612
1613 del __revision__
1614
1616 if isinstance (s, (bytes, bytearray)) or bytes is str:
1617 return s
1618 return bytes (s, 'utf-8')
1619
1621 if bytes is str or is_String(s):
1622 return s
1623 return str (s, 'utf-8')
1624
1625
1626
1627
1628
1629
1630