From ed95d9abf624213fc2dee3e44e9a3478047102ef Mon Sep 17 00:00:00 2001 From: Joshua Shaffer Date: Fri, 3 Jun 2022 16:38:34 -0400 Subject: [PATCH] Added by_alias --- pydantic2ts/cli/script.py | 20 ++++++++++----- .../__pycache__/input.cpython-310.pyc | Bin 0 -> 1070 bytes .../single_module_alias_id/input.py | 20 +++++++++++++++ .../single_module_alias_id/output.ts | 24 ++++++++++++++++++ tests/test_script.py | 13 ++++++++-- 5 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 tests/expected_results/single_module_alias_id/__pycache__/input.cpython-310.pyc create mode 100644 tests/expected_results/single_module_alias_id/input.py create mode 100644 tests/expected_results/single_module_alias_id/output.ts diff --git a/pydantic2ts/cli/script.py b/pydantic2ts/cli/script.py index 08b02ca..e1674da 100644 --- a/pydantic2ts/cli/script.py +++ b/pydantic2ts/cli/script.py @@ -128,7 +128,7 @@ def clean_schema(schema: Dict[str, Any]) -> None: del schema["description"] -def generate_json_schema(models: List[Type[BaseModel]]) -> str: +def generate_json_schema(models: List[Type[BaseModel]], by_alias: bool) -> str: """ Create a top-level '_Master_' model with references to each of the actual models. Generate the schema for this model, which will include the schemas for all the @@ -152,7 +152,7 @@ def generate_json_schema(models: List[Type[BaseModel]]) -> str: master_model.Config.extra = Extra.forbid master_model.Config.schema_extra = staticmethod(clean_schema) - schema = json.loads(master_model.schema_json()) + schema = json.loads(master_model.schema_json(by_alias=by_alias)) for d in schema.get("definitions", {}).values(): clean_schema(d) @@ -166,7 +166,8 @@ def generate_json_schema(models: List[Type[BaseModel]]) -> str: def generate_typescript_defs( - module: str, output: str, exclude: Tuple[str] = (), json2ts_cmd: str = "json2ts" + module: str, output: str, exclude: Tuple[str] = (), json2ts_cmd: str + = "json2ts", by_alias: bool = False ) -> None: """ Convert the pydantic models in a python module into typescript interfaces. @@ -191,7 +192,7 @@ def generate_typescript_defs( logger.info("Generating JSON schema from pydantic models...") - schema = generate_json_schema(models) + schema = generate_json_schema(models, by_alias) schema_dir = mkdtemp() schema_file_path = os.path.join(schema_dir, "schema.json") @@ -227,6 +228,11 @@ def generate_typescript_defs( @click.option( "--output", help="name of the file the typescript definitions should be written to" ) +@click.option( + "--by-alias", + help="Use the backing field name (True) or the model field name (False)", + default=False +) @click.option( "--exclude", multiple=True, @@ -234,13 +240,15 @@ def generate_typescript_defs( ) @click.option("--json2ts-cmd", default="json2ts") def main( - module: str, output: str, exclude: Tuple[str], json2ts_cmd: str = "json2ts" + module: str, output: str, exclude: Tuple[str], json2ts_cmd: str = + "json2ts", by_alias: bool = False ) -> None: """ CLI entrypoint to run :func:`generate_typescript_defs` """ logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(message)s") - return generate_typescript_defs(module, output, exclude, json2ts_cmd) + return generate_typescript_defs(module, output, exclude, + json2ts_cmd, by_alias) if __name__ == "__main__": diff --git a/tests/expected_results/single_module_alias_id/__pycache__/input.cpython-310.pyc b/tests/expected_results/single_module_alias_id/__pycache__/input.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17293e583f35aebaf1d9ef7e0a7a357862779ef3 GIT binary patch literal 1070 zcmah}&2AGh5VrR}Y1(d4g~SEzH4^Q& zmB;aw6K8H*V7!Uch*rXq$McQ7p7A%IR&8$&369i6mcpt#95CsF?dDB!=HFF z83%6gm>YPm1k^5mDxnq_%U-lrs)pAtI+4cC{n5=4A~?cn?xO)xQ9-KU4S^6MK_{y< zm|$6$D02CUI+M*44FVb~d2L+Q8PE-1g3DTN%%##|I*wh&m=7}MhKwzh=xXne7`y0r zz1|6p)ozzD-ZaW`U!`H}8__#hNpF6?Ef;DD<@wB%r_d@>wpW5<;`xD92llE3GuN`U zr3GV62_IURTM$fx>1qrZ*_>hCb$VV)ZkQCMY}(EqwpTjAL@~}^-WigNj%XjdL6Sdo zgwq_O*(6C&5%`XM39ATVNJNa3rMM=zW)R;a=%?rpAnpAOsqA~^(wADjlQkSxAr|#< z@~CZrYg5Rkz=EMJE~QX09|mC}tQl7G2RFDWpBbKF9s@+?H5#f^51# z3Y}ubRmjhvN*8K2lVGOfp&npVd)?|SZ@dWfJ{lLw#_DYkN8WhxYXAD{rmVbOAKOFY zFEPGjLz2*d?)=Gu5zT48cZ0|Oi7iIaU5jn67uzYA7L@_V+;SIN^&T3Rwkz(Y%Y70dY4UBf_sR6 Q17bWsImu}r=J9^^7e~qQga7~l literal 0 HcmV?d00001 diff --git a/tests/expected_results/single_module_alias_id/input.py b/tests/expected_results/single_module_alias_id/input.py new file mode 100644 index 0000000..a2cc634 --- /dev/null +++ b/tests/expected_results/single_module_alias_id/input.py @@ -0,0 +1,20 @@ +from pydantic import BaseModel, Field +from typing import Optional, List + + +class LoginCredentials(BaseModel): + username: str + password: str + + +class Profile(BaseModel): + id: int = Field(..., alias='_id', + description="Appears in model without the underscore, but stored with it.") + username: str + age: Optional[int] + hobbies: List[str] + + +class LoginResponseData(BaseModel): + token: str + profile: Profile diff --git a/tests/expected_results/single_module_alias_id/output.ts b/tests/expected_results/single_module_alias_id/output.ts new file mode 100644 index 0000000..5ba1128 --- /dev/null +++ b/tests/expected_results/single_module_alias_id/output.ts @@ -0,0 +1,24 @@ +/* tslint:disable */ +/* eslint-disable */ +/** +/* This file was automatically generated from pydantic models by running pydantic2ts. +/* Do not modify it by hand - just update the pydantic models and then re-run the script +*/ + +export interface LoginCredentials { + username: string; + password: string; +} +export interface LoginResponseData { + token: string; + profile: Profile; +} +export interface Profile { + /** + * Appears in model without the underscore, but stored with it. + */ + _id: number; + username: string; + age?: number; + hobbies: string[]; +} diff --git a/tests/test_script.py b/tests/test_script.py index bec06d1..8b602e7 100644 --- a/tests/test_script.py +++ b/tests/test_script.py @@ -17,7 +17,8 @@ def get_expected_output(test_name: str) -> str: def run_test( - tmpdir, test_name, *, module_path=None, call_from_python=False, exclude=() + tmpdir, test_name, *, module_path=None, call_from_python=False, + exclude=(), by_alias: bool = False ): """ Execute pydantic2ts logic for converting pydantic models into tyepscript definitions. @@ -27,11 +28,13 @@ def run_test( output_path = tmpdir.join(f"cli_{test_name}.ts").strpath if call_from_python: - generate_typescript_defs(module_path, output_path, exclude) + generate_typescript_defs(module_path, output_path, exclude, + by_alias) else: cmd = f"pydantic2ts --module {module_path} --output {output_path}" for model_to_exclude in exclude: cmd += f" --exclude {model_to_exclude}" + cmd += f" --by-alias {by_alias}" os.system(cmd) with open(output_path, "r") as f: @@ -42,6 +45,12 @@ def run_test( def test_single_module(tmpdir): run_test(tmpdir, "single_module") +def test_single_module_alias_id(tmpdir): + run_test(tmpdir, "single_module_alias_id", + call_from_python=True, by_alias=True) + +def test_single_module_alias_id_cmd(tmpdir): + run_test(tmpdir, "single_module_alias_id", by_alias=True) def test_submodules(tmpdir): run_test(tmpdir, "submodules")