Skip to content

Commit 48d2a85

Browse files
authored
Merge pull request #482 from dan-blanchard/fix-relative-to
Fix support for egg packages with files outside site-packages by using `pathlib.Path.relative_to(walk_up=True)`.
2 parents e8998d9 + b94b42e commit 48d2a85

File tree

5 files changed

+61
-4
lines changed

5 files changed

+61
-4
lines changed

importlib_metadata/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import collections
2020

2121
from . import _meta
22-
from .compat import py39
22+
from .compat import py39, py311
2323
from ._collections import FreezableDefaultDict, Pair
2424
from ._compat import (
2525
NullFinder,
@@ -570,9 +570,8 @@ def _read_files_egginfo_installed(self):
570570
return
571571

572572
paths = (
573-
(subdir / name)
574-
.resolve()
575-
.relative_to(self.locate_file('').resolve())
573+
py311.relative_fix((subdir / name).resolve())
574+
.relative_to(self.locate_file('').resolve(), walk_up=True)
576575
.as_posix()
577576
for name in text.splitlines()
578577
)

importlib_metadata/compat/py311.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import os
2+
import pathlib
3+
import sys
4+
import types
5+
6+
7+
def wrap(path): # pragma: no cover
8+
"""
9+
Workaround for https://github.com/python/cpython/issues/84538
10+
to add backward compatibility for walk_up=True.
11+
An example affected package is dask-labextension, which uses
12+
jupyter-packaging to install JupyterLab javascript files outside
13+
of site-packages.
14+
"""
15+
16+
def relative_to(root, *, walk_up=False):
17+
return pathlib.Path(os.path.relpath(path, root))
18+
19+
return types.SimpleNamespace(relative_to=relative_to)
20+
21+
22+
relative_fix = wrap if sys.version_info < (3, 12) else lambda x: x

newsfragments/455.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
When reading installed files from an egg, use ``relative_to(walk_up=True)`` to honor files installed outside of the installation root.

tests/fixtures.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,40 @@ def main():
233233
}
234234

235235

236+
class EggInfoPkgPipInstalledExternalDataFiles(OnSysPath, SiteBuilder):
237+
files: FilesSpec = {
238+
"egg_with_module_pkg.egg-info": {
239+
"PKG-INFO": "Name: egg_with_module-pkg",
240+
# SOURCES.txt is made from the source archive, and contains files
241+
# (setup.py) that are not present after installation.
242+
"SOURCES.txt": """
243+
egg_with_module.py
244+
setup.py
245+
egg_with_module.json
246+
egg_with_module_pkg.egg-info/PKG-INFO
247+
egg_with_module_pkg.egg-info/SOURCES.txt
248+
egg_with_module_pkg.egg-info/top_level.txt
249+
""",
250+
# installed-files.txt is written by pip, and is a strictly more
251+
# accurate source than SOURCES.txt as to the installed contents of
252+
# the package.
253+
"installed-files.txt": """
254+
../../../etc/jupyter/jupyter_notebook_config.d/relative.json
255+
/etc/jupyter/jupyter_notebook_config.d/absolute.json
256+
../egg_with_module.py
257+
PKG-INFO
258+
SOURCES.txt
259+
top_level.txt
260+
""",
261+
# missing top_level.txt (to trigger fallback to installed-files.txt)
262+
},
263+
"egg_with_module.py": """
264+
def main():
265+
print("hello world")
266+
""",
267+
}
268+
269+
236270
class EggInfoPkgPipInstalledNoModules(OnSysPath, SiteBuilder):
237271
files: FilesSpec = {
238272
"egg_with_no_modules_pkg.egg-info": {

tests/test_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class APITests(
2929
fixtures.EggInfoPkg,
3030
fixtures.EggInfoPkgPipInstalledNoToplevel,
3131
fixtures.EggInfoPkgPipInstalledNoModules,
32+
fixtures.EggInfoPkgPipInstalledExternalDataFiles,
3233
fixtures.EggInfoPkgSourcesFallback,
3334
fixtures.DistInfoPkg,
3435
fixtures.DistInfoPkgWithDot,

0 commit comments

Comments
 (0)