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:
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
return self.parser.parse_args(args)

View File

@ -1,9 +1,11 @@
import re
from typing import Optional
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(
pkg + r"-[\d\.]+\.dist-info." + DIRECT_URL_METADATA_NAME + r"$"
)

View File

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

View File

@ -1,8 +1,12 @@
from typing import Optional
from pip._internal.models.candidate import InstallationCandidate
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"
if hex_digest is not None:
assert len(hex_digest) == 64

View File

@ -1,13 +1,18 @@
"""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.base_command import Command
from pip._internal.commands import CommandInfo, commands_dict
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(
cmdoptions.index_group,
self.parser,
@ -17,12 +22,12 @@ class FakeCommand(Command):
class AddFakeCommandMixin:
def setup(self):
def setup(self) -> None:
commands_dict["fake"] = CommandInfo(
"tests.lib.options_helpers",
"FakeCommand",
"fake summary",
)
def teardown(self):
def teardown(self) -> None:
commands_dict.pop("fake")

View File

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

View File

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