From 7ffdafd91aab97a92099ca5455bc199f2a047d0a Mon Sep 17 00:00:00 2001 From: Ionel Cristian M?rie? Date: Sat, 6 Jun 2015 19:17:41 +0000 Subject: Correct path normalization on Windows: the drive was not normalized (different inputs like "c:\asdf" and "C:\asdf" did not return the same path). --- coverage/files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coverage/files.py') diff --git a/coverage/files.py b/coverage/files.py index f7fc969..1feb9b6 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -64,7 +64,7 @@ if env.WINDOWS: head, tail = os.path.split(path) if not tail: - actpath = head + actpath = head.upper() elif not head: actpath = tail else: -- cgit v1.2.1 From bbb7a1a7d2c1f0d251c2b1221263e0d4f1ca7527 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 7 Jun 2015 12:01:11 -0400 Subject: Tweak up the last merge --- coverage/files.py | 1 + 1 file changed, 1 insertion(+) (limited to 'coverage/files.py') diff --git a/coverage/files.py b/coverage/files.py index 1feb9b6..a800b7a 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -64,6 +64,7 @@ if env.WINDOWS: head, tail = os.path.split(path) if not tail: + # This means head is the drive spec: normalize it. actpath = head.upper() elif not head: actpath = tail -- cgit v1.2.1 From f230be76462efd15f48f216631f4d90db8d5685d Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 13 Jun 2015 14:19:45 -0400 Subject: Change FileLocator from a class to module-level functions --- coverage/files.py | 92 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 42 deletions(-) (limited to 'coverage/files.py') diff --git a/coverage/files.py b/coverage/files.py index a800b7a..665e2f3 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -12,55 +12,66 @@ from coverage import env from coverage.misc import CoverageException, join_regex -class FileLocator(object): - """Understand how filenames work.""" +RELATIVE_DIR = None +CANONICAL_FILENAME_CACHE = {} - def __init__(self): - # The absolute path to our current directory. - self.relative_dir = os.path.normcase(abs_file(os.curdir) + os.sep) - # Cache of results of calling the canonical_filename() method, to - # avoid duplicating work. - self.canonical_filename_cache = {} +def set_relative_directory(): + """Set the directory that `relative_filename` will be relative to.""" + global RELATIVE_DIR, CANONICAL_FILENAME_CACHE - def relative_filename(self, filename): - """Return the relative form of `filename`. + # The absolute path to our current directory. + RELATIVE_DIR = os.path.normcase(abs_file(os.curdir) + os.sep) - The filename will be relative to the current directory when the - `FileLocator` was constructed. + # Cache of results of calling the canonical_filename() method, to + # avoid duplicating work. + CANONICAL_FILENAME_CACHE = {} - """ - fnorm = os.path.normcase(filename) - if fnorm.startswith(self.relative_dir): - filename = filename[len(self.relative_dir):] - return filename +def relative_directory(): + """Return the directory that `relative_filename` is relative to.""" + return RELATIVE_DIR - def canonical_filename(self, filename): - """Return a canonical filename for `filename`. +def relative_filename(filename): + """Return the relative form of `filename`. - An absolute path with no redundant components and normalized case. + The filename will be relative to the current directory when the + `set_relative_directory` was called. - """ - if filename not in self.canonical_filename_cache: - if not os.path.isabs(filename): - for path in [os.curdir] + sys.path: - if path is None: - continue - f = os.path.join(path, filename) - if os.path.exists(f): - filename = f - break - cf = abs_file(filename) - self.canonical_filename_cache[filename] = cf - return self.canonical_filename_cache[filename] + """ + fnorm = os.path.normcase(filename) + if fnorm.startswith(RELATIVE_DIR): + filename = filename[len(RELATIVE_DIR):] + return filename + +def canonical_filename(filename): + """Return a canonical filename for `filename`. + + An absolute path with no redundant components and normalized case. + + """ + if filename not in CANONICAL_FILENAME_CACHE: + if not os.path.isabs(filename): + for path in [os.curdir] + sys.path: + if path is None: + continue + f = os.path.join(path, filename) + if os.path.exists(f): + filename = f + break + cf = abs_file(filename) + CANONICAL_FILENAME_CACHE[filename] = cf + return CANONICAL_FILENAME_CACHE[filename] if env.WINDOWS: + _ACTUAL_PATH_CACHE = {} + _ACTUAL_PATH_LIST_CACHE = {} + def actual_path(path): """Get the actual path of `path`, including the correct case.""" - if path in actual_path.cache: - return actual_path.cache[path] + if path in _ACTUAL_PATH_CACHE: + return _ACTUAL_PATH_CACHE[path] head, tail = os.path.split(path) if not tail: @@ -70,26 +81,23 @@ if env.WINDOWS: actpath = tail else: head = actual_path(head) - if head in actual_path.list_cache: - files = actual_path.list_cache[head] + if head in _ACTUAL_PATH_LIST_CACHE: + files = _ACTUAL_PATH_LIST_CACHE[head] else: try: files = os.listdir(head) except OSError: files = [] - actual_path.list_cache[head] = files + _ACTUAL_PATH_LIST_CACHE[head] = files normtail = os.path.normcase(tail) for f in files: if os.path.normcase(f) == normtail: tail = f break actpath = os.path.join(head, tail) - actual_path.cache[path] = actpath + _ACTUAL_PATH_CACHE[path] = actpath return actpath - actual_path.cache = {} - actual_path.list_cache = {} - else: def actual_path(filename): """The actual path for non-Windows platforms.""" -- cgit v1.2.1 From 6e5e9ae9d54e5fc1f4ac96c51344cb37c8ea3395 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 13 Jun 2015 21:44:43 -0400 Subject: Remove FileLocator from PathAliases. Now it always produces canonicalized paths. --- coverage/files.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'coverage/files.py') diff --git a/coverage/files.py b/coverage/files.py index 665e2f3..c9afefd 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -237,12 +237,9 @@ class PathAliases(object): A `PathAliases` object tracks a list of pattern/result pairs, and can map a path through those aliases to produce a unified path. - `locator` is a FileLocator that is used to canonicalize the results. - """ - def __init__(self, locator=None): + def __init__(self): self.aliases = [] - self.locator = locator def add(self, pattern, result): """Add the `pattern`/`result` pair to the list of aliases. @@ -295,6 +292,9 @@ class PathAliases(object): The separator style in the result is made to match that of the result in the alias. + Returns: + The mapped path. This is always a canonical filename. + """ for regex, result, pattern_sep, result_sep in self.aliases: m = regex.match(path) @@ -302,8 +302,7 @@ class PathAliases(object): new = path.replace(m.group(0), result) if pattern_sep != result_sep: new = new.replace(pattern_sep, result_sep) - if self.locator: - new = self.locator.canonical_filename(new) + new = canonical_filename(new) return new return path -- cgit v1.2.1 From b55dadbceff60aeb2ee75bc2df55c7374f28d8f3 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 16 Jun 2015 16:17:24 -0400 Subject: Be more specific with PathAliases tests. --- coverage/files.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'coverage/files.py') diff --git a/coverage/files.py b/coverage/files.py index c9afefd..154954d 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -293,7 +293,9 @@ class PathAliases(object): in the alias. Returns: - The mapped path. This is always a canonical filename. + The mapped path. If a mapping has happened, this is a + canonical path. If no mapping has happened, it is the + original value of `path` unchanged. """ for regex, result, pattern_sep, result_sep in self.aliases: -- cgit v1.2.1 From dc0d0c613de54cd5af74a1d3ac9d86235dc0aee9 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 24 Jul 2015 10:43:46 -0400 Subject: Add license mention to the top of all files. #313. --- coverage/files.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'coverage/files.py') diff --git a/coverage/files.py b/coverage/files.py index 154954d..762445f 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -1,3 +1,6 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt + """File wrangling.""" import fnmatch -- cgit v1.2.1 From fd2284632777a235ac663b7b9912246b30bc538b Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 26 Jul 2015 06:56:58 -0400 Subject: Get rid of napoleon style docstrings, they don't format nicely. --- coverage/files.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'coverage/files.py') diff --git a/coverage/files.py b/coverage/files.py index 762445f..bc9b0c9 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -295,10 +295,9 @@ class PathAliases(object): The separator style in the result is made to match that of the result in the alias. - Returns: - The mapped path. If a mapping has happened, this is a - canonical path. If no mapping has happened, it is the - original value of `path` unchanged. + Returns the mapped path. If a mapping has happened, this is a + canonical path. If no mapping has happened, it is the original value + of `path` unchanged. """ for regex, result, pattern_sep, result_sep in self.aliases: -- cgit v1.2.1 From a2c2e4365a9f1dde956319d5bc75bff6eef7ddfd Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 26 Jul 2015 22:51:26 -0400 Subject: Windows fixes due to data changes --- coverage/files.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'coverage/files.py') diff --git a/coverage/files.py b/coverage/files.py index bc9b0c9..e3ebd6c 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -12,6 +12,7 @@ import re import sys from coverage import env +from coverage.backward import unicode_class from coverage.misc import CoverageException, join_regex @@ -73,6 +74,8 @@ if env.WINDOWS: def actual_path(path): """Get the actual path of `path`, including the correct case.""" + if env.PY2 and isinstance(path, unicode_class): + path = path.encode(sys.getfilesystemencoding()) if path in _ACTUAL_PATH_CACHE: return _ACTUAL_PATH_CACHE[path] @@ -84,7 +87,7 @@ if env.WINDOWS: actpath = tail else: head = actual_path(head) - if head in _ACTUAL_PATH_LIST_CACHE: + if head in _ACTUAL_PATH_LIST_CACHE: files = _ACTUAL_PATH_LIST_CACHE[head] else: try: -- cgit v1.2.1