57 |
57 |
58 An absolute path with no redundant components and normalized case. |
58 An absolute path with no redundant components and normalized case. |
59 |
59 |
60 """ |
60 """ |
61 if filename not in CANONICAL_FILENAME_CACHE: |
61 if filename not in CANONICAL_FILENAME_CACHE: |
|
62 cf = filename |
62 if not os.path.isabs(filename): |
63 if not os.path.isabs(filename): |
63 for path in [os.curdir] + sys.path: |
64 for path in [os.curdir] + sys.path: |
64 if path is None: |
65 if path is None: |
65 continue |
66 continue |
66 f = os.path.join(path, filename) |
67 f = os.path.join(path, filename) |
67 try: |
68 try: |
68 exists = os.path.exists(f) |
69 exists = os.path.exists(f) |
69 except UnicodeError: |
70 except UnicodeError: |
70 exists = False |
71 exists = False |
71 if exists: |
72 if exists: |
72 filename = f |
73 cf = f |
73 break |
74 break |
74 cf = abs_file(filename) |
75 cf = abs_file(cf) |
75 CANONICAL_FILENAME_CACHE[filename] = cf |
76 CANONICAL_FILENAME_CACHE[filename] = cf |
76 return CANONICAL_FILENAME_CACHE[filename] |
77 return CANONICAL_FILENAME_CACHE[filename] |
77 |
78 |
78 |
79 |
79 MAX_FLAT = 200 |
80 MAX_FLAT = 200 |
120 if head in _ACTUAL_PATH_LIST_CACHE: |
121 if head in _ACTUAL_PATH_LIST_CACHE: |
121 files = _ACTUAL_PATH_LIST_CACHE[head] |
122 files = _ACTUAL_PATH_LIST_CACHE[head] |
122 else: |
123 else: |
123 try: |
124 try: |
124 files = os.listdir(head) |
125 files = os.listdir(head) |
125 except OSError: |
126 except Exception: |
|
127 # This will raise OSError, or this bizarre TypeError: |
|
128 # https://bugs.python.org/issue1776160 |
126 files = [] |
129 files = [] |
127 _ACTUAL_PATH_LIST_CACHE[head] = files |
130 _ACTUAL_PATH_LIST_CACHE[head] = files |
128 normtail = os.path.normcase(tail) |
131 normtail = os.path.normcase(tail) |
129 for f in files: |
132 for f in files: |
130 if os.path.normcase(f) == normtail: |
133 if os.path.normcase(f) == normtail: |
154 """Return a Unicode version of `filename`.""" |
157 """Return a Unicode version of `filename`.""" |
155 return filename |
158 return filename |
156 |
159 |
157 |
160 |
158 @contract(returns='unicode') |
161 @contract(returns='unicode') |
159 def abs_file(filename): |
162 def abs_file(path): |
160 """Return the absolute normalized form of `filename`.""" |
163 """Return the absolute normalized form of `path`.""" |
161 path = os.path.expandvars(os.path.expanduser(filename)) |
|
162 try: |
164 try: |
163 path = os.path.realpath(path) |
165 path = os.path.realpath(path) |
164 except UnicodeError: |
166 except UnicodeError: |
165 pass |
167 pass |
166 path = os.path.abspath(path) |
168 path = os.path.abspath(path) |
167 path = actual_path(path) |
169 path = actual_path(path) |
168 path = unicode_filename(path) |
170 path = unicode_filename(path) |
169 return path |
171 return path |
|
172 |
|
173 |
|
174 def python_reported_file(filename): |
|
175 """Return the string as Python would describe this file name.""" |
|
176 if env.PYBEHAVIOR.report_absolute_files: |
|
177 filename = os.path.abspath(filename) |
|
178 return filename |
170 |
179 |
171 |
180 |
172 RELATIVE_DIR = None |
181 RELATIVE_DIR = None |
173 CANONICAL_FILENAME_CACHE = None |
182 CANONICAL_FILENAME_CACHE = None |
174 set_relative_directory() |
183 set_relative_directory() |
333 self.aliases = [] |
342 self.aliases = [] |
334 |
343 |
335 def pprint(self): # pragma: debugging |
344 def pprint(self): # pragma: debugging |
336 """Dump the important parts of the PathAliases, for debugging.""" |
345 """Dump the important parts of the PathAliases, for debugging.""" |
337 for regex, result in self.aliases: |
346 for regex, result in self.aliases: |
338 print("{0!r} --> {1!r}".format(regex.pattern, result)) |
347 print("{!r} --> {!r}".format(regex.pattern, result)) |
339 |
348 |
340 def add(self, pattern, result): |
349 def add(self, pattern, result): |
341 """Add the `pattern`/`result` pair to the list of aliases. |
350 """Add the `pattern`/`result` pair to the list of aliases. |
342 |
351 |
343 `pattern` is an `fnmatch`-style pattern. `result` is a simple |
352 `pattern` is an `fnmatch`-style pattern. `result` is a simple |