Repository: Materials-Consortia/optimade-python-tools

Issue:
server.jsonapi has no patternProperties 
In the current version of pydanitc patternProperties can only be added inside sub-elements of properties. If that is fixed then remove items from optimade.server.models.jsonapi.Attributes and optimade.server.models.jsonapi.Realationships and make it match that new formalism.

Somewhere in the creation of the openapi.json file the patternProperties is lost (likely something is using an old version of pydantic that converts a Dict object to object if the key is not a string).

Discussion:

Patch:
diff --git a/optimade/models/jsonapi.py b/optimade/models/jsonapi.py
index a6bbd197..80189d34 100644
--- a/optimade/models/jsonapi.py
+++ b/optimade/models/jsonapi.py
@@ -1,5 +1,5 @@
 """This module should reproduce JSON API v1.0 https://jsonapi.org/format/1.0/"""
-from typing import Optional, Set, Union
+from typing import Optional, Set, Union, Any
 from pydantic import BaseModel, UrlStr, Schema, validator
 
 
@@ -180,6 +180,13 @@ class Relationships(BaseModel):
         id
     """
 
+    id: Optional[Any] = Schema(..., description="Not allowed key")
+    type: Optional[Any] = Schema(..., description="Not allowed key")
+
+    @validator("id", "type")
+    def check_illegal_relationships_fields(cls, v):
+        raise AssertionError('"id", "type" MUST NOT be fields under relationships')
+
 
 class ResourceLinks(BaseModel):
     """A Resource Links object"""
@@ -193,16 +200,27 @@ class ResourceLinks(BaseModel):
 class Attributes(BaseModel):
     """
     Members of the attributes object ("attributes\") represent information about the resource object in which it's defined.
-    The keys for Attributes must NOT be:
+    The keys for Attributes MUST NOT be:
         relationships
         links
         id
         type
     """
 
+    relationships: Optional[Any] = Schema(..., description="Not allowed key")
+    links: Optional[Any] = Schema(..., description="Not allowed key")
+    id: Optional[Any] = Schema(..., description="Not allowed key")
+    type: Optional[Any] = Schema(..., description="Not allowed key")
+
     class Config:
         extra = "allow"
 
+    @validator("relationships", "links", "id", "type")
+    def check_illegal_attributes_fields(cls, v):
+        raise ValueError(
+            '"relationships", "links", "id", "type" MUST NOT be fields under attributes'
+        )
+
 
 class Resource(BaseResource):
     """Resource objects appear in a JSON:API document to represent resources."""
diff --git a/optimade/models/structures.py b/optimade/models/structures.py
index c24d2429..31f23b3f 100644
--- a/optimade/models/structures.py
+++ b/optimade/models/structures.py
@@ -621,7 +621,7 @@ class StructureResourceAttributes(EntryResourceAttributes):
 
     @validator("chemical_formula_reduced", "chemical_formula_hill")
     def no_spaces_in_reduced(cls, v):
-        if " " in v:
+        if v and " " in v:
             raise ValueError(f"Spaces are not allowed, you passed: {v}")
         return v
 


Test patch:
diff --git a/optimade/models/tests/test_bad_structures.json b/optimade/models/tests/test_bad_structures.json
index 99bcce98..fd9bf7ea 100644
--- a/optimade/models/tests/test_bad_structures.json
+++ b/optimade/models/tests/test_bad_structures.json
@@ -1494,5 +1494,73 @@
     ],
     "structure_features": ["assemblies"],
     "task_id": "mpf_276"
+  },
+  {
+    "_id": {
+      "$oid": "5cfb441f053b174410700d02"
+    },
+    "type": "structure",
+    "links": ["C-H"],
+    "relationships": "single",
+    "id": "some_id",
+    "_mp_chemsys": "Ac",
+    "cartesian_site_positions": [
+      [
+        0.17570227444196573,
+        0.17570227444196573,
+        0.17570227444196573
+      ]
+    ],
+    "dimension_types": [
+      1,
+      1,
+      1
+    ],
+    "elements": [
+      "Ac"
+    ],
+    "elements_ratios": [
+      1.0
+    ],
+    "formula_anonymous": "A",
+    "last_modified": {
+      "$date": "2019-06-08T05:13:37.331Z"
+    },
+    "lattice_vectors": [
+      [
+        1.2503264826932692,
+        0,
+        0
+      ],
+      [
+        0,
+        9.888509716321765,
+        0
+      ],
+      [
+        0,
+        0,
+        0.2972637673241818
+      ]
+    ],
+    "nelements": 1,
+    "nsites": 1,
+    "pretty_formula": "Ac",
+    "species": [
+      {
+        "chemical_symbols": [
+          "Ac"
+        ],
+        "concentration": [
+          1.0
+        ],
+        "name": "Ac"
+      }
+    ],
+    "species_at_sites": [
+      "Ac"
+    ],
+    "structure_features": [],
+    "task_id": "mpf_1"
   }
 ]