From e7e048e5d81b29d7b30ebc9af75c14b6b086aa04 Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 9 Feb 2021 07:47:30 +0700 Subject: [PATCH 01/10] Add typings for the scripts.compile module (WIP) --- piptools/repositories/base.py | 8 +++ piptools/repositories/local.py | 9 +++- piptools/repositories/pypi.py | 3 +- piptools/scripts/compile.py | 98 ++++++++++++++++++---------------- piptools/writer.py | 5 +- 5 files changed, 72 insertions(+), 51 deletions(-) diff --git a/piptools/repositories/base.py b/piptools/repositories/base.py index 4d80bbf73..136f42824 100644 --- a/piptools/repositories/base.py +++ b/piptools/repositories/base.py @@ -1,11 +1,19 @@ +import optparse from abc import ABCMeta, abstractmethod from contextlib import contextmanager from typing import Iterator, Optional, Set +from pip._internal.index.package_finder import PackageFinder +from pip._internal.network.session import PipSession from pip._internal.req import InstallRequirement class BaseRepository(metaclass=ABCMeta): + DEFAULT_INDEX_URL: str + finder: PackageFinder + session: PipSession + options: optparse.Values + def clear_caches(self) -> None: """Should clear any caches used by the implementation.""" diff --git a/piptools/repositories/local.py b/piptools/repositories/local.py index e2a96be4d..240c869f2 100644 --- a/piptools/repositories/local.py +++ b/piptools/repositories/local.py @@ -1,5 +1,7 @@ from contextlib import contextmanager +from typing import Mapping +from pip._internal.req import InstallRequirement from pip._internal.utils.hashes import FAVORITE_HASH from piptools.utils import as_tuple, key_from_ireq, make_install_requirement @@ -29,7 +31,12 @@ class LocalRequirementsRepository(BaseRepository): PyPI. This keeps updates to the requirements.txt down to a minimum. """ - def __init__(self, existing_pins, proxied_repository, reuse_hashes=True): + def __init__( + self, + existing_pins: Mapping[str, InstallRequirement], + proxied_repository: BaseRepository, + reuse_hashes: bool = True, + ): self._reuse_hashes = reuse_hashes self.repository = proxied_repository self.existing_pins = existing_pins diff --git a/piptools/repositories/pypi.py b/piptools/repositories/pypi.py index 433187dda..383275cce 100644 --- a/piptools/repositories/pypi.py +++ b/piptools/repositories/pypi.py @@ -6,6 +6,7 @@ import tempfile from contextlib import contextmanager from shutil import rmtree +from typing import Sequence from click import progressbar from pip._internal.cache import WheelCache @@ -51,7 +52,7 @@ class PyPIRepository(BaseRepository): changed/configured on the Finder. """ - def __init__(self, pip_args, cache_dir): + def __init__(self, pip_args: Sequence[str], cache_dir): # Use pip's parser for pip.conf management and defaults. # General options (find_links, index_url, extra_index_url, trusted_host, # and pre) are deferred to pip. diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index d21f0dec9..fc56b2f2d 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -3,11 +3,10 @@ import sys import tempfile import warnings -from typing import Any +from typing import Any, List, Optional, Set, Tuple, cast import click -from click import Command -from click.utils import safecall +from click.utils import LazyFile, safecall from pip._internal.commands import create_command from pip._internal.req.constructors import install_req_from_line from pip._internal.utils.misc import redact_auth_from_url @@ -18,6 +17,7 @@ from ..locations import CACHE_DIR from ..logging import log from ..repositories import LocalRequirementsRepository, PyPIRepository +from ..repositories.base import BaseRepository from ..resolver import Resolver from ..utils import UNSAFE_PACKAGES, dedup, is_pinned_requirement, key_from_ireq from ..writer import OutputWriter @@ -36,17 +36,17 @@ def _get_default_option(option_name: str) -> Any: return getattr(default_values, option_name) -class BaseCommand(Command): - _os_args = None +class BaseCommand(click.Command): + _os_args: Set[str] - def parse_args(self, ctx, args): + def parse_args(self, ctx: click.Context, args: List[str]) -> List[str]: """ Override base `parse_args` to store the argument part of `sys.argv`. """ self._os_args = set(args) return super().parse_args(ctx, args) - def has_arg(self, arg_name): + def has_arg(self, arg_name: str) -> bool: """ Detect whether a given arg name (including negative counterparts to the arg, e.g. --no-arg) is present in the argument part of `sys.argv`. @@ -216,7 +216,9 @@ def has_arg(self, arg_name): show_default=True, type=click.Path(file_okay=False, writable=True), ) -@click.option("--pip-args", help="Arguments to pass directly to the pip command.") +@click.option( + "--pip-args", "pip_args_str", help="Arguments to pass directly to the pip command." +) @click.option( "--emit-index-url/--no-emit-index-url", is_flag=True, @@ -224,37 +226,39 @@ def has_arg(self, arg_name): help="Add index URL to generated file", ) def cli( - ctx, - verbose, - quiet, - dry_run, - pre, - rebuild, - find_links, - index_url, - extra_index_url, - cert, - client_cert, - trusted_host, - header, - index, - emit_trusted_host, - annotate, - upgrade, - upgrade_packages, - output_file, - allow_unsafe, - generate_hashes, - reuse_hashes, - src_files, - max_rounds, - build_isolation, - emit_find_links, - cache_dir, - pip_args, - emit_index_url, -): + ctx: click.Context, + verbose: int, + quiet: int, + dry_run: bool, + pre: bool, + rebuild: bool, + find_links: Tuple[str], + index_url: str, + extra_index_url: Tuple[str], + cert: Optional[str], + client_cert: Optional[str], + trusted_host: Tuple[str], + header: bool, + index: bool, + emit_trusted_host: bool, + annotate: bool, + upgrade: bool, + upgrade_packages: Tuple[str], + output_file: Optional[LazyFile], + allow_unsafe: bool, + generate_hashes: bool, + reuse_hashes: bool, + src_files: Tuple[str], + max_rounds: int, + build_isolation: bool, + emit_find_links: bool, + cache_dir: str, + pip_args_str: Optional[str], + emit_index_url: bool, +) -> None: """Compiles requirements.txt from requirements.in specs.""" + breakpoint() + log.verbosity = verbose - quiet if len(src_files) == 0: @@ -290,14 +294,16 @@ def cli( output_file = click.open_file(file_name, "w+b", atomic=True, lazy=True) # Close the file at the end of the context execution + assert output_file is not None ctx.call_on_close(safecall(output_file.close_intelligently)) - if cli.has_arg("index") and cli.has_arg("emit_index_url"): + command = cast(BaseCommand, ctx.command) + if command.has_arg("index") and command.has_arg("emit_index_url"): raise click.BadParameter( "--index/--no-index and --emit-index-url/--no-emit-index-url " "are mutually exclusive." ) - elif cli.has_arg("index"): + elif command.has_arg("index"): warnings.warn( "--index and --no-index are deprecated and will be removed " "in future versions. Use --emit-index-url/--no-emit-index-url instead.", @@ -309,7 +315,7 @@ def cli( # Setup ### - right_args = shlex.split(pip_args or "") + right_args = shlex.split(pip_args_str or "") pip_args = [] for link in find_links: pip_args.extend(["-f", link]) @@ -330,6 +336,7 @@ def cli( pip_args.append("--no-build-isolation") pip_args.extend(right_args) + repository: BaseRepository repository = PyPIRepository(pip_args, cache_dir=cache_dir) # Parse all constraints coming from --upgrade-package/-P @@ -383,8 +390,8 @@ def cli( from distutils.core import run_setup dist = run_setup(src_file) - tmpfile.write("\n".join(dist.install_requires)) - comes_from = f"{dist.get_name()} ({src_file})" + tmpfile.write("\n".join(dist.install_requires)) # type: ignore + comes_from = f"{dist.get_name()} ({src_file})" # type: ignore else: tmpfile.write(sys.stdin.read()) comes_from = "-r -" @@ -446,10 +453,7 @@ def cli( allow_unsafe=allow_unsafe, ) results = resolver.resolve(max_rounds=max_rounds) - if generate_hashes: - hashes = resolver.resolve_hashes(results) - else: - hashes = None + hashes = resolver.resolve_hashes(results) if generate_hashes else None except PipToolsError as e: log.error(str(e)) sys.exit(2) diff --git a/piptools/writer.py b/piptools/writer.py index d66dc4648..df974ef37 100644 --- a/piptools/writer.py +++ b/piptools/writer.py @@ -1,10 +1,11 @@ import os import re from itertools import chain -from typing import BinaryIO, Dict, Iterator, List, Optional, Sequence, Set, Tuple +from typing import Dict, Iterator, List, Optional, Sequence, Set, Tuple from click import unstyle from click.core import Context +from click.utils import LazyFile from pip._internal.models.format_control import FormatControl from pip._internal.req.req_install import InstallRequirement from pip._vendor.packaging.markers import Marker @@ -53,7 +54,7 @@ def _comes_from_as_string(ireq: InstallRequirement) -> str: class OutputWriter: def __init__( self, - dst_file: BinaryIO, + dst_file: LazyFile, click_ctx: Context, dry_run: bool, emit_header: bool, From 7faaded935908b74e22483554e008c9486a03bb6 Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 23 Feb 2021 13:58:56 +0700 Subject: [PATCH 02/10] Add missing type hints --- piptools/repositories/pypi.py | 17 ++++++++++------- piptools/scripts/compile.py | 4 ++-- piptools/writer.py | 10 +++++----- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/piptools/repositories/pypi.py b/piptools/repositories/pypi.py index 383275cce..d60d2b383 100644 --- a/piptools/repositories/pypi.py +++ b/piptools/repositories/pypi.py @@ -6,16 +6,17 @@ import tempfile from contextlib import contextmanager from shutil import rmtree -from typing import Sequence +from typing import Dict, List from click import progressbar from pip._internal.cache import WheelCache from pip._internal.cli.progress_bars import BAR_TYPES from pip._internal.commands import create_command +from pip._internal.models.candidate import InstallationCandidate from pip._internal.models.index import PackageIndex, PyPI from pip._internal.models.link import Link from pip._internal.models.wheel import Wheel -from pip._internal.req import RequirementSet +from pip._internal.req import InstallRequirement, RequirementSet from pip._internal.req.req_tracker import get_requirement_tracker from pip._internal.utils.hashes import FAVORITE_HASH from pip._internal.utils.logging import indent_log, setup_logging @@ -52,7 +53,7 @@ class PyPIRepository(BaseRepository): changed/configured on the Finder. """ - def __init__(self, pip_args: Sequence[str], cache_dir): + def __init__(self, pip_args: List[str], cache_dir: str) -> None: # Use pip's parser for pip.conf management and defaults. # General options (find_links, index_url, extra_index_url, trusted_host, # and pre) are deferred to pip. @@ -78,12 +79,14 @@ def __init__(self, pip_args: Sequence[str], cache_dir): # stores project_name => InstallationCandidate mappings for all # versions reported by PyPI, so we only have to ask once for each # project - self._available_candidates_cache = {} + self._available_candidates_cache: Dict[str, List[InstallationCandidate]] = {} # stores InstallRequirement => list(InstallRequirement) mappings # of all secondary dependencies for the given requirement, so we # only have to go to disk once for each requirement - self._dependencies_cache = {} + self._dependencies_cache: Dict[ + InstallRequirement, List[InstallRequirement] + ] = {} # Setup file paths self._build_dir = None @@ -449,7 +452,7 @@ def _wheel_support_index_min(self, tags=None): Wheel.support_index_min = original_support_index_min self._available_candidates_cache = original_cache - def _setup_logging(self): + def _setup_logging(self) -> None: """ Setup pip's logger. Ensure pip is verbose same as pip-tools and sync pip's log stream with LogContext.stream. @@ -465,7 +468,7 @@ def _setup_logging(self): logger = logging.getLogger() for handler in logger.handlers: if handler.name == "console": # pragma: no branch - handler.stream = log.stream + handler.stream = log.stream # type: ignore[attr-defined] break else: # pragma: no cover # There is always a console handler. This warning would be a signal that diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index fc56b2f2d..61dc00ca0 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -390,8 +390,8 @@ def cli( from distutils.core import run_setup dist = run_setup(src_file) - tmpfile.write("\n".join(dist.install_requires)) # type: ignore - comes_from = f"{dist.get_name()} ({src_file})" # type: ignore + tmpfile.write("\n".join(dist.install_requires)) # type: ignore[attr-defined] + comes_from = f"{dist.get_name()} ({src_file})" # type: ignore[attr-defined] else: tmpfile.write(sys.stdin.read()) comes_from = "-r -" diff --git a/piptools/writer.py b/piptools/writer.py index df974ef37..adcdda416 100644 --- a/piptools/writer.py +++ b/piptools/writer.py @@ -1,7 +1,7 @@ import os import re from itertools import chain -from typing import Dict, Iterator, List, Optional, Sequence, Set, Tuple +from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple from click import unstyle from click.core import Context @@ -63,8 +63,8 @@ def __init__( annotate: bool, generate_hashes: bool, default_index_url: str, - index_urls: Sequence[str], - trusted_hosts: Sequence[str], + index_urls: Iterable[str], + trusted_hosts: Iterable[str], format_control: FormatControl, allow_unsafe: bool, find_links: List[str], @@ -219,8 +219,8 @@ def write( for line in self._iter_lines(results, unsafe_requirements, markers, hashes): log.info(line) if not self.dry_run: - self.dst_file.write(unstyle(line).encode()) - self.dst_file.write(os.linesep.encode()) + self.dst_file.write(unstyle(line).encode()) # type: ignore[attr-defined] + self.dst_file.write(os.linesep.encode()) # type: ignore[attr-defined] def _format_requirement( self, From b2be5f9ea35b8b3196841fc784b0fce1bab0156b Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 23 Feb 2021 14:12:46 +0700 Subject: [PATCH 03/10] Remove breakpoint --- piptools/scripts/compile.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index 61dc00ca0..d847a12c1 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -257,8 +257,6 @@ def cli( emit_index_url: bool, ) -> None: """Compiles requirements.txt from requirements.in specs.""" - breakpoint() - log.verbosity = verbose - quiet if len(src_files) == 0: From 4e2c3ef44f3e1344995df05f08647968d41e3968 Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 23 Feb 2021 14:41:58 +0700 Subject: [PATCH 04/10] Fix failing test --- piptools/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piptools/utils.py b/piptools/utils.py index 5ed2c38b9..39d543f9f 100644 --- a/piptools/utils.py +++ b/piptools/utils.py @@ -305,7 +305,7 @@ def get_compile_command(click_ctx: click.Context) -> str: else: if isinstance(val, str) and is_url(val): val = redact_auth_from_url(val) - if option.name == "pip_args": + if option.name == "pip_args_str": # shlex.quote() would produce functional but noisily quoted results, # e.g. --pip-args='--cache-dir='"'"'/tmp/with spaces'"'"'' # Instead, we try to get more legible quoting via repr: From 775de7e0295e1974399ad079d5e97d23f2399a33 Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Sat, 6 Mar 2021 12:06:08 +0700 Subject: [PATCH 05/10] Use cast instead of ignore type --- piptools/repositories/pypi.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/piptools/repositories/pypi.py b/piptools/repositories/pypi.py index bf278cdc4..ebb483326 100644 --- a/piptools/repositories/pypi.py +++ b/piptools/repositories/pypi.py @@ -6,7 +6,7 @@ import tempfile from contextlib import contextmanager from shutil import rmtree -from typing import Dict, List +from typing import Dict, List, cast from click import progressbar from pip._internal.cache import WheelCache @@ -467,7 +467,8 @@ def _setup_logging(self) -> None: logger = logging.getLogger() for handler in logger.handlers: if handler.name == "console": # pragma: no branch - handler.stream = log.stream # type: ignore[attr-defined] + handler = cast(logging.StreamHandler, handler) + handler.stream = log.stream break else: # pragma: no cover # There is always a console handler. This warning would be a signal that From f583f047b187183aa4f114a3129d67850cec19c7 Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Sun, 7 Mar 2021 10:32:38 +0700 Subject: [PATCH 06/10] Use BinaryIO for OutputWroter.dst_file instead of LazyFile --- piptools/scripts/compile.py | 4 ++-- piptools/writer.py | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index 53e9a070e..062d58d0c 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -2,7 +2,7 @@ import shlex import sys import tempfile -from typing import Any, Optional, Tuple +from typing import Any, BinaryIO, Optional, Tuple, cast import click from click.utils import LazyFile, safecall @@ -432,7 +432,7 @@ def cli( ## writer = OutputWriter( - output_file, + cast(BinaryIO, output_file), click_ctx=ctx, dry_run=dry_run, emit_header=header, diff --git a/piptools/writer.py b/piptools/writer.py index 3f3d74854..1d319f21a 100644 --- a/piptools/writer.py +++ b/piptools/writer.py @@ -1,11 +1,10 @@ import os import re from itertools import chain -from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple +from typing import BinaryIO, Dict, Iterable, Iterator, List, Optional, Set, Tuple from click import unstyle from click.core import Context -from click.utils import LazyFile from pip._internal.models.format_control import FormatControl from pip._internal.req.req_install import InstallRequirement from pip._vendor.packaging.markers import Marker @@ -54,7 +53,7 @@ def _comes_from_as_string(ireq: InstallRequirement) -> str: class OutputWriter: def __init__( self, - dst_file: LazyFile, + dst_file: BinaryIO, click_ctx: Context, dry_run: bool, emit_header: bool, @@ -219,8 +218,8 @@ def write( for line in self._iter_lines(results, unsafe_requirements, markers, hashes): log.info(line) if not self.dry_run: - self.dst_file.write(unstyle(line).encode()) # type: ignore[attr-defined] - self.dst_file.write(os.linesep.encode()) # type: ignore[attr-defined] + self.dst_file.write(unstyle(line).encode()) + self.dst_file.write(os.linesep.encode()) def _format_requirement( self, From 3f1f578a650e29ab96f26fda2bec643843a92269 Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 9 Mar 2021 19:54:14 +0700 Subject: [PATCH 07/10] Correct type annotations after merging master --- piptools/repositories/base.py | 21 +++++++++++++++---- piptools/repositories/local.py | 10 +++------ piptools/repositories/pypi.py | 38 ++++++++++++++++++++++++---------- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/piptools/repositories/base.py b/piptools/repositories/base.py index e24f7678c..a73c169b6 100644 --- a/piptools/repositories/base.py +++ b/piptools/repositories/base.py @@ -4,15 +4,13 @@ from typing import Iterator, Optional, Set from pip._internal.index.package_finder import PackageFinder +from pip._internal.models.index import PyPI from pip._internal.network.session import PipSession from pip._internal.req import InstallRequirement class BaseRepository(metaclass=ABCMeta): - DEFAULT_INDEX_URL: str - finder: PackageFinder - session: PipSession - options: optparse.Values + DEFAULT_INDEX_URL = PyPI.simple_url def clear_caches(self) -> None: """Should clear any caches used by the implementation.""" @@ -59,3 +57,18 @@ def copy_ireq_dependencies( it its name, we would lose track of those dependencies on combining that ireq with others. """ + + @property + @abstractmethod + def options(self) -> optparse.Values: + pass + + @property + @abstractmethod + def session(self) -> PipSession: + pass + + @property + @abstractmethod + def finder(self) -> PackageFinder: + pass diff --git a/piptools/repositories/local.py b/piptools/repositories/local.py index f38239101..40edca7ef 100644 --- a/piptools/repositories/local.py +++ b/piptools/repositories/local.py @@ -1,6 +1,6 @@ import optparse from contextlib import contextmanager -from typing import Iterator, List, Mapping, Optional, Set, cast +from typing import Iterator, Mapping, Optional, Set, cast from pip._internal.index.package_finder import PackageFinder from pip._internal.models.candidate import InstallationCandidate @@ -50,8 +50,8 @@ def __init__( self.existing_pins = existing_pins @property - def options(self) -> List[optparse.Option]: - return cast(List[optparse.Option], self.repository.options) + def options(self) -> optparse.Values: + return self.repository.options @property def finder(self) -> PackageFinder: @@ -61,10 +61,6 @@ def finder(self) -> PackageFinder: def session(self) -> Session: return self.repository.session - @property - def DEFAULT_INDEX_URL(self) -> str: - return cast(str, self.repository.DEFAULT_INDEX_URL) - def clear_caches(self) -> None: self.repository.clear_caches() diff --git a/piptools/repositories/pypi.py b/piptools/repositories/pypi.py index 89afbbbec..732547775 100644 --- a/piptools/repositories/pypi.py +++ b/piptools/repositories/pypi.py @@ -2,6 +2,7 @@ import hashlib import itertools import logging +import optparse import os from contextlib import contextmanager from shutil import rmtree @@ -11,10 +12,13 @@ from pip._internal.cache import WheelCache from pip._internal.cli.progress_bars import BAR_TYPES from pip._internal.commands import create_command +from pip._internal.commands.install import InstallCommand +from pip._internal.index.package_finder import PackageFinder from pip._internal.models.candidate import InstallationCandidate -from pip._internal.models.index import PackageIndex, PyPI +from pip._internal.models.index import PackageIndex from pip._internal.models.link import Link from pip._internal.models.wheel import Wheel +from pip._internal.network.session import PipSession from pip._internal.req import InstallRequirement, RequirementSet from pip._internal.req.req_tracker import get_requirement_tracker from pip._internal.utils.hashes import FAVORITE_HASH @@ -43,7 +47,6 @@ class PyPIRepository(BaseRepository): - DEFAULT_INDEX_URL = PyPI.simple_url HASHABLE_PACKAGE_TYPES = {"bdist_wheel", "sdist"} """ @@ -57,18 +60,19 @@ def __init__(self, pip_args: List[str], cache_dir: str): # Use pip's parser for pip.conf management and defaults. # General options (find_links, index_url, extra_index_url, trusted_host, # and pre) are deferred to pip. - self.command = create_command("install") + self.command: InstallCommand = create_command("install") extra_pip_args = ["--use-deprecated", "legacy-resolver"] - self.options, _ = self.command.parse_args(pip_args + extra_pip_args) - if self.options.cache_dir: - self.options.cache_dir = normalize_path(self.options.cache_dir) - self.options.require_hashes = False - self.options.ignore_dependencies = False + options, _ = self.command.parse_args(pip_args + extra_pip_args) + if options.cache_dir: + options.cache_dir = normalize_path(options.cache_dir) + options.require_hashes = False + options.ignore_dependencies = False - self.session = self.command._build_session(self.options) - self.finder = self.command._build_package_finder( - options=self.options, session=self.session + self._options: optparse.Values = options + self._session = self.command._build_session(options) + self._finder = self.command._build_package_finder( + options=options, session=self.session ) # Caches @@ -91,6 +95,18 @@ def __init__(self, pip_args: List[str], cache_dir: str): def clear_caches(self) -> None: rmtree(self._download_dir, ignore_errors=True) + @property + def options(self) -> optparse.Values: + return self._options + + @property + def session(self) -> PipSession: + return self._session + + @property + def finder(self) -> PackageFinder: + return self._finder + def find_all_candidates(self, req_name: str) -> List[InstallationCandidate]: if req_name not in self._available_candidates_cache: candidates = self.finder.find_all_candidates(req_name) From 081339b300d4790391f217f351cfbd329edf44ed Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 9 Mar 2021 20:03:02 +0700 Subject: [PATCH 08/10] Fix failing tests --- tests/conftest.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 13104d1f4..7c95f6521 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -90,6 +90,18 @@ def copy_ireq_dependencies(self, source, dest): # No state to update. pass + @property + def options(self): + pass + + @property + def session(self): + pass + + @property + def finder(self): + pass + class FakeInstalledDistribution: def __init__(self, line, deps=None): From 293aaadf90eca9152d95190944d92a7e553b8e11 Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 9 Mar 2021 20:55:32 +0700 Subject: [PATCH 09/10] Fix decreased coverage --- piptools/repositories/base.py | 6 +++--- tests/conftest.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/piptools/repositories/base.py b/piptools/repositories/base.py index a73c169b6..734ac6f57 100644 --- a/piptools/repositories/base.py +++ b/piptools/repositories/base.py @@ -61,14 +61,14 @@ def copy_ireq_dependencies( @property @abstractmethod def options(self) -> optparse.Values: - pass + """Returns parsed pip options""" @property @abstractmethod def session(self) -> PipSession: - pass + """Returns a session to make requests""" @property @abstractmethod def finder(self) -> PackageFinder: - pass + """Returns a package finder to interact with simple repository API (PEP 503)""" diff --git a/tests/conftest.py b/tests/conftest.py index 7c95f6521..e39f7d19b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -92,15 +92,15 @@ def copy_ireq_dependencies(self, source, dest): @property def options(self): - pass + """Not used""" @property def session(self): - pass + """Not used""" @property def finder(self): - pass + """Not used""" class FakeInstalledDistribution: From 5f43774eacb849e4483fd2d67f5389af1c1fa0ca Mon Sep 17 00:00:00 2001 From: Albert Tugushev Date: Tue, 9 Mar 2021 22:21:18 +0700 Subject: [PATCH 10/10] Address review comments https://github.com/jazzband/pip-tools/pull/1322#discussion_r590455449 --- tests/conftest.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index e39f7d19b..e824baf90 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ import json +import optparse import os import subprocess import sys @@ -8,7 +9,9 @@ import pytest from click.testing import CliRunner +from pip._internal.index.package_finder import PackageFinder from pip._internal.models.candidate import InstallationCandidate +from pip._internal.network.session import PipSession from pip._internal.req.constructors import ( install_req_from_editable, install_req_from_line, @@ -91,15 +94,15 @@ def copy_ireq_dependencies(self, source, dest): pass @property - def options(self): + def options(self) -> optparse.Values: """Not used""" @property - def session(self): + def session(self) -> PipSession: """Not used""" @property - def finder(self): + def finder(self) -> PackageFinder: """Not used"""