From f7cd93a5ded0086017e7062f0fd198cc77ad6a4b Mon Sep 17 00:00:00 2001 From: Devesh Kumar Singh Date: Mon, 18 May 2020 01:58:29 +0530 Subject: [PATCH 1/7] Type annotations for pip._internal.commands.freeze --- src/pip/_internal/commands/freeze.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pip/_internal/commands/freeze.py b/src/pip/_internal/commands/freeze.py index 13171772e..5b9a78ff5 100644 --- a/src/pip/_internal/commands/freeze.py +++ b/src/pip/_internal/commands/freeze.py @@ -1,6 +1,3 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - from __future__ import absolute_import import sys @@ -8,12 +5,18 @@ import sys from pip._internal.cache import WheelCache from pip._internal.cli import cmdoptions from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import SUCCESS from pip._internal.models.format_control import FormatControl from pip._internal.operations.freeze import freeze from pip._internal.utils.compat import stdlib_pkgs +from pip._internal.utils.typing import MYPY_CHECK_RUNNING DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel'} +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import Any, List + class FreezeCommand(Command): """ @@ -27,6 +30,7 @@ class FreezeCommand(Command): log_streams = ("ext://sys.stderr", "ext://sys.stderr") def __init__(self, *args, **kw): + # type: (*Any, **Any) -> None super(FreezeCommand, self).__init__(*args, **kw) self.cmd_opts.add_option( @@ -75,6 +79,7 @@ class FreezeCommand(Command): self.parser.insert_option_group(0, self.cmd_opts) def run(self, options, args): + # type: (Values, List[str]) -> int format_control = FormatControl(set(), set()) wheel_cache = WheelCache(options.cache_dir, format_control) skip = set(stdlib_pkgs) @@ -97,3 +102,4 @@ class FreezeCommand(Command): for line in freeze(**freeze_kwargs): sys.stdout.write(line + '\n') + return SUCCESS From 2da7a2b077169db62bf38d7b554a045f633c9d87 Mon Sep 17 00:00:00 2001 From: Devesh Kumar Singh Date: Mon, 18 May 2020 02:00:22 +0530 Subject: [PATCH 2/7] Type annotations for pip._internal.commands.download --- src/pip/_internal/commands/download.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pip/_internal/commands/download.py b/src/pip/_internal/commands/download.py index c82955063..570d7289c 100644 --- a/src/pip/_internal/commands/download.py +++ b/src/pip/_internal/commands/download.py @@ -1,6 +1,3 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - from __future__ import absolute_import import logging @@ -12,6 +9,12 @@ from pip._internal.cli.req_command import RequirementCommand, with_cleanup from pip._internal.req.req_tracker import get_requirement_tracker from pip._internal.utils.misc import ensure_dir, normalize_path, write_output from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import Any, List + from pip._internal.req.req_set import RequirementSet logger = logging.getLogger(__name__) @@ -37,6 +40,7 @@ class DownloadCommand(RequirementCommand): %prog [options] ...""" def __init__(self, *args, **kw): + # type: (*Any, **Any) -> None super(DownloadCommand, self).__init__(*args, **kw) cmd_opts = self.cmd_opts @@ -77,6 +81,8 @@ class DownloadCommand(RequirementCommand): @with_cleanup def run(self, options, args): + # type: (Values, List[str]) -> RequirementSet + options.ignore_installed = True # editable doesn't really make sense for `pip download`, but the bowels # of the RequirementSet code require that property. @@ -134,7 +140,7 @@ class DownloadCommand(RequirementCommand): downloaded = ' '.join([ req.name for req in requirement_set.requirements.values() - if req.successfully_downloaded + if req.successfully_downloaded and req.name ]) if downloaded: write_output('Successfully downloaded %s', downloaded) From 4f98df6e3e61d50ea0c584d1297cd1f8bbb1c2e2 Mon Sep 17 00:00:00 2001 From: Devesh Kumar Singh Date: Mon, 18 May 2020 02:00:41 +0530 Subject: [PATCH 3/7] Type annotations for pip._internal.commands.search --- src/pip/_internal/commands/search.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/pip/_internal/commands/search.py b/src/pip/_internal/commands/search.py index e5f286ea5..8d581b9bd 100644 --- a/src/pip/_internal/commands/search.py +++ b/src/pip/_internal/commands/search.py @@ -1,6 +1,3 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - from __future__ import absolute_import import logging @@ -23,6 +20,12 @@ from pip._internal.network.xmlrpc import PipXmlrpcTransport from pip._internal.utils.compat import get_terminal_size from pip._internal.utils.logging import indent_log from pip._internal.utils.misc import write_output +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import Any, List, Dict, Optional + logger = logging.getLogger(__name__) @@ -35,6 +38,7 @@ class SearchCommand(Command, SessionCommandMixin): ignore_require_venv = True def __init__(self, *args, **kw): + # type: (*Any, **Any) -> None super(SearchCommand, self).__init__(*args, **kw) self.cmd_opts.add_option( '-i', '--index', @@ -46,6 +50,7 @@ class SearchCommand(Command, SessionCommandMixin): self.parser.insert_option_group(0, self.cmd_opts) def run(self, options, args): + # type: (Values, List[str]) -> int if not args: raise CommandError('Missing required argument (search query).') query = args @@ -62,6 +67,7 @@ class SearchCommand(Command, SessionCommandMixin): return NO_MATCHES_FOUND def search(self, query, options): + # type: (List[str], Values) -> List[Dict[str, str]] index_url = options.index session = self.get_default_session(options) @@ -73,12 +79,13 @@ class SearchCommand(Command, SessionCommandMixin): def transform_hits(hits): + # type: (List[Dict[str, str]]) -> List[Dict[str, Any]] """ The list from pypi is really a list of versions. We want a list of packages with the list of versions stored inline. This converts the list from pypi into one we can use. """ - packages = OrderedDict() + packages = OrderedDict() # type: OrderedDict[str, Any] for hit in hits: name = hit['name'] summary = hit['summary'] @@ -101,6 +108,7 @@ def transform_hits(hits): def print_results(hits, name_column_width=None, terminal_width=None): + # type: (List[Dict[str, Any]], Optional[int], Optional[int]) -> None if not hits: return if name_column_width is None: @@ -143,4 +151,5 @@ def print_results(hits, name_column_width=None, terminal_width=None): def highest_version(versions): + # type: (List[str]) -> str return max(versions, key=parse_version) From 197bbceed172bebba95b5f3a8ff190820a6107df Mon Sep 17 00:00:00 2001 From: Devesh Kumar Singh Date: Tue, 19 May 2020 12:49:46 +0530 Subject: [PATCH 4/7] Add news file and convert TransformedHit type to TypedDict --- ...3C29002F-4AB2-4093-B321-994F7882F944.trivial | 0 src/pip/_internal/commands/search.py | 17 +++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 news/3C29002F-4AB2-4093-B321-994F7882F944.trivial diff --git a/news/3C29002F-4AB2-4093-B321-994F7882F944.trivial b/news/3C29002F-4AB2-4093-B321-994F7882F944.trivial new file mode 100644 index 000000000..e69de29bb diff --git a/src/pip/_internal/commands/search.py b/src/pip/_internal/commands/search.py index 8d581b9bd..d8c5fba8f 100644 --- a/src/pip/_internal/commands/search.py +++ b/src/pip/_internal/commands/search.py @@ -25,7 +25,11 @@ from pip._internal.utils.typing import MYPY_CHECK_RUNNING if MYPY_CHECK_RUNNING: from optparse import Values from typing import Any, List, Dict, Optional - + from typing_extensions import TypedDict + TransformedHit = TypedDict( + 'TransformedHit', + {'name': str, 'summary': str, 'versions': List[str]}, + ) logger = logging.getLogger(__name__) @@ -79,13 +83,13 @@ class SearchCommand(Command, SessionCommandMixin): def transform_hits(hits): - # type: (List[Dict[str, str]]) -> List[Dict[str, Any]] + # type: (List[Dict[str, str]]) -> List[TransformedHit] """ The list from pypi is really a list of versions. We want a list of packages with the list of versions stored inline. This converts the list from pypi into one we can use. """ - packages = OrderedDict() # type: OrderedDict[str, Any] + packages = OrderedDict() # type: OrderedDict[str, TransformedHit] for hit in hits: name = hit['name'] summary = hit['summary'] @@ -108,7 +112,7 @@ def transform_hits(hits): def print_results(hits, name_column_width=None, terminal_width=None): - # type: (List[Dict[str, Any]], Optional[int], Optional[int]) -> None + # type: (List[TransformedHit], Optional[int], Optional[int]) -> None if not hits: return if name_column_width is None: @@ -126,8 +130,9 @@ def print_results(hits, name_column_width=None, terminal_width=None): target_width = terminal_width - name_column_width - 5 if target_width > 10: # wrap and indent summary to fit terminal - summary = textwrap.wrap(summary, target_width) - summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) + summary_lines = textwrap.wrap(summary, target_width) + summary = ('\n' + ' ' * (name_column_width + 3)).join( + summary_lines) line = '{name_latest:{name_column_width}} - {summary}'.format( name_latest='{name} ({latest})'.format(**locals()), From 716a067335a39766a9d05544093cc36573500dfb Mon Sep 17 00:00:00 2001 From: Devesh Kumar Singh Date: Fri, 22 May 2020 00:32:37 +0530 Subject: [PATCH 5/7] Return int status code from download.run --- src/pip/_internal/commands/download.py | 7 ++++--- tests/functional/test_download.py | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/pip/_internal/commands/download.py b/src/pip/_internal/commands/download.py index 570d7289c..62bca709c 100644 --- a/src/pip/_internal/commands/download.py +++ b/src/pip/_internal/commands/download.py @@ -6,6 +6,7 @@ import os from pip._internal.cli import cmdoptions from pip._internal.cli.cmdoptions import make_target_python from pip._internal.cli.req_command import RequirementCommand, with_cleanup +from pip._internal.cli.status_codes import ERROR, SUCCESS from pip._internal.req.req_tracker import get_requirement_tracker from pip._internal.utils.misc import ensure_dir, normalize_path, write_output from pip._internal.utils.temp_dir import TempDirectory @@ -14,7 +15,6 @@ from pip._internal.utils.typing import MYPY_CHECK_RUNNING if MYPY_CHECK_RUNNING: from optparse import Values from typing import Any, List - from pip._internal.req.req_set import RequirementSet logger = logging.getLogger(__name__) @@ -81,7 +81,7 @@ class DownloadCommand(RequirementCommand): @with_cleanup def run(self, options, args): - # type: (Values, List[str]) -> RequirementSet + # type: (Values, List[str]) -> int options.ignore_installed = True # editable doesn't really make sense for `pip download`, but the bowels @@ -144,5 +144,6 @@ class DownloadCommand(RequirementCommand): ]) if downloaded: write_output('Successfully downloaded %s', downloaded) + return SUCCESS - return requirement_set + return ERROR diff --git a/tests/functional/test_download.py b/tests/functional/test_download.py index 05b97ab3a..2b6ff8e9d 100644 --- a/tests/functional/test_download.py +++ b/tests/functional/test_download.py @@ -666,7 +666,9 @@ def test_download_exit_status_code_when_blank_requirements_file(script): Test download exit status code when blank requirements file specified """ script.scratch_path.joinpath("blank.txt").write_text("\n") - script.pip('download', '-r', 'blank.txt') + result = script.pip('download', '-r', 'blank.txt', expect_error=True) + print(result) + assert result.returncode == ERROR def test_download_prefer_binary_when_tarball_higher_than_wheel(script, data): From 5e33373a0738a03ca8515e3618046f0ad4b10582 Mon Sep 17 00:00:00 2001 From: Devesh Kumar Singh Date: Fri, 22 May 2020 00:41:50 +0530 Subject: [PATCH 6/7] Remove req.name check --- src/pip/_internal/commands/download.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pip/_internal/commands/download.py b/src/pip/_internal/commands/download.py index 62bca709c..01ebf6a55 100644 --- a/src/pip/_internal/commands/download.py +++ b/src/pip/_internal/commands/download.py @@ -138,10 +138,9 @@ class DownloadCommand(RequirementCommand): reqs, check_supported_wheels=True ) - downloaded = ' '.join([ - req.name for req in requirement_set.requirements.values() - if req.successfully_downloaded and req.name - ]) + downloaded = ' '.join([req.name # type: ignore + for req in requirement_set.requirements.values() + if req.successfully_downloaded]) if downloaded: write_output('Successfully downloaded %s', downloaded) return SUCCESS From e8b842389c94111f510d372ca834a6d4a123ae0b Mon Sep 17 00:00:00 2001 From: Devesh Kumar Singh Date: Fri, 22 May 2020 19:44:29 +0530 Subject: [PATCH 7/7] Always return SUCCESS from download.run --- src/pip/_internal/commands/download.py | 5 ++--- tests/functional/test_download.py | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/pip/_internal/commands/download.py b/src/pip/_internal/commands/download.py index 01ebf6a55..e48a7838c 100644 --- a/src/pip/_internal/commands/download.py +++ b/src/pip/_internal/commands/download.py @@ -6,7 +6,7 @@ import os from pip._internal.cli import cmdoptions from pip._internal.cli.cmdoptions import make_target_python from pip._internal.cli.req_command import RequirementCommand, with_cleanup -from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.cli.status_codes import SUCCESS from pip._internal.req.req_tracker import get_requirement_tracker from pip._internal.utils.misc import ensure_dir, normalize_path, write_output from pip._internal.utils.temp_dir import TempDirectory @@ -143,6 +143,5 @@ class DownloadCommand(RequirementCommand): if req.successfully_downloaded]) if downloaded: write_output('Successfully downloaded %s', downloaded) - return SUCCESS - return ERROR + return SUCCESS diff --git a/tests/functional/test_download.py b/tests/functional/test_download.py index 2b6ff8e9d..05b97ab3a 100644 --- a/tests/functional/test_download.py +++ b/tests/functional/test_download.py @@ -666,9 +666,7 @@ def test_download_exit_status_code_when_blank_requirements_file(script): Test download exit status code when blank requirements file specified """ script.scratch_path.joinpath("blank.txt").write_text("\n") - result = script.pip('download', '-r', 'blank.txt', expect_error=True) - print(result) - assert result.returncode == ERROR + script.pip('download', '-r', 'blank.txt') def test_download_prefer_binary_when_tarball_higher_than_wheel(script, data):