Repository: beda-software/fhir-py-types

Issue:
Reserved keywords are not dumped by dict by default
When resource contains field like `for` or `class` it's dumped as `for_` or `class_` instead of original name

Hints from issue comments:

Solution patch:
diff --git a/fhir_py_types/__init__.py b/fhir_py_types/__init__.py
index 98e292d..be71948 100644
--- a/fhir_py_types/__init__.py
+++ b/fhir_py_types/__init__.py
@@ -33,6 +33,7 @@ class StructurePropertyType:
     isarray: bool = False
     literal: bool = False
     target_profile: list[str] | None = None
+    alias: str | None = None
 
 
 @dataclass(frozen=True)
diff --git a/fhir_py_types/ast.py b/fhir_py_types/ast.py
index 2f2d843..8c2ed7a 100644
--- a/fhir_py_types/ast.py
+++ b/fhir_py_types/ast.py
@@ -51,7 +51,7 @@ def make_default_initializer(
 ) -> ast.expr | None:
     default: ast.expr | None = None
 
-    if keyword.iskeyword(identifier):
+    if keyword.iskeyword(identifier) or type_.alias:
         default = ast.Call(
             ast.Name("Field"),
             args=[],
@@ -61,7 +61,7 @@ def make_default_initializer(
                     if not type_.required
                     else []
                 ),
-                ast.keyword(arg="alias", value=ast.Constant(identifier)),
+                ast.keyword(arg="alias", value=ast.Constant(type_.alias or identifier)),
             ],
         )
     else:
@@ -115,19 +115,20 @@ def zip_identifier_type(
     result = []
 
     for t in [remap_type(definition, t) for t in definition.type]:
-        result.append((format_identifier(definition, identifier, t), t))
-        if (
-            definition.kind != StructureDefinitionKind.PRIMITIVE
-            and is_primitive_type(t)
+        name = format_identifier(definition, identifier, t)
+        result.append((name, t))
+        if definition.kind != StructureDefinitionKind.PRIMITIVE and is_primitive_type(
+            t
         ):
             result.append(
                 (
-                    f"_{format_identifier(definition, identifier, t)}",
+                    f"{name}__ext",
                     StructurePropertyType(
                         code="Element",
                         target_profile=[],
                         required=False,
                         isarray=definition.type[0].isarray,
+                        alias=f"_{name}"
                     ),
                 )
             )
diff --git a/fhir_py_types/cli.py b/fhir_py_types/cli.py
index 1c08540..1acd577 100644
--- a/fhir_py_types/cli.py
+++ b/fhir_py_types/cli.py
@@ -40,7 +40,6 @@ def main() -> None:
             load_from_bundle(bundle) for bundle in args.from_bundles
         )
     )
-
     with open(os.path.join(dir_path, "header.py.tpl")) as header_file:
         header_lines = header_file.readlines()
 
diff --git a/fhir_py_types/header.py.tpl b/fhir_py_types/header.py.tpl
index c22d38c..61e023a 100644
--- a/fhir_py_types/header.py.tpl
+++ b/fhir_py_types/header.py.tpl
@@ -3,6 +3,7 @@ from typing import List as List_, Optional as Optional_, Literal as Literal_, An
 from pydantic import BaseModel as BaseModel_, Field, Extra
 
 
+
 class BaseModel(BaseModel_):
     class Config:
         extra = Extra.forbid


Test patch:
diff --git a/tests/test_ast.py b/tests/test_ast.py
index c3e5e23..0270655 100644
--- a/tests/test_ast.py
+++ b/tests/test_ast.py
@@ -20,6 +20,17 @@ def assert_eq(
     assert generated == expected
 
 
+def build_field_with_alias(identifier: str) -> ast.Call:
+    return ast.Call(
+        func=ast.Name(id="Field"),
+        args=[],
+        keywords=[
+            ast.keyword(arg="default", value=ast.Constant(value=None)),
+            ast.keyword(arg="alias", value=ast.Constant(value=identifier)),
+        ],
+    )
+
+
 def test_generates_empty_ast_from_empty_definitions() -> None:
     assert build_ast([]) == []
 
@@ -64,12 +75,12 @@ def test_generates_class_for_flat_definition() -> None:
                     ),
                     ast.Expr(value=ast.Constant(value="test resource property 1")),
                     ast.AnnAssign(
-                        target=ast.Name(id="_property1"),
+                        target=ast.Name(id="property1__ext"),
                         annotation=ast.Subscript(
                             value=ast.Name(id="Optional_"),
                             slice=ast.Constant("Element"),
                         ),
-                        value=ast.Constant(None),
+                        value=build_field_with_alias("_property1"),
                         simple=1,
                     ),
                     ast.Expr(value=ast.Constant(value="test resource property 1")),
@@ -176,13 +187,13 @@ def test_generates_multiple_classes_for_compound_definition() -> None:
                         value=ast.Constant(value="nested test resource property 1")
                     ),
                     ast.AnnAssign(
-                        target=ast.Name(id="_property1"),
+                        target=ast.Name(id="property1__ext"),
                         annotation=ast.Subscript(
                             value=ast.Name(id="Optional_"),
                             slice=ast.Constant("Element"),
                         ),
                         simple=1,
-                        value=ast.Constant(None),
+                        value=build_field_with_alias("_property1"),
                     ),
                     ast.Expr(
                         value=ast.Constant(value="nested test resource property 1")
@@ -329,7 +340,7 @@ def test_generates_annotations_according_to_structure_type(
                     ),
                     ast.Expr(value=ast.Constant(value="test resource property 1")),
                     ast.AnnAssign(
-                        target=ast.Name(id="_property1"),
+                        target=ast.Name(id="property1__ext"),
                         annotation=ast.Subscript(
                             value=ast.Name(id="Optional_"),
                             slice=ast.Subscript(
@@ -343,7 +354,7 @@ def test_generates_annotations_according_to_structure_type(
                             slice=ast.Constant("Element"),
                         ),
                         simple=1,
-                        value=ast.Constant(None),
+                        value=build_field_with_alias("_property1"),
                     ),
                     ast.Expr(value=ast.Constant(value="test resource property 1")),
                 ],
@@ -418,13 +429,13 @@ def test_unrolls_required_polymorphic_into_class_union() -> None:
                     ),
                     ast.Expr(value=ast.Constant(value="monotype property definition")),
                     ast.AnnAssign(
-                        target=ast.Name(id="_monotype"),
+                        target=ast.Name(id="monotype__ext"),
                         annotation=ast.Subscript(
                             value=ast.Name(id="Optional_"),
                             slice=ast.Constant("Element"),
                         ),
                         simple=1,
-                        value=ast.Constant(None),
+                        value=build_field_with_alias("_monotype"),
                     ),
                     ast.Expr(value=ast.Constant(value="monotype property definition")),
                     ast.AnnAssign(
@@ -440,13 +451,13 @@ def test_unrolls_required_polymorphic_into_class_union() -> None:
                         value=ast.Constant(value="polymorphic property definition")
                     ),
                     ast.AnnAssign(
-                        target=ast.Name(id="_valueBoolean"),
+                        target=ast.Name(id="valueBoolean__ext"),
                         annotation=ast.Subscript(
                             value=ast.Name(id="Optional_"),
                             slice=ast.Constant("Element"),
                         ),
                         simple=1,
-                        value=ast.Constant(None),
+                        value=build_field_with_alias("_valueBoolean"),
                     ),
                     ast.Expr(
                         value=ast.Constant(value="polymorphic property definition")