SEPURI-SAI-KRISHNA commented on PR #72171:
URL: https://github.com/apache/airflow/pull/72171#issuecomment-5728553802

   Expanding here on the inline thread about `trigger=` expressions the sweep 
cannot read, since that thread is now outdated and collapses by default.
   
   I checked the two cases reported there and then went through the guard for 
the other cases in the same category instead of fixing only the reported ones.
   
   | `trigger=` expression      | constructions | flagged unreadable | outcome 
before                                         |
   | -------------------------- | ------------: | ------------------ | 
------------------------------------------------------ |
   | `SomeTrigger(...)`         |             1 | no                 | covered  
                                              |
   | `trigger` (bare name)      |             0 | yes                | covered 
through the allowlist                          |
   | `self._trigger`            |             0 | **no**             | silently 
missed                                        |
   | `triggers[kind]`           |             0 | **no**             | silently 
missed                                        |
   | `A() if flag else self._t` |         **1** | **no**             | worse: 
looked covered, but only one branch was checked |
   | `TRIGGERS[kind](x=1)`      |             1 | no                 | recorded 
with an **empty** class name                  |
   
   The fifth row was the main one I wanted to fix. It ends up in `DEFER_SITES`, 
so the site appears in the parametrized test and looks covered, but the 
unreadable branch contributes nothing. Someone looking at the test ids would 
see the file listed and assume it had been checked.
   
   I found the sixth case while doing the sweep. A construction whose callee 
cannot be resolved is still a `Call`, so it was kept. However, 
`PENDING_MIGRATION` and `UNCONFIGURABLE_TRIGGERS` are keyed by class name. An 
unnamed construction can therefore never match either allowlist, and the 
failure would end up saying `defers to  without passing ...`.
   
   I fixed this as you suggested. `trigger_constructions` now returns `None` 
instead of `[]` whenever the expression cannot be resolved. That covers bare 
references, attributes, subscripts, conditionals where either branch is 
unreadable, and calls where the callee cannot be named.
   
   `find_unreadable_defer_sites` now checks for exactly that `None` result 
instead of checking for `ast.Name`. Anything the sweep cannot resolve therefore 
has to be added to `UNREADABLE_DEFER_SITES` or the suite fails. The entries use 
`ast.unparse`, so a future entry shows the actual expression.
   
   I also cleaned up two things while I was there.
   
   The two almost identical walks are now a single `walk_defer_sites()` 
generator that both functions use. This also removes the duplicated 
`self.defer` matching that came up earlier in the review.
   
   The sweep also no longer skips files whose `path.parent.name` is not 
`operators` or `sensors`. `defer` is a `BaseOperator` method, so a site can 
appear anywhere. A nested subpackage would previously have been silently 
skipped. There are no such sites today, so the counts are unchanged: 113 defer 
sites, 44 hand built hook constructions, and one allowlisted `operators/eks.py` 
entry.
   
   `test_unreadable_trigger_expressions_resolve_to_none` is parametrized over 
all eight shapes. Five of the eight fail with the previous implementation, so 
the test is checking the actual gap rather than just exercising the new code.
   
   There are no affected provider sites today. Apart from the allowlisted bare 
name in `operators/eks.py`, the only trigger expressions that are not a plain 
`SomeTrigger(...)` call are the two `EmrContainerTrigger` conditionals in 
`operators/emr.py` and `sensors/emr.py`, where both branches are readable, and 
one `self.trigger_class(...)` in `sensors/bedrock.py`. So this was a latent 
hole in the guard rather than a current gap.
   
   I also checked four related cases and left them unchanged:
   
   * `find_hand_built_hooks` still relies on the callee name ending in `Hook`, 
so a hook created through a variable or `self.hook_class` would not be found. 
That is a limitation of the current heuristic and fixing it would need a 
different approach.
   
   * `find_waiter_triggers()` imports every trigger module, so a partial 
install can turn an `ImportError` into a collection error. This was already 
noted earlier in the review and will go into the prek hook follow up, together 
with changing the exception lists to use relative paths instead of bare 
filenames. There are no colliding basenames today.
   
   * A hook construction using `**kwargs` would report all three parameters as 
missing. That fails loudly rather than passing silently, so it is a false 
positive rather than a hole. There are no such cases today.
   
   * `read_trigger_name` returns the attribute name for a callee like 
`self.trigger_class(...)` in `sensors/bedrock.py`, so that site is recorded as 
`trigger_class` rather than a real class name. It passes today because all 
three parameters are passed there, and a site like that would fail loudly 
rather than silently, so I left it as is.
   
   Finally, `defer()` takes `trigger` as a keyword only argument, so the 
keyword lookup cannot miss a positional argument. That case is safe by 
construction.
   
   ---
   Drafted-by: Claude Opus 5; reviewed by @SEPURI-SAI-KRISHNA before posting
   


-- 
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