2.8.1.4. pycsamt.site.metadata#

Declarative, auditable editing of EDI station metadata.

Functions

rename_sites(sites, names, *[, inplace, ...])

Rename stations from a mapping, aligned sequence, or callable.

update_metadata(site, update, *[, inplace, ...])

Update metadata for one site or EDI-like object.

update_metadata_all(sites, updates, *[, ...])

Apply metadata specifications to a station collection.

Classes

MetadataChange(index, old_name, new_name, ...)

Describe the metadata changes attempted for one station.

SiteMetadataEditor(updates, *[, missing, ...])

Apply declarative, validated, and auditable EDI metadata changes.

class pycsamt.site.metadata.MetadataChange(index, old_name, new_name, changed_fields, status='updated', error=None, requested_fields=(), before=None, after=None)[source]

Bases: object

Describe the metadata changes attempted for one station.

Parameters:
  • index (int) – Zero-based position of the station in the input collection.

  • old_name (str) – Station identity before editing.

  • new_name (str) – Station identity after editing. For a failed operation this remains equal to old_name.

  • changed_fields (tuple of str) – Canonical paths of fields whose values changed.

  • status ({'updated', 'unchanged', 'error'}, default='updated') – Outcome of the station-level operation.

  • error (str or None, default=None) – Error message captured when status='error'.

  • requested_fields (tuple of str, default=()) – Canonical paths requested by the metadata specification.

  • before (mapping or None, default=None) – Audit snapshots surrounding the operation.

  • after (mapping or None, default=None) – Audit snapshots surrounding the operation.

Variables:

Notes

Instances are immutable. Use to_dict() when serializing an audit or constructing a tabular report.

Examples

>>> from pycsamt.site import MetadataChange
>>> change = MetadataChange(
...     0, "18-012A", "L01_012", ("name", "head.project")
... )
>>> change.status
'updated'
>>> change.to_dict()["changed_fields"]
['name', 'head.project']

See also

SiteMetadataEditor.audit

Return all station records as a DataFrame.

index: int
old_name: str
new_name: str
changed_fields: tuple[str, ...]
status: str = 'updated'
error: str | None = None
requested_fields: tuple[str, ...] = ()
before: Mapping[str, Any] | None = None
after: Mapping[str, Any] | None = None
to_dict()[source]

Return the record as a serialization-friendly dictionary.

Returns:

Dataclass fields with tuple-valued field lists converted to ordinary lists.

Return type:

dict of str to Any

Examples

>>> from pycsamt.site import MetadataChange
>>> record = MetadataChange(0, "A01", "B01", ("name",))
>>> record.to_dict()["changed_fields"]
['name']

See also

SiteMetadataEditor.audit

Build a DataFrame from change records.

class pycsamt.site.metadata.SiteMetadataEditor(updates, *, missing='raise', allow_duplicates=False, on_error='raise', validate_coordinates=True, allow_empty_names=False, validators=None)[source]

Bases: object

Apply declarative, validated, and auditable EDI metadata changes.

Parameters:
  • updates (mapping, sequence, callable, pandas.DataFrame, or path-like) – Metadata source. A mapping may be keyed by current station identity or may be one specification applied to every station. A sequence is aligned with input order. A callable receives an EDI object and, optionally, its zero-based index. DataFrames and CSV files require a station column named station, name, site, dataid, or id.

  • missing ({'raise', 'warn', 'ignore'}, default='raise') – Policy for source keys that match no input station.

  • allow_duplicates (bool, default=False) – Permit duplicate final station identities. Keeping the default avoids ambiguous selection and export filenames.

  • on_error ({'raise', 'warn', 'ignore'}, default='raise') – Station-level failure policy. raise preserves batch atomicity; warn and ignore retain failed stations unchanged and commit successful stations.

  • validate_coordinates (bool, default=True) – Validate finite latitude, longitude, and elevation values and enforce geographic latitude/longitude bounds.

  • allow_empty_names (bool, default=False) – Permit an empty final station identity.

  • validators (sequence of callable or None, default=None) – Additional validators called after each staged update. A validator receives the staged EDI and, optionally, its index. Returning False rejects the station; raising an exception records that exception.

Variables:
  • updates (Any) – Original metadata source.

  • on_error (missing,) – Configured unmatched-key and station-error policies.

  • allow_empty_names (allow_duplicates, validate_coordinates,) – Validation switches.

  • validators (tuple of callable) – Custom validators in execution order.

  • records (list of MetadataChange) – Audit records from the latest apply() or plan() call.

  • output_paths (list of pathlib.Path) – Paths written by the latest apply_and_write() call.

Notes

A station specification recognizes name/station, lat, lon, elev, coords, head, info, sections, set, unset, and transform. Generic paths default to HEAD. Explicit path forms are head.<field>, info.<field>, edi.<field>, and section.<name>.<field>.

All changes are staged on deep copies. With on_error='raise', an in-place batch is committed only after every station and final identity constraint passes validation.

Examples

Rename stations and update acquisition metadata:

>>> from pycsamt.site import SiteMetadataEditor
>>> editor = SiteMetadataEditor(
...     {
...         "18-012A": {
...             "name": "L01_012",
...             "coords": (5.25, -3.75, 120.0),
...             "head": {"project": "LINE_01"},
...         }
...     }
... )
>>> # updated = editor.apply(sites)
>>> # editor.audit()[["old_name", "new_name", "status"]]

Generic actions can address nested fields:

>>> editor = SiteMetadataEditor(
...     {
...         "18-012A": {
...             "set": {"info.processingtag": "reviewed"},
...             "transform": {"head.elev": lambda value: value + 1.5},
...             "unset": ["head.county"],
...         }
...     }
... )

See also

update_metadata

Update one site or EDI-like object.

update_metadata_all

Update a station collection.

rename_sites

Rename from a mapping, sequence, or callable.

pycsamt.site.export.write_sites

Export edited stations separately.

records_: list[MetadataChange]
output_paths_: list[Path]
apply(source, *, inplace=False)[source]

Apply the configured metadata updates.

Parameters:
  • source (Site, Sites, EDI-like object, or iterable of EDI-like objects) – Station data to edit.

  • inplace (bool, default=False) – Commit successful staged objects back into source. With the default, return independently copied objects.

Returns:

One-site inputs retain their logical type. Collection inputs return Sites unless the input is already a Sites object edited in place.

Return type:

Site, Sites, or EDI-like object

Raises:
  • KeyError – If metadata keys are unmatched and missing='raise'.

  • ValueError – If names, coordinates, actions, or validators fail validation.

  • TypeError – If the source cannot be staged safely or an action has an invalid type.

Notes

All edits are first performed on private copies. With inplace=True and on_error='raise', the original object is updated only after the complete batch passes validation. warn and ignore deliberately commit successful stations while retaining failed stations unchanged.

Examples

>>> from pycsamt.site import SiteMetadataEditor
>>> editor = SiteMetadataEditor({"A01": {"name": "L01_001"}})
>>> # renamed = editor.apply(sites)
>>> # renamed["L01_001"].name

See also

plan

Preview and validate without modifying the source.

apply_and_write

Apply and export in one operation.

audit

Return records from the latest operation.

plan(source, *, api=False)[source]

Validate and preview changes without modifying the source.

Parameters:
  • source (Site, Sites, EDI-like object, or iterable of EDI-like objects) – Station data used to evaluate the configured changes.

  • api (bool or None, default=False) – Passed to the API-view wrapper. False returns a pandas DataFrame, True forces an API frame, and None defers to the global API-view configuration.

Returns:

Audit preview with one row per input station.

Return type:

pandas.DataFrame or APIFrame

Raises:

KeyError, ValueError, TypeError – Propagated from staged resolution and validation, according to the configured policies.

Notes

Actions run only on staged copies, so callable transformations and validators are evaluated realistically. A later apply() invokes callables again; stateful callables should therefore be avoided.

Examples

>>> from pycsamt.site import SiteMetadataEditor
>>> editor = SiteMetadataEditor({"A01": {"elev": 125.0}})
>>> # preview = editor.plan(sites)
>>> # preview[["old_name", "changed_fields", "status"]]

See also

apply

Apply the configured updates.

audit

Return the most recently generated records.

apply_and_write(source, outdir, *, inplace=False, template='{station}.edi', exist_ok=False, manifest_csv=None)[source]

Apply metadata changes and export the resulting stations.

Parameters:
  • source (Site, Sites, EDI-like object, or iterable of EDI-like objects) – Station data to edit and export.

  • outdir (path-like) – Destination directory.

  • inplace (bool, default=False) – Commit staged metadata changes back into source.

  • template (str, default='{station}.edi') – Export filename template accepted by pycsamt.site.export.write_sites().

  • exist_ok (bool, default=False) – Permit destinations that already exist.

  • manifest_csv (path-like or None, default=None) – Optional manifest CSV destination.

Returns:

Edited result. Written paths are available in output_paths_.

Return type:

Site, Sites, or EDI-like object

Raises:

Notes

Editing and persistence remain separate internally: apply() is completed before pycsamt.site.export.write_sites() is called.

Examples

>>> from pycsamt.site import SiteMetadataEditor
>>> editor = SiteMetadataEditor({"A01": {"name": "L01_001"}})
>>> # result = editor.apply_and_write(sites, "renamed_edi")
>>> # [path.name for path in editor.output_paths_]

See also

apply

Apply without writing files.

pycsamt.site.export.write_sites

Export an existing collection.

audit(*, api=False)[source]

Return records from the latest operation as a table.

Parameters:

api (bool or None, default=False) – False returns a pandas DataFrame, True forces an API frame, and None defers to the global API-view configuration.

Returns:

Columns correspond to MetadataChange fields. Before any operation, an empty table with the stable audit schema is returned.

Return type:

pandas.DataFrame or APIFrame

Examples

>>> from pycsamt.site import SiteMetadataEditor
>>> editor = SiteMetadataEditor({"A01": {"name": "B01"}})
>>> list(editor.audit(api=False).columns[:4])
['index', 'old_name', 'new_name', 'changed_fields']

See also

MetadataChange

Station-level audit record.

plan

Populate the audit through a non-mutating preview.

apply

Populate the audit while applying updates.

pycsamt.site.metadata.rename_sites(sites, names, *, inplace=False, missing='raise', allow_duplicates=False, allow_empty_names=False)[source]

Rename stations from a mapping, aligned sequence, or callable.

Parameters:
  • sites (Sites, iterable of EDI-like objects, Site, or EDI-like object) – Stations to rename.

  • names (mapping, sequence of str, or callable) – A mapping relates current names to new names. A sequence is aligned with input order. A callable receives an EDI object and, optionally, its zero-based index, and returns the new name.

  • inplace (bool, default=False) – Commit synchronized identities back into the input.

  • missing ({'raise', 'warn', 'ignore'}, default='raise') – Policy for mapping keys that match no station.

  • allow_duplicates (bool, default=False) – Permit duplicate final identities.

  • allow_empty_names (bool, default=False) – Permit empty final identities.

Returns:

Renamed station data.

Return type:

Sites, Site, or EDI-like object

Raises:
  • KeyError – If a mapping key is unmatched and missing='raise'.

  • ValueError – If names are duplicate or empty under the configured policy, or a sequence length differs from the number of stations.

  • TypeError – If names or the station source is unsupported.

Notes

Renaming synchronizes object-level identity, common HEAD aliases, and linked SECTID values. It does not rename an existing source file; exporting with template='{station}.edi' uses the new identity.

Examples

>>> from pycsamt.site import rename_sites
>>> mapping = {"18-012A": "L01_012", "18-013A": "L01_013"}
>>> # renamed = rename_sites(sites, mapping)

Generate names from input order:

>>> # renamed = rename_sites(
>>> #     sites, lambda _edi, index: f"L22_{index + 1:03d}"
>>> # )

See also

update_metadata

Update one station and its metadata.

update_metadata_all

Apply richer station-specific specifications.

SiteMetadataEditor

Reusable editor with planning and audit records.

pycsamt.site.export.write_sites

Export using updated station names.

pycsamt.site.metadata.update_metadata(site, update, *, inplace=False, validate_coordinates=True, validators=None)[source]

Update metadata for one site or EDI-like object.

Parameters:
  • site (Site or EDI-like object) – Object to update.

  • update (mapping) – One metadata specification. Supported keys are name, station, lat, lon, long, elev, coords, head, info, sections, set, unset, and transform.

  • inplace (bool, default=False) – Commit the staged state into site rather than returning an independent copy.

  • validate_coordinates (bool, default=True) – Enforce finite geographic coordinate values and valid latitude and longitude ranges.

  • validators (sequence of callable or None, default=None) – Additional staged-object validators.

Returns:

Updated object with the same logical single-site form as the input.

Return type:

Site or EDI-like object

Raises:
  • ValueError – If a field, coordinate, station identity, or validator is invalid.

  • TypeError – If the update specification or input cannot be handled safely.

Examples

>>> from pycsamt.site import update_metadata
>>> update = {
...     "name": "L01_012",
...     "coords": (5.25, -3.75, 120.0),
...     "info": {"processingtag": "reviewed"},
... }
>>> # reviewed = update_metadata(site, update)

See also

update_metadata_all

Apply station-specific updates to a collection.

SiteMetadataEditor

Configure validation, planning, and audit behavior.

rename_sites

Rename one or many stations using a compact interface.

pycsamt.site.metadata.update_metadata_all(sites, updates, *, inplace=False, missing='raise', allow_duplicates=False, on_error='raise', validate_coordinates=True, allow_empty_names=False, validators=None)[source]

Apply metadata specifications to a station collection.

Parameters:
  • sites (Sites, iterable of EDI-like objects, Site, or EDI-like object) – Input station data.

  • updates (mapping, sequence, callable, pandas.DataFrame, or path-like) – Metadata source accepted by SiteMetadataEditor.

  • inplace (bool, default=False) – Commit staged objects back into the supplied input.

  • missing ({'raise', 'warn', 'ignore'}, default='raise') – Policy for update keys that match no station.

  • allow_duplicates (bool, default=False) – Permit duplicate final station identities.

  • on_error ({'raise', 'warn', 'ignore'}, default='raise') – Station-level failure policy.

  • validate_coordinates (bool, default=True) – Validate geographic coordinates before committing.

  • allow_empty_names (bool, default=False) – Permit empty final station identities.

  • validators (sequence of callable or None, default=None) – Additional validators applied to each staged station.

Returns:

Updated data. Collection-like inputs normally return Sites.

Return type:

Sites, Site, or EDI-like object

Raises:
  • KeyError – If station-keyed metadata contains unmatched keys and missing='raise'.

  • ValueError – If the batch violates metadata or identity constraints.

  • TypeError – If the source, metadata source, or action is unsupported.

Examples

Use an explicit station mapping:

>>> from pycsamt.site import update_metadata_all
>>> updates = {
...     "A01": {"name": "L01_001", "head": {"project": "L01"}},
...     "A02": {"name": "L01_002", "elev": 121.0},
... }
>>> # updated = update_metadata_all(sites, updates)

A DataFrame or CSV review table can use columns such as station, new_name, latitude, and head.project.

See also

update_metadata

Update one site.

SiteMetadataEditor.apply

Apply with a reusable configured editor.

SiteMetadataEditor.plan

Preview a batch before committing.

rename_sites

Rename a collection without a full metadata specification.