From db650bd951466015483b48c264f4c95bc307057a Mon Sep 17 00:00:00 2001 From: Takashi Ono Date: Wed, 8 Apr 2026 16:43:13 +0900 Subject: [PATCH 1/2] [python] Add buildSystem option to support hatchling as build backend Allow users to choose between setuptools (default) and hatchling as the build system in generated pyproject.toml files. The buildSystem option can be set to 'hatchling' to generate projects using hatchling instead of setuptools. - Add BUILD_SYSTEM constant and CLI option to PythonClientCodegen - Update pyproject.mustache template to conditionally use hatchling or setuptools - Add tests to verify both buildSystem configurations work correctly - Update python generator documentation with buildSystem option Co-Authored-By: Claude Haiku 4.5 --- docs/generators/python.md | 1 + .../languages/PythonClientCodegen.java | 9 ++++ .../main/resources/python/pyproject.mustache | 7 +++- .../python/PythonClientCodegenTest.java | 41 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/docs/generators/python.md b/docs/generators/python.md index 791bc88a5a50..bc3a0feb7b83 100644 --- a/docs/generators/python.md +++ b/docs/generators/python.md @@ -19,6 +19,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl | Option | Description | Values | Default | | ------ | ----------- | ------ | ------- | +|buildSystem|Build system to use in pyproject.toml (setuptools, hatchling).| |setuptools| |dateFormat|date format for query parameters| |%Y-%m-%d| |datetimeFormat|datetime format for query parameters| |%Y-%m-%dT%H:%M:%S%z| |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| 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 e26d5ff71c3a..0a02a1265526 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 @@ -49,6 +49,7 @@ public class PythonClientCodegen extends AbstractPythonCodegen implements Codege public static final String SET_ENSURE_ASCII_TO_FALSE = "setEnsureAsciiToFalse"; public static final String POETRY1_FALLBACK = "poetry1"; public static final String LAZY_IMPORTS = "lazyImports"; + public static final String BUILD_SYSTEM = "buildSystem"; @Setter protected String packageUrl; protected String apiDocPath = "docs/"; @@ -153,6 +154,7 @@ public PythonClientCodegen() { cliOptions.add(new CliOption(CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP_DESC).defaultValue("false")); cliOptions.add(new CliOption(POETRY1_FALLBACK, "Fallback to formatting pyproject.toml to Poetry 1.x format.")); cliOptions.add(new CliOption(LAZY_IMPORTS, "Enable lazy imports.").defaultValue(Boolean.FALSE.toString())); + cliOptions.add(new CliOption(BUILD_SYSTEM, "Build system to use in pyproject.toml (setuptools, hatchling).").defaultValue("setuptools")); supportedLibraries.put("urllib3", "urllib3-based client"); supportedLibraries.put("asyncio", "asyncio-based client"); @@ -271,6 +273,13 @@ public void processOpts() { additionalProperties.put(LAZY_IMPORTS, Boolean.valueOf(additionalProperties.get(LAZY_IMPORTS).toString())); } + if (additionalProperties.containsKey(BUILD_SYSTEM)) { + String buildSystem = (String) additionalProperties.get(BUILD_SYSTEM); + if ("hatchling".equals(buildSystem)) { + additionalProperties.put("hatchling", true); + } + } + String modelPath = packagePath() + File.separatorChar + modelPackage.replace('.', File.separatorChar); String apiPath = packagePath() + File.separatorChar + apiPackage.replace('.', File.separatorChar); diff --git a/modules/openapi-generator/src/main/resources/python/pyproject.mustache b/modules/openapi-generator/src/main/resources/python/pyproject.mustache index c6d5328337d7..578e2c796706 100644 --- a/modules/openapi-generator/src/main/resources/python/pyproject.mustache +++ b/modules/openapi-generator/src/main/resources/python/pyproject.mustache @@ -108,10 +108,15 @@ flake8 = ">= 4.0.0" types-python-dateutil = ">= 2.8.19.14" mypy = ">= 1.5" - [build-system] +{{#hatchling}} +requires = ["hatchling"] +build-backend = "hatchling.build" +{{/hatchling}} +{{^hatchling}} requires = ["setuptools"] build-backend = "setuptools.build_meta" +{{/hatchling}} [tool.pylint.'MESSAGES CONTROL'] extension-pkg-whitelist = "pydantic" 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 0ec48cfb7072..f5bc24393993 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 @@ -670,6 +670,47 @@ public void testUuidWithPatternImportsFieldValidator() throws IOException { assertFileContains(p, "from pydantic import BaseModel, ConfigDict, field_validator"); } + @Test(description = "Verify default buildSystem uses setuptools") + public void testDefaultBuildSystemSetuptools() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("python") + .setInputSpec("src/test/resources/bugs/issue_21619.yaml") + .setOutputDir(output.getAbsolutePath()); + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + Path pyprojectPath = Paths.get(output.getAbsolutePath(), "pyproject.toml"); + TestUtils.assertFileExists(pyprojectPath); + TestUtils.assertFileContains(pyprojectPath, "requires = [\"setuptools\"]"); + TestUtils.assertFileContains(pyprojectPath, "build-backend = \"setuptools.build_meta\""); + } + + @Test(description = "Verify buildSystem=hatchling uses hatchling") + public void testBuildSystemHatchling() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("python") + .setInputSpec("src/test/resources/bugs/issue_21619.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty("buildSystem", "hatchling"); + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + Path pyprojectPath = Paths.get(output.getAbsolutePath(), "pyproject.toml"); + TestUtils.assertFileExists(pyprojectPath); + TestUtils.assertFileContains(pyprojectPath, "requires = [\"hatchling\"]"); + TestUtils.assertFileContains(pyprojectPath, "build-backend = \"hatchling.build\""); + } + @Test(description = "Verify non-poetry1 mode uses object notation for license") public void testNonPoetry1LicenseFormat() throws IOException { File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); From ec7220fb177c3353b293c99e9bc4e60342d9731f Mon Sep 17 00:00:00 2001 From: Takashi Ono Date: Wed, 8 Apr 2026 22:12:31 +0900 Subject: [PATCH 2/2] fix: diff in bin/generate-samples.sh --- .../src/main/resources/python/pyproject.mustache | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/openapi-generator/src/main/resources/python/pyproject.mustache b/modules/openapi-generator/src/main/resources/python/pyproject.mustache index 578e2c796706..315d750bacd8 100644 --- a/modules/openapi-generator/src/main/resources/python/pyproject.mustache +++ b/modules/openapi-generator/src/main/resources/python/pyproject.mustache @@ -108,6 +108,7 @@ flake8 = ">= 4.0.0" types-python-dateutil = ">= 2.8.19.14" mypy = ">= 1.5" + [build-system] {{#hatchling}} requires = ["hatchling"]