Skip to content
This repository has been archived by the owner on Jan 12, 2021. It is now read-only.

Commit

Permalink
Merge pull request #459 from dephell/more-types-2
Browse files Browse the repository at this point in the history
Type check controllers
  • Loading branch information
orsinium committed Aug 24, 2020
2 parents 657b25a + c0eb923 commit b9a7f59
Show file tree
Hide file tree
Showing 22 changed files with 123 additions and 176 deletions.
27 changes: 27 additions & 0 deletions dephell/cached_property.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# built-in
from typing import Any, Callable, Generic, Optional, Type, TypeVar, overload


_AnyCallable = Callable[..., Any]

_T = TypeVar("_T")
_S = TypeVar("_S")


# https://github.com/python/typeshed/blob/master/stdlib/3/functools.pyi
class cached_property(Generic[_S, _T]):
func: Callable[[_S], _T]

def __init__(self, func: Callable[[_S], _T]) -> None:
...

@overload
def __get__(self, instance: None, owner: Optional[Type[_S]] = ...) -> 'cached_property[_S, _T]':
...

@overload
def __get__(self, instance: _S, owner: Optional[Type[_S]] = ...) -> _T:
...

def __set_name__(self, owner: Type[_S], name: str) -> None:
...
2 changes: 2 additions & 0 deletions dephell/commands/deps_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def __call__(self) -> bool:
data = []
reqs = Requirement.from_graph(graph=resolver.graph, lock=True)
for req in reqs:
if not req.version:
continue
version = req.version.strip('=')
# not installed
if req.name not in installed:
Expand Down
2 changes: 2 additions & 0 deletions dephell/commands/deps_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ def _get_install_remove(self, graph, python) -> Tuple[list, list]:
install.append(req)
continue
# installed the same version, skip
if not req.version:
continue
version = req.version.strip('=')
if version in installed[req.name]:
continue
Expand Down
2 changes: 1 addition & 1 deletion dephell/commands/project_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def __call__(self) -> bool:
venv.create(python_path=python.path)

# copy tests
for path in self.config['tests']: # type: Path # type: ignore
for path in self.config['tests']: # type: Path
self.logger.info('copy files', extra=dict(path=path))
path = Path(path)
if not path.exists():
Expand Down
3 changes: 0 additions & 3 deletions dephell/controllers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from ._repos import RepositoriesRegistry
from ._resolver import Resolver
from ._safety import Safety, SafetyVulnInfo
from ._snyk import Snyk, SnykVulnInfo
from ._uploader import Uploader


Expand All @@ -24,7 +23,5 @@
'Resolver',
'Safety',
'SafetyVulnInfo',
'Snyk',
'SnykVulnInfo',
'Uploader',
]
2 changes: 2 additions & 0 deletions dephell/controllers/_conflict.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# built-in
import re
from logging import getLogger
from typing import Tuple

# external
from jinja2 import Environment, PackageLoader
Expand Down Expand Up @@ -47,6 +48,7 @@ def analyze_conflict(resolver, suffix: str = '') -> str:
logger.warning(e.args[0])

conflict = resolver.graph.conflict
templates: Tuple[str, ...]
if conflict is None:
templates = ('state.html.j2', )
elif not resolver.graph.conflict.python_compat:
Expand Down
25 changes: 16 additions & 9 deletions dephell/controllers/_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@
from ..networking import requests_session


docker = lazy_import('docker')
dockerpty = lazy_import('dockerpty')

if TYPE_CHECKING:
# external
import docker
import dockerpty


docker = lazy_import('docker') # noqa: F811
dockerpty = lazy_import('dockerpty') # noqa: F811


DOCKER_PREFIX = 'dephell-'


Expand Down Expand Up @@ -142,14 +143,18 @@ def create(self, *, pull=True) -> None:
)

def stop(self) -> None:
self.container.stop()
if self.container:
self.container.stop()

def remove(self) -> None:
self.stop()
self.container.remove(force=True)
for container in self.network.containers:
self.network.disconnect(container, force=True)
self.network.remove()
if self.container:
self.stop()
self.container.remove(force=True)

if self.network:
for container in self.network.containers:
self.network.disconnect(container, force=True)
self.network.remove()

def exists(self) -> bool:
if 'container' in self.__dict__:
Expand All @@ -162,6 +167,8 @@ def activate(self) -> None:
def run(self, command: List[str]) -> None:
if dockerpty is None:
raise RuntimeError('cannot run Docker on Windows')
if not self.container:
raise RuntimeError('cannot find container')
self.container.start()
dockerpty.exec_command(
client=self.client.api,
Expand Down
15 changes: 9 additions & 6 deletions dephell/controllers/_graph.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
# built-in
from collections import ChainMap
from logging import getLogger
from typing import TYPE_CHECKING, Iterator, Optional
from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional

# app
from ..imports import lazy_import
from ..models.dependency import Dependency
from ..models.root import RootDependency


graphviz = lazy_import('graphviz')
graphviz_backend = lazy_import('graphviz.backend')


if TYPE_CHECKING:
# external
import graphviz
import graphviz.backend as graphviz_backend


graphviz = lazy_import('graphviz') # noqa: F811
graphviz_backend = lazy_import('graphviz.backend') # noqa: F811


logger = getLogger(__name__)


class Layer:
_mapping: Dict[str, Any]

def __init__(self, level: int, *deps):
self.level = level
self._mapping = dict()
Expand Down Expand Up @@ -75,7 +77,8 @@ def __repr__(self):


class Graph:
conflict = None # type: Optional[Dependency]
conflict: Optional[Dependency] = None
_layers: List[Layer]

def __init__(self, *roots: RootDependency) -> None:
for root in roots:
Expand Down
5 changes: 3 additions & 2 deletions dephell/controllers/_mutator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# built-in
from itertools import product
from logging import getLogger
from typing import Iterable, Iterator, Optional, Sequence, Set, Tuple
from typing import Iterable, Iterator, List, Optional, Sequence, Set, Tuple

# external
import attr
Expand All @@ -17,7 +17,7 @@


def lazy_product(*all_groups) -> Iterator:
slices = [[] for _ in range(len(all_groups))]
slices: List[List[str]] = [[] for _ in range(len(all_groups))]
all_groups = [iter(groups) for groups in all_groups]

while True:
Expand Down Expand Up @@ -62,6 +62,7 @@ def mutate(self, graph: Graph) -> Optional[Tuple[Group, ...]]:
self._check_not_empty,
# self._check_soft,
)
assert graph.conflict # hint for mypy
for check in checker:
for groups in self.get_mutations(deps=parents):
if check(groups=groups, deps=parents, conflict=graph.conflict):
Expand Down
37 changes: 25 additions & 12 deletions dephell/controllers/_repos.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# built-in
from functools import lru_cache
from pathlib import Path
from typing import Dict, Iterable, List, Optional
from typing import Dict, Iterable, List, Optional, Set, Type, Union
from urllib.parse import urljoin, urlparse

# external
Expand Down Expand Up @@ -31,14 +31,12 @@ def _has_api(url: str) -> bool:

@attr.s()
class RepositoriesRegistry(WarehouseBaseRepo):
repos = attr.ib(factory=list)
repos: List[WarehouseBaseRepo] = attr.ib(factory=list)
prereleases = attr.ib(type=bool, factory=lambda: global_config['prereleases']) # allow prereleases
from_config = attr.ib(type=bool, default=False)

_urls = attr.ib(factory=set)
_names = attr.ib(factory=set)

propagate = True
_urls: Set[str] = attr.ib(factory=set)
_names: Set[str] = attr.ib(factory=set)

def add_repo(self, *, url: str, name: str = None, from_config: bool = False) -> bool:
if url in self._urls:
Expand Down Expand Up @@ -74,8 +72,11 @@ def add_repo(self, *, url: str, name: str = None, from_config: bool = False) ->
name = urlparse(url).hostname
if name in self._names:
return False
if not name:
name = 'pypi'
self._names.add(name)

cls: Union[Type[WarehouseAPIRepo], Type[WarehouseSimpleRepo]]
if _has_api(url=url):
cls = WarehouseAPIRepo
else:
Expand Down Expand Up @@ -132,23 +133,27 @@ def make(self, name: str) -> 'RepositoriesRegistry':
return type(self)(repos=repos, prereleases=self.prereleases)

def get_releases(self, dep) -> tuple:
first_exception = None
first_exception: Optional[Exception] = None
for repo in self.repos:
try:
return repo.get_releases(dep=dep)
except PackageNotFoundError as exc:
if first_exception is None:
first_exception = exc
if first_exception is None:
raise LookupError('no repositories in registry')
raise first_exception

async def get_dependencies(self, name: str, version: str, extra: Optional[str] = None) -> tuple:
first_exception = None
first_exception: Optional[Exception] = None
for repo in self.repos:
try:
return await repo.get_dependencies(name=name, version=version, extra=extra)
except PackageNotFoundError as exc:
if first_exception is None:
first_exception = exc
if first_exception is None:
raise LookupError('no repositories in registry')
raise first_exception

def search(self, query: Iterable[str]) -> List[Dict[str, str]]:
Expand All @@ -166,17 +171,25 @@ async def download(self, name: str, version: str, path: Path) -> bool:
# properties

@property
def name(self) -> str:
def name(self) -> str: # type: ignore
return self.repos[0].name

@property
def url(self) -> str:
@property # type: ignore
def url(self) -> str: # type: ignore
return self.repos[0].url

@url.setter
def url(self, url: str):
self.repos[0].url = url

@property
def pretty_url(self) -> str:
return self.url

@pretty_url.setter
def pretty_url(self, url: str):
self.repos[0].url = url

@property
def propagate(self) -> bool:
def propagate(self) -> bool: # type: ignore
return self.repos[0].propagate
6 changes: 5 additions & 1 deletion dephell/controllers/_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ def _resolve(self, debug: bool, silent: bool, level: Optional[int], spinner) ->
))
self.unapply(dep)
dep.group = group
return None

def apply_envs(self, envs: set, deep: bool = True) -> None:
"""Filter out dependencies from the graph by the given envs.
Expand Down Expand Up @@ -191,7 +192,10 @@ def apply_markers(self, python) -> None:

# get only base part of python version because `packagings` drops
# all markers for python prereleases
python_version = REX_BASE_VERSION.match(str(python.version)).group()
python_version = str(python.version)
match = REX_BASE_VERSION.match(python_version)
if match:
python_version = match.group()

for dep in self.graph:
if not dep.applied:
Expand Down
2 changes: 1 addition & 1 deletion dephell/controllers/_safety.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def vulns(self) -> Dict[str, Tuple[SafetyVulnInfo, ...]]:
return vulns

def get(self, name: str, version: Union[str, Version]) -> List[SafetyVulnInfo]:
if type(version) is str:
if isinstance(version, str):
version = Version(version)
vulns = []
for vuln in self.vulns.get(name, []):
Expand Down
Loading

0 comments on commit b9a7f59

Please sign in to comment.