Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate Typescript enums instead of string types #3

Merged
merged 25 commits into from
Oct 23, 2024

Conversation

guaycuru
Copy link

@guaycuru guaycuru commented Sep 24, 2024

This converts Python enums to Typescript enums.

I.e. instead of:

export type CatBreed = "domestic shorthair" | "bengal" | "persian" | "siamese";
export type DogBreed = "mutt" | "labrador" | "golden retriever";

It generates:

export const enum CatBreed {
  domestic_shorthair = "domestic shorthair",
  bengal = "bengal",
  persian = "persian",
  siamese = "siamese"
}
export const enum DogBreed {
  mutt = "mutt",
  labrador = "labrador",
  golden_retriever = "golden retriever"
}

Fixes phillipdupuis#30

This also fixes some V1 issues and updates GitHub Actions to run tests in both Pydantic V1 and V2.

@guaycuru guaycuru changed the title Generate enums Generate Typescript enums instead of string types Sep 24, 2024
@guaycuru
Copy link
Author

@seanwessmith Do you think this could be merged?

@guaycuru guaycuru force-pushed the generate-enums branch 4 times, most recently from c22c647 to ae39ab0 Compare September 26, 2024 12:29
@guaycuru guaycuru force-pushed the generate-enums branch 2 times, most recently from a4a57d4 to 6ae626b Compare September 26, 2024 15:02
@guaycuru guaycuru force-pushed the generate-enums branch 2 times, most recently from d0291f0 to 42fd716 Compare September 26, 2024 15:11
@guaycuru guaycuru marked this pull request as draft September 26, 2024 15:21
@guaycuru guaycuru marked this pull request as ready for review September 26, 2024 17:29
@seanwessmith
Copy link
Collaborator

@guaycuru lmk when you're done adding commits and i'll review this PR

@guaycuru
Copy link
Author

@seanwessmith Sorry for all the noise and tagging you too early. I'm done adding commits now!

@guaycuru
Copy link
Author

Just one last commit to allow disabling debug from calling scripts :)
Now I'm really done!

Comment on lines 132 to 135
for _, submodule in inspect.getmembers(
module, lambda obj: is_submodule(obj, module_name)
):
enums.extend(extract_enum_models(submodule))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed there's an edge case that this logic for walking module imports isn't able to catch: when there's an import statement of the form from module import X, module doesn't get listed as a member of the importing module by inspect.getmembers.

So for example:

from another_module import ModelWithEnumField

When a field in ModelWithEnumField references an enum class defined in another_module, the enum class doesn't get extracted by this function, because it won't recurse into another_module.

Branch with a test script that demonstrates this: https://github.com/ento/pydantic-to-typescript2/blob/testing-enums/abs_vs_rel.sh

Output from the script

### Relative import
+ git checkout 972fc5e7e311a43ab14a97e1bfb6e40ca3c39d3d
+ pydantic2ts --module tests/expected_results/enums/v1/input.py --output output.ts --json2ts ./node_modules/.bin/json2ts
2024-10-05 13:27:43,533 Finding pydantic models...
2024-10-05 13:27:43,537 Generating JSON schema from pydantic models...  
cf5cdb5a30c04533858cee0ef94cf0d6                                                       
['AnimalShelter', 'BaseModel', 'Cat', 'Dog', 'Enum', 'List', 'ModelOne', 'ModelTwo', 'Optional', 'Standalone', '__builtins__', '__cached__', '__doc__', '__file__', '__loader_
_', '__name__', '__package__', '__path__', '__spec__', 'schemas']                                                                                                             
cf5cdb5a30c04533858cee0ef94cf0d6.schemas
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'schema_one', 'schema_two']
cf5cdb5a30c04533858cee0ef94cf0d6.schemas.schema_one      
['BaseModel', 'Foo', 'ModelOne', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'enum']
cf5cdb5a30c04533858cee0ef94cf0d6.schemas.schema_two
['BaseModel', 'Foo', 'ModelTwo', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'enum']
2024-10-05 13:27:43,539 Converting JSON schema to typescript definitions...
2024-10-05 13:27:43,731 Saved typescript definitions to output.ts.
+ grep -E 'Foo.? ' output.ts                                                           
export const enum Foo {                                                                
export const enum Foo1 {
+ set +x                                                                               
                                                                                       
### Absolute import
+ git checkout f828b0393d123fbf82b3f45489d61cf81257471d
++ pwd                                                                                 
+ PYTHONPATH=/home/ento/workspace/pydantic-to-typescript2/tests/expected_results/enums/v1
+ pydantic2ts --module /home/ento/workspace/pydantic-to-typescript2/tests/expected_results/enums/v1/input.py --output output.ts --json2ts ./node_modules/.bin/json2ts
2024-10-05 13:27:43,848 Finding pydantic models...
2024-10-05 13:27:43,851 Generating JSON schema from pydantic models...
e270b5d4c08f470fb81b727e49611131
['AnimalShelter', 'BaseModel', 'Cat', 'Dog', 'Enum', 'List', 'ModelOne', 'ModelTwo', 'Optional', 'Standalone', '__builtins__', '__cached__', '__doc__', '__file__', '__loader_
_', '__name__', '__package__', '__path__', '__spec__']
2024-10-05 13:27:43,853 Converting JSON schema to typescript definitions...
2024-10-05 13:27:44,090 Saved typescript definitions to output.ts.
+ grep -E 'Foo.? ' output.ts
export type Foo = "one_a" | "one_b";
export type Foo1 = "two_a" | "two_b";

I wonder if going through the list of Pydantic models extracted and recursing into their fields would work instead

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I'll try to find a fix for that!

@guaycuru
Copy link
Author

guaycuru commented Oct 8, 2024

Found another edge case related to absolute imports. Looking for a fix...

@guaycuru
Copy link
Author

guaycuru commented Oct 8, 2024

All fixed!

@seanwessmith This is ready to be reviewed whenever you get a chance!

@guaycuru
Copy link
Author

@seanwessmith Sorry to ping you, but any updates regarding reviewing this PR?

@seanwessmith
Copy link
Collaborator

Sorry for the delay. I'm not the in house python expert and the mrs large. I'll take a look tomorrow

@seanwessmith seanwessmith merged commit 4eb2292 into Darius-Labs:main Oct 23, 2024
1 check passed
@coveralls
Copy link

Pull Request Test Coverage Report for Build 11256006730

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 64 of 80 (80.0%) changed or added relevant lines in 1 file are covered.
  • 15 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+0.1%) to 80.383%

Changes Missing Coverage Covered Lines Changed/Added Lines %
pydantic2ts/cli/script.py 64 80 80.0%
Files with Coverage Reduction New Missed Lines %
pydantic2ts/cli/script.py 15 80.29%
Totals Coverage Status
Change from base Build 10823919211: 0.1%
Covered Lines: 168
Relevant Lines: 209

💛 - Coveralls

@guaycuru
Copy link
Author

@seanwessmith Thank you very much for reviewing and approving this.
Do you think we could get a new release that includes these changes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enum names are not preserved
4 participants