1
1
Fork 0
mirror of https://github.com/pypa/pip synced 2023-12-13 21:30:23 +01:00

Complete typing of some tests/lib/* files

This commit is contained in:
Jon Dufresne 2021-08-25 07:02:26 -07:00
parent ed9c0d96ec
commit 34a3838b73
8 changed files with 89 additions and 62 deletions

View file

@ -88,7 +88,7 @@ class Command(CommandContextMixIn):
def run(self, options: Values, args: List[Any]) -> int: def run(self, options: Values, args: List[Any]) -> int:
raise NotImplementedError raise NotImplementedError
def parse_args(self, args: List[str]) -> Tuple[Any, Any]: def parse_args(self, args: List[str]) -> Tuple[Values, List[str]]:
# factored out for testability # factored out for testability
return self.parser.parse_args(args) return self.parser.parse_args(args)

View file

@ -1,9 +1,11 @@
import re import re
from typing import Optional
from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl
from tests.lib import TestPipResult
def get_created_direct_url(result, pkg): def get_created_direct_url(result: TestPipResult, pkg: str) -> Optional[DirectUrl]:
direct_url_metadata_re = re.compile( direct_url_metadata_re = re.compile(
pkg + r"-[\d\.]+\.dist-info." + DIRECT_URL_METADATA_NAME + r"$" pkg + r"-[\d\.]+\.dist-info." + DIRECT_URL_METADATA_NAME + r"$"
) )

View file

@ -6,11 +6,12 @@ import subprocess
import sys import sys
from functools import partial from functools import partial
from itertools import chain from itertools import chain
from typing import Iterator, List, Set
from .path import Path from .path import Path
def make_socket_file(path): def make_socket_file(path: str) -> None:
# Socket paths are limited to 108 characters (sometimes less) so we # Socket paths are limited to 108 characters (sometimes less) so we
# chdir before creating it and use a relative path name. # chdir before creating it and use a relative path name.
cwd = os.getcwd() cwd = os.getcwd()
@ -22,7 +23,7 @@ def make_socket_file(path):
os.chdir(cwd) os.chdir(cwd)
def make_unreadable_file(path): def make_unreadable_file(path: str) -> None:
Path(path).touch() Path(path).touch()
os.chmod(path, 0o000) os.chmod(path, 0o000)
if sys.platform == "win32": if sys.platform == "win32":
@ -34,8 +35,8 @@ def make_unreadable_file(path):
subprocess.check_call(args) subprocess.check_call(args)
def get_filelist(base): def get_filelist(base: str) -> Set[str]:
def join(dirpath, dirnames, filenames): def join(dirpath: str, dirnames: List[str], filenames: List[str]) -> Iterator[str]:
relative_dirpath = os.path.relpath(dirpath, base) relative_dirpath = os.path.relpath(dirpath, base)
join_dirpath = partial(os.path.join, relative_dirpath) join_dirpath = partial(os.path.join, relative_dirpath)
return chain( return chain(

View file

@ -1,8 +1,12 @@
from typing import Optional
from pip._internal.models.candidate import InstallationCandidate from pip._internal.models.candidate import InstallationCandidate
from pip._internal.models.link import Link from pip._internal.models.link import Link
def make_mock_candidate(version, yanked_reason=None, hex_digest=None): def make_mock_candidate(
version: str, yanked_reason: Optional[str] = None, hex_digest: Optional[str] = None
) -> InstallationCandidate:
url = f"https://example.com/pkg-{version}.tar.gz" url = f"https://example.com/pkg-{version}.tar.gz"
if hex_digest is not None: if hex_digest is not None:
assert len(hex_digest) == 64 assert len(hex_digest) == 64

View file

@ -1,13 +1,18 @@
"""Provides helper classes for testing option handling in pip """Provides helper classes for testing option handling in pip
""" """
from optparse import Values
from typing import List, Tuple
from pip._internal.cli import cmdoptions from pip._internal.cli import cmdoptions
from pip._internal.cli.base_command import Command from pip._internal.cli.base_command import Command
from pip._internal.commands import CommandInfo, commands_dict from pip._internal.commands import CommandInfo, commands_dict
class FakeCommand(Command): class FakeCommand(Command):
def main(self, args): def main( # type: ignore[override]
self, args: List[str]
) -> Tuple[Values, List[str]]:
index_opts = cmdoptions.make_option_group( index_opts = cmdoptions.make_option_group(
cmdoptions.index_group, cmdoptions.index_group,
self.parser, self.parser,
@ -17,12 +22,12 @@ class FakeCommand(Command):
class AddFakeCommandMixin: class AddFakeCommandMixin:
def setup(self): def setup(self) -> None:
commands_dict["fake"] = CommandInfo( commands_dict["fake"] = CommandInfo(
"tests.lib.options_helpers", "tests.lib.options_helpers",
"FakeCommand", "FakeCommand",
"fake summary", "fake summary",
) )
def teardown(self): def teardown(self) -> None:
commands_dict.pop("fake") commands_dict.pop("fake")

View file

@ -1,12 +1,7 @@
# flake8: noqa
# Author: Aziz Köksal # Author: Aziz Köksal
import glob import glob
import os import os
from typing import Iterable, Iterator, Union
try:
from os import supports_fd
except ImportError:
supports_fd = set()
class Path(str): class Path(str):
@ -20,12 +15,12 @@ class Path(str):
# Separator in the PATH environment variable. # Separator in the PATH environment variable.
pathsep = os.pathsep pathsep = os.pathsep
def __new__(cls, *paths): def __new__(cls, *paths: str) -> "Path":
if len(paths): if len(paths):
return super().__new__(cls, os.path.join(*paths)) return super().__new__(cls, os.path.join(*paths))
return super().__new__(cls) return super().__new__(cls)
def __div__(self, path): def __div__(self, path: str) -> "Path":
""" """
Joins this path with another path. Joins this path with another path.
@ -36,7 +31,7 @@ class Path(str):
__truediv__ = __div__ __truediv__ = __div__
def __rdiv__(self, path): def __rdiv__(self, path: str) -> "Path":
""" """
Joins this path with another path. Joins this path with another path.
@ -46,7 +41,7 @@ class Path(str):
__rtruediv__ = __rdiv__ __rtruediv__ = __rdiv__
def __idiv__(self, path): def __idiv__(self, path: str) -> "Path":
""" """
Like __div__ but also assigns to the variable. Like __div__ but also assigns to the variable.
@ -56,52 +51,52 @@ class Path(str):
__itruediv__ = __idiv__ __itruediv__ = __idiv__
def __add__(self, path): def __add__(self, path: str) -> "Path":
""" """
>>> Path('/home/a') + 'bc.d' >>> Path('/home/a') + 'bc.d'
'/home/abc.d' '/home/abc.d'
""" """
return Path(str(self) + path) return Path(str(self) + path)
def __radd__(self, path): def __radd__(self, path: str) -> "Path":
""" """
>>> '/home/a' + Path('bc.d') >>> '/home/a' + Path('bc.d')
'/home/abc.d' '/home/abc.d'
""" """
return Path(path + str(self)) return Path(path + str(self))
def __repr__(self): def __repr__(self) -> str:
return "Path({inner})".format(inner=str.__repr__(self)) return "Path({inner})".format(inner=str.__repr__(self))
@property @property
def name(self): def name(self) -> str:
""" """
'/home/a/bc.d' -> 'bc.d' '/home/a/bc.d' -> 'bc.d'
""" """
return os.path.basename(self) return os.path.basename(self)
@property @property
def stem(self): def stem(self) -> str:
""" """
'/home/a/bc.d' -> 'bc' '/home/a/bc.d' -> 'bc'
""" """
return Path(os.path.splitext(self)[0]).name return Path(os.path.splitext(self)[0]).name
@property @property
def suffix(self): def suffix(self) -> str:
""" """
'/home/a/bc.d' -> '.d' '/home/a/bc.d' -> '.d'
""" """
return Path(os.path.splitext(self)[1]) return Path(os.path.splitext(self)[1])
def resolve(self): def resolve(self) -> "Path":
""" """
Resolves symbolic links. Resolves symbolic links.
""" """
return Path(os.path.realpath(self)) return Path(os.path.realpath(self))
@property @property
def parent(self): def parent(self) -> "Path":
""" """
Returns the parent directory of this path. Returns the parent directory of this path.
@ -111,13 +106,18 @@ class Path(str):
""" """
return Path(os.path.dirname(self)) return Path(os.path.dirname(self))
def exists(self): def exists(self) -> bool:
""" """
Returns True if the path exists. Returns True if the path exists.
""" """
return os.path.exists(self) return os.path.exists(self)
def mkdir(self, mode=0x1FF, exist_ok=False, parents=False): # 0o777 def mkdir(
self,
mode: int = 0o777,
exist_ok: bool = False,
parents: bool = False,
) -> None:
""" """
Creates a directory, if it doesn't exist already. Creates a directory, if it doesn't exist already.
@ -131,32 +131,32 @@ class Path(str):
if not exist_ok or not os.path.isdir(self): if not exist_ok or not os.path.isdir(self):
raise raise
def unlink(self): def unlink(self) -> None:
""" """
Removes a file. Removes a file.
""" """
return os.remove(self) os.remove(self)
def rmdir(self): def rmdir(self) -> None:
""" """
Removes a directory. Removes a directory.
""" """
return os.rmdir(self) os.rmdir(self)
def rename(self, to): def rename(self, to: str) -> None:
""" """
Renames a file or directory. May throw an OSError. Renames a file or directory. May throw an OSError.
""" """
return os.rename(self, to) os.rename(self, to)
def glob(self, pattern): def glob(self, pattern: str) -> Iterator["Path"]:
return (Path(i) for i in glob.iglob(self.joinpath(pattern))) return (Path(i) for i in glob.iglob(self.joinpath(pattern)))
def joinpath(self, *parts): def joinpath(self, *parts: str) -> "Path":
return Path(self, *parts) return Path(self, *parts)
# TODO: Remove after removing inheritance from str. # TODO: Remove after removing inheritance from str.
def join(self, *parts): def join(self, parts: Iterable[str]) -> str:
raise RuntimeError("Path.join is invalid, use joinpath instead.") raise RuntimeError("Path.join is invalid, use joinpath instead.")
def read_bytes(self) -> bytes: def read_bytes(self) -> bytes:
@ -167,23 +167,23 @@ class Path(str):
with open(self, "wb") as f: with open(self, "wb") as f:
f.write(content) f.write(content)
def read_text(self): def read_text(self) -> str:
with open(self, "r") as fp: with open(self, "r") as fp:
return fp.read() return fp.read()
def write_text(self, content): def write_text(self, content: str) -> None:
with open(self, "w") as fp: with open(self, "w") as fp:
fp.write(content) fp.write(content)
def touch(self): def touch(self) -> None:
with open(self, "a") as fp: with open(self, "a") as fp:
path = fp.fileno() if os.utime in supports_fd else self path: Union[int, str] = fp.fileno() if os.utime in os.supports_fd else self
os.utime(path, None) # times is not optional on Python 2.7 os.utime(path)
def symlink_to(self, target): def symlink_to(self, target: str) -> None:
os.symlink(target, self) os.symlink(target, self)
def stat(self): def stat(self) -> os.stat_result:
return os.stat(self) return os.stat(self)

View file

@ -4,11 +4,16 @@ import subprocess
import sys import sys
import textwrap import textwrap
import venv as _venv import venv as _venv
from typing import TYPE_CHECKING, Optional
import virtualenv as _virtualenv import virtualenv as _virtualenv
from .path import Path from .path import Path
if TYPE_CHECKING:
# Literal was introduced in Python 3.8.
from typing import Literal
class VirtualEnvironment: class VirtualEnvironment:
""" """
@ -16,18 +21,28 @@ class VirtualEnvironment:
virtualenv but in the future it could use pyvenv. virtualenv but in the future it could use pyvenv.
""" """
def __init__(self, location, template=None, venv_type=None): def __init__(
assert template is None or venv_type is None self,
assert venv_type in (None, "virtualenv", "venv") location: str,
template: Optional["VirtualEnvironment"] = None,
venv_type: 'Literal[None, "virtualenv", "venv"]' = None,
):
self.location = Path(location) self.location = Path(location)
self._venv_type = venv_type or template._venv_type or "virtualenv" assert template is None or venv_type is None
self._venv_type: Literal["virtualenv", "venv"]
if template is not None:
self._venv_type = template._venv_type
elif venv_type is not None:
self._venv_type = venv_type
else:
self._venv_type = "virtualenv"
self._user_site_packages = False self._user_site_packages = False
self._template = template self._template = template
self._sitecustomize = None self._sitecustomize: Optional[str] = None
self._update_paths() self._update_paths()
self._create() self._create()
def _update_paths(self): def _update_paths(self) -> None:
home, lib, inc, bin = _virtualenv.path_locations(self.location) home, lib, inc, bin = _virtualenv.path_locations(self.location)
self.bin = Path(bin) self.bin = Path(bin)
self.site = Path(lib) / "site-packages" self.site = Path(lib) / "site-packages"
@ -38,10 +53,10 @@ class VirtualEnvironment:
else: else:
self.lib = Path(lib) self.lib = Path(lib)
def __repr__(self): def __repr__(self) -> str:
return f"<VirtualEnvironment {self.location}>" return f"<VirtualEnvironment {self.location}>"
def _create(self, clear=False): def _create(self, clear: bool = False) -> None:
if clear: if clear:
shutil.rmtree(self.location) shutil.rmtree(self.location)
if self._template: if self._template:
@ -77,7 +92,7 @@ class VirtualEnvironment:
self.sitecustomize = self._sitecustomize self.sitecustomize = self._sitecustomize
self.user_site_packages = self._user_site_packages self.user_site_packages = self._user_site_packages
def _fix_virtualenv_site_module(self): def _fix_virtualenv_site_module(self) -> None:
# Patch `site.py` so user site work as expected. # Patch `site.py` so user site work as expected.
site_py = self.lib / "site.py" site_py = self.lib / "site.py"
with open(site_py) as fp: with open(site_py) as fp:
@ -111,7 +126,7 @@ class VirtualEnvironment:
# Make sure bytecode is up-to-date too. # Make sure bytecode is up-to-date too.
assert compileall.compile_file(str(site_py), quiet=1, force=True) assert compileall.compile_file(str(site_py), quiet=1, force=True)
def _customize_site(self): def _customize_site(self) -> None:
contents = "" contents = ""
if self._venv_type == "venv": if self._venv_type == "venv":
# Enable user site (before system). # Enable user site (before system).
@ -149,29 +164,29 @@ class VirtualEnvironment:
# Make sure bytecode is up-to-date too. # Make sure bytecode is up-to-date too.
assert compileall.compile_file(str(sitecustomize), quiet=1, force=True) assert compileall.compile_file(str(sitecustomize), quiet=1, force=True)
def clear(self): def clear(self) -> None:
self._create(clear=True) self._create(clear=True)
def move(self, location): def move(self, location: str) -> None:
shutil.move(self.location, location) shutil.move(self.location, location)
self.location = Path(location) self.location = Path(location)
self._update_paths() self._update_paths()
@property @property
def sitecustomize(self): def sitecustomize(self) -> Optional[str]:
return self._sitecustomize return self._sitecustomize
@sitecustomize.setter @sitecustomize.setter
def sitecustomize(self, value): def sitecustomize(self, value: str) -> None:
self._sitecustomize = value self._sitecustomize = value
self._customize_site() self._customize_site()
@property @property
def user_site_packages(self): def user_site_packages(self) -> bool:
return self._user_site_packages return self._user_site_packages
@user_site_packages.setter @user_site_packages.setter
def user_site_packages(self, value): def user_site_packages(self, value: bool) -> None:
self._user_site_packages = value self._user_site_packages = value
if self._venv_type == "virtualenv": if self._venv_type == "virtualenv":
marker = self.lib / "no-global-site-packages.txt" marker = self.lib / "no-global-site-packages.txt"