diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2012-11-11 12:22:03 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2012-11-11 12:22:03 -0500 |
commit | de89438a0346e3dca4f7e8afe24efa38810deebe (patch) | |
tree | 82acb47b22bf967a9573651adb6cc18d9bc216a2 /coverage | |
parent | 99480be7da89cb82cfff01e5d10a2514546faf39 (diff) | |
download | python-coveragepy-git-de89438a0346e3dca4f7e8afe24efa38810deebe.tar.gz |
Windows now reports file names in their correct case. #89 and #203.
Diffstat (limited to 'coverage')
-rw-r--r-- | coverage/__init__.py | 7 | ||||
-rw-r--r-- | coverage/control.py | 1 | ||||
-rw-r--r-- | coverage/files.py | 49 | ||||
-rw-r--r-- | coverage/fullcoverage/encodings.py | 8 |
4 files changed, 61 insertions, 4 deletions
diff --git a/coverage/__init__.py b/coverage/__init__.py index a10b4a67..2653853b 100644 --- a/coverage/__init__.py +++ b/coverage/__init__.py @@ -78,6 +78,12 @@ analysis2 = _singleton_method('analysis2') report = _singleton_method('report') annotate = _singleton_method('annotate') + +# On Windows, we encode and decode deep enough that something goes wrong and +# the encodings.utf_8 module is loaded and then unloaded, I don't know why. +# Adding a reference here prevents it from being unloaded. Yuk. +import encodings.utf_8 + # Because of the "from coverage.control import fooey" lines at the top of the # file, there's an entry for coverage.coverage in sys.modules, mapped to None. # This makes some inspection tools (like pydoc) unable to find the class @@ -88,6 +94,7 @@ try: except KeyError: pass + # COPYRIGHT AND LICENSE # # Copyright 2001 Gareth Rees. All rights reserved. diff --git a/coverage/control.py b/coverage/control.py index 9523defa..0391352d 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -475,6 +475,7 @@ class coverage(object): # Find files that were never executed at all. for src in self.source: for py_file in find_python_files(src): + py_file = self.file_locator.canonical_filename(py_file) self.data.touch_file(py_file) self._harvested = True diff --git a/coverage/files.py b/coverage/files.py index 84466504..65b1dc01 100644 --- a/coverage/files.py +++ b/coverage/files.py @@ -9,7 +9,7 @@ class FileLocator(object): def __init__(self): # The absolute path to our current directory. - self.relative_dir = abs_file(os.curdir) + os.sep + 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. @@ -22,8 +22,9 @@ class FileLocator(object): `FileLocator` was constructed. """ - if filename.startswith(self.relative_dir): - filename = filename.replace(self.relative_dir, "", 1) + fnorm = os.path.normcase(filename) + if fnorm.startswith(self.relative_dir): + filename = filename[len(self.relative_dir):] return filename def canonical_filename(self, filename): @@ -74,9 +75,49 @@ class FileLocator(object): return None +if sys.platform == 'win32': + import ctypes + + def getLongPathName(path): + """Call Windows' GetLongPathNameW, unicode to unicode.""" + buf = ctypes.create_unicode_buffer(260) + rv = ctypes.windll.kernel32.GetLongPathNameW(path, buf, 260) + if rv == 0 or rv > 260: + return path + else: + return buf.value + + def getShortPathName(path): + """Call Windows' GetShortPathNameW, unicode to unicode.""" + buf = ctypes.create_unicode_buffer(260) + rv = ctypes.windll.kernel32.GetShortPathNameW(path, buf, 260) + if rv == 0 or rv > 260: + return path + else: + return buf.value + + def actual_path(path): + """Get the actual path of `path`, including the correct case.""" + if sys.version_info >= (3,0): + path = path.encode('utf-16') + else: + path = path.decode('utf8') + actual = getLongPathName(getShortPathName(path)) + if sys.version_info >= (3,0): + actual = actual.decode('utf-16') + else: + actual = actual.encode('utf8') + return actual +else: + def actual_filename(filename): + """The actual filename for non-Windows platforms.""" + return filename + def abs_file(filename): """Return the absolute normalized form of `filename`.""" - return os.path.normcase(os.path.abspath(os.path.realpath(filename))) + path = os.path.abspath(os.path.realpath(filename)) + path = actual_filename(path) + return path def prep_patterns(patterns): diff --git a/coverage/fullcoverage/encodings.py b/coverage/fullcoverage/encodings.py index ad350bc0..6a258d67 100644 --- a/coverage/fullcoverage/encodings.py +++ b/coverage/fullcoverage/encodings.py @@ -37,6 +37,14 @@ class FullCoverageTracer(object): sys.settrace(FullCoverageTracer().fullcoverage_trace) +# In coverage/files.py is actual_filename(), which uses glob.glob. I don't +# understand why, but that use of glob borks everything if fullcoverage is in +# effect. So here we make an ugly hail-mary pass to switch off glob.glob over +# there. This means when using fullcoverage, Windows path names will not be +# their actual case. + +#sys.fullcoverage = True + # Finally, remove our own directory from sys.path; remove ourselves from # sys.modules; and re-import "encodings", which will be the real package # this time. Note that the delete from sys.modules dictionary has to |