Skip to content

Commit

Permalink
Also include package dist-info for editable installs
Browse files Browse the repository at this point in the history
For editable installs the .egg-info/.dist-info does not
contain a list of installed files. Calculate the list of
files to include from the toplevels in the distribution.

Fixes #417
  • Loading branch information
ronaldoussoren committed Apr 4, 2022
1 parent 172439b commit c5270cd
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
2 changes: 2 additions & 0 deletions doc/changelog.rst
Expand Up @@ -4,6 +4,8 @@ Release history
py2app 0.28
-----------

* #417: Also include package dist-info for editable installs

* The qt5 and qt6 recipes used dodge logic to detect
if the Qt library itself is inside the python package,
resulting in duplicate copies of Qt.
Expand Down
62 changes: 59 additions & 3 deletions py2app/_pkg_meta.py
Expand Up @@ -3,7 +3,7 @@
IGNORED_DISTINFO = set(["installed-files.txt", "RECORD"]) # noqa: C405


def update_metadata_cache(infos, dist_info_path):
def update_metadata_cache_distinfo(infos, dist_info_path):
"""
Update mapping from filename to dist_info directory
for all files installed by the package described
Expand Down Expand Up @@ -40,6 +40,56 @@ def update_metadata_cache(infos, dist_info_path):
)
] = dist_info_path

def update_metadata_cache_distlink(infos, dist_link_path):
"""
Update mapping from filename to dist_info directory
for all files in the package installed in editable mode.
*dist_link_path* is the .egg-link file for the package
"""
# An editable install does not contain a listing of installed
# files.
with open(dist_link_path, "r") as fp:
dn = fp.readline()[:-1]


# The list of files and directories that would have been
# in the list of installed items.
to_include = []

# First look for the dist-info for this editable install
for fn in os.listdir(dn):
if fn.endswith(".egg-info") or fn.endswith(".dist-info"):
dist_info_path = os.path.join(dn, fn)
to_include.append(dist_info_path)
try:
with open(os.path.join(dist_info_path, "top_level.txt"), "r") as fp:
toplevels = fp.read().splitlines()
except OSError:
continue
break
else:
# No dist-info for this install
return

# Then look for the toplevels for this package
for fn in os.listdir(dn):
if fn in toplevels or fn.rstrip(".py") in toplevels:
to_include.append(os.path.join(dn, fn))

# Finally recursively add all items found to
# the cache.
add_recursive(infos, dist_info_path, to_include)

def add_recursive(infos, dist_info_path, to_include):
""" Add items from to_include to infos, recursively
walking into directories """
for item in to_include:
if os.path.isdir(item):
add_recursive(infos, dist_info_path, [os.path.join(item, fn) for fn in os.listdir(item)])

else:
infos[item] = dist_info_path

def scan_for_metadata(path):
"""
Expand All @@ -52,7 +102,13 @@ def scan_for_metadata(path):
if not os.path.isdir(dirname):
continue
for nm in os.listdir(dirname):
if nm.endswith(".egg-info") or nm.endswith(".dist-info"):
update_metadata_cache(infos, os.path.join(dirname, nm))
if nm.endswith(".egg-link"):
# Editable install, these will be found later on in
# *path* as well, but contain metadata without a list
# of installed files.
update_metadata_cache_distlink(infos, os.path.join(dirname, nm))

elif nm.endswith(".egg-info") or nm.endswith(".dist-info"):
update_metadata_cache_distinfo(infos, os.path.join(dirname, nm))

return infos

0 comments on commit c5270cd

Please sign in to comment.