diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b2248ccc..8274815a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,10 +2,20 @@ Changelog ========= + +v0.9.8 +------------- + +- Improve command line options output in the JSON output header. Add missing + options. + + + + v0.9.7 ------------- -- Fix resolution of setup files which partially have dynamic dependencies. +- Fix resolution of setup files that have partially dynamic dependencies. v0.9.6 diff --git a/src/python_inspector/api.py b/src/python_inspector/api.py index 1f9e0d46..ae1e572e 100644 --- a/src/python_inspector/api.py +++ b/src/python_inspector/api.py @@ -36,7 +36,7 @@ from python_inspector.resolution import format_resolution from python_inspector.resolution import get_environment_marker_from_environment from python_inspector.resolution import get_package_list -from python_inspector.resolution import get_python_version_from_env_tag +from python_inspector.resolution import get_python_dot_version_from_env_tag from python_inspector.resolution import get_reqs_insecurely from python_inspector.resolution import get_requirements_from_python_manifest from python_inspector.utils_pypi import PLATFORMS_BY_OS @@ -168,11 +168,11 @@ def resolve_dependencies( # validate if python require matches our current python version python_requires = package_data.extra_data.get("python_requires") if not utils_pypi.valid_python_version( - python_version=get_python_version_from_env_tag(python_version), + python_version=get_python_dot_version_from_env_tag(python_version), python_requires=python_requires, ): raise Exception( - f"Python version {get_python_version_from_env_tag(python_version)} " + f"Python version {get_python_dot_version_from_env_tag(python_version)} " f"is not compatible with setup.py {setup_py_file} " f"python_requires {python_requires}", ) diff --git a/src/python_inspector/dependencies.py b/src/python_inspector/dependencies.py index bfb060f7..4f557689 100644 --- a/src/python_inspector/dependencies.py +++ b/src/python_inspector/dependencies.py @@ -11,7 +11,6 @@ from packageurl import PackageURL from packvers.requirements import Requirement -from pip_requirements_parser import InstallRequirement from _packagedcode import models from _packagedcode.pypi import PipRequirementsFileHandler diff --git a/src/python_inspector/package_data.py b/src/python_inspector/package_data.py index 023b5159..6d0c045a 100644 --- a/src/python_inspector/package_data.py +++ b/src/python_inspector/package_data.py @@ -19,7 +19,7 @@ from _packagedcode.pypi import get_keywords from _packagedcode.pypi import get_parties from python_inspector import utils_pypi -from python_inspector.resolution import get_python_version_from_env_tag +from python_inspector.resolution import get_python_dot_version_from_env_tag from python_inspector.utils_pypi import Environment from python_inspector.utils_pypi import PypiSimpleRepository @@ -53,7 +53,7 @@ def get_pypi_data_from_purl( project_urls = info.get("project_urls") or {} code_view_url = get_pypi_codeview_url(project_urls) bug_tracking_url = get_pypi_bugtracker_url(project_urls) - python_version = get_python_version_from_env_tag(python_version=environment.python_version) + python_version = get_python_dot_version_from_env_tag(python_version=environment.python_version) valid_distribution_urls = [] valid_distribution_urls.append( diff --git a/src/python_inspector/resolution.py b/src/python_inspector/resolution.py index e9e520ed..77496c51 100644 --- a/src/python_inspector/resolution.py +++ b/src/python_inspector/resolution.py @@ -10,7 +10,6 @@ import ast import operator import os -import re import tarfile from typing import Dict from typing import Generator @@ -111,7 +110,7 @@ def get_deps_from_distribution( def get_environment_marker_from_environment(environment): return { "extra": "", - "python_version": get_python_version_from_env_tag( + "python_version": get_python_dot_version_from_env_tag( python_version=environment.python_version ), "platform_system": environment.operating_system.capitalize(), @@ -135,6 +134,7 @@ def parse_deps_from_setup_py_insecurely(setup_py): """ if not os.path.exists(setup_py): return [] + for req in iter_requirements(level="", extras=[], setup_file=setup_py): parsed_req = Requirement(req) yield DependentPackage( @@ -168,10 +168,10 @@ def is_valid_version( return True -def get_python_version_from_env_tag(python_version: str) -> str: +def get_python_dot_version_from_env_tag(python_version: str) -> str: """ - >>> assert get_python_version_from_env_tag("310") == "3.10" - >>> assert get_python_version_from_env_tag("39") == "3.9" + >>> assert get_python_dot_version_from_env_tag("310") == "3.10" + >>> assert get_python_dot_version_from_env_tag("39") == "3.9" """ elements = list(python_version) elements.insert(1, ".") @@ -183,46 +183,50 @@ def fetch_and_extract_sdist( repos: List[PypiSimpleRepository], candidate: Candidate, python_version: str ) -> Union[str, None]: """ - Fetch and extract the source distribution (sdist) for the ``candidate`` Candidate - from the `repos` list of PyPiRepository - and a required ``python_version`` Python version. - Return the directory location string where the sdist has been extracted. - Return None if the sdist was not fetched either - because does not exist in any of the ``repos`` or it does not work with - the required ``python_version``. + Fetch and extract the source distribution (sdist_filename) for the ``candidate`` + Candidate from the ``repos`` list of PyPiRepository and a required + ``python_version`` Python version. + + Return the directory location string where the sdist_filename has been extracted. + + Return None if the sdist_filename was not fetched either because does not exist in + any of the ``repos`` or it does not work with the required ``python_version``. + Raise an Exception if extraction fails. """ - sdist = utils_pypi.download_sdist( + sdist_filename = utils_pypi.download_sdist( name=candidate.name, version=str(candidate.version), repos=repos, python_version=python_version, ) - if not sdist: + if not sdist_filename: return - return get_sdist_file_path_from_filename(sdist) + return get_sdist_file_path_from_filename(sdist_filename) -def get_sdist_file_path_from_filename(sdist): - if sdist.endswith(".tar.gz"): - sdist_file = sdist.rstrip(".tar.gz") - with tarfile.open(os.path.join(utils_pypi.CACHE_THIRDPARTY_DIR, sdist)) as file: - file.extractall( - os.path.join(utils_pypi.CACHE_THIRDPARTY_DIR, "extracted_sdists", sdist_file) - ) - elif sdist.endswith(".zip"): - sdist_file = sdist.rstrip(".zip") - with ZipFile(os.path.join(utils_pypi.CACHE_THIRDPARTY_DIR, sdist)) as zip: - zip.extractall( - os.path.join(utils_pypi.CACHE_THIRDPARTY_DIR, "extracted_sdists", sdist_file) - ) +def get_sdist_file_path_from_filename(sdist_filename): + """ + Extract the ``sdist_filename`` tarball and return the directory where it is extracted. + """ + base_dir = os.path.join(utils_pypi.CACHE_THIRDPARTY_DIR, "extracted_sdists") + + if sdist_filename.endswith(".tar.gz"): + sdist_file, _, _ = sdist_filename.rpartition(".tar.gz") + with tarfile.open(os.path.join(utils_pypi.CACHE_THIRDPARTY_DIR, sdist_filename)) as tarball: + tarball.extractall(os.path.join(base_dir, sdist_file)) + + elif sdist_filename.endswith(".zip"): + sdist_file, _, _ = sdist_filename.rpartition(".zip") + with ZipFile(os.path.join(utils_pypi.CACHE_THIRDPARTY_DIR, sdist_filename)) as zipped: + zipped.extractall(os.path.join(base_dir, sdist_file)) else: - raise Exception(f"Unable to extract sdist {sdist}") + raise Exception(f"Unable to extract sdist_filename {sdist_filename}") - return os.path.join(utils_pypi.CACHE_THIRDPARTY_DIR, "extracted_sdists", sdist_file, sdist_file) + return os.path.join(base_dir, sdist_file, sdist_file) def get_requirements_from_dependencies( @@ -403,7 +407,7 @@ def get_versions_for_package_from_repo( versions = [] for version, package in repo.get_package_versions(name).items(): python_version = parse_version( - get_python_version_from_env_tag(python_version=self.environment.python_version) + get_python_dot_version_from_env_tag(python_version=self.environment.python_version) ) wheels = list(package.get_supported_wheels(environment=self.environment)) valid_wheel_present = False @@ -454,7 +458,7 @@ def get_requirements_for_package_from_pypi_simple( Return requirements for a package from the simple repositories. """ python_version = parse_version( - get_python_version_from_env_tag(python_version=self.environment.python_version) + get_python_dot_version_from_env_tag(python_version=self.environment.python_version) ) wheels = utils_pypi.download_wheel( @@ -508,7 +512,7 @@ def get_requirements_for_package_from_pypi_simple( if requirements: yield from requirements else: - # Look in requirements file if and only if thy are refered in setup.py or setup.cfg + # Look in requirements file if and only if they are refered in setup.py or setup.cfg # And no deps have been yielded by requirements file yield from get_requirements_from_python_manifest( diff --git a/src/python_inspector/resolve_cli.py b/src/python_inspector/resolve_cli.py index 12416961..3acbb881 100644 --- a/src/python_inspector/resolve_cli.py +++ b/src/python_inspector/resolve_cli.py @@ -74,7 +74,7 @@ def print_version(ctx, param, value): metavar="PYVER", show_default=True, required=True, - help="Python version to use for dependency resolution.", + help="Python version to use for dependency resolution as in 3.8 or 3.11.2", ) @click.option( "-o", @@ -104,7 +104,7 @@ def print_version(ctx, param, value): required=False, metavar="FILE", help="Write output as pretty-printed JSON to FILE. " - "Use the special '-' file name to print results on screen/stdout.", + "Use the special '-' file name to print results on screen to stdout.", ) @click.option( "--json-pdt", @@ -115,6 +115,7 @@ def print_version(ctx, param, value): help="Write output as pretty-printed JSON to FILE as a tree in the style of pipdeptree. " "Use the special '-' file name to print results on screen/stdout.", ) +# Special hidden option @click.option( "-n", "--netrc", @@ -123,16 +124,18 @@ def print_version(ctx, param, value): metavar="NETRC-FILE", hidden=True, required=False, - help="Netrc file to use for authentication. ", + help="Netrc file to use for authentication.", ) +# Special hidden option @click.option( "--max-rounds", "max_rounds", hidden=True, type=int, default=200000, - help="Increase the max rounds whenever the resolution is too deep", + help="Increase the max number of resolution rounds when the package tree is too complex.", ) +# Special hidden option @click.option( "--use-cached-index", is_flag=True, @@ -148,14 +151,14 @@ def print_version(ctx, param, value): @click.option( "--analyze-setup-py-insecurely", is_flag=True, - help="Enable collection of requirements in setup.py that compute these" - " dynamically. This is an insecure operation as it can run arbitrary code.", + help="Enable collection of requirements in setup.py that compute these " + "dynamically. This is an insecure operation as it can run arbitrary code.", ) @click.option( "--prefer-source", is_flag=True, - help="Prefer source distributions over binary distributions" - " if no source distribution is available then binary distributions are used", + help="Prefer source distributions over binary distributions " + "if no source distribution is available then binary distributions are used", ) @click.option( "--verbose", @@ -220,12 +223,28 @@ def resolve_dependencies( click.secho("Only one of --json or --json-pdt can be used.", err=True) ctx.exit(1) - options = [f"--requirement {rf}" for rf in requirement_files] - options += [f"--specifier {sp}" for sp in specifiers] - options += [f"--index-url {iu}" for iu in index_urls] - options += [f"--python-version {python_version}"] - options += [f"--operating-system {operating_system}"] - options += ["--json "] + options = [] + options.extend(f"--requirement {rf}" for rf in requirement_files) + if setup_py_file: + options.append(f"--setup-py {setup_py_file}") + + options.extend(f"--specifier {sp}" for sp in specifiers) + options.extend(f"--index-url {iu}" for iu in index_urls) + options.append(f"--python-version {python_version}") + options.append(f"--operating-system {operating_system}") + + if analyze_setup_py_insecurely: + options.append(f"--analyze-setup-py-insecurely") + if prefer_source: + options.append(f"--prefer-source") + if use_pypi_json_api: + options.append(f"--use-pypi-json-api") + if netrc_file: + options.append(f"--netrc {netrc_file}") + if json_output: + options.append("--json ") + if pdt_output: + options.append("--json-pdt ") notice = ( "Dependency tree generated with python-inspector.\n" @@ -271,7 +290,7 @@ def resolve_dependencies( output=output, location=json_output or pdt_output, ) - except Exception as exc: + except Exception: import traceback click.secho(traceback.format_exc(), err=True) diff --git a/src/python_inspector/setup_py_live_eval.py b/src/python_inspector/setup_py_live_eval.py index 7ba51c52..82bf8128 100755 --- a/src/python_inspector/setup_py_live_eval.py +++ b/src/python_inspector/setup_py_live_eval.py @@ -1,204 +1,232 @@ # -*- coding: utf-8 -*- # # This file is part of Requirements-Builder +# Further modified for python-inspector by nexB Inc. # Copyright (C) 2015, 2016, 2017, 2018 CERN. # # Requirements-Builder is free software; you can redistribute it and/or -# modify it under the terms of the Revised BSD License; see LICENSE -# file for more details. +# modify it under the terms of the Revised BSD License; +# see setup_py_live_eval.py.LICENSE file for more details. # -"""Generate requirements from `setup.py` and `requirements-devel.txt`.""" + +""" +Collect requirements from a setup.py file, by doing a live evaluation using AST +parsing and mocking. +""" import ast import os import sys -try: - import configparser -except ImportError: # pragma: no cover - import ConfigParser as configparser - -import distutils.core - import mock -import setuptools from commoncode.command import pushd from packvers.requirements import Requirement +################################################################################ +# The order of these imports matters +try: + import setuptools -def minver_error(pkg_name): - """Report error about missing minimum version constraint and exit.""" - print( - 'ERROR: specify minimal version of "{0}" using ' '">=" or "=="'.format(pkg_name), - file=sys.stderr, - ) - sys.exit(1) + setuptools_name = setuptools.__name__ +except ImportError: + setuptools_name = "setuptools" + +try: + import distutils.core + + distutils_core_name = distutils.core.__name__ +except ImportError: + distutils_core_name = "distutils.core" +################################################################################ def build_pkg_name(pkg): - """Build package name, including extras if present.""" + """ + Return a package name from a ``pkg`` package including extras if present. + """ if pkg.extras: - return "{0}[{1}]".format(str(pkg.name), ",".join(sorted(pkg.extras))) + extras = ",".join(sorted(pkg.extras)) + return f"{pkg.name}[{extras}]" return str(pkg.name) -def iter_requirements(level, extras, setup_file): - """Iterate over requirements.""" +def iter_requirements(level, extras, setup_file, echo=print): + """ + Iterate over setup.py requirements and yield requirement strings. + """ from pathlib import Path setup_file = str(Path(setup_file).absolute()) - result = dict() - requires = [] - stuff = [] + requirement_by_package_name = {} + install_requires = [] requires_extras = {} test_requires = {} setup_requires = {} + # change directory to setup.py path with pushd(os.path.dirname(setup_file)): with open(setup_file) as sf: file_contents = sf.read() - node = ast.parse(file_contents) - asnames = {} - imports = [] - for elem in ast.walk(node): - # save the asnames to parse aliases later - if isinstance(elem, ast.Import): - for n in elem.names: - asnames[(n.asname if n.asname is not None else n.name)] = n.name - for elem in ast.walk(node): - # for function imports, e.g. from setuptools import setup; setup() - if isinstance(elem, ast.ImportFrom) and "setup" in [e.name for e in elem.names]: - imports.append(elem.module) + + node = ast.parse(file_contents) + asnames = {} + imports = [] + + for elem in ast.walk(node): + # save the asnames to parse aliases later + if isinstance(elem, ast.Import): + for n in elem.names: + asnames[(n.asname if n.asname is not None else n.name)] = n.name + + for elem in ast.walk(node): + # for function imports, e.g. from setuptools import setup; setup() + if isinstance(elem, ast.ImportFrom) and "setup" in [e.name for e in elem.names]: + imports.append(elem.module) + + elif ( + isinstance(elem, ast.Expr) + and isinstance(elem.value, ast.Call) + and isinstance(elem.value.func, ast.Attribute) + and elem.value.func.attr == "setup" + ): + # for module imports, e.g. import setuptools; setuptools.setup(...) - elif ( - isinstance(elem, ast.Expr) - and isinstance(elem.value, ast.Call) - and isinstance(elem.value.func, ast.Attribute) - and isinstance(elem.value.func.value, ast.Name) - and elem.value.func.attr == "setup" - ): + if isinstance(elem.value.func.value, ast.Name): name = elem.value.func.value.id - if name in asnames.keys(): - name = asnames[name] - imports.append(name) - # for module imports, e.g. import disttools.core; disttools.core.setup(...) - elif ( - isinstance(elem, ast.Expr) - and isinstance(elem.value, ast.Call) - and isinstance(elem.value.func, ast.Attribute) - and isinstance(elem.value.func.value, ast.Attribute) - and elem.value.func.attr == "setup" - ): - name = ( - str(elem.value.func.value.value.id) + "." + str(elem.value.func.value.attr) - ) - if name in asnames.keys(): - name = asnames[name] - imports.append(name) - setup_providers = [i for i in imports if i in ["distutils.core", "setuptools"]] - if len(setup_providers) == 0: - print( - f"Warning: unable to recognize setup provider in {setup_file}: " - "defaulting to 'distutils.core'." - ) - setup_provider = "distutils.core" - elif len(setup_providers) == 1: - setup_provider = setup_providers[0] - else: - print( - f"Warning: ambiguous setup provider in {setup_file}: candidates are {setup_providers}" - "defaulting to 'distutils.core'." - ) - setup_provider = "distutils.core" - with mock.patch.object(eval(setup_provider), "setup") as mock_setup: - sys.path.append(os.path.dirname(setup_file)) - g = {"__file__": setup_file, "__name__": "__main__"} - exec(file_contents, g) + + # for module imports, e.g. import distutils.core; distutils.core.setup(...) + elif isinstance(elem.value.func.value, ast.Attribute): + name = f"{elem.value.func.value.value.id}.{elem.value.func.value.attr}" + + if name in asnames: + name = asnames[name] + imports.append(name) + + setup_providers = [i for i in imports if i in [distutils_core_name, setuptools_name]] + if not setup_providers: + echo( + f"Warning: unable to recognize setup provider in {setup_file}: " + "defaulting to 'distutils.core'." + ) + setup_provider = distutils_core_name + + elif len(setup_providers) == 1: + setup_provider = setup_providers[0] + + else: + echo( + f"Warning: ambiguous setup provider in {setup_file}: candidates are {setup_providers}" + "defaulting to 'distutils.core'." + ) + setup_provider = distutils_core_name + + try: + sys.path.append(os.path.dirname(setup_file)) + + with mock.patch.object(eval(setup_provider), "setup") as mock_setup: # NOQA + mock_globals = {"__file__": setup_file, "__name__": "__main__"} + exec(file_contents, mock_globals) + finally: sys.path.pop() - # removing the assertion `assert g["setup"]`` since this is not true for all cases - # for example when setuptools.setup() is called instead of setup() - mock_args, mock_kwargs = mock_setup.call_args + _mock_args, mock_kwargs = mock_setup.call_args install_requires = mock_kwargs.get("install_requires", install_requires) requires_extras = mock_kwargs.get("extras_require", requires_extras) test_requires = mock_kwargs.get("test_requires", test_requires) setup_requires = mock_kwargs.get("setup_requires", setup_requires) + # FIXME: these do make any sense: we should add a test or setup extra to the install_requires instead + # but test and setup requires are legacy for e, reqs in requires_extras.items(): # Handle conditions on extras. See pkginfo_to_metadata function # in Wheel for details. condition = "" if ":" in e: - e, condition = e.split(":", 1) + e, _, condition = e.partition(":") if not e or e in extras: if condition: - reqs = ["{0}; {1}".format(r, condition) for r in reqs] + reqs = [f"{rq}; {condition}" for rq in reqs] install_requires.extend(reqs) - for reqs in test_requires: - if "test" in extras: + # FIXME: these do not make any sense: we should add a test or setup extra to + # the install_requires instead + # but test and setup requires are legacy + if "test" in extras: + for reqs in test_requires: install_requires.extend(reqs) - for reqs in setup_requires: - if "setup" in extras: + if "setup" in extras: + for reqs in setup_requires: install_requires.extend(reqs) for req in install_requires: # skip things we already know # FIXME be smarter about merging things - pkg = Requirement(req) + + requirement = Requirement(req) + # Evaluate environment markers skip if not applicable - if hasattr(pkg, "marker") and pkg.marker is not None: - if not pkg.marker.evaluate(): + if hasattr(requirement, "marker") and requirement.marker is not None: + # FIXME: we should pass a proepr environment to evaluate markers!!! + if not requirement.marker.evaluate(): continue else: # Remove markers from the output - pkg.marker = None + requirement.marker = None - if pkg.name in result: + if requirement.name in requirement_by_package_name: continue - specs = pkg.specifier - specs = {s.operator: s.version for s in specs._specs} - if ((">=" in specs) and (">" in specs)) or (("<=" in specs) and ("<" in specs)): - print( - "ERROR: Do not specify such weird constraints! " '("{0}")'.format(pkg), - file=sys.stderr, - ) - sys.exit(1) + pkg_name = build_pkg_name(requirement) - if "==" in specs: - result[pkg.name] = "{0}=={1}".format(build_pkg_name(pkg), specs["=="]) + specifier = requirement.specifier + comparators = {s.operator: s.version for s in specifier._specs} - elif ">=" in specs: + if (">=" in comparators and ">" in comparators) or ( + "<=" in comparators and "<" in comparators + ): + raise Exception(f'ERROR: Inconsistent comparators! ("{requirement}")') + + if "==" in comparators: + comp = comparators["=="] + req_string = f"{pkg_name}=={comp}" + + elif ">=" in comparators: if level == "min": - result[pkg.name] = "{0}=={1}".format(build_pkg_name(pkg), specs[">="]) + comp = comparators[">="] + req_string = f"{pkg_name}=={comp}" else: - result[pkg.name] = pkg + req_string = requirement - elif ">" in specs: + elif "~=" in comparators: + comp = comparators["~="] if level == "min": - minver_error(build_pkg_name(pkg)) + req_string = f"{pkg_name}=={comp}" else: - result[pkg.name] = pkg + ver, _ = os.path.splitext(comp) + req_string = f"{pkg_name}>={comp},=={ver}.*" - elif "~=" in specs: + elif ">" in comparators: if level == "min": - result[pkg.name] = "{0}=={1}".format(build_pkg_name(pkg), specs["~="]) + raise Exception( + f"ERROR: specify minimal version of {build_pkg_name(requirement)!r} " + 'using comparators such as ">=" or "=="' + ) else: - ver, _ = os.path.splitext(specs["~="]) - result[pkg.name] = "{0}>={1},=={2}.*".format(build_pkg_name(pkg), specs["~="], ver) + req_string = requirement else: if level == "min": - minver_error(build_pkg_name(pkg)) + raise Exception( + f"ERROR: specify minimal version of {pkg_name!r} " + 'using comparators such as ">=" or "=="' + ) else: - result[pkg.name] = build_pkg_name(pkg) + req_string = pkg_name - for s in stuff: - yield s + requirement_by_package_name[requirement.name] = req_string - for k in sorted(result.keys()): - yield str(result[k]) + for _key, value in sorted(requirement_by_package_name.items()): + yield str(value) diff --git a/src/python_inspector/utils_pypi.py b/src/python_inspector/utils_pypi.py index df14920f..43e3ffe9 100644 --- a/src/python_inspector/utils_pypi.py +++ b/src/python_inspector/utils_pypi.py @@ -102,12 +102,12 @@ PYTHON_VERSIONS = "36", "37", "38", "39", "310", "311", "27" PYTHON_DOT_VERSIONS_BY_VER = { + "27": "2.7", "36": "3.6", "37": "3.7", "38": "3.8", "39": "3.9", "310": "3.10", - "27": "2.7", "311": "3.11", } @@ -123,13 +123,13 @@ def get_python_dot_version(version): ABIS_BY_PYTHON_VERSION = { + "27": ["cp27", "cp27m"], "36": ["cp36", "cp36m", "abi3"], "37": ["cp37", "cp37m", "abi3"], "38": ["cp38", "cp38m", "abi3"], "39": ["cp39", "cp39m", "abi3"], "310": ["cp310", "cp310m", "abi3"], "311": ["cp311", "cp311m", "abi3"], - "27": ["cp27", "cp27m"], } PLATFORMS_BY_OS = { @@ -137,7 +137,9 @@ def get_python_dot_version(version): "linux_x86_64", "manylinux1_x86_64", "manylinux2010_x86_64", - "manylinux2014_x86_64", + "manylinux_2014_x86_64", + # TODO add https://peps.python.org/pep-0600/ + # "manylinux_2_17", ], "macos": [ "macosx_10_6_intel", @@ -261,6 +263,9 @@ def download_wheel( def get_valid_sdist(repo, name, version, python_version=DEFAULT_PYTHON_VERSION): + """ + Return an Sdist or None. + """ package = repo.get_package_version(name=name, version=version) if not package: if TRACE_DEEP: @@ -337,7 +342,8 @@ def download_sdist( ): """ Download the sdist source distribution of package ``name`` and ``version`` - into the ``dest_dir`` directory. Return a fetched filename or None. + into the ``dest_dir`` directory. Return the filename fetched and stored in + ``dest_dir`` or None. Use the first PyPI simple repository from a list of ``repos`` that contains this sdist. diff --git a/tests/data/azure-devops.req-310-expected.json b/tests/data/azure-devops.req-310-expected.json index f978e1da..c8c34fc8 100644 --- a/tests/data/azure-devops.req-310-expected.json +++ b/tests/data/azure-devops.req-310-expected.json @@ -4,7 +4,7 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ - "--requirement /home/tg1999/Desktop/python-inspector-1/tests/data/azure-devops.req.txt", + "--requirement tests/data/azure-devops.req.txt", "--index-url https://pypi.org/simple", "--python-version 310", "--operating-system linux", @@ -17,7 +17,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/azure-devops.req.txt", + "path": "tests/data/azure-devops.req.txt", "package_data": [ { "type": "pypi", diff --git a/tests/data/azure-devops.req-38-expected.json b/tests/data/azure-devops.req-38-expected.json index d4773189..c5bff2ec 100644 --- a/tests/data/azure-devops.req-38-expected.json +++ b/tests/data/azure-devops.req-38-expected.json @@ -4,7 +4,7 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ - "--requirement /home/tg1999/Desktop/python-inspector-1/tests/data/azure-devops.req.txt", + "--requirement tests/data/azure-devops.req.txt", "--index-url https://pypi.org/simple", "--python-version 38", "--operating-system linux", @@ -17,7 +17,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/azure-devops.req.txt", + "path": "tests/data/azure-devops.req.txt", "package_data": [ { "type": "pypi", diff --git a/tests/data/default-url-expected.json b/tests/data/default-url-expected.json index 28f3dbcd..4f503cb8 100644 --- a/tests/data/default-url-expected.json +++ b/tests/data/default-url-expected.json @@ -8,6 +8,7 @@ "--index-url https://pypi.org/simple", "--python-version 38", "--operating-system linux", + "--use-pypi-json-api", "--json " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", diff --git a/tests/data/environment-marker-test-requirements.txt-expected.json b/tests/data/environment-marker-test-requirements.txt-expected.json index 746d60d6..64e21580 100644 --- a/tests/data/environment-marker-test-requirements.txt-expected.json +++ b/tests/data/environment-marker-test-requirements.txt-expected.json @@ -4,11 +4,11 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ - "--requirement /home/tg1999/Desktop/python-inspector-1/tests/data/environment-marker-test-requirements.txt", + "--requirement tests/data/environment-marker-test-requirements.txt", "--index-url https://pypi.org/simple", "--python-version 37", "--operating-system linux", - "--json " + "--json-pdt " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", "warnings": [], @@ -17,7 +17,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/environment-marker-test-requirements.txt", + "path": "tests/data/environment-marker-test-requirements.txt", "package_data": [ { "type": "pypi", diff --git a/tests/data/frozen-requirements.txt-expected.json b/tests/data/frozen-requirements.txt-expected.json index 03f50f95..2a7d3678 100644 --- a/tests/data/frozen-requirements.txt-expected.json +++ b/tests/data/frozen-requirements.txt-expected.json @@ -4,11 +4,11 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ - "--requirement /home/tg1999/Desktop/python-inspector-1/tests/data/frozen-requirements.txt", + "--requirement tests/data/frozen-requirements.txt", "--index-url https://pypi.org/simple", "--python-version 38", "--operating-system linux", - "--json " + "--json-pdt " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", "warnings": [], @@ -17,7 +17,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/frozen-requirements.txt", + "path": "tests/data/frozen-requirements.txt", "package_data": [ { "type": "pypi", @@ -5992,12 +5992,12 @@ "type": "pypi", "namespace": null, "name": "pip", - "version": "23.0.1", + "version": "23.1", "qualifiers": {}, "subpath": null, "primary_language": "Python", "description": "The PyPA recommended tool for installing Python packages.\npip - The Python Package Installer\n==================================\n\n.. image:: https://img.shields.io/pypi/v/pip.svg\n :target: https://pypi.org/project/pip/\n\n.. image:: https://readthedocs.org/projects/pip/badge/?version=latest\n :target: https://pip.pypa.io/en/latest\n\npip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.\n\nPlease take a look at our documentation for how to install and use pip:\n\n* `Installation`_\n* `Usage`_\n\nWe release updates regularly, with a new version every 3 months. Find more details in our documentation:\n\n* `Release notes`_\n* `Release process`_\n\nIn pip 20.3, we've `made a big improvement to the heart of pip`_; `learn more`_. We want your input, so `sign up for our user experience research studies`_ to help us do it right.\n\n**Note**: pip 21.0, in January 2021, removed Python 2 support, per pip's `Python 2 support policy`_. Please migrate to Python 3.\n\nIf you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:\n\n* `Issue tracking`_\n* `Discourse channel`_\n* `User IRC`_\n\nIf you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:\n\n* `GitHub page`_\n* `Development documentation`_\n* `Development IRC`_\n\nCode of Conduct\n---------------\n\nEveryone interacting in the pip project's codebases, issue trackers, chat\nrooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.\n\n.. _package installer: https://packaging.python.org/guides/tool-recommendations/\n.. _Python Package Index: https://pypi.org\n.. _Installation: https://pip.pypa.io/en/stable/installation/\n.. _Usage: https://pip.pypa.io/en/stable/\n.. _Release notes: https://pip.pypa.io/en/stable/news.html\n.. _Release process: https://pip.pypa.io/en/latest/development/release-process/\n.. _GitHub page: https://github.com/pypa/pip\n.. _Development documentation: https://pip.pypa.io/en/latest/development\n.. _made a big improvement to the heart of pip: https://pyfound.blogspot.com/2020/11/pip-20-3-new-resolver.html\n.. _learn more: https://pip.pypa.io/en/latest/user_guide/#changes-to-the-pip-dependency-resolver-in-20-3-2020\n.. _sign up for our user experience research studies: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-roll-out-this-year.html\n.. _Python 2 support policy: https://pip.pypa.io/en/latest/development/release-process/#python-2-support\n.. _Issue tracking: https://github.com/pypa/pip/issues\n.. _Discourse channel: https://discuss.python.org/c/packaging\n.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa\n.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev\n.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md", - "release_date": "2023-02-17T18:31:51", + "release_date": "2023-04-15T10:52:52", "parties": [ { "type": "person", @@ -6023,11 +6023,11 @@ "Topic :: Software Development :: Build Tools" ], "homepage_url": "https://pip.pypa.io/", - "download_url": "https://files.pythonhosted.org/packages/07/51/2c0959c5adf988c44d9e1e0d940f5b074516ecc87e96b1af25f59de9ba38/pip-23.0.1-py3-none-any.whl", - "size": 2055563, + "download_url": "https://files.pythonhosted.org/packages/ae/db/a8821cdac455a1740580c92de3ed7b7f257cfdbad8b1ba8864e6abe58a08/pip-23.1-py3-none-any.whl", + "size": 2064542, "sha1": null, - "md5": "83b53b599a1644afe7e76debe4a62bcc", - "sha256": "236bcb61156d76c4b8a05821b988c7b8c35bf0da28a4b614e8d6ab5212c25c6f", + "md5": "dea8a29f0029b31db3325078023bfaaf", + "sha256": "64b1d4528e491aa835ec6ece0c1ac40ce6ab6d886e60740f6519db44b2e9634d", "sha512": null, "bug_tracking_url": null, "code_view_url": "https://github.com/pypa/pip", @@ -6047,20 +6047,20 @@ "dependencies": [], "repository_homepage_url": null, "repository_download_url": null, - "api_data_url": "https://pypi.org/pypi/pip/23.0.1/json", + "api_data_url": "https://pypi.org/pypi/pip/23.1/json", "datasource_id": null, - "purl": "pkg:pypi/pip@23.0.1" + "purl": "pkg:pypi/pip@23.1" }, { "type": "pypi", "namespace": null, "name": "pip", - "version": "23.0.1", + "version": "23.1", "qualifiers": {}, "subpath": null, "primary_language": "Python", "description": "The PyPA recommended tool for installing Python packages.\npip - The Python Package Installer\n==================================\n\n.. image:: https://img.shields.io/pypi/v/pip.svg\n :target: https://pypi.org/project/pip/\n\n.. image:: https://readthedocs.org/projects/pip/badge/?version=latest\n :target: https://pip.pypa.io/en/latest\n\npip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.\n\nPlease take a look at our documentation for how to install and use pip:\n\n* `Installation`_\n* `Usage`_\n\nWe release updates regularly, with a new version every 3 months. Find more details in our documentation:\n\n* `Release notes`_\n* `Release process`_\n\nIn pip 20.3, we've `made a big improvement to the heart of pip`_; `learn more`_. We want your input, so `sign up for our user experience research studies`_ to help us do it right.\n\n**Note**: pip 21.0, in January 2021, removed Python 2 support, per pip's `Python 2 support policy`_. Please migrate to Python 3.\n\nIf you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:\n\n* `Issue tracking`_\n* `Discourse channel`_\n* `User IRC`_\n\nIf you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:\n\n* `GitHub page`_\n* `Development documentation`_\n* `Development IRC`_\n\nCode of Conduct\n---------------\n\nEveryone interacting in the pip project's codebases, issue trackers, chat\nrooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.\n\n.. _package installer: https://packaging.python.org/guides/tool-recommendations/\n.. _Python Package Index: https://pypi.org\n.. _Installation: https://pip.pypa.io/en/stable/installation/\n.. _Usage: https://pip.pypa.io/en/stable/\n.. _Release notes: https://pip.pypa.io/en/stable/news.html\n.. _Release process: https://pip.pypa.io/en/latest/development/release-process/\n.. _GitHub page: https://github.com/pypa/pip\n.. _Development documentation: https://pip.pypa.io/en/latest/development\n.. _made a big improvement to the heart of pip: https://pyfound.blogspot.com/2020/11/pip-20-3-new-resolver.html\n.. _learn more: https://pip.pypa.io/en/latest/user_guide/#changes-to-the-pip-dependency-resolver-in-20-3-2020\n.. _sign up for our user experience research studies: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-roll-out-this-year.html\n.. _Python 2 support policy: https://pip.pypa.io/en/latest/development/release-process/#python-2-support\n.. _Issue tracking: https://github.com/pypa/pip/issues\n.. _Discourse channel: https://discuss.python.org/c/packaging\n.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa\n.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev\n.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md", - "release_date": "2023-02-17T18:31:56", + "release_date": "2023-04-15T10:52:54", "parties": [ { "type": "person", @@ -6086,11 +6086,11 @@ "Topic :: Software Development :: Build Tools" ], "homepage_url": "https://pip.pypa.io/", - "download_url": "https://files.pythonhosted.org/packages/6b/8b/0b16094553ecc680e43ded8f920c3873b01b1da79a54274c98f08cb29fca/pip-23.0.1.tar.gz", - "size": 2082217, + "download_url": "https://files.pythonhosted.org/packages/da/bf/1bdbe62f5fbde085351693e3a8e387a59f8220932b911b1719fe65efa2d7/pip-23.1.tar.gz", + "size": 2087572, "sha1": null, - "md5": "f988022baba70f483744cc8c0e584010", - "sha256": "cd015ea1bfb0fcef59d8a286c1f8bebcb983f6317719d415dc5351efb7cd7024", + "md5": "b730fe00a3d43fa86e67472ad9d1de4d", + "sha256": "408539897ee535dbfb83a153f7bc4d620f990d8bd44a52a986efc0b4d330d34a", "sha512": null, "bug_tracking_url": null, "code_view_url": "https://github.com/pypa/pip", @@ -6110,9 +6110,9 @@ "dependencies": [], "repository_homepage_url": null, "repository_download_url": null, - "api_data_url": "https://pypi.org/pypi/pip/23.0.1/json", + "api_data_url": "https://pypi.org/pypi/pip/23.1/json", "datasource_id": null, - "purl": "pkg:pypi/pip@23.0.1" + "purl": "pkg:pypi/pip@23.1" }, { "type": "pypi", @@ -10801,7 +10801,7 @@ { "key": "pip", "package_name": "pip", - "installed_version": "23.0.1", + "installed_version": "23.1", "dependencies": [] } ] diff --git a/tests/data/insecure-setup-2/setup.py-expected.json b/tests/data/insecure-setup-2/setup.py-expected.json index 67d33d31..2923f9c5 100644 --- a/tests/data/insecure-setup-2/setup.py-expected.json +++ b/tests/data/insecure-setup-2/setup.py-expected.json @@ -4,9 +4,11 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ + "--setup-py tests/data/insecure-setup-2/setup.py", "--index-url https://pypi.org/simple", "--python-version 27", "--operating-system linux", + "--analyze-setup-py-insecurely", "--json " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", @@ -16,7 +18,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/insecure-setup-2/setup.py", + "path": "tests/data/insecure-setup-2/setup.py", "package_data": [ { "type": "pypi", diff --git a/tests/data/insecure-setup/setup.py-expected.json b/tests/data/insecure-setup/setup.py-expected.json index 2a4ea87a..b0670cdb 100644 --- a/tests/data/insecure-setup/setup.py-expected.json +++ b/tests/data/insecure-setup/setup.py-expected.json @@ -4,9 +4,11 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ + "--setup-py tests/data/insecure-setup/setup.py", "--index-url https://pypi.org/simple", "--python-version 27", "--operating-system linux", + "--analyze-setup-py-insecurely", "--json " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", @@ -16,7 +18,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/insecure-setup/setup.py", + "path": "tests/data/insecure-setup/setup.py", "package_data": [ { "type": "pypi", diff --git a/tests/data/pdt-requirements.txt-expected.json b/tests/data/pdt-requirements.txt-expected.json index 11253a80..156559c3 100644 --- a/tests/data/pdt-requirements.txt-expected.json +++ b/tests/data/pdt-requirements.txt-expected.json @@ -4,11 +4,11 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ - "--requirement /home/tg1999/Desktop/python-inspector-1/tests/data/pdt-requirements.txt", + "--requirement tests/data/pdt-requirements.txt", "--index-url https://pypi.org/simple", "--python-version 38", "--operating-system linux", - "--json " + "--json-pdt " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", "warnings": [], @@ -17,7 +17,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/pdt-requirements.txt", + "path": "tests/data/pdt-requirements.txt", "package_data": [ { "type": "pypi", diff --git a/tests/data/pinned-pdt-requirements.txt-expected.json b/tests/data/pinned-pdt-requirements.txt-expected.json index a16ec7ed..fd96cfc6 100644 --- a/tests/data/pinned-pdt-requirements.txt-expected.json +++ b/tests/data/pinned-pdt-requirements.txt-expected.json @@ -4,11 +4,11 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ - "--requirement /home/tg1999/Desktop/python-inspector-1/tests/data/pinned-pdt-requirements.txt", + "--requirement tests/data/pinned-pdt-requirements.txt", "--index-url https://pypi.org/simple", "--python-version 38", "--operating-system linux", - "--json " + "--json-pdt " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", "warnings": [], @@ -17,7 +17,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/pinned-pdt-requirements.txt", + "path": "tests/data/pinned-pdt-requirements.txt", "package_data": [ { "type": "pypi", diff --git a/tests/data/pinned-requirements.txt-expected.json b/tests/data/pinned-requirements.txt-expected.json index 77b92b9e..51f82d2f 100644 --- a/tests/data/pinned-requirements.txt-expected.json +++ b/tests/data/pinned-requirements.txt-expected.json @@ -4,7 +4,7 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ - "--requirement /home/tg1999/Desktop/python-inspector-1/tests/data/pinned-requirements.txt", + "--requirement tests/data/pinned-requirements.txt", "--index-url https://pypi.org/simple", "--python-version 38", "--operating-system linux", @@ -17,7 +17,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/pinned-requirements.txt", + "path": "tests/data/pinned-requirements.txt", "package_data": [ { "type": "pypi", diff --git a/tests/data/prefer-source-expected.json b/tests/data/prefer-source-expected.json index 2460aa47..f6665879 100644 --- a/tests/data/prefer-source-expected.json +++ b/tests/data/prefer-source-expected.json @@ -8,6 +8,7 @@ "--index-url https://pypi.org/simple", "--python-version 38", "--operating-system linux", + "--prefer-source", "--json " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", diff --git a/tests/data/setup/no-direct-dependencies-setup.py-expected.json b/tests/data/setup/no-direct-dependencies-setup.py-expected.json index 7dac3144..c6260ff9 100644 --- a/tests/data/setup/no-direct-dependencies-setup.py-expected.json +++ b/tests/data/setup/no-direct-dependencies-setup.py-expected.json @@ -4,9 +4,11 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ + "--setup-py tests/data/setup/no-direct-dependencies-setup.py", "--index-url https://pypi.org/simple", "--python-version 27", "--operating-system linux", + "--analyze-setup-py-insecurely", "--json " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", @@ -16,7 +18,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/setup/no-direct-dependencies-setup.py", + "path": "tests/data/setup/no-direct-dependencies-setup.py", "package_data": [ { "type": "pypi", diff --git a/tests/data/setup/simple-setup.py-expected.json b/tests/data/setup/simple-setup.py-expected.json index ea34e23e..fccc00f3 100644 --- a/tests/data/setup/simple-setup.py-expected.json +++ b/tests/data/setup/simple-setup.py-expected.json @@ -4,6 +4,7 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ + "--setup-py tests/data/setup/simple-setup.py", "--index-url https://pypi.org/simple", "--python-version 27", "--operating-system linux", @@ -16,7 +17,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/setup/simple-setup.py", + "path": "tests/data/setup/simple-setup.py", "package_data": [ { "type": "pypi", diff --git a/tests/data/setup/spdx-setup.py-expected.json b/tests/data/setup/spdx-setup.py-expected.json index 88f95591..1bec2dfe 100644 --- a/tests/data/setup/spdx-setup.py-expected.json +++ b/tests/data/setup/spdx-setup.py-expected.json @@ -4,10 +4,12 @@ "tool_homepageurl": "https://github.com/nexB/python-inspector", "tool_version": "0.9.7", "options": [ + "--setup-py tests/data/setup/spdx-setup.py", "--index-url https://pypi.org/simple", "--python-version 27", "--operating-system linux", - "--json " + "--analyze-setup-py-insecurely", + "--json-pdt " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", "warnings": [], @@ -16,7 +18,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/setup/spdx-setup.py", + "path": "tests/data/setup/spdx-setup.py", "package_data": [ { "type": "pypi", diff --git a/tests/data/single-url-except-simple-expected.json b/tests/data/single-url-except-simple-expected.json index 626de1ad..09c3e589 100644 --- a/tests/data/single-url-except-simple-expected.json +++ b/tests/data/single-url-except-simple-expected.json @@ -276,12 +276,12 @@ "type": "pypi", "namespace": null, "name": "importlib-metadata", - "version": "6.3.0", + "version": "6.4.1", "qualifiers": {}, "subpath": null, "primary_language": "Python", "description": "Read metadata from Python packages\n.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg\n :target: https://pypi.org/project/importlib_metadata\n\n.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg\n\n.. image:: https://github.com/python/importlib_metadata/workflows/tests/badge.svg\n :target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22\n :alt: tests\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :target: https://github.com/psf/black\n :alt: Code style: Black\n\n.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest\n :target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest\n\n.. image:: https://img.shields.io/badge/skeleton-2023-informational\n :target: https://blog.jaraco.com/skeleton\n\n.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata\n :target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme\n\nLibrary to access the metadata for a Python package.\n\nThis package supplies third-party access to the functionality of\n`importlib.metadata `_\nincluding improvements added to subsequent Python versions.\n\n\nCompatibility\n=============\n\nNew features are introduced in this third-party library and later merged\ninto CPython. The following table indicates which versions of this library\nwere contributed to different versions in the standard library:\n\n.. list-table::\n :header-rows: 1\n\n * - importlib_metadata\n - stdlib\n * - 5.0\n - 3.12\n * - 4.13\n - 3.11\n * - 4.6\n - 3.10\n * - 1.4\n - 3.8\n\n\nUsage\n=====\n\nSee the `online documentation `_\nfor usage details.\n\n`Finder authors\n`_ can\nalso add support for custom package installers. See the above documentation\nfor details.\n\n\nCaveats\n=======\n\nThis project primarily supports third-party packages installed by PyPA\ntools (or other conforming packages). It does not support:\n\n- Packages in the stdlib.\n- Packages installed without metadata.\n\nProject details\n===============\n\n * Project home: https://github.com/python/importlib_metadata\n * Report bugs at: https://github.com/python/importlib_metadata/issues\n * Code hosting: https://github.com/python/importlib_metadata\n * Documentation: https://importlib_metadata.readthedocs.io/\n\nFor Enterprise\n==============\n\nAvailable as part of the Tidelift Subscription.\n\nThis project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.\n\n`Learn more `_.\n\nSecurity Contact\n================\n\nTo report a security vulnerability, please use the\n`Tidelift security contact `_.\nTidelift will coordinate the fix and disclosure.", - "release_date": "2023-04-10T02:27:40", + "release_date": "2023-04-15T15:24:52", "parties": [ { "type": "person", @@ -298,11 +298,11 @@ "Programming Language :: Python :: 3 :: Only" ], "homepage_url": "https://github.com/python/importlib_metadata", - "download_url": "https://files.pythonhosted.org/packages/af/15/544ee37359dd4d8e490d1846062015f9d7d59b0f11e2e8e629917608e592/importlib_metadata-6.3.0-py3-none-any.whl", - "size": 22533, + "download_url": "https://files.pythonhosted.org/packages/fb/1d/11424f62d6057539224541f69282c300f11ac3f7dde8a92294145af8ea7f/importlib_metadata-6.4.1-py3-none-any.whl", + "size": 22557, "sha1": null, - "md5": "fa927011905878792c54886f35e59bca", - "sha256": "8f8bd2af397cf33bd344d35cfe7f489219b7d14fc79a3f854b75b8417e9226b0", + "md5": "2ac7dc6d83d24ddf055dabf907519eab", + "sha256": "63ace321e24167d12fbb176b6015f4dbe06868c54a2af4f15849586afb9027fd", "sha512": null, "bug_tracking_url": null, "code_view_url": null, @@ -321,20 +321,20 @@ "dependencies": [], "repository_homepage_url": null, "repository_download_url": null, - "api_data_url": "https://pypi.org/pypi/importlib-metadata/6.3.0/json", + "api_data_url": "https://pypi.org/pypi/importlib-metadata/6.4.1/json", "datasource_id": null, - "purl": "pkg:pypi/importlib-metadata@6.3.0" + "purl": "pkg:pypi/importlib-metadata@6.4.1" }, { "type": "pypi", "namespace": null, "name": "importlib-metadata", - "version": "6.3.0", + "version": "6.4.1", "qualifiers": {}, "subpath": null, "primary_language": "Python", "description": "Read metadata from Python packages\n.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg\n :target: https://pypi.org/project/importlib_metadata\n\n.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg\n\n.. image:: https://github.com/python/importlib_metadata/workflows/tests/badge.svg\n :target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22\n :alt: tests\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :target: https://github.com/psf/black\n :alt: Code style: Black\n\n.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest\n :target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest\n\n.. image:: https://img.shields.io/badge/skeleton-2023-informational\n :target: https://blog.jaraco.com/skeleton\n\n.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata\n :target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme\n\nLibrary to access the metadata for a Python package.\n\nThis package supplies third-party access to the functionality of\n`importlib.metadata `_\nincluding improvements added to subsequent Python versions.\n\n\nCompatibility\n=============\n\nNew features are introduced in this third-party library and later merged\ninto CPython. The following table indicates which versions of this library\nwere contributed to different versions in the standard library:\n\n.. list-table::\n :header-rows: 1\n\n * - importlib_metadata\n - stdlib\n * - 5.0\n - 3.12\n * - 4.13\n - 3.11\n * - 4.6\n - 3.10\n * - 1.4\n - 3.8\n\n\nUsage\n=====\n\nSee the `online documentation `_\nfor usage details.\n\n`Finder authors\n`_ can\nalso add support for custom package installers. See the above documentation\nfor details.\n\n\nCaveats\n=======\n\nThis project primarily supports third-party packages installed by PyPA\ntools (or other conforming packages). It does not support:\n\n- Packages in the stdlib.\n- Packages installed without metadata.\n\nProject details\n===============\n\n * Project home: https://github.com/python/importlib_metadata\n * Report bugs at: https://github.com/python/importlib_metadata/issues\n * Code hosting: https://github.com/python/importlib_metadata\n * Documentation: https://importlib_metadata.readthedocs.io/\n\nFor Enterprise\n==============\n\nAvailable as part of the Tidelift Subscription.\n\nThis project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.\n\n`Learn more `_.\n\nSecurity Contact\n================\n\nTo report a security vulnerability, please use the\n`Tidelift security contact `_.\nTidelift will coordinate the fix and disclosure.", - "release_date": "2023-04-10T02:27:42", + "release_date": "2023-04-15T15:24:54", "parties": [ { "type": "person", @@ -351,11 +351,11 @@ "Programming Language :: Python :: 3 :: Only" ], "homepage_url": "https://github.com/python/importlib_metadata", - "download_url": "https://files.pythonhosted.org/packages/c2/84/ab374b7e05fbdeecf867294660ac0fdb23aa286aca68a31d587f67d181ad/importlib_metadata-6.3.0.tar.gz", - "size": 52838, + "download_url": "https://files.pythonhosted.org/packages/20/fc/a0e728307f38609ef849d813c95dc974d344a3d395f62013ddcd8fbe0bfe/importlib_metadata-6.4.1.tar.gz", + "size": 52684, "sha1": null, - "md5": "f06a844f0917a1f4db1a1050f750c4fb", - "sha256": "23c2bcae4762dfb0bbe072d358faec24957901d75b6c4ab11172c0c982532402", + "md5": "b852ac8a5bce8c89feb12dd2de1e3e0f", + "sha256": "eb1a7933041f0f85c94cd130258df3fb0dec060ad8c1c9318892ef4192c47ce1", "sha512": null, "bug_tracking_url": null, "code_view_url": null, @@ -374,9 +374,9 @@ "dependencies": [], "repository_homepage_url": null, "repository_download_url": null, - "api_data_url": "https://pypi.org/pypi/importlib-metadata/6.3.0/json", + "api_data_url": "https://pypi.org/pypi/importlib-metadata/6.4.1/json", "datasource_id": null, - "purl": "pkg:pypi/importlib-metadata@6.3.0" + "purl": "pkg:pypi/importlib-metadata@6.4.1" }, { "type": "pypi", @@ -1006,14 +1006,14 @@ "package": "pkg:pypi/flask@2.2.3", "dependencies": [ "pkg:pypi/click@8.1.3", - "pkg:pypi/importlib-metadata@6.3.0", + "pkg:pypi/importlib-metadata@6.4.1", "pkg:pypi/itsdangerous@2.1.2", "pkg:pypi/jinja2@3.1.2", "pkg:pypi/werkzeug@2.2.3" ] }, { - "package": "pkg:pypi/importlib-metadata@6.3.0", + "package": "pkg:pypi/importlib-metadata@6.4.1", "dependencies": [ "pkg:pypi/zipp@3.15.0" ] diff --git a/tests/data/test-api-with-partial-setup-py.json b/tests/data/test-api-with-partial-setup-py.json index 97d7e3d1..824731ed 100644 --- a/tests/data/test-api-with-partial-setup-py.json +++ b/tests/data/test-api-with-partial-setup-py.json @@ -2,7 +2,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/partial-setup.py", + "path": "tests/data/partial-setup.py", "package_data": [ { "type": "pypi", diff --git a/tests/data/test-api-with-recursive-requirement-file.json b/tests/data/test-api-with-recursive-requirement-file.json index dff2d6e9..2f717a3e 100644 --- a/tests/data/test-api-with-recursive-requirement-file.json +++ b/tests/data/test-api-with-recursive-requirement-file.json @@ -2,7 +2,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/recursive_requirements/r.txt", + "path": "tests/data/recursive_requirements/r.txt", "package_data": [ { "type": "pypi", diff --git a/tests/data/test-api-with-requirement-file.json b/tests/data/test-api-with-requirement-file.json index d201b65d..a67c2d56 100644 --- a/tests/data/test-api-with-requirement-file.json +++ b/tests/data/test-api-with-requirement-file.json @@ -2,7 +2,7 @@ "files": [ { "type": "file", - "path": "/home/tg1999/Desktop/python-inspector-1/tests/data/frozen-requirements.txt", + "path": "tests/data/frozen-requirements.txt", "package_data": [ { "type": "pypi", @@ -5977,12 +5977,12 @@ "type": "pypi", "namespace": null, "name": "pip", - "version": "23.0.1", + "version": "23.1", "qualifiers": {}, "subpath": null, "primary_language": "Python", "description": "The PyPA recommended tool for installing Python packages.\npip - The Python Package Installer\n==================================\n\n.. image:: https://img.shields.io/pypi/v/pip.svg\n :target: https://pypi.org/project/pip/\n\n.. image:: https://readthedocs.org/projects/pip/badge/?version=latest\n :target: https://pip.pypa.io/en/latest\n\npip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.\n\nPlease take a look at our documentation for how to install and use pip:\n\n* `Installation`_\n* `Usage`_\n\nWe release updates regularly, with a new version every 3 months. Find more details in our documentation:\n\n* `Release notes`_\n* `Release process`_\n\nIn pip 20.3, we've `made a big improvement to the heart of pip`_; `learn more`_. We want your input, so `sign up for our user experience research studies`_ to help us do it right.\n\n**Note**: pip 21.0, in January 2021, removed Python 2 support, per pip's `Python 2 support policy`_. Please migrate to Python 3.\n\nIf you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:\n\n* `Issue tracking`_\n* `Discourse channel`_\n* `User IRC`_\n\nIf you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:\n\n* `GitHub page`_\n* `Development documentation`_\n* `Development IRC`_\n\nCode of Conduct\n---------------\n\nEveryone interacting in the pip project's codebases, issue trackers, chat\nrooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.\n\n.. _package installer: https://packaging.python.org/guides/tool-recommendations/\n.. _Python Package Index: https://pypi.org\n.. _Installation: https://pip.pypa.io/en/stable/installation/\n.. _Usage: https://pip.pypa.io/en/stable/\n.. _Release notes: https://pip.pypa.io/en/stable/news.html\n.. _Release process: https://pip.pypa.io/en/latest/development/release-process/\n.. _GitHub page: https://github.com/pypa/pip\n.. _Development documentation: https://pip.pypa.io/en/latest/development\n.. _made a big improvement to the heart of pip: https://pyfound.blogspot.com/2020/11/pip-20-3-new-resolver.html\n.. _learn more: https://pip.pypa.io/en/latest/user_guide/#changes-to-the-pip-dependency-resolver-in-20-3-2020\n.. _sign up for our user experience research studies: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-roll-out-this-year.html\n.. _Python 2 support policy: https://pip.pypa.io/en/latest/development/release-process/#python-2-support\n.. _Issue tracking: https://github.com/pypa/pip/issues\n.. _Discourse channel: https://discuss.python.org/c/packaging\n.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa\n.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev\n.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md", - "release_date": "2023-02-17T18:31:51", + "release_date": "2023-04-15T10:52:52", "parties": [ { "type": "person", @@ -6008,11 +6008,11 @@ "Topic :: Software Development :: Build Tools" ], "homepage_url": "https://pip.pypa.io/", - "download_url": "https://files.pythonhosted.org/packages/07/51/2c0959c5adf988c44d9e1e0d940f5b074516ecc87e96b1af25f59de9ba38/pip-23.0.1-py3-none-any.whl", - "size": 2055563, + "download_url": "https://files.pythonhosted.org/packages/ae/db/a8821cdac455a1740580c92de3ed7b7f257cfdbad8b1ba8864e6abe58a08/pip-23.1-py3-none-any.whl", + "size": 2064542, "sha1": null, - "md5": "83b53b599a1644afe7e76debe4a62bcc", - "sha256": "236bcb61156d76c4b8a05821b988c7b8c35bf0da28a4b614e8d6ab5212c25c6f", + "md5": "dea8a29f0029b31db3325078023bfaaf", + "sha256": "64b1d4528e491aa835ec6ece0c1ac40ce6ab6d886e60740f6519db44b2e9634d", "sha512": null, "bug_tracking_url": null, "code_view_url": "https://github.com/pypa/pip", @@ -6032,20 +6032,20 @@ "dependencies": [], "repository_homepage_url": null, "repository_download_url": null, - "api_data_url": "https://pypi.org/pypi/pip/23.0.1/json", + "api_data_url": "https://pypi.org/pypi/pip/23.1/json", "datasource_id": null, - "purl": "pkg:pypi/pip@23.0.1" + "purl": "pkg:pypi/pip@23.1" }, { "type": "pypi", "namespace": null, "name": "pip", - "version": "23.0.1", + "version": "23.1", "qualifiers": {}, "subpath": null, "primary_language": "Python", "description": "The PyPA recommended tool for installing Python packages.\npip - The Python Package Installer\n==================================\n\n.. image:: https://img.shields.io/pypi/v/pip.svg\n :target: https://pypi.org/project/pip/\n\n.. image:: https://readthedocs.org/projects/pip/badge/?version=latest\n :target: https://pip.pypa.io/en/latest\n\npip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.\n\nPlease take a look at our documentation for how to install and use pip:\n\n* `Installation`_\n* `Usage`_\n\nWe release updates regularly, with a new version every 3 months. Find more details in our documentation:\n\n* `Release notes`_\n* `Release process`_\n\nIn pip 20.3, we've `made a big improvement to the heart of pip`_; `learn more`_. We want your input, so `sign up for our user experience research studies`_ to help us do it right.\n\n**Note**: pip 21.0, in January 2021, removed Python 2 support, per pip's `Python 2 support policy`_. Please migrate to Python 3.\n\nIf you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:\n\n* `Issue tracking`_\n* `Discourse channel`_\n* `User IRC`_\n\nIf you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:\n\n* `GitHub page`_\n* `Development documentation`_\n* `Development IRC`_\n\nCode of Conduct\n---------------\n\nEveryone interacting in the pip project's codebases, issue trackers, chat\nrooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.\n\n.. _package installer: https://packaging.python.org/guides/tool-recommendations/\n.. _Python Package Index: https://pypi.org\n.. _Installation: https://pip.pypa.io/en/stable/installation/\n.. _Usage: https://pip.pypa.io/en/stable/\n.. _Release notes: https://pip.pypa.io/en/stable/news.html\n.. _Release process: https://pip.pypa.io/en/latest/development/release-process/\n.. _GitHub page: https://github.com/pypa/pip\n.. _Development documentation: https://pip.pypa.io/en/latest/development\n.. _made a big improvement to the heart of pip: https://pyfound.blogspot.com/2020/11/pip-20-3-new-resolver.html\n.. _learn more: https://pip.pypa.io/en/latest/user_guide/#changes-to-the-pip-dependency-resolver-in-20-3-2020\n.. _sign up for our user experience research studies: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-roll-out-this-year.html\n.. _Python 2 support policy: https://pip.pypa.io/en/latest/development/release-process/#python-2-support\n.. _Issue tracking: https://github.com/pypa/pip/issues\n.. _Discourse channel: https://discuss.python.org/c/packaging\n.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa\n.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev\n.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md", - "release_date": "2023-02-17T18:31:56", + "release_date": "2023-04-15T10:52:54", "parties": [ { "type": "person", @@ -6071,11 +6071,11 @@ "Topic :: Software Development :: Build Tools" ], "homepage_url": "https://pip.pypa.io/", - "download_url": "https://files.pythonhosted.org/packages/6b/8b/0b16094553ecc680e43ded8f920c3873b01b1da79a54274c98f08cb29fca/pip-23.0.1.tar.gz", - "size": 2082217, + "download_url": "https://files.pythonhosted.org/packages/da/bf/1bdbe62f5fbde085351693e3a8e387a59f8220932b911b1719fe65efa2d7/pip-23.1.tar.gz", + "size": 2087572, "sha1": null, - "md5": "f988022baba70f483744cc8c0e584010", - "sha256": "cd015ea1bfb0fcef59d8a286c1f8bebcb983f6317719d415dc5351efb7cd7024", + "md5": "b730fe00a3d43fa86e67472ad9d1de4d", + "sha256": "408539897ee535dbfb83a153f7bc4d620f990d8bd44a52a986efc0b4d330d34a", "sha512": null, "bug_tracking_url": null, "code_view_url": "https://github.com/pypa/pip", @@ -6095,9 +6095,9 @@ "dependencies": [], "repository_homepage_url": null, "repository_download_url": null, - "api_data_url": "https://pypi.org/pypi/pip/23.0.1/json", + "api_data_url": "https://pypi.org/pypi/pip/23.1/json", "datasource_id": null, - "purl": "pkg:pypi/pip@23.0.1" + "purl": "pkg:pypi/pip@23.1" }, { "type": "pypi", @@ -10649,13 +10649,13 @@ ] }, { - "package": "pkg:pypi/pip@23.0.1", + "package": "pkg:pypi/pip@23.1", "dependencies": [] }, { "package": "pkg:pypi/pipdeptree@2.2.1", "dependencies": [ - "pkg:pypi/pip@23.0.1" + "pkg:pypi/pip@23.1" ] }, { diff --git a/tests/data/tilde_req-expected.json b/tests/data/tilde_req-expected.json index 702807a8..9dc12bb8 100644 --- a/tests/data/tilde_req-expected.json +++ b/tests/data/tilde_req-expected.json @@ -9,6 +9,7 @@ "--index-url https://thirdparty.aboutcode.org/pypi/simple/", "--python-version 38", "--operating-system linux", + "--netrc tests/data/test-commented.netrc", "--json " ], "notice": "Dependency tree generated with python-inspector.\npython-inspector is a free software tool from nexB Inc. and others.\nVisit https://github.com/nexB/python-inspector/ for support and download.", diff --git a/tests/test_api.py b/tests/test_api.py index 6d406323..63c5f374 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -25,16 +25,14 @@ def test_api_with_specifier(): result_file = test_env.get_temp_file("json") expected_file = test_env.get_test_loc("test-api-expected.json", must_exist=False) + + resolution = resolver_api( + specifiers=["flask==2.1.2"], python_version="3.10", operating_system="linux" + ) + with open(result_file, "w") as result: - result.write( - json.dumps( - resolver_api( - specifiers=["flask==2.1.2"], - python_version="3.10", - operating_system="linux", - ).to_dict() - ) - ) + json.dump(resolution.to_dict(), result, indent=2, separators=(",", ": ")) + check_json_results( result_file=result_file, expected_file=expected_file, @@ -45,17 +43,17 @@ def test_api_with_specifier(): def test_api_with_specifier_pdt(): result_file = test_env.get_temp_file("json") expected_file = test_env.get_test_loc("test-api-pdt-expected.json", must_exist=False) + + resolution = resolver_api( + specifiers=["flask==2.1.2"], + python_version="3.10", + operating_system="linux", + pdt_output=True, + ) + with open(result_file, "w") as result: - result.write( - json.dumps( - resolver_api( - specifiers=["flask==2.1.2"], - python_version="3.10", - operating_system="linux", - pdt_output=True, - ).to_dict() - ) - ) + json.dump(resolution.to_dict(), result, indent=2, separators=(",", ": ")) + check_json_results( result_file=result_file, expected_file=expected_file, @@ -67,16 +65,14 @@ def test_api_with_requirement_file(): result_file = test_env.get_temp_file("json") requirement_file = test_env.get_test_loc("frozen-requirements.txt") expected_file = test_env.get_test_loc("test-api-with-requirement-file.json", must_exist=False) + + resolution = resolver_api( + python_version="3.10", operating_system="linux", requirement_files=[requirement_file] + ) + with open(result_file, "w") as result: - result.write( - json.dumps( - resolver_api( - python_version="3.10", - operating_system="linux", - requirement_files=[requirement_file], - ).to_dict() - ) - ) + json.dump(resolution.to_dict(), result, indent=2, separators=(",", ": ")) + check_json_results( result_file=result_file, expected_file=expected_file, @@ -87,17 +83,17 @@ def test_api_with_requirement_file(): def test_api_with_prefer_source(): result_file = test_env.get_temp_file("json") expected_file = test_env.get_test_loc("test-api-with-prefer-source.json", must_exist=False) + + resolution = resolver_api( + specifiers=["flask==2.1.2"], + python_version="3.10", + operating_system="linux", + prefer_source=True, + ) + with open(result_file, "w") as result: - result.write( - json.dumps( - resolver_api( - specifiers=["flask==2.1.2"], - python_version="3.10", - operating_system="linux", - prefer_source=True, - ).to_dict() - ) - ) + json.dump(resolution.to_dict(), result, indent=2, separators=(",", ": ")) + check_json_results( result_file=result_file, expected_file=expected_file, @@ -111,16 +107,14 @@ def test_api_with_recursive_requirement_file(): expected_file = test_env.get_test_loc( "test-api-with-recursive-requirement-file.json", must_exist=False ) + + resolution = resolver_api( + python_version="3.8", operating_system="linux", requirement_files=[requirement_file] + ) + with open(result_file, "w") as result: - result.write( - json.dumps( - resolver_api( - python_version="3.8", - operating_system="linux", - requirement_files=[requirement_file], - ).to_dict() - ) - ) + json.dump(resolution.to_dict(), result, indent=2, separators=(",", ": ")) + check_json_results( result_file=result_file, expected_file=expected_file, @@ -165,17 +159,17 @@ def test_api_with_wrong_pyver(): def test_api_with_python_311(): result_file = test_env.get_temp_file("json") expected_file = test_env.get_test_loc("test-api-with-python-311.json", must_exist=False) + + resolution = resolver_api( + specifiers=["flask==2.1.2"], + python_version="3.11", + operating_system="linux", + prefer_source=True, + ) + with open(result_file, "w") as result: - result.write( - json.dumps( - resolver_api( - specifiers=["flask==2.1.2"], - python_version="3.11", - operating_system="linux", - prefer_source=True, - ).to_dict() - ) - ) + json.dump(resolution.to_dict(), result, indent=2, separators=(",", ": ")) + check_json_results( result_file=result_file, expected_file=expected_file, @@ -187,18 +181,18 @@ def test_api_with_partial_setup_py(): result_file = test_env.get_temp_file("json") setup_py_file = test_env.get_test_loc("partial-setup.py") expected_file = test_env.get_test_loc("test-api-with-partial-setup-py.json", must_exist=False) + + resolution = resolver_api( + python_version="3.11", + operating_system="linux", + setup_py_file=setup_py_file, + prefer_source=True, + analyze_setup_py_insecurely=True, + ) + with open(result_file, "w") as result: - result.write( - json.dumps( - resolver_api( - python_version="3.11", - operating_system="linux", - setup_py_file=setup_py_file, - prefer_source=True, - analyze_setup_py_insecurely=True, - ).to_dict() - ) - ) + json.dump(resolution.to_dict(), result, indent=2, separators=(",", ": ")) + check_json_results( result_file=result_file, expected_file=expected_file, diff --git a/tests/test_cli.py b/tests/test_cli.py index a15a255b..15243241 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -480,18 +480,21 @@ def check_json_results(result_file, expected_file, clean=True, regen=REGEN_TEST_ """ with open(result_file) as res: results = json.load(res) + + if clean: + results = clean_results(results) + if regen: with open(expected_file, "w") as reg: json.dump(results, reg, indent=2, separators=(",", ": ")) expected = results + else: with open(expected_file) as res: expected = json.load(res) + if clean: + clean_results(expected) - if clean: - clean_results(expected) - if clean: - results = clean_results(results) assert results == expected @@ -500,17 +503,27 @@ def clean_results(results): Return cleaned results removing transient values that can change across test runs. """ - files = results.get("files", []) - for file in files: - path = os.path.split(file["path"])[-1] - file["path"] = path + for file in results.get("files", []): + file_path = file["path"] + _prefix, test_root, suffix = file_path.partition("tests/data") + file["path"] = f"{test_root}{suffix}" + headers = results.get("headers", {}) - options = headers.get("options", []) - headers["options"] = [ - o - for o in options - if (not o.startswith("--requirement") and not o.startswith("requirement_files-")) - ] + + new_options = [] + for o in headers.get("options", []): + newopt = o + + # clean file path options + if o.startswith(("--requirement", "--setup-py", "--netrc")): + opt, _, path = o.partition(" ") + _prefix, test_root, suffix = path.partition("tests/data") + newopt = f"{opt} {test_root}{suffix}" + + new_options.append(newopt) + + headers["options"] = new_options + return results diff --git a/tests/test_resolution.py b/tests/test_resolution.py index d5df82c2..efb63bd9 100644 --- a/tests/test_resolution.py +++ b/tests/test_resolution.py @@ -121,7 +121,7 @@ def test_get_resolved_dependencies_with_tilde_requirement_using_json_api(): assert plist == [ "pkg:pypi/click@8.1.3", "pkg:pypi/flask@2.1.3", - "pkg:pypi/importlib-metadata@6.3.0", + "pkg:pypi/importlib-metadata@6.4.1", "pkg:pypi/itsdangerous@2.1.2", "pkg:pypi/jinja2@3.1.2", "pkg:pypi/markupsafe@2.1.2",