Skip to content
This repository has been archived by the owner on Jan 12, 2021. It is now read-only.

Commit

Permalink
Merge pull request #395 from dephell/improve-entrypoints-lookup
Browse files Browse the repository at this point in the history
Improve entrypoints lookup
  • Loading branch information
orsinium committed Mar 12, 2020
2 parents 449c933 + 8aa9fde commit 3f0ad08
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 26 deletions.
71 changes: 45 additions & 26 deletions dephell/actions/_entrypoints.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# built-in
from logging import getLogger
from typing import Optional, Tuple
from typing import Iterable, Optional, Tuple

# external
from dephell_venvs import VEnv
from packaging.utils import canonicalize_name

# app
from ..constants import IS_WINDOWS
Expand All @@ -14,34 +15,52 @@
logger = getLogger('dephell.actions')


def _get_matching_path(paths: Iterable, name: str) -> Optional[str]:
name = canonicalize_name(name)
for path in paths:
package_name = path.stem.split('-')[0]
if canonicalize_name(package_name) == name:
return path
return None


def get_entrypoints(*, venv: VEnv, name: str) -> Optional[Tuple[EntryPoint, ...]]:
if not venv.lib_path:
logger.critical('cannot locate lib path in the venv')
return None
paths = list(venv.lib_path.glob('{}*.*-info'.format(name)))
if not paths:
paths = list(venv.lib_path.glob('{}*.*-info'.format(name.replace('-', '_'))))
if not paths:
logger.critical('cannot locate dist-info for installed package')
return None

path = paths[0] / 'entry_points.txt'
if not path.exists():
# entry_points.txt can be missed for egg-info.
# In that case let's try to find a binary with the same name as package.
if venv.bin_path:
paths = (
venv.bin_path / name,
venv.bin_path / name.replace('-', '_'),
venv.bin_path / name.replace('_', '-'),
)

if IS_WINDOWS:
paths = tuple(p.with_suffix('.exe') for p in paths)

for path in paths:
if path.exists():
return (EntryPoint(path=path, name=name), )
paths = venv.lib_path.glob('*-*.*-info')
path = _get_matching_path(paths=paths, name=name)
if not path:
logger.critical('cannot locate dist-info for installed package')
return None

path = path / 'entry_points.txt'
if path.exists():
return EggInfoConverter().parse_entrypoints(content=path.read_text()).entrypoints

if not venv.bin_path:
logger.error('cannot find any entrypoints for package')
return None
return EggInfoConverter().parse_entrypoints(content=path.read_text()).entrypoints

# entry_points.txt can be missed for egg-info.
# In that case let's try to find a binary with the same name as package.
names = {
name,
name.replace('-', '_'),
name.replace('_', '-'),
name.replace('-', '').replace('_', ''),

canonicalize_name(name),
canonicalize_name(name).replace('-', '_'),
canonicalize_name(name).replace('_', '-'),
canonicalize_name(name).replace('-', '').replace('_', ''),
}
paths = (venv.bin_path / name for name in names)
if IS_WINDOWS:
paths = tuple(p.with_suffix('.exe') for p in paths)

for path in paths:
if path.exists():
return (EntryPoint(path=path, name=name), )
logger.error('cannot find any entrypoints for package')
return None
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
except ImportError:
from distutils.core import setup

# built-in
import os.path


readme = ''
here = os.path.abspath(os.path.dirname(__file__))
readme_path = os.path.join(here, 'README.rst')
Expand Down
41 changes: 41 additions & 0 deletions tests/test_actions/test_entrypoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# built-in
from pathlib import Path

# external
import pytest

# project
from dephell.actions._entrypoints import _get_matching_path, get_entrypoints


@pytest.mark.parametrize('distinfo, pkg, match', [
('isort-4.3.21.dist-info', 'isort', True),
('flake8-3.7.9.dist-info', 'flake8', True),
('flake8-3.7.9.dist-info', 'flake8-isort', False),
('flake8_isort-2.7.0.dist-info', 'flake8-isort', True),
('flake8_isort-2.7.0.dist-info', 'flake8', False),
# https://github.com/dephell/dephell/pull/380
('Sphinx-2.3.1.dist-info', 'sphinx', True),
('sphinxcontrib-2.3.1.dist-info', 'sphinx', False),
])
def test_get_matching_path(distinfo: str, pkg: str, match: bool):
actual = _get_matching_path(paths=[Path(distinfo)], name=pkg)
if match:
assert actual is not None
assert actual.name == distinfo
else:
assert actual is None


def test_smoke_get_entrypoints():
class FakeVenv:
lib_path = Path(pytest.__file__).parent.parent
bin_path = None

entrypoints = get_entrypoints(venv=FakeVenv, name='pytest')
assert len(entrypoints) == 2
assert {e.name for e in entrypoints} == {'pytest', 'py.test'}
assert {e.path for e in entrypoints} == {'pytest:main'}
2 changes: 2 additions & 0 deletions tests/test_actions/test_json.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# external
import pytest

# project
from dephell.actions._json import _flatdict


Expand Down

0 comments on commit 3f0ad08

Please sign in to comment.