API Reference

pint-cf has three public functions.

Registry

pint_cf.cf_unitregistry(*, cf_extensions=True)[source]

Create a CF-ready pint UnitRegistry.

Parameters:

cf_extensions (bool, optional) –

By default (True), the registry also includes CF units that UDUNITS-2 itself doesn’t define:

  • level, sigma_level, layer - dimensionless vertical-coordinate placeholders, deprecated (parsing one raises DeprecationWarning).

  • practical_salinity_unit / psu.

  • decibel / dB, bel.

  • Reassigning the Sv symbol from sievert to sverdrup.

Pass False to get a registry that matches plain UDUNITS-2 instead, without any of these additions.

Returns:

pint.UnitRegistry – A registry ready to parse UDUNITS-2/CF unit strings and to format results back with format(q, "cf") / format(q, "~cf").

Return type:

UnitRegistry

Temperature metadata (units_metadata)

pint_cf.CFContext(*, units_metadata=None)[source]

Apply a CF units_metadata attribute while building a unit or quantity.

A NetCDF/CF variable can carry a units_metadata attribute that disambiguates a temperature unit as either a point on a scale ("temperature: on_scale", e.g. a measured temperature of 15 degrees Celsius) or a difference between two temperatures ("temperature: difference", e.g. a 5-degree warming). Plain pint has no way to know which one you mean from the unit string alone. Wrap the ureg.Quantity(...)/ureg.Unit(...) call that needs this distinction in a with CFContext(...): block, and it will resolve to the right pint unit (e.g. delta_degree_Celsius for a difference).

Scope this tightly around a single unit/quantity construction: it must not wrap a loop over multiple variables that may carry different metadata, since the value set here is only reset on exiting the block.

Parameters:

units_metadata (str or None, optional) – A CF units_metadata attribute value, e.g. "temperature: difference" (CF conventions, section 3.1.2, “Temperature units”). None (the default) is a no-op.

Yields:

None

Raises:

ValueError – If units_metadata is set but isn’t one of the values CF defines for the temperature key.

Return type:

Iterator[None]

Examples

>>> with CFContext(units_metadata="temperature: difference"):
...     q = ureg.Quantity(1, "degree_C")
>>> q.units
<Unit('delta_degree_Celsius')>
pint_cf.cf_attributes_for(unit)[source]

Derive CF variable attributes from a pint Unit or Quantity.

The reverse of what CFContext does going in: for writing a result back to a NetCDF variable, e.g. via var.setncatts(...) or ds[name].attrs.update(...).

Currently only ever produces a units_metadata entry, and only for a temperature unit - CF’s own rule is that this attribute must be absent unless the unit involves temperature, so a non-temperature unit (or one without a genuine on_scale/difference distinction to report) yields an empty dict rather than a key with a null-ish value.

Only reliable for units with a genuine on_scale/difference distinction (Celsius, Fahrenheit - units with their own offset, which is why pint gives them a delta_ counterpart at all). For Kelvin/Rankine (no offset, so no delta_ variant exists), on_scale and difference are numerically identical and structurally indistinguishable from the unit alone - this reports "temperature: unknown" for those rather than guessing; if that distinction matters, the caller must track it through their own computation instead of recovering it from the resulting unit.

Parameters:

unit (pint.Unit or pint.Quantity) – The unit (or quantity, from which .units is used) to derive CF attributes from.

Returns:

dict of str to str{"units_metadata": ...} if unit involves temperature, otherwise {}.

Return type:

dict[str, str]

Examples

>>> cf_attributes_for(ureg.Unit("delta_degree_Celsius"))
{'units_metadata': 'temperature: difference'}
>>> cf_attributes_for(ureg.Unit("meter"))
{}