Skip to content

Commit

Permalink
Implement import detection
Browse files Browse the repository at this point in the history
Ref #25
  • Loading branch information
jaraco authored Aug 31, 2024
2 parents 8bf9356 + a3a390a commit 1899445
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
2 changes: 2 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
'jaraco.compat >= 4.1',
'importlib_resources; python_version < "3.12"',
'jaraco.vcs',
'more-itertools',
'coherent.deps',
]


Expand Down
75 changes: 74 additions & 1 deletion discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import mimetypes
import operator
import pathlib
import re
import subprocess
import sys
import types
import urllib.parse
from collections.abc import Mapping
Expand All @@ -19,9 +21,12 @@
import setuptools_scm
from jaraco.compat.py38 import r_fix
from jaraco.context import suppress
from more_itertools import unique_everseen
from packaging.version import Version
from pip_run import scripts

from ..deps import imports, pypi

log = logging.getLogger(__name__)

mimetypes.add_type('text/plain', '', strict=True)
Expand Down Expand Up @@ -120,13 +125,81 @@ def python_requires_supported():
return f'>= {min_ver}'


def read_deps():
def declared_deps():
"""
Read deps from ``__init__.py``.
"""
return scripts.DepsReader.search(['__init__.py'])


def source_files():
"""
Return all files in the source distribution.
>>> list(source_files())
[...Path('discovery.py')...]
"""
return (
pathlib.Path(path)
for path in subprocess.check_output(['git', 'ls-files'], text=True).splitlines()
)


def is_python(path: pathlib.Path) -> bool:
return path.suffix == '.py'


def inferred_deps():
"""
Infer deps from module imports.
"""
names = [
(imp.relative_to(best_name()), module)
for module in filter(is_python, source_files())
for imp in imports.get_module_imports(module)
if not imp.builtin()
and not imp.relative_to(best_name()).startswith(best_name())
]
for name, module in names:
try:
yield pypi.distribution_for(name) + extra_for(module)
except Exception:
print("Error resolving import", name, file=sys.stderr)


def combined_deps():
def normalize(name):
return re.sub(r'[.-_]', '-', name).lower()

def package_name(dep):
return normalize(packaging.requirements.Requirement(dep).name)

return unique_everseen(
itertools.chain(declared_deps(), inferred_deps()),
key=package_name,
)


def extra_for(module: pathlib.Path) -> str:
"""
Emit appropriate extra marker if relevant to the module's path.
>>> extra_for(pathlib.Path('foo/bar'))
''
>>> extra_for(pathlib.Path('foo.py'))
''
>>> extra_for(pathlib.Path('tests/functional/foo'))
'; extra=="test"'
>>> extra_for(pathlib.Path('docs/conf.py'))
'; extra=="doc"'
"""
mapping = dict(tests='test', docs='doc')
try:
return f'; extra=="{mapping[str(list(module.parents)[-2])]}"'
except (KeyError, IndexError):
return ''


def extras_from_dep(dep):
try:
markers = packaging.requirements.Requirement(dep).marker._markers
Expand Down
2 changes: 1 addition & 1 deletion metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def _discover_fields():
yield 'Author-Email', discovery.author_from_vcs()
yield 'Summary', discovery.summary_from_github()
yield 'Requires-Python', discovery.python_requires_supported()
deps = list(discovery.read_deps())
deps = list(discovery.combined_deps())
for dep in deps:
yield 'Requires-Dist', dep
for extra in discovery.full_extras(discovery.extras_from_deps(deps)):
Expand Down

0 comments on commit 1899445

Please sign in to comment.