def test_custom_schema(settings): with pytest.raises(AssertionError, match="Unsupported"): create_schema(CustomField, {}) settings.REACTIVATED_SERIALIZATION = "tests.types.custom_schema" create_schema(CustomField, {}) == ({"type": "string"}, {})
def test_override_pick_types(settings): settings.INSTALLED_APPS = ["tests.serialization"] test_apps = Apps(settings.INSTALLED_APPS) class TestModel(Model): forced_nullable: Optional[int] = IntegerField() forced_non_nullable: int = IntegerField(null=True) forced_none: None = IntegerField() class Meta: apps = test_apps Picked = Pick[TestModel, "forced_nullable", "forced_non_nullable", "forced_none"] assert create_schema(Picked, {}).schema == { "type": "object", "additionalProperties": False, "properties": { "forced_nullable": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "forced_non_nullable": { "type": "number" }, "forced_none": { "type": "null" }, }, "required": ["forced_nullable", "forced_non_nullable", "forced_none"], }
def test_named_tuple(): assert create_schema(NamedTupleType, {}) == ( { "$ref": "#/definitions/tests.types.NamedTupleType" }, { "tests.types.NamedTupleType": { "additionalProperties": False, "properties": { "first": { "type": "string" }, "second": { "type": "boolean" }, "third": { "type": "number" }, "fourth_as_property": { "type": "number" }, }, "required": ["first", "second", "third", "fourth_as_property"], "serializer": None, "type": "object", } }, )
def test_typed_dict(): assert create_schema(TypedDictType, {}) == ( { "$ref": "#/definitions/tests.types.TypedDictType" }, { "tests.types.TypedDictType": { "additionalProperties": False, "properties": { "first": { "type": "string" }, "second": { "type": "boolean" }, "third": { "type": "number" }, }, "required": ["first", "second", "third"], "serializer": None, "type": "object", } }, )
def test_form_set(): schema = create_schema(forms.OperaFormSet, {}) assert schema.schema == { "$ref": "#/definitions/django.forms.formsets.OperaFormFormSet" } # Ensure the children of the child form are serialized by passing # definitions around without mutating. assert "sample.server.apps.samples.models.Opera.Style" in schema.definitions
def test_subwidget(): class SubwidgetForm(django_forms.Form): date_field = django_forms.DateField( widget=django_forms.SelectDateWidget) generated_schema = create_schema(SubwidgetForm, {}) form = SubwidgetForm() serialized_form = serialize(form, generated_schema) convert_to_json_and_validate(serialized_form, generated_schema)
def test_open_tuple(): assert create_schema(Tuple[str, ...], {}) == ( { "items": { "type": "string" }, "type": "array" }, {}, )
def test_list(): assert create_schema(List[str], {}) == ( { "type": "array", "items": { "type": "string" } }, {}, )
def test_form(): generated_schema = create_schema(forms.OperaForm, {}) form = forms.OperaForm() serialized_form = serialize(form, generated_schema) convert_to_json_and_validate(serialized_form, generated_schema) form_with_errors = forms.OperaForm({}) form_with_errors.is_valid() serialized_form = serialize(form_with_errors, generated_schema) assert "name" in serialized_form.errors convert_to_json_and_validate(serialized_form, generated_schema)
def test_dict(): assert create_schema(Dict[str, Any], {}) == ( { "type": "object", "properties": {}, "additionalProperties": {} }, {}, ) assert create_schema(Dict[str, str], {}) == ( { "type": "object", "properties": {}, "additionalProperties": { "type": "string" }, }, {}, )
def test_empty_form(): class EmptyForm(django_forms.Form): pass assert create_schema( EmptyForm, {}).definitions["tests.types.test_empty_form.<locals>.EmptyForm"][ "properties"]["iterator"] == { "items": [], "type": "array" }
def test_widget_inheritance(): class WidgetMixin: pass class ChildWidget(WidgetMixin, django_forms.TextInput): pass class FormWithChildWidget(django_forms.Form): my_field = django_forms.CharField(widget=ChildWidget) # No error, depth-1 inheritance. create_schema(FormWithChildWidget, {}) class GrandchildWidget(ChildWidget): pass class FormWithGrandchildWidget(django_forms.Form): my_field = django_forms.CharField(widget=GrandchildWidget) with pytest.raises(AssertionError, match="depth-1"): create_schema(FormWithGrandchildWidget, {})
def test_literal(): schema = create_schema(Literal["hello"], {}) assert schema == ( { "type": "string", "enum": [ "hello", ], }, {}, ) convert_to_json_and_validate("hello", schema)
def test_custom_widget(): class CustomWidget(django_forms.Select): reactivated_widget = "foo" class CustomForm(django_forms.Form): field = django_forms.CharField(widget=CustomWidget) generated_schema = create_schema(CustomForm, {}) form = CustomForm() serialized_form = serialize(form, generated_schema) convert_to_json_and_validate(serialized_form, generated_schema) assert serialized_form.fields["field"].widget["template_name"] == "foo"
def test_enum(): assert create_schema(EnumType, {}) == ( { "$ref": "#/definitions/tests.types.EnumType" }, { "tests.types.EnumType": { "type": "string", "enum": ["ONE", "TWO", "CHUNK"], "serializer": "reactivated.serialization.EnumMemberType", } }, )
def test_fixed_tuple(): assert create_schema(Tuple[str, str], {}) == ( { "items": [{ "type": "string" }, { "type": "string" }], "minItems": 2, "maxItems": 2, "type": "array", }, {}, )
def test_enum_field_descriptor(): descriptor = EnumField(enum=EnumType) assert create_schema(descriptor, {}) == ( { "$ref": "#/definitions/tests.types.EnumType" }, { "tests.types.EnumType": { "type": "string", "enum": ["ONE", "TWO", "CHUNK"], "serializer": "reactivated.serialization.EnumMemberType", } }, )
def test_enum_type(): assert create_schema(Type[EnumType], {}) == ( { "$ref": "#/definitions/tests.types.EnumTypeEnumType" }, { "tests.types.EnumTypeEnumType": { "additionalProperties": False, "properties": { "CHUNK": { "$ref": "#/definitions/tests.types.NamedTupleType", "serializer": "reactivated.serialization.EnumValueType", }, "ONE": { "serializer": "reactivated.serialization.EnumValueType", "type": "string", }, "TWO": { "serializer": "reactivated.serialization.EnumValueType", "type": "string", }, }, "required": ["ONE", "TWO", "CHUNK"], "type": "object", }, "tests.types.NamedTupleType": { "additionalProperties": False, "properties": { "first": { "type": "string" }, "fourth_as_property": { "type": "number" }, "second": { "type": "boolean" }, "third": { "type": "number" }, }, "required": ["first", "second", "third", "fourth_as_property"], "serializer": None, "type": "object", }, }, )
def test_form_set(): generated_schema = create_schema(forms.OperaFormSet, {}) form_set = forms.OperaFormSet() serialized_form_set = serialize(form_set, generated_schema) convert_to_json_and_validate(serialized_form_set, generated_schema) form_set_with_errors = forms.OperaFormSet({ "form-TOTAL_FORMS": 20, "form-INITIAL_FORMS": 0 }) form_set_with_errors.is_valid() serialized_form_set = serialize(form_set_with_errors, generated_schema) assert "name" in serialized_form_set["forms"][0]["errors"] convert_to_json_and_validate(serialized_form_set, generated_schema)
def test_form_with_model_choice_iterator_value(): models.Country.objects.create( name="USA", continent=models.Continent.objects.create(name="America", hemisphere="NORTHERN"), ) iterator = (forms.ComposerForm().fields["countries"].widget.optgroups( "countries", "")[0][1][0]["value"]) assert isinstance(iterator, ModelChoiceIteratorValue) generated_schema = create_schema(forms.ComposerForm, {}) form = forms.ComposerForm() serialized_form = serialize(form, generated_schema) import pprint pprint.pprint(generated_schema.dereference()) convert_to_json_and_validate(serialized_form, generated_schema) assert serialized_form["fields"]["countries"]["widget"]["optgroups"][0][1][ 0]["value"] == str(iterator.value)
def test_typed_choices_non_enum(settings): settings.INSTALLED_APPS = ["tests.serialization"] test_apps = Apps(settings.INSTALLED_APPS) class TestModel(Model): non_enum_typed_field = IntegerField(choices=((0, "Zero"), (1, "One"))) class Meta: apps = test_apps class TestForm(django_forms.ModelForm): class Meta: model = TestModel fields = "__all__" generated_schema = create_schema(TestForm, {}) assert generated_schema.definitions[ "tests.serialization.test_typed_choices_non_enum.<locals>.TestForm"][ "properties"]["fields"]["properties"]["non_enum_typed_field"][ "properties"]["widget"] == { "tsType": "widgets.Select" }
def test_deferred_evaluation_of_types(settings): settings.INSTALLED_APPS = ["tests.serialization"] test_apps = Apps(settings.INSTALLED_APPS) class TestModel(Model): deferred_field: DoesNotExist = IntegerField() @property def bar(self) -> DoesNotExist: assert False @classmethod def resolve_type_hints(cls): return { "DoesNotExist": bool, } class Meta: apps = test_apps Picked = Pick[TestModel, "bar", "deferred_field"] assert create_schema(Picked, {}).schema == { "type": "object", "additionalProperties": False, "properties": { "bar": { "type": "boolean", "serializer": "reactivated.serialization.ComputedField", }, "deferred_field": { "type": "boolean" }, }, "required": ["bar", "deferred_field"], }
def test_none(): assert create_schema(type(None), {}) == ({"type": "null"}, {})
def custom_schema(Type, definitions): if issubclass(Type, CustomField): return create_schema(str, definitions) return None
def test_form(): schema = create_schema(forms.OperaForm, {}) assert schema.schema == { "$ref": "#/definitions/sample.server.apps.samples.forms.OperaForm" } assert schema.definitions["sample.server.apps.samples.forms.OperaForm"] == { "additionalProperties": False, "properties": { "name": { "enum": ["sample.server.apps.samples.forms.OperaForm"], "type": "string", }, "errors": { "anyOf": [ { "additionalProperties": False, "properties": { "composer": { "items": { "type": "string" }, "type": "array" }, "has_piano_transcription": { "items": { "type": "string" }, "type": "array", }, "name": { "items": { "type": "string" }, "type": "array" }, "style": { "items": { "type": "string" }, "type": "array" }, }, "type": "object", }, { "type": "null" }, ] }, "fields": { "additionalProperties": False, "properties": { "composer": { "additionalProperties": False, "properties": { "help_text": { "type": "string" }, "label": { "type": "string" }, "name": { "type": "string" }, "widget": { "tsType": "widgets.Select" }, }, "required": ["name", "label", "help_text", "widget"], "serializer": "field_serializer", "type": "object", }, "has_piano_transcription": { "additionalProperties": False, "properties": { "help_text": { "type": "string" }, "label": { "type": "string" }, "name": { "type": "string" }, "widget": { "tsType": "widgets.CheckboxInput" }, }, "required": ["name", "label", "help_text", "widget"], "serializer": "field_serializer", "type": "object", }, "name": { "additionalProperties": False, "properties": { "help_text": { "type": "string" }, "label": { "type": "string" }, "name": { "type": "string" }, "widget": { "tsType": "widgets.TextInput" }, }, "required": ["name", "label", "help_text", "widget"], "serializer": "field_serializer", "type": "object", }, "style": { "additionalProperties": False, "properties": { "help_text": { "type": "string" }, "label": { "type": "string" }, "name": { "type": "string" }, "widget": { "tsType": 'widgets.Select<Types["globals"]["SampleServerAppsSamplesModelsOperaStyle"]>' }, }, "required": ["name", "label", "help_text", "widget"], "serializer": "field_serializer", "type": "object", }, }, "required": ["name", "composer", "style", "has_piano_transcription"], "type": "object", }, "iterator": { "items": { "enum": ["name", "composer", "style", "has_piano_transcription"], "type": "string", }, "type": "array", }, "prefix": { "type": "string" }, }, "required": ["name", "prefix", "fields", "iterator", "errors"], "serializer": "reactivated.serialization.FormType", "type": "object", }
def test_enum_does_not_clobber_enum_type(): schema = create_schema(EnumType, {}) schema = create_schema(Type[EnumType], schema.definitions) assert "tests.types.EnumType" in schema.definitions assert "tests.types.EnumTypeEnumType" in schema.definitions
def test_context_processor_type(): with pytest.raises(AssertionError, match="No annotations found"): ContextProcessorType = create_context_processor_type( ["tests.types.sample_unannotated_context_processor"]) context_processors = [ "django.template.context_processors.request", "tests.types.sample_context_processor_one", "tests.types.sample_context_processor_two", ] ContextProcessorType = create_context_processor_type(context_processors) schema, definitions = create_schema(ContextProcessorType, {}) assert schema == { "allOf": [ { "$ref": "#/definitions/reactivated.serialization.context_processors.BaseContext" }, { "$ref": "#/definitions/reactivated.serialization.context_processors.RequestProcessor" }, { "$ref": "#/definitions/tests.types.SampleContextOne" }, { "$ref": "#/definitions/tests.types.SampleContextTwo" }, ] } assert definitions == { "reactivated.serialization.context_processors.BaseContext": { "serializer": None, "type": "object", "additionalProperties": False, "properties": { "template_name": { "type": "string" } }, "required": ["template_name"], }, "reactivated.serialization.context_processors.Request": { "serializer": "reactivated.serialization.context_processors.Request", "type": "object", "additionalProperties": False, "properties": { "path": { "type": "string" }, "url": { "type": "string" } }, "required": ["path", "url"], }, "reactivated.serialization.context_processors.RequestProcessor": { "serializer": None, "type": "object", "additionalProperties": False, "properties": { "request": { "$ref": "#/definitions/reactivated.serialization.context_processors.Request" } }, "required": ["request"], }, "tests.types.ComplexType": { "serializer": None, "type": "object", "additionalProperties": False, "properties": { "required": { "type": "number" }, "optional": { "anyOf": [{ "type": "boolean" }, { "type": "null" }] }, }, "required": ["required", "optional"], }, "tests.types.SampleContextOne": { "serializer": None, "type": "object", "additionalProperties": False, "properties": { "complex": { "$ref": "#/definitions/tests.types.ComplexType" }, "boolean": { "type": "boolean" }, }, "required": ["complex", "boolean"], }, "tests.types.SampleContextTwo": { "serializer": None, "type": "object", "additionalProperties": False, "properties": { "number": { "type": "number" } }, "required": ["number"], }, }
def test_float(): assert create_schema(float, {}) == ({"type": "number"}, {})
def test_int(): assert create_schema(int, {}) == ({"type": "number"}, {})
import subprocess import simplejson from reactivated.serialization import create_schema from reactivated.types import Types types_schema = create_schema(Types, {}) schema = simplejson.dumps({ "title": "Types", "definitions": types_schema.definitions, **types_schema.dereference(), }) encoded_schema = schema.encode() process = subprocess.Popen( ["./packages/reactivated/node_modules/.bin/json2ts"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, ) out, error = process.communicate(encoded_schema) with open("packages/reactivated/generated.tsx", "w+b") as output: output.write(out)