Skip to content

Commit

Permalink
Merge pull request #618 from nolar/fix-subhandlers-docs
Browse files Browse the repository at this point in the history
Rename @kopf.on.this → @kopf.subhandler for readability
  • Loading branch information
nolar committed Dec 15, 2020
2 parents 1e517d0 + c698d28 commit d4d09be
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 29 deletions.
12 changes: 6 additions & 6 deletions docs/handlers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -235,24 +235,25 @@ partials (`functools.partial`), or the inner functions in the closures:
- item1
- item2
Sub-handlers can be implemented either imperatively::
Sub-handlers can be implemented either imperatively
(where it requires :doc:`asynchronous handlers <async>` and ``async/await``)::

import functools
import kopf

@kopf.on.create('zalando.org', 'v1', 'kopfexamples')
def create_fn(spec, **_):
async def create_fn(spec, **_):
fns = {}

for item in spec.get('items', []):
fns[item] = functools.partial(handle_item, item=item)

kopf.execute(fns)
await kopf.execute(fns=fns)

def handle_item(item, *, spec, **_):
pass

Or decoratively::
Or declaratively with decorators::

import kopf

Expand All @@ -261,9 +262,8 @@ Or decoratively::

for item in spec.get('items', []):

@kopf.on.this(id=item)
@kopf.subhandler(id=item)
def handle_item(item=item, **_):

pass

Both of these ways are equivalent.
Expand Down
4 changes: 2 additions & 2 deletions docs/idempotence.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Idempotence

Kopf provides tools to make the handlers idempotent.

`kopf.register` function and `kopf.on.this` decorator allow to schedule
arbitrary sub-handlers for the execution in the current cycle.
The `kopf.register` function and the `kopf.subhandler` decorator allow
to schedule arbitrary sub-handlers for the execution in the current cycle.

`kopf.execute` coroutine executes arbitrary sub-handlers
directly in the place of invocation, and returns when all they have succeeded.
Expand Down
2 changes: 1 addition & 1 deletion examples/07-subhandlers/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ def create_fn(spec, **kwargs):

for item in spec.get('items', []):

@kopf.on.this(id=item)
@kopf.subhandler(id=item)
async def create_item_fn(item=item, **kwargs):
print(f"=== Handling creation for {item}. ===")
5 changes: 2 additions & 3 deletions kopf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@
exception,
)
from kopf.on import (
subhandler,
register,
daemon,
timer,
)
from kopf.on import (
register,
)
from kopf.reactor import (
lifecycles, # as a separate name on the public namespace
)
Expand Down
17 changes: 9 additions & 8 deletions kopf/on.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,7 @@ def decorator( # lgtm[py/similar-function]
return decorator


# TODO: find a better name: `@kopf.on.this` is confusing and does not fully
# TODO: match with the `@kopf.on.{cause}` pattern, where cause is create/update/delete.
def this( # lgtm[py/similar-function]
def subhandler( # lgtm[py/similar-function]
*,
id: Optional[str] = None,
errors: Optional[handlers.ErrorsMode] = None,
Expand All @@ -434,7 +432,7 @@ def this( # lgtm[py/similar-function]
when: Optional[callbacks.WhenFilterFn] = None,
) -> ResourceChangingDecorator:
"""
``@kopf.on.this()`` decorator for the dynamically generated sub-handlers.
``@kopf.subhandler()`` decorator for the dynamically generated sub-handlers.
Can be used only inside of the handler function.
It is efficiently a syntax sugar to look like all other handlers::
Expand All @@ -444,9 +442,8 @@ def create(*, spec, **kwargs):
for task in spec.get('tasks', []):
@kopf.on.this(id=f'task_{task}')
@kopf.subhandler(id=f'task_{task}')
def create_task(*, spec, task=task, **kwargs):
pass
In this example, having spec.tasks set to ``[abc, def]``, this will create
Expand Down Expand Up @@ -517,18 +514,22 @@ def create_single_task(task=task, **_):
def create_it(spec, **kwargs):
for task in spec.get('tasks', []):
@kopf.on.this(id=task)
@kopf.subhandler(id=task)
def create_single_task(task=task, **_):
pass
"""
decorator = this(
decorator = subhandler(
id=id, registry=registry,
errors=errors, timeout=timeout, retries=retries, backoff=backoff, cooldown=cooldown,
labels=labels, annotations=annotations, when=when,
)
return decorator(fn)


# DEPRECATED: for backward compatibility, the original name of @kopf.on.this() is kept.
this = subhandler


def _warn_deprecated_signatures(
fn: Callable[..., Any],
) -> None:
Expand Down
10 changes: 5 additions & 5 deletions kopf/reactor/handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class HandlerChildrenRetry(TemporaryError):


# The task-local context; propagated down the stack instead of multiple kwargs.
# Used in `@kopf.on.this` and `kopf.execute()` to add/get the sub-handlers.
# Used in `@kopf.subhandler` and `kopf.execute()` to add/get the sub-handlers.
sublifecycle_var: ContextVar[Optional[lifecycles.LifeCycleFn]] = ContextVar('sublifecycle_var')
subregistry_var: ContextVar[registries.ResourceChangingRegistry] = ContextVar('subregistry_var')
subsettings_var: ContextVar[configuration.OperatorSettings] = ContextVar('subsettings_var')
Expand All @@ -77,7 +77,7 @@ async def execute(
If no explicit functions or handlers or registry are passed,
the sub-handlers of the current handler are assumed, as accumulated
in the per-handler registry with ``@kopf.on.this``.
in the per-handler registry with ``@kopf.subhandler``.
If the call to this method for the sub-handlers is not done explicitly
in the handler, it is done implicitly after the handler is exited.
Expand Down Expand Up @@ -137,7 +137,7 @@ async def execute(
elif subexecuted_var.get():
return

# If no explicit args were passed, implicitly use the accumulated handlers from `@kopf.on.this`.
# If no explicit args were passed, use the accumulated handlers from `@kopf.subhandler`.
else:
subexecuted_var.set(True)
subregistry = subregistry_var.get()
Expand Down Expand Up @@ -336,7 +336,7 @@ async def invoke_handler(
Ensure the global context for this asyncio task is set to the handler and
its cause -- for proper population of the sub-handlers via the decorators
(see `@kopf.on.this`).
(see `@kopf.subhandler`).
"""

# For the field-handlers, the old/new/diff values must match the field, not the whole object.
Expand All @@ -349,7 +349,7 @@ async def invoke_handler(
diff = diffs.reduce(cause.diff, handler.field)
cause = causation.enrich_cause(cause=cause, old=old, new=new, diff=diff)

# Store the context of the current resource-object-event-handler, to be used in `@kopf.on.this`,
# Store the context of the current handler, to be used in `@kopf.subhandler`,
# and maybe other places, and consumed in the recursive `execute()` calls for the children.
# This replaces the multiple kwargs passing through the whole call stack (easy to forget).
with invocation.context([
Expand Down
4 changes: 2 additions & 2 deletions tests/registries/test_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ def test_subhandler_fails_with_no_parent_handler():

# Check the actual behaviour of the decorator.
with pytest.raises(LookupError):
@kopf.on.this()
@kopf.subhandler()
def fn(**_):
pass

Expand All @@ -437,7 +437,7 @@ def test_subhandler_declaratively(parent_handler, cause_factory):
subregistry_var.set(registry)

with context([(handler_var, parent_handler)]):
@kopf.on.this()
@kopf.subhandler()
def fn(**_):
pass

Expand Down
4 changes: 2 additions & 2 deletions tests/registries/test_subhandlers_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def test_with_no_parent(
registry = resource_registry_cls()

with context([(handler_var, None)]):
kopf.on.this(registry=registry)(child_fn)
kopf.subhandler(registry=registry)(child_fn)

handlers = registry.get_handlers(cause)
assert len(handlers) == 1
Expand All @@ -30,7 +30,7 @@ def test_with_parent(
registry = resource_registry_cls()

with context([(handler_var, parent_handler)]):
kopf.on.this(registry=registry)(child_fn)
kopf.subhandler(registry=registry)(child_fn)

handlers = registry.get_handlers(cause)
assert len(handlers) == 1
Expand Down

0 comments on commit d4d09be

Please sign in to comment.