Skip to content

Commit 0d74bab

Browse files
Replace @sync decorator with APIObjectSyncMixin for all sync objects (#551)
1 parent 06794cc commit 0d74bab

File tree

10 files changed

+523
-192
lines changed

10 files changed

+523
-192
lines changed

conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import gc
44
import os
55
import time
6+
from collections.abc import Generator
67

78
import pytest
89
from pytest_kind.cluster import KindCluster
@@ -17,7 +18,7 @@ def ensure_gc():
1718

1819

1920
@pytest.fixture(scope="session", autouse=True)
20-
def k8s_cluster(request) -> KindCluster:
21+
def k8s_cluster(request) -> Generator[KindCluster, None, None]:
2122
image = None
2223
if version := os.environ.get("KUBERNETES_VERSION"):
2324
image = f"kindest/node:v{version}"

kr8s/__init__.py

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,25 @@
66
At the top level, `kr8s` provides a synchronous API that wraps the asynchronous API provided by `kr8s.asyncio`.
77
Both APIs are functionally identical with the same objects, method signatures and return values.
88
"""
9+
# Disable missing docstrings, these are inherited from the async version of the objects
10+
# ruff: noqa: D102
11+
from __future__ import annotations
12+
913
from functools import partial, update_wrapper
10-
from typing import Dict, Optional, Type, Union
14+
from typing import Generator
1115

1216
from . import asyncio, objects, portforward
1317
from ._api import ALL
1418
from ._api import Api as _AsyncApi
1519
from ._async_utils import run_sync as _run_sync
16-
from ._async_utils import sync as _sync
1720
from ._exceptions import (
1821
APITimeoutError,
1922
ConnectionClosedError,
2023
ExecError,
2124
NotFoundError,
2225
ServerError,
2326
)
27+
from ._objects import APIObject
2428
from .asyncio import (
2529
api as _api,
2630
)
@@ -48,18 +52,73 @@
4852
__version_tuple__ = (0, 0, 0)
4953

5054

51-
@_sync
5255
class Api(_AsyncApi):
53-
__doc__ = _AsyncApi.__doc__
56+
_asyncio = False
57+
58+
def version(self) -> dict: # type: ignore
59+
return _run_sync(self.async_version)() # type: ignore
60+
61+
def reauthenticate(self): # type: ignore
62+
return _run_sync(self.async_reauthenticate)() # type: ignore
63+
64+
def whoami(self): # type: ignore
65+
return _run_sync(self.async_whoami)() # type: ignore
66+
67+
def lookup_kind(self, kind) -> tuple[str, str, bool]: # type: ignore
68+
return _run_sync(self.async_lookup_kind)(kind) # type: ignore
69+
70+
def get( # type: ignore
71+
self,
72+
kind: str | type,
73+
*names: str,
74+
namespace: str | None = None,
75+
label_selector: str | dict | None = None,
76+
field_selector: str | dict | None = None,
77+
as_object: type[APIObject] | None = None,
78+
allow_unknown_type: bool = True,
79+
**kwargs,
80+
) -> Generator[APIObject]:
81+
yield from _run_sync(self.async_get)(
82+
kind,
83+
*names,
84+
namespace=namespace,
85+
label_selector=label_selector,
86+
field_selector=field_selector,
87+
as_object=as_object,
88+
allow_unknown_type=allow_unknown_type,
89+
**kwargs,
90+
)
91+
92+
def watch( # type: ignore
93+
self,
94+
kind: str,
95+
namespace: str | None = None,
96+
label_selector: str | dict | None = None,
97+
field_selector: str | dict | None = None,
98+
since: str | None = None,
99+
) -> Generator[tuple[str, APIObject]]:
100+
yield from _run_sync(self.async_watch)(
101+
kind,
102+
namespace=namespace,
103+
label_selector=label_selector,
104+
field_selector=field_selector,
105+
since=since,
106+
)
107+
108+
def api_resources(self) -> list[dict]: # type: ignore
109+
return _run_sync(self.async_api_resources)() # type: ignore
110+
111+
def api_versions(self) -> Generator[str]: # type: ignore
112+
yield from _run_sync(self.async_api_versions)()
54113

55114

56115
def get(
57116
kind: str,
58117
*names: str,
59-
namespace: Optional[str] = None,
60-
label_selector: Optional[Union[str, Dict]] = None,
61-
field_selector: Optional[Union[str, Dict]] = None,
62-
as_object: Optional[Type] = None,
118+
namespace: str | None = None,
119+
label_selector: str | dict | None = None,
120+
field_selector: str | dict | None = None,
121+
as_object: type | None = None,
63122
allow_unknown_type: bool = True,
64123
api=None,
65124
**kwargs,
@@ -109,12 +168,12 @@ def get(
109168

110169

111170
def api(
112-
url: Optional[str] = None,
113-
kubeconfig: Optional[str] = None,
114-
serviceaccount: Optional[str] = None,
115-
namespace: Optional[str] = None,
116-
context: Optional[str] = None,
117-
) -> Union[Api, _AsyncApi]:
171+
url: str | None = None,
172+
kubeconfig: str | None = None,
173+
serviceaccount: str | None = None,
174+
namespace: str | None = None,
175+
context: str | None = None,
176+
) -> Api:
118177
"""Create a :class:`kr8s.Api` object for interacting with the Kubernetes API.
119178
120179
If a kr8s object already exists with the same arguments in this thread, it will be returned.
@@ -142,7 +201,7 @@ def api(
142201
context=context,
143202
_asyncio=False,
144203
)
145-
assert isinstance(ret, (Api, _AsyncApi))
204+
assert isinstance(ret, Api)
146205
return ret
147206

148207

kr8s/_api.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ async def async_version(self) -> dict:
260260

261261
async def reauthenticate(self) -> None:
262262
"""Reauthenticate the API."""
263+
return await self.async_reauthenticate()
264+
265+
async def async_reauthenticate(self) -> None:
263266
await self.auth.reauthenticate()
264267

265268
async def whoami(self):
@@ -293,6 +296,22 @@ async def async_whoami(self):
293296
[name] = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)
294297
return name.value
295298

299+
async def lookup_kind(self, kind) -> tuple[str, str, bool]:
300+
"""Lookup a Kubernetes resource kind.
301+
302+
Check whether a resource kind exists on the remote server.
303+
304+
Args:
305+
kind: The kind of resource to lookup.
306+
307+
Returns:
308+
The kind of resource, the plural form and whether the resource is namespaced
309+
310+
Raises:
311+
ValueError: If the kind is not found.
312+
"""
313+
return await self.async_lookup_kind(kind)
314+
296315
async def async_lookup_kind(self, kind) -> tuple[str, str, bool]:
297316
"""Lookup a Kubernetes resource kind."""
298317
from ._objects import parse_kind
@@ -321,22 +340,6 @@ async def async_lookup_kind(self, kind) -> tuple[str, str, bool]:
321340
)
322341
raise ValueError(f"Kind {kind} not found.")
323342

324-
async def lookup_kind(self, kind) -> tuple[str, str, bool]:
325-
"""Lookup a Kubernetes resource kind.
326-
327-
Check whether a resource kind exists on the remote server.
328-
329-
Args:
330-
kind: The kind of resource to lookup.
331-
332-
Returns:
333-
The kind of resource, the plural form and whether the resource is namespaced
334-
335-
Raises:
336-
ValueError: If the kind is not found.
337-
"""
338-
return await self.async_lookup_kind(kind)
339-
340343
@contextlib.asynccontextmanager
341344
async def async_get_kind(
342345
self,
@@ -542,7 +545,7 @@ async def watch(
542545
label_selector: str | dict | None = None,
543546
field_selector: str | dict | None = None,
544547
since: str | None = None,
545-
):
548+
) -> AsyncGenerator[tuple[str, APIObject]]:
546549
"""Watch a Kubernetes resource."""
547550
async for t, object in self.async_watch(
548551
kind,

0 commit comments

Comments
 (0)