[Distutils] [issue140] [PATCH] Make 'develop --egg-path' respect specified path in easy_install.pth
R. Andrew Ohana
setuptools at bugs.python.org
Wed Jul 4 06:11:41 CEST 2012
New submission from R. Andrew Ohana <andrew.ohana at gmail.com>:
Currently easy_install.pth will either contain paths relative to the site-packages directory, or the normalized_path. This is because the framework has been setup to use normalized paths everywhere. The patch should properly extend the current framework to make the argument to the egg-path option actually respected.
----------
files: respect-egg-path.patch
messages: 663
nosy: ohanar
priority: feature
status: unread
title: [PATCH] Make 'develop --egg-path' respect specified path in easy_install.pth
Added file: http://bugs.python.org/setuptools/file82/respect-egg-path.patch
_______________________________________________
Setuptools tracker <setuptools at bugs.python.org>
<http://bugs.python.org/setuptools/issue140>
_______________________________________________
-------------- next part --------------
diff --git a/pkg_resources.py b/pkg_resources.py
index 79db00b..5eacb69 100644
--- a/pkg_resources.py
+++ b/pkg_resources.py
@@ -1650,13 +1650,13 @@ def register_finder(importer_type, distribution_finder):
_distribution_finders[importer_type] = distribution_finder
-def find_distributions(path_item, only=False):
+def find_distributions(path_item, only=False, basedir=None):
"""Yield distributions accessible via `path_item`"""
importer = get_importer(path_item)
finder = _find_adapter(_distribution_finders, importer)
- return finder(importer, path_item, only)
+ return finder(importer, path_item, only, basedir)
-def find_in_zip(importer, path_item, only=False):
+def find_in_zip(importer, path_item, only=False, basedir=None):
metadata = EggMetadata(importer)
if metadata.has_metadata('PKG-INFO'):
yield Distribution.from_filename(path_item, metadata=metadata)
@@ -1679,13 +1679,15 @@ def StringIO(*args, **kw):
from StringIO import StringIO
return StringIO(*args,**kw)
-def find_nothing(importer, path_item, only=False):
+def find_nothing(importer, path_item, only=False, basedir=None):
return ()
register_finder(object,find_nothing)
-def find_on_path(importer, path_item, only=False):
+def find_on_path(importer, path_item, only=False, basedir=None):
"""Yield distributions accessible on a sys.path directory"""
- path_item = _normalize_cached(path_item)
+ normal_path_item = _normalize_cached(path_item, basedir=basedir)
+ if basedir is None or path_item.startswith(basedir):
+ path_item = normal_path_item
if os.path.isdir(path_item) and os.access(path_item, os.R_OK):
if path_item.lower().endswith('.egg'):
@@ -1824,15 +1826,24 @@ def null_ns_handler(importer, path_item, packageName, module):
register_namespace_handler(object,null_ns_handler)
-def normalize_path(filename):
+def normalize_path(filename,basedir=None):
"""Normalize a file/dir name for comparison purposes"""
+ if basedir is not None and not os.path.isabs(filename):
+ filename = os.path.join(basedir, filename)
return os.path.normcase(os.path.realpath(filename))
-def _normalize_cached(filename,_cache={}):
+def _normalize_cached(filename,_cache={},basedir=None):
try:
- return _cache[filename]
+ if basedir is None:
+ return _cache[filename]
+ else:
+ return _cache[(filename,basedir)]
except KeyError:
- _cache[filename] = result = normalize_path(filename)
+ result = normalize_path(filename,basedir)
+ if basedir is None:
+ _cache[filename] = result
+ else:
+ _cache[(filename,basedir)] = result
return result
def _set_parent_ns(packageName):
diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py
index f128b80..fb1c05e 100755
--- a/setuptools/command/develop.py
+++ b/setuptools/command/develop.py
@@ -53,10 +53,15 @@ class develop(easy_install):
self.egg_link = os.path.join(self.install_dir, ei.egg_name+'.egg-link')
self.egg_base = ei.egg_base
+
+ target = normalize_path(self.egg_base)
+
if self.egg_path is None:
self.egg_path = os.path.abspath(ei.egg_base)
+ dist_location = target
+ else:
+ dist_location = self.egg_path
- target = normalize_path(self.egg_base)
if normalize_path(os.path.join(self.install_dir, self.egg_path)) != target:
raise DistutilsOptionError(
"--egg-path must be a relative path from the install"
@@ -65,7 +70,7 @@ class develop(easy_install):
# Make a distribution for the package's source
self.dist = Distribution(
- target,
+ dist_location,
PathMetadata(target, os.path.abspath(ei.egg_info)),
project_name = ei.egg_name
)
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index af4e349..f1c9ff9 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -465,7 +465,7 @@ Please make the appropriate changes for your system and try again.
# at this point, we know it's a local .egg, we just don't know if
# it's already installed.
for dist in self.local_index[spec.project_name]:
- if dist.location==download:
+ if not self.pth_file.cmp_paths(dist.location, download):
break
else:
install_needed = True # it's not in the local index
@@ -946,18 +946,26 @@ See the setuptools documentation for the "develop" command for more info.
return
for d in self.pth_file[dist.key]: # drop old entries
- if self.multi_version or d.location != dist.location:
+ if (self.multi_version or
+ self.pth_file.cmp_paths(d.location, dist.location)):
log.info("Removing %s from easy-install.pth file", d)
self.pth_file.remove(d)
if d.location in self.shadow_path:
self.shadow_path.remove(d.location)
if not self.multi_version:
- if dist.location in self.pth_file.paths:
- log.info(
- "%s is already the active version in easy-install.pth",
- dist
- )
+ if dist in self.pth_file:
+ updated = self.pth_file.update(dist)
+ if updated:
+ log.info(
+ "Updated %s to the active version in easy-install.pth",
+ dist
+ )
+ else:
+ log.info(
+ "%s is already the active version in easy-install.pth",
+ dist
+ )
else:
log.info("Adding %s to easy-install.pth file", dist)
self.pth_file.add(dist) # add new entry
@@ -1320,12 +1328,19 @@ class PthDistributions(Environment):
self.basedir = normalize_path(os.path.dirname(self.filename))
self._load(); Environment.__init__(self, [], None, None)
for path in yield_lines(self.paths):
- map(self.add, find_distributions(path, True))
+ map(self.add, find_distributions(path, True, self.basedir))
+
+ def cmp_paths(self,left,right):
+ """Return 0 iff left and right refer to the same location
+ relative to self.basedir
+ """
+ return int(normalize_path(left, self.basedir) != \
+ normalize_path(right, self.basedir))
def _load(self):
self.paths = []
+ self.normalized_paths = dict.fromkeys(self.sitedirs)
saw_import = False
- seen = dict.fromkeys(self.sitedirs)
if os.path.isfile(self.filename):
for line in open(self.filename,'rt'):
if line.startswith('import'):
@@ -1337,14 +1352,14 @@ class PthDistributions(Environment):
continue
# skip non-existent paths, in case somebody deleted a package
# manually, and duplicate paths as well
- path = self.paths[-1] = normalize_path(
- os.path.join(self.basedir,path)
- )
- if not os.path.exists(path) or path in seen:
+ real_path = normalize_path(path, self.basedir)
+ if not os.path.exists(real_path) or real_path in self.normalized_paths:
self.paths.pop() # skip it
self.dirty = True # we cleaned up, so we're dirty now :)
continue
- seen[path] = 1
+ if real_path.startswith(self.basedir):
+ path = self.paths[-1] = real_path
+ self.normalized_paths[real_path] = path
if self.paths and not saw_import:
self.dirty = True # ensure anything we touch has import wrappers
@@ -1379,21 +1394,40 @@ class PthDistributions(Environment):
self.dirty = False
+ def __contains__(self,dist):
+ """Return True iff `dist` is already in the distribution map"""
+ return normalize_path(dist.location, self.basedir) in self.normalized_paths
+
def add(self,dist):
"""Add `dist` to the distribution map"""
- if dist.location not in self.paths and dist.location not in self.sitedirs:
+ path = normalize_path(dist.location, self.basedir)
+ if path not in self.normalized_paths and path not in self.sitedirs:
+ self.normalized_paths[path] = dist.location
self.paths.append(dist.location); self.dirty = True
Environment.add(self,dist)
def remove(self,dist):
"""Remove `dist` from the distribution map"""
- while dist.location in self.paths:
- self.paths.remove(dist.location); self.dirty = True
+ path = normalize_path(dist.location, self.basedir)
+ if path in self.normalized_paths:
+ self.paths.remove(self.normalized_paths[path])
+ del self.normalized_paths[path]; self.dirty = True
Environment.remove(self,dist)
+ def update(self,dist):
+ """Update `dist` in the distribution map"""
+ path = normalize_path(dist.location, self.basedir)
+ if path in self.normalized_paths and dist.location not in self.paths:
+ self.paths.remove(self.normalized_paths[path])
+ self.paths.append(dist.location)
+ self.normalized_paths[path] = dist.location; self.dirty = True
+ return True
+ return False
def make_relative(self,path):
- npath, last = os.path.split(normalize_path(path))
+ if not path.startswith(self.basedir):
+ return path
+ npath, last = os.path.split(normalize_path(path, self.basedir))
baselen = len(self.basedir)
parts = [last]
sep = os.altsep=='/' and '/' or os.sep
More information about the Distutils-SIG
mailing list