Repository: s-knibbs/dataclasses-jsonschema (python)

Issue:
Add option to include the python module name
To aid code generation when generating python code from the schemas within an OpenAPI spec, it would be useful to have an option to include the module name with each schema:

```python

@dataclass
class Pet(JsonSchemaMixin):
    """A pet"""
    name: str
    age: int

>>> JsonSchemaMixin.all_json_schemas(schema_type=SchemaType.SWAGGER_V3, include_module_names=True)
{
    "Pet": {
        "description": "A pet",
        "type": "object",
        "x-module-name": "petstore.data_types",
        ....
    }
}
```

Pull request description:
Add `x-module-name` extension to generated schema
Fixes #114

Patch:
diff --git a/dataclasses_jsonschema/__init__.py b/dataclasses_jsonschema/__init__.py
index 965d706..e972c46 100644
--- a/dataclasses_jsonschema/__init__.py
+++ b/dataclasses_jsonschema/__init__.py
@@ -645,6 +645,8 @@ class JsonSchemaMixin:
                     # Note: Unlike swagger, JSON schema does not support extensions
                     if schema_options.schema_type in (SchemaType.SWAGGER_V2, SchemaType.SWAGGER_V3):
                         field_schema['x-enum-name'] = field_type_name
+                    if schema_options.schema_type == SchemaType.SWAGGER_V3:
+                        field_schema['x-module-name'] = field_type.__module__
             elif field_type_name == 'Union':
                 if schema_options.schema_type == SchemaType.SWAGGER_V2:
                     raise TypeError('Type unions unsupported in Swagger 2.0')
@@ -777,6 +779,9 @@ class JsonSchemaMixin:
                 'properties': properties
             }
 
+            if schema_options.schema_type == SchemaType.OPENAPI_3:
+                schema['x-module-name'] = cls.__module__
+
             if not cls.__allow_additional_props:
                 schema["additionalProperties"] = False
 


Test patch:
diff --git a/tests/test_apispec_plugin.py b/tests/test_apispec_plugin.py
index 34cfc33..83b09ca 100644
--- a/tests/test_apispec_plugin.py
+++ b/tests/test_apispec_plugin.py
@@ -67,6 +67,7 @@ EXPECTED_API_SPEC = {
     "components": {
         "schemas": {
             "Category": {
+                "x-module-name": "tests.test_apispec_plugin",
                 "description": "Pet category",
                 "type": "object",
                 "properties": {
@@ -82,6 +83,7 @@ EXPECTED_API_SPEC = {
                 ]
             },
             "Pet": {
+                "x-module-name": "tests.test_apispec_plugin",
                 "description": "A pet",
                 "type": "object",
                 "properties": {
@@ -109,7 +111,8 @@ EXPECTED_API_SPEC = {
                         ],
                         "properties": {
                             "colour": {"type": "string"}
-                        }
+                        },
+                        "x-module-name": "tests.test_apispec_plugin"
                     }
                 ],
                 "description": "A cat"
@@ -126,7 +129,8 @@ EXPECTED_API_SPEC = {
                         ],
                         "properties": {
                             "favourite_food": {"type": "string"}
-                        }
+                        },
+                        "x-module-name": "tests.test_apispec_plugin"
                     }
                 ],
                 "description": "A dog"
diff --git a/tests/test_core.py b/tests/test_core.py
index 56605bf..2c42e0f 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -1,5 +1,6 @@
 import datetime
 from _decimal import Decimal
+from copy import deepcopy
 from enum import Enum
 
 from dataclasses import dataclass, field
@@ -178,7 +179,13 @@ def test_embeddable_json_schema():
     assert expected == Foo.json_schema(embeddable=True)
     expected = {'Point': POINT_SCHEMA, 'Foo': SWAGGER_V2_FOO_SCHEMA}
     assert expected == SubSchemas.all_json_schemas(schema_type=SchemaType.SWAGGER_V2)
-    expected = {'Point': POINT_SCHEMA, 'Foo': SWAGGER_V3_FOO_SCHEMA}
+    expected = {
+        'Point': deepcopy(POINT_SCHEMA),
+        'Foo': deepcopy(SWAGGER_V3_FOO_SCHEMA),
+    }
+    expected['Point']['x-module-name'] = 'tests.conftest'
+    expected['Foo']['x-module-name'] = 'tests.conftest'
+    expected['Foo']['properties']['d']['x-module-name'] = 'tests.conftest'
     assert expected == SubSchemas.all_json_schemas(schema_type=SchemaType.SWAGGER_V3)
     expected = {
         'Point': POINT_SCHEMA,
@@ -441,9 +448,11 @@ def test_field_metadata():
     expected_full_schema = compose_schema(expected_schema)
     assert Test.json_schema() == expected_full_schema
     expected_schema['properties']['name']['x-field-group'] = 1
+    expected_schema['x-module-name'] = 'tests.test_core'
     assert Test.json_schema(schema_type=SchemaType.OPENAPI_3, embeddable=True) == {'Test': expected_schema}
     expected_schema['properties']['name']['example'] = 'foo'
     del expected_schema['properties']['name']['examples']
+    del expected_schema['x-module-name']
     assert Test.json_schema(schema_type=SchemaType.SWAGGER_V2, embeddable=True) == {'Test': expected_schema}
 
 
@@ -632,7 +641,8 @@ def test_nullable_field():
             "name": {"type": "string"},
             "manager": {"type": "string", "nullable": True}
         },
-        "required": ["name"]
+        "required": ["name"],
+        "x-module-name": "tests.test_core"
     }
     expected_json_schema = compose_schema({
         "type": "object",
@@ -696,7 +706,8 @@ def test_discriminators():
                 {
                     "type": "object",
                     "properties": {"breed": {"type": "string"}},
-                    "required": ["breed"]
+                    "required": ["breed"],
+                    "x-module-name": "tests.test_core",
                 },
             ]
         },
@@ -708,7 +719,8 @@ def test_discriminators():
                 "name": {"type": "string"}
             },
             "required": ["name", "PetType"],
-            "discriminator": {"propertyName": "PetType"}
+            "discriminator": {"propertyName": "PetType"},
+            "x-module-name": "tests.test_core",
         }
     }
 
@@ -951,3 +963,18 @@ def test_newtype_decoding():
 
     p = Pet.from_dict({'name': '  Fido ', 'type': 'dog'})
     assert p.name == 'Fido'
+
+
+def test_module_name_extension():
+    class PetType(Enum):
+        DOG = "dog"
+        CAT = "cat"
+
+    @dataclass
+    class Pet(JsonSchemaMixin):
+        name: str
+        type: PetType
+
+    schema = Pet.json_schema(embeddable=True, schema_type=SchemaType.OPENAPI_3)
+    assert schema['Pet']['x-module-name'] == 'tests.test_core'
+    assert schema['Pet']['properties']['type']['x-module-name'] == 'tests.test_core'