diff --git a/.gitignore b/.gitignore index d4163725b2..d45f349939 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ docs/moduleguides .mypy_cache mypy types +mypy.xml +coverage diff --git a/requirements.txt b/requirements.txt index 8c4c919eaf..f7127ef38b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,5 +21,6 @@ sphinx-rtd-theme==0.4.2 sphinx==1.8.1 texttable==1.5.0 tornado==4.5.3 +tox==3.5.3 typing==3.6.6 virtualenv==16.1.0 diff --git a/src/inmanta/agent/agent.py b/src/inmanta/agent/agent.py index df3eaf101e..e1d726b61a 100644 --- a/src/inmanta/agent/agent.py +++ b/src/inmanta/agent/agent.py @@ -39,6 +39,7 @@ from inmanta.agent import config as cfg from inmanta.agent.reporting import collect_report from inmanta.const import ResourceState +from typing import Tuple LOGGER = logging.getLogger(__name__) GET_RESOURCE_BACKOFF = 5 @@ -90,7 +91,7 @@ def cancel(self): self.future.set_result(ResourceActionResult(False, False, True)) @gen.coroutine - def _execute(self, ctx: handler.HandlerContext, events: dict, cache: AgentCache, event_only: bool=False) -> (bool, bool): + def _execute(self, ctx: handler.HandlerContext, events: dict, cache: AgentCache, event_only: bool=False) -> Tuple[bool, bool]: """ :param ctx The context to use during execution of this deploy :param events Possible events that are available for this resource @@ -362,7 +363,7 @@ def get_client(self): class AgentInstance(object): - def __init__(self, process, name: str, uri: str): + def __init__(self, process, name: str, uri: str) -> None: self.process = process self.name = name self._uri = uri diff --git a/src/inmanta/agent/handler.py b/src/inmanta/agent/handler.py index 24581d8e8c..75e2008a7c 100644 --- a/src/inmanta/agent/handler.py +++ b/src/inmanta/agent/handler.py @@ -45,7 +45,7 @@ class provider(object): # noqa: H801 :param name: A name to reference this provider. """ - def __init__(self, resource_type: str, name: str): + def __init__(self, resource_type: str, name: str) -> None: self._resource_type = resource_type self._name = name diff --git a/src/inmanta/agent/io/local.py b/src/inmanta/agent/io/local.py index fa0b7b8a73..7f64afe1a0 100644 --- a/src/inmanta/agent/io/local.py +++ b/src/inmanta/agent/io/local.py @@ -569,7 +569,7 @@ def rmdir(self, path): global channel if os.getuid() == 0: - local_io = LocalIO(uri="local:", config={}) + local_io = LocalIO(uri="local:", config={}) # type: IOBase else: local_io = BashIO(uri="local:", config={}, run_as="root") diff --git a/src/inmanta/ast/__init__.py b/src/inmanta/ast/__init__.py index 698c806f29..45455350d4 100644 --- a/src/inmanta/ast/__init__.py +++ b/src/inmanta/ast/__init__.py @@ -52,7 +52,7 @@ def __eq__(self, other: object) -> bool: return False return self.file == other.file and self.lnr == other.lnr - def merge(self, other): + def merge(self, other: "Location") -> "Location": if other is None: return self @@ -70,7 +70,7 @@ def __init__(self, file: str, start_lnr: int, start_char: int, end_lnr: int, end self.end_lnr = end_lnr self.end_char = end_char - def merge(self, other): + def merge(self, other: Location) -> Location: if other is None: return self @@ -107,10 +107,10 @@ def __str__(self) -> str: class Locatable(object): - def __init__(self): - self._location = None # type: Location + def __init__(self) -> None: + self._location = None # type: Optional[Location] - def set_location(self, location: Location): + def set_location(self, location: Location) -> None: assert location is not None and location.lnr > 0 self._location = location @@ -135,7 +135,7 @@ class LocatableString(object): 2. in the constructors of other statements """ - def __init__(self, value, location: Range, lexpos, namespace): + def __init__(self, value, location: Range, lexpos: "int", namespace: "Namespace") -> None: self.value = value self.location = location @@ -159,7 +159,7 @@ def __str__(self): class Anchor(object): - def __init__(self, range: Range): + def __init__(self, range: Range) -> None: self.range = range def get_range(self) -> Range: @@ -169,31 +169,31 @@ def get_location(self) -> Range: return self.range @abstractmethod - def resolve(self): + def resolve(self) -> Location: raise NotImplementedError() class TypeReferenceAnchor(Anchor): - def __init__(self, range: Range, namespace: "Namespace", type: str): + def __init__(self, range: Range, namespace: "Namespace", type: str) -> None: Anchor.__init__(self, range=range) self.namespace = namespace self.type = type - def resolve(self): + def resolve(self) -> Location: t = self.namespace.get_type(self.type) return t.get_location() class AttributeReferenceAnchor(Anchor): - def __init__(self, range: Range, namespace: "Namespace", type: str, attribute: str): + def __init__(self, range: Range, namespace: "Namespace", type: str, attribute: str) -> None: Anchor.__init__(self, range=range) self.namespace = namespace self.type = type self.attribute = attribute - def resolve(self): + def resolve(self) -> Location: return self.namespace.get_type(self.type).get_attribute(self.attribute).get_location() @@ -234,9 +234,10 @@ def __init__(self, name: str, parent: "Optional[Namespace]"=None) -> None: self.visible_namespaces = {self.get_full_name(): MockImport(self)} self.__parent.add_child(self) else: + # type: Dict[str,Union[DefineImport, MockImport]] self.visible_namespaces = {name: MockImport(self)} - self.primitives = None # type: Dict[str,Type] - self.scope = None # type: ExecutionContext + self.primitives = None # type: Optional[Dict[str,Type]] + self.scope = None # type: Optional[ExecutionContext] def set_primitives(self, primitives: "Dict[str,Type]") -> None: self.primitives = primitives diff --git a/src/inmanta/export.py b/src/inmanta/export.py index 2baed1f23e..cfbf8cdc86 100644 --- a/src/inmanta/export.py +++ b/src/inmanta/export.py @@ -580,7 +580,7 @@ def convert_attribute(attr): def convert_relation(relation: RelationAttribute): return model.Relation(relation.type.get_full_name(), - [relation.low, relation.high], + (relation.low, relation.high), relation_name(relation.type, relation.end), convert_comment(relation.comment), location(relation), [convert_value_for_type(x.get_value()) for x in relation.source_annotations], diff --git a/src/inmanta/model.py b/src/inmanta/model.py index 1159579852..5787b7c292 100644 --- a/src/inmanta/model.py +++ b/src/inmanta/model.py @@ -69,7 +69,7 @@ class Attribute(object): :param Location location: source location where this attribute is defined """ - def __init__(self, mytype: str, nullable: bool, multi: bool, comment: str, location: Location): + def __init__(self, mytype: str, nullable: bool, multi: bool, comment: str, location: Location) -> None: self.type = mytype self.nullable = nullable self.multi = multi @@ -191,7 +191,7 @@ class Relation(object): """ def __init__(self, mytype: str, multi: Tuple[int, int], reverse: str, comment: str, location: Location, - source_annotations: List[Value], target_annotations: List[Value]): + source_annotations: List[Value], target_annotations: List[Value]) -> None: self.type = mytype lower = multi[0] if lower is None: @@ -259,7 +259,7 @@ class Entity(object): """ def __init__(self, parents: List[str], attributes: Dict[str, Attribute], - relations: Dict[str, Relation], location: Location): + relations: Dict[str, Relation], location: Location) -> None: self.parents = parents self.attributes = attributes self.relations = relations diff --git a/src/inmanta/module.py b/src/inmanta/module.py index 8a2eb2e5bc..e55b0c416d 100644 --- a/src/inmanta/module.py +++ b/src/inmanta/module.py @@ -345,14 +345,14 @@ def _load_file(self, ns, file) -> Tuple[List[Statement], BasicBlock]: block.add(s) return (statements, block) - def requires(self) -> dict: + def requires(self) -> "List[List[Requirement]]": """ Get the requires for this module """ # filter on import stmt if "requires" not in self._meta or self._meta["requires"] is None: - return {} + return [] reqs = [] for spec in self._meta["requires"]: diff --git a/src/inmanta/moduletool.py b/src/inmanta/moduletool.py index 1a92415361..bb7da74730 100644 --- a/src/inmanta/moduletool.py +++ b/src/inmanta/moduletool.py @@ -20,7 +20,7 @@ import inspect import logging import os -from os.path import sys +import sys import shutil import subprocess import tempfile diff --git a/src/inmanta/server/agentmanager.py b/src/inmanta/server/agentmanager.py index 8964acc6d7..040f11546b 100644 --- a/src/inmanta/server/agentmanager.py +++ b/src/inmanta/server/agentmanager.py @@ -437,8 +437,8 @@ def _ensure_agents(self, env: data.Environment, agents: list, restart: bool=Fals LOGGER.info("%s matches agents managed by server, ensuring it is started.", agents) for agent in agents: with (yield self.session_lock.acquire()): - agent = self.get_agent_client(env.id, agent) - if agent is None: + myagent = self.get_agent_client(env.id, agent) + if myagent is None: needsstart = True if needsstart: diff --git a/tox.ini b/tox.ini index e77ac4ac78..d7eca83b35 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py34,py35,py36,pep8 +envlist = py34,py35,py36,pep8,mypy skip_missing_interpreters=True [pep8] @@ -53,3 +53,15 @@ changedir=docs deps=pytest -rrequirements.txt commands=py.test -v check_sphinx.py + + +[testenv:mypy] +deps= + mypy + lxml +commands_pre = mkdir -p coverage +whitelist_externals = */mkdir +commands = + python -m mypy src --ignore-missing-imports --junit-xml mypy.xml --cobertura-xml-report coverage +basepython = python3 +ignore_outcome = true