Add missing tests for `cncf.kubernetes` script and delete utilities
Description
Two modules in the cncf.kubernetes provider have no dedicated test module, and (unlike most entries on the OVERLOOKED_TESTS list) they are not covered indirectly. Nothing under any providers/*/tests/ directory imports them at all:
| Module | Expected test file |
|---|---|
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/python_kubernetes_script.py |
providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_python_kubernetes_script.py |
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/utils/delete_from.py |
providers/cncf/kubernetes/tests/unit/cncf/kubernetes/utils/test_delete_from.py |
Both are currently suppressed in the OVERLOOKED_TESTS allowlist in airflow-core/tests/unit/always/test_project_structure.py.
This is a scoped subset of the meta issue #35442, limited to the cncf.kubernetes provider.
What should these tests cover?
python_kubernetes_script.py backs the @task.kubernetes decorator. remove_task_decorator does string surgery on user source, stripping @setup, @teardown and the task decorator itself, with _balance_parens walking nested parentheses to find where a parameterised decorator ends. That is easy to break and the failure mode is silently corrupted user code, so it is worth covering directly:
- a decorator with no arguments, with arguments, and with nested parentheses inside the arguments
- source carrying
@setupand@teardownalongside the task decorator - source where the decorator name never appears, which should return the input unchanged
write_python_scriptrendering the Jinja template to the target file, includingrender_template_as_native_obj=TrueselectingNativeEnvironment, andStrictUndefinedraising on a missing context variable
While writing these it is worth pinning the current behaviour of the inner _remove_task_decorator, which reads python_source from the enclosing scope rather than its own py_source argument. The two happen to be the same object on every iteration of the loop that calls it, so the result is correct today, but nothing stops that from silently changing.
delete_from.py is vendored from kubernetes_asyncio and mirrors the upstream create_from_yaml helpers. Worth covering:
- the API class name derivation in
_delete_from_yaml_single_itemfromapiVersion, covering the core group, a named group,.k8s.iostripping, and DNS subdomain to CamelCase conversion - the kind conversion from CamelCase to snake_case
- namespaced versus non namespaced dispatch, meaning
delete_namespaced_<kind>when the API exposes it anddelete_<kind>otherwise - a
namespacein the document metadata taking precedence over thenamespaceargument, which the code calls out explicitly Listkinds fanning out overitemsand inheritingapiVersionfrom the parent documentApiExceptions being collected rather than raised eagerly, then surfaced together asFailToDeleteError, plus theFailToDeleteError.__str__formatting
These can all be driven with mocked kubernetes.client API classes using autospec, so no cluster is required.
Definition of Done
- Add the two test modules at the paths in the table above.
- Remove the two corresponding entries from
OVERLOOKED_TESTSinairflow-core/tests/unit/always/test_project_structure.py - Both of these tests should pass:
breeze testing providers-tests providers/cncf/kubernetes/tests/unit/cncf/kubernetes/test_python_kubernetes_script.py
breeze testing providers-tests providers/cncf/kubernetes/tests/unit/cncf/kubernetes/utils/test_delete_from.py
Drafted-by: Claude Code (Opus 5); reviewed and edited by @jroachgolf84 before posting.
Source: apache/airflow