summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Laxalde <denis.laxalde@logilab.fr>2016-11-14 09:48:38 +0100
committerDenis Laxalde <denis.laxalde@logilab.fr>2016-11-14 09:48:38 +0100
commit02334198369c0f65a9da6d544d0f15f4ac7d4812 (patch)
treedefd9357680714891e4a7e2a6a235056089e4fef
parentc36a5d74e4ac35d79206b6215726757385af536c (diff)
downloadlogilab-common-02334198369c0f65a9da6d544d0f15f4ac7d4812.tar.gz
[modutils] Copy back modpath_from_file from astroid
Astroid has copy of modutils, originally from logilab-common, which has been modified and improved since. Copy back the `modpath_from_file` function in logilab-common, so that it is more robust to file path "subtelities" (case, symlinks, user, in particular).
-rw-r--r--logilab/common/modutils.py36
1 files changed, 27 insertions, 9 deletions
diff --git a/logilab/common/modutils.py b/logilab/common/modutils.py
index e70a1a9..6d13201 100644
--- a/logilab/common/modutils.py
+++ b/logilab/common/modutils.py
@@ -32,12 +32,14 @@ __docformat__ = "restructuredtext en"
import sys
import os
-from os.path import splitext, join, abspath, isdir, dirname, exists, basename
+from os.path import (splitext, join, abspath, isdir, dirname, exists,
+ basename, expanduser, normcase, realpath)
from imp import find_module, load_module, C_BUILTIN, PY_COMPILED, PKG_DIRECTORY
from distutils.sysconfig import get_config_var, get_python_lib, get_python_version
from distutils.errors import DistutilsPlatformError
-from six.moves import range
+from six import PY3
+from six.moves import map, range
try:
import zipimport
@@ -219,6 +221,19 @@ def _check_init(path, mod_path):
return True
+def _canonicalize_path(path):
+ return realpath(expanduser(path))
+
+
+def _path_from_filename(filename):
+ if PY3:
+ return filename
+ else:
+ if filename.endswith(".pyc"):
+ return filename[:-1]
+ return filename
+
+
def modpath_from_file(filename, extrapath=None):
"""given a file path return the corresponding splitted module's name
(i.e name of a module or package splitted on '.')
@@ -239,26 +254,29 @@ def modpath_from_file(filename, extrapath=None):
:rtype: list(str)
:return: the corresponding splitted module's name
"""
- base = splitext(abspath(filename))[0]
+ filename = _path_from_filename(filename)
+ filename = _canonicalize_path(filename)
+ base = os.path.splitext(filename)[0]
+
if extrapath is not None:
- for path_ in extrapath:
+ for path_ in map(_canonicalize_path, extrapath):
path = abspath(path_)
- if path and base[:len(path)] == path:
+ if path and normcase(base[:len(path)]) == normcase(path):
submodpath = [pkg for pkg in base[len(path):].split(os.sep)
if pkg]
if _check_init(path, submodpath[:-1]):
return extrapath[path_].split('.') + submodpath
- for path in sys.path:
- path = abspath(path)
- if path and base.startswith(path):
+
+ for path in map(_canonicalize_path, sys.path):
+ if path and normcase(base).startswith(path):
modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg]
if _check_init(path, modpath[:-1]):
return modpath
+
raise ImportError('Unable to find module for %s in %s' % (
filename, ', \n'.join(sys.path)))
-
def file_from_modpath(modpath, path=None, context_file=None):
"""given a mod path (i.e. splitted module / package name), return the
corresponding file, giving priority to source file over precompiled