From 14a5a2d93f79857f293640825aa544dd52da7f36 Mon Sep 17 00:00:00 2001 From: anystubbs Date: Fri, 2 Oct 2026 10:06:32 +0200 Subject: [PATCH 1/2] Make RFC compliance default --- docs/generators/python.md | 2 +- .../languages/PythonClientCodegen.java | 7 ++---- .../src/main/resources/python/api.mustache | 4 +++- .../resources/python/configuration.mustache | 3 ++- .../python/PythonClientCodegenTest.java | 24 +++++++++++++++++++ .../openapi_client/api/query_api.py | 4 +++- .../openapi_client/configuration.py | 3 ++- .../tests/test_manual.py | 2 +- .../python/openapi_client/api/query_api.py | 4 +++- .../python/openapi_client/configuration.py | 3 ++- .../echo_api/python/tests/test_manual.py | 2 +- .../legacy_model_dict_client/configuration.py | 3 ++- .../petstore_api/api/fake_api.py | 4 +++- .../petstore_api/configuration.py | 3 ++- .../petstore_api/api/fake_api.py | 4 +++- .../petstore_api/configuration.py | 3 ++- .../python-httpx/petstore_api/api/fake_api.py | 4 +++- .../petstore_api/configuration.py | 3 ++- .../petstore_api/api/fake_api.py | 4 +++- .../petstore_api/configuration.py | 3 ++- .../petstore_api/api/fake_api.py | 4 +++- .../petstore_api/configuration.py | 3 ++- .../petstore_api/api/fake_api.py | 4 +++- .../petstore_api/configuration.py | 3 ++- .../python/petstore_api/api/fake_api.py | 4 +++- .../python/petstore_api/configuration.py | 3 ++- 26 files changed, 81 insertions(+), 29 deletions(-) diff --git a/docs/generators/python.md b/docs/generators/python.md index 828b94f83cfc..4c6a0868996a 100644 --- a/docs/generators/python.md +++ b/docs/generators/python.md @@ -22,7 +22,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |buildSystem|Build system to use in pyproject.toml (setuptools, hatchling).| |setuptools| |compatibleWithPythonLegacy|Enable compatibility with python-legacy. Currently, generated model field aliases preserve normalized Python constructor names while accepting wire names, and to_dict() emits every declared field, using None for missing attributes, under public names by default and wire names with serialize=True. Generic models expose openapi_types and attribute_map, reject unknown constructor keys, and use legacy display and equality helpers. Container conversion is limited to immediate list elements and dictionary values, matching python-legacy. Synchronous urllib3 operations keep async_req, _preload_content, tuple with_http_info() behavior, and integer _request_timeout inputs. JSON and request serialization remain unchanged.| |false| |dateFormat|date format for query parameters| |%Y-%m-%d| -|datetimeFormat|datetime format for query parameters| |%Y-%m-%dT%H:%M:%S%z| +|datetimeFormat|datetime format for query parameters. If not set, datetime.isoformat() is used, which is RFC 3339 compliant.| |null| |disallowAdditionalPropertiesIfNotPresent|If false, the 'additionalProperties' implementation (set to true by default) is compliant with the OAS and JSON schema specifications. If true (default), keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.|
**false**
The 'additionalProperties' implementation is compliant with the OAS and JSON schema specifications.
**true**
Keep the old (incorrect) behaviour that 'additionalProperties' is set to false by default.
|true| |generateSourceCodeOnly|Specifies that only a library source code is to be generated.| |false| |hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java index 61936225db59..4c248efe2d4e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java @@ -114,7 +114,7 @@ public class PythonClientCodegen extends AbstractPythonCodegen implements Codege protected String apiDocPath = "docs/"; protected String modelDocPath = "docs/"; @Setter protected boolean useOneOfDiscriminatorLookup = false; // use oneOf discriminator's mapping for model lookup - @Setter protected String datetimeFormat = "%Y-%m-%dT%H:%M:%S.%f%z"; + @Setter protected String datetimeFormat = null; @Setter protected String dateFormat = "%Y-%m-%d"; @Setter protected boolean setEnsureAsciiToFalse = false; @Setter protected boolean useIndependentImplicitClients = false; @@ -221,8 +221,7 @@ public PythonClientCodegen() { cliOptions.add(new CliOption(RECURSION_LIMIT, "Set the recursion limit. If not set, use the system default value.")); cliOptions.add(new CliOption(MAP_NUMBER_TO, "Map number to Union[StrictFloat, StrictInt], StrictFloat, float or Decimal.") .defaultValue("Union[StrictFloat, StrictInt]")); - cliOptions.add(new CliOption(DATETIME_FORMAT, "datetime format for query parameters") - .defaultValue("%Y-%m-%dT%H:%M:%S%z")); + cliOptions.add(new CliOption(DATETIME_FORMAT, "datetime format for query parameters. If not set, datetime.isoformat() is used, which is RFC 3339 compliant.")); cliOptions.add(new CliOption(DATE_FORMAT, "date format for query parameters") .defaultValue("%Y-%m-%d")); cliOptions.add(new CliOption(CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP_DESC).defaultValue("false")); @@ -356,8 +355,6 @@ public void processOpts() { if (additionalProperties.containsKey(DATETIME_FORMAT)) { setDatetimeFormat((String) additionalProperties.get(DATETIME_FORMAT)); - } else { - additionalProperties.put(DATETIME_FORMAT, datetimeFormat); } if (additionalProperties.containsKey(DATE_FORMAT)) { diff --git a/modules/openapi-generator/src/main/resources/python/api.mustache b/modules/openapi-generator/src/main/resources/python/api.mustache index 3cee5c88c1b8..a7ef2dfc0e23 100644 --- a/modules/openapi-generator/src/main/resources/python/api.mustache +++ b/modules/openapi-generator/src/main/resources/python/api.mustache @@ -325,7 +325,9 @@ https://github.com/OpenAPITools/openapi-generator/blob/c84b949df1a9ec04ba75989cb _query_params.append( ( '{{baseName}}', - {{paramName}}.strftime( + {{paramName}}.isoformat() + if self.api_client.configuration.datetime_format is None + else {{paramName}}.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/modules/openapi-generator/src/main/resources/python/configuration.mustache b/modules/openapi-generator/src/main/resources/python/configuration.mustache index 920408100449..c05b71a63a7b 100644 --- a/modules/openapi-generator/src/main/resources/python/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python/configuration.mustache @@ -237,6 +237,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. {{#hasAuthMethods}} @@ -373,7 +374,7 @@ conf = {{{packageName}}}.Configuration( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="{{{datetimeFormat}}}", + datetime_format: Optional[str]={{#datetimeFormat}}"{{{.}}}"{{/datetimeFormat}}{{^datetimeFormat}}None{{/datetimeFormat}}, date_format: str="{{{dateFormat}}}", *, debug: Optional[bool] = None, diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java index 7ae88fae560b..3c8718125ffa 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java @@ -128,6 +128,30 @@ public void testHttpx2Generation(boolean sync, Object poetry1, String backend) t Assert.assertFalse(Files.readString(Paths.get(output, "requirements.txt")).contains("httpx >=")); } + @Test + public void testDatetimeQueryParamDefaultsToIsoformat() throws IOException { + final PythonClientCodegen codegen = new PythonClientCodegen(); + final String output = generateFiles(codegen, "src/test/resources/3_0/echo_api.yaml"); + + // strftime's %z renders +0000; RFC 3339 requires +00:00, which isoformat() emits. + assertFileContains(Paths.get(output, "openapi_client/configuration.py"), + "datetime_format: Optional[str]=None,"); + assertFileContains(Paths.get(output, "openapi_client/api/query_api.py"), + "datetime_query.isoformat()", + "if self.api_client.configuration.datetime_format is None"); + Assert.assertNull(codegen.additionalProperties().get(PythonClientCodegen.DATETIME_FORMAT)); + } + + @Test + public void testDatetimeFormatOptionIsStillHonoured() throws IOException { + final PythonClientCodegen codegen = new PythonClientCodegen(); + codegen.additionalProperties().put(PythonClientCodegen.DATETIME_FORMAT, "%Y-%m-%dT%H:%M:%SZ"); + final String output = generateFiles(codegen, "src/test/resources/3_0/echo_api.yaml"); + + assertFileContains(Paths.get(output, "openapi_client/configuration.py"), + "datetime_format: Optional[str]=\"%Y-%m-%dT%H:%M:%SZ\","); + } + @Test public void testInitialConfigValues() throws Exception { final PythonClientCodegen codegen = new PythonClientCodegen(); diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api/query_api.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api/query_api.py index 05837d93cbee..23c22c5edadb 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api/query_api.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/api/query_api.py @@ -573,7 +573,9 @@ def _test_query_datetime_date_string_serialize( _query_params.append( ( 'datetime_query', - datetime_query.strftime( + datetime_query.isoformat() + if self.api_client.configuration.datetime_format is None + else datetime_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py index f2411fe6bd9d..c9778c308367 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py @@ -181,6 +181,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -233,7 +234,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/tests/test_manual.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/tests/test_manual.py index 1a5d0bb4d83f..760fa3a86cf4 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/tests/test_manual.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/tests/test_manual.py @@ -72,7 +72,7 @@ def testDateTimeQueryWithDateTime(self): # Test query parameter(s) api_response = api_instance.test_query_datetime_date_string(datetime_query=datetime_query, date_query=date_query, string_query=string_query) e = EchoServerResponseParser(api_response) - self.assertEqual(e.path, "/query/datetime/date/string?datetime_query=2013-10-20T19%3A20%3A30.000000-0500&date_query=2013-10-20&string_query=string_query_example") + self.assertEqual(e.path, "/query/datetime/date/string?datetime_query=2013-10-20T19%3A20%3A30-05%3A00&date_query=2013-10-20&string_query=string_query_example") def testBinaryGif(self): api_instance = openapi_client.BodyApi() diff --git a/samples/client/echo_api/python/openapi_client/api/query_api.py b/samples/client/echo_api/python/openapi_client/api/query_api.py index 05837d93cbee..23c22c5edadb 100644 --- a/samples/client/echo_api/python/openapi_client/api/query_api.py +++ b/samples/client/echo_api/python/openapi_client/api/query_api.py @@ -573,7 +573,9 @@ def _test_query_datetime_date_string_serialize( _query_params.append( ( 'datetime_query', - datetime_query.strftime( + datetime_query.isoformat() + if self.api_client.configuration.datetime_format is None + else datetime_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/client/echo_api/python/openapi_client/configuration.py b/samples/client/echo_api/python/openapi_client/configuration.py index f2411fe6bd9d..c9778c308367 100644 --- a/samples/client/echo_api/python/openapi_client/configuration.py +++ b/samples/client/echo_api/python/openapi_client/configuration.py @@ -181,6 +181,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -233,7 +234,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/client/echo_api/python/tests/test_manual.py b/samples/client/echo_api/python/tests/test_manual.py index b6d2a30e7c67..faf0a5ab8ed2 100644 --- a/samples/client/echo_api/python/tests/test_manual.py +++ b/samples/client/echo_api/python/tests/test_manual.py @@ -143,7 +143,7 @@ def testDateTimeQueryWithDateTime(self): # Test query parameter(s) api_response = api_instance.test_query_datetime_date_string(datetime_query=datetime_query, date_query=date_query, string_query=string_query) e = EchoServerResponseParser(api_response) - self.assertEqual(e.path, "/query/datetime/date/string?datetime_query=2013-10-20T19%3A20%3A30.000000-0500&date_query=2013-10-20&string_query=string_query_example") + self.assertEqual(e.path, "/query/datetime/date/string?datetime_query=2013-10-20T19%3A20%3A30-05%3A00&date_query=2013-10-20&string_query=string_query_example") def testStringEnum(self): api_instance = openapi_client.BodyApi() diff --git a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py index b99862654f04..45eefd3b6a0c 100644 --- a/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py +++ b/samples/client/others/python-legacy-model-dictionaries/legacy_model_dict_client/configuration.py @@ -178,6 +178,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. """ @@ -213,7 +214,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api/fake_api.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api/fake_api.py index f5034ea9753a..e48a3164b15e 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api/fake_api.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/api/fake_api.py @@ -6777,7 +6777,9 @@ def _test_date_time_query_parameter_serialize( _query_params.append( ( 'date_time_query', - date_time_query.strftime( + date_time_query.isoformat() + if self.api_client.configuration.datetime_format is None + else date_time_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py index 38f5a69aeef3..bb427cc4413d 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py @@ -192,6 +192,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -304,7 +305,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api/fake_api.py b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api/fake_api.py index c22c0ab04bda..80c8a6a0d760 100644 --- a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api/fake_api.py +++ b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/api/fake_api.py @@ -9375,7 +9375,9 @@ def _test_date_time_query_parameter_serialize( _query_params.append( ( 'date_time_query', - date_time_query.strftime( + date_time_query.isoformat() + if self.api_client.configuration.datetime_format is None + else date_time_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py index cefa6fa3a1f9..a9373c0bac0d 100644 --- a/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-httpx-sync/petstore_api/configuration.py @@ -181,6 +181,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -290,7 +291,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/openapi3/client/petstore/python-httpx/petstore_api/api/fake_api.py b/samples/openapi3/client/petstore/python-httpx/petstore_api/api/fake_api.py index 6adfebde84fb..89888949e809 100644 --- a/samples/openapi3/client/petstore/python-httpx/petstore_api/api/fake_api.py +++ b/samples/openapi3/client/petstore/python-httpx/petstore_api/api/fake_api.py @@ -6758,7 +6758,9 @@ def _test_date_time_query_parameter_serialize( _query_params.append( ( 'date_time_query', - date_time_query.strftime( + date_time_query.isoformat() + if self.api_client.configuration.datetime_format is None + else date_time_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py index cefa6fa3a1f9..a9373c0bac0d 100644 --- a/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-httpx/petstore_api/configuration.py @@ -181,6 +181,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -290,7 +291,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/openapi3/client/petstore/python-httpx2-sync/petstore_api/api/fake_api.py b/samples/openapi3/client/petstore/python-httpx2-sync/petstore_api/api/fake_api.py index c22c0ab04bda..80c8a6a0d760 100644 --- a/samples/openapi3/client/petstore/python-httpx2-sync/petstore_api/api/fake_api.py +++ b/samples/openapi3/client/petstore/python-httpx2-sync/petstore_api/api/fake_api.py @@ -9375,7 +9375,9 @@ def _test_date_time_query_parameter_serialize( _query_params.append( ( 'date_time_query', - date_time_query.strftime( + date_time_query.isoformat() + if self.api_client.configuration.datetime_format is None + else date_time_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/openapi3/client/petstore/python-httpx2-sync/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-httpx2-sync/petstore_api/configuration.py index cefa6fa3a1f9..a9373c0bac0d 100644 --- a/samples/openapi3/client/petstore/python-httpx2-sync/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-httpx2-sync/petstore_api/configuration.py @@ -181,6 +181,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -290,7 +291,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/openapi3/client/petstore/python-httpx2/petstore_api/api/fake_api.py b/samples/openapi3/client/petstore/python-httpx2/petstore_api/api/fake_api.py index 6adfebde84fb..89888949e809 100644 --- a/samples/openapi3/client/petstore/python-httpx2/petstore_api/api/fake_api.py +++ b/samples/openapi3/client/petstore/python-httpx2/petstore_api/api/fake_api.py @@ -6758,7 +6758,9 @@ def _test_date_time_query_parameter_serialize( _query_params.append( ( 'date_time_query', - date_time_query.strftime( + date_time_query.isoformat() + if self.api_client.configuration.datetime_format is None + else date_time_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/openapi3/client/petstore/python-httpx2/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-httpx2/petstore_api/configuration.py index cefa6fa3a1f9..a9373c0bac0d 100644 --- a/samples/openapi3/client/petstore/python-httpx2/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-httpx2/petstore_api/configuration.py @@ -181,6 +181,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -290,7 +291,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api/fake_api.py b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api/fake_api.py index feba662440e8..d36a6ce0c038 100644 --- a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api/fake_api.py +++ b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/api/fake_api.py @@ -6778,7 +6778,9 @@ def _test_date_time_query_parameter_serialize( _query_params.append( ( 'date_time_query', - date_time_query.strftime( + date_time_query.isoformat() + if self.api_client.configuration.datetime_format is None + else date_time_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py index 7e9c9d177921..9d89d297283a 100644 --- a/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-lazyImports/petstore_api/configuration.py @@ -187,6 +187,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -298,7 +299,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, diff --git a/samples/openapi3/client/petstore/python/petstore_api/api/fake_api.py b/samples/openapi3/client/petstore/python/petstore_api/api/fake_api.py index 0605972caae5..cdd1e822dbda 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/api/fake_api.py +++ b/samples/openapi3/client/petstore/python/petstore_api/api/fake_api.py @@ -6758,7 +6758,9 @@ def _test_date_time_query_parameter_serialize( _query_params.append( ( 'date_time_query', - date_time_query.strftime( + date_time_query.isoformat() + if self.api_client.configuration.datetime_format is None + else date_time_query.strftime( self.api_client.configuration.datetime_format ) ) diff --git a/samples/openapi3/client/petstore/python/petstore_api/configuration.py b/samples/openapi3/client/petstore/python/petstore_api/configuration.py index 3fdb5641b4d3..ac7d2940a0db 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python/petstore_api/configuration.py @@ -187,6 +187,7 @@ class Configuration: :param client_side_validation: Enable client-side validation. Default True. :param socket_options: Options to pass down to the underlying urllib3 socket. :param datetime_format: Datetime format string for serialization. + If None, datetime.isoformat() is used, which is RFC 3339 compliant. :param date_format: Date format string for serialization. :Example: @@ -298,7 +299,7 @@ def __init__( safe_chars_for_path_param: str='', client_side_validation: bool=True, socket_options: Optional[Any]=None, - datetime_format: str="%Y-%m-%dT%H:%M:%S.%f%z", + datetime_format: Optional[str]=None, date_format: str="%Y-%m-%d", *, debug: Optional[bool] = None, From 6b824c9fe140504c96913d912c1a0e731569b2ab Mon Sep 17 00:00:00 2001 From: anystubbs Date: Fri, 2 Oct 2026 10:09:33 +0200 Subject: [PATCH 2/2] Setter fix --- .../codegen/languages/PythonClientCodegen.java | 2 ++ .../codegen/python/PythonClientCodegenTest.java | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java index 4c248efe2d4e..6c8c4117445f 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java @@ -355,6 +355,8 @@ public void processOpts() { if (additionalProperties.containsKey(DATETIME_FORMAT)) { setDatetimeFormat((String) additionalProperties.get(DATETIME_FORMAT)); + } else if (datetimeFormat != null) { + additionalProperties.put(DATETIME_FORMAT, datetimeFormat); } if (additionalProperties.containsKey(DATE_FORMAT)) { diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java index 3c8718125ffa..93ef33cd40a7 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java @@ -142,6 +142,16 @@ public void testDatetimeQueryParamDefaultsToIsoformat() throws IOException { Assert.assertNull(codegen.additionalProperties().get(PythonClientCodegen.DATETIME_FORMAT)); } + @Test + public void testDatetimeFormatSetterIsStillHonoured() throws IOException { + final PythonClientCodegen codegen = new PythonClientCodegen(); + codegen.setDatetimeFormat("%Y-%m-%dT%H:%M:%SZ"); + final String output = generateFiles(codegen, "src/test/resources/3_0/echo_api.yaml"); + + assertFileContains(Paths.get(output, "openapi_client/configuration.py"), + "datetime_format: Optional[str]=\"%Y-%m-%dT%H:%M:%SZ\","); + } + @Test public void testDatetimeFormatOptionIsStillHonoured() throws IOException { final PythonClientCodegen codegen = new PythonClientCodegen();