Skip to content

Commit

Permalink
feat(dependency): add PEP 508 parser using packaging
Browse files Browse the repository at this point in the history
  • Loading branch information
mkniewallner committed Jun 16, 2024
1 parent e1cd973 commit c59ba15
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 2 deletions.
19 changes: 18 additions & 1 deletion python/deptry/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import re
from contextlib import suppress
from importlib import metadata
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Mapping

from packaging.requirements import InvalidRequirement, Requirement

if TYPE_CHECKING:
from collections.abc import Sequence
Expand Down Expand Up @@ -132,3 +134,18 @@ def _get_top_level_module_names_from_record_file(distribution: Distribution) ->
matches = re.finditer(r"^(?!__)([a-zA-Z0-9-_]+)(?:/|\.py,)", metadata_records, re.MULTILINE)

return {x.group(1) for x in matches}


def parse_pep_508_dependency(
specification: str, definition_file: Path, package_module_name_map: Mapping[str, Sequence[str]]
) -> Dependency | None:
try:
requirement = Requirement(specification)
except InvalidRequirement:
return None

return Dependency(
name=requirement.name,
definition_file=definition_file,
module_names=package_module_name_map.get(requirement.name),
)
48 changes: 47 additions & 1 deletion tests/unit/test_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

from importlib.metadata import PackageNotFoundError
from pathlib import Path
from typing import Any
from unittest.mock import patch

from deptry.dependency import Dependency
import pytest

from deptry.dependency import Dependency, parse_pep_508_dependency


def test_simple_dependency() -> None:
Expand Down Expand Up @@ -99,3 +102,46 @@ def test_not_predefined_and_not_installed() -> None:

assert dependency.name == "Foo-bar"
assert dependency.top_levels == {"foo_bar"}


@pytest.mark.parametrize(
("specification", "definition_file", "package_module_name_map", "expected"),
[
(
"foo",
Path("pyproject.toml"),
{},
{
"name": "foo",
"definition_file": Path("pyproject.toml"),
"found": False,
"top_levels": {"foo"},
},
),
(
'foobar[extra]==1.2.3; python_version < "3.9"',
Path("requirements.txt"),
{"foobar": ["foo"], "barfoo": ["bar"]},
{
"name": "foobar",
"definition_file": Path("requirements.txt"),
"found": False,
"top_levels": {"foo"},
},
),
],
)
def test_parse_pep_508_dependency(
specification: str,
definition_file: Path,
package_module_name_map: dict[str, list[str]],
expected: dict[str, Any],
) -> None:
dependency = parse_pep_508_dependency(specification, definition_file, package_module_name_map)

for dependency_key, expected_value in expected.items():
assert getattr(dependency, dependency_key) == expected_value


def test_parse_pep_508_dependency_invalid_definition() -> None:
assert parse_pep_508_dependency("an_incorrect_definition=1.2.3", Path("pyproject.toml"), {}) is None

0 comments on commit c59ba15

Please sign in to comment.