Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion kopf/_cogs/structs/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import collections
import dataclasses
import datetime
import inspect
import random
from collections.abc import AsyncIterable, AsyncIterator, Callable, Mapping
from typing import NewType, TypeVar, cast
Expand Down Expand Up @@ -386,7 +387,7 @@ async def _flush_caches(
if item.caches:
for obj in item.caches.values():
if hasattr(obj, 'close'):
if asyncio.iscoroutinefunction(getattr(obj, 'close')):
if inspect.iscoroutinefunction(getattr(obj, 'close')):
await getattr(obj, 'close')()
else:
getattr(obj, 'close')()
Expand Down
3 changes: 2 additions & 1 deletion kopf/_core/actions/invocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import contextlib
import contextvars
import functools
import inspect
from collections.abc import Callable, Coroutine, Iterable, Iterator, Mapping
from typing import Any, TypeAlias, TypeVar, final

Expand Down Expand Up @@ -154,4 +155,4 @@ def is_async_fn(
elif hasattr(fn, '__wrapped__'): # @functools.wraps()
return is_async_fn(fn.__wrapped__)
else:
return asyncio.iscoroutinefunction(fn)
return inspect.iscoroutinefunction(fn)
48 changes: 35 additions & 13 deletions kopf/_kits/loops.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import asyncio
import contextlib
from collections.abc import Generator
import sys
from collections.abc import Iterator


@contextlib.contextmanager
def proper_loop(suggested_loop: asyncio.AbstractEventLoop | None = None) -> Generator[None, None, None]:
def proper_loop(suggested_loop: asyncio.AbstractEventLoop | None = None) -> Iterator[asyncio.AbstractEventLoop | None]:
"""
Ensure that we have the proper loop, either suggested or properly managed.

Expand All @@ -15,22 +16,43 @@ def proper_loop(suggested_loop: asyncio.AbstractEventLoop | None = None) -> Gene
This loop manager is usually used in CLI only, not deeper than that;
i.e. not even in ``kopf.run()``, since uvloop is only auto-managed for CLI.
"""
original_policy = asyncio.get_event_loop_policy()
if suggested_loop is None: # the pure CLI use, not a KopfRunner or other code
# Event loop policies were deprecated in 3.14 entirely. Yet they still exist in older versions.
# However, the asyncio.Runner was introduced in Python 3.11, so we can use the logic from there.
if suggested_loop is not None:
yield suggested_loop

elif sys.version_info >= (3, 11): # optional in 3.11-3.13, mandatory in >=3.14
# Use uvloop if available by injecting it as the selected loop.
try:
import uvloop
except ImportError:
pass
else:
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner:
yield runner.get_loop()
return

# Use the default loop/runner in place, do not inject anything.
yield None

try:
yield
# For Python<=3.10, use the event-loop-policy-based injection.
else:
original_policy = asyncio.get_event_loop_policy()
if suggested_loop is None: # the pure CLI use, not a KopfRunner or other code
try:
import uvloop
except ImportError:
pass
else:
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

finally:
try:
import uvloop
except ImportError:
pass
else:
asyncio.set_event_loop_policy(original_policy)
yield

finally:
try:
import uvloop
except ImportError:
pass
else:
asyncio.set_event_loop_policy(original_policy)
10 changes: 6 additions & 4 deletions kopf/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def run(
paths=paths,
modules=modules,
)
with loops.proper_loop(__controls.loop):
with loops.proper_loop(suggested_loop=__controls.loop) as actual_loop:
return running.run(
standalone=standalone,
namespaces=namespaces,
Expand All @@ -108,7 +108,7 @@ def run(
stop_flag=__controls.stop_flag,
ready_flag=__controls.ready_flag,
vault=__controls.vault,
loop=__controls.loop,
loop=actual_loop,
)


Expand Down Expand Up @@ -141,13 +141,14 @@ def freeze(
settings = configuration.OperatorSettings()
settings.peering.name = peering_name
settings.peering.priority = priority
with loops.proper_loop(__controls.loop):
with loops.proper_loop(suggested_loop=__controls.loop) as actual_loop:
return running.run(
clusterwide=clusterwide,
namespaces=namespaces,
insights=insights,
identity=identity,
settings=settings,
loop=actual_loop,
_command=peering.touch_command(
insights=insights,
identity=identity,
Expand All @@ -174,13 +175,14 @@ def resume(
insights = references.Insights()
settings = configuration.OperatorSettings()
settings.peering.name = peering_name
with loops.proper_loop(__controls.loop):
with loops.proper_loop(suggested_loop=__controls.loop) as actual_loop:
return running.run(
clusterwide=clusterwide,
namespaces=namespaces,
insights=insights,
identity=identity,
settings=settings,
loop=actual_loop,
_command=peering.touch_command(
insights=insights,
identity=identity,
Expand Down
Loading