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


##########
providers/http/tests/unit/http/triggers/test_http.py:
##########
@@ -36,6 +36,7 @@
     HttpSensorTrigger,
     HttpTrigger,
 )
+from airflow.sdk.execution_time.context import AssetStateStoreAccessors

Review Comment:
   This import is unguarded at module level, but `AssetStateStoreAccessors` 
first shipped in Airflow 3.3.0. `PROVIDERS_COMPATIBILITY_TESTS_MATRIX` runs 
this provider's unit tests against 2.11.1, 3.0.6, 3.1.8 and 3.2.2 as well, so 
on those four the import raises at collection and every test in this file fails 
— not just the new ones.
   
   The Iceberg trigger's tests guard it by importing inside the version-gated 
test instead 
(`providers/apache/iceberg/tests/unit/apache/iceberg/triggers/test_iceberg.py:232`),
 with `AIRFLOW_V_3_3_PLUS` from `tests_common.test_utils.version_compat`. Most 
of the shapes below would also work with a plain `MagicMock()` store, which 
needs no import at all.



##########
providers/http/docs/triggers.rst:
##########
@@ -66,27 +64,17 @@ Here's an example of using the ``HttpEventTrigger`` in an 
``AssetWatcher`` to mo
     }
 
 
-    async def check_github_api_response(response):
+    async def check_github_api_response(response, asset_state_store=None):
         """Determine if a new version of Airflow has been released."""
-        # Convert Variable.get to be asynchronous to be used on the Triggerer
-        get_variable_async = sync_to_async(Variable.get)
-
-        # Retrieve the previous and current release IDs (one from Variables, 
one from response)
-        previous_release_id = await get_variable_async(key="release_id_var", 
default=None)
         data = response.json()
         release_id = str(data["id"])
 
-        if release_id == previous_release_id:
-            return False
-
-        # Parse and persist Airflow release data to be used in the downstream 
Task
-        release_name = data["name"]
-        release_html_url = data["html_url"]
-        set_variable_async = sync_to_async(Variable.set)
-
-        await set_variable_async(key="release_id_var", value=str(release_id))
-        await set_variable_async(key="release_name_var", value=release_name)
-        await set_variable_async(key="release_html_url_var", 
value=release_html_url)
+        if asset_state_store is not None:
+            previous_release_id = asset_state_store.get("release_id", None)

Review Comment:
   `AssetStateStoreAccessor.get`/`.set` do a synchronous 
`SUPERVISOR_COMMS.send(...)` round-trip 
(`task-sdk/src/airflow/sdk/execution_time/context.py:759`), and this callable 
runs on the triggerer's shared event loop — so a user copying this example 
stalls every other trigger in the process on each poll. The accessor's own 
docstring says `aget`/`aset` "await instead of blocking the event loop".
   
   `aget`/`aset` are not in a released version yet (3.3.0/3.3.1 only have the 
blocking API), so the example needs the same shape the Kinesis trigger uses:
   
   ```python
   if hasattr(asset_state_store, "aget"):
       previous_release_id = await asset_state_store.aget("release_id", None)
   else:
       previous_release_id = await asyncio.to_thread(asset_state_store.get, 
"release_id", None)
   ```
   
   Same for the `.set` on line 77.



##########
providers/http/docs/triggers.rst:
##########
@@ -109,10 +97,7 @@ Here's an example of using the ``HttpEventTrigger`` in an 
``AssetWatcher`` to mo
     def check_airflow_releases():
         @task()
         def print_airflow_release_info():
-            # Retrieve and output values persisted from the 
``response_check_path`` function
-            release_name = Variable.get("release_name_var")
-            release_html_url = Variable.get("release_html_url_var")
-            print(f"{release_name} has been released. Check it out at 
{release_html_url}")
+            print("A new Airflow release was detected by the HTTP event 
trigger.")

Review Comment:
   The downstream task no longer demonstrates anything — it prints a fixed 
string, so `check_airflow_releases` is now just scaffolding. The old version 
showed how to get the release name and URL to a downstream task, which is the 
half of the story readers actually need.
   
   Since the state store is reachable from task context too, writing 
`release_name` / `release_html_url` alongside `release_id` in the check and 
reading them back here would keep the example end-to-end.



##########
providers/http/tests/unit/http/triggers/test_http.py:
##########
@@ -388,3 +389,88 @@ async def test_trigger_on_post_with_data(
         assert kwargs["data"] == TEST_DATA
         assert kwargs["json"] is None
         assert kwargs["params"] is None
+
+    @pytest.mark.asyncio
+    @pytest.mark.parametrize(

Review Comment:
   `expected_result` is `True` in all six cases, so that half of the 
parametrize carries no information, and the actual variation is an `if`/`elif` 
chain dispatching on a string id — which is a switch statement wearing a 
parametrize costume.
   
   `AGENTS.md` asks to "use `@pytest.mark.parametrize` for multiple similar 
inputs — consolidate tests that only differ in input/expected values". 
Parametrizing over the callables themselves drops the chain:
   
   ```python
   async def _single_positional(resp):
       return resp == "ok"
   
   
   async def _default_second_arg(resp, threshold=5):
       return resp == "ok" and threshold == 5
   
   
   @pytest.mark.parametrize("check", [_single_positional, _default_second_arg, 
...])
   async def test_run_response_check_callable_shapes(self, event_trigger, 
check):
       ...
   ```
   
   The two shapes that need `mock_store` can close over a module-level 
sentinel, or take it from the fixture.



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