44import functools
55from decimal import Decimal
66from ipaddress import IPv4Address , IPv6Address
7- from typing import Optional , Type , Union , Any , Dict , Tuple , List , TypeVar , get_type_hints , Callable
7+ from typing import Optional , Type , Union , Any , Dict , Tuple , List , Callable , TypeVar
88import re
99from datetime import datetime , date
1010from dataclasses import fields , is_dataclass , Field , MISSING , dataclass , asdict
1818 from typing_extensions import Final , Literal # type: ignore
1919
2020
21- from dataclasses_jsonschema .field_types import ( # noqa: F401
21+ from .field_types import ( # noqa: F401
2222 FieldEncoder , DateFieldEncoder , DateTimeFieldEncoder , UuidField , DecimalField ,
23- IPv4AddressField , IPv6AddressField , DateTimeField
23+ IPv4AddressField , IPv6AddressField , DateTimeField , UUID_REGEX
2424)
25- from dataclasses_jsonschema .type_defs import JsonDict , SchemaType , JsonSchemaMeta , _NULL_TYPE , NULL # noqa: F401
25+ from .type_defs import JsonDict , SchemaType , JsonSchemaMeta , _NULL_TYPE , NULL # noqa: F401
26+ from .type_hints import get_class_type_hints
2627
2728try :
2829 import fastjsonschema
@@ -46,8 +47,12 @@ def validate_func(data, schema):
4647SEQUENCE_TYPES = {
4748 'Sequence' : list ,
4849 'List' : list ,
49- 'Set' : set
50+ 'Set' : set ,
51+ 'set' : set ,
52+ 'list' : list
5053}
54+ MAPPING_TYPES = ('Dict' , 'Mapping' , 'dict' )
55+ TUPLE_TYPES = ('Tuple' , 'tuple' )
5156
5257
5358class ValidationError (Exception ):
@@ -310,15 +315,15 @@ def encoder(_, v, __):
310315 if encoded is None :
311316 raise TypeError ("No variant of '{}' matched the type '{}'" .format (field_type , type (value )))
312317 return encoded
313- elif field_type_name in ( 'Mapping' , 'Dict' ) :
318+ elif field_type_name in MAPPING_TYPES :
314319 def encoder (ft , val , o ):
315320 return {
316321 cls ._encode_field (ft .__args__ [0 ], k , o ): cls ._encode_field (ft .__args__ [1 ], v , o )
317322 for k , v in val .items ()
318323 }
319- elif field_type_name in SEQUENCE_TYPES or (field_type_name == "Tuple" and ... in field_type .__args__ ):
324+ elif field_type_name in SEQUENCE_TYPES or (field_type_name in TUPLE_TYPES and ... in field_type .__args__ ):
320325 def encoder (ft , val , o ): return [cls ._encode_field (ft .__args__ [0 ], v , o ) for v in val ]
321- elif field_type_name == 'Tuple' :
326+ elif field_type_name in TUPLE_TYPES :
322327 def encoder (ft , val , o ):
323328 return [cls ._encode_field (ft .__args__ [idx ], v , o ) for idx , v in enumerate (val )]
324329 elif cls ._is_json_schema_subclass (field_type ):
@@ -344,7 +349,7 @@ def _get_fields_uncached():
344349 base_fields_types |= {(f .name , f .type ) for f in fields (base )}
345350
346351 mapped_fields = []
347- type_hints = get_type_hints (cls )
352+ type_hints = get_class_type_hints (cls )
348353 for f in fields (cls ):
349354 # Skip internal fields
350355 if f .name .startswith ("__" ) or (not base_fields and (f .name , f .type ) in base_fields_types ):
@@ -433,18 +438,18 @@ def decoder(f, ft, val): return cls._decode_field(f, unwrap_final(ft), val)
433438 continue
434439 if decoded is not None :
435440 return decoded
436- elif field_type_name in ( 'Mapping' , 'Dict' ) :
441+ elif field_type_name in MAPPING_TYPES :
437442 def decoder (f , ft , val ):
438443 return {
439444 cls ._decode_field (f , ft .__args__ [0 ], k ): cls ._decode_field (f , ft .__args__ [1 ], v )
440445 for k , v in val .items ()
441446 }
442- elif field_type_name in SEQUENCE_TYPES or (field_type_name == "Tuple" and ... in field_type .__args__ ):
443- seq_type = tuple if field_type_name == "Tuple" else SEQUENCE_TYPES [field_type_name ]
447+ elif field_type_name in SEQUENCE_TYPES or (field_type_name in TUPLE_TYPES and ... in field_type .__args__ ):
448+ seq_type = tuple if field_type_name in TUPLE_TYPES else SEQUENCE_TYPES [field_type_name ]
444449
445450 def decoder (f , ft , val ):
446451 return seq_type (cls ._decode_field (f , ft .__args__ [0 ], v ) for v in val )
447- elif field_type_name == "Tuple" :
452+ elif field_type_name in TUPLE_TYPES :
448453 def decoder (f , ft , val ):
449454 return tuple (cls ._decode_field (f , ft .__args__ [idx ], v ) for idx , v in enumerate (val ))
450455 elif field_type in cls ._field_encoders :
@@ -469,7 +474,9 @@ def _validate(cls, data: JsonDict, validate_enums: bool = True):
469474 # TODO: Support validating with other schema types
470475 schema_validator = cls .__compiled_schema .get (SchemaOptions (DEFAULT_SCHEMA_TYPE , validate_enums ))
471476 if schema_validator is None :
472- schema_validator = fastjsonschema .compile (cls .json_schema (validate_enums = validate_enums ))
477+ schema_validator = fastjsonschema .compile (
478+ cls .json_schema (validate_enums = validate_enums ), formats = {'uuid' : UUID_REGEX }
479+ )
473480 cls .__compiled_schema [SchemaOptions (DEFAULT_SCHEMA_TYPE , validate_enums )] = schema_validator
474481 schema_validator (data )
475482 else :
@@ -545,7 +552,7 @@ def from_object(cls: Type[T], obj: Any, exclude: FieldExcludeList = tuple()) ->
545552 values [f .field .name ] = ft .from_object (from_value , exclude = sub_exclude )
546553 elif is_enum (ft ):
547554 values [f .field .name ] = ft (from_value )
548- elif field_type_name == "List" and cls ._is_json_schema_subclass (ft .__args__ [0 ]):
555+ elif field_type_name in ( "List" , "list" ) and cls ._is_json_schema_subclass (ft .__args__ [0 ]):
549556 values [f .field .name ] = [
550557 ft .__args__ [0 ].from_object (v , exclude = sub_exclude ) for v in from_value
551558 ]
@@ -653,19 +660,19 @@ def _get_field_schema(cls, field: Union[Field, Type], schema_options: SchemaOpti
653660 field_schema = {
654661 'oneOf' : [cls ._get_field_schema (variant , schema_options )[0 ] for variant in field_type .__args__ ]
655662 }
656- elif field_type_name in ( 'Dict' , 'Mapping' ) :
663+ elif field_type_name in MAPPING_TYPES :
657664 field_schema = {'type' : 'object' }
658665 if field_type .__args__ [1 ] is not Any :
659666 field_schema ['additionalProperties' ] = cls ._get_field_schema (
660667 field_type .__args__ [1 ], schema_options
661668 )[0 ]
662- elif field_type_name in SEQUENCE_TYPES or (field_type_name == "Tuple" and ... in field_type .__args__ ):
669+ elif field_type_name in SEQUENCE_TYPES or (field_type_name in TUPLE_TYPES and ... in field_type .__args__ ):
663670 field_schema = {'type' : 'array' }
664671 if field_type .__args__ [0 ] is not Any :
665672 field_schema ['items' ] = cls ._get_field_schema (field_type .__args__ [0 ], schema_options )[0 ]
666- if field_type_name == "Set" :
673+ if field_type_name in ( "Set" , "set" ) :
667674 field_schema ['uniqueItems' ] = True
668- elif field_type_name == "Tuple" :
675+ elif field_type_name in TUPLE_TYPES :
669676 tuple_len = len (field_type .__args__ )
670677 # TODO: How do we handle Optional type within lists / tuples
671678 field_schema = {
@@ -691,9 +698,9 @@ def _get_field_definitions(cls, field_type: Any, definitions: JsonDict,
691698 field_type_name = cls ._get_field_type_name (field_type )
692699 if is_optional (field_type ):
693700 cls ._get_field_definitions (unwrap_optional (field_type ), definitions , schema_options )
694- elif field_type_name in ( 'Sequence' , 'List' , 'Tuple' ) :
701+ elif field_type_name in SEQUENCE_TYPES :
695702 cls ._get_field_definitions (field_type .__args__ [0 ], definitions , schema_options )
696- elif field_type_name in ( 'Dict' , 'Mapping' ) :
703+ elif field_type_name in MAPPING_TYPES :
697704 cls ._get_field_definitions (field_type .__args__ [1 ], definitions , schema_options )
698705 elif field_type_name == 'Union' :
699706 for variant in field_type .__args__ :
@@ -760,7 +767,7 @@ def json_schema(
760767 else :
761768 definitions = cls .__definitions [schema_options ]
762769
763- if cls . __schema is not None and schema_options in cls .__schema :
770+ if schema_options in cls .__schema :
764771 schema = cls .__schema [schema_options ]
765772 else :
766773 properties = {}
0 commit comments