Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Workers and API servers deploy independently, so backward compatibility is criti
3. Regenerate Task SDK models:

```bash
cd task-sdk && python dev/generate_task_sdk_models.py
uv run --active --group codegen --project apache-airflow-task-sdk --directory task-sdk -s dev/generate_task_sdk_models.py
```

4. Add tests for both the new and previous API versions.
Expand Down Expand Up @@ -44,7 +44,7 @@ Adding a new Execution API feature touches multiple packages. All of these must
5. **Task SDK client** — add the client method in `task-sdk/src/airflow/sdk/api/client.py`.
6. **Supervisor** — handle the new message in `task-sdk/src/airflow/sdk/execution_time/supervisor.py`.
7. **Dag processor & triggerer exclusions** — these use `InProcessExecutionAPI` and have explicit message type unions. Add new types to their handler or exclusion lists in `airflow/dag_processing/processor.py` and `airflow/jobs/triggerer_job_runner.py`.
8. **Regenerate models** — `cd task-sdk && python dev/generate_task_sdk_models.py`.
8. **Regenerate models** — `uv run --active --group codegen --project apache-airflow-task-sdk --directory task-sdk -s dev/generate_task_sdk_models.py`.
9. **Tests** — if the new message type requires an API endpoint, add tests in all of these:
- `airflow-core/tests/unit/api_fastapi/execution_api/` — endpoint tests
- `task-sdk/tests/task_sdk/api/test_client.py` — client method tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def mock_get_connection(conn_id):
host=conn.host,
login=conn.login,
password=conn.password,
schema_=conn.schema,
schema=conn.schema,
port=conn.port,
extra=conn.extra,
)
Expand Down
8 changes: 8 additions & 0 deletions airflow-core/tests/unit/dag_processing/test_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2167,6 +2167,10 @@ def test_handle_request_get_connection_masks_password_and_extra(self, proc):
conn_type="mysql",
password="super-secret-password",
extra='{"api_key":"super-secret-extra"}',
host=None,
schema=None,
login=None,
port=None,
)

with (
Expand Down Expand Up @@ -2197,6 +2201,10 @@ def test_handle_request_get_connection_masks_password_and_extra(self, proc):
"conn_type": "mysql",
"password": "super-secret-password",
"extra": '{"api_key":"super-secret-extra"}',
"host": None,
"schema": None,
"login": None,
"port": None,
"type": "ConnectionResult",
}

Expand Down
2 changes: 1 addition & 1 deletion airflow-ctl/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ dev = [
"apache-airflow-devel-common",
]
codegen = [
"datamodel-code-generator[http]==0.33.0",
"datamodel-code-generator[http]>=0.71.0",
"apache-airflow-devel-common"
]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# generated by datamodel-codegen:
# filename: v2-simple-auth-manager-generated.yaml
# version: 0.33.0
# version: 0.71.0

from __future__ import annotations

Expand Down
379 changes: 188 additions & 191 deletions airflow-ctl/src/airflowctl/api/datamodels/generated.py

Large diffs are not rendered by default.

65 changes: 56 additions & 9 deletions airflow-ctl/tests/airflow_ctl/api/test_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,11 @@ class TestAssetsOperations:
)

dag_run_response = DAGRunResponse(
duration=None,
triggering_user_name=None,
bundle_version=None,
partition_key=None,
partition_date=None,
dag_display_name=dag_id,
dag_run_id=dag_id,
dag_id=dag_id,
Expand All @@ -296,6 +301,7 @@ class TestAssetsOperations:
note=None,
dag_versions=[
DagVersionResponse(
bundle_url=None,
id=uuid.uuid4(),
version_number=1,
dag_id=dag_id,
Expand Down Expand Up @@ -655,15 +661,17 @@ class TestConnectionsOperations:
)

connection_response = ConnectionResponse(
description=None,
team_name=None,
connection_id=connection_id,
conn_type=conn_type,
host=host,
schema_=schema_,
schema=schema_,
login=login,
password=password,
port=port,
extra=extra,
)
) # type: ignore[call-arg]

connections_response = ConnectionCollectionResponse(
connections=[connection_response],
Expand All @@ -689,7 +697,9 @@ class TestConnectionsOperations:
def test_get(self):
def handle_request(request: httpx.Request) -> httpx.Response:
assert request.url.path == f"/api/v2/connections/{self.connection_id}"
return httpx.Response(200, json=json.loads(self.connection_response.model_dump_json()))
return httpx.Response(
200, json=json.loads(self.connection_response.model_dump_json(by_alias=True))
)

client = make_api_client(transport=httpx.MockTransport(handle_request))
response = client.connections.get(self.connection_id)
Expand All @@ -698,7 +708,9 @@ def handle_request(request: httpx.Request) -> httpx.Response:
def test_list(self):
def handle_request(request: httpx.Request) -> httpx.Response:
assert request.url.path == "/api/v2/connections"
return httpx.Response(200, json=json.loads(self.connections_response.model_dump_json()))
return httpx.Response(
200, json=json.loads(self.connections_response.model_dump_json(by_alias=True))
)

client = make_api_client(transport=httpx.MockTransport(handle_request))
response = client.connections.list()
Expand All @@ -707,7 +719,9 @@ def handle_request(request: httpx.Request) -> httpx.Response:
def test_create(self):
def handle_request(request: httpx.Request) -> httpx.Response:
assert request.url.path == "/api/v2/connections"
return httpx.Response(200, json=json.loads(self.connection_response.model_dump_json()))
return httpx.Response(
200, json=json.loads(self.connection_response.model_dump_json(by_alias=True))
)

client = make_api_client(transport=httpx.MockTransport(handle_request))
response = client.connections.create(connection=self.connection)
Expand All @@ -729,7 +743,9 @@ def handle_request(request: httpx.Request) -> httpx.Response:
"schema": self.schema_,
}
assert "schema_" not in request_body
return httpx.Response(200, json=json.loads(self.connection_response.model_dump_json()))
return httpx.Response(
200, json=json.loads(self.connection_response.model_dump_json(by_alias=True))
)

client = make_api_client(transport=httpx.MockTransport(handle_request))
response = client.connections.create(connection=connection)
Expand Down Expand Up @@ -775,7 +791,9 @@ def handle_request(request: httpx.Request) -> httpx.Response:
def test_delete(self):
def handle_request(request: httpx.Request) -> httpx.Response:
assert request.url.path == f"/api/v2/connections/{self.connection_id}"
return httpx.Response(200, json=json.loads(self.connection_response.model_dump_json()))
return httpx.Response(
200, json=json.loads(self.connection_response.model_dump_json(by_alias=True))
)

client = make_api_client(transport=httpx.MockTransport(handle_request))
response = client.connections.delete(self.connection_id)
Expand All @@ -784,7 +802,9 @@ def handle_request(request: httpx.Request) -> httpx.Response:
def test_update(self):
def handle_request(request: httpx.Request) -> httpx.Response:
assert request.url.path == f"/api/v2/connections/{self.connection_id}"
return httpx.Response(200, json=json.loads(self.connection_response.model_dump_json()))
return httpx.Response(
200, json=json.loads(self.connection_response.model_dump_json(by_alias=True))
)

client = make_api_client(transport=httpx.MockTransport(handle_request))
response = client.connections.update(connection=self.connection)
Expand Down Expand Up @@ -813,7 +833,9 @@ def handle_request(request: httpx.Request) -> httpx.Response:
"team_name": None,
}
assert "schema_" not in request_body
return httpx.Response(200, json=json.loads(self.connection_response.model_dump_json()))
return httpx.Response(
200, json=json.loads(self.connection_response.model_dump_json(by_alias=True))
)

client = make_api_client(transport=httpx.MockTransport(handle_request))
response = client.connections.update(connection=connection)
Expand Down Expand Up @@ -871,6 +893,9 @@ class TestDagOperations:
dag_id = "dag_id"
dag_display_name = "dag_display_name"
dag_response = DAGResponse(
last_parse_duration=None,
bundle_version=None,
allowed_run_types=None,
dag_id=dag_id,
dag_display_name=dag_display_name,
is_paused=False,
Expand Down Expand Up @@ -901,6 +926,11 @@ class TestDagOperations:
)

dag_details_response = DAGDetailsResponse(
last_parse_duration=None,
bundle_version=None,
allowed_run_types=None,
default_args=None,
latest_dag_version=None,
dag_id=dag_id,
dag_display_name="dag_display_name",
is_paused=False,
Expand Down Expand Up @@ -978,6 +1008,7 @@ class TestDagOperations:
)

dag_version_response = DagVersionResponse(
bundle_url=None,
id=uuid.uuid4(),
version_number=1,
dag_id=dag_id,
Expand Down Expand Up @@ -1011,13 +1042,19 @@ class TestDagOperations:

# DagRun related
trigger_dag_run = TriggerDAGRunPostBody(
logical_date=None,
conf=None,
note=None,
)

dag_id = "dag_id"
dag_run_id = "dag_run_id"
dag_run_response = DAGRunResponse(
duration=None,
triggering_user_name=None,
bundle_version=None,
partition_key=None,
partition_date=None,
dag_display_name=dag_run_id,
dag_run_id=dag_run_id,
dag_id=dag_id,
Expand All @@ -1036,6 +1073,7 @@ class TestDagOperations:
note=None,
dag_versions=[
DagVersionResponse(
bundle_url=None,
id=uuid.uuid4(),
version_number=1,
dag_id=dag_id,
Expand Down Expand Up @@ -1175,6 +1213,11 @@ class TestDagRunOperations:
dag_id = "dag_id"
dag_run_id = "dag_run_id"
dag_run_response = DAGRunResponse(
duration=None,
triggering_user_name=None,
bundle_version=None,
partition_key=None,
partition_date=None,
dag_display_name=dag_run_id,
dag_run_id=dag_run_id,
dag_id=dag_id,
Expand All @@ -1193,6 +1236,7 @@ class TestDagRunOperations:
note=None,
dag_versions=[
DagVersionResponse(
bundle_url=None,
id=uuid.uuid4(),
version_number=1,
dag_id=dag_id,
Expand Down Expand Up @@ -1387,6 +1431,7 @@ class TestPoolsOperations:
]
)
pool_response = PoolResponse(
team_name=None,
name=pool_name,
slots=1,
description="description",
Expand Down Expand Up @@ -1456,6 +1501,7 @@ def handle_request(request: httpx.Request) -> httpx.Response:

class TestProvidersOperations:
provider_response = ProviderResponse(
documentation_url=None,
package_name="package_name",
version="version",
description="description",
Expand Down Expand Up @@ -1487,6 +1533,7 @@ class TestVariablesOperations:
}
)
variable_response = VariableResponse(
team_name=None,
key=key,
value=value,
description=description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ class TestCliConnectionCommands:
port=1234,
extra="{}",
description="Test connection description",
)
schema=None,
team_name=None,
) # type: ignore[call-arg]
],
total_entries=1,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class TestDagCommands:
file_token="file_token",
bundle_name="bundle_name",
is_stale=False,
last_parse_duration=None,
bundle_version=None,
allowed_run_types=None,
)

dag_response_unpaused = DAGResponse(
Expand Down Expand Up @@ -88,6 +91,9 @@ class TestDagCommands:
file_token="file_token",
bundle_name="bundle_name",
is_stale=False,
last_parse_duration=None,
bundle_version=None,
allowed_run_types=None,
)

dag_response_no_schedule = DAGResponse(
Expand Down Expand Up @@ -118,6 +124,9 @@ class TestDagCommands:
file_token="file_token",
bundle_name="bundle_name",
is_stale=False,
last_parse_duration=None,
bundle_version=None,
allowed_run_types=None,
)

def test_pause_dag(self, api_client_maker, monkeypatch):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ class TestCliVariableCommands:
variable_collection_response = VariableCollectionResponse(
variables=[
VariableResponse(
key=key,
value=value,
description=description,
is_encrypted=False,
key=key, value=value, description=description, is_encrypted=False, team_name=None
),
],
total_entries=1,
Expand Down
3 changes: 3 additions & 0 deletions devel-common/src/tests_common/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2818,6 +2818,9 @@ def _create_task_instance(
"run_after": run_after, # type: ignore
"conf": conf,
"consumed_asset_events": [],
# Nullable-but-required in the generated schema, so they must be
# passed explicitly; guarded for older Task SDKs that lack them.
**{f: None for f in ("end_date", "partition_key") if f in DagRun.model_fields},
**({"state": DagRunState.RUNNING} if "state" in DagRun.model_fields else {}),
}
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,12 @@ def test_user_agent_dag_run_key_is_hashed_correctly(
mock_supervisor_comms.send.return_value = ConnectionResult(
conn_id="aws_default",
conn_type="aws",
host=None,
schema=None,
login=None,
password=None,
port=None,
extra=None,
)
with mock.patch.dict(os.environ, env_var, clear=True):
dag_run_key = self.fetch_tags()["DagRunKey"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1289,9 +1289,17 @@ def _create_listener_and_task_instance(
"run_type": DagRunType.MANUAL,
"run_after": timezone.datetime(2023, 1, 3, 13, 1, 1),
"consumed_asset_events": [],
**(
{"state": SdkDagRunState.RUNNING} if "state" in SdkDagRun.model_fields else {}
),
# Nullable-but-required on newer SDKs, absent on older ones.
**{
field: value
for field, value in (
("state", SdkDagRunState.RUNNING),
("data_interval_start", None),
("data_interval_end", None),
("partition_key", None),
)
if field in SdkDagRun.model_fields
},
}
),
task_reschedule_count=0,
Expand Down
2 changes: 1 addition & 1 deletion task-sdk/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ exclude_also = [

[dependency-groups]
codegen = [
"datamodel-code-generator[http]==0.33.0",
"datamodel-code-generator[http]>=0.71.0",
"openapi-spec-validator>=0.7.1",
"svcs>=25.1.0",
"rich>=13.6.0",
Expand Down
Loading