diff --git a/CHANGELOG.md b/CHANGELOG.md index ed62a40..e482fad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,13 @@ under the License. --> + +# v3.2.1 + +## Bug Fixes: + + - Fix: use Dag form when materializing asset ([#64211](https://github.com/apache/airflow/pull/64211)) + # v3.2.0 ## New Features: diff --git a/airflow_client/client/__init__.py b/airflow_client/client/__init__.py index da267df..50a6230 100644 --- a/airflow_client/client/__init__.py +++ b/airflow_client/client/__init__.py @@ -14,7 +14,7 @@ """ # noqa: E501 -__version__ = "3.2.0" +__version__ = "3.2.1" # Define package exports __all__ = [ @@ -157,6 +157,7 @@ "JobResponse", "LastAssetEventResponse", "LocationInner", + "MaterializeAssetBody", "PatchTaskInstanceBody", "PluginCollectionResponse", "PluginImportErrorCollectionResponse", @@ -352,6 +353,7 @@ from airflow_client.client.models.job_response import JobResponse as JobResponse from airflow_client.client.models.last_asset_event_response import LastAssetEventResponse as LastAssetEventResponse from airflow_client.client.models.location_inner import LocationInner as LocationInner +from airflow_client.client.models.materialize_asset_body import MaterializeAssetBody as MaterializeAssetBody from airflow_client.client.models.patch_task_instance_body import PatchTaskInstanceBody as PatchTaskInstanceBody from airflow_client.client.models.plugin_collection_response import PluginCollectionResponse as PluginCollectionResponse from airflow_client.client.models.plugin_import_error_collection_response import PluginImportErrorCollectionResponse as PluginImportErrorCollectionResponse diff --git a/airflow_client/client/api/asset_api.py b/airflow_client/client/api/asset_api.py index b1bfd5f..2c4b3e9 100644 --- a/airflow_client/client/api/asset_api.py +++ b/airflow_client/client/api/asset_api.py @@ -26,6 +26,7 @@ from airflow_client.client.models.asset_response import AssetResponse from airflow_client.client.models.create_asset_events_body import CreateAssetEventsBody from airflow_client.client.models.dag_run_response import DAGRunResponse +from airflow_client.client.models.materialize_asset_body import MaterializeAssetBody from airflow_client.client.models.queued_event_collection_response import QueuedEventCollectionResponse from airflow_client.client.models.queued_event_response import QueuedEventResponse @@ -3884,6 +3885,7 @@ def _get_dag_asset_queued_events_serialize( def materialize_asset( self, asset_id: StrictInt, + materialize_asset_body: Optional[MaterializeAssetBody] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3903,6 +3905,8 @@ def materialize_asset( :param asset_id: (required) :type asset_id: int + :param materialize_asset_body: + :type materialize_asset_body: MaterializeAssetBody :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -3927,6 +3931,7 @@ def materialize_asset( _param = self._materialize_asset_serialize( asset_id=asset_id, + materialize_asset_body=materialize_asset_body, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -3957,6 +3962,7 @@ def materialize_asset( def materialize_asset_with_http_info( self, asset_id: StrictInt, + materialize_asset_body: Optional[MaterializeAssetBody] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -3976,6 +3982,8 @@ def materialize_asset_with_http_info( :param asset_id: (required) :type asset_id: int + :param materialize_asset_body: + :type materialize_asset_body: MaterializeAssetBody :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -4000,6 +4008,7 @@ def materialize_asset_with_http_info( _param = self._materialize_asset_serialize( asset_id=asset_id, + materialize_asset_body=materialize_asset_body, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -4030,6 +4039,7 @@ def materialize_asset_with_http_info( def materialize_asset_without_preload_content( self, asset_id: StrictInt, + materialize_asset_body: Optional[MaterializeAssetBody] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -4049,6 +4059,8 @@ def materialize_asset_without_preload_content( :param asset_id: (required) :type asset_id: int + :param materialize_asset_body: + :type materialize_asset_body: MaterializeAssetBody :param _request_timeout: timeout setting for this request. If one number provided, it will be total request timeout. It can also be a pair (tuple) of @@ -4073,6 +4085,7 @@ def materialize_asset_without_preload_content( _param = self._materialize_asset_serialize( asset_id=asset_id, + materialize_asset_body=materialize_asset_body, _request_auth=_request_auth, _content_type=_content_type, _headers=_headers, @@ -4098,6 +4111,7 @@ def materialize_asset_without_preload_content( def _materialize_asset_serialize( self, asset_id, + materialize_asset_body, _request_auth, _content_type, _headers, @@ -4125,6 +4139,8 @@ def _materialize_asset_serialize( # process the header parameters # process the form parameters # process the body parameter + if materialize_asset_body is not None: + _body_params = materialize_asset_body # set the HTTP header `Accept` @@ -4135,6 +4151,19 @@ def _materialize_asset_serialize( ] ) + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type # authentication setting _auth_settings: List[str] = [ diff --git a/airflow_client/client/api_client.py b/airflow_client/client/api_client.py index 80e5ccf..a1e8a00 100644 --- a/airflow_client/client/api_client.py +++ b/airflow_client/client/api_client.py @@ -91,7 +91,7 @@ def __init__( self.default_headers[header_name] = header_value self.cookie = cookie # Set default User-Agent. - self.user_agent = 'OpenAPI-Generator/3.2.0/python' + self.user_agent = 'OpenAPI-Generator/3.2.1/python' self.client_side_validation = configuration.client_side_validation def __enter__(self): diff --git a/airflow_client/client/configuration.py b/airflow_client/client/configuration.py index 4e7e4ec..4723793 100644 --- a/airflow_client/client/configuration.py +++ b/airflow_client/client/configuration.py @@ -541,7 +541,7 @@ def to_debug_report(self) -> str: "OS: {env}\n"\ "Python Version: {pyversion}\n"\ "Version of the API: 2\n"\ - "SDK Package Version: 3.2.0".\ + "SDK Package Version: 3.2.1".\ format(env=sys.platform, pyversion=sys.version) def get_host_settings(self) -> List[HostSetting]: diff --git a/airflow_client/client/models/__init__.py b/airflow_client/client/models/__init__.py index 38a35f4..4262e20 100644 --- a/airflow_client/client/models/__init__.py +++ b/airflow_client/client/models/__init__.py @@ -117,6 +117,7 @@ from airflow_client.client.models.job_response import JobResponse from airflow_client.client.models.last_asset_event_response import LastAssetEventResponse from airflow_client.client.models.location_inner import LocationInner +from airflow_client.client.models.materialize_asset_body import MaterializeAssetBody from airflow_client.client.models.patch_task_instance_body import PatchTaskInstanceBody from airflow_client.client.models.plugin_collection_response import PluginCollectionResponse from airflow_client.client.models.plugin_import_error_collection_response import PluginImportErrorCollectionResponse diff --git a/airflow_client/client/models/materialize_asset_body.py b/airflow_client/client/models/materialize_asset_body.py new file mode 100644 index 0000000..a244690 --- /dev/null +++ b/airflow_client/client/models/materialize_asset_body.py @@ -0,0 +1,116 @@ +# coding: utf-8 + +""" + Airflow API + + Airflow API. All endpoints located under ``/api/v2`` can be used safely, are stable and backward compatible. Endpoints located under ``/ui`` are dedicated to the UI and are subject to breaking change depending on the need of the frontend. Users should not rely on those but use the public ones instead. + + The version of the OpenAPI document: 2 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from datetime import datetime +from pydantic import BaseModel, ConfigDict, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from typing import Optional, Set +from typing_extensions import Self +from pydantic_core import to_jsonable_python + +class MaterializeAssetBody(BaseModel): + """ + Materialize asset request. + """ # noqa: E501 + conf: Optional[Dict[str, Any]] = None + dag_run_id: Optional[StrictStr] = None + data_interval_end: Optional[datetime] = None + data_interval_start: Optional[datetime] = None + logical_date: Optional[datetime] = None + note: Optional[StrictStr] = None + partition_key: Optional[StrictStr] = None + run_after: Optional[datetime] = None + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["conf", "dag_run_id", "data_interval_end", "data_interval_start", "logical_date", "note", "partition_key", "run_after"] + + model_config = ConfigDict( + validate_by_name=True, + validate_by_alias=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + return json.dumps(to_jsonable_python(self.to_dict())) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of MaterializeAssetBody from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of MaterializeAssetBody from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "conf": obj.get("conf"), + "dag_run_id": obj.get("dag_run_id"), + "data_interval_end": obj.get("data_interval_end"), + "data_interval_start": obj.get("data_interval_start"), + "logical_date": obj.get("logical_date"), + "note": obj.get("note"), + "partition_key": obj.get("partition_key"), + "run_after": obj.get("run_after") + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + + diff --git a/docs/AssetApi.md b/docs/AssetApi.md index 2319423..827680b 100644 --- a/docs/AssetApi.md +++ b/docs/AssetApi.md @@ -1087,7 +1087,7 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) # **materialize_asset** -> DAGRunResponse materialize_asset(asset_id) +> DAGRunResponse materialize_asset(asset_id, materialize_asset_body=materialize_asset_body) Materialize Asset @@ -1101,6 +1101,7 @@ Materialize an asset by triggering a DAG run that produces it. ```python import airflow_client.client from airflow_client.client.models.dag_run_response import DAGRunResponse +from airflow_client.client.models.materialize_asset_body import MaterializeAssetBody from airflow_client.client.rest import ApiException from pprint import pprint @@ -1127,10 +1128,11 @@ with airflow_client.client.ApiClient(configuration) as api_client: # Create an instance of the API class api_instance = airflow_client.client.AssetApi(api_client) asset_id = 56 # int | + materialize_asset_body = airflow_client.client.MaterializeAssetBody() # MaterializeAssetBody | (optional) try: # Materialize Asset - api_response = api_instance.materialize_asset(asset_id) + api_response = api_instance.materialize_asset(asset_id, materialize_asset_body=materialize_asset_body) print("The response of AssetApi->materialize_asset:\n") pprint(api_response) except Exception as e: @@ -1145,6 +1147,7 @@ with airflow_client.client.ApiClient(configuration) as api_client: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **asset_id** | **int**| | + **materialize_asset_body** | [**MaterializeAssetBody**](MaterializeAssetBody.md)| | [optional] ### Return type @@ -1156,7 +1159,7 @@ Name | Type | Description | Notes ### HTTP request headers - - **Content-Type**: Not defined + - **Content-Type**: application/json - **Accept**: application/json ### HTTP response details diff --git a/docs/MaterializeAssetBody.md b/docs/MaterializeAssetBody.md new file mode 100644 index 0000000..240a33e --- /dev/null +++ b/docs/MaterializeAssetBody.md @@ -0,0 +1,37 @@ +# MaterializeAssetBody + +Materialize asset request. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**conf** | **Dict[str, object]** | | [optional] +**dag_run_id** | **str** | | [optional] +**data_interval_end** | **datetime** | | [optional] +**data_interval_start** | **datetime** | | [optional] +**logical_date** | **datetime** | | [optional] +**note** | **str** | | [optional] +**partition_key** | **str** | | [optional] +**run_after** | **datetime** | | [optional] + +## Example + +```python +from airflow_client.client.models.materialize_asset_body import MaterializeAssetBody + +# TODO update the JSON string below +json = "{}" +# create an instance of MaterializeAssetBody from a JSON string +materialize_asset_body_instance = MaterializeAssetBody.from_json(json) +# print the JSON string representation of the object +print(MaterializeAssetBody.to_json()) + +# convert the object into a dict +materialize_asset_body_dict = materialize_asset_body_instance.to_dict() +# create an instance of MaterializeAssetBody from a dict +materialize_asset_body_from_dict = MaterializeAssetBody.from_dict(materialize_asset_body_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pyproject.toml b/pyproject.toml index bf9c5cf..ed91dbb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ [build-system] requires = [ "hatchling==1.29.0", - "packaging==26.0", + "packaging==26.1", "pathspec==1.0.4", "pluggy==1.6.0", "tomli==2.4.1; python_version < '3.11'", diff --git a/spec/v2.yaml b/spec/v2.yaml index e4be048..d4fe7bd 100644 --- a/spec/v2.yaml +++ b/spec/v2.yaml @@ -2540,6 +2540,41 @@ components: type: string title: LastAssetEventResponse type: object + MaterializeAssetBody: + additionalProperties: false + description: Materialize asset request. + properties: + conf: + additionalProperties: true + nullable: true + type: object + dag_run_id: + nullable: true + type: string + data_interval_end: + format: date-time + nullable: true + type: string + data_interval_start: + format: date-time + nullable: true + type: string + logical_date: + format: date-time + nullable: true + type: string + note: + nullable: true + type: string + partition_key: + nullable: true + type: string + run_after: + format: date-time + nullable: true + type: string + title: MaterializeAssetBody + type: object PatchTaskInstanceBody: additionalProperties: false description: Request body for Clear Task Instances endpoint. @@ -4525,6 +4560,12 @@ paths: schema: title: Asset Id type: integer + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MaterializeAssetBody' + nullable: true responses: '200': content: diff --git a/test/test_materialize_asset_body.py b/test/test_materialize_asset_body.py new file mode 100644 index 0000000..9204bce --- /dev/null +++ b/test/test_materialize_asset_body.py @@ -0,0 +1,58 @@ +# coding: utf-8 + +""" + Airflow API + + Airflow API. All endpoints located under ``/api/v2`` can be used safely, are stable and backward compatible. Endpoints located under ``/ui`` are dedicated to the UI and are subject to breaking change depending on the need of the frontend. Users should not rely on those but use the public ones instead. + + The version of the OpenAPI document: 2 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from airflow_client.client.models.materialize_asset_body import MaterializeAssetBody + +class TestMaterializeAssetBody(unittest.TestCase): + """MaterializeAssetBody unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> MaterializeAssetBody: + """Test MaterializeAssetBody + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `MaterializeAssetBody` + """ + model = MaterializeAssetBody() + if include_optional: + return MaterializeAssetBody( + conf = { }, + dag_run_id = '', + data_interval_end = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + data_interval_start = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + logical_date = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f'), + note = '', + partition_key = '', + run_after = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f') + ) + else: + return MaterializeAssetBody( + ) + """ + + def testMaterializeAssetBody(self): + """Test MaterializeAssetBody""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/version.txt b/version.txt index 944880f..e4604e3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.2.0 +3.2.1