diff --git a/jsonschema_gentypes/__init__.py b/jsonschema_gentypes/__init__.py index 1e0e823a..f4287d9c 100644 --- a/jsonschema_gentypes/__init__.py +++ b/jsonschema_gentypes/__init__.py @@ -725,32 +725,33 @@ def get_description( result.append("") result += schema["description"].split("\n") first = True + used = cast(set[str], schema.get("used", set())) + used = { + *used, + "$schema", + "$id", + "type", + "used", + "required", + "$defs", + "definitions", + "properties", + } for key, value in schema.items(): - if ( - key not in schema.get("used", set()) # type: ignore[operator] - and key not in ("$schema", "$id", "type", "used") - and not isinstance(value, list) - and not isinstance(value, dict) - ): - if first: - if result: - result.append("") - first = False - result.append(f"{key}: {value}") - elif key in ( - "not", - "default", - "examples", - "contains", - "dependencies", - "propertyNames", - ): - if first: - if result: - result.append("") - first = False - result.append(f"{key}:") - lines = yaml.dump(value, Dumper=yaml.SafeDumper).split("\n") - result += [f" {line}" for line in lines if line] + if key not in used: + if not isinstance(value, (list, dict)): + if first: + if result: + result.append("") + first = False + result.append(f"{key}: {value}") + else: + if first: + if result: + result.append("") + first = False + result.append(f"{key}:") + lines = yaml.dump(value, Dumper=yaml.SafeDumper).split("\n") + result += [f" {line}" for line in lines if line] return result diff --git a/jsonschema_gentypes/api.py b/jsonschema_gentypes/api.py index 8aa8365f..38251977 100644 --- a/jsonschema_gentypes/api.py +++ b/jsonschema_gentypes/api.py @@ -236,6 +236,7 @@ def build_type( proposed_name = schema_meta_data.get("title", proposed_name) if "if" in schema: + schema.setdefault("used", set()).add("if") # type: ignore[typeddict-item] base_schema = cast( Union[ jsonschema_draft_04.JSONSchemaD4, jsonschema_draft_2020_12_applicator.JSONSchemaItemD2020 @@ -253,6 +254,7 @@ def build_type( {}, ) then_schema.update(base_schema) # type: ignore + schema.setdefault("used", set()).add("then") # type: ignore[typeddict-item] then_schema.update( self.resolve_ref( # type: ignore cast( @@ -267,8 +269,9 @@ def build_type( if "properties" not in then_schema: then_schema["properties"] = {} then_properties = then_schema["properties"] + then_schema.setdefault("used", set()).add("properties") # type: ignore[typeddict-item] assert then_properties - if_properties = self.resolve_ref( + if_schema = self.resolve_ref( cast( Union[ jsonschema_draft_04.JSONSchemaD4, @@ -276,7 +279,9 @@ def build_type( ], schema.get("if", {}), ) - ).get("properties", {}) + ) + if_schema.setdefault("used", set()).add("properties") # type: ignore[typeddict-item] + if_properties = if_schema.get("properties", {}) assert if_properties then_properties.update(if_properties) # type: ignore[arg-type] else_schema = cast( @@ -285,18 +290,19 @@ def build_type( ], {}, ) - else_schema.update(base_schema) # type: ignore - else_schema.update( - self.resolve_ref( # type: ignore - cast( - Union[ - jsonschema_draft_04.JSONSchemaD4, - jsonschema_draft_2020_12_applicator.JSONSchemaItemD2020, - ], - schema.get("else", {}), - ) + else_schema.update(base_schema) # type: ignore[typeddict-item] + schema.setdefault("used", set()).add("else") # type: ignore[typeddict-item] + original_else_schema = self.resolve_ref( + cast( + Union[ + jsonschema_draft_04.JSONSchemaD4, + jsonschema_draft_2020_12_applicator.JSONSchemaItemD2020, + ], + schema.get("else", {}), ) ) + else_schema.update(original_else_schema) # type: ignore[typeddict-item] + original_else_schema.setdefault("used", set()).add("properties") # type: ignore[typeddict-item] return CombinedType( NativeType("Union"), @@ -334,6 +340,7 @@ def build_type( "allof", ) if "anyOf" in schema: + schema.setdefault("used", set()).add("anyOf") # type: ignore[typeddict-item] type_ = self.any_of( schema, cast( @@ -355,6 +362,7 @@ def build_type( type_.comments().append("Aggregation type: anyOf") return type_ if "oneOf" in schema: + schema.setdefault("used", set()).add("oneOf") # type: ignore[typeddict-item] type_ = self.any_of( schema, cast( diff --git a/jsonschema_gentypes/api_draft_04.py b/jsonschema_gentypes/api_draft_04.py index ac138967..365d336c 100644 --- a/jsonschema_gentypes/api_draft_04.py +++ b/jsonschema_gentypes/api_draft_04.py @@ -41,6 +41,8 @@ def enum( """ Generate an enum. """ + schema.setdefault("used", set()).add("enum") # type: ignore[typeddict-item] + schema_meta_data = cast( Union[ jsonschema_draft_04.JSONSchemaD4, @@ -179,13 +181,17 @@ def array( """ Generate a ``List[]`` annotation with the allowed types. """ - schema.setdefault("used", set()).add("items") # type: ignore[typeddict-item] items = schema.get("items") if items is True: + schema.setdefault("used", set()).add("items") # type: ignore[typeddict-item] return CombinedType(NativeType("List"), [NativeType("Any")]) elif items is False: - raise NotImplementedError('"items": false is not supported') + result = NativeType("None") + result.set_comments(["`items: false` is not supported"]) + return result elif isinstance(items, list): + schema.setdefault("used", set()).add("items") # type: ignore[typeddict-item] + schema.setdefault("used", set()).add("additionalItems") # type: ignore[typeddict-item] additional_items = schema.get("additionalItems") if additional_items: items = [*items, additional_items] @@ -213,6 +219,7 @@ def array( ) return type_ elif items is not None: + schema.setdefault("used", set()).add("items") # type: ignore[typeddict-item] return CombinedType( NativeType("List"), [ @@ -229,6 +236,7 @@ def array( ], ) else: + schema.setdefault("used", set()).add("items") # type: ignore[typeddict-item] return CombinedType(NativeType("List"), [NativeType("Any")]) def any_of( @@ -298,6 +306,8 @@ def all_of( combined_schema: dict[str, Any] = {} if "properties" in new_schema and "properties" in all_schema: + all_schema.setdefault("used", set()).add("properties") + new_schema.setdefault("used", set()).add("properties") # type: ignore[typeddict-item] combined_schema["properties"] = { **all_schema["properties"], **new_schema["properties"], diff --git a/jsonschema_gentypes/api_draft_2020_12.py b/jsonschema_gentypes/api_draft_2020_12.py index 51b20af1..dff416f4 100644 --- a/jsonschema_gentypes/api_draft_2020_12.py +++ b/jsonschema_gentypes/api_draft_2020_12.py @@ -109,6 +109,7 @@ def array( if items is not None: all_items = [*all_items, items] if prefix_items is not None: + schema.setdefault("used", set()).add("prefixItems") # type: ignore[typeddict-item] inner_types = [ self.get_type( cast( @@ -133,6 +134,7 @@ def array( ) return type_ elif items is not None: + schema.setdefault("used", set()).add("items") # type: ignore[typeddict-item] return CombinedType( NativeType("List"), [ diff --git a/jsonschema_gentypes/jsonschema_draft_2020_12.py b/jsonschema_gentypes/jsonschema_draft_2020_12.py index 4a7d4c92..a9801fd6 100644 --- a/jsonschema_gentypes/jsonschema_draft_2020_12.py +++ b/jsonschema_gentypes/jsonschema_draft_2020_12.py @@ -107,7 +107,6 @@ # Aggregation type: anyOf "type": "_ContentVocabularyMetaSchemaObjectType", "const": Any, - # items: True "enum": list[Any], # exclusiveMinimum: 0 "multipleOf": Union[int, float], @@ -149,7 +148,6 @@ "readOnly": bool, # default: False "writeOnly": bool, - # items: True "examples": list[Any], "format": str, "contentEncoding": str, diff --git a/jsonschema_gentypes/jsonschema_draft_2020_12_meta_data.py b/jsonschema_gentypes/jsonschema_draft_2020_12_meta_data.py index c1233357..cc1279ce 100644 --- a/jsonschema_gentypes/jsonschema_draft_2020_12_meta_data.py +++ b/jsonschema_gentypes/jsonschema_draft_2020_12_meta_data.py @@ -20,7 +20,6 @@ class JSONSchemaItemD2020(TypedDict, total=False): """ default: False """ examples: list[Any] - """ items: True """ MetaDataVocabularyMetaSchema = Union["JSONSchemaItemD2020", bool] diff --git a/jsonschema_gentypes/jsonschema_draft_2020_12_validation.py b/jsonschema_gentypes/jsonschema_draft_2020_12_validation.py index aa4e91a0..a3888b72 100644 --- a/jsonschema_gentypes/jsonschema_draft_2020_12_validation.py +++ b/jsonschema_gentypes/jsonschema_draft_2020_12_validation.py @@ -15,8 +15,6 @@ class JSONSchemaItemD2020(TypedDict, total=False): const: Any enum: list[Any] - """ items: True """ - multipleOf: Union[int, float] """ exclusiveMinimum: 0 """ diff --git a/tests/openapi3.py b/tests/openapi3.py index f9892c80..f233ac29 100644 --- a/tests/openapi3.py +++ b/tests/openapi3.py @@ -168,7 +168,35 @@ class OgcapiCollectionsCollectionidGetResponse200(TypedDict, total=False): """ links: Required[list["_ComponentsSchemasLink"]] - """ Required property """ + """ + example: + - href: http://data.example.org/collections/dem?f=json + rel: self + title: Digital Elevation Model + type: application/json + - href: http://data.example.org/collections/dem?f=html + rel: alternate + title: Digital Elevation Model + type: application/json + - href: http://data.example.org/collections/dem/coverage + rel: coverage + title: Digital Elevation Model + type: image/tiff; application=geotiff + - href: http://data.example.org/collections/dem/coverage/domainset + rel: domainset + title: Digital Elevation Model + type: application/json + - href: http://data.example.org/collections/dem/coverage/rangetype + rel: rangetype + title: Digital Elevation Model + type: application/json + - href: http://data.example.org/collections/dem/coverage/metadata + rel: metadata + title: Digital Elevation Model + type: application/json + + Required property + """ extent: "ExtentWithUniformAdditionalDimensionsSchema" """ @@ -202,6 +230,9 @@ class OgcapiCollectionsCollectionidGetResponse200(TypedDict, total=False): default: - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + example: + - http://www.opengis.net/def/crs/OGC/1.3/CRS84 + - http://www.opengis.net/def/crs/EPSG/0/4326 """ dataType: "_Ogcapicollectionscollectionidgetresponse200Datatype" @@ -385,6 +416,14 @@ class _ExtentWithUniformAdditionalDimensionsSchemaSpatial(TypedDict, total=False server whether only a single spatial geometry property is used to determine the extent or all relevant geometries. +items: + type: number +example: + - -180 + - -90 + - 180 + - 90 + Aggregation type: oneOf """ @@ -438,6 +477,11 @@ class _ExtentWithUniformAdditionalDimensionsSchemaSpatialGridItem(TypedDict, tot (e.g., 2, 10, 80, 100). minItems: 1 + example: + - 2 + - 10 + - 80 + - 100 """ cellsCount: int @@ -517,6 +561,10 @@ class _ExtentWithUniformAdditionalDimensionsSchemaTemporalGrid(TypedDict, total= (e.g., "2017-11-14T09:00Z","2017-11-14T12:00Z","2017-11-14T15:00Z","2017-11-14T18:00Z","2017-11-14T21:00Z"). minItems: 1 + example: + - - 2020-11-12T12:15Z + - 2020-11-12T12:30Z + - 2020-11-12T12:45Z """ cellsCount: int @@ -560,6 +608,9 @@ class _ExtentWithUniformAdditionalDimensionsSchemaTemporalGrid(TypedDict, total= minItems: 2 maxItems: 2 +example: + - '2011-11-11T12:22:11Z' + - null """ diff --git a/tests/test_test.py b/tests/test_test.py index 275e36b7..698eb748 100644 --- a/tests/test_test.py +++ b/tests/test_test.py @@ -364,7 +364,7 @@ def test_pattern_properties_multiple(): type_ = get_types( { "type": "object", - "Title": "Pattern properties with tow patterns", + "title": "Pattern properties with tow patterns", "patternProperties": {"^[a-z]+$": {"type": "string"}, "^[0-9]+$": {"type": "number"}}, } ) @@ -372,8 +372,16 @@ def test_pattern_properties_multiple(): "\n".join([d.rstrip() for d in type_.definition(None)]) == ''' -_Base = Dict[str, Any] -""" Title: Pattern properties with tow patterns """ +PatternPropertiesWithTowPatterns = Dict[str, Any] +""" +Pattern properties with tow patterns. + +patternProperties: + ^[0-9]+$: + type: number + ^[a-z]+$: + type: string +""" ''' ) @@ -1053,9 +1061,7 @@ def test_array_true(): class TestBasicTypes(TypedDict, total=False): """ test basic types. """ - array: List[Any] - """ items: True """ -''' + array: List[Any]''' )