|
1 | 1 | package org.openapitools.codegen.python; |
2 | 2 |
|
3 | 3 | import com.google.common.collect.ImmutableMap; |
| 4 | +import io.swagger.parser.OpenAPIParser; |
| 5 | +import io.swagger.v3.oas.models.OpenAPI; |
| 6 | +import io.swagger.v3.oas.models.parameters.Parameter; |
| 7 | +import io.swagger.v3.parser.core.models.ParseOptions; |
| 8 | +import org.apache.commons.io.FileUtils; |
4 | 9 | import org.apache.commons.lang3.StringUtils; |
5 | 10 | import org.openapitools.codegen.CodegenConstants; |
| 11 | +import org.openapitools.codegen.CodegenParameter; |
| 12 | +import org.openapitools.codegen.DefaultGenerator; |
| 13 | +import org.openapitools.codegen.config.CodegenConfigurator; |
6 | 14 | import org.openapitools.codegen.languages.AbstractPythonConnexionServerCodegen; |
| 15 | +import org.openapitools.codegen.languages.PythonAiohttpConnexionServerCodegen; |
7 | 16 | import org.testng.annotations.DataProvider; |
8 | 17 | import org.testng.annotations.Test; |
9 | 18 |
|
10 | 19 | import java.io.File; |
| 20 | +import java.io.IOException; |
| 21 | +import java.nio.file.Files; |
| 22 | +import java.nio.file.Path; |
| 23 | +import java.nio.file.Paths; |
11 | 24 | import java.util.Collections; |
| 25 | +import java.util.HashSet; |
| 26 | +import java.util.List; |
12 | 27 | import java.util.Map; |
13 | 28 | import java.util.Objects; |
14 | 29 |
|
15 | 30 | import static org.assertj.core.api.Assertions.assertThat; |
| 31 | +import static org.openapitools.codegen.TestUtils.assertFileContains; |
| 32 | +import static org.openapitools.codegen.TestUtils.assertFileExists; |
| 33 | +import static org.openapitools.codegen.TestUtils.assertFileNotContains; |
16 | 34 | import static org.openapitools.codegen.languages.AbstractPythonConnexionServerCodegen.*; |
17 | 35 |
|
18 | 36 | public class AbstractPythonConnexionServerCodegenTest { |
@@ -142,4 +160,176 @@ private static String platformAgnosticPath(String... nodes) { |
142 | 160 | return StringUtils.join(nodes, File.separatorChar); |
143 | 161 | } |
144 | 162 |
|
| 163 | + @Test(description = "python-aiohttp map parameters should iterate .items()") |
| 164 | + public void testAiohttpMapParametersIterateItems() throws IOException { |
| 165 | + String specPath = "src/test/resources/3_1/python/map-and-freeform-params.yaml"; |
| 166 | + |
| 167 | + File aiohttpOutput = Files.createTempDirectory("test-aiohttp-map-params").toFile().getCanonicalFile(); |
| 168 | + try { |
| 169 | + CodegenConfigurator aiohttpConfig = new CodegenConfigurator() |
| 170 | + .setGeneratorName("python-aiohttp") |
| 171 | + .setInputSpec(specPath) |
| 172 | + .setOutputDir(aiohttpOutput.getAbsolutePath()); |
| 173 | + new DefaultGenerator().opts(aiohttpConfig.toClientOptInput()).generate(); |
| 174 | + |
| 175 | + Path aiohttpController = Paths.get( |
| 176 | + aiohttpOutput.getAbsolutePath(), |
| 177 | + "openapi_server", |
| 178 | + "controllers", |
| 179 | + "default_controller.py"); |
| 180 | + assertFileExists(aiohttpController); |
| 181 | + assertFileContains( |
| 182 | + aiohttpController, |
| 183 | + " if date_map is not None:\n date_map = {k: util.deserialize_date(v) for k, v in date_map.items()}", |
| 184 | + " if datetime_map is not None:\n datetime_map = {k: util.deserialize_datetime(v) for k, v in datetime_map.items()}", |
| 185 | + " if model_map is not None:\n model_map = {k: Tag.from_dict(v) for k, v in model_map.items()}"); |
| 186 | + assertFileNotContains( |
| 187 | + aiohttpController, |
| 188 | + "for k, v in date_map}", |
| 189 | + "for k, v in datetime_map}", |
| 190 | + "for k, v in model_map}"); |
| 191 | + } finally { |
| 192 | + FileUtils.deleteDirectory(aiohttpOutput); |
| 193 | + } |
| 194 | + } |
| 195 | + |
| 196 | + @Test(description = "Connexion servers should skip from_dict only on untyped/free-form object parameters and keep from_dict on composed/model parameters") |
| 197 | + public void testFreeFormAndAnyTypeParametersDoNotCallFromDict() throws IOException { |
| 198 | + String specPath = "src/test/resources/3_1/python/map-and-freeform-params.yaml"; |
| 199 | + String composedSpecPath = "src/test/resources/3_1/python/composed-query-params.yaml"; |
| 200 | + |
| 201 | + OpenAPI openAPI = new OpenAPIParser().readLocation(specPath, null, new ParseOptions()).getOpenAPI(); |
| 202 | + PythonAiohttpConnexionServerCodegen codegen = new PythonAiohttpConnexionServerCodegen(); |
| 203 | + codegen.setOpenAPI(openAPI); |
| 204 | + List<Parameter> testParameters = openAPI.getPaths().get("/test").getGet().getParameters(); |
| 205 | + CodegenParameter freeFormParam = codegen.fromParameter(testParameters.get(3), new HashSet<>()); |
| 206 | + CodegenParameter anyValParam = codegen.fromParameter(testParameters.get(4), new HashSet<>()); |
| 207 | + |
| 208 | + assertThat(freeFormParam.paramName).isEqualTo("free_form"); |
| 209 | + assertThat(freeFormParam.isFreeFormObject).isTrue(); |
| 210 | + assertThat(freeFormParam.isAnyType).isFalse(); |
| 211 | + assertThat(freeFormParam.isContainer).isFalse(); |
| 212 | + assertThat(freeFormParam.isPrimitiveType).isFalse(); |
| 213 | + assertThat(freeFormParam.dataType).isEqualTo("object"); |
| 214 | + |
| 215 | + assertThat(anyValParam.paramName).isEqualTo("any_val"); |
| 216 | + assertThat(anyValParam.isFreeFormObject).isFalse(); |
| 217 | + assertThat(anyValParam.isAnyType).isTrue(); |
| 218 | + assertThat(anyValParam.isContainer).isFalse(); |
| 219 | + assertThat(anyValParam.isPrimitiveType).isFalse(); |
| 220 | + assertThat(anyValParam.dataType).isEqualTo("object"); |
| 221 | + |
| 222 | + OpenAPI composedOpenAPI = new OpenAPIParser().readLocation(composedSpecPath, null, new ParseOptions()).getOpenAPI(); |
| 223 | + PythonAiohttpConnexionServerCodegen composedCodegen = new PythonAiohttpConnexionServerCodegen(); |
| 224 | + composedCodegen.setOpenAPI(composedOpenAPI); |
| 225 | + List<Parameter> probeParameters = composedOpenAPI.getPaths().get("/t").getGet().getParameters(); |
| 226 | + CodegenParameter composedParam = composedCodegen.fromParameter(probeParameters.get(0), new HashSet<>()); |
| 227 | + CodegenParameter oneOfParam = composedCodegen.fromParameter(probeParameters.get(1), new HashSet<>()); |
| 228 | + CodegenParameter addlParam = composedCodegen.fromParameter(probeParameters.get(2), new HashSet<>()); |
| 229 | + assertThat(composedParam.isAnyType).isTrue(); |
| 230 | + assertThat(composedParam.dataType).isEqualTo("Composed"); |
| 231 | + assertThat(oneOfParam.isAnyType).isTrue(); |
| 232 | + assertThat(oneOfParam.dataType).isEqualTo("OneOfM"); |
| 233 | + assertThat(addlParam.paramName).isEqualTo("addl"); |
| 234 | + assertThat(addlParam.isMap).isTrue(); |
| 235 | + assertThat(addlParam.isContainer).isTrue(); |
| 236 | + assertThat(addlParam.isFreeFormObject).isFalse(); |
| 237 | + assertThat(addlParam.isAnyType).isFalse(); |
| 238 | + assertThat(addlParam.dataType).isEqualTo("WithAddl"); |
| 239 | + |
| 240 | + File aiohttpOutput = Files.createTempDirectory("test-aiohttp-freeform-params").toFile().getCanonicalFile(); |
| 241 | + try { |
| 242 | + CodegenConfigurator aiohttpConfig = new CodegenConfigurator() |
| 243 | + .setGeneratorName("python-aiohttp") |
| 244 | + .setInputSpec(specPath) |
| 245 | + .setOutputDir(aiohttpOutput.getAbsolutePath()); |
| 246 | + new DefaultGenerator().opts(aiohttpConfig.toClientOptInput()).generate(); |
| 247 | + |
| 248 | + Path aiohttpController = Paths.get( |
| 249 | + aiohttpOutput.getAbsolutePath(), |
| 250 | + "openapi_server", |
| 251 | + "controllers", |
| 252 | + "default_controller.py"); |
| 253 | + assertFileExists(aiohttpController); |
| 254 | + assertFileNotContains( |
| 255 | + aiohttpController, |
| 256 | + "free_form = ", |
| 257 | + "any_val = "); |
| 258 | + } finally { |
| 259 | + FileUtils.deleteDirectory(aiohttpOutput); |
| 260 | + } |
| 261 | + |
| 262 | + File blueplanetOutput = Files.createTempDirectory("test-blueplanet-freeform-params").toFile().getCanonicalFile(); |
| 263 | + try { |
| 264 | + CodegenConfigurator blueplanetConfig = new CodegenConfigurator() |
| 265 | + .setGeneratorName("python-blueplanet") |
| 266 | + .setInputSpec(specPath) |
| 267 | + .setOutputDir(blueplanetOutput.getAbsolutePath()); |
| 268 | + new DefaultGenerator().opts(blueplanetConfig.toClientOptInput()).generate(); |
| 269 | + |
| 270 | + Path blueplanetController = Paths.get( |
| 271 | + blueplanetOutput.getAbsolutePath(), |
| 272 | + "app", |
| 273 | + "openapi_server", |
| 274 | + "controllers", |
| 275 | + "default_controller.py"); |
| 276 | + assertFileExists(blueplanetController); |
| 277 | + assertFileNotContains( |
| 278 | + blueplanetController, |
| 279 | + "free_form = ", |
| 280 | + "any_val = "); |
| 281 | + } finally { |
| 282 | + FileUtils.deleteDirectory(blueplanetOutput); |
| 283 | + } |
| 284 | + |
| 285 | + File flaskOutput = Files.createTempDirectory("test-flask-freeform-params").toFile().getCanonicalFile(); |
| 286 | + try { |
| 287 | + CodegenConfigurator flaskConfig = new CodegenConfigurator() |
| 288 | + .setGeneratorName("python-flask") |
| 289 | + .setInputSpec(specPath) |
| 290 | + .setOutputDir(flaskOutput.getAbsolutePath()); |
| 291 | + new DefaultGenerator().opts(flaskConfig.toClientOptInput()).generate(); |
| 292 | + |
| 293 | + Path flaskController = Paths.get( |
| 294 | + flaskOutput.getAbsolutePath(), |
| 295 | + "openapi_server", |
| 296 | + "controllers", |
| 297 | + "default_controller.py"); |
| 298 | + assertFileExists(flaskController); |
| 299 | + assertFileNotContains( |
| 300 | + flaskController, |
| 301 | + "free_form =", |
| 302 | + "any_val ="); |
| 303 | + } finally { |
| 304 | + FileUtils.deleteDirectory(flaskOutput); |
| 305 | + } |
| 306 | + |
| 307 | + File flaskComposedOutput = Files.createTempDirectory("test-flask-composed-params").toFile().getCanonicalFile(); |
| 308 | + try { |
| 309 | + CodegenConfigurator flaskComposedConfig = new CodegenConfigurator() |
| 310 | + .setGeneratorName("python-flask") |
| 311 | + .setInputSpec(composedSpecPath) |
| 312 | + .setOutputDir(flaskComposedOutput.getAbsolutePath()); |
| 313 | + new DefaultGenerator().opts(flaskComposedConfig.toClientOptInput()).generate(); |
| 314 | + |
| 315 | + Path flaskComposedController = Paths.get( |
| 316 | + flaskComposedOutput.getAbsolutePath(), |
| 317 | + "openapi_server", |
| 318 | + "controllers", |
| 319 | + "default_controller.py"); |
| 320 | + assertFileExists(flaskComposedController); |
| 321 | + assertFileContains( |
| 322 | + flaskComposedController, |
| 323 | + ":type addl: Dict[str, str]", |
| 324 | + "composed = Composed.from_dict(flask.request.get_json()) # noqa: E501", |
| 325 | + "oneof = OneOfM.from_dict(flask.request.get_json()) # noqa: E501", |
| 326 | + "plain = Pet.from_dict(flask.request.get_json()) # noqa: E501"); |
| 327 | + assertFileNotContains( |
| 328 | + flaskComposedController, |
| 329 | + "addl ="); |
| 330 | + } finally { |
| 331 | + FileUtils.deleteDirectory(flaskComposedOutput); |
| 332 | + } |
| 333 | + } |
| 334 | + |
145 | 335 | } |
0 commit comments