eoio.writers package#

eoio.writers - dataset writers

Writers serialise an xarray Dataset or DataTree to a file format. They are selected explicitly by name rather than inferred from the output path:

from eoio.writers import WriterFactory

writer_cls = WriterFactory.get_writer("netcdf")
writer_cls().write(ds, "output.nc")

See docs/content/developer_guide/writers/writers.rst for how to add one.

class eoio.writers.BaseWriter(write_params: Dict[str, Any] | None = None)[source]#

Bases: ABC

Base class for eoio writers.

This class is intentionally small. It owns: - config merge/validation - a single public entrypoint: write() - the orchestration common to every format: capability check, conformance check,

provenance, attribute encoding

Concrete writers implement write_dataset() and get_extension().

property all_options: Dict[str, Any]#

Return the available options for this writer.

Returns:

Dictionary of available write parameters.

all_write_params: Dict[str, str] = {'create_parents': 'True/False', 'encode_attrs': 'True/False', 'on_nonconformance': 'warn/error/ignore', 'update_history': 'True/False'}#
can_write(obj: Any) → WriteCapability[source]#

Report whether this writer can express obj.

The default accepts any Dataset or DataTree, which is correct for general-purpose formats: anything expressible in xarray is expressible in netCDF or Zarr. Format-specific writers should override this and explain what is missing - a Sentinel-2 SAFE writer needs an S2-shaped dataset, and saying so is more useful than emitting a broken product.

Parameters:

obj – Candidate object.

Returns:

Capability, with a reason when the answer is no.

check_conformance(obj: Dataset | DataTree) → List[str][source]#

Check the object against CF-1.8 / ACDD / the controlled vocabulary.

Placeholder until the conformance checks land (see #205); returning no issues keeps the orchestration honest in the meantime rather than pretending to check.

Parameters:

obj – Object about to be written.

Returns:

Human-readable descriptions of non-conformances; empty when it conforms.

default_write_params: Dict[str, Any] = {'create_parents': True, 'encode_attrs': True, 'on_nonconformance': 'warn', 'update_history': True}#
abstractmethod static get_extension() → str[source]#

Return the filename extension this writer produces, including the dot.

Used to name outputs when the caller gives a directory rather than a full path (see write_multi).

name: str = ''#

Name this writer is registered under. Concrete writers must set this.

write(obj: Dataset | DataTree, path: Path | str) → str[source]#

Public entrypoint: write an object to path.

Orchestration is the same for every format:

  1. can_write() - refuse early, with a reason the user can act on

  2. check_conformance() - CF-1.8 / ACDD / controlled vocabulary

  3. provenance - append to history and eoio:processing_steps

  4. encode_attrs() - make attributes serialisable

  5. write_dataset() - the format-specific part

Provenance is added before encoding and writing, so that it ends up in the written file rather than only on a discarded in-memory copy.

The input object is never modified.

Parameters:
  • obj – Dataset or DataTree to write.

  • path – Destination path.

Returns:

The path written, as a string.

Raises:

TypeError – If this writer cannot express obj.

abstractmethod write_dataset(obj: Dataset | DataTree, path: Path) → None[source]#

Write the object in this writer’s format.

Called with attributes already encoded and provenance already applied, so implementations only have to deal with the format itself.

Parameters:
  • obj – Dataset or DataTree to write.

  • path – Destination path, already resolved.

class eoio.writers.WriteCapability(ok: bool, reason: str = '')[source]#

Bases: object

Whether a writer can express a given object in its format.

Parameters:
  • ok – Whether the object can be written.

  • reason – Why not, when ok is False. Should say what is missing, so the user can act on it.

ok: bool#
reason: str = ''#
class eoio.writers.WriterConfig(write_params: Dict[str, Any], provided_write_params: FrozenSet[str] = frozenset({}))[source]#

Bases: object

Normalised, validated configuration for a writer instance.

provided_write_params: FrozenSet[str] = frozenset({})#

Names the caller actually supplied. Needed wherever a default and an explicitly requested value of the same parameter must behave differently: the Zarr writer refuses mode alongside append_dim, which it can only do without also refusing its own default.

write_params: Dict[str, Any]#
class eoio.writers.WriterFactory[source]#

Bases: object

Writer Factory class

static get_writer(name: str) → Type[BaseWriter][source]#

Return the writer registered under name.

Parameters:

name – Writer name, e.g. "netcdf".

Returns:

Writer class.

Raises:

ValueError – If no writer is registered under that name.

static list_writers() → List[str][source]#

List the names of all available writers.

Returns:

Sorted writer names.

eoio.writers.register_writer(name: str, writer_cls: Type[BaseWriter], overwrite: bool = False) → Type[BaseWriter][source]#
eoio.writers.register_writer(name: str, writer_cls: None = None, overwrite: bool = False) → Callable[[Type[BaseWriter]], Type[BaseWriter]]

Register a writer class under a name.

Used as a decorator, matching eoio.processors.registry.register_processor():

@register_writer("netcdf")
class NetCDFWriter(BaseWriter):
    ...

Or called directly, which is what you want for a class you do not own:

register_writer("geotiff", SomeThirdPartyWriter)

Either way the class gets its name set, so a registered writer always knows what it is called - which is what ends up in the provenance a write records.

Parameters:
  • name – Name used to select the writer, e.g. "netcdf".

  • writer_cls – Writer class. Omit it to use this as a decorator.

  • overwrite – Whether replacing an already-registered name is permitted.

Returns:

The registered class, or the decorator that will register it.

Raises:

KeyError – If the name is taken and overwrite is False.

eoio.writers.unregister_writer(name: str) → Type[BaseWriter][source]#

Remove a writer registered with register_writer().

Parameters:

name – Registered writer name.

Returns:

The removed class.

Raises:

KeyError – If no writer was registered at runtime under that name.

Subpackages#

Submodules#