Skip to content

Commit

Permalink
fix dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
jonaslagoni committed Mar 8, 2024
1 parent 16a3535 commit 0ad97a2
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`Should be able to render python models and should generate \`implicit\` or \`explicit\` imports for models implementing referenced types: nested-model 1`] = `
Array [
"
from typing import Any
class ObjProperty:
def __init__(self, input: dict):
if hasattr(input, \\"number\\"):
Expand Down Expand Up @@ -31,7 +31,7 @@ class ObjProperty:
exports[`Should be able to render python models and should generate \`implicit\` or \`explicit\` imports for models implementing referenced types: nested-model 2`] = `
Array [
"
from typing import Any
class ObjProperty:
def __init__(self, input: dict):
if hasattr(input, \\"number\\"):
Expand Down Expand Up @@ -59,7 +59,7 @@ class ObjProperty:
exports[`Should be able to render python models and should generate \`implicit\` or \`explicit\` imports for models implementing referenced types: root-model-explicit-import 1`] = `
Array [
"from ObjProperty import ObjProperty
from typing import Any
class Root:
def __init__(self, input: dict):
if hasattr(input, \\"email\\"):
Expand Down Expand Up @@ -87,7 +87,7 @@ class Root:
exports[`Should be able to render python models and should generate \`implicit\` or \`explicit\` imports for models implementing referenced types: root-model-implicit-import 1`] = `
Array [
"from ObjProperty import ObjProperty
from typing import Any
class Root:
def __init__(self, input: dict):
if hasattr(input, \\"email\\"):
Expand Down
5 changes: 3 additions & 2 deletions src/generators/python/PythonConstrainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ export const PythonDefaultTypeMapping: PythonTypeMapping = {
});
return `tuple[${tupleTypes.join(', ')}]`;
},
Array({ constrainedModel }): string {
return `list[${constrainedModel.valueModel.type}]`;
Array({ constrainedModel, dependencyManager }): string {
dependencyManager.addDependency('from typing import List');
return `List[${constrainedModel.valueModel.type}]`;
},
Enum({ constrainedModel }): string {
//Returning name here because all enum models have been split out
Expand Down
40 changes: 40 additions & 0 deletions src/generators/python/PythonDependencyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,44 @@ export class PythonDependencyManager extends AbstractDependencyManager {
model.name
}`;
}

/**
* Renders all added dependencies a single time.
*
* For example `from typing import Dict` and `from typing import Any` would form a single import `from typing import Dict, Any`
*/
renderDependencies(): string[] {
const importMap: Record<string, string[]> = {};
const dependenciesToRender = [];
/**
* Split up each dependency that matches `from x import y` and keep everything else as is.
*
* Merge all `y` together and make sure they are unique and render the dependency as `from x import y1, y2, y3`
*/
for (const dependency of this.dependencies) {
const regex = /from ([A-Za-z]+) import ([A-Za-z,\s]+)/g;
const matches = regex.exec(dependency);

if (!matches) {
dependenciesToRender.push(dependency);
} else {
const from = matches[1];
if (!importMap[`${from}`]) {
importMap[`${from}`] = [];
}
const toImport = matches[2]
.split(',')
.map((importMatch) => importMatch.trim());
// eslint-disable-next-line security/detect-object-injection
importMap[`${from}`].push(...toImport);
}
}
for (const [from, toImport] of Object.entries(importMap)) {
const uniqueToImport = [...new Set(toImport)];
dependenciesToRender.push(
`from ${from} import ${uniqueToImport.join(', ')}`
);
}
return dependenciesToRender;
}
}
4 changes: 2 additions & 2 deletions src/generators/python/PythonGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ ${outputModel.result}`;
return RenderOutput.toRenderOutput({
result,
renderedName: model.name,
dependencies: dependencyManagerToUse.dependencies
dependencies: dependencyManagerToUse.renderDependencies()
});
}

Expand All @@ -266,7 +266,7 @@ ${outputModel.result}`;
return RenderOutput.toRenderOutput({
result,
renderedName: model.name,
dependencies: dependencyManagerToUse.dependencies
dependencies: dependencyManagerToUse.renderDependencies()
});
}
}
3 changes: 2 additions & 1 deletion src/generators/python/renderers/ClassRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ export const PYTHON_DEFAULT_CLASS_PRESET: ClassPresetType<PythonOptions> = {
No properties
"""`;
}
return `def __init__(self, input: dict):
renderer.dependencyManager.addDependency(`from typing import Dict`);
return `def __init__(self, input: Dict):
${renderer.indent(body)}`;
},
getter({ property }) {
Expand Down
2 changes: 1 addition & 1 deletion test/generators/python/PythonConstrainer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ describe('PythonConstrainer', () => {
constrainedModel: model,
...defaultOptions
});
expect(type).toEqual('list[str]');
expect(type).toEqual('List[str]');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`PythonGenerator Class should not render reserved keyword 1`] = `
"class Address:
def __init__(self, input: dict):
def __init__(self, input: Dict):
if hasattr(input, \\"reservedReservedDel\\"):
self._reservedReservedDel: str = input[\\"reservedReservedDel\\"]
if hasattr(input, \\"reservedDel\\"):
Expand All @@ -26,7 +26,7 @@ exports[`PythonGenerator Class should not render reserved keyword 1`] = `

exports[`PythonGenerator Class should render \`class\` type 1`] = `
"class Address:
def __init__(self, input: dict):
def __init__(self, input: Dict):
self._streetName: str = input[\\"streetName\\"]
self._city: str = input[\\"city\\"]
self._state: str = input[\\"state\\"]
Expand All @@ -35,7 +35,7 @@ exports[`PythonGenerator Class should render \`class\` type 1`] = `
self._marriage: bool = input[\\"marriage\\"]
if hasattr(input, \\"members\\"):
self._members: str | float | bool = input[\\"members\\"]
self._arrayType: list[str | float | Any] = input[\\"arrayType\\"]
self._arrayType: List[str | float | Any] = input[\\"arrayType\\"]
if hasattr(input, \\"additionalProperties\\"):
self._additionalProperties: dict[Any | str, Any | str] = input[\\"additionalProperties\\"]
Expand Down Expand Up @@ -82,10 +82,10 @@ exports[`PythonGenerator Class should render \`class\` type 1`] = `
self._members = members
@property
def arrayType(self) -> list[str | float | Any]:
def arrayType(self) -> List[str | float | Any]:
return self._arrayType
@arrayType.setter
def arrayType(self, arrayType: list[str | float | Any]):
def arrayType(self, arrayType: List[str | float | Any]):
self._arrayType = arrayType
@property
Expand All @@ -104,7 +104,7 @@ exports[`PythonGenerator Class should work with custom preset for \`class\` type
test1
def __init__(self, input: dict):
def __init__(self, input: Dict):
if hasattr(input, \\"property\\"):
self._property: str = input[\\"property\\"]
if hasattr(input, \\"additionalProperties\\"):
Expand Down Expand Up @@ -132,7 +132,7 @@ exports[`PythonGenerator Class should work with custom preset for \`class\` type

exports[`PythonGenerator Class should work with empty objects 1`] = `
"class CustomClass:
def __init__(self, input: dict):
def __init__(self, input: Dict):
\\"\\"\\"
No properties
\\"\\"\\"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`PYTHON_JSON_SERIALIZER_PRESET should render serializer and deserializer for class 1`] = `
"class Test:
def __init__(self, input: dict):
def __init__(self, input: Dict):
if hasattr(input, \\"prop\\"):
self._prop: str = input[\\"prop\\"]
if hasattr(input, \\"additionalProperties\\"):
Expand Down

0 comments on commit 0ad97a2

Please sign in to comment.