Update mypy test. Fix type hints for Python 3.9.

This also bumps the minimum controller version (for mypy only) to Python 3.9.
pull/77679/head
Matt Clay 3 years ago
parent 7471c036ec
commit cc5ac88c4c

@ -156,7 +156,7 @@ class CollectionVerifyResult:
def verify_local_collection(local_collection, remote_collection, artifacts_manager):
# type: (Candidate, Candidate | None, ConcreteArtifactsManager) -> CollectionVerifyResult
# type: (Candidate, t.Optional[Candidate], ConcreteArtifactsManager) -> CollectionVerifyResult
"""Verify integrity of the locally installed collection.
:param local_collection: Collection being checked.

@ -88,7 +88,7 @@ class ConcreteArtifactsManager:
return self._ignore_signature_errors
def get_galaxy_artifact_source_info(self, collection):
# type: (Candidate) -> dict[str, str | list[dict[str, str]]]
# type: (Candidate) -> dict[str, t.Union[str, list[dict[str, str]]]]
server = collection.src.api_server
try:
@ -112,7 +112,7 @@ class ConcreteArtifactsManager:
}
def get_galaxy_artifact_path(self, collection):
# type: (Candidate | Requirement) -> bytes
# type: (t.Union[Candidate, Requirement]) -> bytes
"""Given a Galaxy-stored collection, return a cached path.
If it's not yet on disk, this method downloads the artifact first.
@ -172,7 +172,7 @@ class ConcreteArtifactsManager:
return b_artifact_path
def get_artifact_path(self, collection):
# type: (Candidate | Requirement) -> bytes
# type: (t.Union[Candidate, Requirement]) -> bytes
"""Given a concrete collection pointer, return a cached path.
If it's not yet on disk, this method downloads the artifact first.
@ -237,15 +237,15 @@ class ConcreteArtifactsManager:
return b_artifact_path
def _get_direct_collection_namespace(self, collection):
# type: (Candidate) -> str | None
# type: (Candidate) -> t.Optional[str]
return self.get_direct_collection_meta(collection)['namespace'] # type: ignore[return-value]
def _get_direct_collection_name(self, collection):
# type: (Candidate) -> str | None
# type: (Candidate) -> t.Optional[str]
return self.get_direct_collection_meta(collection)['name'] # type: ignore[return-value]
def get_direct_collection_fqcn(self, collection):
# type: (Candidate) -> str | None
# type: (Candidate) -> t.Optional[str]
"""Extract FQCN from the given on-disk collection artifact.
If the collection is virtual, ``None`` is returned instead
@ -261,12 +261,12 @@ class ConcreteArtifactsManager:
))
def get_direct_collection_version(self, collection):
# type: (Candidate | Requirement) -> str
# type: (t.Union[Candidate, Requirement]) -> str
"""Extract version from the given on-disk collection artifact."""
return self.get_direct_collection_meta(collection)['version'] # type: ignore[return-value]
def get_direct_collection_dependencies(self, collection):
# type: (Candidate | Requirement) -> dict[str, str]
# type: (t.Union[Candidate, Requirement]) -> dict[str, str]
"""Extract deps from the given on-disk collection artifact."""
collection_dependencies = self.get_direct_collection_meta(collection)['dependencies']
if collection_dependencies is None:
@ -274,7 +274,7 @@ class ConcreteArtifactsManager:
return collection_dependencies # type: ignore[return-value]
def get_direct_collection_meta(self, collection):
# type: (Candidate | Requirement) -> dict[str, str | dict[str, str] | list[str] | None]
# type: (t.Union[Candidate, Requirement]) -> dict[str, t.Union[str, dict[str, str], list[str], None]]
"""Extract meta from the given on-disk collection artifact."""
try: # FIXME: use unique collection identifier as a cache key?
return self._artifact_meta_cache[collection.src]
@ -447,7 +447,7 @@ def _extract_collection_from_git(repo_url, coll_ver, b_path):
# FIXME: use random subdirs while preserving the file names
def _download_file(url, b_path, expected_hash, validate_certs, token=None, timeout=60):
# type: (str, bytes, str | None, bool, GalaxyToken, int) -> bytes
# type: (str, bytes, t.Optional[str], bool, GalaxyToken, int) -> bytes
# ^ NOTE: used in download and verify_collections ^
b_tarball_name = to_bytes(
url.rsplit('/', 1)[1], errors='surrogate_or_strict',
@ -503,14 +503,14 @@ def _consume_file(read_from, write_to=None):
def _normalize_galaxy_yml_manifest(
galaxy_yml, # type: dict[str, str | list[str] | dict[str, str] | None]
galaxy_yml, # type: dict[str, t.Union[str, list[str], dict[str, str], None]]
b_galaxy_yml_path, # type: bytes
):
# type: (...) -> dict[str, str | list[str] | dict[str, str] | None]
# type: (...) -> dict[str, t.Union[str, list[str], dict[str, str], None]]
galaxy_yml_schema = (
get_collections_galaxy_meta_info()
) # type: list[dict[str, t.Any]] # FIXME: <--
# FIXME: 👆maybe precise type: list[dict[str, bool | str | list[str]]]
# FIXME: 👆maybe precise type: list[dict[str, t.Union[bool, str, list[str]]]]
mandatory_keys = set()
string_keys = set() # type: set[str]
@ -570,7 +570,7 @@ def _normalize_galaxy_yml_manifest(
def _get_meta_from_dir(
b_path, # type: bytes
): # type: (...) -> dict[str, str | list[str] | dict[str, str] | None]
): # type: (...) -> dict[str, t.Union[str, list[str], dict[str, str], None]]
try:
return _get_meta_from_installed_dir(b_path)
except LookupError:
@ -579,7 +579,7 @@ def _get_meta_from_dir(
def _get_meta_from_src_dir(
b_path, # type: bytes
): # type: (...) -> dict[str, str | list[str] | dict[str, str] | None]
): # type: (...) -> dict[str, t.Union[str, list[str], dict[str, str], None]]
galaxy_yml = os.path.join(b_path, _GALAXY_YAML)
if not os.path.isfile(galaxy_yml):
raise LookupError(
@ -641,7 +641,7 @@ def _get_json_from_installed_dir(
def _get_meta_from_installed_dir(
b_path, # type: bytes
): # type: (...) -> dict[str, str | list[str] | dict[str, str] | None]
): # type: (...) -> dict[str, t.Union[str, list[str], dict[str, str], None]]
manifest = _get_json_from_installed_dir(b_path, MANIFEST_FILENAME)
collection_info = manifest['collection_info']
@ -662,7 +662,7 @@ def _get_meta_from_installed_dir(
def _get_meta_from_tar(
b_path, # type: bytes
): # type: (...) -> dict[str, str | list[str] | dict[str, str] | None]
): # type: (...) -> dict[str, t.Union[str, list[str], dict[str, str], None]]
if not tarfile.is_tarfile(b_path):
raise AnsibleError(
"Collection artifact at '{path!s}' is not a valid tar file.".
@ -710,7 +710,7 @@ def _tarfile_extract(
tar, # type: tarfile.TarFile
member, # type: tarfile.TarInfo
):
# type: (...) -> t.Iterator[tuple[tarfile.TarInfo, t.IO[bytes] | None]]
# type: (...) -> t.Iterator[tuple[tarfile.TarInfo, t.Optional[t.IO[bytes]]]]
tar_obj = tar.extractfile(member)
try:
yield member, tar_obj

@ -25,7 +25,7 @@ IS_PY310_PLUS = sys.version_info[:2] >= (3, 10)
frozen_dataclass = partial(dataclass, frozen=True, **({'slots': True} if IS_PY310_PLUS else {}))
def get_signature_from_source(source, display=None): # type: (str, Display | None) -> str
def get_signature_from_source(source, display=None): # type: (str, t.Optional[Display]) -> str
if display is not None:
display.vvvv(f"Using signature at {source}")
try:

@ -155,7 +155,7 @@ class CollectionDependencyProvider(AbstractProvider):
return False
def identify(self, requirement_or_candidate):
# type: (Candidate | Requirement) -> str
# type: (t.Union[Candidate, Requirement]) -> str
"""Given requirement or candidate, return an identifier for it.
This is used to identify a requirement or candidate, e.g.
@ -168,10 +168,10 @@ class CollectionDependencyProvider(AbstractProvider):
def get_preference(
self, # type: CollectionDependencyProvider
resolution, # type: Candidate | None
resolution, # type: t.Optional[Candidate]
candidates, # type: list[Candidate]
information, # type: list[t.NamedTuple]
): # type: (...) -> float | int
): # type: (...) -> t.Union[float, int]
"""Return sort key function return value for given requirement.
This result should be based on preference that is defined as

@ -2,8 +2,9 @@ mypy[python2]
packaging # type stubs not published separately
types-backports
types-jinja2
types-paramiko
types-paramiko < 2.8.14 # newer versions drop support for Python 2.7
types-pyyaml < 6 # PyYAML 6+ stubs do not support Python 2.7
types-cryptography < 3.3.16 # newer versions drop support for Python 2.7
types-requests
types-setuptools
types-toml

@ -1,10 +1,10 @@
# edit "sanity.mypy.in" and generate with: hacking/update-sanity-requirements.py --test mypy
mypy==0.931
mypy==0.950
mypy-extensions==0.4.3
packaging==21.2
pyparsing==2.4.7
tomli==2.0.1
typed-ast==1.5.2
typed-ast==1.5.3
types-backports==0.1.3
types-cryptography==3.3.15
types-enum34==1.1.8
@ -13,8 +13,8 @@ types-Jinja2==2.11.9
types-MarkupSafe==1.1.10
types-paramiko==2.8.13
types-PyYAML==5.4.12
types-requests==2.27.10
types-setuptools==57.4.9
types-toml==0.10.4
types-urllib3==1.26.9
types-requests==2.27.25
types-setuptools==57.4.14
types-toml==0.10.6
types-urllib3==1.26.14
typing-extensions==3.10.0.2

@ -90,11 +90,22 @@ class MypyTest(SanityMultipleVersion):
display.warning(f'Skipping sanity test "{self.name}" due to missing virtual environment support on Python {args.controller_python.version}.')
return SanitySkipped(self.name, python.version)
# Temporary hack to make Python 3.8 a remote-only Python version since we'll be dropping controller support for it soon.
# This avoids having to change annotations or add ignores for issues that are specific to that version.
change_version = '3.8'
if change_version not in CONTROLLER_PYTHON_VERSIONS or change_version in REMOTE_ONLY_PYTHON_VERSIONS:
raise Exception(f'Remove this hack now that Python {change_version} is not supported by the controller.')
controller_python_versions = tuple(version for version in CONTROLLER_PYTHON_VERSIONS if version != change_version)
remote_only_python_versions = REMOTE_ONLY_PYTHON_VERSIONS + (change_version,)
contexts = (
MyPyContext('ansible-test', ['test/lib/ansible_test/_util/target/sanity/import/'], CONTROLLER_PYTHON_VERSIONS),
MyPyContext('ansible-test', ['test/lib/ansible_test/_internal/'], CONTROLLER_PYTHON_VERSIONS),
MyPyContext('ansible-core', ['lib/ansible/'], CONTROLLER_PYTHON_VERSIONS),
MyPyContext('modules', ['lib/ansible/modules/', 'lib/ansible/module_utils/'], REMOTE_ONLY_PYTHON_VERSIONS),
MyPyContext('ansible-test', ['test/lib/ansible_test/_util/target/sanity/import/'], controller_python_versions),
MyPyContext('ansible-test', ['test/lib/ansible_test/_internal/'], controller_python_versions),
MyPyContext('ansible-core', ['lib/ansible/'], controller_python_versions),
MyPyContext('modules', ['lib/ansible/modules/', 'lib/ansible/module_utils/'], remote_only_python_versions),
)
unfiltered_messages = [] # type: t.List[SanityMessage]

@ -286,6 +286,7 @@ lib/ansible/module_utils/six/__init__.py mypy-2.7:assignment # vendored code
lib/ansible/module_utils/six/__init__.py mypy-3.5:assignment # vendored code
lib/ansible/module_utils/six/__init__.py mypy-3.6:assignment # vendored code
lib/ansible/module_utils/six/__init__.py mypy-3.7:assignment # vendored code
lib/ansible/module_utils/six/__init__.py mypy-3.8:assignment # vendored code
lib/ansible/module_utils/six/__init__.py mypy-2.7:misc # vendored code
lib/ansible/module_utils/six/__init__.py mypy-3.5:misc # vendored code
lib/ansible/module_utils/six/__init__.py mypy-3.6:misc # vendored code

Loading…
Cancel
Save