Commit 1346497b by finswimmer

fix and add several type hints

parent a106cb21
......@@ -19,11 +19,11 @@ from .dict_config_source import DictConfigSource
_NOT_SET = object()
def boolean_validator(val):
def boolean_validator(val): # type: (str) -> bool
return val in {"true", "false", "1", "0"}
def boolean_normalizer(val):
def boolean_normalizer(val): # type: (str) -> bool
return val in ["true", "1"]
......@@ -51,11 +51,11 @@ class Config(object):
self._auth_config_source = DictConfigSource()
@property
def name(self):
def name(self): # type: () -> str
return str(self._file.path)
@property
def config(self):
def config(self): # type: () -> Dict
return self._config
@property
......@@ -82,7 +82,7 @@ class Config(object):
merge_dicts(self._config, config)
def all(self): # type: () -> Dict[str, Any]
def _all(config, parent_key=""):
def _all(config, parent_key=""): # type: (Dict, str) -> Dict
all_ = {}
for key in config:
......
from contextlib import contextmanager
from typing import TYPE_CHECKING
from typing import Any
from typing import Generator
from tomlkit import document
from tomlkit import table
......@@ -9,6 +10,8 @@ from .config_source import ConfigSource
if TYPE_CHECKING:
from tomlkit.toml_document import TOMLDocument # noqa
from poetry.core.toml.file import TOMLFile # noqa
......@@ -56,7 +59,7 @@ class FileConfigSource(ConfigSource):
current_config = current_config[key]
@contextmanager
def secure(self):
def secure(self): # type: () -> Generator["TOMLDocument"]
if self.file.exists():
initial_config = self.file.read()
config = self.file.read()
......
from .application import Application
def main():
def main(): # type: () -> int
return Application().run()
import sys
from typing import TYPE_CHECKING
from cleo import Application as BaseApplication
from poetry.__version__ import __version__
......@@ -29,8 +31,12 @@ from .commands.version import VersionCommand
from .config import ApplicationConfig
if TYPE_CHECKING:
from poetry.poetry import Poetry # noqa
class Application(BaseApplication):
def __init__(self):
def __init__(self): # type: () -> None
super(Application, self).__init__(
"poetry", __version__, config=ApplicationConfig("poetry", __version__)
)
......@@ -59,7 +65,7 @@ class Application(BaseApplication):
self._preliminary_io.error_line("<fg=yellow>{}</>\n".format(message))
@property
def poetry(self):
def poetry(self): # type: () -> "Poetry"
from pathlib import Path
from poetry.factory import Factory
......
......@@ -7,7 +7,7 @@ class AboutCommand(Command):
description = "Shows information about Poetry."
def handle(self):
def handle(self): # type: () -> None
self.line(
"""<info>Poetry - Package Management for Python</info>
......
......@@ -68,7 +68,7 @@ class AddCommand(InstallerCommand, InitCommand):
loggers = ["poetry.repositories.pypi_repository", "poetry.inspection.info"]
def handle(self):
def handle(self): # type: () -> int
from tomlkit import inline_table
from poetry.core.semver import parse_constraint
......
......@@ -18,7 +18,7 @@ class BuildCommand(EnvCommand):
"poetry.core.masonry.builders.wheel",
]
def handle(self):
def handle(self): # type: () -> None
from poetry.core.masonry import Builder
fmt = "all"
......
......@@ -11,5 +11,5 @@ class CacheCommand(Command):
commands = [CacheClearCommand(), CacheListCommand()]
def handle(self):
def handle(self): # type: () -> int
return self.call("help", self._config.name)
......@@ -14,7 +14,7 @@ class CacheClearCommand(Command):
arguments = [argument("cache", description="The name of the cache to clear.")]
options = [option("all", description="Clear all entries in the cache.")]
def handle(self):
def handle(self): # type: () -> int
from cachy import CacheManager
from poetry.locations import REPOSITORY_CACHE_DIR
......
import os
from typing import Optional
from ..command import Command
......@@ -8,7 +10,7 @@ class CacheListCommand(Command):
name = "list"
description = "List Poetry's caches."
def handle(self):
def handle(self): # type: () -> Optional[int]
from poetry.locations import REPOSITORY_CACHE_DIR
if os.path.exists(str(REPOSITORY_CACHE_DIR)):
......
......@@ -11,7 +11,7 @@ class CheckCommand(Command):
name = "check"
description = "Checks the validity of the <comment>pyproject.toml</comment> file."
def handle(self):
def handle(self): # type: () -> int
# Load poetry config and display errors, if any
poetry_file = Factory.locate(Path.cwd())
config = PyProjectTOML(poetry_file).poetry_config
......
from typing import TYPE_CHECKING
from cleo import Command as BaseCommand
if TYPE_CHECKING:
from poetry.poetry import Poetry # noqa
class Command(BaseCommand):
loggers = []
@property
def poetry(self):
def poetry(self): # type: () -> "Poetry"
return self.application.poetry
def reset_poetry(self): # type: () -> None
......
import json
import re
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple
from cleo import argument
from cleo import option
......@@ -11,6 +18,10 @@ from poetry.factory import Factory
from .command import Command
if TYPE_CHECKING:
from poetry.config.config_source import ConfigSource # noqa
class ConfigCommand(Command):
name = "config"
......@@ -40,7 +51,7 @@ To remove a repository (repo is a short alias for repositories):
LIST_PROHIBITED_SETTINGS = {"http-basic", "pypi-token"}
@property
def unique_config_values(self):
def unique_config_values(self): # type: () -> Dict[str, Tuple[Any, Any, Any]]
from pathlib import Path
from poetry.config.config import boolean_normalizer
......@@ -75,7 +86,7 @@ To remove a repository (repo is a short alias for repositories):
return unique_config_values
def handle(self):
def handle(self): # type: () -> Optional[int]
from pathlib import Path
from poetry.config.file_config_source import FileConfigSource
......@@ -253,7 +264,9 @@ To remove a repository (repo is a short alias for repositories):
raise ValueError("Setting {} does not exist".format(self.argument("key")))
def _handle_single_value(self, source, key, callbacks, values):
def _handle_single_value(
self, source, key, callbacks, values
): # type: ("ConfigSource", str, Tuple[Any, Any, Any], List[Any]) -> int
validator, normalizer, _ = callbacks
if len(values) > 1:
......@@ -267,7 +280,7 @@ To remove a repository (repo is a short alias for repositories):
return 0
def _list_configuration(self, config, raw, k=""):
def _list_configuration(self, config, raw, k=""): # type: (Dict, Dict, str) -> None
orig_k = k
for key, value in sorted(config.items()):
if k + key in self.LIST_PROHIBITED_SETTINGS:
......@@ -301,7 +314,9 @@ To remove a repository (repo is a short alias for repositories):
self.line(message)
def _get_setting(self, contents, setting=None, k=None, default=None):
def _get_setting(
self, contents, setting=None, k=None, default=None
): # type: (Dict, Optional[str], Optional[str], Optional[Any]) -> List[Tuple[str, str]]
orig_k = k
if setting and setting.split(".")[0] not in contents:
......
......@@ -10,7 +10,7 @@ class DebugInfoCommand(Command):
name = "info"
description = "Shows debug information."
def handle(self):
def handle(self): # type: () -> int
poetry_python_version = ".".join(str(s) for s in sys.version_info[:3])
self.line("")
......
from typing import Optional
from cleo import argument
from cleo import option
......@@ -27,7 +29,7 @@ class DebugResolveCommand(InitCommand):
loggers = ["poetry.repositories.pypi_repository", "poetry.inspection.info"]
def handle(self):
def handle(self): # type: () -> Optional[int]
from poetry.core.packages.project_package import ProjectPackage
from poetry.factory import Factory
from poetry.io.null_io import NullIO
......
from typing import TYPE_CHECKING
from typing import Optional
from cleo import option
from ..command import Command
if TYPE_CHECKING:
from poetry.utils.env import Env # noqa
class EnvInfoCommand(Command):
name = "info"
......@@ -10,7 +17,7 @@ class EnvInfoCommand(Command):
options = [option("path", "p", "Only display the environment's path.")]
def handle(self):
def handle(self): # type: () -> Optional[int]
from poetry.utils.env import EnvManager
env = EnvManager(self.poetry).get()
......@@ -25,7 +32,7 @@ class EnvInfoCommand(Command):
self._display_complete_info(env)
def _display_complete_info(self, env):
def _display_complete_info(self, env): # type: ("Env") -> None
env_python_version = ".".join(str(s) for s in env.version_info[:3])
self.line("")
self.line("<b>Virtualenv</b>")
......
......@@ -10,7 +10,7 @@ class EnvListCommand(Command):
options = [option("full-path", None, "Output the full paths of the virtualenvs.")]
def handle(self):
def handle(self): # type: () -> None
from poetry.utils.env import EnvManager
manager = EnvManager(self.poetry)
......
......@@ -12,7 +12,7 @@ class EnvRemoveCommand(Command):
argument("python", "The python executable to remove the virtualenv for.")
]
def handle(self):
def handle(self): # type: () -> None
from poetry.utils.env import EnvManager
manager = EnvManager(self.poetry)
......
......@@ -10,7 +10,7 @@ class EnvUseCommand(Command):
arguments = [argument("python", "The python executable to use.")]
def handle(self):
def handle(self): # type: () -> None
from poetry.utils.env import EnvManager
manager = EnvManager(self.poetry)
......
from typing import TYPE_CHECKING
from .command import Command
if TYPE_CHECKING:
from poetry.utils.env import VirtualEnv # noqa
class EnvCommand(Command):
def __init__(self):
def __init__(self): # type: () -> None
self._env = None
super(EnvCommand, self).__init__()
@property
def env(self):
def env(self): # type: () -> "VirtualEnv"
return self._env
def set_env(self, env):
def set_env(self, env): # type: ("VirtualEnv") -> None
self._env = env
......@@ -31,7 +31,7 @@ class ExportCommand(Command):
option("with-credentials", None, "Include credentials for extra indices."),
]
def handle(self):
def handle(self): # type: () -> None
fmt = self.option("format")
if fmt not in Exporter.ACCEPTED_FORMATS:
......
......@@ -9,6 +9,7 @@ import urllib.parse
from pathlib import Path
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple
from typing import Union
......@@ -56,12 +57,12 @@ class InitCommand(Command):
The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the current directory.
"""
def __init__(self):
def __init__(self): # type: () -> None
super(InitCommand, self).__init__()
self._pool = None
def handle(self):
def handle(self): # type: () -> int
from pathlib import Path
from poetry.core.vcs.git import GitConfig
......@@ -227,7 +228,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
def _determine_requirements(
self, requires, allow_prereleases=False, source=None
): # type: (List[str], bool) -> List[Dict[str, str]]
): # type: (List[str], bool, Optional[str]) -> List[Dict[str, Union[str, List[str]]]]
if not requires:
requires = []
......@@ -354,7 +355,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
def _find_best_version_for_package(
self, name, required_version=None, allow_prereleases=False, source=None
): # type: (...) -> Tuple[str, str]
): # type: (str, Optional[str], bool, Optional[str]) -> Tuple[str, str]
from poetry.version.version_selector import VersionSelector
selector = VersionSelector(self._get_pool())
......@@ -505,7 +506,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
return requires
def _validate_author(self, author, default):
def _validate_author(self, author, default): # type: (str, str) -> Optional[str]
from poetry.core.packages.package import AUTHOR_REGEX
author = author or default
......@@ -522,7 +523,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
return author
def _validate_license(self, license):
def _validate_license(self, license): # type: (str) -> str
from poetry.core.spdx import license_by_id
if license:
......@@ -530,7 +531,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
return license
def _get_pool(self):
def _get_pool(self): # type: () -> "Pool"
from poetry.repositories import Pool
from poetry.repositories.pypi_repository import PyPiRepository
......
......@@ -47,7 +47,7 @@ dependencies and not including the current project, run the command with the
_loggers = ["poetry.repositories.pypi_repository", "poetry.inspection.info"]
def handle(self):
def handle(self): # type: () -> int
from poetry.core.masonry.utils.module import ModuleOrPackageNotFound
from poetry.masonry.builders import EditableBuilder
......
......@@ -9,12 +9,12 @@ if TYPE_CHECKING:
class InstallerCommand(EnvCommand):
def __init__(self):
def __init__(self): # type: () -> None
self._installer = None # type: Optional[Installer]
super(InstallerCommand, self).__init__()
def reset_poetry(self):
def reset_poetry(self): # type: () -> None
super(InstallerCommand, self).reset_poetry()
self._installer.set_package(self.poetry.package)
......
......@@ -24,7 +24,7 @@ file.
loggers = ["poetry.repositories.pypi_repository"]
def handle(self):
def handle(self): # type: () -> int
self._installer.use_executor(
self.poetry.config.get("experimental.new-installer", False)
)
......
......@@ -19,7 +19,7 @@ class NewCommand(Command):
option("src", None, "Use the src layout for the project."),
]
def handle(self):
def handle(self): # type: () -> None
from pathlib import Path
from poetry.core.semver import parse_constraint
......
from pathlib import Path
from typing import Optional
from cleo import option
......@@ -40,7 +41,7 @@ the config command.
loggers = ["poetry.masonry.publishing.publisher"]
def handle(self):
def handle(self): # type: () -> Optional[int]
from poetry.publishing.publisher import Publisher
publisher = Publisher(self.poetry, self.io)
......
......@@ -27,7 +27,7 @@ list of installed packages
loggers = ["poetry.repositories.pypi_repository", "poetry.inspection.info"]
def handle(self):
def handle(self): # type: () -> int
packages = self.argument("packages")
is_dev = self.option("dev")
......
from typing import Any
from typing import Union
from cleo import argument
from .env_command import EnvCommand
......@@ -19,7 +22,7 @@ class RunCommand(EnvCommand):
self.config.set_args_parser(RunArgsParser())
def handle(self):
def handle(self): # type: () -> Any
args = self.argument("args")
script = args[0]
scripts = self.poetry.local_config.get("scripts")
......@@ -29,7 +32,7 @@ class RunCommand(EnvCommand):
return self.env.execute(*args)
def run_script(self, script, args):
def run_script(self, script, args): # type: (Union[str, dict], str) -> Any
if isinstance(script, dict):
script = script["callable"]
......
......@@ -10,7 +10,7 @@ class SearchCommand(Command):
arguments = [argument("tokens", "The tokens to search for.", multiple=True)]
def handle(self):
def handle(self): # type: () -> None
from poetry.repositories.pypi_repository import PyPiRepository
results = PyPiRepository().search(self.argument("tokens"))
......
......@@ -9,5 +9,5 @@ class SelfCommand(Command):
commands = [SelfUpdateCommand()]
def handle(self):
def handle(self): # type: () -> int
return self.call("help", self._config.name)
......@@ -11,6 +11,8 @@ import tarfile
from functools import cmp_to_key
from gzip import GzipFile
from typing import TYPE_CHECKING
from typing import Any
from cleo import argument
from cleo import option
......@@ -20,6 +22,12 @@ from poetry.core.packages import Dependency
from ..command import Command
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
from poetry.core.semver import Version
from poetry.utils._compat import Path
try:
from urllib.error import HTTPError
from urllib.request import urlopen
......@@ -61,24 +69,24 @@ class SelfUpdateCommand(Command):
BASE_URL = REPOSITORY_URL + "/releases/download"
@property
def home(self):
def home(self): # type: () -> Path
from pathlib import Path
return Path(os.environ.get("POETRY_HOME", "~/.poetry")).expanduser()
@property
def bin(self):
def bin(self): # type: () -> Path
return self.home / "bin"
@property
def lib(self):
def lib(self): # type: () -> Path
return self.home / "lib"
@property
def lib_backup(self):
def lib_backup(self): # type: () -> Path
return self.home / "lib-backup"
def handle(self):
def handle(self): # type: () -> None
from poetry.__version__ import __version__
from poetry.core.semver import Version
from poetry.repositories.pypi_repository import PyPiRepository
......@@ -129,7 +137,7 @@ class SelfUpdateCommand(Command):
self.update(release)
def update(self, release):
def update(self, release): # type: ("Package") -> None
version = release.version
self.line("Updating to <info>{}</info>".format(version))
......@@ -165,7 +173,7 @@ class SelfUpdateCommand(Command):
)
)
def _update(self, version):
def _update(self, version): # type: ("Version") -> None
from poetry.utils.helpers import temporary_directory
release_name = self._get_release_name(version)
......@@ -235,10 +243,10 @@ class SelfUpdateCommand(Command):
finally:
gz.close()
def process(self, *args):
def process(self, *args): # type: (*Any) -> str
return subprocess.check_output(list(args), stderr=subprocess.STDOUT)
def _check_recommended_installation(self):
def _check_recommended_installation(self): # type: () -> None
from pathlib import Path
current = Path(__file__)
......@@ -250,14 +258,14 @@ class SelfUpdateCommand(Command):
"Cannot update automatically."
)
def _get_release_name(self, version):
def _get_release_name(self, version): # type: ("Version") -> str
platform = sys.platform
if platform == "linux2":
platform = "linux"
return "poetry-{}-{}".format(version, platform)
def make_bin(self):
def make_bin(self): # type: () -> None
from poetry.utils._compat import WINDOWS
self.bin.mkdir(0o755, parents=True, exist_ok=True)
......@@ -286,7 +294,7 @@ class SelfUpdateCommand(Command):
st = os.stat(str(self.bin.joinpath("poetry")))
os.chmod(str(self.bin.joinpath("poetry")), st.st_mode | stat.S_IEXEC)
def _which_python(self):
def _which_python(self): # type: () -> str
"""
Decides which python executable we'll embed in the launcher script.
"""
......
......@@ -16,7 +16,7 @@ class ShellCommand(EnvCommand):
If one doesn't exist yet, it will be created.
"""
def handle(self):
def handle(self): # type: () -> None
from poetry.utils.shell import Shell
# Check if it's already activated or doesn't exist and won't be created
......
# -*- coding: utf-8 -*-
from typing import TYPE_CHECKING
from typing import List
from typing import Optional
from typing import Union
from cleo import argument
from cleo import option
from .env_command import EnvCommand
if TYPE_CHECKING:
from clikit.api.io import IO # noqa
from poetry.core.packages import Dependency # noqa
from poetry.core.packages import Package # noqa
from poetry.repositories import Repository
from poetry.repositories.installed_repository import InstalledRepository
class ShowCommand(EnvCommand):
name = "show"
......@@ -32,7 +46,7 @@ lists all packages available."""
colors = ["cyan", "yellow", "green", "magenta", "blue"]
def handle(self):
def handle(self): # type: () -> Optional[int]
from clikit.utils.terminal import Terminal
from poetry.io.null_io import NullIO
......@@ -257,7 +271,9 @@ lists all packages available."""
self.line(line)
def display_package_tree(self, io, package, installed_repo):
def display_package_tree(
self, io, package, installed_repo
): # type: ("IO", "Package", "Repository") -> None
io.write("<c1>{}</c1>".format(package.pretty_name))
description = ""
if package.description:
......@@ -294,13 +310,13 @@ lists all packages available."""
def _display_tree(
self,
io,
dependency,
installed_repo,
packages_in_tree,
previous_tree_bar="├",
level=1,
):
io, # type: "IO"
dependency, # type: "Dependency"
installed_repo, # type: "Repository"
packages_in_tree, # type: List[str]
previous_tree_bar="├", # type: str
level=1, # type: int
): # type: (...) -> None
previous_tree_bar = previous_tree_bar.replace("├", "│")
dependencies = []
......@@ -345,7 +361,7 @@ lists all packages available."""
io, dependency, installed_repo, current_tree, tree_bar, level + 1
)
def _write_tree_line(self, io, line):
def _write_tree_line(self, io, line): # type: ("IO", str) -> None
if not io.output.supports_ansi():
line = line.replace("└", "`-")
line = line.replace("├", "|-")
......@@ -354,7 +370,7 @@ lists all packages available."""
io.write_line(line)
def init_styles(self, io):
def init_styles(self, io): # type: ("IO") -> None
from clikit.api.formatter import Style
for color in self.colors:
......@@ -362,7 +378,9 @@ lists all packages available."""
io.output.formatter.add_style(style)
io.error_output.formatter.add_style(style)
def find_latest_package(self, package, include_dev):
def find_latest_package(
self, package, include_dev
): # type: ("Package", bool) -> Union["Package", bool]
from clikit.io import NullIO
from poetry.puzzle.provider import Provider
......@@ -390,7 +408,7 @@ lists all packages available."""
return selector.find_best_candidate(name, ">={}".format(package.pretty_version))
def get_update_status(self, latest, package):
def get_update_status(self, latest, package): # type: ("Package", "Package") -> str
from poetry.core.semver import parse_constraint
if latest.full_pretty_version == package.full_pretty_version:
......@@ -405,7 +423,9 @@ lists all packages available."""
# it needs an upgrade but has potential BC breaks so is not urgent
return "update-possible"
def get_installed_status(self, locked, installed_repo):
def get_installed_status(
self, locked, installed_repo
): # type: ("Package", "InstalledRepository") -> str
for package in installed_repo.packages:
if locked.name == package.name:
return "installed"
......
......@@ -27,7 +27,7 @@ class UpdateCommand(InstallerCommand):
loggers = ["poetry.repositories.pypi_repository"]
def handle(self):
def handle(self): # type: () -> int
packages = self.argument("packages")
self._installer.use_executor(
......
......@@ -40,7 +40,7 @@ patch, minor, major, prepatch, preminor, premajor, prerelease.
"prerelease",
}
def handle(self):
def handle(self): # type: () -> None
version = self.argument("version")
if version:
......@@ -72,7 +72,7 @@ patch, minor, major, prepatch, preminor, premajor, prerelease.
)
)
def increment_version(self, version, rule):
def increment_version(self, version, rule): # type: (str, str) -> "Version"
from poetry.core.semver import Version
try:
......
......@@ -34,7 +34,7 @@ from poetry.mixology.solutions.providers import PythonRequirementSolutionProvide
class ApplicationConfig(BaseApplicationConfig):
def configure(self):
def configure(self): # type: () -> None
super(ApplicationConfig, self).configure()
self.add_style(Style("c1").fg("cyan"))
......
import logging
from typing import TYPE_CHECKING
from .formatters import FORMATTERS
if TYPE_CHECKING:
from logging import LogRecord # noqa
class IOFormatter(logging.Formatter):
_colors = {
......@@ -12,7 +18,7 @@ class IOFormatter(logging.Formatter):
"info": "fg=blue",
}
def format(self, record):
def format(self, record): # type: ("LogRecord") -> str
if not record.exc_info:
level = record.levelname.lower()
msg = record.msg
......
import logging
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from logging import LogRecord # noqa
from clikit.api.io import IO # noqa
class IOHandler(logging.Handler):
def __init__(self, io):
def __init__(self, io): # type: ("IO") -> None
self._io = io
super(IOHandler, self).__init__()
def emit(self, record):
def emit(self, record): # type: ("LogRecord") -> None
try:
msg = self.format(record)
level = record.levelname.lower()
......
......@@ -137,7 +137,7 @@ class Factory(BaseFactory):
def create_legacy_repository(
self, source, auth_config
): # type: (Dict[str, str], Config) -> LegacyRepository
): # type: (Dict[str, str], Config) -> "LegacyRepository"
from .repositories.legacy_repository import LegacyRepository
from .utils.helpers import get_cert
from .utils.helpers import get_client_cert
......
......@@ -120,7 +120,7 @@ class PackageInfo:
return cls(cache_version=cache_version, **data)
@classmethod
def _log(cls, msg, level="info"):
def _log(cls, msg, level="info"): # type: (str, str) -> None
"""Internal helper method to log information."""
getattr(logger, level)("<debug>{}:</debug> {}".format(cls.__name__, msg))
......@@ -436,7 +436,7 @@ class PackageInfo:
return Factory().create_poetry(path).package
@classmethod
def _pep517_metadata(cls, path): # type (Path) -> PackageInfo
def _pep517_metadata(cls, path): # type: (Path) -> PackageInfo
"""
Helper method to use PEP-517 library to build and read package metadata.
......
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
class BaseInstaller:
def install(self, package):
def install(self, package): # type: ("Package") -> None
raise NotImplementedError
def update(self, source, target):
def update(self, source, target): # type: ("Package", "Package") -> None
raise NotImplementedError
def remove(self, package):
def remove(self, package): # type: ("Package") -> None
raise NotImplementedError
import re
from typing import List
from typing import Optional
from typing import Tuple
from packaging.tags import Tag
......@@ -34,12 +35,12 @@ class Wheel(object):
Tag(x, y, z) for x in self.pyversions for y in self.abis for z in self.plats
}
def get_minimum_supported_index(self, tags):
def get_minimum_supported_index(self, tags): # type: (List[Tag]) -> Optional[int]
indexes = [tags.index(t) for t in self.tags if t in tags]
return min(indexes) if indexes else None
def is_supported_by_environment(self, env):
def is_supported_by_environment(self, env): # type: (Env) -> bool
return bool(set(env.supported_tags).intersection(self.tags))
......
......@@ -9,6 +9,10 @@ from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import wait
from pathlib import Path
from subprocess import CalledProcessError
from typing import TYPE_CHECKING
from typing import Any
from typing import List
from typing import Union
from poetry.core.packages.file_dependency import FileDependency
from poetry.core.packages.utils.link import Link
......@@ -27,8 +31,20 @@ from .operations.uninstall import Uninstall
from .operations.update import Update
if TYPE_CHECKING:
from clikit.api.io import IO # noqa
from poetry.config.config import Config # noqa
from poetry.repositories import Pool # noqa
from poetry.utils.env import Env # noqa
from .operations import OperationTypes # noqa
class Executor(object):
def __init__(self, env, pool, config, io, parallel=None):
def __init__(
self, env, pool, config, io, parallel=None
): # type: ("Env", "Pool", "Config", "IO", bool) -> None
self._env = env
self._io = io
self._dry_run = False
......@@ -77,22 +93,22 @@ class Executor(object):
def supports_fancy_output(self): # type: () -> bool
return self._io.supports_ansi() and not self._dry_run
def disable(self):
def disable(self): # type: () -> "Executor"
self._enabled = False
return self
def dry_run(self, dry_run=True):
def dry_run(self, dry_run=True): # type: (bool) -> Executor
self._dry_run = dry_run
return self
def verbose(self, verbose=True):
def verbose(self, verbose=True): # type: (bool) -> Executor
self._verbose = verbose
return self
def execute(self, operations): # type: (Operation) -> int
def execute(self, operations): # type: (List["OperationTypes"]) -> int
self._total_operations = len(operations)
for job_type in self._executed:
self._executed[job_type] = 0
......@@ -145,7 +161,7 @@ class Executor(object):
return 1 if self._shutdown else 0
def _write(self, operation, line):
def _write(self, operation, line): # type: ("OperationTypes", str) -> None
if not self.supports_fancy_output() or not self._should_write_operation(
operation
):
......@@ -163,7 +179,7 @@ class Executor(object):
section.output.clear()
section.write(line)
def _execute_operation(self, operation):
def _execute_operation(self, operation): # type: ("OperationTypes") -> None
try:
if self.supports_fancy_output():
if id(operation) not in self._sections:
......@@ -240,7 +256,7 @@ class Executor(object):
with self._lock:
self._shutdown = True
def _do_execute_operation(self, operation):
def _do_execute_operation(self, operation): # type: ("OperationTypes") -> int
method = operation.job_type
operation_message = self.get_operation_message(operation)
......@@ -283,7 +299,9 @@ class Executor(object):
return result
def _increment_operations_count(self, operation, executed):
def _increment_operations_count(
self, operation, executed
): # type: ("OperationTypes", bool) -> None
with self._lock:
if executed:
self._executed_operations += 1
......@@ -291,7 +309,7 @@ class Executor(object):
else:
self._skipped[operation.job_type] += 1
def run_pip(self, *args, **kwargs): # type: (...) -> int
def run_pip(self, *args, **kwargs): # type: (*Any, **Any) -> int
try:
self._env.run_pip(*args, **kwargs)
except EnvCommandError as e:
......@@ -306,7 +324,9 @@ class Executor(object):
return 0
def get_operation_message(self, operation, done=False, error=False, warning=False):
def get_operation_message(
self, operation, done=False, error=False, warning=False
): # type: ("OperationTypes", bool, bool, bool) -> str
base_tag = "fg=default"
operation_color = "c2"
source_operation_color = "c2"
......@@ -360,7 +380,7 @@ class Executor(object):
return ""
def _display_summary(self, operations):
def _display_summary(self, operations): # type: (List["OperationTypes"]) -> None
installs = 0
updates = 0
uninstalls = 0
......@@ -403,13 +423,13 @@ class Executor(object):
)
self._io.write_line("")
def _execute_install(self, operation): # type: (Install) -> None
def _execute_install(self, operation): # type: (Union[Install, Update]) -> int
return self._install(operation)
def _execute_update(self, operation): # type: (Update) -> None
def _execute_update(self, operation): # type: (Union[Install, Update]) -> int
return self._update(operation)
def _execute_uninstall(self, operation): # type: (Uninstall) -> None
def _execute_uninstall(self, operation): # type: (Uninstall) -> int
message = " <fg=blue;options=bold>•</> {message}: <info>Removing...</info>".format(
message=self.get_operation_message(operation),
)
......@@ -417,7 +437,7 @@ class Executor(object):
return self._remove(operation)
def _install(self, operation):
def _install(self, operation): # type: (Union[Install, Update]) -> int
package = operation.package
if package.source_type == "directory":
return self._install_directory(operation)
......@@ -444,10 +464,10 @@ class Executor(object):
return self.run_pip(*args)
def _update(self, operation):
def _update(self, operation): # type: (Union[Install, Update]) -> int
return self._install(operation)
def _remove(self, operation):
def _remove(self, operation): # type: (Uninstall) -> int
package = operation.package
# If we have a VCS package, remove its source directory
......@@ -464,7 +484,7 @@ class Executor(object):
raise
def _prepare_file(self, operation):
def _prepare_file(self, operation): # type: (Union[Install, Update]) -> Path
package = operation.package
message = " <fg=blue;options=bold>•</> {message}: <info>Preparing...</info>".format(
......@@ -480,7 +500,7 @@ class Executor(object):
return archive
def _install_directory(self, operation):
def _install_directory(self, operation): # type: (Union[Install, Update]) -> int
from poetry.factory import Factory
package = operation.package
......@@ -544,7 +564,7 @@ class Executor(object):
return self.run_pip(*args)
def _install_git(self, operation):
def _install_git(self, operation): # type: (Union[Install, Update]) -> int
from poetry.core.vcs import Git
package = operation.package
......@@ -570,12 +590,14 @@ class Executor(object):
return self._install_directory(operation)
def _download(self, operation): # type: (Operation) -> Path
def _download(self, operation): # type: (Union[Install, Update]) -> Link
link = self._chooser.choose_for(operation.package)
return self._download_link(operation, link)
def _download_link(self, operation, link):
def _download_link(
self, operation, link
): # type: (Union[Install, Update], Link) -> Link
package = operation.package
archive = self._chef.get_cached_archive_for_link(link)
......@@ -607,7 +629,9 @@ class Executor(object):
return archive
def _download_archive(self, operation, link): # type: (Operation, Link) -> Path
def _download_archive(
self, operation, link
): # type: (Union[Install, Update], Link) -> Path
response = self._authenticator.request(
"get", link.url, stream=True, io=self._sections.get(id(operation), self._io)
)
......
from typing import TYPE_CHECKING
from typing import Iterable
from typing import List
from typing import Optional
from typing import Union
......@@ -23,11 +25,17 @@ from .operations.operation import Operation
from .pip_installer import PipInstaller
if TYPE_CHECKING:
from poetry.utils.env import Env # noqa
from .operations import OperationTypes # noqa
class Installer:
def __init__(
self,
io, # type: IO
env,
env, # type: "Env"
package, # type: ProjectPackage
locker, # type: Locker
pool, # type: Pool
......@@ -67,11 +75,11 @@ class Installer:
self._installed_repository = installed
@property
def executor(self):
def executor(self): # type: () -> Executor
return self._executor
@property
def installer(self):
def installer(self): # type: () -> BaseInstaller
return self._installer
def set_package(self, package): # type: (ProjectPackage) -> Installer
......@@ -84,7 +92,7 @@ class Installer:
return self
def run(self):
def run(self): # type: () -> int
# Check if refresh
if not self._update and self._lock and self._locker.is_locked():
return self._do_refresh()
......@@ -162,7 +170,7 @@ class Installer:
return self
def whitelist(self, packages): # type: (dict) -> Installer
def whitelist(self, packages): # type: (Iterable[str]) -> Installer
self._whitelist = [canonicalize_name(p) for p in packages]
return self
......@@ -177,7 +185,7 @@ class Installer:
return self
def _do_refresh(self):
def _do_refresh(self): # type: () -> int
from poetry.puzzle import Solver
# Checking extras
......@@ -203,7 +211,7 @@ class Installer:
return 0
def _do_install(self, local_repo):
def _do_install(self, local_repo): # type: (Repository) -> int
from poetry.puzzle import Solver
locked_repository = Repository()
......@@ -323,7 +331,7 @@ class Installer:
self._io.write_line("")
self._io.write_line("<info>Writing lock file</>")
def _execute(self, operations):
def _execute(self, operations): # type: (List["OperationTypes"]) -> int
if self._use_executor:
return self._executor.execute(operations)
......@@ -459,7 +467,9 @@ class Installer:
self._installer.remove(operation.package)
def _populate_local_repo(self, local_repo, ops):
def _populate_local_repo(
self, local_repo, ops
): # type: (Repository, List[Operation]) -> None
for op in ops:
if isinstance(op, Uninstall):
continue
......@@ -472,8 +482,8 @@ class Installer:
local_repo.add_package(package)
def _get_operations_from_lock(
self, locked_repository # type: Repository
): # type: (...) -> List[Operation]
self, locked_repository
): # type: (Repository) -> List[Operation]
installed_repo = self._installed_repository
ops = []
......
from typing import TYPE_CHECKING
from typing import List
from .base_installer import BaseInstaller
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
class NoopInstaller(BaseInstaller):
def __init__(self):
def __init__(self): # type: () -> None
self._installs = []
self._updates = []
self._removals = []
@property
def installs(self):
def installs(self): # type: () -> List["Package"]
return self._installs
@property
def updates(self):
def updates(self): # type: () -> List["Package"]
return self._updates
@property
def removals(self):
def removals(self): # type: () -> List["Package"]
return self._removals
def install(self, package):
def install(self, package): # type: ("Package") -> None
self._installs.append(package)
def update(self, source, target):
def update(self, source, target): # type: ("Package", "Package") -> None
self._updates.append((source, target))
def remove(self, package):
def remove(self, package): # type: ("Package") -> None
self._removals.append(package)
from typing import Union
from .install import Install
from .uninstall import Uninstall
from .update import Update
OperationTypes = Union[Install, Uninstall, Update]
from typing import TYPE_CHECKING
from typing import Optional
from .operation import Operation
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
class Install(Operation):
def __init__(self, package, reason=None, priority=0):
def __init__(
self, package, reason=None, priority=0
): # type: ("Package", Optional[str], int) -> None
super(Install, self).__init__(reason, priority=priority)
self._package = package
@property
def package(self):
def package(self): # type: () -> "Package"
return self._package
@property
def job_type(self):
def job_type(self): # type: () -> str
return "install"
def __str__(self):
def __str__(self): # type: () -> str
return "Installing {} ({})".format(
self.package.pretty_name, self.format_version(self.package)
)
def __repr__(self):
def __repr__(self): # type: () -> str
return "<Install {} ({})>".format(
self.package.pretty_name, self.format_version(self.package)
)
# -*- coding: utf-8 -*-
from typing import Union
from typing import TYPE_CHECKING
from typing import Optional
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
class Operation(object):
def __init__(
self, reason=None, priority=0
): # type: (Union[str, None], int) -> None
def __init__(self, reason=None, priority=0): # type: (Optional[str], int) -> None
self._reason = reason
self._skipped = False
......@@ -26,7 +29,7 @@ class Operation(object):
return self._skipped
@property
def skip_reason(self): # type: () -> Union[str, None]
def skip_reason(self): # type: () -> Optional[str]
return self._skip_reason
@property
......@@ -34,10 +37,10 @@ class Operation(object):
return self._priority
@property
def package(self):
def package(self): # type: () -> "Package"
raise NotImplementedError()
def format_version(self, package): # type: (...) -> str
def format_version(self, package): # type: ("Package") -> str
return package.full_pretty_version
def skip(self, reason): # type: (str) -> Operation
......
from typing import TYPE_CHECKING
from typing import Optional
from .operation import Operation
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
class Uninstall(Operation):
def __init__(self, package, reason=None, priority=float("inf")):
def __init__(
self, package, reason=None, priority=float("inf")
): # type: ("Package", Optional[str], int) -> None
super(Uninstall, self).__init__(reason, priority=priority)
self._package = package
@property
def package(self):
def package(self): # type: () -> "Package"
return self._package
@property
def job_type(self):
def job_type(self): # type: () -> str
return "uninstall"
def __str__(self):
def __str__(self): # type: () -> str
return "Uninstalling {} ({})".format(
self.package.pretty_name, self.format_version(self._package)
)
def __repr__(self):
def __repr__(self): # type: () -> str
return "<Uninstall {} ({})>".format(
self.package.pretty_name, self.format_version(self.package)
)
from typing import TYPE_CHECKING
from typing import Optional
from .operation import Operation
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
class Update(Operation):
def __init__(self, initial, target, reason=None, priority=0):
def __init__(
self, initial, target, reason=None, priority=0
): # type: ("Package", "Package", Optional[str], int) -> None
self._initial_package = initial
self._target_package = target
super(Update, self).__init__(reason, priority=priority)
@property
def initial_package(self):
def initial_package(self): # type: () -> "Package"
return self._initial_package
@property
def target_package(self):
def target_package(self): # type: () -> "Package"
return self._target_package
@property
def package(self):
def package(self): # type: () -> "Package"
return self._target_package
@property
def job_type(self):
def job_type(self): # type: () -> str
return "update"
def __str__(self):
def __str__(self): # type: () -> str
return "Updating {} ({}) to {} ({})".format(
self.initial_package.pretty_name,
self.format_version(self.initial_package),
......@@ -32,7 +41,7 @@ class Update(Operation):
self.format_version(self.target_package),
)
def __repr__(self):
def __repr__(self): # type: () -> str
return "<Update {} ({}) to {} ({})>".format(
self.initial_package.pretty_name,
self.format_version(self.initial_package),
......
......@@ -3,6 +3,9 @@ import tempfile
import urllib.parse
from subprocess import CalledProcessError
from typing import TYPE_CHECKING
from typing import Any
from typing import Union
from clikit.api.io import IO
......@@ -15,13 +18,17 @@ from poetry.utils.helpers import safe_rmtree
from .base_installer import BaseInstaller
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
class PipInstaller(BaseInstaller):
def __init__(self, env, io, pool): # type: (Env, IO, Pool) -> None
self._env = env
self._io = io
self._pool = pool
def install(self, package, update=False):
def install(self, package, update=False): # type: ("Package", bool) -> None
if package.source_type == "directory":
self.install_directory(package)
......@@ -90,7 +97,7 @@ class PipInstaller(BaseInstaller):
self.run(*args)
def update(self, package, target):
def update(self, package, target): # type: ("Package", "Package") -> None
if package.source_type != target.source_type:
# If the source type has changed, we remove the current
# package to avoid perpetual updates in some cases
......@@ -98,7 +105,7 @@ class PipInstaller(BaseInstaller):
self.install(target, update=True)
def remove(self, package):
def remove(self, package): # type: ("Package") -> None
try:
self.run("uninstall", package.name, "-y")
except CalledProcessError as e:
......@@ -120,10 +127,10 @@ class PipInstaller(BaseInstaller):
if src_dir.exists():
safe_rmtree(str(src_dir))
def run(self, *args, **kwargs): # type: (...) -> str
def run(self, *args, **kwargs): # type: (*Any,**Any) -> str
return self._env.run_pip(*args, **kwargs)
def requirement(self, package, formatted=False):
def requirement(self, package, formatted=False): # type: ("Package", bool) -> str
if formatted and not package.source_type:
req = "{}=={}".format(package.name, package.version)
for f in package.files:
......@@ -164,7 +171,7 @@ class PipInstaller(BaseInstaller):
return "{}=={}".format(package.name, package.version)
def create_temporary_requirement(self, package):
def create_temporary_requirement(self, package): # type: ("Package") -> str
fd, name = tempfile.mkstemp(
"reqs.txt", "{}-{}".format(package.name, package.version)
)
......@@ -176,7 +183,7 @@ class PipInstaller(BaseInstaller):
return name
def install_directory(self, package):
def install_directory(self, package): # type: ("Package") -> Union[str, int]
from poetry.factory import Factory
from poetry.io.null_io import NullIO
......@@ -233,7 +240,7 @@ class PipInstaller(BaseInstaller):
return self.run(*args)
def install_git(self, package):
def install_git(self, package): # type: ("Package") -> None
from poetry.core.packages import Package
from poetry.core.vcs import Git
......
from typing import Any
from cleo.io.io_mixin import IOMixin
from clikit.io import NullIO as BaseNullIO
......@@ -7,5 +9,5 @@ class NullIO(IOMixin, BaseNullIO):
A wrapper around CliKit's NullIO.
"""
def __init__(self, *args, **kwargs):
def __init__(self, *args, **kwargs): # type: (*Any, **Any) -> None
super(NullIO, self).__init__(*args, **kwargs)
from typing import TYPE_CHECKING
from typing import Dict
from typing import Optional
from tomlkit import dumps
......@@ -9,7 +10,8 @@ from poetry.utils.helpers import module_name
if TYPE_CHECKING:
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.core.pyproject.toml import PyProjectTOML # noqa
from poetry.utils._compat import Path # noqa
TESTS_DEFAULT = u"""from {package_name} import __version__
......@@ -45,21 +47,21 @@ license = ""
"""
BUILD_SYSTEM_MIN_VERSION = "1.0.0"
BUILD_SYSTEM_MAX_VERSION = None
BUILD_SYSTEM_MAX_VERSION = None # type: Optional[str]
class Layout(object):
def __init__(
self,
project,
version="0.1.0",
description="",
readme_format="md",
author=None,
license=None,
python="*",
dependencies=None,
dev_dependencies=None,
project, # type: str
version="0.1.0", # type: str
description="", # type: str
readme_format="md", # type: str
author=None, # type: Optional[str]
license=None, # type: Optional[str]
python="*", # type: str
dependencies=None, # type: Optional[Dict[str, str]]
dev_dependencies=None, # type: Optional[Dict[str, str]]
):
self._project = project
self._package_name = module_name(project)
......@@ -76,7 +78,7 @@ class Layout(object):
self._author = author
def create(self, path, with_tests=True):
def create(self, path, with_tests=True): # type: (Path, bool) -> None
path.mkdir(parents=True, exist_ok=True)
self._create_default(path)
......@@ -129,10 +131,10 @@ class Layout(object):
return content
def _create_default(self, path, src=True):
def _create_default(self, path, src=True): # type: (Path, bool) -> None
raise NotImplementedError()
def _create_readme(self, path):
def _create_readme(self, path): # type: (Path) -> None
if self._readme_format == "rst":
readme_file = path / "README.rst"
else:
......@@ -140,7 +142,7 @@ class Layout(object):
readme_file.touch()
def _create_tests(self, path):
def _create_tests(self, path): # type: (Path) -> None
tests = path / "tests"
tests_init = tests / "__init__.py"
tests_default = tests / "test_{}.py".format(self._package_name)
......@@ -155,7 +157,7 @@ class Layout(object):
)
)
def _write_poetry(self, path):
def _write_poetry(self, path): # type: ("Path") -> None
content = self.generate_poetry_content()
poetry = path / "pyproject.toml"
......
# -*- coding: utf-8 -*-
from typing import TYPE_CHECKING
from .layout import Layout
if TYPE_CHECKING:
from poetry.utils._compat import Path # noqa
DEFAULT = u"""__version__ = '{version}'
"""
class SrcLayout(Layout):
def _create_default(self, path):
def _create_default(self, path): # type: ("Path") -> None
package_path = path / "src" / self._package_name
package_init = package_path / "__init__.py"
......
# -*- coding: utf-8 -*-
from typing import TYPE_CHECKING
from .layout import Layout
if TYPE_CHECKING:
from poetry.utils._compat import Path # noqa
DEFAULT = u"""__version__ = '{version}'
"""
class StandardLayout(Layout):
def _create_default(self, path):
def _create_default(self, path): # type: ("Path") -> None
package_path = path / self._package_name
package_init = package_path / "__init__.py"
......
......@@ -6,6 +6,8 @@ import shutil
from base64 import urlsafe_b64encode
from pathlib import Path
from typing import TYPE_CHECKING
from typing import List
from poetry.core.masonry.builders.builder import Builder
from poetry.core.masonry.builders.sdist import SdistBuilder
......@@ -16,6 +18,12 @@ from poetry.utils._compat import decode
from poetry.utils.helpers import is_dir_writable
if TYPE_CHECKING:
from clikit.api.io import IO # noqa
from poetry.core.poetry import Poetry # noqa
from poetry.utils.env import Env # noqa
SCRIPT_TEMPLATE = """\
#!{python}
from {module} import {callable_holder}
......@@ -30,13 +38,13 @@ WINDOWS_CMD_TEMPLATE = """\
class EditableBuilder(Builder):
def __init__(self, poetry, env, io):
def __init__(self, poetry, env, io): # type: ("Poetry", "Env", "IO") -> None
super(EditableBuilder, self).__init__(poetry)
self._env = env
self._io = io
def build(self):
def build(self): # type: () -> None
self._debug(
" - Building package <c1>{}</c1> in <info>editable</info> mode".format(
self._package.name
......@@ -58,11 +66,11 @@ class EditableBuilder(Builder):
added_files += self._add_scripts()
self._add_dist_info(added_files)
def _run_build_script(self, build_script):
def _run_build_script(self, build_script): # type: (Path) -> None
self._debug(" - Executing build script: <b>{}</b>".format(build_script))
self._env.run("python", str(self._path.joinpath(build_script)), call=True)
def _setup_build(self):
def _setup_build(self): # type: () -> None
builder = SdistBuilder(self._poetry)
setup = self._path / "setup.py"
has_setup = setup.exists()
......@@ -94,7 +102,7 @@ class EditableBuilder(Builder):
if not has_setup:
os.remove(str(setup))
def _add_pth(self):
def _add_pth(self): # type: () -> List[Path]
paths = set()
for include in self._module.includes:
if isinstance(include, PackageInclude) and (
......@@ -126,7 +134,7 @@ class EditableBuilder(Builder):
)
return []
def _add_scripts(self):
def _add_scripts(self): # type: () -> List[Path]
added = []
entry_points = self.convert_entry_points()
......@@ -185,7 +193,7 @@ class EditableBuilder(Builder):
return added
def _add_dist_info(self, added_files):
def _add_dist_info(self, added_files): # type: (List[Path]) -> None
from poetry.core.masonry.builders.wheel import WheelBuilder
added_files = added_files[:]
......@@ -239,7 +247,7 @@ class EditableBuilder(Builder):
# RECORD itself is recorded with no hash or size
f.write("{},,\n".format(dist_info.joinpath("RECORD")))
def _get_file_hash(self, filepath):
def _get_file_hash(self, filepath): # type: (Path) -> str
hashsum = hashlib.sha256()
with filepath.open("rb") as src:
while True:
......@@ -252,6 +260,6 @@ class EditableBuilder(Builder):
return urlsafe_b64encode(hashsum.digest()).decode("ascii").rstrip("=")
def _debug(self, msg):
def _debug(self, msg): # type: (str) -> None
if self._io.is_debug():
self._io.write_line(msg)
from typing import TYPE_CHECKING
from typing import Dict
from typing import List
from .version_solver import VersionSolver
def resolve_version(root, provider, locked=None, use_latest=None):
if TYPE_CHECKING:
from poetry.core.packages import DependencyPackage # noqa
from poetry.core.packages import ProjectPackage # noqa
from poetry.puzzle.provider import Provider # noqa
from .result import SolverResult # noqa
def resolve_version(
root, provider, locked=None, use_latest=None
): # type: ("ProjectPackage", "Provider", Dict[str, "DependencyPackage"],List[str]) -> "SolverResult"
solver = VersionSolver(root, provider, locked=locked, use_latest=use_latest)
return solver.solve()
from typing import TYPE_CHECKING
from typing import Any
from typing import Optional
from .incompatibility import Incompatibility
from .term import Term
if TYPE_CHECKING:
from poetry.core.packages import Dependency # noqa
from poetry.core.packages import Package # noqa
from .incompatibility import Incompatibility # noqa
class Assignment(Term):
"""
A term in a PartialSolution that tracks some additional metadata.
"""
def __init__(self, dependency, is_positive, decision_level, index, cause=None):
def __init__(
self, dependency, is_positive, decision_level, index, cause=None
): # type: ("Dependency", bool, int, int, Optional["Incompatibility"]) -> None
super(Assignment, self).__init__(dependency, is_positive)
self._decision_level = decision_level
......@@ -25,19 +35,19 @@ class Assignment(Term):
return self._index
@property
def cause(self): # type: () -> Incompatibility
def cause(self): # type: () -> "Incompatibility"
return self._cause
@classmethod
def decision(
cls, package, decision_level, index
): # type: (Any, int, int) -> Assignment
): # type: ("Package", int, int) -> Assignment
return cls(package.to_dependency(), True, decision_level, index)
@classmethod
def derivation(
cls, dependency, is_positive, cause, decision_level, index
): # type: (Any, bool, Incompatibility, int, int) -> Assignment
): # type: (Any, bool, "Incompatibility", int, int) -> "Assignment"
return cls(dependency, is_positive, decision_level, index, cause)
def is_decision(self): # type: () -> bool
......
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple
from poetry.core.semver import parse_constraint
......@@ -14,10 +15,10 @@ class SolveFailure(Exception):
self._incompatibility = incompatibility
@property
def message(self):
def message(self): # type: () -> str
return str(self)
def __str__(self):
def __str__(self): # type: () -> str
return _Writer(self._incompatibility).write()
......@@ -25,12 +26,12 @@ class _Writer:
def __init__(self, root): # type: (Incompatibility) -> None
self._root = root
self._derivations = {} # type: Dict[Incompatibility, int]
self._lines = [] # type: List[Tuple[str, int]]
self._lines = [] # type: List[Tuple[str, Optional[int]]]
self._line_numbers = {} # type: Dict[Incompatibility, int]
self._count_derivations(self._root)
def write(self):
def write(self): # type: () -> str
buffer = []
required_python_version_notification = False
......@@ -113,7 +114,7 @@ class _Writer:
conjunction = "So," if conclusion or incompatibility == self._root else "And"
incompatibility_string = str(incompatibility)
cause = incompatibility.cause # type: ConflictCause
cause = incompatibility.cause
details_for_cause = {}
if isinstance(cause.conflict.cause, ConflictCause) and isinstance(
cause.other.cause, ConflictCause
......
from typing import Dict
from typing import Generator
from typing import List
from typing import Optional
from typing import Union
from .incompatibility_cause import ConflictCause
from .incompatibility_cause import DependencyCause
......@@ -82,11 +84,15 @@ class Incompatibility:
return self._terms
@property
def cause(self): # type: () -> IncompatibilityCause
def cause(
self,
): # type: () -> Union[RootCause, NoVersionsCause, DependencyCause, ConflictCause, PythonCause, PlatformCause, PackageNotFoundCause]
return self._cause
@property
def external_incompatibilities(self): # type: () -> Generator[Incompatibility]
def external_incompatibilities(
self,
): # type: () -> Generator[Union[ConflictCause, Incompatibility]]
"""
Returns all external incompatibilities in this incompatibility's
derivation graph.
......@@ -106,7 +112,7 @@ class Incompatibility:
len(self._terms) == 1 and self._terms[0].dependency.is_root
)
def __str__(self):
def __str__(self): # type: () -> str
if isinstance(self._cause, DependencyCause):
assert len(self._terms) == 2
......@@ -222,7 +228,7 @@ class Incompatibility:
def and_to_string(
self, other, details, this_line, other_line
): # type: (Incompatibility, dict, int, int) -> str
): # type: (Incompatibility, dict, Optional[int], Optional[int]) -> str
requires_both = self._try_requires_both(other, details, this_line, other_line)
if requires_both is not None:
return requires_both
......@@ -241,18 +247,18 @@ class Incompatibility:
buffer = [str(self)]
if this_line is not None:
buffer.append(" " + this_line)
buffer.append(" " + str(this_line))
buffer.append(" and {}".format(str(other)))
if other_line is not None:
buffer.append(" " + other_line)
buffer.append(" " + str(other_line))
return "\n".join(buffer)
def _try_requires_both(
self, other, details, this_line, other_line
): # type: (Incompatibility, dict, int, int) -> str
): # type: (Incompatibility, dict, Optional[int], Optional[int]) -> Optional[str]
if len(self._terms) == 1 or len(other.terms) == 1:
return
......@@ -298,7 +304,7 @@ class Incompatibility:
def _try_requires_through(
self, other, details, this_line, other_line
): # type: (Incompatibility, dict, int, int) -> str
): # type: (Incompatibility, dict, int, int) -> Optional[str]
if len(self._terms) == 1 or len(other.terms) == 1:
return
......@@ -376,7 +382,7 @@ class Incompatibility:
def _try_requires_forbidden(
self, other, details, this_line, other_line
): # type: (Incompatibility, dict, int, int) -> str
): # type: (Incompatibility, dict, int, int) -> Optional[str]
if len(self._terms) != 1 and len(other.terms) != 1:
return None
......@@ -430,13 +436,13 @@ class Incompatibility:
return "".join(buffer)
def _terse(self, term, allow_every=False):
def _terse(self, term, allow_every=False): # type: (Term, bool) -> str
if allow_every and term.constraint.is_any():
return "every version of {}".format(term.dependency.complete_name)
return str(term.dependency)
def _single_term_where(self, callable): # type: (callable) -> Term
def _single_term_where(self, callable): # type: (callable) -> Optional[Term]
found = None
for term in self._terms:
if not callable(term):
......@@ -449,5 +455,5 @@ class Incompatibility:
return found
def __repr__(self):
def __repr__(self): # type: () -> str
return "<Incompatibility {}>".format(str(self))
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from poetry.mixology.incompatibility import Incompatibility # noqa
class IncompatibilityCause(Exception):
"""
The reason and Incompatibility's terms are incompatible.
......@@ -25,19 +32,21 @@ class ConflictCause(IncompatibilityCause):
during conflict resolution.
"""
def __init__(self, conflict, other):
def __init__(
self, conflict, other
): # type: ("Incompatibility", "Incompatibility") -> None
self._conflict = conflict
self._other = other
@property
def conflict(self):
def conflict(self): # type: () -> "Incompatibility"
return self._conflict
@property
def other(self):
def other(self): # type: () -> "Incompatibility"
return self._other
def __str__(self):
def __str__(self): # type: () -> str
return str(self._conflict)
......@@ -48,16 +57,16 @@ class PythonCause(IncompatibilityCause):
with the current python version.
"""
def __init__(self, python_version, root_python_version):
def __init__(self, python_version, root_python_version): # type: (str, str) -> None
self._python_version = python_version
self._root_python_version = root_python_version
@property
def python_version(self):
def python_version(self): # type: () -> str
return self._python_version
@property
def root_python_version(self):
def root_python_version(self): # type: () -> str
return self._root_python_version
......@@ -67,11 +76,11 @@ class PlatformCause(IncompatibilityCause):
(OS most likely) being incompatible with the current platform.
"""
def __init__(self, platform):
def __init__(self, platform): # type: (str) -> None
self._platform = platform
@property
def platform(self):
def platform(self): # type: () -> str
return self._platform
......@@ -81,9 +90,9 @@ class PackageNotFoundCause(IncompatibilityCause):
source.
"""
def __init__(self, error):
def __init__(self, error): # type: (Exception) -> None
self._error = error
@property
def error(self):
def error(self): # type: () -> Exception
return self._error
from typing import TYPE_CHECKING
from typing import Dict
from typing import List
from poetry.core.packages import Dependency
from poetry.core.packages import Package
from .assignment import Assignment
from .incompatibility import Incompatibility
from .set_relation import SetRelation
from .term import Term
if TYPE_CHECKING:
from poetry.core.packages import Dependency # noqa
from poetry.core.packages import Package # noqa
from poetry.packages import DependencyPackage # noqa
class PartialSolution:
"""
# A list of Assignments that represent the solver's current best guess about
......@@ -19,13 +23,13 @@ class PartialSolution:
# See https://github.com/dart-lang/mixology/tree/master/doc/solver.md#partial-solution.
"""
def __init__(self):
def __init__(self): # type: () -> None
# The assignments that have been made so far, in the order they were
# assigned.
self._assignments = [] # type: List[Assignment]
# The decisions made for each package.
self._decisions = dict() # type: Dict[str, Package]
self._decisions = dict() # type: Dict[str, "Package"]
# The intersection of all positive Assignments for each package, minus any
# negative Assignments that refer to that package.
......@@ -48,7 +52,7 @@ class PartialSolution:
self._backtracking = False
@property
def decisions(self): # type: () -> List[Package]
def decisions(self): # type: () -> List["Package"]
return list(self._decisions.values())
@property
......@@ -60,14 +64,14 @@ class PartialSolution:
return self._attempted_solutions
@property
def unsatisfied(self): # type: () -> List[Dependency]
def unsatisfied(self): # type: () -> List["Dependency"]
return [
term.dependency
for term in self._positive.values()
if term.dependency.complete_name not in self._decisions
]
def decide(self, package): # type: (Package) -> None
def decide(self, package): # type: ("Package") -> None
"""
Adds an assignment of package as a decision
and increments the decision level.
......@@ -88,7 +92,7 @@ class PartialSolution:
def derive(
self, dependency, is_positive, cause
): # type: (Dependency, bool, Incompatibility) -> None
): # type: ("Dependency", bool, Incompatibility) -> None
"""
Adds an assignment of package as a derivation.
"""
......@@ -170,7 +174,7 @@ class PartialSolution:
Returns the first Assignment in this solution such that the sublist of
assignments up to and including that entry collectively satisfies term.
"""
assigned_term = None # type: Term
assigned_term = None
for assignment in self._assignments:
if assignment.dependency.complete_name != term.dependency.complete_name:
......
from typing import TYPE_CHECKING
from typing import List
if TYPE_CHECKING:
from poetry.core.packages import Package # noqa
from poetry.core.packages import ProjectPackage # noqa
class SolverResult:
def __init__(self, root, packages, attempted_solutions):
def __init__(
self, root, packages, attempted_solutions
): # type: ("ProjectPackage", List["Package"], int) -> None
self._root = root
self._packages = packages
self._attempted_solutions = attempted_solutions
@property
def packages(self):
def packages(self): # type: () -> List["Package"]
return self._packages
@property
def attempted_solutions(self):
def attempted_solutions(self): # type: () -> int
return self._attempted_solutions
from typing import TYPE_CHECKING
from typing import List
from crashtest.contracts.solution import Solution
if TYPE_CHECKING:
from poetry.mixology.incompatibility_cause import PackageNotFoundCause # noqa
class PythonRequirementSolution(Solution):
def __init__(self, exception):
def __init__(self, exception): # type: ("PackageNotFoundCause") -> None
from poetry.core.semver import parse_constraint
from poetry.mixology.incompatibility_cause import PythonCause
......@@ -37,15 +44,15 @@ class PythonRequirementSolution(Solution):
self._description = description
@property
def solution_title(self) -> str:
def solution_title(self): # type: () -> str
return self._title
@property
def solution_description(self):
def solution_description(self): # type: () -> str
return self._description
@property
def documentation_links(self):
def documentation_links(self): # type: () -> List[str]
return [
"https://python-poetry.org/docs/dependency-specification/#python-restricted-dependencies",
"https://python-poetry.org/docs/dependency-specification/#using-environment-markers",
......
# -*- coding: utf-8 -*-
from typing import Union
from typing import TYPE_CHECKING
from typing import Optional
from poetry.core.packages import Dependency
from .set_relation import SetRelation
if TYPE_CHECKING:
from poetry.core.semver import VersionTypes # noqa
class Term(object):
"""
A statement about a package which is true or false for a given selection of
......@@ -23,11 +28,11 @@ class Term(object):
return Term(self._dependency, not self.is_positive())
@property
def dependency(self):
def dependency(self): # type: () -> Dependency
return self._dependency
@property
def constraint(self):
def constraint(self): # type: () -> "VersionTypes"
return self._dependency.constraint
def is_positive(self): # type: () -> bool
......@@ -106,7 +111,7 @@ class Term(object):
# not foo ^1.5.0 is a superset of not foo ^1.0.0
return SetRelation.OVERLAPPING
def intersect(self, other): # type: (Term) -> Union[Term, None]
def intersect(self, other): # type: (Term) -> Optional[Term]
"""
Returns a Term that represents the packages
allowed by both this term and another
......@@ -147,21 +152,23 @@ class Term(object):
"""
return self.intersect(other.inverse)
def _compatible_dependency(self, other):
def _compatible_dependency(self, other): # type: (Term) -> bool
return (
self.dependency.is_root
or other.is_root
or other.is_same_package_as(self.dependency)
)
def _non_empty_term(self, constraint, is_positive):
def _non_empty_term(
self, constraint, is_positive
): # type: ("VersionTypes", bool) -> Optional[Term]
if constraint.is_empty():
return
return Term(self.dependency.with_constraint(constraint), is_positive)
def __str__(self):
def __str__(self): # type: () -> str
return "{}{}".format("not " if not self.is_positive() else "", self._dependency)
def __repr__(self):
def __repr__(self): # type: () -> str
return "<Term {}>".format(str(self))
......@@ -4,7 +4,7 @@ import time
from typing import TYPE_CHECKING
from typing import Dict
from typing import List
from typing import Union
from typing import Optional
from poetry.core.packages import Dependency
from poetry.core.packages import Package
......@@ -130,7 +130,7 @@ class VersionSolver:
def _propagate_incompatibility(
self, incompatibility
): # type: (Incompatibility) -> Union[str, _conflict, None]
): # type: (Incompatibility) -> Optional[str, _conflict]
"""
If incompatibility is almost satisfied by _solution, adds the
negation of the unsatisfied term to _solution.
......@@ -317,7 +317,7 @@ class VersionSolver:
raise SolveFailure(incompatibility)
def _choose_package_version(self): # type: () -> Union[str, None]
def _choose_package_version(self): # type: () -> Optional[str]
"""
Tries to select a version of a required package.
......@@ -331,7 +331,7 @@ class VersionSolver:
# Prefer packages with as few remaining versions as possible,
# so that if a conflict is necessary it's forced quickly.
def _get_min(dependency):
def _get_min(dependency): # type: (Dependency) -> int
if dependency.name in self._use_latest:
# If we're forced to use the latest version of a package, it effectively
# only has one version to choose from.
......@@ -447,7 +447,7 @@ class VersionSolver:
incompatibility
)
def _get_locked(self, dependency): # type: (Dependency) -> Union[Package, None]
def _get_locked(self, dependency): # type: (Dependency) -> Optional[Package]
if dependency.name in self._use_latest:
return
......@@ -460,5 +460,5 @@ class VersionSolver:
return locked
def _log(self, text):
def _log(self, text): # type: (str) -> None
self._provider.debug(text, self._solution.attempted_solutions)
from typing import Any
from typing import List
from typing import Union
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
......@@ -17,7 +19,7 @@ class DependencyPackage(object):
def package(self): # type: () -> Package
return self._package
def clone(self): # type: () -> DependencyPackage
def clone(self): # type: () -> "DependencyPackage"
return self.__class__(self._dependency, self._package.clone())
def with_features(self, features): # type: (List[str]) -> "DependencyPackage"
......@@ -26,25 +28,25 @@ class DependencyPackage(object):
def without_features(self): # type: () -> "DependencyPackage"
return self.with_features([])
def __getattr__(self, name):
def __getattr__(self, name): # type: (str) -> Any
return getattr(self._package, name)
def __setattr__(self, key, value):
def __setattr__(self, key, value): # type: (str, Any) -> None
if key in {"_dependency", "_package"}:
return super(DependencyPackage, self).__setattr__(key, value)
setattr(self._package, key, value)
def __str__(self):
def __str__(self): # type: () -> str
return str(self._package)
def __repr__(self):
def __repr__(self): # type: () -> str
return repr(self._package)
def __hash__(self):
def __hash__(self): # type: () -> int
return hash(self._package)
def __eq__(self, other):
def __eq__(self, other): # type: (Union[Package, "DependencyPackage"]) -> bool
if isinstance(other, DependencyPackage):
other = other.package
......
......@@ -6,6 +6,7 @@ import re
from copy import deepcopy
from hashlib import sha256
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Dict
from typing import Iterable
from typing import Iterator
......@@ -26,7 +27,7 @@ from tomlkit.exceptions import TOMLKitError
import poetry.repositories
from poetry.core.packages import dependency_from_pep_508
from poetry.core.packages.package import Dependency
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
from poetry.core.semver import parse_constraint
from poetry.core.semver.version import Version
......@@ -37,6 +38,9 @@ from poetry.packages import DependencyPackage
from poetry.utils.extras import get_extra_package_names
if TYPE_CHECKING:
from ptomlkit.toml_document import TOMLDocument # noqa
logger = logging.getLogger(__name__)
......@@ -46,7 +50,7 @@ class Locker(object):
_relevant_keys = ["dependencies", "dev-dependencies", "source", "extras"]
def __init__(self, lock, local_config): # type: (Path, dict) -> None
def __init__(self, lock, local_config): # type: (Union[str, Path], dict) -> None
self._lock = TOMLFile(lock)
self._local_config = local_config
self._lock_data = None
......@@ -57,7 +61,7 @@ class Locker(object):
return self._lock
@property
def lock_data(self):
def lock_data(self): # type: () -> TOMLDocument
if self._lock_data is None:
self._lock_data = self._get_lock_data()
......@@ -382,7 +386,7 @@ class Locker(object):
yield DependencyPackage(dependency=dependency, package=package)
def set_lock_data(self, root, packages): # type: (...) -> bool
def set_lock_data(self, root, packages): # type: (Package, List[Package]) -> bool
files = table()
packages = self._lock_packages(packages)
# Retrieving hashes
......@@ -427,7 +431,7 @@ class Locker(object):
return False
def _write_lock_data(self, data):
def _write_lock_data(self, data): # type: ("TOMLDocument") -> None
self.lock.write(data)
# Checking lock file data consistency
......@@ -452,7 +456,7 @@ class Locker(object):
return content_hash
def _get_lock_data(self): # type: () -> dict
def _get_lock_data(self): # type: () -> "TOMLDocument"
if not self._lock.exists():
raise RuntimeError("No lockfile found. Unable to read locked packages")
......@@ -484,9 +488,7 @@ class Locker(object):
return lock_data
def _lock_packages(
self, packages
): # type: (List['poetry.packages.Package']) -> list
def _lock_packages(self, packages): # type: (List[Package]) -> list
locked = []
for package in sorted(packages, key=lambda x: x.name):
......
from typing import TYPE_CHECKING
from typing import List
from typing import Union
from .dependency_package import DependencyPackage
if TYPE_CHECKING:
from poetry.core.packages import Dependency # noqa
from poetry.core.packages import Package # noqa
class PackageCollection(list):
def __init__(self, dependency, packages=None):
def __init__(
self, dependency, packages=None
): # type: (Dependency, List[Union["Package", DependencyPackage]]) -> None
self._dependency = dependency
if packages is None:
......@@ -13,7 +24,7 @@ class PackageCollection(list):
for package in packages:
self.append(package)
def append(self, package):
def append(self, package): # type: (Union["Package", DependencyPackage]) -> None
if isinstance(package, DependencyPackage):
package = package.package
......
import logging
from pathlib import Path
from typing import TYPE_CHECKING
from typing import List
from typing import Optional
from typing import Union
from poetry.utils.helpers import get_cert
from poetry.utils.helpers import get_client_cert
......@@ -10,6 +13,13 @@ from poetry.utils.password_manager import PasswordManager
from .uploader import Uploader
if TYPE_CHECKING:
from cleo.io import BufferedIO # noqa
from cleo.io import ConsoleIO # noqa
from clikit.io import NullIO # noqa
from ..poetry import Poetry # noqa
logger = logging.getLogger(__name__)
......@@ -18,7 +28,9 @@ class Publisher:
Registers and publishes packages to remote repositories.
"""
def __init__(self, poetry, io):
def __init__(
self, poetry, io
): # type: ("Poetry", Union["ConsoleIO", "BufferedIO", "NullIO"]) -> None
self._poetry = poetry
self._package = poetry.package
self._io = io
......@@ -26,7 +38,7 @@ class Publisher:
self._password_manager = PasswordManager(poetry.config)
@property
def files(self):
def files(self): # type: () -> List[Path]
return self._uploader.files
def publish(
......
......@@ -2,10 +2,12 @@ import hashlib
import io
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple
from typing import Union
import requests
......@@ -26,11 +28,17 @@ from poetry.utils.helpers import normalize_version
from poetry.utils.patterns import wheel_file_re
if TYPE_CHECKING:
from cleo.io import ConsoleIO # noqa
from clikit.io import NullIO # noqa
from poetry.poetry import Poetry # noqa
_has_blake2 = hasattr(hashlib, "blake2b")
class UploadError(Exception):
def __init__(self, error): # type: (Union[ConnectionError, HTTPError]) -> None
def __init__(self, error): # type: (Union[ConnectionError, HTTPError, str]) -> None
if isinstance(error, HTTPError):
message = "HTTP Error {}: {}".format(
error.response.status_code, error.response.reason
......@@ -46,7 +54,9 @@ class UploadError(Exception):
class Uploader:
def __init__(self, poetry, io):
def __init__(
self, poetry, io
): # type: ("Poetry", Union["ConsoleIO", "NullIO"]) -> None
self._poetry = poetry
self._package = poetry.package
self._io = io
......@@ -54,11 +64,11 @@ class Uploader:
self._password = None
@property
def user_agent(self):
def user_agent(self): # type: () -> str
return user_agent("poetry", __version__)
@property
def adapter(self):
def adapter(self): # type: () -> adapters.HTTPAdapter
retry = util.Retry(
connect=5,
total=10,
......@@ -86,7 +96,7 @@ class Uploader:
return sorted(wheels + tars)
def auth(self, username, password):
def auth(self, username, password): # type: (str, str) -> None
self._username = username
self._password = password
......@@ -101,7 +111,7 @@ class Uploader:
return session
def is_authenticated(self):
def is_authenticated(self): # type: () -> bool
return self._username is not None and self._password is not None
def upload(
......@@ -326,7 +336,7 @@ class Uploader:
return resp
def _prepare_data(self, data):
def _prepare_data(self, data): # type: (Dict) -> List[Tuple[str, str]]
data_to_send = []
for key, value in data.items():
if not isinstance(value, (list, tuple)):
......@@ -337,7 +347,7 @@ class Uploader:
return data_to_send
def _get_type(self, file):
def _get_type(self, file): # type: (Path) -> str
exts = file.suffixes
if exts[-1] == ".whl":
return "bdist_wheel"
......
from typing import Dict
from typing import Tuple
class SolverProblemError(Exception):
def __init__(self, error):
def __init__(self, error): # type: (Exception) -> None
self._error = error
super(SolverProblemError, self).__init__(str(error))
@property
def error(self):
def error(self): # type: () -> Exception
return self._error
class OverrideNeeded(Exception):
def __init__(self, *overrides):
def __init__(self, *overrides): # type: (*Dict) -> None
self._overrides = overrides
@property
def overrides(self):
def overrides(self): # type: () -> Tuple[Dict]
return self._overrides
......@@ -7,8 +7,11 @@ from contextlib import contextmanager
from pathlib import Path
from tempfile import mkdtemp
from typing import Any
from typing import Dict
from typing import Iterator
from typing import List
from typing import Optional
from typing import Union
from clikit.ui.components import ProgressIndicator
......@@ -68,10 +71,10 @@ class Provider:
def pool(self): # type: () -> Pool
return self._pool
def is_debugging(self):
def is_debugging(self): # type: () -> bool
return self._is_debugging
def set_overrides(self, overrides):
def set_overrides(self, overrides): # type: (Dict) -> None
self._overrides = overrides
def load_deferred(self, load_deferred): # type: (bool) -> None
......@@ -90,7 +93,9 @@ class Provider:
self._env = original_env
self._python_constraint = original_python_constraint
def search_for(self, dependency): # type: (Dependency) -> List[Package]
def search_for(
self, dependency
): # type: (Union[Dependency, VCSDependency, FileDependency, DirectoryDependency, URLDependency]) -> List[DependencyPackage]
"""
Search for the specifications that match the given dependency.
......@@ -175,7 +180,7 @@ class Provider:
@classmethod
def get_package_from_vcs(
cls, vcs, url, branch=None, tag=None, rev=None, name=None
): # type: (str, str, Optional[str], Optional[str]) -> Package
): # type: (str, str, Optional[str], Optional[str], Optional[str], Optional[str]) -> Package
if vcs != "git":
raise ValueError("Unsupported VCS dependency {}".format(vcs))
......@@ -684,7 +689,7 @@ class Provider:
return package
def debug(self, message, depth=0):
def debug(self, message, depth=0): # type: (str, int) -> None
if not (self._io.is_very_verbose() or self._io.is_debug()):
return
......@@ -771,7 +776,7 @@ class Provider:
self._io.write(debug_info)
@contextmanager
def progress(self):
def progress(self): # type: () -> Iterator[None]
if not self._io.output.supports_ansi() or self.is_debugging():
self._io.write_line("Resolving dependencies...")
yield
......
......@@ -3,17 +3,21 @@ import time
from collections import defaultdict
from contextlib import contextmanager
from typing import TYPE_CHECKING
from typing import Callable
from typing import Dict
from typing import List
from typing import Optional
from typing import Tuple
from typing import Union
from clikit.io import ConsoleIO
from clikit.api.io import IO
from poetry.core.packages import Package
from poetry.core.packages.project_package import ProjectPackage
from poetry.installation.operations import Install
from poetry.installation.operations import Uninstall
from poetry.installation.operations import Update
from poetry.installation.operations.operation import Operation
from poetry.mixology import resolve_version
from poetry.mixology.failure import SolveFailure
from poetry.packages import DependencyPackage
......@@ -26,6 +30,15 @@ from .exceptions import SolverProblemError
from .provider import Provider
if TYPE_CHECKING:
from poetry.core.packages import Dependency # noqa
from poetry.core.packages import DirectoryDependency # noqa
from poetry.core.packages import FileDependency # noqa
from poetry.core.packages import URLDependency # noqa
from poetry.core.packages import VCSDependency # noqa
from poetry.installation.operations import OperationTypes # noqa
class Solver:
def __init__(
self,
......@@ -33,7 +46,7 @@ class Solver:
pool, # type: Pool
installed, # type: Repository
locked, # type: Repository
io, # type: ConsoleIO
io, # type: IO
remove_untracked=False, # type: bool
provider=None, # type: Optional[Provider]
):
......@@ -59,7 +72,7 @@ class Solver:
with self.provider.use_environment(env):
yield
def solve(self, use_latest=None): # type: (...) -> List[Operation]
def solve(self, use_latest=None): # type: (List[str]) -> List["OperationTypes"]
with self._provider.progress():
start = time.time()
packages, depths = self._solve(use_latest=use_latest)
......@@ -191,7 +204,9 @@ class Solver:
operations, key=lambda o: (-o.priority, o.package.name, o.package.version,),
)
def solve_in_compatibility_mode(self, overrides, use_latest=None):
def solve_in_compatibility_mode(
self, overrides, use_latest=None
): # type: (Tuple[Dict], List[str]) -> Tuple[List["Package"], List[int]]
locked = {}
for package in self._locked.packages:
locked[package.name] = DependencyPackage(package.to_dependency(), package)
......@@ -221,7 +236,9 @@ class Solver:
return packages, depths
def _solve(self, use_latest=None):
def _solve(
self, use_latest=None
): # type: (List[str]) -> Tuple[List[Package], List[int]]
if self._provider._overrides:
self._overrides.append(self._provider._overrides)
......@@ -274,18 +291,20 @@ class Solver:
class DFSNode(object):
def __init__(self, id, name, base_name):
def __init__(
self, id, name, base_name
): # type: (Tuple[str, str, bool], str, str) -> None
self.id = id
self.name = name
self.base_name = base_name
def reachable(self):
def reachable(self): # type: () -> List
return []
def visit(self, parents):
def visit(self, parents): # type: (List[PackageNode]) -> None
pass
def __str__(self):
def __str__(self): # type: () -> str
return str(self.id)
......@@ -295,7 +314,9 @@ class VisitedState(enum.Enum):
Visited = 2
def depth_first_search(source, aggregator):
def depth_first_search(
source, aggregator
): # type: (PackageNode, Callable) -> List[Tuple[Package, int]]
back_edges = defaultdict(list)
visited = {}
topo_sorted_nodes = []
......@@ -322,7 +343,9 @@ def depth_first_search(source, aggregator):
return results
def dfs_visit(node, back_edges, visited, sorted_nodes):
def dfs_visit(
node, back_edges, visited, sorted_nodes
): # type: (PackageNode, Dict[str, List[PackageNode]], Dict[str, VisitedState], List[PackageNode]) -> bool
if visited.get(node.id, VisitedState.Unvisited) == VisitedState.Visited:
return True
if visited.get(node.id, VisitedState.Unvisited) == VisitedState.PartiallyVisited:
......@@ -343,8 +366,13 @@ def dfs_visit(node, back_edges, visited, sorted_nodes):
class PackageNode(DFSNode):
def __init__(
self, package, packages, previous=None, previous_dep=None, dep=None,
):
self,
package, # type: Package
packages, # type: List[Package]
previous=None, # type: Optional[PackageNode]
previous_dep=None, # type: Optional[Union["DirectoryDependency", "FileDependency", "URLDependency", "VCSDependency", "Dependency"]]
dep=None, # type: Optional[Union["DirectoryDependency", "FileDependency", "URLDependency", "VCSDependency", "Dependency"]]
): # type: (...) -> None
self.package = package
self.packages = packages
......@@ -366,7 +394,7 @@ class PackageNode(DFSNode):
package.name,
)
def reachable(self):
def reachable(self): # type: () -> List[PackageNode]
children = [] # type: List[PackageNode]
if (
......@@ -413,7 +441,7 @@ class PackageNode(DFSNode):
return children
def visit(self, parents):
def visit(self, parents): # type: (PackageNode) -> None
# The root package, which has no parents, is defined as having depth -1
# So that the root package's top-level dependencies have depth 0.
self.depth = 1 + max(
......@@ -425,7 +453,9 @@ class PackageNode(DFSNode):
)
def aggregate_package_nodes(nodes, children):
def aggregate_package_nodes(
nodes, children
): # type: (List[PackageNode], List[PackageNode]) -> Tuple[Package, int]
package = nodes[0].package
depth = max(node.depth for node in nodes)
category = (
......
from typing import TYPE_CHECKING
from typing import List
from typing import Optional
if TYPE_CHECKING:
from poetry.core.packages import Dependency # noqa
from poetry.core.packages import Package # noqa
class BaseRepository(object):
def __init__(self):
def __init__(self): # type: () -> None
self._packages = []
@property
def packages(self):
def packages(self): # type: () -> List["Package"]
return self._packages
def has_package(self, package):
def has_package(self, package): # type: ("Package") -> None
raise NotImplementedError()
def package(self, name, version, extras=None):
def package(
self, name, version, extras=None
): # type: (str, str, Optional[List[str]]) -> None
raise NotImplementedError()
def find_packages(self, dependency):
def find_packages(self, dependency): # type: ("Dependency") -> None
raise NotImplementedError()
def search(self, query):
def search(self, query): # type: (str) -> None
raise NotImplementedError()
......@@ -5,9 +5,12 @@ import warnings
from collections import defaultdict
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
from typing import Dict
from typing import Generator
from typing import List
from typing import Optional
from typing import Union
import requests
import requests.auth
......@@ -34,6 +37,9 @@ from .exceptions import RepositoryError
from .pypi_repository import PyPiRepository
if TYPE_CHECKING:
from poetry.core.packages import Dependency # noqa
try:
from html import unescape
except ImportError:
......@@ -69,7 +75,9 @@ class Page:
".tar",
]
def __init__(self, url, content, headers):
def __init__(
self, url, content, headers
): # type: (str, str, Dict[str, Any]) -> None
if not url.endswith("/"):
url += "/"
......@@ -127,7 +135,7 @@ class Page:
if self.link_version(link) == version:
yield link
def link_version(self, link): # type: (Link) -> Union[Version, None]
def link_version(self, link): # type: (Link) -> Optional[Version]
m = wheel_file_re.match(link.filename)
if m:
version = m.group("ver")
......@@ -148,7 +156,7 @@ class Page:
_clean_re = re.compile(r"[^a-z0-9$&+,/:;=?@.#%_\\|-]", re.I)
def clean_link(self, url):
def clean_link(self, url): # type: (str) -> str
"""Makes sure a link is fully encoded. That is, if a ' ' shows up in
the link, it will be rewritten to %20 (while not over-quoting
% or other characters)."""
......@@ -225,7 +233,7 @@ class LegacyRepository(PyPiRepository):
path=parsed.path,
)
def find_packages(self, dependency):
def find_packages(self, dependency): # type: ("Dependency") -> List[Package]
packages = []
constraint = dependency.constraint
......@@ -296,7 +304,9 @@ class LegacyRepository(PyPiRepository):
return packages
def package(self, name, version, extras=None): # type: (...) -> Package
def package(
self, name, version, extras=None
): # type: (str, str, Optional[List[str]]) -> Package
"""
Retrieve the release information.
......@@ -320,7 +330,7 @@ class LegacyRepository(PyPiRepository):
return package
def find_links_for_package(self, package):
def find_links_for_package(self, package): # type: (Package) -> List[Link]
page = self._get("/{}/".format(package.name.replace(".", "-")))
if page is None:
return []
......@@ -375,7 +385,7 @@ class LegacyRepository(PyPiRepository):
return data.asdict()
def _get(self, endpoint): # type: (str) -> Union[Page, None]
def _get(self, endpoint): # type: (str) -> Optional[Page]
url = self._url + endpoint
try:
response = self.session.get(url)
......
......@@ -9,7 +9,8 @@ from .repository import Repository
if TYPE_CHECKING:
from poetry.core.packages import Package
from poetry.core.packages import Dependency # noqa
from poetry.core.packages import Package # noqa
class Pool(BaseRepository):
......@@ -108,12 +109,12 @@ class Pool(BaseRepository):
return self
def has_package(self, package):
def has_package(self, package): # type: ("Package") -> bool
raise NotImplementedError()
def package(
self, name, version, extras=None, repository=None
): # type: (str, str, List[str], str) -> Package
): # type: (str, str, List[str], str) -> "Package"
if repository is not None:
repository = repository.lower()
......@@ -143,9 +144,7 @@ class Pool(BaseRepository):
raise PackageNotFound("Package {} ({}) not found.".format(name, version))
def find_packages(
self, dependency,
):
def find_packages(self, dependency): # type: ("Dependency") -> List["Package"]
repository = dependency.source_name
if repository is not None:
repository = repository.lower()
......@@ -166,7 +165,7 @@ class Pool(BaseRepository):
return packages
def search(self, query):
def search(self, query): # type: (str) -> List["Package"]
from .legacy_repository import LegacyRepository
results = []
......
......@@ -45,7 +45,9 @@ class PyPiRepository(RemoteRepository):
CACHE_VERSION = parse_constraint("1.0.0")
def __init__(self, url="https://pypi.org/", disable_cache=False, fallback=True):
def __init__(
self, url="https://pypi.org/", disable_cache=False, fallback=True
): # type: (str, bool, bool) -> None
super(PyPiRepository, self).__init__(url.rstrip("/") + "/simple/")
self._base_url = url
......@@ -72,7 +74,7 @@ class PyPiRepository(RemoteRepository):
self._name = "PyPI"
@property
def session(self):
def session(self): # type: () -> CacheControl
return self._session
def find_packages(self, dependency): # type: (Dependency) -> List[Package]
......@@ -156,7 +158,7 @@ class PyPiRepository(RemoteRepository):
): # type: (...) -> Package
return self.get_release_info(name, version).to_package(name=name, extras=extras)
def search(self, query):
def search(self, query): # type: (str) -> List[Package]
results = []
search = {"q": query}
......@@ -236,7 +238,7 @@ class PyPiRepository(RemoteRepository):
return PackageInfo.load(cached)
def find_links_for_package(self, package):
def find_links_for_package(self, package): # type: (Package) -> List[Link]
json_data = self._get("pypi/{}/{}/json".format(package.name, package.version))
if json_data is None:
return []
......@@ -452,5 +454,5 @@ class PyPiRepository(RemoteRepository):
def _download(self, url, dest): # type: (str, str) -> None
return download_file(url, dest, session=self.session)
def _log(self, msg, level="info"):
def _log(self, msg, level="info"): # type: (str, str) -> None
getattr(logger, level)("<debug>{}:</debug> {}".format(self._name, msg))
from typing import TYPE_CHECKING
from typing import List
from typing import Optional
from poetry.core.semver import VersionConstraint
from poetry.core.semver import VersionRange
from poetry.core.semver import parse_constraint
......@@ -5,8 +9,16 @@ from poetry.core.semver import parse_constraint
from .base_repository import BaseRepository
if TYPE_CHECKING:
from poetry.core.packages import Dependency # noqa
from poetry.core.packages import Link # noqa
from poetry.core.packages import Package # noqa
class Repository(BaseRepository):
def __init__(self, packages=None, name=None):
def __init__(
self, packages=None, name=None
): # type: (List["Package"], str) -> None
super(Repository, self).__init__()
self._name = name
......@@ -18,17 +30,19 @@ class Repository(BaseRepository):
self.add_package(package)
@property
def name(self):
def name(self): # type: () -> str
return self._name
def package(self, name, version, extras=None):
def package(
self, name, version, extras=None
): # type: (str, str, Optional[List[str]]) -> "Package"
name = name.lower()
for package in self.packages:
if name == package.name and package.version.text == version:
return package.clone()
def find_packages(self, dependency):
def find_packages(self, dependency): # type: ("Dependency") -> List["Package"]
constraint = dependency.constraint
packages = []
ignored_pre_release_packages = []
......@@ -71,7 +85,7 @@ class Repository(BaseRepository):
return packages or ignored_pre_release_packages
def has_package(self, package):
def has_package(self, package): # type: ("Package") -> bool
package_id = package.unique_name
for repo_package in self.packages:
......@@ -80,10 +94,10 @@ class Repository(BaseRepository):
return False
def add_package(self, package):
def add_package(self, package): # type: ("Package") -> None
self._packages.append(package)
def remove_package(self, package):
def remove_package(self, package): # type: ("Package") -> None
package_id = package.unique_name
index = None
......@@ -95,10 +109,10 @@ class Repository(BaseRepository):
if index is not None:
del self._packages[index]
def find_links_for_package(self, package):
def find_links_for_package(self, package): # type: ("Package") -> List["Link"]
return []
def search(self, query):
def search(self, query): # type: (str) -> List["Package"]
results = []
for package in self.packages:
......@@ -107,5 +121,5 @@ class Repository(BaseRepository):
return results
def __len__(self):
def __len__(self): # type: () -> int
return len(self._packages)
......@@ -5,11 +5,19 @@ to suit our purposes.
import os
import sys
from typing import TYPE_CHECKING
from typing import List
from typing import Union
if TYPE_CHECKING:
from poetry.utils._compat import Path # noqa
WINDOWS = sys.platform.startswith("win") or (sys.platform == "cli" and os.name == "nt")
def expanduser(path):
def expanduser(path): # type: (Union[str, "Path"]) -> str
"""
Expand ~ and ~user constructions.
......@@ -21,7 +29,7 @@ def expanduser(path):
return expanded
def user_cache_dir(appname):
def user_cache_dir(appname): # type: (str) -> str
r"""
Return full path to the user-specific cache dir for this application.
......@@ -64,7 +72,7 @@ def user_cache_dir(appname):
return path
def user_data_dir(appname, roaming=False):
def user_data_dir(appname, roaming=False): # type: (str, bool) -> str
r"""
Return full path to the user-specific data dir for this application.
......@@ -104,7 +112,7 @@ def user_data_dir(appname, roaming=False):
return path
def user_config_dir(appname, roaming=True):
def user_config_dir(appname, roaming=True): # type: (str, bool) -> str
"""Return full path to the user-specific config dir for this application.
"appname" is the name of application.
......@@ -137,7 +145,7 @@ def user_config_dir(appname, roaming=True):
# for the discussion regarding site_config_dirs locations
# see <https://github.com/pypa/pip/issues/1733>
def site_config_dirs(appname):
def site_config_dirs(appname): # type: (str) -> List[str]
r"""Return a list of potential user-shared config dirs for this application.
"appname" is the name of application.
......@@ -178,7 +186,7 @@ def site_config_dirs(appname):
# -- Windows support functions --
def _get_win_folder_from_registry(csidl_name):
def _get_win_folder_from_registry(csidl_name): # type: (str) -> str
"""
This is a fallback technique at best. I'm not sure if using the
registry for this guarantees us the correct answer for all CSIDL_*
......@@ -200,7 +208,7 @@ def _get_win_folder_from_registry(csidl_name):
return directory
def _get_win_folder_with_ctypes(csidl_name):
def _get_win_folder_with_ctypes(csidl_name): # type: (str) -> str
csidl_const = {
"CSIDL_APPDATA": 26,
"CSIDL_COMMON_APPDATA": 35,
......@@ -234,7 +242,7 @@ if WINDOWS:
_get_win_folder = _get_win_folder_from_registry
def _win_path_to_bytes(path):
def _win_path_to_bytes(path): # type: (str) -> Union[str, bytes]
"""Encode Windows paths to bytes. Only used on Python 2.
Motivation is to be consistent with other operating systems where paths
......
......@@ -15,6 +15,7 @@ from pathlib import Path
from subprocess import CalledProcessError
from typing import Any
from typing import Dict
from typing import Iterator
from typing import List
from typing import Optional
from typing import Tuple
......@@ -252,7 +253,7 @@ class SitePackages:
if value[-1] is True
]
def __getattr__(self, item):
def __getattr__(self, item): # type: (str) -> Any
try:
return super(SitePackages, self).__getattribute__(item)
except AttributeError:
......@@ -265,7 +266,9 @@ class EnvError(Exception):
class EnvCommandError(EnvError):
def __init__(self, e, input=None): # type: (CalledProcessError) -> None
def __init__(
self, e, input=None
): # type: (CalledProcessError, Optional[str]) -> None
self.e = e
message = "Command {} errored with the following return code {}, and output: \n{}".format(
......@@ -277,7 +280,7 @@ class EnvCommandError(EnvError):
class NoCompatiblePythonVersionFound(EnvError):
def __init__(self, expected, given=None):
def __init__(self, expected, given=None): # type: (str, Optional[str]) -> None
if given:
message = (
"The specified Python version ({}) "
......@@ -618,7 +621,7 @@ class EnvManager(object):
def create_venv(
self, io, name=None, executable=None, force=False
): # type: (IO, Optional[str], Optional[str], bool) -> Env
): # type: (IO, Optional[str], Optional[str], bool) -> VirtualEnv
if self._env is not None and not force:
return self._env
......@@ -849,12 +852,12 @@ class EnvManager(object):
def get_base_prefix(self): # type: () -> Path
if hasattr(sys, "real_prefix"):
return sys.real_prefix
return Path(sys.real_prefix)
if hasattr(sys, "base_prefix"):
return sys.base_prefix
return Path(sys.base_prefix)
return sys.prefix
return Path(sys.prefix)
@classmethod
def generate_env_name(cls, name, cwd): # type: (str, str) -> str
......@@ -913,7 +916,7 @@ class Env(object):
return self._bin("python")
@property
def marker_env(self):
def marker_env(self): # type: () -> Dict[str, Any]
if self._marker_env is None:
self._marker_env = self.get_marker_env()
......@@ -935,7 +938,7 @@ class Env(object):
return os.name
@property
def pip_version(self):
def pip_version(self): # type: () -> Version
if self._pip_version is None:
self._pip_version = self.get_pip_version()
......@@ -1009,12 +1012,12 @@ class Env(object):
@classmethod
def get_base_prefix(cls): # type: () -> Path
if hasattr(sys, "real_prefix"):
return sys.real_prefix
return Path(sys.real_prefix)
if hasattr(sys, "base_prefix"):
return sys.base_prefix
return Path(sys.base_prefix)
return sys.prefix
return Path(sys.prefix)
def get_version_info(self): # type: () -> Tuple[int]
raise NotImplementedError()
......@@ -1046,17 +1049,17 @@ class Env(object):
"""
return True
def run(self, bin, *args, **kwargs):
def run(self, bin, *args, **kwargs): # type: (str, *str, **Any) -> Union[str, int]
bin = self._bin(bin)
cmd = [bin] + list(args)
return self._run(cmd, **kwargs)
def run_pip(self, *args, **kwargs):
def run_pip(self, *args, **kwargs): # type: (*str, **Any) -> Union[int, str]
pip = self.get_pip_command()
cmd = pip + list(args)
return self._run(cmd, **kwargs)
def _run(self, cmd, **kwargs):
def _run(self, cmd, **kwargs): # type: (List[str], **Any) -> Union[int, str]
"""
Run a command inside the Python environment.
"""
......@@ -1077,7 +1080,7 @@ class Env(object):
stderr=subprocess.STDOUT,
input=encode(input_),
check=True,
**kwargs
**kwargs,
).stdout
elif call:
return subprocess.call(cmd, stderr=subprocess.STDOUT, **kwargs)
......@@ -1090,7 +1093,9 @@ class Env(object):
return decode(output)
def execute(self, bin, *args, **kwargs):
def execute(
self, bin, *args, **kwargs
): # type: (str, *str, **Any) -> Optional[int]
bin = self._bin(bin)
if not self._is_windows:
......@@ -1145,7 +1150,7 @@ class Env(object):
def __eq__(self, other): # type: (Env) -> bool
return other.__class__ == self.__class__ and other.path == self.path
def __repr__(self):
def __repr__(self): # type: () -> str
return '{}("{}")'.format(self.__class__.__name__, self._path)
......@@ -1332,11 +1337,11 @@ class VirtualEnv(Env):
def is_venv(self): # type: () -> bool
return True
def is_sane(self):
def is_sane(self): # type: () -> bool
# A virtualenv is considered sane if both "python" and "pip" exist.
return os.path.exists(self.python) and os.path.exists(self._bin("pip"))
def _run(self, cmd, **kwargs):
def _run(self, cmd, **kwargs): # type: (List[str], **Any) -> Optional[int]
with self.temp_environ():
os.environ["PATH"] = self._updated_path()
os.environ["VIRTUAL_ENV"] = str(self._path)
......@@ -1346,7 +1351,9 @@ class VirtualEnv(Env):
return super(VirtualEnv, self)._run(cmd, **kwargs)
def execute(self, bin, *args, **kwargs):
def execute(
self, bin, *args, **kwargs
): # type: (str, *str, **Any) -> Optional[int]
with self.temp_environ():
os.environ["PATH"] = self._updated_path()
os.environ["VIRTUAL_ENV"] = str(self._path)
......@@ -1357,7 +1364,7 @@ class VirtualEnv(Env):
return super(VirtualEnv, self).execute(bin, *args, **kwargs)
@contextmanager
def temp_environ(self):
def temp_environ(self): # type: () -> Iterator[None]
environ = dict(os.environ)
try:
yield
......@@ -1365,16 +1372,18 @@ class VirtualEnv(Env):
os.environ.clear()
os.environ.update(environ)
def unset_env(self, key):
def unset_env(self, key): # type: (str) -> None
if key in os.environ:
del os.environ[key]
def _updated_path(self):
def _updated_path(self): # type: () -> str
return os.pathsep.join([str(self._bin_dir), os.environ.get("PATH", "")])
class NullEnv(SystemEnv):
def __init__(self, path=None, base=None, execute=False):
def __init__(
self, path=None, base=None, execute=False
): # type: (Path, Optional[Path], bool) -> None
if path is None:
path = Path(sys.prefix)
......@@ -1386,35 +1395,37 @@ class NullEnv(SystemEnv):
def get_pip_command(self): # type: () -> List[str]
return [self._bin("python"), "-m", "pip"]
def _run(self, cmd, **kwargs):
def _run(self, cmd, **kwargs): # type: (List[str], **Any) -> int
self.executed.append(cmd)
if self._execute:
return super(NullEnv, self)._run(cmd, **kwargs)
def execute(self, bin, *args, **kwargs):
def execute(
self, bin, *args, **kwargs
): # type: (str, *str, **Any) -> Optional[int]
self.executed.append([bin] + list(args))
if self._execute:
return super(NullEnv, self).execute(bin, *args, **kwargs)
def _bin(self, bin):
def _bin(self, bin): # type: (str) -> str
return bin
class MockEnv(NullEnv):
def __init__(
self,
version_info=(3, 7, 0),
python_implementation="CPython",
platform="darwin",
os_name="posix",
is_venv=False,
pip_version="19.1",
sys_path=None,
marker_env=None,
supported_tags=None,
**kwargs
version_info=(3, 7, 0), # type: Tuple[int, int, int]
python_implementation="CPython", # type: str
platform="darwin", # type: str
os_name="posix", # type: str
is_venv=False, # type: bool
pip_version="19.1", # type: str
sys_path=None, # type: Optional[List[str]]
marker_env=None, # type: Dict[str, Any]
supported_tags=None, # type: List[Tag]
**kwargs, # type: Any
):
super(MockEnv, self).__init__(**kwargs)
......@@ -1437,11 +1448,11 @@ class MockEnv(NullEnv):
return self._os_name
@property
def pip_version(self):
def pip_version(self): # type: () -> Version
return self._pip_version
@property
def sys_path(self):
def sys_path(self): # type: () -> List[str]
if self._sys_path is None:
return super(MockEnv, self).sys_path
......
from typing import Iterable
from typing import Iterator
from typing import List
from typing import Mapping
......@@ -36,7 +37,7 @@ def get_extra_package_names(
# keep record of packages seen during recursion in order to avoid recursion error
seen_package_names = set()
def _extra_packages(package_names):
def _extra_packages(package_names): # type: (Iterable[str]) -> Iterator[str]
"""Recursively find dependencies for packages names"""
# for each extra pacakge name
for package_name in package_names:
......
......@@ -6,6 +6,10 @@ import tempfile
from contextlib import contextmanager
from pathlib import Path
from typing import Any
from typing import Callable
from typing import Dict
from typing import Iterator
from typing import List
from typing import Optional
......@@ -37,13 +41,13 @@ def normalize_version(version): # type: (str) -> str
return str(Version(version))
def _del_ro(action, name, exc):
def _del_ro(action, name, exc): # type: (Callable, str, Exception) -> None
os.chmod(name, stat.S_IWRITE)
os.remove(name)
@contextmanager
def temporary_directory(*args, **kwargs):
def temporary_directory(*args, **kwargs): # type: (*Any, **Any) -> Iterator[str]
name = tempfile.mkdtemp(*args, **kwargs)
yield name
......@@ -67,7 +71,7 @@ def get_client_cert(config, repository_name): # type: (Config, str) -> Optional
return None
def _on_rm_error(func, path, exc_info):
def _on_rm_error(func, path, exc_info): # type: (Callable, str, Exception) -> None
if not os.path.exists(path):
return
......@@ -75,14 +79,14 @@ def _on_rm_error(func, path, exc_info):
func(path)
def safe_rmtree(path):
def safe_rmtree(path): # type: (str) -> None
if Path(path).is_symlink():
return os.unlink(str(path))
shutil.rmtree(path, onerror=_on_rm_error)
def merge_dicts(d1, d2):
def merge_dicts(d1, d2): # type: (Dict, Dict) -> None
for k, v in d2.items():
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], Mapping):
merge_dicts(d1[k], d2[k])
......
import logging
from typing import TYPE_CHECKING
from typing import Dict
from typing import Optional
if TYPE_CHECKING:
from poetry.config.config import Config # noqa
logger = logging.getLogger(__name__)
......@@ -15,16 +22,16 @@ class KeyRingError(Exception):
class KeyRing:
def __init__(self, namespace):
def __init__(self, namespace): # type: (str) -> None
self._namespace = namespace
self._is_available = True
self._check()
def is_available(self):
def is_available(self): # type: () -> bool
return self._is_available
def get_password(self, name, username):
def get_password(self, name, username): # type: (str, str) -> Optional[str]
if not self.is_available():
return
......@@ -40,7 +47,7 @@ class KeyRing:
"Unable to retrieve the password for {} from the key ring".format(name)
)
def set_password(self, name, username, password):
def set_password(self, name, username, password): # type: (str, str, str) -> None
if not self.is_available():
return
......@@ -58,7 +65,7 @@ class KeyRing:
)
)
def delete_password(self, name, username):
def delete_password(self, name, username): # type: (str, str) -> None
if not self.is_available():
return
......@@ -74,10 +81,10 @@ class KeyRing:
"Unable to delete the password for {} from the key ring".format(name)
)
def get_entry_name(self, name):
def get_entry_name(self, name): # type: (str) -> str
return "{}-{}".format(self._namespace, name)
def _check(self):
def _check(self): # type: () -> None
try:
import keyring
except Exception as e:
......@@ -113,12 +120,12 @@ class KeyRing:
class PasswordManager:
def __init__(self, config):
def __init__(self, config): # type: ("Config") -> None
self._config = config
self._keyring = None
@property
def keyring(self):
def keyring(self): # type: () -> KeyRing
if self._keyring is None:
self._keyring = KeyRing("poetry-repository")
if not self._keyring.is_available():
......@@ -128,7 +135,7 @@ class PasswordManager:
return self._keyring
def set_pypi_token(self, name, token):
def set_pypi_token(self, name, token): # type: (str, str) -> None
if not self.keyring.is_available():
self._config.auth_config_source.add_property(
"pypi-token.{}".format(name), token
......@@ -136,13 +143,13 @@ class PasswordManager:
else:
self.keyring.set_password(name, "__token__", token)
def get_pypi_token(self, name):
def get_pypi_token(self, name): # type: (str) -> str
if not self.keyring.is_available():
return self._config.get("pypi-token.{}".format(name))
return self.keyring.get_password(name, "__token__")
def delete_pypi_token(self, name):
def delete_pypi_token(self, name): # type: (str) -> None
if not self.keyring.is_available():
return self._config.auth_config_source.remove_property(
"pypi-token.{}".format(name)
......@@ -150,7 +157,7 @@ class PasswordManager:
self.keyring.delete_password(name, "__token__")
def get_http_auth(self, name):
def get_http_auth(self, name): # type: (str) -> Optional[Dict[str, str]]
auth = self._config.get("http-basic.{}".format(name))
if not auth:
username = self._config.get("http-basic.{}.username".format(name))
......@@ -167,7 +174,9 @@ class PasswordManager:
"password": password,
}
def set_http_password(self, name, username, password):
def set_http_password(
self, name, username, password
): # type: (str, str, str) -> None
auth = {"username": username}
if not self.keyring.is_available():
......@@ -177,7 +186,7 @@ class PasswordManager:
self._config.auth_config_source.add_property("http-basic.{}".format(name), auth)
def delete_http_password(self, name):
def delete_http_password(self, name): # type: (str) -> None
auth = self.get_http_auth(name)
if not auth or "username" not in auth:
return
......
......@@ -356,7 +356,9 @@ class SetupReader(object):
if target.id == name:
return elem.value
def _find_in_dict(self, dict_, name): # type: (ast.Call, str) -> Optional[Any]
def _find_in_dict(
self, dict_, name
): # type: (Union[ast.Dict, ast.Call], str) -> Optional[Any]
for key, val in zip(dict_.keys, dict_.values):
if isinstance(key, ast.Str) and key.s == name:
return val
......@@ -3,6 +3,7 @@ import signal
import sys
from pathlib import Path
from typing import Any
import pexpect
......@@ -78,7 +79,7 @@ class Shell:
activate_path = env.path / bin_dir / activate_script
c.sendline("{} {}".format(self._get_source_command(), activate_path))
def resize(sig, data):
def resize(sig, data): # type: (Any, Any) -> None
terminal = Terminal()
c.setwinsize(terminal.height, terminal.width)
......@@ -90,7 +91,7 @@ class Shell:
sys.exit(c.exitstatus)
def _get_activate_script(self):
def _get_activate_script(self): # type: () -> str
if "fish" == self._name:
suffix = ".fish"
elif "csh" == self._name:
......@@ -102,7 +103,7 @@ class Shell:
return "activate" + suffix
def _get_source_command(self):
def _get_source_command(self): # type: () -> str
if "fish" == self._name:
return "source"
elif "csh" == self._name:
......
from typing import TYPE_CHECKING
from typing import Optional
from typing import Union
from poetry.core.packages import Package
from poetry.core.semver import Version
if TYPE_CHECKING:
from poetry.repositories import Pool # noqa
class VersionSelector(object):
def __init__(self, pool):
def __init__(self, pool): # type: ("Pool") -> None
self._pool = pool
def find_best_candidate(
self,
package_name, # type: str
target_package_version=None, # type: Union[str, None]
target_package_version=None, # type: Optional[str]
allow_prereleases=False, # type: bool
source=None, # type: str
source=None, # type: Optional[str]
): # type: (...) -> Union[Package, bool]
"""
Given a package name and optional version,
......@@ -52,12 +58,12 @@ class VersionSelector(object):
return False
return package
def find_recommended_require_version(self, package):
def find_recommended_require_version(self, package): # type: (Package) -> str
version = package.version
return self._transform_version(version.text, package.pretty_version)
def _transform_version(self, version, pretty_version):
def _transform_version(self, version, pretty_version): # type: (str, str) -> str
try:
parsed = Version.parse(version)
parts = [parsed.major, parsed.minor, parsed.patch]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment