netCDF4 file access via h5py with hierarchical and legacy APIs for scientific computing
npx @tessl/cli install tessl/pypi-h5netcdf@1.6.0A Python library that provides netCDF4 file access via h5py, offering both a modern hierarchical API and a legacy netCDF4-python compatible API. h5netcdf bypasses the traditional Unidata netCDF library, reducing binary dependencies while maintaining full compatibility with the netCDF4 file format.
pip install h5netcdf (requires h5py)Modern API (recommended for new code):
import h5netcdfLegacy API (compatible with netCDF4-python):
import h5netcdf.legacyapi as netCDF4import h5netcdf
import numpy as np
# Read a netCDF4 file
with h5netcdf.File('data.nc', 'r') as f:
# Access variables
temperature = f['temperature'][:]
# Access attributes
units = f['temperature'].attrs['units']
# Access dimensions
time_dim = f.dimensions['time']
print(f"Time dimension size: {time_dim.size}")
# Create a new netCDF4 file
with h5netcdf.File('output.nc', 'w') as f:
# Create dimensions
f.dimensions['time'] = 10
f.dimensions['lat'] = 180
f.dimensions['lon'] = 360
# Create variables
temp = f.create_variable('temperature', ('time', 'lat', 'lon'), dtype='f4')
temp[:] = np.random.random((10, 180, 360))
temp.attrs['units'] = 'K'
temp.attrs['long_name'] = 'Air Temperature'import h5netcdf.legacyapi as netCDF4
import numpy as np
# Compatible with existing netCDF4-python code
with netCDF4.Dataset('data.nc', 'r') as f:
# Access variables through .variables
temperature = f.variables['temperature'][:]
units = f.variables['temperature'].getncattr('units')
# Access dimensions
time_size = len(f.dimensions['time'])h5netcdf provides two distinct APIs:
h5netcdf.File): Hierarchical, h5py-inspired interface with direct access to variables and attributesh5netcdf.legacyapi.Dataset): Drop-in replacement for netCDF4-python with identical method names and behaviorBoth APIs operate on the same underlying HDF5 files via h5py, ensuring full interoperability while providing flexibility for different coding styles and migration paths.
Core file management including opening, creating, and closing netCDF4 files with various access modes and configuration options.
class File(Group):
def __init__(self, path, mode: str = "r", invalid_netcdf: bool = False,
phony_dims: str = None, track_order: bool = None,
decode_vlen_strings: bool = False, **kwargs): ...
def close(self) -> None: ...
def flush(self) -> None: ...
def sync(self) -> None: ...
@property
def filename(self) -> str: ...
@property
def mode(self) -> str: ...Managing hierarchical data organization through groups, including creation, navigation, and nested group structures.
class Group(Mapping):
def create_group(self, name: str) -> Group: ...
def create_variable(self, name: str, dimensions: tuple = (), dtype=None,
data=None, fillvalue=None, chunks=None, **kwargs) -> Variable: ...
def resize_dimension(self, dim: str, size: int) -> None: ...
def create_enumtype(self, datatype, datatype_name: str, enum_dict: dict) -> EnumType: ...
def create_vltype(self, datatype, datatype_name: str) -> VLType: ...
def create_cmptype(self, datatype, datatype_name: str) -> CompoundType: ...
def flush(self) -> None: ...
def sync(self) -> None: ...
@property
def groups(self) -> Frozen: ...
@property
def variables(self) -> Frozen: ...
@property
def parent(self) -> Group: ...
@property
def name(self) -> str: ...
@property
def dims(self) -> Dimensions: ...
@property
def enumtypes(self) -> Frozen: ...
@property
def vltypes(self) -> Frozen: ...
@property
def cmptypes(self) -> Frozen: ...Groups and Hierarchical Organization
Creating, reading, and writing data variables with support for chunking, compression, and various data types.
class Variable(BaseVariable):
def __getitem__(self, key) -> np.ndarray: ...
def __setitem__(self, key, value) -> None: ...
def __len__(self) -> int: ...
def __array__(self, *args, **kwargs) -> np.ndarray: ...
@property
def shape(self) -> tuple: ...
@property
def dtype(self) -> np.dtype: ...
@property
def datatype(self): ...
@property
def dimensions(self) -> tuple: ...
@property
def ndim(self) -> int: ...
@property
def chunks(self) -> tuple: ...
@property
def compression(self) -> str: ...
@property
def compression_opts(self): ...
@property
def fletcher32(self) -> bool: ...
@property
def shuffle(self) -> bool: ...Creating and managing dimensions including unlimited dimensions and dimension scaling.
class Dimension:
def __init__(self, parent: Group, name: str, size: int = None,
create_h5ds: bool = False, phony: bool = False): ...
def isunlimited(self) -> bool: ...
@property
def size(self) -> int: ...Managing attributes on files, groups, and variables with proper type handling and netCDF4 conventions.
class Attributes(MutableMapping):
def __getitem__(self, key: str): ...
def __setitem__(self, key: str, value) -> None: ...
def __delitem__(self, key: str) -> None: ...Creating and managing custom data types including enumeration, variable-length, and compound types.
class EnumType(UserType):
@property
def enum_dict(self) -> dict: ...
class VLType(UserType): ...
class CompoundType(UserType):
@property
def dtype_view(self) -> np.dtype: ...netCDF4-python compatible interface for existing code migration and compatibility.
class Dataset(File, Group, HasAttributesMixin):
def createGroup(self, name: str) -> Group: ...
def createDimension(self, name: str, size: int = None) -> Dimension: ...
def createVariable(self, varname: str, datatype, dimensions: tuple = (), **kwargs) -> Variable: ...class CompatibilityError(Exception):
"""Raised when using features incompatible with netCDF4 API."""
pass
class BaseObject:
@property
def name(self) -> str: ...
@property
def dtype(self) -> np.dtype: ...
class BaseVariable(BaseObject):
"""Base class for Variable with common functionality."""
def __array__(self) -> np.ndarray: ...
@property
def shape(self) -> tuple: ...
@property
def ndim(self) -> int: ...
@property
def dimensions(self) -> tuple: ...
class UserType(BaseObject):
@property
def dtype(self) -> np.dtype: ...
class Frozen(Mapping):
"""Immutable wrapper for mapping objects."""
@property
def _mapping(self): ...
class Dimensions(MutableMapping):
"""Container for managing dimensions within a group."""
def add(self, name: str): ...
def add_phony(self, name: str, size: int): ...
# Constants
NOT_A_VARIABLE: bytes = b"This is a netCDF dimension but not a netCDF variable."
# Default fill values (from legacy API)
default_fillvals: dict = {
'S1': '\x00',
'i1': -127,
'u1': 255,
'i2': -32767,
'u2': 65535,
'i4': -2147483647,
'u4': 4294967295,
'i8': -9223372036854775806,
'u8': 18446744073709551614,
'f4': 9.969209968386869e36,
'f8': 9.969209968386869e36,
}
# Utility Functions
def _join_h5paths(parent_path: str, child_path: str) -> str:
"""Join HDF5 paths properly."""
...
def _name_from_dimension(dim) -> str:
"""Extract name from dimension."""
...
def _invalid_netcdf_feature(feature: str, allow: bool) -> None:
"""Check feature compatibility and raise CompatibilityError if needed."""
...
def _get_default_fillvalue(dtype) -> any:
"""Get default fill value for data type."""
...
def _check_return_dtype_endianess(endian: str = "native") -> str:
"""Check and normalize endianness specification."""
...