Skip to content

deptry fails to parse requirements.txt files with filepath entries in #1348

Description

@sambrown3-nhs

Environment

  • deptry version: 0.24.0
  • Python version: 3.11
  • Operating system (e.g. Ubuntu 22.04, Windows 11): Ubuntu 22.04

Describe the issue

Our requirements.txt file contains a filepath to a locally held python wheel file, as is specified as an option in the Requirements File Format specification, but this causes deptry to bail out with a crashdump when trying to parse this file.

Sample Output:

$ deptry . --verbose
Running with the following configuration:
root: (PosixPath('.'),)
config: pyproject.toml
no_ansi: False
per_rule_ignores: {}
ignore: ()
exclude: ('venv', '\\.venv', '\\.direnv', 'tests', '\\.git', 'setup\\.py')
extend_exclude: ()
using_default_exclude: True
ignore_notebooks: False
requirements_files: ('requirements.txt',)
using_default_requirements_files: False
requirements_files_dev: ('ide-requirements-dev.txt',)
known_first_party: ()
json_output: None
package_module_name_map: {}
pep621_dev_dependency_groups: ()
experimental_namespace_package: False
github_output: False
github_warning_errors: ()

pyproject.toml found!
pyproject.toml does not contain a [tool.poetry] section, so Poetry is not used to specify the project's dependencies.
pyproject.toml does not contain a [tool.uv.dev-dependencies] section, so uv is not used to specify the project's dependencies.
pyproject.toml does not contain a [tool.pdm.dev-dependencies] section, so PDM is not used to specify the project's dependencies.
pyproject.toml contains a [project] section, so PEP 621 is used to specify the project's dependencies.
pyproject.toml has the entry build-system.build-backend == 'setuptools.build_meta', so setuptoolsis used to specify the project's dependencies.
Scanning requirements.txt for dependencies
Traceback (most recent call last):
  File "/opt/project-env/lib/python3.11/site-packages/packaging/requirements.py", line 36, in __init__
    parsed = _parse_requirement(requirement_string)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/packaging/_parser.py", line 62, in parse_requirement
    return _parse_requirement(Tokenizer(source, rules=DEFAULT_RULES))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/packaging/_parser.py", line 71, in _parse_requirement
    name_token = tokenizer.expect(
                 ^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/packaging/_tokenizer.py", line 143, in expect
    raise self.raise_syntax_error(f"Expected {expected}")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/packaging/_tokenizer.py", line 168, in raise_syntax_error
    raise ParserSyntaxError(
packaging._tokenizer.ParserSyntaxError: Expected package name at the start of dependency specifier
    ./basket/our_internal_package.whl
    ^

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/project-env/bin/deptry", line 7, in <module>
    sys.exit(deptry())
             ^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/deptry/cli.py", line 318, in deptry
    cli(max_content_width=column_size)
  File "/opt/project-env/lib/python3.11/site-packages/click/core.py", line 1485, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/click/core.py", line 1406, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/click/core.py", line 1269, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/click/core.py", line 824, in invoke
    return callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/deptry/cli.py", line 312, in cli
    ).run()
      ^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/deptry/core.py", line 58, in run
    dependencies_extract = dependency_getter.get()
                           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/deptry/dependency_getter/pep621/base.py", line 48, in get
    dependencies = self._get_dependencies()
                   ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/deptry/dependency_getter/pep621/base.py", line 71, in _get_dependencies
    return get_dependencies_from_requirements_files(dependencies_files, self.package_module_name_map)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/deptry/dependency_getter/requirements_files.py", line 56, in get_dependencies_from_requirements_files
    itertools.chain(
  File "/opt/project-env/lib/python3.11/site-packages/deptry/dependency_getter/requirements_files.py", line 58, in <genexpr>
    get_dependencies_from_requirements_file(file_name, package_module_name_map, is_dev)
  File "/opt/project-env/lib/python3.11/site-packages/deptry/dependency_getter/requirements_files.py", line 74, in get_dependencies_from_requirements_file
    for requirement in requirements.parse(requirements_file_content):
  File "/opt/project-env/lib/python3.11/site-packages/requirements/parser.py", line 90, in parse
    yield Requirement.parse(line)
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/requirements/requirement.py", line 274, in parse
    return cls.parse_line(line)
           ^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/requirements/requirement.py", line 240, in parse_line
    pkg_req = Req(line_without_comment)
              ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/project-env/lib/python3.11/site-packages/packaging/requirements.py", line 38, in __init__
    raise InvalidRequirement(str(e)) from e
packaging.requirements.InvalidRequirement: Expected package name at the start of dependency specifier
    ./basket/our_internal_package.whl
    ^

Minimal way to reproduce the issue

Download any python wheel, and add a path to that file to a requirements.txt file. When deptry parses that reqs file, it fails to do so.

Expected behavior

Deptry should parse the requirements file successfully, and run as normal

Additional context

When I remove that path from our requirements file, deptry successfully runs, but throws a lot of DEP003 'our_internal_package' imported but it is a transitive dependency as it hasn't detected that our_internal_package is specified as a wheel file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingupstream issueIssue is related to an upstream dependency

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions