Skip to content

Commit a0d7ded

Browse files
authored
Merge pull request #119 from wimglenn/entry_points
Entry points
2 parents 2b20984 + be2e314 commit a0d7ded

File tree

8 files changed

+55
-12
lines changed

8 files changed

+55
-12
lines changed

johnnydep/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Display dependency tree of Python distribution"""
22

3-
__version__ = "1.18.0"
3+
__version__ = "1.19.0"
44

55
from johnnydep.lib import *

johnnydep/cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
("requires", "Immediate dependencies"),
2323
("required_by", "Parent(s) in the tree"),
2424
("import_names", "Python imports provided (top-level names only)"),
25+
("console_scripts", "Entry points in the console_scripts group"),
2526
("homepage", "Project URL"),
2627
("extras_available", "Optional extensions available for the distribution"),
2728
("extras_requested", "Optional extensions parsed from requirement specifier"),

johnnydep/compat.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ def urlretrieve(url, filename, data=None, auth=None):
6262

6363

6464
try:
65-
from importlib.metadata import distribution, PackageNotFoundError
65+
from importlib.metadata import distribution, PackageNotFoundError, PathDistribution
6666
except ImportError:
67-
from importlib_metadata import distribution, PackageNotFoundError
67+
from importlib_metadata import distribution, PackageNotFoundError, PathDistribution
68+
69+
70+
try:
71+
from zipfile import Path as zipfile_path
72+
except ImportError:
73+
from zipfile39 import Path as zipfile_path

johnnydep/lib.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
from johnnydep.compat import distribution
3030
from johnnydep.compat import oyaml
3131
from johnnydep.compat import PackageNotFoundError
32+
from johnnydep.compat import PathDistribution
33+
from johnnydep.compat import zipfile_path
3234
from johnnydep.dot import jd2dot
3335
from johnnydep.util import CircularMarker
3436

@@ -70,6 +72,7 @@ def __init__(self, req_string, parent=None, index_url=None, env=None, extra_inde
7072
self.req = requirements.Requirement(self.name + sep + extras + self.specifier)
7173
self.import_names = _discover_import_names(fname)
7274
self.metadata = _extract_metadata(fname)
75+
self.entry_points = _discover_entry_points(fname)
7376
self._from_fname = os.path.abspath(fname)
7477
else:
7578
self._from_fname = None
@@ -78,7 +81,7 @@ def __init__(self, req_string, parent=None, index_url=None, env=None, extra_inde
7881
self.specifier = str(self.req.specifier)
7982
log.debug("fetching best wheel")
8083
try:
81-
self.import_names, self.metadata = _get_info(
84+
self.import_names, self.metadata, self.entry_points = _get_info(
8285
dist_name=req_string,
8386
index_url=index_url,
8487
env=env,
@@ -89,6 +92,7 @@ def __init__(self, req_string, parent=None, index_url=None, env=None, extra_inde
8992
raise
9093
self.import_names = None
9194
self.metadata = {}
95+
self.entry_points = None
9296
self.error = err
9397

9498
self.extras_requested = sorted(self.req.extras)
@@ -249,6 +253,11 @@ def extras_available(self):
249253
def project_name(self):
250254
return self.metadata.get("name", self.name)
251255

256+
@property
257+
def console_scripts(self):
258+
eps = [ep for ep in self.entry_points or [] if ep.group == "console_scripts"]
259+
return ", ".join(["{} = {}".format(ep.name, ep.value) for ep in eps])
260+
252261
@property
253262
def pinned(self):
254263
if self.extras_requested:
@@ -420,9 +429,9 @@ def flatten_deps(johnnydist):
420429

421430
def _discover_import_names(whl_file):
422431
log = logger.bind(whl_file=whl_file)
423-
logger.debug("finding import names")
424-
zipfile = ZipFile(file=whl_file)
425-
namelist = zipfile.namelist()
432+
log.debug("finding import names")
433+
zf = ZipFile(file=whl_file)
434+
namelist = zf.namelist()
426435
try:
427436
[top_level_fname] = [x for x in namelist if x.endswith("top_level.txt")]
428437
except ValueError:
@@ -447,13 +456,25 @@ def _discover_import_names(whl_file):
447456
# found a top level module
448457
public_names.append(name)
449458
else:
450-
all_names = zipfile.read(top_level_fname).decode("utf-8").strip().splitlines()
459+
all_names = zf.read(top_level_fname).decode("utf-8").strip().splitlines()
451460
public_names = [n for n in all_names if not n.startswith("_")]
452-
return public_names
461+
result = [n.replace("/", ".") for n in public_names]
462+
return result
463+
464+
465+
def _discover_entry_points(whl_file):
466+
log = logger.bind(whl_file=whl_file)
467+
log.debug("finding entry points")
468+
parts = os.path.basename(whl_file).split("-")
469+
metadata_path = "-".join(parts[:2]) + ".dist-info/"
470+
zf_path = zipfile_path(whl_file, metadata_path)
471+
path_dist = PathDistribution(zf_path)
472+
return path_dist.entry_points
453473

454474

455475
def _extract_metadata(whl_file):
456-
logger.debug("searching metadata", whl_file=whl_file)
476+
log = logger.bind(whl_file=whl_file)
477+
log.debug("searching metadata", whl_file=whl_file)
457478
info = pkginfo.get_metadata(whl_file)
458479
if info is None:
459480
raise JohnnyError("failed to get metadata")
@@ -486,10 +507,11 @@ def _get_info(dist_name, index_url=None, env=None, extra_index_url=None):
486507
# downloaded file can be cleaned up immediately
487508
import_names = _discover_import_names(dist_path)
488509
metadata = _extract_metadata(dist_path)
510+
entry_points = _discover_entry_points(dist_path)
489511
finally:
490512
log.debug("removing scratch", tmpdir=tmpdir)
491513
rmtree(tmpdir, ignore_errors=True)
492-
return import_names, metadata
514+
return import_names, metadata, entry_points
493515

494516

495517
# TODO: multi-line progress bar?

requirements-dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ pytest-raisin
66
pytest-socket
77
coverage
88
wheel
9-
whl >= 0.0.3
9+
whl >= 0.0.4
1010
wimpy == 0.3 # just something we can pin

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"wheel >= 0.32.0",
3232
"pkginfo >= 1.4.2",
3333
"importlib_metadata ; python_version < '3.7'",
34+
"zipfile39 ; python_version < '3.9'",
3435
],
3536
entry_points={
3637
"console_scripts": [

tests/test_cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ def test_all_fields_toml_out(mocker, capsys, make_dist):
148148
requires = []
149149
required_by = []
150150
import_names = [ "that",]
151+
console_scripts = ""
151152
homepage = "https://www.example.org/default"
152153
extras_available = []
153154
extras_requested = []

tests/test_lib.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,3 +537,15 @@ def test_local_whl_json(make_dist):
537537
assert link.startswith("file://")
538538
assert link.endswith("loc-0.1.2-py2.py3-none-any.whl")
539539
assert result["versions_available"] == ["0.1.1", "0.1.2", "0.1.3"]
540+
541+
542+
def test_entry_points(make_dist):
543+
# https://packaging.python.org/en/latest/specifications/entry-points/
544+
entry_points = {"console_scripts": ["my-script = mypkg.mymod:foo"]}
545+
make_dist(name="example", entry_points=entry_points)
546+
dist = JohnnyDist("example")
547+
[ep] = dist.entry_points
548+
assert ep.name == "my-script"
549+
assert ep.group == "console_scripts"
550+
assert ep.value == "mypkg.mymod:foo"
551+
assert dist.console_scripts == "my-script = mypkg.mymod:foo"

0 commit comments

Comments
 (0)