Source code for sdmx.writer.base

from functools import singledispatch


[docs]class BaseWriter: """Base class for recursive writers. Usage: - Create an instance of this class. - Use :meth:`register` in the same manner as Python's built-in :func:`functools.singledispatch` to decorate functions that certain types of :mod:`sdmx.model` or :mod:`sdmx.message` objects. - Call :meth:`recurse` to kick off recursive writing of objects, including from inside other functions. Example ------- >>> MyWriter = BaseWriter('my') >>> @MyWriter.register >>> def _(obj: sdmx.model.ItemScheme): >>> ... code to write an ItemScheme ... >>> return result >>> @MyWriter.register >>> def _(obj: sdmx.model.Codelist): >>> ... code to write a Codelist ... >>> return result """ def __init__(self, format_name): # Create the single-dispatch function @singledispatch def func(obj, *args, **kwargs): raise NotImplementedError( f"write {obj.__class__.__name__} to " f"{format_name}" ) self._dispatcher = func
[docs] def recurse(self, obj, *args, **kwargs): """Recursively write *obj*. If there is no :meth:`register` 'ed function to write the class of `obj`, then the parent class of `obj` is used to find a method. """ # TODO use a cache to speed up, so the MRO does not need to be traversed for # every object instance dispatcher = getattr(self, "_dispatcher") try: # Let the single dispatch function choose the overload return dispatcher(obj, *args, **kwargs) except NotImplementedError as exc: try: # Use the object's parent class to get a different overload func = dispatcher.registry[obj.__class__.mro()[1]] except KeyError: # Overload for the parent class did not exist raise exc return func(obj, *args, **kwargs)
def __call__(self, func): """Register *func* as a writer for a particular object type.""" dispatcher = getattr(self, "_dispatcher") dispatcher.register(func) return func