diff --git a/pydantic2ts/cli/script.py b/pydantic2ts/cli/script.py index 8518395..19a341f 100644 --- a/pydantic2ts/cli/script.py +++ b/pydantic2ts/cli/script.py @@ -14,10 +14,6 @@ from pydantic import BaseModel, Extra, create_model -try: - from pydantic.generics import GenericModel -except ImportError: - GenericModel = None logger = logging.getLogger("pydantic2ts") @@ -65,8 +61,9 @@ def is_concrete_pydantic_model(obj) -> bool: return False elif obj is BaseModel: return False - elif GenericModel and issubclass(obj, GenericModel): - return bool(obj.__concrete__) + # Generic model was removed + # elif GenericModel and issubclass(obj, GenericModel): + # return bool(obj.__concrete__) else: return issubclass(obj, BaseModel) @@ -137,6 +134,11 @@ def clean_schema(schema: Dict[str, Any]) -> None: for prop in schema.get("properties", {}).values(): prop.pop("title", None) + # Work around to produce Tuples just like Arrays since json2ts doesn't support the + # prefixItems json openAPI spec + if "prefixItems" in prop: + prop["items"] = prop["prefixItems"] + if "enum" in schema and schema.get("description") == "An enumeration.": del schema["description"] @@ -152,22 +154,24 @@ def generate_json_schema(models: List[Type[BaseModel]]) -> str: '[k: string]: any' from being added to every interface. This change is reverted once the schema has been generated. """ - model_extras = [getattr(m.Config, "extra", None) for m in models] + model_extras = [m.model_config.get("extra", None) for m in models] try: for m in models: - if getattr(m.Config, "extra", None) != Extra.allow: - m.Config.extra = Extra.forbid + if m.model_config.get("extra", None) != "allow": + m.model_config["extra"] = "forbid" master_model = create_model( "_Master_", **{m.__name__: (m, ...) for m in models} ) - master_model.Config.extra = Extra.forbid - master_model.Config.schema_extra = staticmethod(clean_schema) + master_model.model_config["extra"] = "forbid" + master_model.model_config["json_schema_extra"] = staticmethod(clean_schema) + + schema = master_model.model_json_schema() - schema = json.loads(master_model.schema_json()) + # prefixItems - for d in schema.get("definitions", {}).values(): + for d in schema.get("$defs", {}).values(): clean_schema(d) return json.dumps(schema, indent=2) @@ -175,7 +179,7 @@ def generate_json_schema(models: List[Type[BaseModel]]) -> str: finally: for m, x in zip(models, model_extras): if x is not None: - m.Config.extra = x + m.model_config["extra"] = x def generate_typescript_defs( @@ -281,3 +285,4 @@ def main() -> None: if __name__ == "__main__": main() + diff --git a/setup.py b/setup.py index dff85f4..7777cdc 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ def readme(): setup( name="pydantic-to-typescript", - version="1.0.10", + version="2.0.0", description="Convert pydantic models to typescript interfaces", license="MIT", long_description=readme(), diff --git a/tests/expected_results/excluding_models/output.ts b/tests/expected_results/excluding_models/output.ts index 451bb73..af83361 100644 --- a/tests/expected_results/excluding_models/output.ts +++ b/tests/expected_results/excluding_models/output.ts @@ -7,6 +7,6 @@ export interface Profile { username: string; - age?: number; + age: number | null; hobbies: string[]; } diff --git a/tests/expected_results/generics/input.py b/tests/expected_results/generics/input.py index a37bc55..61a67a8 100644 --- a/tests/expected_results/generics/input.py +++ b/tests/expected_results/generics/input.py @@ -2,7 +2,6 @@ from typing import Generic, TypeVar, Optional, List, Type, cast, Union from pydantic import BaseModel -from pydantic.generics import GenericModel T = TypeVar("T") @@ -12,7 +11,7 @@ class Error(BaseModel): message: str -class ApiResponse(GenericModel, Generic[T]): +class ApiResponse(BaseModel, Generic[T]): data: Optional[T] error: Optional[Error] diff --git a/tests/expected_results/generics/output.ts b/tests/expected_results/generics/output.ts index 5da2624..79b3b5f 100644 --- a/tests/expected_results/generics/output.ts +++ b/tests/expected_results/generics/output.ts @@ -5,6 +5,14 @@ /* Do not modify it by hand - just update the pydantic models and then re-run the script */ +export interface ApiResponse { + data: unknown; + error: Error | null; +} +export interface Error { + code: number; + message: string; +} export interface Article { author: User; content: string; @@ -14,17 +22,13 @@ export interface User { name: string; email: string; } -export interface Error { - code: number; - message: string; -} export interface ListArticlesResponse { - data?: Article[]; - error?: Error; + data: Article[] | null; + error: Error | null; } export interface ListUsersResponse { - data?: User[]; - error?: Error; + data: User[] | null; + error: Error | null; } export interface UserProfile { name: string; @@ -34,6 +38,6 @@ export interface UserProfile { age: number; } export interface UserProfileResponse { - data?: UserProfile; - error?: Error; + data: UserProfile | null; + error: Error | null; } diff --git a/tests/expected_results/single_module/output.ts b/tests/expected_results/single_module/output.ts index 4defc90..56ea42c 100644 --- a/tests/expected_results/single_module/output.ts +++ b/tests/expected_results/single_module/output.ts @@ -15,6 +15,6 @@ export interface LoginResponseData { } export interface Profile { username: string; - age?: number; + age: number | null; hobbies: string[]; }