22
33from __future__ import annotations
44
5+ import importlib
56import logging
67from pathlib import Path
78from typing import TYPE_CHECKING
89
910import dlite
1011from optimade .adapters import Structure
11- from optimade .models import StructureResponseMany , StructureResponseOne , Success
12+ from optimade .models import (
13+ Response as OPTIMADEResponse ,
14+ )
15+ from optimade .models import (
16+ StructureResponseMany ,
17+ StructureResponseOne ,
18+ Success ,
19+ )
1220from oteapi .models import SessionUpdate
1321from oteapi_dlite .models import DLiteSessionUpdate
1422from oteapi_dlite .utils import get_collection , update_collection
@@ -89,7 +97,14 @@ def get(
8997 context from services.
9098
9199 """
92- session = OPTIMADEParseStrategy (self .parse_config ).get (session )
100+ generic_parse_config = self .parse_config .model_copy (
101+ update = {
102+ "mediaType" : self .parse_config .mediaType .lower ().replace (
103+ "+dlite" , "+json"
104+ )
105+ }
106+ ).model_dump ()
107+ session = OPTIMADEParseStrategy (generic_parse_config ).get (session )
93108
94109 entities_path = Path (__file__ ).resolve ().parent .resolve () / "entities"
95110
@@ -111,108 +126,117 @@ def get(
111126 f"yaml://{ entities_path } /OPTIMADEStructureSpecies.yaml"
112127 )
113128
129+ if not all (
130+ _ in session for _ in ("optimade_response" , "optimade_response_model" )
131+ ):
132+ base_error_message = (
133+ "Could not retrieve response from OPTIMADE parse strategy."
134+ )
135+ LOGGER .error (
136+ "%s\n "
137+ "optimade_response=%r\n "
138+ "optimade_response_model=%r\n "
139+ "session fields=%r" ,
140+ base_error_message ,
141+ session .get ("optimade_response" ),
142+ session .get ("optimade_response_model" ),
143+ list (session .keys ()),
144+ )
145+ raise OPTIMADEParseError (base_error_message )
146+
147+ optimade_response_model_module , optimade_response_model_name = session .get (
148+ "optimade_response_model"
149+ )
150+ optimade_response_dict = session .get ("optimade_response" )
151+
114152 error_message_supporting_only_structures = (
115153 "The DLite OPTIMADE Parser currently only supports structures entities."
116154 )
117155
118- if self .parse_config .configuration .return_object :
119- # The response is given as a "proper" pydantic data model instance
120-
121- if "optimade_response_object" not in session :
122- error_message = (
123- "'optimade_response_object' was expected to be present in the "
124- "session."
156+ # Parse response using the provided model
157+ try :
158+ optimade_response_model : type [OPTIMADEResponse ] = getattr (
159+ importlib .import_module (optimade_response_model_module ),
160+ optimade_response_model_name ,
161+ )
162+ optimade_response = optimade_response_model (** optimade_response_dict )
163+ except (ImportError , AttributeError ) as exc :
164+ base_error_message = "Could not import the response model."
165+ LOGGER .error (
166+ "%s\n "
167+ "ImportError: %s\n "
168+ "optimade_response_model_module=%r\n "
169+ "optimade_response_model_name=%r" ,
170+ base_error_message ,
171+ exc ,
172+ optimade_response_model_module ,
173+ optimade_response_model_name ,
174+ )
175+ raise OPTIMADEParseError (base_error_message ) from exc
176+ except ValidationError as exc :
177+ base_error_message = "Could not validate the response model."
178+ LOGGER .error (
179+ "%s\n "
180+ "ValidationError: %s\n "
181+ "optimade_response_model_module=%r\n "
182+ "optimade_response_model_name=%r" ,
183+ base_error_message ,
184+ exc ,
185+ optimade_response_model_module ,
186+ optimade_response_model_name ,
187+ )
188+ raise OPTIMADEParseError (base_error_message ) from exc
189+
190+ # Currently, only "structures" entries are supported and handled
191+ if isinstance (optimade_response , StructureResponseMany ):
192+ structures = [
193+ (
194+ Structure (entry )
195+ if isinstance (entry , dict )
196+ else Structure (entry .model_dump ())
125197 )
126- raise ValueError (error_message )
127-
128- # Currently, only "structures" entries are supported and handled
129- if isinstance (session .optimade_response_object , StructureResponseMany ):
198+ for entry in optimade_response .data
199+ ]
200+ elif isinstance (optimade_response , StructureResponseOne ):
201+ structures = [
202+ (
203+ Structure (optimade_response .data )
204+ if isinstance (optimade_response .data , dict )
205+ else Structure (optimade_response .data .model_dump ())
206+ )
207+ ]
208+ elif isinstance (optimade_response , Success ):
209+ if isinstance (optimade_response .data , dict ):
210+ structures = [Structure (optimade_response .data )]
211+ elif isinstance (optimade_response .data , BaseModel ):
212+ structures = [Structure (optimade_response .data .model_dump ())]
213+ elif isinstance (optimade_response .data , list ):
130214 structures = [
131215 (
132216 Structure (entry )
133217 if isinstance (entry , dict )
134- else Structure (entry .dict ())
218+ else Structure (entry .model_dump ())
135219 )
136- for entry in session . optimade_response_object .data
220+ for entry in optimade_response .data
137221 ]
138- elif isinstance (session .optimade_response_object , StructureResponseOne ):
139- structures = [
140- (
141- Structure (session .optimade_response_object .data )
142- if isinstance (session .optimade_response_object .data , dict )
143- else Structure (session .optimade_response_object .data .dict ())
144- )
145- ]
146- elif isinstance (session .optimade_response_object , Success ):
147- if isinstance (session .optimade_response_object .data , dict ):
148- structures = [Structure (session .optimade_response_object .data )]
149- elif isinstance (session .optimade_response_object .data , BaseModel ):
150- structures = [
151- Structure (session .optimade_response_object .data .dict ())
152- ]
153- elif isinstance (session .optimade_response_object .data , list ):
154- structures = [
155- (
156- Structure (entry )
157- if isinstance (entry , dict )
158- else Structure (entry .dict ())
159- )
160- for entry in session .optimade_response_object .data
161- ]
162- else :
163- LOGGER .debug (
164- "Could not determine what to do with `data`. Type %s." ,
165- type (session .optimade_response_object .data ),
166- )
167- error_message = "Could not parse `data` entry in response."
168- raise OPTIMADEParseError (error_message )
169222 else :
170- LOGGER .debug (
171- "Got currently unsupported response type %s. Only structures are "
172- "supported." ,
173- session .optimade_response_object .__class__ .__name__ ,
223+ LOGGER .error (
224+ "Could not determine what to do with `data`. Type %s." ,
225+ type (optimade_response .data ),
174226 )
175- raise OPTIMADEParseError (error_message_supporting_only_structures )
227+ error_message = "Could not parse `data` entry in response."
228+ raise OPTIMADEParseError (error_message )
176229 else :
177- # The response is given as pure Python dictionary
178-
179- if "optimade_response" not in session :
180- error_message = (
181- "'optimade_response' was expected to be present in the session."
182- )
183- raise ValueError (error_message )
184-
185- if not session .optimade_response or "data" not in session .optimade_response :
186- LOGGER .debug ("Not a successful response - no 'data' entry found." )
187- return session
188-
189- if isinstance (session .optimade_response ["data" ], list ):
190- try :
191- structures = [
192- Structure (entry ) for entry in session .optimade_response ["data" ]
193- ]
194- except ValidationError as exc :
195- LOGGER .debug (
196- "Could not parse list of 'data' entries as structures."
197- )
198- raise OPTIMADEParseError (
199- error_message_supporting_only_structures
200- ) from exc
201- elif session .optimade_response is not None :
202- try :
203- structures = [Structure (session .optimade_response ["data" ])]
204- except ValidationError as exc :
205- LOGGER .debug ("Could not parse single 'data' entry as a structure." )
206- raise OPTIMADEParseError (
207- error_message_supporting_only_structures
208- ) from exc
209- else :
210- LOGGER .debug ("Could not parse 'data' entries as structures." ) # type: ignore[unreachable]
211- raise OPTIMADEParseError (error_message_supporting_only_structures )
230+ LOGGER .error (
231+ "Got currently unsupported response type %s. Only structures are "
232+ "supported." ,
233+ optimade_response_model_name ,
234+ )
235+ raise OPTIMADEParseError (error_message_supporting_only_structures )
212236
237+ # DLite-fy OPTIMADE structures
213238 dlite_collection = get_collection (session )
214239
215- # DLite-fy OPTIMADE structures
216240 for structure in structures :
217241 new_structure_attributes : dict [str , Any ] = {}
218242
@@ -226,7 +250,7 @@ def get(
226250 for assembly in structure .attributes .assemblies :
227251 # Ensure we're dealing with a normal Python dict
228252 assembly_dict = (
229- assembly .dict (exclude_none = True )
253+ assembly .model_dump (exclude_none = True )
230254 if isinstance (assembly , BaseModel )
231255 else assembly
232256 )
@@ -252,7 +276,7 @@ def get(
252276 for species_individual in structure .attributes .species :
253277 # Ensure we're dealing with a normal Python dict
254278 species_individual_dict = (
255- species_individual .dict (exclude_none = True )
279+ species_individual .model_dump (exclude_none = True )
256280 if isinstance (species_individual , BaseModel )
257281 else species_individual
258282 )
@@ -274,7 +298,7 @@ def get(
274298
275299 # Attributes
276300 new_structure_attributes .update (
277- structure .attributes .dict (
301+ structure .attributes .model_dump (
278302 exclude = {"species" , "assemblies" , "nelements" , "nsites" }
279303 )
280304 )
0 commit comments