diff --git a/MANIFEST.in b/MANIFEST.in index b254d3a125..003ddfe299 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,6 +3,7 @@ include OWNERS include *.md include *.txt include *.ini +include kubernetes/py.typed include kubernetes/client/py.typed exclude .gitignore exclude .gitreview diff --git a/kubernetes/py.typed b/kubernetes/py.typed new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/kubernetes/py.typed @@ -0,0 +1 @@ + diff --git a/kubernetes/test/test_typing.py b/kubernetes/test/test_typing.py new file mode 100644 index 0000000000..15c6cc42e2 --- /dev/null +++ b/kubernetes/test/test_typing.py @@ -0,0 +1,78 @@ +# Copyright 2026 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from importlib.resources import files +import unittest + +from typing_extensions import assert_type + +from kubernetes import client +from kubernetes.aio import client as aio_client + + +class TestPackageTyping(unittest.TestCase): + def test_root_package_is_marked_as_typed(self): + self.assertTrue(files('kubernetes').joinpath('py.typed').is_file()) + + def test_synchronous_nested_model_types(self): + pod = client.V1Pod(status=client.V1PodStatus(container_statuses=[ + client.V1ContainerStatus( + image='image', + image_id='image-id', + name='container', + ready=True, + restart_count=0, + state=client.V1ContainerState(), + ), + ])) + + status = assert_type(pod.status, client.V1PodStatus | None) + assert status is not None + containers = assert_type( + status.container_statuses, + list[client.V1ContainerStatus] | None, + ) + assert containers is not None + state = assert_type( + containers[0].state, + client.V1ContainerState | None, + ) + self.assertIsInstance(state, client.V1ContainerState) + + def test_asynchronous_nested_model_types(self): + pod = aio_client.V1Pod( + status=aio_client.V1PodStatus(container_statuses=[ + aio_client.V1ContainerStatus( + image='image', + image_id='image-id', + name='container', + ready=True, + restart_count=0, + state=aio_client.V1ContainerState(), + ), + ]), + ) + + status = assert_type(pod.status, aio_client.V1PodStatus | None) + assert status is not None + containers = assert_type( + status.container_statuses, + list[aio_client.V1ContainerStatus] | None, + ) + assert containers is not None + state = assert_type( + containers[0].state, + aio_client.V1ContainerState | None, + ) + self.assertIsInstance(state, aio_client.V1ContainerState) diff --git a/setup-release.py b/setup-release.py index 17fbcbd901..11dd55d7c4 100644 --- a/setup-release.py +++ b/setup-release.py @@ -80,7 +80,10 @@ 'kubernetes.aio.client.api', 'kubernetes.aio.client.models' ], - package_data={'kubernetes.client': ['py.typed']}, + package_data={ + 'kubernetes': ['py.typed'], + 'kubernetes.client': ['py.typed'], + }, include_package_data=True, long_description="Python client for kubernetes http://kubernetes.io/", python_requires='>=3.10', diff --git a/setup.py b/setup.py index ed1321c242..892dfa8ff2 100644 --- a/setup.py +++ b/setup.py @@ -67,7 +67,10 @@ 'kubernetes.leaderelection.resourcelock', 'kubernetes.informer', ], - package_data={'kubernetes.client': ['py.typed']}, + package_data={ + 'kubernetes': ['py.typed'], + 'kubernetes.client': ['py.typed'], + }, include_package_data=True, long_description="Python client for kubernetes http://kubernetes.io/", python_requires='>=3.10',