@@ -163,3 +163,134 @@ def checked(
163163 return method (ref , * args , ** kwargs )
164164
165165 return checked # type: ignore
166+
167+
168+ @define
169+ class FinalisableWrapperBasePtrBased (ABC ):
170+ """
171+ Base class for Fortran derived type wrappers using the pointer-based passing
172+ """
173+
174+ instance_ptr : int | None = None
175+ """
176+ Pointer to Fortran instance (technically a C pointer)
177+ """
178+
179+ def __str__ (self ) -> str :
180+ """
181+ Get string representation of self
182+ """
183+ return to_str (
184+ self ,
185+ self .exposed_attributes ,
186+ )
187+
188+ def _repr_pretty_ (self , p : Any , cycle : bool ) -> None :
189+ """
190+ Get pretty representation of self
191+
192+ Used by IPython notebooks and other tools
193+ """
194+ to_pretty (
195+ self ,
196+ self .exposed_attributes ,
197+ p = p ,
198+ cycle = cycle ,
199+ )
200+
201+ def _repr_html_ (self ) -> str :
202+ """
203+ Get html representation of self
204+
205+ Used by IPython notebooks and other tools
206+ """
207+ return to_html (
208+ self ,
209+ self .exposed_attributes ,
210+ )
211+
212+ @property
213+ def initialized (self ) -> bool :
214+ """
215+ Is the instance initialised, i.e. connected to a Fortran instance?
216+ """
217+ return self .instance_ptr is not None
218+
219+ @property
220+ @abstractmethod
221+ def exposed_attributes (self ) -> tuple [str , ...]:
222+ """
223+ Attributes exposed by this wrapper
224+ """
225+ ...
226+
227+ # TODO: consider whether we need these
228+ # @classmethod
229+ # @abstractmethod
230+ # def from_new_connection(cls) -> FinalisableWrapperBase:
231+ # """
232+ # Initialise by establishing a new connection with the Fortran module
233+ #
234+ # This requests a new model index from the Fortran module and then
235+ # initialises a class instance
236+ #
237+ # Returns
238+ # -------
239+ # New class instance
240+ # """
241+ # ...
242+ #
243+ # @abstractmethod
244+ # def finalize(self) -> None:
245+ # """
246+ # Finalise the Fortran instance and set self back to being uninitialised
247+ #
248+ # This method resets `self.instance_ptr` back to
249+ # `None`
250+ #
251+ # Should be decorated with :func:`check_initialised`
252+ # """
253+ # # call to Fortran module goes here when implementing
254+ # self._uninitialise_instance_index()
255+
256+ def _uninitialise_instance_index (self ) -> None :
257+ self .instance_index = None
258+
259+
260+ WrapperPtrBased = TypeVar ("WrapperPtrBased" , bound = FinalisableWrapperBasePtrBased )
261+
262+
263+ def check_initialised_ptr_based (
264+ method : Callable [Concatenate [WrapperPtrBased , P ], T ],
265+ ) -> Callable [Concatenate [WrapperPtrBased , P ], T ]:
266+ """
267+ Check that the wrapper object has been initialised before executing the method
268+
269+ Parameters
270+ ----------
271+ method
272+ Method to wrap
273+
274+ Returns
275+ -------
276+ :
277+ Wrapped method
278+
279+ Raises
280+ ------
281+ InitialisationError
282+ Wrapper is not initialised
283+ """
284+
285+ @wraps (method )
286+ def checked (
287+ ref : WrapperPtrBased ,
288+ * args : P .args ,
289+ ** kwargs : P .kwargs ,
290+ ) -> Any :
291+ if not ref .initialized :
292+ raise NotInitialisedError (ref , method )
293+
294+ return method (ref , * args , ** kwargs )
295+
296+ return checked # type: ignore
0 commit comments