From 145cdb4adf9f808dd095b3f3e5f9185f88ebe7ed Mon Sep 17 00:00:00 2001 From: Kieran W <41634689+FredHappyface@users.noreply.github.com> Date: Wed, 9 Oct 2024 00:16:38 +0100 Subject: [PATCH 1/5] updates to resolvers. pytests failing --- licensecheck/cli.py | 65 ++++++---- licensecheck/get_deps.py | 131 +++++++------------ licensecheck/resolvers/native.py | 27 ++++ licensecheck/resolvers/uv.py | 4 - tests/data/pep631_socks/pyproject.toml | 40 ++++++ tests/test_get_reqs.py | 166 +++++++++++++++++++++++++ tests/test_resolvers_native.py | 12 +- tests/test_resolvers_uv.py | 18 +-- 8 files changed, 328 insertions(+), 135 deletions(-) create mode 100644 tests/data/pep631_socks/pyproject.toml create mode 100644 tests/test_get_reqs.py diff --git a/licensecheck/cli.py b/licensecheck/cli.py index ca30ba0..c3237ff 100644 --- a/licensecheck/cli.py +++ b/licensecheck/cli.py @@ -8,7 +8,8 @@ from dataclasses import fields from pathlib import Path from sys import exit as sysexit -from sys import stdout +from sys import stdout, stdin +from typing import TextIO from fhconfparser import FHConfParser, SimpleConf @@ -30,17 +31,24 @@ def cli() -> None: # pragma: no cover "-f", help=f"Output format. one of: {', '.join(list(formatter.formatMap))}. default=simple", ) + parser.add_argument( + "--deps-file", + "-i", + "-d", + help="Filename to read from (omit for stdin)", + nargs="+", + ) + parser.add_argument( + "--groups", + "-g", + help="Select groups from supported files", + nargs="+", + ) parser.add_argument( "--file", "-o", help="Filename to write to (omit for stdout)", ) - parser.add_argument( - "--using", - "-u", - help="Environment to use e.g. requirements.txt. one of: " - f"{', '.join(get_deps.USINGS)}. default=poetry", - ) parser.add_argument( "--ignore-packages", help="a list of packages to ignore (compat=True)", @@ -110,31 +118,34 @@ def main(args: dict) -> int: simpleConf = SimpleConf(configparser, "licensecheck", args) # File - textIO = ( + input_file = ( + simpleConf.get("deps_file") or stdin + ) + output_file = ( stdout if simpleConf.get("file") is None else Path(simpleConf.get("file")).open("w", encoding="utf-8") ) # Get my license - myLiceTxt = args["license"] if args.get("license") else packageinfo.getMyPackageLicense() - myLice = license_matrix.licenseType(myLiceTxt)[0] - - # Get list of licenses - depsWithLicenses = get_deps.getDepsWithLicenses( - simpleConf.get("using", "poetry"), - myLice, - list(map(types.ucstr, simpleConf.get("ignore_packages", []))), - list(map(types.ucstr, simpleConf.get("fail_packages", []))), - list(map(types.ucstr, simpleConf.get("ignore_licenses", []))), - list(map(types.ucstr, simpleConf.get("fail_licenses", []))), - list(map(types.ucstr, simpleConf.get("only_licenses", []))), - list(map(types.ucstr, simpleConf.get("skip_dependencies", []))), + this_license_text = args["license"] if args.get("license") else packageinfo.getMyPackageLicense() + this_license = license_matrix.licenseType(this_license_text)[0] + + def getFromConfig(key: str) -> list[types.ucstr]: + return list(map(types.ucstr, simpleConf.get(key, []))) + + incompatible, depsWithLicenses = get_deps.check( + input_file=input_file, + groups=simpleConf.get("groups", []), + this_license=this_license, + ignore_packages=getFromConfig("ignore_packages"), + fail_packages=getFromConfig("fail_packages"), + ignore_licenses=getFromConfig("ignore_licenses"), + fail_licenses=getFromConfig("fail_licenses"), + only_licenses=getFromConfig("only_licenses"), + skip_dependencies=getFromConfig("skip_dependencies"), ) - # Are any licenses incompatible? - incompatible = any(not lice.licenseCompat for lice in depsWithLicenses) - # Format the results hide_output_parameters = [types.ucstr(x) for x in simpleConf.get("hide_output_parameters", [])] available_params = [param.name.upper() for param in fields(types.PackageInfo)] @@ -147,11 +158,11 @@ def main(args: dict) -> int: if simpleConf.get("format", "simple") in formatter.formatMap: print( formatter.formatMap[simpleConf.get("format", "simple")]( - myLice, + this_license, sorted(depsWithLicenses), hide_output_parameters, ), - file=textIO, + file=output_file, ) else: exitCode = 2 @@ -162,5 +173,5 @@ def main(args: dict) -> int: # Cleanup + exit if simpleConf.get("file") is not None: - textIO.close() + output_file.close() return exitCode diff --git a/licensecheck/get_deps.py b/licensecheck/get_deps.py index 1a0df65..b301eb2 100644 --- a/licensecheck/get_deps.py +++ b/licensecheck/get_deps.py @@ -11,126 +11,89 @@ from licensecheck.resolvers import uv as res_uv from licensecheck.types import JOINS, License, PackageInfo, ucstr -USINGS = ["requirements", "poetry", "PEP631"] -def getReqs(using: str, skipDependencies: list[ucstr]) -> set[ucstr]: - """Get requirements for the end user project/ lib. +def resolve_requirements( + requirements_paths: list[str], + groups: list[str], + skip_dependencies: list[ucstr], + ) -> set[ucstr]: - >>> getReqs("poetry") - >>> getReqs("poetry:dev") - >>> getReqs("requirements") - >>> getReqs("requirements:requirements.txt;requirements-dev.txt") - >>> getReqs("PEP631") - >>> getReqs("PEP631:tests") - - Args: - ---- - using (str): use requirements, poetry or PEP631. - skipDependencies (list[str]): list of dependencies to skip. - - Returns: - ------- - set[str]: set of requirement packages - - """ - - _ = using.split(":", 1) - using = _[0] - extras = _[1].split(";") if len(_) > 1 else [] - if using not in USINGS: - using = "poetry" - - # if using poetry or pep621 - requirementsPaths = ["pyproject.toml"] - - # Requirements - if using == "requirements": - requirementsPaths = ["requirements.txt"] if len(extras) > 0 else extras - extras = [] try: return res_uv.get_reqs( - using=using, - skipDependencies=skipDependencies, - extras=extras, - requirementsPaths=requirementsPaths, + skipDependencies=skip_dependencies, + extras=groups, + requirementsPaths=requirements_paths, ) except RuntimeError: pyproject = {} - if "pyproject.toml" in requirementsPaths: + if "pyproject.toml" in requirements_paths: pyproject = tomli.loads(Path("pyproject.toml").read_text("utf-8")) # Fallback to the old resolver (hopefully we can deprecate this asap!) return res_native.get_reqs( - using=using, - skipDependencies=skipDependencies, - extras=extras, + skipDependencies=skip_dependencies, + extras=groups, pyproject=pyproject, - requirementsPaths=[Path(x) for x in requirementsPaths], + requirementsPaths=[Path(x) for x in requirements_paths], ) -def getDepsWithLicenses( - using: str, - myLice: License, - ignorePackages: list[ucstr], - failPackages: list[ucstr], - ignoreLicenses: list[ucstr], - failLicenses: list[ucstr], - onlyLicenses: list[ucstr], - skipDependencies: list[ucstr], -) -> set[PackageInfo]: - """Get a set of dependencies with licenses and determine license compatibility. - - Args: - ---- - using (str): use requirements or poetry - myLice (License): user license - ignorePackages (list[ucstr]): a list of packages to ignore (compat=True) - failPackages (list[ucstr]): a list of packages to fail (compat=False) - ignoreLicenses (list[ucstr]): a list of licenses to ignore (skipped, compat may still be - False) - failLicenses (list[ucstr]): a list of licenses to fail (compat=False) - onlyLicenses (list[ucstr]): a list of allowed licenses (any other license will fail) - skipDependencies (list[ucstr]): a list of dependencies to skip (compat=False) - - Returns: - ------- - tuple[License, set[PackageInfo]]: tuple of - my package license - set of updated dependencies with licenseCompat set - - """ - reqs = getReqs(using, skipDependencies) +def check( + requirements_paths: list[str], + groups: list[str], + this_license: License, + ignore_packages: list[ucstr] | None = None, + fail_packages: list[ucstr] | None = None, + ignore_licenses: list[ucstr] | None = None, + fail_licenses: list[ucstr] | None = None, + only_licenses: list[ucstr] | None = None, + skip_dependencies: list[ucstr] | None = None, +) -> tuple[bool, set[PackageInfo]]: + + # Def values + ignore_packages = ignore_packages or [] + fail_packages = fail_packages or [] + ignore_licenses = ignore_licenses or [] + fail_licenses = fail_licenses or [] + only_licenses = only_licenses or [] + skip_dependencies = skip_dependencies or [] + + + requirements = resolve_requirements(requirements_paths, groups, skip_dependencies) ignoreLicensesType = license_matrix.licenseType( - ucstr(JOINS.join(ignoreLicenses)), ignoreLicenses + ucstr(JOINS.join(ignore_licenses)), ignore_licenses ) - failLicensesType = license_matrix.licenseType(ucstr(JOINS.join(failLicenses)), ignoreLicenses) - onlyLicensesType = license_matrix.licenseType(ucstr(JOINS.join(onlyLicenses)), ignoreLicenses) + failLicensesType = license_matrix.licenseType(ucstr(JOINS.join(fail_licenses)), ignore_licenses) + onlyLicensesType = license_matrix.licenseType(ucstr(JOINS.join(only_licenses)), ignore_licenses) # licenseType will always return NO_LICENSE when onlyLicenses is empty # noqa: ERA001 if License.NO_LICENSE in onlyLicensesType: onlyLicensesType.remove(License.NO_LICENSE) # Check it is compatible with packages and add a note - packages = packageinfo.getPackages(reqs) + packages = packageinfo.getPackages(requirements) for package in packages: # Deal with --ignore-packages and --fail-packages package.licenseCompat = False packageName = package.name.upper() - if packageName in ignorePackages: + if packageName in ignore_packages: package.licenseCompat = True - elif packageName in failPackages: + elif packageName in fail_packages: pass # package.licenseCompat = False # Else get compat with myLice else: package.licenseCompat = license_matrix.depCompatWMyLice( - myLice, - license_matrix.licenseType(package.license, ignoreLicenses), + this_license, + license_matrix.licenseType(package.license, ignore_licenses), ignoreLicensesType, failLicensesType, onlyLicensesType, ) - return packages + + # Are any licenses incompatible? + incompatible = any(not package.licenseCompat for package in packages) + + return incompatible, packages diff --git a/licensecheck/resolvers/native.py b/licensecheck/resolvers/native.py index 8cbe2be..427f0a3 100644 --- a/licensecheck/resolvers/native.py +++ b/licensecheck/resolvers/native.py @@ -8,12 +8,39 @@ from packaging.requirements import Requirement from packaging.utils import canonicalize_name +import tomli from licensecheck.session import session from licensecheck.types import ucstr def get_reqs( + skipDependencies: list[ucstr], + extras: list[str], + requirementsPaths: list[Path], + pyproject: dict[str, Any], +) -> set[ucstr]: + + using = "[unknown]" + + # determine using based on file type + for requirementsPath in requirementsPaths: + try: + tomli.loads(requirementsPath.read_text("utf-8")) + if pyproject.get("project", {}).get("dependencies") is not None: + using = "PEP631" + if pyproject.get("tool", {}).get("poetry", {}).get("dependencies") is not None: + using = "poetry" + + except tomli.TOMLDecodeError: + using = "requirements" + + + return do_get_reqs(using=using, skipDependencies=skipDependencies, extras=extras, pyproject=pyproject, requirementsPaths=requirementsPaths) + + + +def do_get_reqs( using: str, skipDependencies: list[ucstr], extras: list[str], diff --git a/licensecheck/resolvers/uv.py b/licensecheck/resolvers/uv.py index 73015b2..75aa06f 100644 --- a/licensecheck/resolvers/uv.py +++ b/licensecheck/resolvers/uv.py @@ -13,14 +13,10 @@ def get_reqs( - using: str, skipDependencies: list[ucstr], extras: list[str], requirementsPaths: list[str], ) -> set[ucstr]: - if using == "requirements" and len(extras) > 0: - msg = "You may not use extras with requirements.txt" - raise RuntimeError(msg) for idx, requirement in enumerate(requirementsPaths): if not Path(requirement).exists(): diff --git a/tests/data/pep631_socks/pyproject.toml b/tests/data/pep631_socks/pyproject.toml new file mode 100644 index 0000000..ff70564 --- /dev/null +++ b/tests/data/pep631_socks/pyproject.toml @@ -0,0 +1,40 @@ +[project] +# Added to example. +name = "pep631_socks" +license = "gpl-3.0-or-later" + +# Example copied from https://peps.python.org/pep-0631/#example +dependencies = [ + 'cached-property >= 1.2.0, < 2', + 'distro >= 1.5.0, < 2', + 'docker[ssh] >= 4.2.2, < 5', + 'dockerpty >= 0.4.1, < 1', + 'docopt >= 0.6.1, < 1', + 'jsonschema >= 2.5.1, < 4', + 'PyYAML >= 3.10, < 6', + 'python-dotenv >= 0.13.0, < 1', + 'requests >= 2.20.0, < 3', + 'texttable >= 0.9.0, < 2', + 'websocket-client >= 0.32.0, < 1', + # 'toskip >= 0.0.1', + + # Conditional + 'backports.shutil_get_terminal_size == 1.0.0; python_version < "3.3"', + 'backports.ssl_match_hostname >= 3.5, < 4; python_version < "3.5"', + 'colorama >= 0.4, < 1; sys_platform == "win32"', + 'enum34 >= 1.0.4, < 2; python_version < "3.4"', + 'ipaddress >= 1.0.16, < 2; python_version < "3.3"', + 'subprocess32 >= 3.5.4, < 4; python_version < "3.2"', +] + +[project.optional-dependencies] +socks = [ 'PySocks >= 1.5.6, != 1.5.7, < 2' ] +tests = [ + 'ddt >= 1.2.2, < 2', + 'pytest < 6', + 'mock >= 1.0.1, < 4; python_version < "3.4"', +] + +# Added to example. +[tool.licensecheck] +using = "PEP631:socks" diff --git a/tests/test_get_reqs.py b/tests/test_get_reqs.py new file mode 100644 index 0000000..63a7e8f --- /dev/null +++ b/tests/test_get_reqs.py @@ -0,0 +1,166 @@ +import contextlib +from pathlib import Path + +from licensecheck import types +from licensecheck.get_deps import resolve_requirements + +THISDIR = Path(__file__).resolve().parent + + +def test_pep631_socks() -> None: + using = "PEP631:socks" + skipDependencies = [types.ucstr("TOSKIP")] + + assert resolve_requirements(using, skipDependencies) == { + "DOCKERPTY", + "ATTRS", + "JSONSCHEMA", + "PYYAML", + "PYSOCKS", + "CERTIFI", + "DOCKER", + "TEXTTABLE", + "PYWIN32", + "DOCOPT", + "PARAMIKO", + "IDNA", + "COLORAMA", + "CACHED-PROPERTY", + "DISTRO", + "CHARSET-NORMALIZER", + "URLLIB3", + "WEBSOCKET-CLIENT", + "REQUESTS", + "PYTHON-DOTENV", + "CFFI", + "PYNACL", + "BCRYPT", + "SIX", + "PYCPARSER", + "CRYPTOGRAPHY", + "PYRSISTENT", + "PYPIWIN32", + "SETUPTOOLS", + } + + +def test_requirements() -> None: + using = "requirements" + extras = [] + requirementsPaths = [f"{THISDIR}/data/test_requirements.txt"] + skipDependencies = [types.ucstr("TOSKIP")] + + deps = resolve_requirements(using, skipDependencies, extras, requirementsPaths) + assert deps == { + "NUMPY", + "ODFPY", + "OPENPYXL", + "PANDAS", + "SIX", + "DEFUSEDXML", + "ET-XMLFILE", + "PYTHON-DATEUTIL", + "PYTZ", + "PYXLSB", + "TZDATA", + "XLRD", + "XLSXWRITER", + } + assert "OPENPYXL" in deps + assert ( + "XARRAY" not in deps + ) # xarray is an optional dependency of pandas associated with 'computation' key that is not + # tracked in test_requirements.txt + + +def test_requirements_with_hashes() -> None: + using = "requirements" + extras = [] + requirementsPaths = [f"{THISDIR}/data/test_requirements_hash.txt"] + skipDependencies = [types.ucstr("TOSKIP")] + + deps = resolve_requirements(using, skipDependencies, extras, requirementsPaths) + assert deps == {"PACKAGING"} + assert "TOSKIP" not in deps + + +def test_issue_62() -> None: + using = "PEP631" + extras = [] + requirementsPaths = [f"{THISDIR}/data/issue_62.toml"] + skipDependencies = [] + + reqs = resolve_requirements(using, skipDependencies, extras, requirementsPaths) + assert "PYQT5" not in reqs + + assert reqs == { + "CACHETOOLS", + "CERTIFI", + "CHARSET-NORMALIZER", + "DEPRECATED", + "EARTHENGINE-API", + "GOOGLE-API-CORE", + "GOOGLE-API-PYTHON-CLIENT", + "GOOGLE-AUTH", + "GOOGLE-AUTH-HTTPLIB2", + "GOOGLE-CLOUD-CORE", + "GOOGLE-CLOUD-STORAGE", + "GOOGLE-CRC32C", + "GOOGLE-RESUMABLE-MEDIA", + "GOOGLEAPIS-COMMON-PROTOS", + "HTTPLIB2", + "IDNA", + "NUMPY", + "PANDAS", + "PROTO-PLUS", + "PROTOBUF", + "PYARROW", + "PYASN1", + "PYASN1-MODULES", + "PYPARSING", + "PYTHON-DATEUTIL", + "PYTZ", + "REQUESTS", + "RSA", + "SIX", + "URITEMPLATE", + "URLLIB3", + "WRAPT", + } + + +def test_issue_81() -> None: + using = "requirements" + extras = [] + requirementsPaths = [f"{THISDIR}/data/issue_81.txt"] + skipDependencies = [] + with contextlib.suppress(Exception): + deps = resolve_requirements(using, skipDependencies, extras, requirementsPaths) + # RuntimeError: × No solution found when resolving dependencies: + # ╰─▶ Because nvidia-cudnn-cu12==8.9.2.26 has no wheels with a matching + # platform tag and you require nvidia-cudnn-cu12==8.9.2.26, we can + # conclude that your requirements are unsatisfiable. + + +def test_issue_84() -> None: + using = "requirements" + extras = [] + requirementsPaths = [f"{THISDIR}/data/issue_84.txt"] + skipDependencies = [] + + deps = resolve_requirements(using, skipDependencies, extras, requirementsPaths) + assert deps == { + "AMQP", + "BILLIARD", + "CELERY", + "CLICK", + "CLICK-DIDYOUMEAN", + "CLICK-PLUGINS", + "CLICK-REPL", + "COLORAMA", + "KOMBU", + "PROMPT-TOOLKIT", + "PYTZ", + "VINE", + "WCWIDTH", + } diff --git a/tests/test_resolvers_native.py b/tests/test_resolvers_native.py index 984fcc5..d5e654e 100644 --- a/tests/test_resolvers_native.py +++ b/tests/test_resolvers_native.py @@ -9,13 +9,12 @@ def test_doGetReqs_PEP631() -> None: - using = "PEP631" extras = ["socks"] pyproject = tomli.loads((THISDIR / "data/pep631_socks.toml").read_text(encoding="utf-8")) requirementsPaths = [] skipDependencies = [types.ucstr("TOSKIP")] - assert get_deps.get_reqs(using, skipDependencies, extras, pyproject, requirementsPaths) == { + assert get_deps.get_reqs(skipDependencies, extras, requirementsPaths, pyproject) == { "DOCKERPTY", "PACKAGING", "ATTRS", @@ -51,13 +50,12 @@ def test_doGetReqs_PEP631() -> None: def test_doGetReqs_requirements() -> None: - using = "requirements" extras = [f"{THISDIR}/data/test_requirements.txt"] pyproject = {} requirementsPaths = [Path(f"{THISDIR}/data/test_requirements.txt")] skipDependencies = [types.ucstr("TOSKIP")] - deps = get_deps.get_reqs(using, skipDependencies, extras, pyproject, requirementsPaths) + deps = get_deps.get_reqs(skipDependencies, extras, requirementsPaths, pyproject) assert deps == { "NUMPY", "ODFPY", @@ -79,25 +77,23 @@ def test_doGetReqs_requirements() -> None: def test_doGetReqs_requirements_with_hashes() -> None: - using = "requirements" extras = [] pyproject = {} requirementsPaths = [Path(f"{THISDIR}/data/test_requirements_hash.txt")] skipDependencies = [types.ucstr("TOSKIP")] - deps = get_deps.get_reqs(using, skipDependencies, extras, pyproject, requirementsPaths) + deps = get_deps.get_reqs(skipDependencies, extras, requirementsPaths, pyproject) assert deps == {"PACKAGING"} assert "TOSKIP" not in deps def test_issue_81() -> None: - using = "requirements" extras = [] pyproject = {} requirementsPaths = [Path(f"{THISDIR}/data/issue_81.txt")] skipDependencies = [] - deps = get_deps.get_reqs(using, skipDependencies, extras, pyproject, requirementsPaths) + deps = get_deps.get_reqs(skipDependencies, extras, requirementsPaths, pyproject) assert deps == { "DATACLASSES", "LANGSMITH", diff --git a/tests/test_resolvers_uv.py b/tests/test_resolvers_uv.py index 7f46c5f..9d04362 100644 --- a/tests/test_resolvers_uv.py +++ b/tests/test_resolvers_uv.py @@ -8,12 +8,11 @@ def test_PEP631() -> None: - using = "PEP631" extras = ["socks"] requirementsPaths = [f"{THISDIR}/data/pep631_socks.toml"] skipDependencies = [types.ucstr("TOSKIP")] - assert req_uv.get_reqs(using, skipDependencies, extras, requirementsPaths) == { + assert req_uv.get_reqs(skipDependencies, extras, requirementsPaths) == { "DOCKERPTY", "ATTRS", "JSONSCHEMA", @@ -47,12 +46,11 @@ def test_PEP631() -> None: def test_requirements() -> None: - using = "requirements" extras = [] requirementsPaths = [f"{THISDIR}/data/test_requirements.txt"] skipDependencies = [types.ucstr("TOSKIP")] - deps = req_uv.get_reqs(using, skipDependencies, extras, requirementsPaths) + deps = req_uv.get_reqs(skipDependencies, extras, requirementsPaths) assert deps == { "NUMPY", "ODFPY", @@ -76,23 +74,21 @@ def test_requirements() -> None: def test_requirements_with_hashes() -> None: - using = "requirements" extras = [] requirementsPaths = [f"{THISDIR}/data/test_requirements_hash.txt"] skipDependencies = [types.ucstr("TOSKIP")] - deps = req_uv.get_reqs(using, skipDependencies, extras, requirementsPaths) + deps = req_uv.get_reqs(skipDependencies, extras, requirementsPaths) assert deps == {"PACKAGING"} assert "TOSKIP" not in deps def test_issue_62() -> None: - using = "PEP631" extras = [] requirementsPaths = [f"{THISDIR}/data/issue_62.toml"] skipDependencies = [] - reqs = req_uv.get_reqs(using, skipDependencies, extras, requirementsPaths) + reqs = req_uv.get_reqs(skipDependencies, extras, requirementsPaths) assert "PYQT5" not in reqs assert reqs == { @@ -132,12 +128,11 @@ def test_issue_62() -> None: def test_issue_81() -> None: - using = "requirements" extras = [] requirementsPaths = [f"{THISDIR}/data/issue_81.txt"] skipDependencies = [] with contextlib.suppress(Exception): - deps = req_uv.get_reqs(using, skipDependencies, extras, requirementsPaths) + deps = req_uv.get_reqs(skipDependencies, extras, requirementsPaths) # RuntimeError: × No solution found when resolving dependencies: # ╰─▶ Because nvidia-cudnn-cu12==8.9.2.26 has no wheels with a matching # platform tag and you require nvidia-cudnn-cu12==8.9.2.26, we can @@ -145,12 +140,11 @@ def test_issue_81() -> None: def test_issue_84() -> None: - using = "requirements" extras = [] requirementsPaths = [f"{THISDIR}/data/issue_84.txt"] skipDependencies = [] - deps = req_uv.get_reqs(using, skipDependencies, extras, requirementsPaths) + deps = req_uv.get_reqs(skipDependencies, extras, requirementsPaths) assert deps == { "AMQP", "BILLIARD", From 6564798b56e57fdaed81ad917099fab003137b2d Mon Sep 17 00:00:00 2001 From: Kieran W <41634689+FredHappyface@users.noreply.github.com> Date: Wed, 9 Oct 2024 00:41:21 +0100 Subject: [PATCH 2/5] update tests, all passing --- licensecheck/cli.py | 23 ++-- tests/data/pep631_socks/pyproject.toml | 40 ------ tests/test_cli.py | 8 +- tests/test_get_reqs.py | 166 ------------------------- tests/test_resolvers_native.py | 2 +- tests/test_resolvers_uv.py | 1 + 6 files changed, 21 insertions(+), 219 deletions(-) delete mode 100644 tests/data/pep631_socks/pyproject.toml delete mode 100644 tests/test_get_reqs.py diff --git a/licensecheck/cli.py b/licensecheck/cli.py index c3237ff..a57d1c4 100644 --- a/licensecheck/cli.py +++ b/licensecheck/cli.py @@ -32,16 +32,15 @@ def cli() -> None: # pragma: no cover help=f"Output format. one of: {', '.join(list(formatter.formatMap))}. default=simple", ) parser.add_argument( - "--deps-file", - "-i", - "-d", - help="Filename to read from (omit for stdin)", + "--requirements-paths", + "-r", + help="Filenames to read from (omit for stdin)", nargs="+", ) parser.add_argument( "--groups", "-g", - help="Select groups from supported files", + help="Select groups/extras from supported files", nargs="+", ) parser.add_argument( @@ -91,7 +90,13 @@ def cli() -> None: # pragma: no cover action="store_true", ) args = vars(parser.parse_args()) - sysexit(main(args)) + stdin_path = Path("__stdin__") + if stdin: + stdin_path.write_text("\n".join(stdin.readlines()), "utf-8") + ec = main(args) + stdin_path.unlink(missing_ok=True) + + sysexit(ec) def main(args: dict) -> int: @@ -118,8 +123,8 @@ def main(args: dict) -> int: simpleConf = SimpleConf(configparser, "licensecheck", args) # File - input_file = ( - simpleConf.get("deps_file") or stdin + requirements_paths = ( + simpleConf.get("requirements_paths") or ["__stdin__"] ) output_file = ( stdout @@ -135,7 +140,7 @@ def getFromConfig(key: str) -> list[types.ucstr]: return list(map(types.ucstr, simpleConf.get(key, []))) incompatible, depsWithLicenses = get_deps.check( - input_file=input_file, + requirements_paths=requirements_paths, groups=simpleConf.get("groups", []), this_license=this_license, ignore_packages=getFromConfig("ignore_packages"), diff --git a/tests/data/pep631_socks/pyproject.toml b/tests/data/pep631_socks/pyproject.toml deleted file mode 100644 index ff70564..0000000 --- a/tests/data/pep631_socks/pyproject.toml +++ /dev/null @@ -1,40 +0,0 @@ -[project] -# Added to example. -name = "pep631_socks" -license = "gpl-3.0-or-later" - -# Example copied from https://peps.python.org/pep-0631/#example -dependencies = [ - 'cached-property >= 1.2.0, < 2', - 'distro >= 1.5.0, < 2', - 'docker[ssh] >= 4.2.2, < 5', - 'dockerpty >= 0.4.1, < 1', - 'docopt >= 0.6.1, < 1', - 'jsonschema >= 2.5.1, < 4', - 'PyYAML >= 3.10, < 6', - 'python-dotenv >= 0.13.0, < 1', - 'requests >= 2.20.0, < 3', - 'texttable >= 0.9.0, < 2', - 'websocket-client >= 0.32.0, < 1', - # 'toskip >= 0.0.1', - - # Conditional - 'backports.shutil_get_terminal_size == 1.0.0; python_version < "3.3"', - 'backports.ssl_match_hostname >= 3.5, < 4; python_version < "3.5"', - 'colorama >= 0.4, < 1; sys_platform == "win32"', - 'enum34 >= 1.0.4, < 2; python_version < "3.4"', - 'ipaddress >= 1.0.16, < 2; python_version < "3.3"', - 'subprocess32 >= 3.5.4, < 4; python_version < "3.2"', -] - -[project.optional-dependencies] -socks = [ 'PySocks >= 1.5.6, != 1.5.7, < 2' ] -tests = [ - 'ddt >= 1.2.2, < 2', - 'pytest < 6', - 'mock >= 1.0.1, < 4; python_version < "3.4"', -] - -# Added to example. -[tool.licensecheck] -using = "PEP631:socks" diff --git a/tests/test_cli.py b/tests/test_cli.py index d297e79..735a95c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -19,13 +19,14 @@ def aux_file(file: str) -> str: test_data = [ - ({"license": "MIT", "file": aux_file("test_main_tc1.txt")}, 0), + ({"license": "MIT", "file": aux_file("test_main_tc1.txt"), "requirements_paths": ["pyproject.toml"]}, 0), ( { "license": "BSD", "file": aux_file("test_main_tc3.txt"), - "ignore-packages": ["requests"], - "ignore-licenses": ["GPL"], + "requirements_paths": ["pyproject.toml"], + "ignore_packages": ["requests"], + "ignore_licenses": ["GPL"], }, 0, ), @@ -33,6 +34,7 @@ def aux_file(file: str) -> str: { "license": "GPL", "file": aux_file("test_main_tc4.json"), + "requirements_paths": ["pyproject.toml"], "format": "json", "hide_output_parameters": ["size", "version", "namever"], }, diff --git a/tests/test_get_reqs.py b/tests/test_get_reqs.py deleted file mode 100644 index 63a7e8f..0000000 --- a/tests/test_get_reqs.py +++ /dev/null @@ -1,166 +0,0 @@ -import contextlib -from pathlib import Path - -from licensecheck import types -from licensecheck.get_deps import resolve_requirements - -THISDIR = Path(__file__).resolve().parent - - -def test_pep631_socks() -> None: - using = "PEP631:socks" - skipDependencies = [types.ucstr("TOSKIP")] - - assert resolve_requirements(using, skipDependencies) == { - "DOCKERPTY", - "ATTRS", - "JSONSCHEMA", - "PYYAML", - "PYSOCKS", - "CERTIFI", - "DOCKER", - "TEXTTABLE", - "PYWIN32", - "DOCOPT", - "PARAMIKO", - "IDNA", - "COLORAMA", - "CACHED-PROPERTY", - "DISTRO", - "CHARSET-NORMALIZER", - "URLLIB3", - "WEBSOCKET-CLIENT", - "REQUESTS", - "PYTHON-DOTENV", - "CFFI", - "PYNACL", - "BCRYPT", - "SIX", - "PYCPARSER", - "CRYPTOGRAPHY", - "PYRSISTENT", - "PYPIWIN32", - "SETUPTOOLS", - } - - -def test_requirements() -> None: - using = "requirements" - extras = [] - requirementsPaths = [f"{THISDIR}/data/test_requirements.txt"] - skipDependencies = [types.ucstr("TOSKIP")] - - deps = resolve_requirements(using, skipDependencies, extras, requirementsPaths) - assert deps == { - "NUMPY", - "ODFPY", - "OPENPYXL", - "PANDAS", - "SIX", - "DEFUSEDXML", - "ET-XMLFILE", - "PYTHON-DATEUTIL", - "PYTZ", - "PYXLSB", - "TZDATA", - "XLRD", - "XLSXWRITER", - } - assert "OPENPYXL" in deps - assert ( - "XARRAY" not in deps - ) # xarray is an optional dependency of pandas associated with 'computation' key that is not - # tracked in test_requirements.txt - - -def test_requirements_with_hashes() -> None: - using = "requirements" - extras = [] - requirementsPaths = [f"{THISDIR}/data/test_requirements_hash.txt"] - skipDependencies = [types.ucstr("TOSKIP")] - - deps = resolve_requirements(using, skipDependencies, extras, requirementsPaths) - assert deps == {"PACKAGING"} - assert "TOSKIP" not in deps - - -def test_issue_62() -> None: - using = "PEP631" - extras = [] - requirementsPaths = [f"{THISDIR}/data/issue_62.toml"] - skipDependencies = [] - - reqs = resolve_requirements(using, skipDependencies, extras, requirementsPaths) - assert "PYQT5" not in reqs - - assert reqs == { - "CACHETOOLS", - "CERTIFI", - "CHARSET-NORMALIZER", - "DEPRECATED", - "EARTHENGINE-API", - "GOOGLE-API-CORE", - "GOOGLE-API-PYTHON-CLIENT", - "GOOGLE-AUTH", - "GOOGLE-AUTH-HTTPLIB2", - "GOOGLE-CLOUD-CORE", - "GOOGLE-CLOUD-STORAGE", - "GOOGLE-CRC32C", - "GOOGLE-RESUMABLE-MEDIA", - "GOOGLEAPIS-COMMON-PROTOS", - "HTTPLIB2", - "IDNA", - "NUMPY", - "PANDAS", - "PROTO-PLUS", - "PROTOBUF", - "PYARROW", - "PYASN1", - "PYASN1-MODULES", - "PYPARSING", - "PYTHON-DATEUTIL", - "PYTZ", - "REQUESTS", - "RSA", - "SIX", - "URITEMPLATE", - "URLLIB3", - "WRAPT", - } - - -def test_issue_81() -> None: - using = "requirements" - extras = [] - requirementsPaths = [f"{THISDIR}/data/issue_81.txt"] - skipDependencies = [] - with contextlib.suppress(Exception): - deps = resolve_requirements(using, skipDependencies, extras, requirementsPaths) - # RuntimeError: × No solution found when resolving dependencies: - # ╰─▶ Because nvidia-cudnn-cu12==8.9.2.26 has no wheels with a matching - # platform tag and you require nvidia-cudnn-cu12==8.9.2.26, we can - # conclude that your requirements are unsatisfiable. - - -def test_issue_84() -> None: - using = "requirements" - extras = [] - requirementsPaths = [f"{THISDIR}/data/issue_84.txt"] - skipDependencies = [] - - deps = resolve_requirements(using, skipDependencies, extras, requirementsPaths) - assert deps == { - "AMQP", - "BILLIARD", - "CELERY", - "CLICK", - "CLICK-DIDYOUMEAN", - "CLICK-PLUGINS", - "CLICK-REPL", - "COLORAMA", - "KOMBU", - "PROMPT-TOOLKIT", - "PYTZ", - "VINE", - "WCWIDTH", - } diff --git a/tests/test_resolvers_native.py b/tests/test_resolvers_native.py index d5e654e..b9a87de 100644 --- a/tests/test_resolvers_native.py +++ b/tests/test_resolvers_native.py @@ -11,7 +11,7 @@ def test_doGetReqs_PEP631() -> None: extras = ["socks"] pyproject = tomli.loads((THISDIR / "data/pep631_socks.toml").read_text(encoding="utf-8")) - requirementsPaths = [] + requirementsPaths = [(THISDIR / "data/pep631_socks.toml")] skipDependencies = [types.ucstr("TOSKIP")] assert get_deps.get_reqs(skipDependencies, extras, requirementsPaths, pyproject) == { diff --git a/tests/test_resolvers_uv.py b/tests/test_resolvers_uv.py index 9d04362..a8f4502 100644 --- a/tests/test_resolvers_uv.py +++ b/tests/test_resolvers_uv.py @@ -157,6 +157,7 @@ def test_issue_84() -> None: "KOMBU", "PROMPT-TOOLKIT", "PYTZ", + "TZDATA", "VINE", "WCWIDTH", } From 89240b911663d67dad7e4a2c480d25198dd9b5ac Mon Sep 17 00:00:00 2001 From: Kieran W <41634689+FredHappyface@users.noreply.github.com> Date: Wed, 9 Oct 2024 00:46:37 +0100 Subject: [PATCH 3/5] pre-commit and friends --- documentation/reference/licensecheck/cli.md | 2 +- .../reference/licensecheck/get_deps.md | 82 +++++-------------- .../licensecheck/resolvers/native.md | 28 ++++++- .../reference/licensecheck/resolvers/uv.md | 5 +- licensecheck/cli.py | 11 ++- licensecheck/get_deps.py | 7 +- licensecheck/resolvers/native.py | 13 +-- licensecheck/resolvers/uv.py | 1 - tests/test_cli.py | 14 +++- tests/test_resolvers_uv.py | 2 +- 10 files changed, 74 insertions(+), 91 deletions(-) diff --git a/documentation/reference/licensecheck/cli.md b/documentation/reference/licensecheck/cli.md index a5127ec..522b75b 100644 --- a/documentation/reference/licensecheck/cli.md +++ b/documentation/reference/licensecheck/cli.md @@ -24,7 +24,7 @@ def cli() -> None: ... ## main -[Show source in cli.py:89](../../../licensecheck/cli.py#L89) +[Show source in cli.py:101](../../../licensecheck/cli.py#L101) Test entry point. diff --git a/documentation/reference/licensecheck/get_deps.md b/documentation/reference/licensecheck/get_deps.md index 4de9d63..c327aae 100644 --- a/documentation/reference/licensecheck/get_deps.md +++ b/documentation/reference/licensecheck/get_deps.md @@ -5,88 +5,46 @@ > Auto-generated documentation for [licensecheck.get_deps](../../../licensecheck/get_deps.py) module. - [Get Deps](#get-deps) - - [getDepsWithLicenses](#getdepswithlicenses) - - [getReqs](#getreqs) + - [check](#check) + - [resolve_requirements](#resolve_requirements) -## getDepsWithLicenses +## check -[Show source in get_deps.py:75](../../../licensecheck/get_deps.py#L75) - -Get a set of dependencies with licenses and determine license compatibility. - -#### Arguments - ----- - - `using` *str* - use requirements or poetry - - `myLice` *License* - user license - - `ignorePackages` *list[ucstr]* - a list of packages to ignore (compat=True) - - `failPackages` *list[ucstr]* - a list of packages to fail (compat=False) - - `ignoreLicenses` *list[ucstr]* - a list of licenses to ignore (skipped, compat may still be - False) - - `failLicenses` *list[ucstr]* - a list of licenses to fail (compat=False) - - `onlyLicenses` *list[ucstr]* - a list of allowed licenses (any other license will fail) - - `skipDependencies` *list[ucstr]* - a list of dependencies to skip (compat=False) - -#### Returns - -------- - - `tuple[License,` *set[PackageInfo]]* - tuple of - my package license - set of updated dependencies with licenseCompat set +[Show source in get_deps.py:41](../../../licensecheck/get_deps.py#L41) #### Signature ```python -def getDepsWithLicenses( - using: str, - myLice: License, - ignorePackages: list[ucstr], - failPackages: list[ucstr], - ignoreLicenses: list[ucstr], - failLicenses: list[ucstr], - onlyLicenses: list[ucstr], - skipDependencies: list[ucstr], -) -> set[PackageInfo]: ... +def check( + requirements_paths: list[str], + groups: list[str], + this_license: License, + ignore_packages: list[ucstr] | None = None, + fail_packages: list[ucstr] | None = None, + ignore_licenses: list[ucstr] | None = None, + fail_licenses: list[ucstr] | None = None, + only_licenses: list[ucstr] | None = None, + skip_dependencies: list[ucstr] | None = None, +) -> tuple[bool, set[PackageInfo]]: ... ``` #### See also - [License](./types.md#license) - [PackageInfo](./types.md#packageinfo) -- [ucstr](./types.md#ucstr) - - - -## getReqs - -[Show source in get_deps.py:17](../../../licensecheck/get_deps.py#L17) - -Get requirements for the end user project/ lib. - -```python ->>> getReqs("poetry") ->>> getReqs("poetry:dev") ->>> getReqs("requirements") ->>> getReqs("requirements:requirements.txt;requirements-dev.txt") ->>> getReqs("PEP631") ->>> getReqs("PEP631:tests") -``` -#### Arguments ----- - - `using` *str* - use requirements, poetry or PEP631. - - `skipDependencies` *list[str]* - list of dependencies to skip. -#### Returns +## resolve_requirements -------- - - `set[str]` - set of requirement packages +[Show source in get_deps.py:15](../../../licensecheck/get_deps.py#L15) #### Signature ```python -def getReqs(using: str, skipDependencies: list[ucstr]) -> set[ucstr]: ... +def resolve_requirements( + requirements_paths: list[str], groups: list[str], skip_dependencies: list[ucstr] +) -> set[ucstr]: ... ``` #### See also diff --git a/documentation/reference/licensecheck/resolvers/native.md b/documentation/reference/licensecheck/resolvers/native.md index 207115d..435f288 100644 --- a/documentation/reference/licensecheck/resolvers/native.md +++ b/documentation/reference/licensecheck/resolvers/native.md @@ -5,11 +5,12 @@ > Auto-generated documentation for [licensecheck.resolvers.native](../../../../licensecheck/resolvers/native.py) module. - [Native](#native) + - [do_get_reqs](#do_get_reqs) - [get_reqs](#get_reqs) -## get_reqs +## do_get_reqs -[Show source in native.py:16](../../../../licensecheck/resolvers/native.py#L16) +[Show source in native.py:46](../../../../licensecheck/resolvers/native.py#L46) Underlying machineary to get requirements. @@ -30,7 +31,7 @@ Underlying machineary to get requirements. #### Signature ```python -def get_reqs( +def do_get_reqs( using: str, skipDependencies: list[ucstr], extras: list[str], @@ -41,4 +42,25 @@ def get_reqs( #### See also +- [ucstr](../types.md#ucstr) + + + +## get_reqs + +[Show source in native.py:17](../../../../licensecheck/resolvers/native.py#L17) + +#### Signature + +```python +def get_reqs( + skipDependencies: list[ucstr], + extras: list[str], + requirementsPaths: list[Path], + pyproject: dict[str, Any], +) -> set[ucstr]: ... +``` + +#### See also + - [ucstr](../types.md#ucstr) \ No newline at end of file diff --git a/documentation/reference/licensecheck/resolvers/uv.md b/documentation/reference/licensecheck/resolvers/uv.md index 208d2fc..607d7bd 100644 --- a/documentation/reference/licensecheck/resolvers/uv.md +++ b/documentation/reference/licensecheck/resolvers/uv.md @@ -15,10 +15,7 @@ ```python def get_reqs( - using: str, - skipDependencies: list[ucstr], - extras: list[str], - requirementsPaths: list[str], + skipDependencies: list[ucstr], extras: list[str], requirementsPaths: list[str] ) -> set[ucstr]: ... ``` diff --git a/licensecheck/cli.py b/licensecheck/cli.py index a57d1c4..ed711ed 100644 --- a/licensecheck/cli.py +++ b/licensecheck/cli.py @@ -8,8 +8,7 @@ from dataclasses import fields from pathlib import Path from sys import exit as sysexit -from sys import stdout, stdin -from typing import TextIO +from sys import stdin, stdout from fhconfparser import FHConfParser, SimpleConf @@ -123,9 +122,7 @@ def main(args: dict) -> int: simpleConf = SimpleConf(configparser, "licensecheck", args) # File - requirements_paths = ( - simpleConf.get("requirements_paths") or ["__stdin__"] - ) + requirements_paths = simpleConf.get("requirements_paths") or ["__stdin__"] output_file = ( stdout if simpleConf.get("file") is None @@ -133,7 +130,9 @@ def main(args: dict) -> int: ) # Get my license - this_license_text = args["license"] if args.get("license") else packageinfo.getMyPackageLicense() + this_license_text = ( + args["license"] if args.get("license") else packageinfo.getMyPackageLicense() + ) this_license = license_matrix.licenseType(this_license_text)[0] def getFromConfig(key: str) -> list[types.ucstr]: diff --git a/licensecheck/get_deps.py b/licensecheck/get_deps.py index b301eb2..ed185b7 100644 --- a/licensecheck/get_deps.py +++ b/licensecheck/get_deps.py @@ -12,14 +12,11 @@ from licensecheck.types import JOINS, License, PackageInfo, ucstr - def resolve_requirements( requirements_paths: list[str], groups: list[str], skip_dependencies: list[ucstr], - ) -> set[ucstr]: - - +) -> set[ucstr]: try: return res_uv.get_reqs( skipDependencies=skip_dependencies, @@ -52,7 +49,6 @@ def check( only_licenses: list[ucstr] | None = None, skip_dependencies: list[ucstr] | None = None, ) -> tuple[bool, set[PackageInfo]]: - # Def values ignore_packages = ignore_packages or [] fail_packages = fail_packages or [] @@ -61,7 +57,6 @@ def check( only_licenses = only_licenses or [] skip_dependencies = skip_dependencies or [] - requirements = resolve_requirements(requirements_paths, groups, skip_dependencies) ignoreLicensesType = license_matrix.licenseType( diff --git a/licensecheck/resolvers/native.py b/licensecheck/resolvers/native.py index 427f0a3..172992a 100644 --- a/licensecheck/resolvers/native.py +++ b/licensecheck/resolvers/native.py @@ -6,9 +6,9 @@ from pathlib import Path from typing import Any +import tomli from packaging.requirements import Requirement from packaging.utils import canonicalize_name -import tomli from licensecheck.session import session from licensecheck.types import ucstr @@ -20,7 +20,6 @@ def get_reqs( requirementsPaths: list[Path], pyproject: dict[str, Any], ) -> set[ucstr]: - using = "[unknown]" # determine using based on file type @@ -35,9 +34,13 @@ def get_reqs( except tomli.TOMLDecodeError: using = "requirements" - - return do_get_reqs(using=using, skipDependencies=skipDependencies, extras=extras, pyproject=pyproject, requirementsPaths=requirementsPaths) - + return do_get_reqs( + using=using, + skipDependencies=skipDependencies, + extras=extras, + pyproject=pyproject, + requirementsPaths=requirementsPaths, + ) def do_get_reqs( diff --git a/licensecheck/resolvers/uv.py b/licensecheck/resolvers/uv.py index 75aa06f..d89e74d 100644 --- a/licensecheck/resolvers/uv.py +++ b/licensecheck/resolvers/uv.py @@ -17,7 +17,6 @@ def get_reqs( extras: list[str], requirementsPaths: list[str], ) -> set[ucstr]: - for idx, requirement in enumerate(requirementsPaths): if not Path(requirement).exists(): msg = f"Could not find specification of requirements ({requirement})." diff --git a/tests/test_cli.py b/tests/test_cli.py index 735a95c..612a345 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,4 +1,7 @@ +from __future__ import annotations + from pathlib import Path +from typing import Any import pytest @@ -19,7 +22,14 @@ def aux_file(file: str) -> str: test_data = [ - ({"license": "MIT", "file": aux_file("test_main_tc1.txt"), "requirements_paths": ["pyproject.toml"]}, 0), + ( + { + "license": "MIT", + "file": aux_file("test_main_tc1.txt"), + "requirements_paths": ["pyproject.toml"], + }, + 0, + ), ( { "license": "BSD", @@ -44,7 +54,7 @@ def aux_file(file: str) -> str: @pytest.mark.parametrize(("args", "expected_exit_code"), test_data) -def test_main(args, expected_exit_code) -> None: +def test_main(args: dict[str, Any], expected_exit_code: int) -> None: exit_code = main(args) assert exit_code == expected_exit_code assert aux_get_text(args["file"]).replace( diff --git a/tests/test_resolvers_uv.py b/tests/test_resolvers_uv.py index a8f4502..fd9dca7 100644 --- a/tests/test_resolvers_uv.py +++ b/tests/test_resolvers_uv.py @@ -132,7 +132,7 @@ def test_issue_81() -> None: requirementsPaths = [f"{THISDIR}/data/issue_81.txt"] skipDependencies = [] with contextlib.suppress(Exception): - deps = req_uv.get_reqs(skipDependencies, extras, requirementsPaths) + _deps = req_uv.get_reqs(skipDependencies, extras, requirementsPaths) # RuntimeError: × No solution found when resolving dependencies: # ╰─▶ Because nvidia-cudnn-cu12==8.9.2.26 has no wheels with a matching # platform tag and you require nvidia-cudnn-cu12==8.9.2.26, we can From dae04139c010fb707236840402af11a3b612e382 Mon Sep 17 00:00:00 2001 From: Kieran W <41634689+FredHappyface@users.noreply.github.com> Date: Wed, 9 Oct 2024 00:53:24 +0100 Subject: [PATCH 4/5] run subset of tests not depending on env in github workflow --- .github/workflows/test-lint.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-lint.yaml b/.github/workflows/test-lint.yaml index f753a28..d9c43a7 100644 --- a/.github/workflows/test-lint.yaml +++ b/.github/workflows/test-lint.yaml @@ -39,7 +39,7 @@ jobs: run: poetry install - name: Run pytest - run: poetry run pytest + run: poetry run pytest ./tests/test_formatter.py ./tests/test_license_matrix.py ./tests/test_packageinfo.py - name: Run ruff run: poetry run ruff check --output-format=github From 0b833a3c83cd1ec305e175d5313746b96800b039 Mon Sep 17 00:00:00 2001 From: Kieran W <41634689+FredHappyface@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:03:59 +0100 Subject: [PATCH 5/5] refactor tests into ./tests and ./tests/platform_independent for gh runners / cross platform testing --- .github/workflows/test-lint.yaml | 2 +- tests/platform_independent/__init__.py | 0 tests/{ => platform_independent}/data/advanced.ansi | 0 tests/{ => platform_independent}/data/advanced.csv | 0 tests/{ => platform_independent}/data/advanced.json | 0 tests/{ => platform_independent}/data/advanced.md | 0 tests/{ => platform_independent}/data/advanced.txt | 0 .../{ => platform_independent}/data/advanced_ignore_params.json | 0 tests/{ => platform_independent}/data/advanced_ignore_params.md | 0 tests/{ => platform_independent}/data/licenseCheckLicenses.txt | 0 tests/{ => platform_independent}/data/licenses.txt | 0 tests/{ => platform_independent}/data/pypiClassifiers.txt | 0 tests/{ => platform_independent}/data/rawLicenses.txt | 0 tests/{ => platform_independent}/data/simple.ansi | 0 tests/{ => platform_independent}/data/simple.csv | 0 tests/{ => platform_independent}/data/simple.json | 0 tests/{ => platform_independent}/data/simple.md | 0 tests/{ => platform_independent}/data/simple.txt | 0 tests/{ => platform_independent}/test_formatter.py | 0 tests/{ => platform_independent}/test_license_matrix.py | 0 tests/{ => platform_independent}/test_packageinfo.py | 0 21 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 tests/platform_independent/__init__.py rename tests/{ => platform_independent}/data/advanced.ansi (100%) rename tests/{ => platform_independent}/data/advanced.csv (100%) rename tests/{ => platform_independent}/data/advanced.json (100%) rename tests/{ => platform_independent}/data/advanced.md (100%) rename tests/{ => platform_independent}/data/advanced.txt (100%) rename tests/{ => platform_independent}/data/advanced_ignore_params.json (100%) rename tests/{ => platform_independent}/data/advanced_ignore_params.md (100%) rename tests/{ => platform_independent}/data/licenseCheckLicenses.txt (100%) rename tests/{ => platform_independent}/data/licenses.txt (100%) rename tests/{ => platform_independent}/data/pypiClassifiers.txt (100%) rename tests/{ => platform_independent}/data/rawLicenses.txt (100%) rename tests/{ => platform_independent}/data/simple.ansi (100%) rename tests/{ => platform_independent}/data/simple.csv (100%) rename tests/{ => platform_independent}/data/simple.json (100%) rename tests/{ => platform_independent}/data/simple.md (100%) rename tests/{ => platform_independent}/data/simple.txt (100%) rename tests/{ => platform_independent}/test_formatter.py (100%) rename tests/{ => platform_independent}/test_license_matrix.py (100%) rename tests/{ => platform_independent}/test_packageinfo.py (100%) diff --git a/.github/workflows/test-lint.yaml b/.github/workflows/test-lint.yaml index d9c43a7..1f09bff 100644 --- a/.github/workflows/test-lint.yaml +++ b/.github/workflows/test-lint.yaml @@ -39,7 +39,7 @@ jobs: run: poetry install - name: Run pytest - run: poetry run pytest ./tests/test_formatter.py ./tests/test_license_matrix.py ./tests/test_packageinfo.py + run: poetry run pytest ./tests/platform_independent - name: Run ruff run: poetry run ruff check --output-format=github diff --git a/tests/platform_independent/__init__.py b/tests/platform_independent/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/data/advanced.ansi b/tests/platform_independent/data/advanced.ansi similarity index 100% rename from tests/data/advanced.ansi rename to tests/platform_independent/data/advanced.ansi diff --git a/tests/data/advanced.csv b/tests/platform_independent/data/advanced.csv similarity index 100% rename from tests/data/advanced.csv rename to tests/platform_independent/data/advanced.csv diff --git a/tests/data/advanced.json b/tests/platform_independent/data/advanced.json similarity index 100% rename from tests/data/advanced.json rename to tests/platform_independent/data/advanced.json diff --git a/tests/data/advanced.md b/tests/platform_independent/data/advanced.md similarity index 100% rename from tests/data/advanced.md rename to tests/platform_independent/data/advanced.md diff --git a/tests/data/advanced.txt b/tests/platform_independent/data/advanced.txt similarity index 100% rename from tests/data/advanced.txt rename to tests/platform_independent/data/advanced.txt diff --git a/tests/data/advanced_ignore_params.json b/tests/platform_independent/data/advanced_ignore_params.json similarity index 100% rename from tests/data/advanced_ignore_params.json rename to tests/platform_independent/data/advanced_ignore_params.json diff --git a/tests/data/advanced_ignore_params.md b/tests/platform_independent/data/advanced_ignore_params.md similarity index 100% rename from tests/data/advanced_ignore_params.md rename to tests/platform_independent/data/advanced_ignore_params.md diff --git a/tests/data/licenseCheckLicenses.txt b/tests/platform_independent/data/licenseCheckLicenses.txt similarity index 100% rename from tests/data/licenseCheckLicenses.txt rename to tests/platform_independent/data/licenseCheckLicenses.txt diff --git a/tests/data/licenses.txt b/tests/platform_independent/data/licenses.txt similarity index 100% rename from tests/data/licenses.txt rename to tests/platform_independent/data/licenses.txt diff --git a/tests/data/pypiClassifiers.txt b/tests/platform_independent/data/pypiClassifiers.txt similarity index 100% rename from tests/data/pypiClassifiers.txt rename to tests/platform_independent/data/pypiClassifiers.txt diff --git a/tests/data/rawLicenses.txt b/tests/platform_independent/data/rawLicenses.txt similarity index 100% rename from tests/data/rawLicenses.txt rename to tests/platform_independent/data/rawLicenses.txt diff --git a/tests/data/simple.ansi b/tests/platform_independent/data/simple.ansi similarity index 100% rename from tests/data/simple.ansi rename to tests/platform_independent/data/simple.ansi diff --git a/tests/data/simple.csv b/tests/platform_independent/data/simple.csv similarity index 100% rename from tests/data/simple.csv rename to tests/platform_independent/data/simple.csv diff --git a/tests/data/simple.json b/tests/platform_independent/data/simple.json similarity index 100% rename from tests/data/simple.json rename to tests/platform_independent/data/simple.json diff --git a/tests/data/simple.md b/tests/platform_independent/data/simple.md similarity index 100% rename from tests/data/simple.md rename to tests/platform_independent/data/simple.md diff --git a/tests/data/simple.txt b/tests/platform_independent/data/simple.txt similarity index 100% rename from tests/data/simple.txt rename to tests/platform_independent/data/simple.txt diff --git a/tests/test_formatter.py b/tests/platform_independent/test_formatter.py similarity index 100% rename from tests/test_formatter.py rename to tests/platform_independent/test_formatter.py diff --git a/tests/test_license_matrix.py b/tests/platform_independent/test_license_matrix.py similarity index 100% rename from tests/test_license_matrix.py rename to tests/platform_independent/test_license_matrix.py diff --git a/tests/test_packageinfo.py b/tests/platform_independent/test_packageinfo.py similarity index 100% rename from tests/test_packageinfo.py rename to tests/platform_independent/test_packageinfo.py