From 96c016db0e98e999f4663ba2a011b4632b29e6e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Brunner?= <stephane.brunner@camptocamp.com>
Date: Mon, 15 Jan 2024 09:07:32 +0100
Subject: [PATCH] Add unused in the description

---
 jsonschema_gentypes/__init__.py               | 53 ++++++++++---------
 jsonschema_gentypes/api.py                    | 32 ++++++-----
 jsonschema_gentypes/api_draft_04.py           | 14 ++++-
 jsonschema_gentypes/api_draft_2020_12.py      |  2 +
 .../jsonschema_draft_2020_12.py               |  2 -
 .../jsonschema_draft_2020_12_meta_data.py     |  1 -
 .../jsonschema_draft_2020_12_validation.py    |  2 -
 tests/openapi3.py                             | 53 ++++++++++++++++++-
 tests/test_test.py                            | 18 ++++---
 9 files changed, 125 insertions(+), 52 deletions(-)

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]'''
     )