From 7e0a42c258e53fcd7b5fd5288d937f763b2211a3 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 10 Dec 2021 14:20:59 -0500 Subject: [PATCH 01/20] Add stub files for all model classes except those for retrofitting attrs There are a number of model class which are just "empty" subclasses of other models (e.g. ProductIdPushItem(PushItem)), which don't define any additional properties or methods outside of those provided by their base class. It may not be necessary (not 100% sure yet) to stub such classes, but it does provide a place where future stubs will go when needed. --- src/pushsource/_impl/model/ami.pyi | 31 ++++++++++++++ src/pushsource/_impl/model/base.pyi | 23 ++++++++++ src/pushsource/_impl/model/comps.pyi | 1 + src/pushsource/_impl/model/container.pyi | 54 ++++++++++++++++++++++++ src/pushsource/_impl/model/file.pyi | 8 ++++ src/pushsource/_impl/model/modulemd.pyi | 6 +++ src/pushsource/_impl/model/productid.pyi | 4 ++ src/pushsource/_impl/model/rpm.pyi | 7 +++ src/pushsource/type_aliases.pyi | 4 ++ 9 files changed, 138 insertions(+) create mode 100644 src/pushsource/_impl/model/ami.pyi create mode 100644 src/pushsource/_impl/model/base.pyi create mode 100644 src/pushsource/_impl/model/comps.pyi create mode 100644 src/pushsource/_impl/model/container.pyi create mode 100644 src/pushsource/_impl/model/file.pyi create mode 100644 src/pushsource/_impl/model/modulemd.pyi create mode 100644 src/pushsource/_impl/model/productid.pyi create mode 100644 src/pushsource/_impl/model/rpm.pyi create mode 100644 src/pushsource/type_aliases.pyi diff --git a/src/pushsource/_impl/model/ami.pyi b/src/pushsource/_impl/model/ami.pyi new file mode 100644 index 00000000..2efb6553 --- /dev/null +++ b/src/pushsource/_impl/model/ami.pyi @@ -0,0 +1,31 @@ +from typing import AnyStr, List, Text, Optional, Any, TypeVar + +from pushsource import PushItem +from pushsource.type_aliases import Date, FrozenList + +class AmiRelease(object): + product: Text + date: Date + arch: Text + respin: int + version: Optional[Text] = ... + base_product: Optional[Text] = ... + base_version: Optional[Text] = ... + variant: Optional[Text] = ... + type: Optional[Text] = ... + +class AmiBillingCodes(object): + name: Text = ... + codes: Sequence[Text] = ... + +class AmiPushItem(PushItem): + release: Optional[AmiRelease] = ... + type: Optional[Text] = ... + region: Optional[Text] = ... + virtualization: Optional[Text] = ... + volume: Optional[Text] = ... + root_device: Optional[Text] = ... + description: Optional[Text] = ... + sriov_net_support: Optional[Text] = ... + ena_support: Optional[bool] = ... + billing_codes: Optional[AmiBillingCodes] = ... diff --git a/src/pushsource/_impl/model/base.pyi b/src/pushsource/_impl/model/base.pyi new file mode 100644 index 00000000..60ba8691 --- /dev/null +++ b/src/pushsource/_impl/model/base.pyi @@ -0,0 +1,23 @@ +from typing import Text, TypeVar, Type, Sequence, Optional + +BuildInfo = TypeVar("BuildInfo", bound="KojiBuildInfo") + +class KojiBuildInfo(object): + name: Text + version: Text + release: Text + @classmethod + def _from_nvr(cls: Type[BuildInfo], nvr_str: Text) -> BuildInfo: ... + +class PushItem(object): + name: Text + state: Text = ... + src: Optional[Text] = ... + dest: Sequence[Text] = ... + md5sum: Optional[Text] = ... + sha256sum: Optional[Text] = ... + origin: Optional[Text] = ... + build: Optional[Text] = ... + build_info: BuildInfo = ... + signing_key: Optional[Text] = ... + def with_checksums(self) -> "PushItem": ... diff --git a/src/pushsource/_impl/model/comps.pyi b/src/pushsource/_impl/model/comps.pyi new file mode 100644 index 00000000..bc718340 --- /dev/null +++ b/src/pushsource/_impl/model/comps.pyi @@ -0,0 +1 @@ +class CompsXmlPushItem(PushItem): ... \ No newline at end of file diff --git a/src/pushsource/_impl/model/container.pyi b/src/pushsource/_impl/model/container.pyi new file mode 100644 index 00000000..a68b13b8 --- /dev/null +++ b/src/pushsource/_impl/model/container.pyi @@ -0,0 +1,54 @@ +from collections import Sequence, Mapping +from typing import Text, AnyStr, TypeVar, Optional, Type + +from pushsource import PushItem + +PullSpec_co = TypeVar("PullSpec_co", bound="ContainerImagePullSpec", covariant=True) +PullSpec_contra = TypeVar( + "PullSpec_contra", bound="ContainerImagePullSpec", contravariant=True +) + +class ContainerImagePullSpec(object): + registry: Text + repository: Text + @classmethod + def _from_str(cls, pull_spec: AnyStr) -> PullSpec_co: ... + +class ContainerImageTagPullSpec(ContainerImagePullSpec): + tag: Text + media_types: Sequence[Text] + def __str__(self) -> Text: ... + +class ContainerImageDigestPullSpec(ContainerImagePullSpec): + digest: Text + media_type: Optional[Text] = ... + def __str__(self) -> Text: ... + +def specs_converter( + specs: Sequence[PullSpec_contra], expected_class: Type +) -> Sequence[PullSpec_co]: ... + +def tag_specs_converter( + specs: Sequence[PullSpec_contra] +) -> Sequence[ContainerImageTagPullSpec]: ... + +def digest_specs_converter( + specs: Sequence[PullSpec_contra] +) -> Sequence[ContainerImageDigestPullSpec]: ... + +class ContainerImagePullInfo(object): + tag_specs: Sequence[ContainerImageTagPullSpec] + digest_specs: Sequence[ContainerImageDigestPullSpec] + media_types: Sequence[Text] = ... + def digest_spec_for_type(self, media_type: Text) -> Optional[ContainerImageDigestPullSpec]: ... + +class ContainerImagePushItem(PushItem): + dest_signing_key: Optional[Text] = ... + source_tags: Sequence[Text] = ... + labels: Mapping[Text, Text] = ... + arch: Optional[Text] = ... + pull_info: Optional[ContainerImagePullInfo] = ... + +class SourceContainerImagePushItem(ContainerImagePushItem): ... + +class OperatorManifestPushItem(PushItem): ... \ No newline at end of file diff --git a/src/pushsource/_impl/model/file.pyi b/src/pushsource/_impl/model/file.pyi new file mode 100644 index 00000000..221ad1de --- /dev/null +++ b/src/pushsource/_impl/model/file.pyi @@ -0,0 +1,8 @@ +from typing import Optional, Text + +from pushsource import PushItem + + +class FilePushItem(PushItem): + description: Optional[Text] = ... + version: Optional[Text] = ... \ No newline at end of file diff --git a/src/pushsource/_impl/model/modulemd.pyi b/src/pushsource/_impl/model/modulemd.pyi new file mode 100644 index 00000000..14953ce0 --- /dev/null +++ b/src/pushsource/_impl/model/modulemd.pyi @@ -0,0 +1,6 @@ +from pushsource import PushItem + + +class ModuleMdPushItem(PushItem): ... + +class ModuleMdSourcePushItem(PushItem): ... \ No newline at end of file diff --git a/src/pushsource/_impl/model/productid.pyi b/src/pushsource/_impl/model/productid.pyi new file mode 100644 index 00000000..c7ae7b61 --- /dev/null +++ b/src/pushsource/_impl/model/productid.pyi @@ -0,0 +1,4 @@ +from pushsource import PushItem + + +class ProductIdPushItem(PushItem): ... \ No newline at end of file diff --git a/src/pushsource/_impl/model/rpm.pyi b/src/pushsource/_impl/model/rpm.pyi new file mode 100644 index 00000000..2a705342 --- /dev/null +++ b/src/pushsource/_impl/model/rpm.pyi @@ -0,0 +1,7 @@ +from typing import Text, Optional + +from pushsource import PushItem + + +class RpmPushItem(PushItem): + module_build: Optional[Text] = ... diff --git a/src/pushsource/type_aliases.pyi b/src/pushsource/type_aliases.pyi new file mode 100644 index 00000000..c6396240 --- /dev/null +++ b/src/pushsource/type_aliases.pyi @@ -0,0 +1,4 @@ +import datetime + +Date = datetime.date +DateTime = datetime.datetime \ No newline at end of file From e57b42cc0171754c815d9e64a18e4e067838b1d6 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 10 Dec 2021 14:27:09 -0500 Subject: [PATCH 02/20] Run Black over code, since pre-commit hook was not yet installed --- src/pushsource/_impl/model/comps.pyi | 2 +- src/pushsource/_impl/model/container.pyi | 13 ++++++------- src/pushsource/_impl/model/file.pyi | 3 +-- src/pushsource/_impl/model/modulemd.pyi | 4 +--- src/pushsource/_impl/model/productid.pyi | 3 +-- src/pushsource/_impl/model/rpm.pyi | 1 - src/pushsource/type_aliases.pyi | 2 +- 7 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/pushsource/_impl/model/comps.pyi b/src/pushsource/_impl/model/comps.pyi index bc718340..b5bc3937 100644 --- a/src/pushsource/_impl/model/comps.pyi +++ b/src/pushsource/_impl/model/comps.pyi @@ -1 +1 @@ -class CompsXmlPushItem(PushItem): ... \ No newline at end of file +class CompsXmlPushItem(PushItem): ... diff --git a/src/pushsource/_impl/model/container.pyi b/src/pushsource/_impl/model/container.pyi index a68b13b8..d03e06f1 100644 --- a/src/pushsource/_impl/model/container.pyi +++ b/src/pushsource/_impl/model/container.pyi @@ -27,20 +27,20 @@ class ContainerImageDigestPullSpec(ContainerImagePullSpec): def specs_converter( specs: Sequence[PullSpec_contra], expected_class: Type ) -> Sequence[PullSpec_co]: ... - def tag_specs_converter( - specs: Sequence[PullSpec_contra] + specs: Sequence[PullSpec_contra], ) -> Sequence[ContainerImageTagPullSpec]: ... - def digest_specs_converter( - specs: Sequence[PullSpec_contra] + specs: Sequence[PullSpec_contra], ) -> Sequence[ContainerImageDigestPullSpec]: ... class ContainerImagePullInfo(object): tag_specs: Sequence[ContainerImageTagPullSpec] digest_specs: Sequence[ContainerImageDigestPullSpec] media_types: Sequence[Text] = ... - def digest_spec_for_type(self, media_type: Text) -> Optional[ContainerImageDigestPullSpec]: ... + def digest_spec_for_type( + self, media_type: Text + ) -> Optional[ContainerImageDigestPullSpec]: ... class ContainerImagePushItem(PushItem): dest_signing_key: Optional[Text] = ... @@ -50,5 +50,4 @@ class ContainerImagePushItem(PushItem): pull_info: Optional[ContainerImagePullInfo] = ... class SourceContainerImagePushItem(ContainerImagePushItem): ... - -class OperatorManifestPushItem(PushItem): ... \ No newline at end of file +class OperatorManifestPushItem(PushItem): ... diff --git a/src/pushsource/_impl/model/file.pyi b/src/pushsource/_impl/model/file.pyi index 221ad1de..1a9008e8 100644 --- a/src/pushsource/_impl/model/file.pyi +++ b/src/pushsource/_impl/model/file.pyi @@ -2,7 +2,6 @@ from typing import Optional, Text from pushsource import PushItem - class FilePushItem(PushItem): description: Optional[Text] = ... - version: Optional[Text] = ... \ No newline at end of file + version: Optional[Text] = ... diff --git a/src/pushsource/_impl/model/modulemd.pyi b/src/pushsource/_impl/model/modulemd.pyi index 14953ce0..33af5c5d 100644 --- a/src/pushsource/_impl/model/modulemd.pyi +++ b/src/pushsource/_impl/model/modulemd.pyi @@ -1,6 +1,4 @@ from pushsource import PushItem - class ModuleMdPushItem(PushItem): ... - -class ModuleMdSourcePushItem(PushItem): ... \ No newline at end of file +class ModuleMdSourcePushItem(PushItem): ... diff --git a/src/pushsource/_impl/model/productid.pyi b/src/pushsource/_impl/model/productid.pyi index c7ae7b61..1f0e7680 100644 --- a/src/pushsource/_impl/model/productid.pyi +++ b/src/pushsource/_impl/model/productid.pyi @@ -1,4 +1,3 @@ from pushsource import PushItem - -class ProductIdPushItem(PushItem): ... \ No newline at end of file +class ProductIdPushItem(PushItem): ... diff --git a/src/pushsource/_impl/model/rpm.pyi b/src/pushsource/_impl/model/rpm.pyi index 2a705342..a16f56c8 100644 --- a/src/pushsource/_impl/model/rpm.pyi +++ b/src/pushsource/_impl/model/rpm.pyi @@ -2,6 +2,5 @@ from typing import Text, Optional from pushsource import PushItem - class RpmPushItem(PushItem): module_build: Optional[Text] = ... diff --git a/src/pushsource/type_aliases.pyi b/src/pushsource/type_aliases.pyi index c6396240..7d398161 100644 --- a/src/pushsource/type_aliases.pyi +++ b/src/pushsource/type_aliases.pyi @@ -1,4 +1,4 @@ import datetime Date = datetime.date -DateTime = datetime.datetime \ No newline at end of file +DateTime = datetime.datetime From 1a85b568c37dcd91d9772417afde82ff4fc7d681 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 10 Dec 2021 14:46:47 -0500 Subject: [PATCH 03/20] Add missing stub file for erratum.py --- src/pushsource/_impl/model/erratum.pyi | 77 ++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/pushsource/_impl/model/erratum.pyi diff --git a/src/pushsource/_impl/model/erratum.pyi b/src/pushsource/_impl/model/erratum.pyi new file mode 100644 index 00000000..830ff4d2 --- /dev/null +++ b/src/pushsource/_impl/model/erratum.pyi @@ -0,0 +1,77 @@ +from collections import Mapping, Sequence, MutableSequence +from typing import Text, overload, List, Optional + +from pushsource import PushItem + + +class ErratumReference(object): + href: Text + id: Text + title: Text + type: Text = ... + @classmethod + @overload + def _from_data(cls, data: Sequence[Mapping[Text, ...]]) -> MutableSequence["ErratumReference"]: ... + @classmethod + @overload + def _from_data(cls, data: Mapping[Text, ...]) -> "ErratumReference": ... + +class ErratumModule(object): + name: Text + stream: Text + version: Text + context: Text + arch: Text + @classmethod + def _from_data(cls, data: Mapping[Text, ...]) -> Optional["ErratumModule"]: ... + +class ErratumPackage(object): + arch: Text + filename: Text + epoch: Text + name: Text + version: Text + release: Text + src: Text + reboot_suggested: bool = ... + md5sum: Optional[Text] = ... + sha1sum: Optional[Text] = ... + sha256sum: Optional[Text] = ... + +class ErratumPackageCollection(object): + name: Text = ... + packages: Sequence[ErratumPackage] = ... + short: Text = ... + module: Optional[ErratumModule] = ... + @classmethod + @overload + def _from_data( + cls, data: Sequence[Mapping[Text, ...]] + ) -> MutableSequence["ErratumPackageCollection"]: ... + @classmethod + @overload + def _from_data(cls, data: Mapping[Text, ...]) -> "ErratumPackageCollection": ... + +def errata_type_converter(value: Text) -> Text: ... + +class ErratumPushItem(PushItem): + type: Text = ... + release: Text = ... + status: Text = ... + pushcount: Text = ... + reboot_suggested: bool = ... + references: Sequence[ErratumReference] = ... + pkglist: Sequence[ErratumPackageCollection] = ... + from_: Optional[Text] = ... + rights: Optional[Text] = ... + title: Optional[Text] = ... + description: Optional[Text] = ... + version: Text = ... + updated: Text = ... + issued: Optional[Text] = ... + severity: Optional[Text] = ... + summary: Optional[Text] = ... + solution: Optional[Text] = ... + content_types: Sequence[Text] = ... + @classmethod + def _from_data(cls, data: Mapping[Text, ...]) -> "ErratumPushItem": ... From 48b25a1e1389f43cccd6706d5d0711fd34aaad91 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 10 Dec 2021 14:47:31 -0500 Subject: [PATCH 04/20] Remove stub for __str__ since the stdlib covers that --- src/pushsource/_impl/model/container.pyi | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pushsource/_impl/model/container.pyi b/src/pushsource/_impl/model/container.pyi index d03e06f1..d49983e8 100644 --- a/src/pushsource/_impl/model/container.pyi +++ b/src/pushsource/_impl/model/container.pyi @@ -17,12 +17,10 @@ class ContainerImagePullSpec(object): class ContainerImageTagPullSpec(ContainerImagePullSpec): tag: Text media_types: Sequence[Text] - def __str__(self) -> Text: ... class ContainerImageDigestPullSpec(ContainerImagePullSpec): digest: Text media_type: Optional[Text] = ... - def __str__(self) -> Text: ... def specs_converter( specs: Sequence[PullSpec_contra], expected_class: Type From 9636c86c7dd98ff3ba8a87e14d64a1f63a38ad3e Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Tue, 21 Dec 2021 12:54:28 -0500 Subject: [PATCH 05/20] Add py.typed marker file to top-level package per PEP-561 --- setup.py | 1 + src/pushsource/py.typed | 0 2 files changed, 1 insertion(+) create mode 100644 src/pushsource/py.typed diff --git a/setup.py b/setup.py index 1312fea7..9a9a3cad 100644 --- a/setup.py +++ b/setup.py @@ -24,6 +24,7 @@ def get_requirements(): version="2.13.3", packages=find_packages("src"), package_dir={"": "src"}, + package_data={"pushsource": ["py.typed"]}, include_package_data=True, url="https://github.com/release-engineering/pushsource", license="GNU General Public License", diff --git a/src/pushsource/py.typed b/src/pushsource/py.typed new file mode 100644 index 00000000..e69de29b From 66a417279ec52719be7166c4040ac76a570d4d19 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Tue, 21 Dec 2021 13:53:26 -0500 Subject: [PATCH 06/20] Fix import errors --- src/pushsource/_impl/model/ami.pyi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pushsource/_impl/model/ami.pyi b/src/pushsource/_impl/model/ami.pyi index 2efb6553..526085f6 100644 --- a/src/pushsource/_impl/model/ami.pyi +++ b/src/pushsource/_impl/model/ami.pyi @@ -1,7 +1,9 @@ -from typing import AnyStr, List, Text, Optional, Any, TypeVar +from collections import Sequence +from typing import Text, Optional from pushsource import PushItem -from pushsource.type_aliases import Date, FrozenList +from pushsource.type_aliases import Date + class AmiRelease(object): product: Text From b07c9dba9977cf9b520142aa0ad0bc935356323a Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 7 Jan 2022 10:18:20 -0500 Subject: [PATCH 07/20] Remove BuildInfo TypeVar; Add PushItem TypeVars for collections --- src/pushsource/_impl/model/base.pyi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pushsource/_impl/model/base.pyi b/src/pushsource/_impl/model/base.pyi index 60ba8691..54e40931 100644 --- a/src/pushsource/_impl/model/base.pyi +++ b/src/pushsource/_impl/model/base.pyi @@ -1,13 +1,14 @@ from typing import Text, TypeVar, Type, Sequence, Optional -BuildInfo = TypeVar("BuildInfo", bound="KojiBuildInfo") +PushItem_co = TypeVar("PushItem_co", bound="PushItem", covariant=True) +PushItem_contra = TypeVar("PushItem_contra", bound="PushItem", contravariant=True) class KojiBuildInfo(object): name: Text version: Text release: Text @classmethod - def _from_nvr(cls: Type[BuildInfo], nvr_str: Text) -> BuildInfo: ... + def _from_nvr(cls: Type["KojiBuildInfo"], nvr_str: Text) -> "KojiBuildInfo": ... class PushItem(object): name: Text @@ -18,6 +19,6 @@ class PushItem(object): sha256sum: Optional[Text] = ... origin: Optional[Text] = ... build: Optional[Text] = ... - build_info: BuildInfo = ... + build_info: KojiBuildInfo = ... signing_key: Optional[Text] = ... def with_checksums(self) -> "PushItem": ... From e920670dba63a770abb3225edb5e38db1d389771 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 7 Jan 2022 10:20:06 -0500 Subject: [PATCH 08/20] Add MaybeString type to type_aliases --- src/pushsource/type_aliases.pyi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pushsource/type_aliases.pyi b/src/pushsource/type_aliases.pyi index 7d398161..f01adab3 100644 --- a/src/pushsource/type_aliases.pyi +++ b/src/pushsource/type_aliases.pyi @@ -1,4 +1,7 @@ import datetime +from typing import Union, Collection Date = datetime.date DateTime = datetime.datetime + +MaybeString = Union[str, Collection[str]] \ No newline at end of file From f80fc7d6de35075c836f22e03914ad595d90c488 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 7 Jan 2022 10:21:51 -0500 Subject: [PATCH 09/20] Stub source.py --- src/pushsource/_impl/source.pyi | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/pushsource/_impl/source.pyi diff --git a/src/pushsource/_impl/source.pyi b/src/pushsource/_impl/source.pyi new file mode 100644 index 00000000..4a66dd47 --- /dev/null +++ b/src/pushsource/_impl/source.pyi @@ -0,0 +1,42 @@ +from collections import Mapping, Callable, Iterator +from types import TracebackType +from typing import Type, TypeVar, Any + +from pushsource._impl.model.base import PushItem_co + +SourceFactory = Callable[[], "Source"] + +# TODO: See the following example from PEP-484 to demonstrate +# why I think this could be a good idea for Source#get +# and Source#__enter__ annotations. +# https://www.python.org/dev/peps/pep-0484/#id33 +# I could easily be convinced that Source can be used +# in both of those instances without issue. +S = TypeVar("S", bound="Source") + +class SourceWrapper(object): + def __init__(self, delegate: "Source") -> None: ... + @classmethod + def _maybe_wrap(cls, delegate: "Source") -> "SourceWrapper": ... + +class Source(object): + _BACKENDS: Mapping[str, SourceFactory] + _BACKENDS_BUILTIN: Mapping[str, SourceFactory] + def __enter__(self) -> "Source": ... + def __exit__( + self, + exc_type: Type[BaseException], + exc_val: BaseException, + exc_tb: TracebackType, + ) -> None: ... + def __iter__(self) -> Iterator[PushItem_co]: ... + @classmethod + def get(cls, source_url: str, **kwargs: Any) -> "Source": ... + @classmethod + def get_partial(cls, source_url: str, **kwargs: Any) -> SourceFactory: ... + @classmethod + def register_backend(cls, name: str, factory: SourceFactory) -> None: ... + @classmethod + def _register_backend_builtin(cls, name: str, factory: SourceFactory) -> None: ... + @classmethod + def reset(cls) -> None: ... From a995b4af56a83fa284249bec8564f86be196a2a7 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Fri, 7 Jan 2022 11:03:25 -0500 Subject: [PATCH 10/20] Stub errata_source package --- .../backend/errata_source/errata_client.pyi | 42 ++++++++++++ .../backend/errata_source/errata_source.pyi | 68 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/pushsource/_impl/backend/errata_source/errata_client.pyi create mode 100644 src/pushsource/_impl/backend/errata_source/errata_source.pyi diff --git a/src/pushsource/_impl/backend/errata_source/errata_client.pyi b/src/pushsource/_impl/backend/errata_source/errata_client.pyi new file mode 100644 index 00000000..2d508f8c --- /dev/null +++ b/src/pushsource/_impl/backend/errata_source/errata_client.pyi @@ -0,0 +1,42 @@ +# TODO: are stub files subject to the same need for six.moves? +import xmlrpc.client +from collections import Sequence +from typing import Any, TypeVar + +from pushsource.type_aliases import JsonObject + +ErrataRaw_co = TypeVar("ErrataRaw_co", bound="ErrataRaw", covariant=True) + + +class ErrataRaw(object): + advisory_cdn_metadata: JsonObject + advisory_cdn_file_list: JsonObject + advisory_cdn_docker_file_list: JsonObject + ftp_paths: JsonObject + + def __init__( + self, + advisory_cdn_metadata: JsonObject, + advisory_cdn_file_list: JsonObject, + advisory_cdn_docker_file_list: JsonObject, + ftp_paths: JsonObject + ) -> None: ... + +class ErrataClient(object): + _errata_service: xmlrpc.client.ServerProxy + def __init__( + self, + threads: int, + url: str, + **retry_args: Any + ) -> None: ... + + def shutdown(self) -> None: ... + def _log_queried_et(self, response: JsonObject, advisory_id: str) -> JsonObject: ... + def get_raw_f(self, advisory_id: str) -> Sequence[ErrataRaw_co]: ... + # TODO: narrow return type if possible: JsonObject maybe? + # TODO: since this method can explicitly raise, is it appropriate + # to document the return type as Union[Any, NoReturn]? + def _call_et(self, method_name: str, advisory_id: str) -> Any: ... + + diff --git a/src/pushsource/_impl/backend/errata_source/errata_source.pyi b/src/pushsource/_impl/backend/errata_source/errata_source.pyi new file mode 100644 index 00000000..206387cb --- /dev/null +++ b/src/pushsource/_impl/backend/errata_source/errata_source.pyi @@ -0,0 +1,68 @@ +from collections import Mapping, Iterator +from collections.abc import Sequence +from types import TracebackType +from typing import Optional, Type, List, Any + +from pushsource import ( + Source, + ErratumPushItem, + ContainerImagePushItem, +) +from pushsource._impl.backend.errata_source.errata_client import ErrataRaw +from pushsource._impl.model.base import PushItem_co, PushItem_contra +from pushsource.type_aliases import MaybeString + +# TODO: is the value type a model type or just a Mapping? +DockerFileList = Mapping[str, Any] + +# TODO: is the value type a model type or just a Mapping? +RpmList = Mapping[str, Mapping[Any, ...]] + +class ErrataSource(Source): + _errata_service_url: str + _advisory_ids: List[str] + def __init__( + self, + url: str, + errata: MaybeString, + koji_source: Optional[str] = ..., + rpm_filter_arch: Optional[MaybeString] = ..., + legacy_container_repos: bool = ..., + threads: int = ..., + timeout: int = ..., + ) -> None: ... + def __enter__(self) -> "ErrataSource": ... + def __exit__( + self, + exc_type: Type[BaseException], + exc_val: BaseException, + exc_tb: TracebackType, + ) -> None: ... + def __iter__(self) -> Iterator[PushItem_co]: ... + def _koji_source(**kwargs: Any) -> Source: ... + def _push_items_from_raw(self, raw: ErrataRaw) -> Sequence[PushItem_co]: ... + def _push_items_from_container_manifests( + self, erratum: ErratumPushItem, docker_file_list: DockerFileList + ) -> Sequence[PushItem_co]: ... + def _enrich_container_push_item( + self, + erratum: ErratumPushItem, + docker_file_list: DockerFileList, + item: ContainerImagePushItem, + ) -> ContainerImagePushItem: ... + def _push_items_from_rpms( + self, erratum: ErratumPushItem, rpm_list: RpmList + ) -> Sequence[PushItem_co]: ... + def _module_push_items_from_build( + self, erratum: ErratumPushItem, build_nvr: str, build_info: Mapping[Any, ...] + ) -> Sequence[PushItem_co]: ... + def _filter_rpms_by_arch( + self, erratum: ErratumPushItem, rpm_filenames: Sequence[str] + ) -> Sequence[str]: ... + def _rpm_push_items_from_build( + self, erratum: ErratumPushItem, build_nvr: str, build_info: Mapping[Any, ...] + ) -> Sequence[PushItem_co]: ... + def _add_ftp_paths( + self, items: Sequence[PushItem_contra], erratum: ErratumPushItem, raw: ErrataRaw + ) -> Sequence[PushItem_co]: ... + From 67585ba79e3fd7615d046d81f07a9528358803c4 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Mon, 10 Jan 2022 08:40:29 -0500 Subject: [PATCH 11/20] Finish stubbing the top-level modules in the backend package --- .../_impl/backend/koji_containers.pyi | 25 +++++ src/pushsource/_impl/backend/koji_source.pyi | 100 ++++++++++++++++++ src/pushsource/_impl/backend/modulemd.pyi | 9 ++ .../_impl/backend/registry_source.pyi | 27 +++++ 4 files changed, 161 insertions(+) create mode 100644 src/pushsource/_impl/backend/koji_containers.pyi create mode 100644 src/pushsource/_impl/backend/koji_source.pyi create mode 100644 src/pushsource/_impl/backend/modulemd.pyi create mode 100644 src/pushsource/_impl/backend/registry_source.pyi diff --git a/src/pushsource/_impl/backend/koji_containers.pyi b/src/pushsource/_impl/backend/koji_containers.pyi new file mode 100644 index 00000000..45baf917 --- /dev/null +++ b/src/pushsource/_impl/backend/koji_containers.pyi @@ -0,0 +1,25 @@ +from collections import Mapping, Sequence +from typing import Final, Any + +from pushsource import ContainerImagePullInfo +from pushsource._impl.model.container import ContainerImagePullSpec_co + +MIME_TYPE_MANIFEST_LIST: Final[str] = ... + +# TODO: a lot of the properties of this class are ambiguous +# Mapping[Any] (i.e. Mapping[Any, Any]): can this be narrowed? +# Perhaps the JsonObject type would be more helpful. +class ContainerArchiveHelper(object): + build_image: Mapping[Any] + build_index: Mapping[Any] + archive_extra: Mapping[Any] + archive_docker: Mapping[Any] + source_tags: Sequence[str] + arch: str + labels: Mapping[Any] + pull_info: ContainerImagePullInfo + +def get_tag_specs(raw_specs: Sequence[str]) -> Sequence[ContainerImagePullSpec_co]: ... +def get_digest_specs( + raw_specs: Sequence[str], digests_map +): Sequence[ContainerImagePullSpec_co]: ... \ No newline at end of file diff --git a/src/pushsource/_impl/backend/koji_source.pyi b/src/pushsource/_impl/backend/koji_source.pyi new file mode 100644 index 00000000..d03de361 --- /dev/null +++ b/src/pushsource/_impl/backend/koji_source.pyi @@ -0,0 +1,100 @@ +from collections import Mapping, Sequence, Iterator, Iterable, MutableSequence +from concurrent.futures import Executor, Future +from queue import Queue +from threading import RLock as ReentrantLock +from types import TracebackType +from typing import Any, Optional, Union, Type, ClassVar, Final, NoReturn + +from koji import ClientSession, VirtualCall + +from pushsource import Source, RpmPushItem, OperatorManifestPushItem +from pushsource._impl.model.base import PushItem_co +from pushsource.type_aliases import MaybeString, JsonObject + +# TODO: for now using Union[str, int] until I figure out +# which is really intended. This actually might be the best +# option after all, but I need to investigate +Id = Union[str, int] + +CACHE_LOCK: ReentrantLock + +RETRY_ARGS: Mapping[str, Any] + +class ListArchivesCommand(object): + def __init__(self, build: Mapping[str, Any]) -> None: ... + build: Mapping[str, Any] + # TODO: is VirtualCall correct for this type? + call: Optional[VirtualCall] = ... + def execute(self, source: "KojiSource", session: ClientSession) -> int: ... + def save(self, source: "KojiSource", koji_queue: Queue) -> None: ... + +class GetBuildCommand(object): + def __init__(self, ident: int, list_archives: bool = ...) -> None: ... + indent: int + list_archives: bool = ... + # TODO: is VirtualCall correct for this type? + call: Optional[VirtualCall] = ... + def execute(self, source: "KojiSource", session: ClientSession) -> int: ... + def save(self, source: "KojiSource", koji_queue: Queue) -> None: ... + +class GetRpmCommand(object): + def __init__(self, indent: int) -> None: ... + indent: int + # TODO: is VirtualCall correct for this type? + call: Optional[VirtualCall] = ... + def execute(self, source: "KojiSource", session: ClientSession) -> int: ... + def save(self, source: "KojiSource", koji_queue: Queue) -> None: ... + +class KojiSource(Source): + _BATCH_SIZE: Final[ClassVar[int]] + _koji_session: ClientSession + def __init__( + self, + url: str, + dest: MaybeString, + rpm: Optional[Sequence[Id]] = ..., + module_build: Optional[Sequence[Id]] = ..., + module_filter_filename: Optional[Sequence[str]] = ..., + container_build: Optional[Sequence[Id]] = ..., + signing_key: Optional[Sequence[str]] = ..., + basedir: Optional[str] = ..., + threads: int = ..., + timeout: int = ..., + cache: Optional[Mapping[str, Any]] = ..., + executor: Optional[Executor] = ..., + ) -> None: ... + def __enter__(self) -> "KojiSource": ... + def __exit__( + self, + exc_type: Type[BaseException], + exc_val: BaseException, + exc_tb: TracebackType, + ) -> None: ... + def __iter__(self) -> Iterator[PushItem_co]: ... + # TODO: the return type here feels hacky, but is accurate + def _koji_check(self) -> Optional[NoReturn]: ... + def _koji_get_version(self) -> str: ... + # TODO: reasonably sure based on the Fedora Koji XML-RPC + # docs for getRPM, getBuild, and getArchive that what is + # the map returned by those API calls is what's stored in + # the cache. Since it is not unlike a JSON object I am sticking + # with a JsonObject return type for now + def _get_rpm(self, rpm: str) -> JsonObject: ... + def _get_build(self, build_id: Id) -> JsonObject: ... + def _get_archives(self, build_id: Id) -> JsonObject: ... + # TODO: maybe JsonObject is appropriate for the meta parameter type + def _push_items_from_rpm_meta( + self, rpm: str, meta: Mapping[str, Any] + ) -> Sequence[RpmPushItem]: ... + def _module_filtered(self, file_path: str) -> bool: ... + def _get_module_name(self, nvr: str, file_path: str) -> str: ... + # TODO: maybe JsonObject is appropriate for the meta parameter type + def _push_items_from_module_build( + self, nvr: str, meta: Mapping[str, Any] + ) -> Sequence[PushItem_co]: ... + def _push_items_from_container_build(self, nvr: str, meta: Mapping[str, Any]) -> Sequence[PushItem_co]: ... + def _get_operator_item(self, nvr: str, meta: Mapping[str, Any], archives: Iterable[Mapping[str, Any]]) -> OperatorManifestPushItem: ... + def _rpm_futures(self) -> Sequence[Future[PushItem_co]]: ... + def _modulemd_futures(self) -> Sequence[Future[PushItem_co]]: ... + def _container_futures(self) -> Sequence[Future[PushItem_co]]: ... + def _do_fetch(self, koji_queue: Queue, exceptions: MutableSequence) -> None: ... diff --git a/src/pushsource/_impl/backend/modulemd.pyi b/src/pushsource/_impl/backend/modulemd.pyi new file mode 100644 index 00000000..191fa7ca --- /dev/null +++ b/src/pushsource/_impl/backend/modulemd.pyi @@ -0,0 +1,9 @@ +class Module(object): + name: str + stream: str + version: str + context: str + arch: str + nsvca: str + @classmethod + def from_file(cls, fname: str) -> "Module": ... \ No newline at end of file diff --git a/src/pushsource/_impl/backend/registry_source.pyi b/src/pushsource/_impl/backend/registry_source.pyi new file mode 100644 index 00000000..b9050130 --- /dev/null +++ b/src/pushsource/_impl/backend/registry_source.pyi @@ -0,0 +1,27 @@ +from collections import Iterator +from re import Pattern +from types import TracebackType +from typing import Optional, Type + +from pushsource import Source, PushItem +from pushsource._impl.model.base import PushItem_co +from pushsource.type_aliases import MaybeString + +IMAGE_URI_REGEX: Pattern + +class RegistrySource(Source): + def __init__( + self, + image: MaybeString, + dest: Optional[MaybeString] = ..., + dest_signing_key: Optional[MaybeString] = ..., + ) -> None: ... + def __enter__(self) -> "ErrataSource": ... + def __exit__( + self, + exc_type: Type[BaseException], + exc_val: BaseException, + exc_tb: TracebackType, + ) -> None: ... + def __iter__(self) -> Iterator[PushItem_co]: ... + def _push_item_from_registry_uri(self, uri: str, signing_key: str) -> PushItem: ... From 371485efde3d4ab558355b48d0d3fa123941dd15 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Tue, 11 Jan 2022 09:48:27 -0500 Subject: [PATCH 12/20] Rename PullSpec types to ContainerImagePullSpec --- src/pushsource/_impl/model/container.pyi | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/pushsource/_impl/model/container.pyi b/src/pushsource/_impl/model/container.pyi index d49983e8..e3fb1574 100644 --- a/src/pushsource/_impl/model/container.pyi +++ b/src/pushsource/_impl/model/container.pyi @@ -3,16 +3,18 @@ from typing import Text, AnyStr, TypeVar, Optional, Type from pushsource import PushItem -PullSpec_co = TypeVar("PullSpec_co", bound="ContainerImagePullSpec", covariant=True) -PullSpec_contra = TypeVar( - "PullSpec_contra", bound="ContainerImagePullSpec", contravariant=True +ContainerImagePullSpec_co = TypeVar( + "ContainerImagePullSpec_co", bound="ContainerImagePullSpec", covariant=True +) +ContainerImagePullSpec_contra = TypeVar( + "ContainerImagePullSpec_contra", bound="ContainerImagePullSpec", contravariant=True ) class ContainerImagePullSpec(object): registry: Text repository: Text @classmethod - def _from_str(cls, pull_spec: AnyStr) -> PullSpec_co: ... + def _from_str(cls, pull_spec: AnyStr) -> ContainerImagePullSpec_co: ... class ContainerImageTagPullSpec(ContainerImagePullSpec): tag: Text @@ -23,13 +25,13 @@ class ContainerImageDigestPullSpec(ContainerImagePullSpec): media_type: Optional[Text] = ... def specs_converter( - specs: Sequence[PullSpec_contra], expected_class: Type -) -> Sequence[PullSpec_co]: ... + specs: Sequence[ContainerImagePullSpec_contra], expected_class: Type +) -> Sequence[ContainerImagePullSpec_co]: ... def tag_specs_converter( - specs: Sequence[PullSpec_contra], + specs: Sequence[ContainerImagePullSpec_contra], ) -> Sequence[ContainerImageTagPullSpec]: ... def digest_specs_converter( - specs: Sequence[PullSpec_contra], + specs: Sequence[ContainerImagePullSpec_contra], ) -> Sequence[ContainerImageDigestPullSpec]: ... class ContainerImagePullInfo(object): From d9dc2f23e1dcc7e662f5b829db14c4a2f4fae61f Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Tue, 11 Jan 2022 09:48:56 -0500 Subject: [PATCH 13/20] Annotate modules in backend.staged package --- .../_impl/backend/staged/staged_ami.pyi | 10 ++++ .../_impl/backend/staged/staged_base.pyi | 39 +++++++++++++++ .../_impl/backend/staged/staged_compsxml.pyi | 10 ++++ .../_impl/backend/staged/staged_errata.pyi | 10 ++++ .../_impl/backend/staged/staged_files.pyi | 10 ++++ .../_impl/backend/staged/staged_modulemd.pyi | 10 ++++ .../_impl/backend/staged/staged_productid.pyi | 10 ++++ .../_impl/backend/staged/staged_rpm.pyi | 10 ++++ .../_impl/backend/staged/staged_source.pyi | 50 +++++++++++++++++++ .../backend/staged/staged_unsupported.pyi | 9 ++++ .../_impl/backend/staged/staged_utils.pyi | 48 ++++++++++++++++++ 11 files changed, 216 insertions(+) create mode 100644 src/pushsource/_impl/backend/staged/staged_ami.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_base.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_compsxml.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_errata.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_files.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_modulemd.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_productid.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_rpm.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_source.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_unsupported.pyi create mode 100644 src/pushsource/_impl/backend/staged/staged_utils.pyi diff --git a/src/pushsource/_impl/backend/staged/staged_ami.pyi b/src/pushsource/_impl/backend/staged/staged_ami.pyi new file mode 100644 index 00000000..33f3da45 --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_ami.pyi @@ -0,0 +1,10 @@ +from os import DirEntry + +from pushsource import AmiPushItem +from pushsource._impl.backend.staged.staged_base import StagedBaseMixin +from pushsource._impl.backend.staged.staged_utils import StagingLeafDir, StagingMetadata + +class StagedAmiMixin(StagedBaseMixin): + def __push_item( + self, leafdir: StagingLeafDir, metadata: StagingMetadata, entry: DirEntry + ) -> AmiPushItem: ... diff --git a/src/pushsource/_impl/backend/staged/staged_base.pyi b/src/pushsource/_impl/backend/staged/staged_base.pyi new file mode 100644 index 00000000..4ceda743 --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_base.pyi @@ -0,0 +1,39 @@ +from collections import Callable, Sequence +from os import DirEntry +from typing import Final, ClassVar, MutableMapping, Any + +from pushsource import PushItem +from pushsource._impl.backend.staged.staged_utils import StagingLeafDir, StagingMetadata +from pushsource._impl.model.base import PushItem_co + +# Typically "self" isn't annotated, but in this case +# "unbound" methods are being stashed in a dict and +# the "self" parameter is not fulfilled until later via +# partial application. This type annotation accounts for +# the type of unbound "self" parameter in the callable signature. +UnboundTypeHandlerDelegate = Callable[ + ["StagedBaseMixin", StagingLeafDir, StagingMetadata, DirEntry], PushItem +] +# A type for an UnboundTypeHandlerDelegate where "self" has +# been bound to an instance of StagedBaseMixin +BoundTypeHandlerDelegate = Callable[ + [StagingLeafDir, StagingMetadata, DirEntry], PushItem +] +# A partially applied type handler callable +PartialTypeHandler = Callable[[StagingLeafDir, StagingMetadata], Sequence[PushItem_co]] + +class TypeHandler(object): + HANDLERS: Final[ClassVar[MutableMapping[str, UnboundTypeHandlerDelegate]]] + type_name: str + def __init__(self, type_name: str) -> None: ... + def __call__(self, fn: UnboundTypeHandlerDelegate) -> None: ... + +class StagedBaseMixin(object): + _FILE_TYPES = Final[ClassVar[MutableMapping[str, PartialTypeHandler]]] + def __init__(self, *args: Any, **kwargs: Any) -> None: ... + def __mixin_push_items( + self, + leafdir: StagingLeafDir, + metadata: StagingMetadata, + delegate: BoundTypeHandlerDelegate, + ) -> Sequence[PushItem_co]: ... diff --git a/src/pushsource/_impl/backend/staged/staged_compsxml.pyi b/src/pushsource/_impl/backend/staged/staged_compsxml.pyi new file mode 100644 index 00000000..0bc0c536 --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_compsxml.pyi @@ -0,0 +1,10 @@ +from os import DirEntry + +from pushsource import CompsXmlPushItem +from pushsource._impl.backend.staged.staged_base import StagedBaseMixin +from pushsource._impl.backend.staged.staged_utils import StagingLeafDir, StagingMetadata + +class StagedCompsXmlMixin(StagedBaseMixin): + def __push_item( + self, leafdir: StagingLeafDir, _: StagingMetadata, entry: DirEntry + ) -> CompsXmlPushItem: ... diff --git a/src/pushsource/_impl/backend/staged/staged_errata.pyi b/src/pushsource/_impl/backend/staged/staged_errata.pyi new file mode 100644 index 00000000..e4b94df9 --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_errata.pyi @@ -0,0 +1,10 @@ +from os import DirEntry + +from pushsource import ErratumPushItem +from pushsource._impl.backend.staged.staged_base import StagedBaseMixin +from pushsource._impl.backend.staged.staged_utils import StagingMetadata, StagingLeafDir + +class StagedErrataMixin(StagedBaseMixin): + def __make_push_item( + self, leafdir: StagingLeafDir, metadata: StagingMetadata, entry: DirEntry + ) -> ErratumPushItem: ... diff --git a/src/pushsource/_impl/backend/staged/staged_files.pyi b/src/pushsource/_impl/backend/staged/staged_files.pyi new file mode 100644 index 00000000..6bec545e --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_files.pyi @@ -0,0 +1,10 @@ +from os import DirEntry + +from pushsource import FilePushItem +from pushsource._impl.backend.staged.staged_base import StagedBaseMixin +from pushsource._impl.backend.staged.staged_utils import StagingLeafDir, StagingMetadata + +class StagedFilesMixin(StagedBaseMixin): + def __file_push_item( + self, leafdir: StagingLeafDir, metadata: StagingMetadata, entry: DirEntry + ) -> FilePushItem: ... diff --git a/src/pushsource/_impl/backend/staged/staged_modulemd.pyi b/src/pushsource/_impl/backend/staged/staged_modulemd.pyi new file mode 100644 index 00000000..f9dadc63 --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_modulemd.pyi @@ -0,0 +1,10 @@ +from os import DirEntry + +from pushsource import ModuleMdPushItem +from pushsource._impl.backend.staged.staged_base import StagedBaseMixin +from pushsource._impl.backend.staged.staged_utils import StagingLeafDir, StagingMetadata + +class StagedModuleMdMixin(StagedBaseMixin): + def __push_item( + self, leafdir: StagingLeafDir, metadata: StagingMetadata, entry: DirEntry + ) -> ModuleMdPushItem: ... diff --git a/src/pushsource/_impl/backend/staged/staged_productid.pyi b/src/pushsource/_impl/backend/staged/staged_productid.pyi new file mode 100644 index 00000000..0c8f0b07 --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_productid.pyi @@ -0,0 +1,10 @@ +from os import DirEntry + +from .staged_utils import StagingLeafDir, StagingMetadata +from ...model import ProductIdPushItem +from .staged_base import StagedBaseMixin + +class StagedProductIdMixin(StagedBaseMixin): + def __push_item( + self, leafdir: StagingLeafDir, _: StagingMetadata, entry: DirEntry + ) -> ProductIdPushItem: ... diff --git a/src/pushsource/_impl/backend/staged/staged_rpm.pyi b/src/pushsource/_impl/backend/staged/staged_rpm.pyi new file mode 100644 index 00000000..0a4576b8 --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_rpm.pyi @@ -0,0 +1,10 @@ +from os import DirEntry + +from .staged_base import StagedBaseMixin +from .staged_utils import StagingLeafDir, StagingMetadata +from ...model import RpmPushItem + +class StagedRpmMixin(StagedBaseMixin): + def __push_item( + self, leafdir: StagingLeafDir, _: StagingMetadata, entry: DirEntry + ) -> RpmPushItem: ... diff --git a/src/pushsource/_impl/backend/staged/staged_source.pyi b/src/pushsource/_impl/backend/staged/staged_source.pyi new file mode 100644 index 00000000..bcb952ed --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_source.pyi @@ -0,0 +1,50 @@ +from collections import Sequence, Mapping, Iterator, MutableMapping, Generator +from threading import RLock as ReentrantLock +from types import TracebackType +from typing import Final, ClassVar, Type + +from .staged_base import PartialTypeHandler +from .staged_utils import StagingMetadata, StagingLeafDir +from ...model.base import PushItem_co, PushItem +from ...source import Source + +from .staged_ami import StagedAmiMixin +from .staged_compsxml import StagedCompsXmlMixin +from .staged_errata import StagedErrataMixin +from .staged_files import StagedFilesMixin +from .staged_modulemd import StagedModuleMdMixin +from .staged_productid import StagedProductIdMixin +from .staged_rpm import StagedRpmMixin +from .staged_unsupported import StagedUnsupportedMixin + +METADATA_FILES: Final[Sequence[str]] +CACHE_LOCK: Final[ReentrantLock] + +class StagedSource( + Source, + StagedAmiMixin, + StagedFilesMixin, + StagedErrataMixin, + StagedCompsXmlMixin, + StagedModuleMdMixin, + StagedProductIdMixin, + StagedRpmMixin, + StagedUnsupportedMixin, +): + _FILE_TYPES = Final[ClassVar[MutableMapping[str, PartialTypeHandler]]] + def __init__( + self, url: Sequence[str], threads: int = ..., timeout: int = ... + ) -> None: ... + def __enter__(self) -> "Source": ... + def __exit__( + self, + exc_type: Type[BaseException], + exc_val: BaseException, + exc_tb: TracebackType, + ): ... + def __iter__(self) -> Iterator[PushItem_co]: ... + def _load_metadata(self, topdir: str) -> StagingMetadata: ... + def _push_items_for_leafdir( + self, leafdir: StagingLeafDir, metadata: StagingMetadata + ) -> Sequence[PushItem_co]: ... + def _push_items_for_topdir(self, topdir: str) -> Iterator[PushItem_co]: ... diff --git a/src/pushsource/_impl/backend/staged/staged_unsupported.pyi b/src/pushsource/_impl/backend/staged/staged_unsupported.pyi new file mode 100644 index 00000000..1e5fcbae --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_unsupported.pyi @@ -0,0 +1,9 @@ +from os import DirEntry + +from .staged_base import StagedBaseMixin +from .staged_utils import StagingLeafDir, StagingMetadata + +class StagedUnsupportedMixin(StagedBaseMixin): + def __push_item( + self, _leafdir: StagingLeafDir, _metadata: StagingMetadata, entry: DirEntry + ) -> None: ... diff --git a/src/pushsource/_impl/backend/staged/staged_utils.pyi b/src/pushsource/_impl/backend/staged/staged_utils.pyi new file mode 100644 index 00000000..16b87d92 --- /dev/null +++ b/src/pushsource/_impl/backend/staged/staged_utils.pyi @@ -0,0 +1,48 @@ +from collections import Mapping +from typing import Final, Any, Optional, NoReturn, Union + +from pushsource._impl.validator import Validator +from pushsource.type_aliases import JsonObject + +REQUIRED_VERSION: Final[str] = ... +VALIDATOR: Final[Validator] = ... + +class StagingFileMetadata(object): + attributes: Mapping[Any] + filename: str + relative_path: str + sha256sum: str + version: str + def __init__( + self, + attributes: Mapping[Any], + filename: str, + relative_path: str, + sha256sum: str, + version: str, + ) -> None: ... + +class StagingMetadata(object): + filename: Optional[str] = ... + file_metadata: Optional[Mapping[str, StagingFileMetadata]] = ... + def __init__( + self, + filename: Optional[str] = ..., + file_metadata: Optional[Mapping[str, StagingFileMetadata]] = ..., + ) -> None: ... + def file_metadata_or_die(self, relative_path: str) -> StagingFileMetadata: ... + @classmethod + def from_data(cls, data: JsonObject, filename: str = ...) -> "StagingMetadata": ... + +class StagingLeafDir(object): + file_type: str + dest: str + path: str + topdir: str + def __init__( + self, + file_type: str, + dest: str, + path: str, + topdir: str, + ) -> None: ... From 4fcd04771e1a13ab9efded638d1867497d221594 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Tue, 11 Jan 2022 10:17:22 -0500 Subject: [PATCH 14/20] Add missing Json* types --- src/pushsource/type_aliases.pyi | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pushsource/type_aliases.pyi b/src/pushsource/type_aliases.pyi index f01adab3..fa778367 100644 --- a/src/pushsource/type_aliases.pyi +++ b/src/pushsource/type_aliases.pyi @@ -1,7 +1,17 @@ import datetime -from typing import Union, Collection +from collections import Mapping, Sequence +from numbers import Number +from typing import Union, Collection, Optional Date = datetime.date DateTime = datetime.datetime -MaybeString = Union[str, Collection[str]] \ No newline at end of file +MaybeString = Union[str, Collection[str]] + +# First attempt at a JsonObject type based on the spec from +# https://www.json.org/json-en.html +# from the spec a Value can be a string, number, object, array, true, false, or null +# the "null" case is covered by Optional[] +_JsonValue = Optional[Union[str, Number, object, "_JsonArray", bool]] +_JsonArray = Sequence[_JsonValue] +JsonObject = Mapping[str, _JsonValue] From d791837ee40dd7ad8b1e3ea48e9e6bbae8ff984f Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Tue, 11 Jan 2022 10:19:16 -0500 Subject: [PATCH 15/20] Run Black over code. Need to investigate pre-commit hook not working --- .../_impl/backend/errata_source/errata_client.pyi | 14 ++------------ .../_impl/backend/errata_source/errata_source.pyi | 1 - src/pushsource/_impl/backend/koji_containers.pyi | 5 ++--- src/pushsource/_impl/backend/koji_source.pyi | 8 ++++++-- src/pushsource/_impl/backend/modulemd.pyi | 2 +- src/pushsource/_impl/model/ami.pyi | 1 - src/pushsource/_impl/model/erratum.pyi | 5 +++-- 7 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/pushsource/_impl/backend/errata_source/errata_client.pyi b/src/pushsource/_impl/backend/errata_source/errata_client.pyi index 2d508f8c..afb7fd5a 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_client.pyi +++ b/src/pushsource/_impl/backend/errata_source/errata_client.pyi @@ -7,30 +7,22 @@ from pushsource.type_aliases import JsonObject ErrataRaw_co = TypeVar("ErrataRaw_co", bound="ErrataRaw", covariant=True) - class ErrataRaw(object): advisory_cdn_metadata: JsonObject advisory_cdn_file_list: JsonObject advisory_cdn_docker_file_list: JsonObject ftp_paths: JsonObject - def __init__( self, advisory_cdn_metadata: JsonObject, advisory_cdn_file_list: JsonObject, advisory_cdn_docker_file_list: JsonObject, - ftp_paths: JsonObject + ftp_paths: JsonObject, ) -> None: ... class ErrataClient(object): _errata_service: xmlrpc.client.ServerProxy - def __init__( - self, - threads: int, - url: str, - **retry_args: Any - ) -> None: ... - + def __init__(self, threads: int, url: str, **retry_args: Any) -> None: ... def shutdown(self) -> None: ... def _log_queried_et(self, response: JsonObject, advisory_id: str) -> JsonObject: ... def get_raw_f(self, advisory_id: str) -> Sequence[ErrataRaw_co]: ... @@ -38,5 +30,3 @@ class ErrataClient(object): # TODO: since this method can explicitly raise, is it appropriate # to document the return type as Union[Any, NoReturn]? def _call_et(self, method_name: str, advisory_id: str) -> Any: ... - - diff --git a/src/pushsource/_impl/backend/errata_source/errata_source.pyi b/src/pushsource/_impl/backend/errata_source/errata_source.pyi index 206387cb..c91d6b81 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_source.pyi +++ b/src/pushsource/_impl/backend/errata_source/errata_source.pyi @@ -65,4 +65,3 @@ class ErrataSource(Source): def _add_ftp_paths( self, items: Sequence[PushItem_contra], erratum: ErratumPushItem, raw: ErrataRaw ) -> Sequence[PushItem_co]: ... - diff --git a/src/pushsource/_impl/backend/koji_containers.pyi b/src/pushsource/_impl/backend/koji_containers.pyi index 45baf917..410d7e0c 100644 --- a/src/pushsource/_impl/backend/koji_containers.pyi +++ b/src/pushsource/_impl/backend/koji_containers.pyi @@ -20,6 +20,5 @@ class ContainerArchiveHelper(object): pull_info: ContainerImagePullInfo def get_tag_specs(raw_specs: Sequence[str]) -> Sequence[ContainerImagePullSpec_co]: ... -def get_digest_specs( - raw_specs: Sequence[str], digests_map -): Sequence[ContainerImagePullSpec_co]: ... \ No newline at end of file +def get_digest_specs(raw_specs: Sequence[str], digests_map): + Sequence[ContainerImagePullSpec_co]: ... diff --git a/src/pushsource/_impl/backend/koji_source.pyi b/src/pushsource/_impl/backend/koji_source.pyi index d03de361..41290031 100644 --- a/src/pushsource/_impl/backend/koji_source.pyi +++ b/src/pushsource/_impl/backend/koji_source.pyi @@ -92,8 +92,12 @@ class KojiSource(Source): def _push_items_from_module_build( self, nvr: str, meta: Mapping[str, Any] ) -> Sequence[PushItem_co]: ... - def _push_items_from_container_build(self, nvr: str, meta: Mapping[str, Any]) -> Sequence[PushItem_co]: ... - def _get_operator_item(self, nvr: str, meta: Mapping[str, Any], archives: Iterable[Mapping[str, Any]]) -> OperatorManifestPushItem: ... + def _push_items_from_container_build( + self, nvr: str, meta: Mapping[str, Any] + ) -> Sequence[PushItem_co]: ... + def _get_operator_item( + self, nvr: str, meta: Mapping[str, Any], archives: Iterable[Mapping[str, Any]] + ) -> OperatorManifestPushItem: ... def _rpm_futures(self) -> Sequence[Future[PushItem_co]]: ... def _modulemd_futures(self) -> Sequence[Future[PushItem_co]]: ... def _container_futures(self) -> Sequence[Future[PushItem_co]]: ... diff --git a/src/pushsource/_impl/backend/modulemd.pyi b/src/pushsource/_impl/backend/modulemd.pyi index 191fa7ca..266d4522 100644 --- a/src/pushsource/_impl/backend/modulemd.pyi +++ b/src/pushsource/_impl/backend/modulemd.pyi @@ -6,4 +6,4 @@ class Module(object): arch: str nsvca: str @classmethod - def from_file(cls, fname: str) -> "Module": ... \ No newline at end of file + def from_file(cls, fname: str) -> "Module": ... diff --git a/src/pushsource/_impl/model/ami.pyi b/src/pushsource/_impl/model/ami.pyi index 526085f6..697c48b0 100644 --- a/src/pushsource/_impl/model/ami.pyi +++ b/src/pushsource/_impl/model/ami.pyi @@ -4,7 +4,6 @@ from typing import Text, Optional from pushsource import PushItem from pushsource.type_aliases import Date - class AmiRelease(object): product: Text date: Date diff --git a/src/pushsource/_impl/model/erratum.pyi b/src/pushsource/_impl/model/erratum.pyi index 830ff4d2..8f665446 100644 --- a/src/pushsource/_impl/model/erratum.pyi +++ b/src/pushsource/_impl/model/erratum.pyi @@ -3,7 +3,6 @@ from typing import Text, overload, List, Optional from pushsource import PushItem - class ErratumReference(object): href: Text id: Text @@ -11,7 +10,9 @@ class ErratumReference(object): type: Text = ... @classmethod @overload - def _from_data(cls, data: Sequence[Mapping[Text, ...]]) -> MutableSequence["ErratumReference"]: ... + def _from_data( + cls, data: Sequence[Mapping[Text, ...]] + ) -> MutableSequence["ErratumReference"]: ... @classmethod @overload def _from_data(cls, data: Mapping[Text, ...]) -> "ErratumReference": ... From 4c9df5d30164030306e45438200d7f4ad14d949f Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Wed, 12 Jan 2022 14:32:59 -0500 Subject: [PATCH 16/20] Update src/pushsource/_impl/backend/registry_source.pyi Fix copy/paste error in __enter__ stub. Co-authored-by: Rohan McGovern --- src/pushsource/_impl/backend/registry_source.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pushsource/_impl/backend/registry_source.pyi b/src/pushsource/_impl/backend/registry_source.pyi index b9050130..dd650dc4 100644 --- a/src/pushsource/_impl/backend/registry_source.pyi +++ b/src/pushsource/_impl/backend/registry_source.pyi @@ -16,7 +16,7 @@ class RegistrySource(Source): dest: Optional[MaybeString] = ..., dest_signing_key: Optional[MaybeString] = ..., ) -> None: ... - def __enter__(self) -> "ErrataSource": ... + def __enter__(self) -> "RegistrySource": ... def __exit__( self, exc_type: Type[BaseException], From 9096672ae12f367bb03ecf1055d9615dd2a21b1f Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Sat, 15 Jan 2022 12:29:00 -0500 Subject: [PATCH 17/20] Move type_aliases to _impl package --- src/pushsource/_impl/backend/errata_source/errata_client.pyi | 2 +- src/pushsource/_impl/backend/errata_source/errata_source.pyi | 2 +- src/pushsource/_impl/backend/koji_source.pyi | 2 +- src/pushsource/_impl/backend/registry_source.pyi | 2 +- src/pushsource/_impl/backend/staged/staged_utils.pyi | 2 +- src/pushsource/_impl/model/ami.pyi | 3 ++- src/pushsource/{ => _impl}/type_aliases.pyi | 0 7 files changed, 7 insertions(+), 6 deletions(-) rename src/pushsource/{ => _impl}/type_aliases.pyi (100%) diff --git a/src/pushsource/_impl/backend/errata_source/errata_client.pyi b/src/pushsource/_impl/backend/errata_source/errata_client.pyi index afb7fd5a..1f839157 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_client.pyi +++ b/src/pushsource/_impl/backend/errata_source/errata_client.pyi @@ -3,7 +3,7 @@ import xmlrpc.client from collections import Sequence from typing import Any, TypeVar -from pushsource.type_aliases import JsonObject +from pushsource._impl.type_aliases import JsonObject ErrataRaw_co = TypeVar("ErrataRaw_co", bound="ErrataRaw", covariant=True) diff --git a/src/pushsource/_impl/backend/errata_source/errata_source.pyi b/src/pushsource/_impl/backend/errata_source/errata_source.pyi index c91d6b81..d4d6a8c0 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_source.pyi +++ b/src/pushsource/_impl/backend/errata_source/errata_source.pyi @@ -10,7 +10,7 @@ from pushsource import ( ) from pushsource._impl.backend.errata_source.errata_client import ErrataRaw from pushsource._impl.model.base import PushItem_co, PushItem_contra -from pushsource.type_aliases import MaybeString +from pushsource._impl.type_aliases import MaybeString # TODO: is the value type a model type or just a Mapping? DockerFileList = Mapping[str, Any] diff --git a/src/pushsource/_impl/backend/koji_source.pyi b/src/pushsource/_impl/backend/koji_source.pyi index 41290031..d8730297 100644 --- a/src/pushsource/_impl/backend/koji_source.pyi +++ b/src/pushsource/_impl/backend/koji_source.pyi @@ -9,7 +9,7 @@ from koji import ClientSession, VirtualCall from pushsource import Source, RpmPushItem, OperatorManifestPushItem from pushsource._impl.model.base import PushItem_co -from pushsource.type_aliases import MaybeString, JsonObject +from pushsource._impl.type_aliases import MaybeString, JsonObject # TODO: for now using Union[str, int] until I figure out # which is really intended. This actually might be the best diff --git a/src/pushsource/_impl/backend/registry_source.pyi b/src/pushsource/_impl/backend/registry_source.pyi index dd650dc4..1de920a4 100644 --- a/src/pushsource/_impl/backend/registry_source.pyi +++ b/src/pushsource/_impl/backend/registry_source.pyi @@ -5,7 +5,7 @@ from typing import Optional, Type from pushsource import Source, PushItem from pushsource._impl.model.base import PushItem_co -from pushsource.type_aliases import MaybeString +from pushsource._impl.type_aliases import MaybeString IMAGE_URI_REGEX: Pattern diff --git a/src/pushsource/_impl/backend/staged/staged_utils.pyi b/src/pushsource/_impl/backend/staged/staged_utils.pyi index 16b87d92..4186c6d8 100644 --- a/src/pushsource/_impl/backend/staged/staged_utils.pyi +++ b/src/pushsource/_impl/backend/staged/staged_utils.pyi @@ -2,7 +2,7 @@ from collections import Mapping from typing import Final, Any, Optional, NoReturn, Union from pushsource._impl.validator import Validator -from pushsource.type_aliases import JsonObject +from pushsource._impl.type_aliases import JsonObject REQUIRED_VERSION: Final[str] = ... VALIDATOR: Final[Validator] = ... diff --git a/src/pushsource/_impl/model/ami.pyi b/src/pushsource/_impl/model/ami.pyi index 697c48b0..e43192d8 100644 --- a/src/pushsource/_impl/model/ami.pyi +++ b/src/pushsource/_impl/model/ami.pyi @@ -2,7 +2,8 @@ from collections import Sequence from typing import Text, Optional from pushsource import PushItem -from pushsource.type_aliases import Date +from pushsource._impl.type_aliases import Date + class AmiRelease(object): product: Text diff --git a/src/pushsource/type_aliases.pyi b/src/pushsource/_impl/type_aliases.pyi similarity index 100% rename from src/pushsource/type_aliases.pyi rename to src/pushsource/_impl/type_aliases.pyi From 0cae6ffdb4064991085319ffb43fb31aaea3ffd0 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Sat, 15 Jan 2022 12:33:06 -0500 Subject: [PATCH 18/20] Remove uses of NoReturn as it was being used incorrectly --- src/pushsource/_impl/backend/errata_source/errata_client.pyi | 2 -- src/pushsource/_impl/backend/koji_source.pyi | 2 +- src/pushsource/_impl/backend/staged/staged_utils.pyi | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pushsource/_impl/backend/errata_source/errata_client.pyi b/src/pushsource/_impl/backend/errata_source/errata_client.pyi index 1f839157..4f5ab79e 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_client.pyi +++ b/src/pushsource/_impl/backend/errata_source/errata_client.pyi @@ -27,6 +27,4 @@ class ErrataClient(object): def _log_queried_et(self, response: JsonObject, advisory_id: str) -> JsonObject: ... def get_raw_f(self, advisory_id: str) -> Sequence[ErrataRaw_co]: ... # TODO: narrow return type if possible: JsonObject maybe? - # TODO: since this method can explicitly raise, is it appropriate - # to document the return type as Union[Any, NoReturn]? def _call_et(self, method_name: str, advisory_id: str) -> Any: ... diff --git a/src/pushsource/_impl/backend/koji_source.pyi b/src/pushsource/_impl/backend/koji_source.pyi index d8730297..1282df56 100644 --- a/src/pushsource/_impl/backend/koji_source.pyi +++ b/src/pushsource/_impl/backend/koji_source.pyi @@ -72,7 +72,7 @@ class KojiSource(Source): ) -> None: ... def __iter__(self) -> Iterator[PushItem_co]: ... # TODO: the return type here feels hacky, but is accurate - def _koji_check(self) -> Optional[NoReturn]: ... + def _koji_check(self) -> None: ... def _koji_get_version(self) -> str: ... # TODO: reasonably sure based on the Fedora Koji XML-RPC # docs for getRPM, getBuild, and getArchive that what is diff --git a/src/pushsource/_impl/backend/staged/staged_utils.pyi b/src/pushsource/_impl/backend/staged/staged_utils.pyi index 4186c6d8..07d5c147 100644 --- a/src/pushsource/_impl/backend/staged/staged_utils.pyi +++ b/src/pushsource/_impl/backend/staged/staged_utils.pyi @@ -1,5 +1,5 @@ from collections import Mapping -from typing import Final, Any, Optional, NoReturn, Union +from typing import Final, Any, Optional from pushsource._impl.validator import Validator from pushsource._impl.type_aliases import JsonObject From ecf2852cc1dd5d22415190b417b0ccab10837c7a Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Sat, 15 Jan 2022 12:33:43 -0500 Subject: [PATCH 19/20] Resolve some TODOs --- src/pushsource/_impl/backend/errata_source/errata_client.pyi | 1 - src/pushsource/_impl/backend/koji_source.pyi | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/pushsource/_impl/backend/errata_source/errata_client.pyi b/src/pushsource/_impl/backend/errata_source/errata_client.pyi index 4f5ab79e..89fc9754 100644 --- a/src/pushsource/_impl/backend/errata_source/errata_client.pyi +++ b/src/pushsource/_impl/backend/errata_source/errata_client.pyi @@ -1,4 +1,3 @@ -# TODO: are stub files subject to the same need for six.moves? import xmlrpc.client from collections import Sequence from typing import Any, TypeVar diff --git a/src/pushsource/_impl/backend/koji_source.pyi b/src/pushsource/_impl/backend/koji_source.pyi index 1282df56..cec9dab6 100644 --- a/src/pushsource/_impl/backend/koji_source.pyi +++ b/src/pushsource/_impl/backend/koji_source.pyi @@ -11,9 +11,6 @@ from pushsource import Source, RpmPushItem, OperatorManifestPushItem from pushsource._impl.model.base import PushItem_co from pushsource._impl.type_aliases import MaybeString, JsonObject -# TODO: for now using Union[str, int] until I figure out -# which is really intended. This actually might be the best -# option after all, but I need to investigate Id = Union[str, int] CACHE_LOCK: ReentrantLock From 02e6101e653fbbcd4b88193067ac851de0bfc9a2 Mon Sep 17 00:00:00 2001 From: Ryan Smith Date: Sat, 15 Jan 2022 14:17:01 -0500 Subject: [PATCH 20/20] Cache should be MutableMapping, not Mapping --- src/pushsource/_impl/backend/koji_source.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pushsource/_impl/backend/koji_source.pyi b/src/pushsource/_impl/backend/koji_source.pyi index cec9dab6..ee2c9f37 100644 --- a/src/pushsource/_impl/backend/koji_source.pyi +++ b/src/pushsource/_impl/backend/koji_source.pyi @@ -57,7 +57,7 @@ class KojiSource(Source): basedir: Optional[str] = ..., threads: int = ..., timeout: int = ..., - cache: Optional[Mapping[str, Any]] = ..., + cache: Optional[MutableMapping[str, Any]] = ..., executor: Optional[Executor] = ..., ) -> None: ... def __enter__(self) -> "KojiSource": ...