Repository: marcosschroh/dataclasses-avroschema

Issue:
ModelGenerator's output raises NameError for decimal fields
**Describe the bug**
Code generated by the `ModelGenerator` for schemas containing a decimal logical type field cannot run due to a missing import.

**To Reproduce**
```py
import dataclasses_avroschema

schema = {
    "type": "record",
    "name": "demo",
    "fields": [
        {
            "name": "foo",
            "type": {
                "type": "bytes",
                "logicalType": "decimal",
                "precision": 10,
                "scale": 3
            }
        }
    ]
}
code = dataclasses_avroschema.ModelGenerator().render(schema=schema)

with open("/tmp/generated_code.py", "w") as f:
    print(code, file=f)
```
```sh
python3 /tmp/generated_code.py
```
```
Traceback (most recent call last):
  File "/tmp/generated_code.py", line 7, in <module>
    class Demo(AvroModel):
  File "/tmp/generated_code.py", line 8, in Demo
    foo: decimal.Decimal = types.Decimal(scale=3, precision=10)
                           ^^^^^
NameError: name 'types' is not defined. Did you mean: 'type'?
```

**Expected behavior**
Loadable code without the `NameError`.


Discussion:
github-actions[bot]: [PR Preview Action](https://github.com/rossjrw/pr-preview-action) v1.2.0
:---:
:rocket: Deployed preview to https://marcosschroh.github.io/dataclasses-avroschema/pr-preview/pr-236/
on branch [`gh-pages`](https://github.com/marcosschroh/dataclasses-avroschema/tree/gh-pages) at 2023-01-19 07:57 UTC
<!-- Sticky Pull Request Commentpr-preview -->
codecov[bot]: # [Codecov](https://codecov.io/gh/marcosschroh/dataclasses-avroschema/pull/236?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Marcos+Schroh) Report
> Merging [#236](https://codecov.io/gh/marcosschroh/dataclasses-avroschema/pull/236?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Marcos+Schroh) (47abaad) into [master](https://codecov.io/gh/marcosschroh/dataclasses-avroschema/commit/c5a9f9b6bd3fba8301a57787605b84ef06724c63?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Marcos+Schroh) (c5a9f9b) will **not change** coverage.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##           master     #236   +/-   ##
=======================================
  Coverage   99.37%   99.37%           
=======================================
  Files          14       14           
  Lines        1276     1276           
  Branches      264      263    -1     
=======================================
  Hits         1268     1268           
  Misses          3        3           
  Partials        5        5           
```


| [Impacted Files](https://codecov.io/gh/marcosschroh/dataclasses-avroschema/pull/236?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Marcos+Schroh) | Coverage Δ | |
|---|---|---|
| [...ataclasses\_avroschema/model\_generator/generator.py](https://codecov.io/gh/marcosschroh/dataclasses-avroschema/pull/236?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Marcos+Schroh#diff-ZGF0YWNsYXNzZXNfYXZyb3NjaGVtYS9tb2RlbF9nZW5lcmF0b3IvZ2VuZXJhdG9yLnB5) | `99.09% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Marcos+Schroh). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Marcos+Schroh)


Patch:
diff --git a/dataclasses_avroschema/model_generator/generator.py b/dataclasses_avroschema/model_generator/generator.py
index 3c9326c..8a5b4ee 100644
--- a/dataclasses_avroschema/model_generator/generator.py
+++ b/dataclasses_avroschema/model_generator/generator.py
@@ -253,8 +253,9 @@ class ModelGenerator:
             return field_repr
         return avro_to_python_utils.AVRO_TYPE_TO_PYTHON[logical_type]
 
-    @staticmethod
-    def _parse_decimal(*, field: JsonDict) -> str:
+    def _parse_decimal(self, *, field: JsonDict) -> str:
+        self.imports.add("from dataclasses_avroschema import types")
+
         schema: JsonDict = field["type"]
         precision = schema["precision"]
         scale = schema["scale"]
@@ -295,11 +296,6 @@ class ModelGenerator:
                 language_types = self.parse_union(field_types=field_types[1:], model_name=model_name)
             elif isinstance(field_types[1], dict):
                 # TODO: check what happens with more than 2 complex types
-                # it is a complex type like array, dict, enum, fixed or record
-                # it needs to be render
-                # if self._is_logical_type(field_type=field_types[1]):
-                #     language_types = self.parse_logical_type(field=field_types[1])
-                # else:
                 language_types = self.render_field(field=field_types[1], model_name=model_name)
             else:
                 language_types = ", ".join(


Test patch:
diff --git a/tests/model_generator/conftest.py b/tests/model_generator/conftest.py
index a9b7af6..f3f75cc 100644
--- a/tests/model_generator/conftest.py
+++ b/tests/model_generator/conftest.py
@@ -313,6 +313,15 @@ def schema_one_to_self_relationship() -> JsonDict:
     }
 
 
+@pytest.fixture
+def schema_with_decimal_field() -> JsonDict:
+    return {
+        "type": "record",
+        "name": "demo",
+        "fields": [{"name": "foo", "type": {"type": "bytes", "logicalType": "decimal", "precision": 10, "scale": 3}}],
+    }
+
+
 @pytest.fixture
 def schema_with_logical_types() -> JsonDict:
     return {
diff --git a/tests/model_generator/test_model_generator.py b/tests/model_generator/test_model_generator.py
index 36b46e7..4864b5a 100644
--- a/tests/model_generator/test_model_generator.py
+++ b/tests/model_generator/test_model_generator.py
@@ -1,5 +1,4 @@
-from dataclasses_avroschema import ModelGenerator, types, field_utils
-
+from dataclasses_avroschema import ModelGenerator, field_utils, types
 from dataclasses_avroschema.model_generator.avro_to_python_utils import render_datetime
 
 
@@ -282,6 +281,23 @@ class User(AvroModel):
     assert result.strip() == expected_result.strip()
 
 
+def test_decimal_field(schema_with_decimal_field: types.JsonDict) -> None:
+    expected_result = """
+from dataclasses_avroschema import AvroModel
+from dataclasses_avroschema import types
+import dataclasses
+import decimal
+
+
+@dataclasses.dataclass
+class Demo(AvroModel):
+    foo: decimal.Decimal = types.Decimal(scale=3, precision=10)
+"""
+    model_generator = ModelGenerator()
+    result = model_generator.render(schema=schema_with_decimal_field)
+    assert result.strip() == expected_result.strip()
+
+
 def test_schema_logical_types(schema_with_logical_types: types.JsonDict) -> None:
     release_datetime = render_datetime(value=1570903062000, format=field_utils.TIMESTAMP_MILLIS)
     release_datetime_micro = render_datetime(value=1570903062000000, format=field_utils.TIMESTAMP_MICROS)