From 107a9f16fac55fb5fca951bd69f41c18a5be5ab9 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Tue, 26 Sep 2023 18:55:00 +0200 Subject: [PATCH] Relax regex re. recognizing requirements.txt Zhihan found that the plotly project has some requirements files that are not recognized by FawltyDeps, with names like requirements_abc.txt. Using the underscore as a separator in the filename does not match our regex, which requires a word boundary ("\b") around the "requirements" string in the filename. Fix our regex: There is no reason why the underscore separator should disqualify this as a requirements file, and simplifying the regex to ".*requirements.*\.(txt|in)" is unlikely to introduce false positives (files that should _not_ be recognized as requirements.txt files, but now are). Also add unit tests precisely for parsing filenames of dependency files as I could not find another test case that tested exactly this. --- fawltydeps/extract_declared_dependencies.py | 2 +- tests/test_deps_parser_determination.py | 41 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/fawltydeps/extract_declared_dependencies.py b/fawltydeps/extract_declared_dependencies.py index 6c233ab7..e8bd1b8d 100644 --- a/fawltydeps/extract_declared_dependencies.py +++ b/fawltydeps/extract_declared_dependencies.py @@ -367,7 +367,7 @@ def first_applicable_parser(path: Path) -> Optional[ParserChoice]: lambda path: path.name == "pyproject.toml", parse_pyproject_toml ), ParserChoice.REQUIREMENTS_TXT: ParsingStrategy( - lambda path: re.compile(r".*\brequirements\b.*\.(txt|in)").match(path.name) + lambda path: re.compile(r".*requirements.*\.(txt|in)").match(path.name) is not None, parse_requirements_txt, ), diff --git a/tests/test_deps_parser_determination.py b/tests/test_deps_parser_determination.py index aff8c99a..33f9a49f 100644 --- a/tests/test_deps_parser_determination.py +++ b/tests/test_deps_parser_determination.py @@ -2,10 +2,12 @@ import logging import shutil +from pathlib import Path import pytest from fawltydeps.extract_declared_dependencies import ( + first_applicable_parser, parse_source, parse_sources, validate_deps_source, @@ -16,6 +18,45 @@ from .utils import assert_unordered_equivalence, collect_dep_names + +@pytest.mark.parametrize( + ["path", "expect_choice"], + [ + pytest.param(Path(path), expect_choice, id=path) + for path, expect_choice in [ + ("requirements.txt", ParserChoice.REQUIREMENTS_TXT), + ("setup.py", ParserChoice.SETUP_PY), + ("setup.cfg", ParserChoice.SETUP_CFG), + ("pyproject.toml", ParserChoice.PYPROJECT_TOML), + ("anything_else", None), + ("sub/requirements.txt", ParserChoice.REQUIREMENTS_TXT), + ("sub/setup.py", ParserChoice.SETUP_PY), + ("sub/setup.cfg", ParserChoice.SETUP_CFG), + ("sub/pyproject.toml", ParserChoice.PYPROJECT_TOML), + ("sub/anything_else", None), + ("/abs/requirements.txt", ParserChoice.REQUIREMENTS_TXT), + ("/abs/setup.py", ParserChoice.SETUP_PY), + ("/abs/setup.cfg", ParserChoice.SETUP_CFG), + ("/abs/pyproject.toml", ParserChoice.PYPROJECT_TOML), + ("/abs/anything_else", None), + ("requirements.txt/wat", None), + ("setup.py/wat", None), + ("setup.cfg/wat", None), + ("pyproject.toml/wat", None), + ("requirements-dev.txt", ParserChoice.REQUIREMENTS_TXT), + ("test-requirements.txt", ParserChoice.REQUIREMENTS_TXT), + ("extra-requirements-dev.txt", ParserChoice.REQUIREMENTS_TXT), + ("abc_requirements.txt", ParserChoice.REQUIREMENTS_TXT), + ("requirements_abc.txt", ParserChoice.REQUIREMENTS_TXT), + ("more_requirements_stuff.txt", ParserChoice.REQUIREMENTS_TXT), + ("evenrequirementsthis.txt", ParserChoice.REQUIREMENTS_TXT), + ] + ], +) +def test_first_applicable_parser(path, expect_choice): + assert first_applicable_parser(path) is expect_choice + + PARSER_CHOICE_FILE_NAME_MATCH_GRID = { ParserChoice.REQUIREMENTS_TXT: "requirements.txt", ParserChoice.SETUP_PY: "setup.py",