potiuk commented on code in PR #72858:
URL: https://github.com/apache/airflow/pull/72858#discussion_r3977380185


##########
airflow-core/src/airflow/cli/cli_parser.py:
##########
@@ -76,6 +104,11 @@
         log.warning("Failed to load CLI commands from providers: %s", e)
         # do not re-raise for the same reason as above
 
+    # Commands registered through a provider "cli" section take precedence 
over the compat loading below
+    provider_command_names = {command.name for command in airflow_commands} - {

Review Comment:
   This set is built once, before both compat loops, and never updated as they 
extend `airflow_commands`. So `_exclude_registered_commands` dedupes against 
provider `cli`-section commands, but not against commands the fallback itself 
just registered.
   
   That reopens the exact failure the helper was added to prevent, one level 
down. With a provider executor whose provider has no `cli` section — the 
population this fallback exists for — plus a custom subclass:
   
   ```ini
   [core]
   executor = 
airflow.providers.celery.executors.celery_executor.CeleryExecutor,my_company.executors.MyCeleryExecutor
   ```
   
   `executors_defined_cli` is empty so neither path is skipped, 
`CeleryExecutor` registers `celery`, and `MyCeleryExecutor` inherits 
`get_cli_commands()` and registers `celery` again — checked against a 
`provider_command_names` that is empty here. The duplicate then trips the check 
at line 178 and raises `CliConflictError` at import time, which takes down 
every `airflow` command, not just the affected one.
   
   Before this PR the loop skipped anything not in `executors_not_defined_cli`, 
so the subclass was never imported and the collision was unreachable.
   
   The tidiest fix is to make the set live rather than a snapshot — add 
`registered_names.add(command.name)` just before `result.append(command)` in 
`_exclude_registered_commands` (line 86). That closes it for the auth-manager 
loop too, which reuses the same set after the executor loop has already 
appended to `airflow_commands`.
   



##########
airflow-core/tests/unit/cli/test_cli_parser.py:
##########
@@ -179,7 +179,7 @@ def test_dynamic_conflict_detection(self, 
mock_cli_command_functions: MagicMock)
 
     @pytest.mark.parametrize(
         "module_pattern",
-        ["airflow.auth.managers", "airflow.executors.executor_loader"],
+        ["airflow.api_fastapi.auth.managers", 
"airflow.executors.base_executor"],

Review Comment:
   Two different changes bundled in one parametrize list, and I'd like to 
separate them.
   
   `airflow.auth.managers` → `airflow.api_fastapi.auth.managers` is a real fix: 
the old module path no longer exists, so that parameter was asserting nothing 
and passing vacuously. Good catch.
   
   `airflow.executors.executor_loader` → `airflow.executors.base_executor` is 
different — it drops the guard #59805 added, because this PR moves 
`ExecutorLoader` to a module-level import. The docstring two lines below still 
says *"cli_parser does not import auth_managers or executor_loader at import 
time"*, so the test now claims coverage it no longer has.
   
   To be fair on the actual impact: I checked, and there is **no** import-cost 
regression. `airflow.cli.cli_config` already pulls 
`airflow.executors.executor_loader` in transitively via `from airflow.jobs.job 
import JobState`, so the module is in `sys.modules` before `cli_parser` runs 
either way. The guard was already weaker than it looks.
   
   Still, keeping that one import lazy where it was costs nothing and keeps the 
guard meaningful for the `AIRFLOW_PACKAGE_NAME` docs-build path, which skips 
the whole provider block. If removing it is deliberate, that's fine — please 
just update the docstring and note the reasoning in the PR description so the 
next person doesn't have to reconstruct it from the diff.
   



##########
airflow-core/src/airflow/cli/cli_parser.py:
##########
@@ -99,40 +132,48 @@
                     component="executors", 
not_defined_cli_dict=str(executors_not_defined_cli)
                 )
             )
-            from airflow.executors.executor_loader import ExecutorLoader
-
-            for executor_name in 
ExecutorLoader.get_executor_names(validate_teams=False):
-                # Skip if the executor already has CLI commands defined via 
the 'cli' section in provider.yaml
-                if executor_name.module_path not in executors_not_defined_cli:
-                    log.debug(
-                        "Skipping loading for '%s' as it is defined in 'cli' 
section.",
-                        executor_name.module_path,
-                    )
-                    continue
-
-                try:
-                    executor, _ = 
ExecutorLoader.import_executor_cls(executor_name)
-                    airflow_commands.extend(executor.get_cli_commands())
-                except Exception:
-                    log.exception("Failed to load CLI commands from executor: 
%s", executor_name)
-                    log.error(
-                        "Ensure all dependencies are met and try again. If 
using a Celery based executor install "
-                        "a 3.3.0+ version of the Celery provider. If using a 
Kubernetes executor, install a "
-                        "7.4.0+ version of the CNCF provider"
+        executors_defined_cli = {

Review Comment:
   Nit: this is the exact complement of `executors_not_defined_cli` built 
immediately above, over the same `providers_manager.executor_without_check` 
iterable — so it walks it a second time and states the same partition twice.
   
   ```python
   executors_defined_cli = {
       executor_name for executor_name, _ in 
providers_manager.executor_without_check
   } - executors_not_defined_cli.keys()
   ```
   
   Same applies to `auth_managers_defined_cli` at line 188. Beyond saving a 
pass, it keeps the two halves from drifting if the membership predicate ever 
changes.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to