Repository: terminusdb/terminusdb-client-python (language: python)

Issue:
Python schema cannot deal with property of type `JSON`
**Describe the bug**
The Python schema (`schema.py`) generated by the `tdbpy startproject` command is unable to handle properties of type JSON although this is valid property type (at least it can be chosen in the TerminusCMS UI). 

**To Reproduce**
When I commit (`tdbpy commit`) the following schema: 

```python
class Change(DocumentTemplate):
    _subdocument = []
    former_value: Optional[str]
    property: Optional[str]
```
it works. If I then change the type to `JSON` in the dropdown from the schema editor of the TerminusCMS UI and run `tdbpy sync`, I get the following:

```python
class Change(DocumentTemplate):
    _subdocument = []
    former_value: Optional[str]
    property: Optional["xdd:json"]
```
If I then do some further changes in `schema.py` and want to run `tdbpy commit` again, I'm hit with the following error:

**Error logs**

```plaintext
Traceback (most recent call last):
  File "/home/lino/.asdf/installs/python/3.11.1/lib/python3.11/typing.py", line 827, in __init__
    code = compile(arg_to_compile, '<string>', 'eval')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 1
    xdd:json
       ^
SyntaxError: invalid syntax

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/lino/.cache/pypoetry/virtualenvs/tedective-mnyNYuMy-py3.11/bin/tdbpy", line 8, in <module>
    sys.exit(tdbpy())
             ^^^^^^^
  File "/home/lino/.cache/pypoetry/virtualenvs/tedective-mnyNYuMy-py3.11/lib/python3.11/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.cache/pypoetry/virtualenvs/tedective-mnyNYuMy-py3.11/lib/python3.11/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/home/lino/.cache/pypoetry/virtualenvs/tedective-mnyNYuMy-py3.11/lib/python3.11/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.cache/pypoetry/virtualenvs/tedective-mnyNYuMy-py3.11/lib/python3.11/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.cache/pypoetry/virtualenvs/tedective-mnyNYuMy-py3.11/lib/python3.11/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.cache/pypoetry/virtualenvs/tedective-mnyNYuMy-py3.11/lib/python3.11/site-packages/terminusdb_client/scripts/scripts.py", line 329, in commit
    schema_plan = __import__("schema", globals(), locals(), [], 0)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/Source/fsfe.org/tedective/api/tedective/schema.py", line 359, in <module>
    class Change(DocumentTemplate):
  File "/home/lino/Source/fsfe.org/tedective/api/tedective/schema.py", line 362, in Change
    property: Optional["xdd:json"]
              ~~~~~~~~^^^^^^^^^^^^
  File "/home/lino/.asdf/installs/python/3.11.1/lib/python3.11/typing.py", line 341, in inner
    return cached(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.asdf/installs/python/3.11.1/lib/python3.11/typing.py", line 460, in __getitem__
    return self._getitem(self, parameters)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.asdf/installs/python/3.11.1/lib/python3.11/typing.py", line 681, in Optional
    arg = _type_check(parameters, f"{self} requires a single type.")
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.asdf/installs/python/3.11.1/lib/python3.11/typing.py", line 186, in _type_check
    arg = _type_convert(arg, module=module, allow_special_forms=allow_special_forms)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.asdf/installs/python/3.11.1/lib/python3.11/typing.py", line 164, in _type_convert
    return ForwardRef(arg, module=module, is_class=allow_special_forms)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lino/.asdf/installs/python/3.11.1/lib/python3.11/typing.py", line 829, in __init__
    raise SyntaxError(f"Forward reference must be an expression -- got {arg!r}")
SyntaxError: Forward reference must be an expression -- got 'xdd:json'
```

**Expected behavior**
I would expect that the changes pulled via `tdbpy sync` can then be committed again using `tdbpy commit`. 

**System information (please complete the following information):**
 - OS: Docker
 - terminus-client-python version 10.2.2




Discussion / hints:
Thank you for reporting! `xdd:json` is indeed not the right type. We will come back at this and test the JSON type in the Python client properly and make sure it works.

Fix patch:
diff --git a/terminusdb_client/woql_type.py b/terminusdb_client/woql_type.py
index 2db5195c..6102fe1c 100644
--- a/terminusdb_client/woql_type.py
+++ b/terminusdb_client/woql_type.py
@@ -7,6 +7,7 @@
     bool: "xsd:boolean",
     float: "xsd:double",
     int: "xsd:integer",
+    dict: "sys:JSON",
     dt.datetime: "xsd:dateTime",
     dt.date: "xsd:date",
     dt.time: "xsd:time",


Test patch:
diff --git a/terminusdb_client/tests/test_Schema.py b/terminusdb_client/tests/test_Schema.py
index 5a480b62..6bfa496e 100644
--- a/terminusdb_client/tests/test_Schema.py
+++ b/terminusdb_client/tests/test_Schema.py
@@ -206,6 +206,27 @@ def test_embedded_object(test_schema):
     assert (len(result) == 2)
 
 
+def test_person_sys_json():
+    schema_json = {
+        "@id": "PersonJSONTest",
+        "@key": {
+            "@type": "Random"
+        },
+        "@type": "Class",
+        "metadata": {
+            "@class": "sys:JSON",
+            "@type": "Optional"
+        }
+    }
+    schema = Schema()
+    test_result = schema._construct_class(schema_json)
+    result = {'@id': 'PersonJSONTest',
+              '@key': {'@type': 'Random'},
+              '@type': 'Class',
+              'metadata': {'@class': 'sys:JSON', '@type': 'Optional'}}
+    assert test_result._to_dict() == result
+
+
 def test_id_and_capture(test_schema):
     my_schema = test_schema
     Person = my_schema.object.get("Person")