glodformat 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- glodformat/__init__.py +2 -0
- glodformat/_version.py +11 -0
- glodformat/moon.py +149 -0
- glodformat/netcdfcommon.py +190 -0
- glodformat/srf.py +205 -0
- glodformat/tests/__init__.py +0 -0
- glodformat/tests/data/W_XX-EUMETSAT-Darmstadt,VISNIR+SUBSET+MOON,MSG3+SEVIRI_C_EUMG_20140318140112_01.nc +0 -0
- glodformat/tests/data/W_XX-EUMETSAT-Darmstadt_VIS+IR+SRF_MSG3+SEVIRI_C_EUMG.nc +0 -0
- glodformat/tests/test_moon.py +18 -0
- glodformat/tests/test_srf.py +27 -0
- glodformat-0.0.1.dist-info/METADATA +213 -0
- glodformat-0.0.1.dist-info/RECORD +15 -0
- glodformat-0.0.1.dist-info/WHEEL +5 -0
- glodformat-0.0.1.dist-info/licenses/LICENSE +165 -0
- glodformat-0.0.1.dist-info/top_level.txt +1 -0
glodformat/__init__.py
ADDED
glodformat/_version.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
glodformat Version Handler Module
|
|
3
|
+
|
|
4
|
+
Handles versioning for the `glodformat` package.
|
|
5
|
+
"""
|
|
6
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
__version__ = version("glodformat")
|
|
10
|
+
except PackageNotFoundError:
|
|
11
|
+
__version__ = "0.0.0"
|
glodformat/moon.py
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the functionality that validates moon observations files.
|
|
3
|
+
|
|
4
|
+
It exports the following functions:
|
|
5
|
+
* validate_moon_observation - Validates that a xarray dataset follows the Moon Observation schema.
|
|
6
|
+
"""
|
|
7
|
+
from typing import Union
|
|
8
|
+
import re
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
import xarray as xr
|
|
13
|
+
import pandera.xarray as pa
|
|
14
|
+
|
|
15
|
+
from glodformat.netcdfcommon import (
|
|
16
|
+
validate_schema,
|
|
17
|
+
get_valid_metric_units,
|
|
18
|
+
check_stringy,
|
|
19
|
+
check_floating,
|
|
20
|
+
_as_ctx,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
_check_shape_1 = pa.Check(
|
|
24
|
+
lambda da: da.size == 1, error="Coordinate 'date' must have exactly one element."
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
_UNITS_REGEX = "^(?:" + "|".join(re.escape(v) for v in get_valid_metric_units()) + ")$"
|
|
28
|
+
|
|
29
|
+
_LUNAR_OBS_SCHEMA = pa.DatasetSchema(
|
|
30
|
+
data_vars={
|
|
31
|
+
"channel_name": pa.DataArraySchema(checks=check_stringy, dims=["chan"]),
|
|
32
|
+
"sat_pos": pa.DataArraySchema(
|
|
33
|
+
checks=check_floating,
|
|
34
|
+
shape=(3,),
|
|
35
|
+
dims=["sat_xyz"],
|
|
36
|
+
attrs={"units": _UNITS_REGEX},
|
|
37
|
+
),
|
|
38
|
+
"sat_pos_ref": pa.DataArraySchema(checks=check_stringy, dims=[]),
|
|
39
|
+
"irr_obs": pa.DataArraySchema(
|
|
40
|
+
checks=check_floating, dims=["chan"], nullable=True
|
|
41
|
+
),
|
|
42
|
+
},
|
|
43
|
+
coords={"date": pa.Coordinate(np.datetime64, checks=_check_shape_1)},
|
|
44
|
+
attrs={"data_source": lambda _: True},
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
_LUNAR_OBS_OTHER_SCHEMAS = [
|
|
48
|
+
pa.DatasetSchema(
|
|
49
|
+
data_vars={
|
|
50
|
+
"channel_name": pa.DataArraySchema(checks=check_stringy, dims=["chan"]),
|
|
51
|
+
"sat_pos": pa.DataArraySchema(
|
|
52
|
+
checks=check_floating,
|
|
53
|
+
shape=(3,),
|
|
54
|
+
dims=["sat_xyz"],
|
|
55
|
+
attrs={"units": _UNITS_REGEX},
|
|
56
|
+
),
|
|
57
|
+
"sat_pos_ref": pa.DataArraySchema(checks=check_stringy, dims=[]),
|
|
58
|
+
"irr_obs": pa.DataArraySchema(
|
|
59
|
+
checks=check_floating, dims=["chan"], nullable=True
|
|
60
|
+
),
|
|
61
|
+
},
|
|
62
|
+
coords={"date": pa.Coordinate(checks=[check_floating, _check_shape_1])},
|
|
63
|
+
attrs={"data_source": lambda _: True},
|
|
64
|
+
),
|
|
65
|
+
pa.DatasetSchema(
|
|
66
|
+
data_vars={
|
|
67
|
+
"channel_name": pa.DataArraySchema(checks=check_stringy, dims=["chan"]),
|
|
68
|
+
"sat_pos": pa.DataArraySchema(
|
|
69
|
+
checks=check_floating,
|
|
70
|
+
shape=(3,),
|
|
71
|
+
dims=["sat_xyz"],
|
|
72
|
+
attrs={"units": _UNITS_REGEX},
|
|
73
|
+
),
|
|
74
|
+
"sat_pos_ref": pa.DataArraySchema(checks=check_stringy, dims=[]),
|
|
75
|
+
"irr_obs": pa.DataArraySchema(
|
|
76
|
+
checks=check_floating, dims=["chan"], nullable=True
|
|
77
|
+
),
|
|
78
|
+
"date": pa.DataArraySchema(np.datetime64, shape=(1,)),
|
|
79
|
+
},
|
|
80
|
+
attrs={"data_source": lambda _: True},
|
|
81
|
+
),
|
|
82
|
+
pa.DatasetSchema(
|
|
83
|
+
data_vars={
|
|
84
|
+
"channel_name": pa.DataArraySchema(checks=check_stringy, dims=["chan"]),
|
|
85
|
+
"sat_pos": pa.DataArraySchema(
|
|
86
|
+
checks=check_floating,
|
|
87
|
+
shape=(3,),
|
|
88
|
+
dims=["sat_xyz"],
|
|
89
|
+
attrs={"units": _UNITS_REGEX},
|
|
90
|
+
),
|
|
91
|
+
"sat_pos_ref": pa.DataArraySchema(checks=check_stringy, dims=[]),
|
|
92
|
+
"irr_obs": pa.DataArraySchema(
|
|
93
|
+
checks=check_floating, dims=["chan"], nullable=True
|
|
94
|
+
),
|
|
95
|
+
"date": pa.DataArraySchema(checks=check_floating, shape=(1,)),
|
|
96
|
+
},
|
|
97
|
+
attrs={"data_source": lambda _: True},
|
|
98
|
+
),
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _validate_schema_moon_observation(ds: xr.Dataset, strict: bool = False):
|
|
103
|
+
"""Validates that a xarray dataset follows the Basic Moon Observation schema.
|
|
104
|
+
|
|
105
|
+
The dataset structure is:
|
|
106
|
+
|
|
107
|
+
coordinates: 'date': datetime
|
|
108
|
+
dims without coordinates: 'chan' and 'sat_xyz'
|
|
109
|
+
data_vars: 'channel_name': str, 'sat_pos': float, 'sat_pos_ref': str, 'irr_obs': float
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
ds: xr.Dataset
|
|
114
|
+
Dataset to validate
|
|
115
|
+
strict: bool
|
|
116
|
+
Flag to specify if the check must be exact to the desired schema, or if
|
|
117
|
+
it can pass if it would work in most cases.
|
|
118
|
+
"""
|
|
119
|
+
schema = _LUNAR_OBS_SCHEMA
|
|
120
|
+
if strict:
|
|
121
|
+
validate_schema(schema, ds)
|
|
122
|
+
else:
|
|
123
|
+
validate_schema(schema, ds, _LUNAR_OBS_OTHER_SCHEMAS)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def validate_moon_observation(
|
|
127
|
+
data: Union[xr.Dataset, str, Path], strict: bool = False
|
|
128
|
+
) -> None:
|
|
129
|
+
"""Validates that a dataset follows the Moon Observation schema.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
data : xr.Dataset or str or pathlib.Path
|
|
134
|
+
Dataset to validate, or path to a NetCDF file that will be opened
|
|
135
|
+
and validated. If a path is given, the file is opened in read-only
|
|
136
|
+
mode and closed before returning.
|
|
137
|
+
strict : bool
|
|
138
|
+
Flag to specify if the check must be exact to the desired schema, or
|
|
139
|
+
if it can pass if it would work in most cases.
|
|
140
|
+
|
|
141
|
+
Raises
|
|
142
|
+
------
|
|
143
|
+
TypeError
|
|
144
|
+
If ``data`` is neither an ``xr.Dataset``, ``str`` nor ``Path``.
|
|
145
|
+
ValueError
|
|
146
|
+
If the dataset does not conform to any of the accepted SRF schemas.
|
|
147
|
+
"""
|
|
148
|
+
with _as_ctx(data) as ds:
|
|
149
|
+
_validate_schema_moon_observation(ds, strict=strict)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Common functionalities for reading netCDF files with `xarray`."""
|
|
2
|
+
from typing import Iterable, Mapping, Union, Dict, List
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from contextlib import nullcontext
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import xarray as xr
|
|
8
|
+
import pandera.xarray as pa
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _is_stringy(da) -> bool:
|
|
12
|
+
dtype = da.dtype
|
|
13
|
+
if dtype.kind in ("U", "S"):
|
|
14
|
+
return True
|
|
15
|
+
if hasattr(np, "dtypes") and hasattr(np.dtypes, "StringDType"):
|
|
16
|
+
if isinstance(dtype, np.dtypes.StringDType):
|
|
17
|
+
return True
|
|
18
|
+
if dtype.kind == "O":
|
|
19
|
+
return all(isinstance(x, str) for x in da.values.flat)
|
|
20
|
+
return False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
check_stringy = pa.Check(_is_stringy, error="Data array must be of type string/bytes")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _is_floating(da) -> bool:
|
|
27
|
+
return da.dtype.kind == "f"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
check_floating = pa.Check(
|
|
31
|
+
_is_floating,
|
|
32
|
+
error="Data array must have a floating-point dtype (e.g. float32, float64).",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _gen_unit_variations(basename: str) -> List[str]:
|
|
37
|
+
"""Generate common variations of a metric unit (American & British spellings)."""
|
|
38
|
+
return [
|
|
39
|
+
f"{basename}metre", # "metre" (British English)
|
|
40
|
+
f"{basename}meter", # "meter" (American English)
|
|
41
|
+
f"{basename}metres", # "metres" (plural British)
|
|
42
|
+
f"{basename}meters", # "meters" (plural American)
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _get_metric_factors() -> Dict[str, int]:
|
|
47
|
+
# Build the metric factors dictionary efficiently
|
|
48
|
+
metric_factors = {
|
|
49
|
+
**dict.fromkeys(("nm", *_gen_unit_variations("nano")), -9),
|
|
50
|
+
**dict.fromkeys(("um", "μm", *_gen_unit_variations("micro")), -6),
|
|
51
|
+
**dict.fromkeys(("mm", *_gen_unit_variations("milli")), -3),
|
|
52
|
+
**dict.fromkeys(("cm", *_gen_unit_variations("centi")), -2),
|
|
53
|
+
**dict.fromkeys(("m", *_gen_unit_variations("")), 0),
|
|
54
|
+
**dict.fromkeys(("km", *_gen_unit_variations("kilo")), 3),
|
|
55
|
+
}
|
|
56
|
+
return metric_factors
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_valid_metric_units() -> List[str]:
|
|
60
|
+
metric_factors = _get_metric_factors()
|
|
61
|
+
return list(metric_factors.keys())
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_length_conversion_factor(from_unit: str, to_unit: str) -> float:
|
|
65
|
+
"""
|
|
66
|
+
Get the conversion factor between two metric length units.
|
|
67
|
+
|
|
68
|
+
This function calculates the factor needed to convert a length measurement
|
|
69
|
+
from one metric unit to another. It supports various unit spellings, including
|
|
70
|
+
American and British English variations.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
from_unit : str
|
|
75
|
+
The original unit of measurement. Supported units include metres (m),
|
|
76
|
+
centimetres (cm), millimeters (mm), micrometres (μm / um), and nanometres (nm).
|
|
77
|
+
to_unit : str
|
|
78
|
+
The target unit of measurement. Must be one of the supported values listed above.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
float
|
|
83
|
+
The multiplication factor to convert from `from_unit` to `to_unit`.
|
|
84
|
+
|
|
85
|
+
Raises
|
|
86
|
+
------
|
|
87
|
+
ValueError
|
|
88
|
+
If either `from_unit` or `to_unit` is not a recognized metric length unit.
|
|
89
|
+
"""
|
|
90
|
+
metric_factors = _get_metric_factors()
|
|
91
|
+
if from_unit not in metric_factors:
|
|
92
|
+
raise ValueError(
|
|
93
|
+
f"Unsupported unit: {from_unit} or {to_unit}. Supported units: {list(metric_factors.keys())}"
|
|
94
|
+
)
|
|
95
|
+
factor = metric_factors[from_unit] - metric_factors[to_unit]
|
|
96
|
+
factor = 10**factor
|
|
97
|
+
return factor
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def xr_open_dataset(
|
|
101
|
+
filepath: str,
|
|
102
|
+
mask_fillvalue: Union[bool, Mapping[str, bool]] = True,
|
|
103
|
+
mask_limits: Union[bool, Mapping[str, bool]] = True,
|
|
104
|
+
) -> xr.Dataset:
|
|
105
|
+
"""Open a netCDF dataset as an xarray Dataset
|
|
106
|
+
|
|
107
|
+
Read the netCDF dataset masking the appropiate values, checking
|
|
108
|
+
against the variable attributes `_FillValue`, `valid_min` and `valid_max`.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
filepath: str
|
|
113
|
+
Path where the netCDF file is located
|
|
114
|
+
mask_fill_value: bool | Mapping[str, bool]
|
|
115
|
+
If True, tell `xarray` replace array values equal to `_FillValue` with `NA` and scale values.
|
|
116
|
+
Pass a mapping, e.g. {"my_variable": False}, to toggle this feature per-variable individually.
|
|
117
|
+
If a mapping is passed and a variable is missing, it's understood that the variable is mapped to True by default.
|
|
118
|
+
mask_limits: bool | Mapping[str, bool]
|
|
119
|
+
If True, replace array values lower than `valid_min` or higher than `valid_max` with `NA`, if present.
|
|
120
|
+
Pass a mapping, e.g. {"my_variable": False}, to toggle this feature per-variable individually.
|
|
121
|
+
If a mapping is passed and a variable is missing, it's understood that the variable is mapped to the default value.
|
|
122
|
+
The default value is the one defined for the "__default__" mapping, or True if not specified.
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
ds: xr.Dataset
|
|
127
|
+
Dataset with the information of the netCDF file.
|
|
128
|
+
"""
|
|
129
|
+
ds = xr.open_dataset(filepath, engine="netcdf4", mask_and_scale=mask_fillvalue)
|
|
130
|
+
if mask_limits is not False:
|
|
131
|
+
default = True
|
|
132
|
+
if not isinstance(mask_limits, bool):
|
|
133
|
+
default = mask_limits.get("__default__", True)
|
|
134
|
+
for vname, var in ds.data_vars.items():
|
|
135
|
+
mask_limits_var = False
|
|
136
|
+
if isinstance(mask_limits, bool):
|
|
137
|
+
mask_limits_var = mask_limits
|
|
138
|
+
else:
|
|
139
|
+
mask_limits_var = mask_limits.get(vname, default)
|
|
140
|
+
if mask_limits_var:
|
|
141
|
+
values = var.values
|
|
142
|
+
mask = np.ones(values.shape, dtype=bool)
|
|
143
|
+
if hasattr(var, "valid_min"):
|
|
144
|
+
mask &= values >= var.valid_min
|
|
145
|
+
if hasattr(var, "valid_max"):
|
|
146
|
+
mask &= values <= var.valid_max
|
|
147
|
+
var.values = np.where(mask, values, np.nan)
|
|
148
|
+
return ds
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def validate_schema(
|
|
152
|
+
dss: pa.DatasetSchema,
|
|
153
|
+
ds: xr.Dataset,
|
|
154
|
+
other_schemas: Iterable[pa.DatasetSchema] = None,
|
|
155
|
+
):
|
|
156
|
+
"""Validates the dataset `ds` against the schema `dss`.
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
dss: pandera.xarray.DatasetSchema
|
|
161
|
+
Schema that the dataset is going to be validated against.
|
|
162
|
+
ds: xarray.Dataset
|
|
163
|
+
Dataset to validate.
|
|
164
|
+
other_schemas: Iterable[pandera.xarray.DatasetSchema]
|
|
165
|
+
If the dataset can have multiple schemas, it will be validated
|
|
166
|
+
against those before the canonical one. Once it succeeds in a validation,
|
|
167
|
+
it's understood as validated and finishes the validation.
|
|
168
|
+
|
|
169
|
+
Raises
|
|
170
|
+
------
|
|
171
|
+
SchemaErrors
|
|
172
|
+
Error set indicating that the dataset is not following the schema.
|
|
173
|
+
"""
|
|
174
|
+
if other_schemas is not None:
|
|
175
|
+
for odss in other_schemas:
|
|
176
|
+
try:
|
|
177
|
+
odss.validate(ds)
|
|
178
|
+
return
|
|
179
|
+
except pa.errors.SchemaError:
|
|
180
|
+
pass
|
|
181
|
+
dss.validate(ds, lazy=True)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _as_ctx(data: Union[xr.Dataset, str, Path]):
|
|
185
|
+
"""Returns a context manager that produces an xr.Dataset."""
|
|
186
|
+
if isinstance(data, (str, Path)):
|
|
187
|
+
return xr.open_dataset(data)
|
|
188
|
+
if isinstance(data, xr.Dataset):
|
|
189
|
+
return nullcontext(data)
|
|
190
|
+
raise TypeError(f"expected xr.Dataset, str or Path, got {type(data).__name__}")
|
glodformat/srf.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the functionality that validates Spectral Response Function files
|
|
3
|
+
from GLOD format files.
|
|
4
|
+
|
|
5
|
+
It exports the following functions:
|
|
6
|
+
* validate_srf: Validates that a xarray dataset follows the SRF schema.
|
|
7
|
+
"""
|
|
8
|
+
from typing import Union
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
import xarray as xr
|
|
14
|
+
import pandera.xarray as pa
|
|
15
|
+
|
|
16
|
+
from glodformat.netcdfcommon import (
|
|
17
|
+
validate_schema,
|
|
18
|
+
get_valid_metric_units,
|
|
19
|
+
check_floating,
|
|
20
|
+
check_stringy,
|
|
21
|
+
_as_ctx,
|
|
22
|
+
)
|
|
23
|
+
from glodformat import moon
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
_UNITS_REGEX = "^(?:" + "|".join(re.escape(v) for v in get_valid_metric_units()) + ")$"
|
|
27
|
+
|
|
28
|
+
_SRF_SCHEMA = pa.DatasetSchema(
|
|
29
|
+
data_vars={ # TODO check if None works in pandera
|
|
30
|
+
"srf": pa.DataArraySchema(
|
|
31
|
+
checks=check_floating, dims=[None, "channel"], nullable=True
|
|
32
|
+
),
|
|
33
|
+
"wavelength": pa.DataArraySchema(
|
|
34
|
+
checks=check_floating,
|
|
35
|
+
dims=[None, "channel"],
|
|
36
|
+
attrs={"units": _UNITS_REGEX},
|
|
37
|
+
nullable=True,
|
|
38
|
+
),
|
|
39
|
+
"channel_id": pa.DataArraySchema(checks=check_stringy), # TODO check if works
|
|
40
|
+
},
|
|
41
|
+
coords={"channel": pa.Coordinate(checks=check_floating)},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
_SRF_OTHER_SCHEMAS = [
|
|
45
|
+
pa.DatasetSchema(
|
|
46
|
+
data_vars={
|
|
47
|
+
"srf": pa.DataArraySchema(
|
|
48
|
+
checks=check_floating, dims=[None, "channel"], nullable=True
|
|
49
|
+
),
|
|
50
|
+
"wavelength": pa.DataArraySchema(
|
|
51
|
+
checks=check_floating,
|
|
52
|
+
dims=[None, "channel"],
|
|
53
|
+
attrs={"units": _UNITS_REGEX},
|
|
54
|
+
nullable=True,
|
|
55
|
+
),
|
|
56
|
+
},
|
|
57
|
+
coords={
|
|
58
|
+
"channel": pa.Coordinate(checks=check_floating),
|
|
59
|
+
"channel_id": pa.Coordinate(checks=check_stringy),
|
|
60
|
+
},
|
|
61
|
+
),
|
|
62
|
+
pa.DatasetSchema(
|
|
63
|
+
data_vars={
|
|
64
|
+
"srf": pa.DataArraySchema(
|
|
65
|
+
checks=check_floating, dims=[None, None], nullable=True
|
|
66
|
+
),
|
|
67
|
+
"wavelength": pa.DataArraySchema(
|
|
68
|
+
checks=check_floating,
|
|
69
|
+
dims=[None, None],
|
|
70
|
+
attrs={"units": _UNITS_REGEX},
|
|
71
|
+
nullable=True,
|
|
72
|
+
),
|
|
73
|
+
"channel": pa.DataArraySchema(checks=check_floating),
|
|
74
|
+
"channel_id": pa.DataArraySchema(checks=check_stringy),
|
|
75
|
+
},
|
|
76
|
+
),
|
|
77
|
+
pa.DatasetSchema(
|
|
78
|
+
data_vars={
|
|
79
|
+
"srf": pa.DataArraySchema(
|
|
80
|
+
checks=check_floating, dims=[None, "wavelength"], nullable=True
|
|
81
|
+
),
|
|
82
|
+
"channel_id": pa.DataArraySchema(checks=check_stringy),
|
|
83
|
+
},
|
|
84
|
+
coords={
|
|
85
|
+
"channel": pa.Coordinate(checks=check_floating),
|
|
86
|
+
"wavelength": pa.Coordinate(checks=check_floating, nullable=True),
|
|
87
|
+
},
|
|
88
|
+
checks=[
|
|
89
|
+
pa.Check(
|
|
90
|
+
lambda ds: re.match(
|
|
91
|
+
_UNITS_REGEX, ds.coords["wavelength"].attrs.get("units", "")
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
],
|
|
95
|
+
),
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _validate_schema_srf(ds: xr.Dataset, strict: bool = False):
|
|
100
|
+
"""Validates that a xarray dataset follows the SRF schema.
|
|
101
|
+
|
|
102
|
+
The dataset structure is:
|
|
103
|
+
|
|
104
|
+
coordinates: 'channel': float
|
|
105
|
+
dims without coordinates: Any name, for example 'sample'.
|
|
106
|
+
data_vars: 'srf': float, 'wavelength': float, 'channel_id': str
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
ds: xr.Dataset
|
|
111
|
+
Dataset to validate
|
|
112
|
+
strict: bool
|
|
113
|
+
Flag to specify if the check must be exact to the desired schema, or if
|
|
114
|
+
it can pass if it would work in most cases.
|
|
115
|
+
"""
|
|
116
|
+
schema = _SRF_SCHEMA
|
|
117
|
+
if strict:
|
|
118
|
+
validate_schema(schema, ds)
|
|
119
|
+
else:
|
|
120
|
+
validate_schema(schema, ds, _SRF_OTHER_SCHEMAS)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def validate_srf(data: Union[xr.Dataset, str, Path], strict: bool = False) -> None:
|
|
124
|
+
"""Validates that a dataset follows the SRF schema.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
data : xr.Dataset or str or pathlib.Path
|
|
129
|
+
Dataset to validate, or path to a NetCDF file that will be opened
|
|
130
|
+
and validated. If a path is given, the file is opened in read-only
|
|
131
|
+
mode and closed before returning.
|
|
132
|
+
strict : bool
|
|
133
|
+
Flag to specify if the check must be exact to the desired schema, or
|
|
134
|
+
if it can pass if it would work in most cases.
|
|
135
|
+
|
|
136
|
+
Raises
|
|
137
|
+
------
|
|
138
|
+
TypeError
|
|
139
|
+
If ``data`` is neither an ``xr.Dataset``, ``str`` nor ``Path``.
|
|
140
|
+
ValueError
|
|
141
|
+
If the dataset does not conform to any of the accepted SRF schemas.
|
|
142
|
+
"""
|
|
143
|
+
with _as_ctx(data) as ds:
|
|
144
|
+
_validate_schema_srf(ds, strict=strict)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _validate_srf_for_obs(ds_srf: xr.Dataset, ds_obs: xr.Dataset) -> None:
|
|
148
|
+
def _channels(da: xr.DataArray) -> set[str]:
|
|
149
|
+
values = da.values
|
|
150
|
+
if values.dtype.kind == "S": # bytes -> str
|
|
151
|
+
values = np.char.decode(values, "utf-8")
|
|
152
|
+
return {str(v).rstrip("\x00") for v in values}
|
|
153
|
+
|
|
154
|
+
obs_ch_names = _channels(ds_obs["channel_name"])
|
|
155
|
+
srf_channel_ids = _channels(ds_srf["channel_id"])
|
|
156
|
+
|
|
157
|
+
missing = obs_ch_names - srf_channel_ids
|
|
158
|
+
if not missing:
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
raise pa.errors.SchemaError(
|
|
162
|
+
schema=ds_srf,
|
|
163
|
+
data=ds_obs,
|
|
164
|
+
message=(
|
|
165
|
+
"SRF is missing channel_ids required by the observation data: "
|
|
166
|
+
f"{sorted(missing)}"
|
|
167
|
+
),
|
|
168
|
+
check="srf_contains_obs_channels",
|
|
169
|
+
reason_code="DATA",
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def validate_srf_for_obs(
|
|
174
|
+
srf_data: Union[xr.Dataset, str, Path],
|
|
175
|
+
obs_data: Union[xr.Dataset, str, Path],
|
|
176
|
+
strict: bool = False,
|
|
177
|
+
) -> None:
|
|
178
|
+
"""Validates that a SRF dataset correctly represents the channels of an observation dataset.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
srf_data : xr.Dataset or str or pathlib.Path
|
|
183
|
+
SRF Dataset to validate, or path to a NetCDF file that will be opened
|
|
184
|
+
and validated. If a path is given, the file is opened in read-only
|
|
185
|
+
mode and closed before returning.
|
|
186
|
+
obs_data : xr.Dataset or str or pathlib.Path
|
|
187
|
+
Observation Dataset to validate, or path to a NetCDF file that will be opened
|
|
188
|
+
and validated. If a path is given, the file is opened in read-only
|
|
189
|
+
mode and closed before returning.
|
|
190
|
+
strict : bool
|
|
191
|
+
Prior to checking the channels, both datasets are validated independently.
|
|
192
|
+
This flag specifies if the check must be exact to the desired schema,
|
|
193
|
+
or if it can pass if it would work in most cases.
|
|
194
|
+
|
|
195
|
+
Raises
|
|
196
|
+
------
|
|
197
|
+
TypeError
|
|
198
|
+
If ``data`` is neither an ``xr.Dataset``, ``str`` nor ``Path``.
|
|
199
|
+
ValueError
|
|
200
|
+
If the dataset does not conform to any of the accepted SRF schemas.
|
|
201
|
+
"""
|
|
202
|
+
validate_srf(srf_data, strict)
|
|
203
|
+
moon.validate_moon_observation(obs_data, strict)
|
|
204
|
+
with _as_ctx(srf_data) as ds_srf, _as_ctx(obs_data) as ds_obs:
|
|
205
|
+
_validate_srf_for_obs(ds_srf, ds_obs)
|
|
File without changes
|
|
Binary file
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Tests for moon module"""
|
|
2
|
+
import unittest
|
|
3
|
+
from importlib.resources import files, as_file
|
|
4
|
+
|
|
5
|
+
from glodformat.moon import validate_moon_observation
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestMoon(unittest.TestCase):
|
|
9
|
+
def test_val_moon(self):
|
|
10
|
+
data_file = files("glodformat.tests").joinpath(
|
|
11
|
+
"data/W_XX-EUMETSAT-Darmstadt,VISNIR+SUBSET+MOON,MSG3+SEVIRI_C_EUMG_20140318140112_01.nc"
|
|
12
|
+
)
|
|
13
|
+
with as_file(data_file) as path:
|
|
14
|
+
validate_moon_observation(path, strict=True)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if __name__ == "__main__":
|
|
18
|
+
unittest.main()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from importlib.resources import files, as_file
|
|
3
|
+
|
|
4
|
+
from glodformat.srf import validate_srf, validate_srf_for_obs
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestSRF(unittest.TestCase):
|
|
8
|
+
def test_val_srf(self):
|
|
9
|
+
data_file = files("glodformat.tests").joinpath(
|
|
10
|
+
"data/W_XX-EUMETSAT-Darmstadt_VIS+IR+SRF_MSG3+SEVIRI_C_EUMG.nc"
|
|
11
|
+
)
|
|
12
|
+
with as_file(data_file) as path:
|
|
13
|
+
validate_srf(path, strict=True)
|
|
14
|
+
|
|
15
|
+
def test_val_srf_for_obs(self):
|
|
16
|
+
srf_file = files("glodformat.tests").joinpath(
|
|
17
|
+
"data/W_XX-EUMETSAT-Darmstadt_VIS+IR+SRF_MSG3+SEVIRI_C_EUMG.nc"
|
|
18
|
+
)
|
|
19
|
+
obs_file = files("glodformat.tests").joinpath(
|
|
20
|
+
"data/W_XX-EUMETSAT-Darmstadt,VISNIR+SUBSET+MOON,MSG3+SEVIRI_C_EUMG_20140318140112_01.nc"
|
|
21
|
+
)
|
|
22
|
+
with as_file(srf_file) as srf_path, as_file(obs_file) as obs_path:
|
|
23
|
+
validate_srf_for_obs(srf_path, obs_path, strict=True)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if __name__ == "__main__":
|
|
27
|
+
unittest.main()
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: glodformat
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Reader and diagnostics toolkit for GLOD-based netCDF files.
|
|
5
|
+
Author-email: Javier Gatón Herguedas <gaton@goa.uva.es>
|
|
6
|
+
Maintainer-email: Javier Gatón Herguedas <gaton@goa.uva.es>
|
|
7
|
+
License-Expression: LGPL-3.0-only
|
|
8
|
+
Project-URL: Homepage, https://lime.uva.es
|
|
9
|
+
Project-URL: Repository, https://github.com/LIME-ESA/glodformat.git
|
|
10
|
+
Project-URL: Issues, https://github.com/LIME-ESA/glodformat/issues
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: netcdf4~=1.7
|
|
29
|
+
Requires-Dist: PyYAML~=6.0
|
|
30
|
+
Requires-Dist: pandera~=0.36.0
|
|
31
|
+
Requires-Dist: xarray>=2024.10.0
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest; extra == "dev"
|
|
35
|
+
Provides-Extra: docs
|
|
36
|
+
Requires-Dist: sphinx~=7.0; extra == "docs"
|
|
37
|
+
Requires-Dist: sphinx_rtd_theme; extra == "docs"
|
|
38
|
+
Requires-Dist: myst_parser; extra == "docs"
|
|
39
|
+
Requires-Dist: sphinxcontrib-openapi; extra == "docs"
|
|
40
|
+
Requires-Dist: linkify-it-py; extra == "docs"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
[](https://github.com/LIME-ESA/glodformat/tags)
|
|
44
|
+
[![License: LGPL 3.0][license-shield]][license-url]
|
|
45
|
+
[![Issues][issues-shield]][issues-url]
|
|
46
|
+
[![Stargazers][stars-shield]][stars-url]
|
|
47
|
+
|
|
48
|
+
<!-- PROJECT LOGO -->
|
|
49
|
+
<br />
|
|
50
|
+
<div align="center">
|
|
51
|
+
<a href="https://lime.uva.es">
|
|
52
|
+
<img src="https://raw.githubusercontent.com/LIME-ESA/glodformat/main/docs/images/glodformat_logo.png" alt="glodformat logo" height="80" style="height: 80px !important;">
|
|
53
|
+
</a>
|
|
54
|
+
|
|
55
|
+
<h3 align="center">glodformat</h3>
|
|
56
|
+
|
|
57
|
+
<p align="center">
|
|
58
|
+
Reader and diagnostics toolkit for GLOD-based netCDF files.
|
|
59
|
+
<br />
|
|
60
|
+
<!--<a href="https://lime-esa.github.io/glodformat/"><strong>Explore the docs »</strong></a>-->
|
|
61
|
+
<br />
|
|
62
|
+
</p>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
<!-- TABLE OF CONTENTS -->
|
|
67
|
+
<details>
|
|
68
|
+
<summary>Table of Contents</summary>
|
|
69
|
+
<ol>
|
|
70
|
+
<li>
|
|
71
|
+
<a href="#about-the-project">About The Project</a>
|
|
72
|
+
<ul>
|
|
73
|
+
<li><a href="#collaborators">Collaborators</a></li>
|
|
74
|
+
</ul>
|
|
75
|
+
</li>
|
|
76
|
+
<li>
|
|
77
|
+
<a href="#getting-started">Getting Started</a>
|
|
78
|
+
<ul>
|
|
79
|
+
<li><a href="#prerequisites">Prerequisites</a></li>
|
|
80
|
+
<li><a href="#installation">Installation</a></li>
|
|
81
|
+
</ul>
|
|
82
|
+
</li>
|
|
83
|
+
<li><a href="#usage">Usage</a></li>
|
|
84
|
+
<li><a href="#roadmap">Roadmap</a></li>
|
|
85
|
+
<li>
|
|
86
|
+
<a href="#development-guide">Development Guide</a>
|
|
87
|
+
<ul>
|
|
88
|
+
<li><a href="#versioning">Versioning</a></li>
|
|
89
|
+
<li><a href="#setting-up-the-environment">Setting Up the Environment</a></li>
|
|
90
|
+
<li><a href="#testing">Testing</a></li>
|
|
91
|
+
</ul>
|
|
92
|
+
</li>
|
|
93
|
+
<li><a href="#license">License</a></li>
|
|
94
|
+
<li><a href="#authors">Authors</a></li>
|
|
95
|
+
</ol>
|
|
96
|
+
</details>
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## About the project
|
|
100
|
+
|
|
101
|
+
`glodformat` is a Python package that helps validate the format of netCDF files derived
|
|
102
|
+
from GLOD and other specifications.
|
|
103
|
+
|
|
104
|
+
This library was developed for the LIME Toolbox, under the LIME projects development efforts.
|
|
105
|
+
More information about LIME can be found on [lime.uva.es](https://lime.uva.es).
|
|
106
|
+
|
|
107
|
+
### Collaborators
|
|
108
|
+
|
|
109
|
+
The LIME project is managed, financed and supported by the European Space
|
|
110
|
+
Agency ([ESA](https://esa.int)).
|
|
111
|
+
|
|
112
|
+
The project is a collaboration between multiple institutions, including:
|
|
113
|
+
- [NPL](https://npl.co.uk) (National Physics Laboratory, United Kingdom)
|
|
114
|
+
- [UVa](https://uva.es) (Universidad de Valladolid, Spain)
|
|
115
|
+
- [VITO](https://vito.be) (Vlaamse Instelling voor Technologisch Onderzoek, Belgium)
|
|
116
|
+
|
|
117
|
+
## Getting started
|
|
118
|
+
|
|
119
|
+
### Prerequisites
|
|
120
|
+
|
|
121
|
+
- Python >= 3.10
|
|
122
|
+
|
|
123
|
+
### Installation
|
|
124
|
+
|
|
125
|
+
The package is available at PyPI and can be installed with:
|
|
126
|
+
```sh
|
|
127
|
+
pip install glodformat
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Another option is installing the python package and its dependencies
|
|
131
|
+
directly from the cloned repository in editable mode by using:
|
|
132
|
+
```sh
|
|
133
|
+
pip install -e .
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Usage
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
import glodformat
|
|
140
|
+
|
|
141
|
+
# Functions accept both paths or loaded xarray datasets
|
|
142
|
+
glodformat.validate_srf("response.nc")
|
|
143
|
+
glodformat.validate_moon_observation("moon_obs.nc")
|
|
144
|
+
glodformat.validate_srf_for_obs("response.nc", "moon_obs.nc")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Roadmap
|
|
148
|
+
|
|
149
|
+
- [ ] Fully support checking if an observation file is correctly represented by a SRF file
|
|
150
|
+
- [ ] Add support for LIME Toolbox related formats
|
|
151
|
+
|
|
152
|
+
## Development Guide
|
|
153
|
+
|
|
154
|
+
### Versioning
|
|
155
|
+
|
|
156
|
+
Version changes and descriptions are stored in the <a href="./CHANGELOG.md">CHANGELOG</a>.
|
|
157
|
+
This file is updated each time a new version is released.
|
|
158
|
+
|
|
159
|
+
### Setting Up the Environment
|
|
160
|
+
|
|
161
|
+
To prepare your environment for development, testing or deployment, follow these steps:
|
|
162
|
+
|
|
163
|
+
1. **Install Pre-commit Hooks**
|
|
164
|
+
Install the `pre-commit` hooks to automatically check code styling:
|
|
165
|
+
```sh
|
|
166
|
+
pre-commit install
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
- When you commit changes, `black` will check your code for styling errors.
|
|
170
|
+
- If errors are found, they will be corrected, and the commit will be aborted to allow you to review the changes.
|
|
171
|
+
- If you're satisfied, reattempt the commit.
|
|
172
|
+
|
|
173
|
+
2. **Install Python Dependencies**
|
|
174
|
+
|
|
175
|
+
Install the python package dependencies listed in the `requirements.txt` file, preferably in a python virtual enironment:
|
|
176
|
+
```sh
|
|
177
|
+
pip install -r requirements.txt
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Testing
|
|
181
|
+
|
|
182
|
+
Run the following commands to ensure the code works as expected:
|
|
183
|
+
|
|
184
|
+
1. **Unit Tests**
|
|
185
|
+
To perform unit tests:
|
|
186
|
+
```sh
|
|
187
|
+
python3 -m unittest
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
Distributed under the LGPL-v3 License. See [LGPL v3](./LICENSE) for more information.
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
## Acknowledgements
|
|
197
|
+
|
|
198
|
+
* [Javier Gatón Herguedas](mailto:gaton@goa.uva.es) - [GOA-UVa](https://goa.uva.es)
|
|
199
|
+
* [Pieter De Vis](mailto:pieter.de.vis@npl.co.uk) - [NPL](https://npl.co.uk)
|
|
200
|
+
* [Stefan Adriaensen](mailto:stefan.adriaensen@vito.be) - [VITO](https://vito.be)
|
|
201
|
+
* [Jacob Fahy](mailto:jacob.fahy@npl.co.uk) - [NPL](https://npl.co.uk)
|
|
202
|
+
* [Ramiro González Catón](mailto:ramiro@goa.uva.es) - [GOA-UVa](https://goa.uva.es)
|
|
203
|
+
* [Carlos Toledano](mailto:toledano@goa.uva.es) - [GOA-UVa](https://goa.uva.es)
|
|
204
|
+
* [África Barreto](mailto:abarretov@aemet.es) - [AEMET](https://aemet.es)
|
|
205
|
+
* [Agnieszka Bialek](mailto:agnieszka.bialek@npl.co.uk) - [NPL](https://npl.co.uk)
|
|
206
|
+
* [Marc Bouvet](mailto:marc.bouvet@esa.int) - [ESA](https://esa.int)
|
|
207
|
+
|
|
208
|
+
[stars-shield]: https://img.shields.io/github/stars/LIME-ESA/glodformat.svg?style=for-the-badge
|
|
209
|
+
[stars-url]: https://github.com/LIME-ESA/glodformat/stargazers
|
|
210
|
+
[issues-shield]: https://img.shields.io/github/issues/LIME-ESA/glodformat.svg?style=for-the-badge
|
|
211
|
+
[issues-url]: https://github.com/LIME-ESA/glodformat/issues
|
|
212
|
+
[license-shield]: https://img.shields.io/github/license/LIME-ESA/glodformat.svg?style=for-the-badge
|
|
213
|
+
[license-url]: https://github.com/LIME-ESA/glodformat/blob/main/LICENSE
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
glodformat/__init__.py,sha256=Kbx2Pm0dxZOfhZSoAMG9uO_60o887YnICmrlPjNLwTg,116
|
|
2
|
+
glodformat/_version.py,sha256=6Fr5RRjm7dcNtKqECuaZKcxVk8ULxysaxd4Wt1wFjMo,254
|
|
3
|
+
glodformat/moon.py,sha256=RnwrX-5-ODF_K_7j4hRBcagLJfXb_F7eRSZZUP2vTwo,5043
|
|
4
|
+
glodformat/netcdfcommon.py,sha256=lqDJtof8XaifNOTrc5ETuvFEYRhntEjFsf8_ncrhm18,6924
|
|
5
|
+
glodformat/srf.py,sha256=b1il5tgpBbXdCK7vMt59vEWoTDPyLePMAwKkl9Eecl0,6695
|
|
6
|
+
glodformat/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
glodformat/tests/test_moon.py,sha256=GHh8omMqNQ7FZsXUb8zfdoPiyO7-C6-LAZM5nBWwu-Y,527
|
|
8
|
+
glodformat/tests/test_srf.py,sha256=lfyKfuP4Oc1hOQfLTn4ANrwtTs-HKuTE3IvltK-dMos,952
|
|
9
|
+
"glodformat/tests/data/W_XX-EUMETSAT-Darmstadt,VISNIR+SUBSET+MOON,MSG3+SEVIRI_C_EUMG_20140318140112_01.nc",sha256=9RwunNtejAwKOGE_yb6iR7HNDp6ypXX25m5gtfmXvT8,252693
|
|
10
|
+
glodformat/tests/data/W_XX-EUMETSAT-Darmstadt_VIS+IR+SRF_MSG3+SEVIRI_C_EUMG.nc,sha256=K8NonT30emxud-er42PdWCcsfr-22tcQjWbjYU5InTo,62918
|
|
11
|
+
glodformat-0.0.1.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
12
|
+
glodformat-0.0.1.dist-info/METADATA,sha256=xLNPYMpP-mcEwA5Iq4jCJYOSqOQ3IsenMon1a0hh4jM,7367
|
|
13
|
+
glodformat-0.0.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
14
|
+
glodformat-0.0.1.dist-info/top_level.txt,sha256=Eznz5y9S10OcJviz7wFkEo_blPEprE7WNiOrmu-rSic,11
|
|
15
|
+
glodformat-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
GNU LESSER GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 3, 29 June 2007
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
5
|
+
Everyone is permitted to copy and distribute verbatim copies
|
|
6
|
+
of this license document, but changing it is not allowed.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
This version of the GNU Lesser General Public License incorporates
|
|
10
|
+
the terms and conditions of version 3 of the GNU General Public
|
|
11
|
+
License, supplemented by the additional permissions listed below.
|
|
12
|
+
|
|
13
|
+
0. Additional Definitions.
|
|
14
|
+
|
|
15
|
+
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
16
|
+
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
17
|
+
General Public License.
|
|
18
|
+
|
|
19
|
+
"The Library" refers to a covered work governed by this License,
|
|
20
|
+
other than an Application or a Combined Work as defined below.
|
|
21
|
+
|
|
22
|
+
An "Application" is any work that makes use of an interface provided
|
|
23
|
+
by the Library, but which is not otherwise based on the Library.
|
|
24
|
+
Defining a subclass of a class defined by the Library is deemed a mode
|
|
25
|
+
of using an interface provided by the Library.
|
|
26
|
+
|
|
27
|
+
A "Combined Work" is a work produced by combining or linking an
|
|
28
|
+
Application with the Library. The particular version of the Library
|
|
29
|
+
with which the Combined Work was made is also called the "Linked
|
|
30
|
+
Version".
|
|
31
|
+
|
|
32
|
+
The "Minimal Corresponding Source" for a Combined Work means the
|
|
33
|
+
Corresponding Source for the Combined Work, excluding any source code
|
|
34
|
+
for portions of the Combined Work that, considered in isolation, are
|
|
35
|
+
based on the Application, and not on the Linked Version.
|
|
36
|
+
|
|
37
|
+
The "Corresponding Application Code" for a Combined Work means the
|
|
38
|
+
object code and/or source code for the Application, including any data
|
|
39
|
+
and utility programs needed for reproducing the Combined Work from the
|
|
40
|
+
Application, but excluding the System Libraries of the Combined Work.
|
|
41
|
+
|
|
42
|
+
1. Exception to Section 3 of the GNU GPL.
|
|
43
|
+
|
|
44
|
+
You may convey a covered work under sections 3 and 4 of this License
|
|
45
|
+
without being bound by section 3 of the GNU GPL.
|
|
46
|
+
|
|
47
|
+
2. Conveying Modified Versions.
|
|
48
|
+
|
|
49
|
+
If you modify a copy of the Library, and, in your modifications, a
|
|
50
|
+
facility refers to a function or data to be supplied by an Application
|
|
51
|
+
that uses the facility (other than as an argument passed when the
|
|
52
|
+
facility is invoked), then you may convey a copy of the modified
|
|
53
|
+
version:
|
|
54
|
+
|
|
55
|
+
a) under this License, provided that you make a good faith effort to
|
|
56
|
+
ensure that, in the event an Application does not supply the
|
|
57
|
+
function or data, the facility still operates, and performs
|
|
58
|
+
whatever part of its purpose remains meaningful, or
|
|
59
|
+
|
|
60
|
+
b) under the GNU GPL, with none of the additional permissions of
|
|
61
|
+
this License applicable to that copy.
|
|
62
|
+
|
|
63
|
+
3. Object Code Incorporating Material from Library Header Files.
|
|
64
|
+
|
|
65
|
+
The object code form of an Application may incorporate material from
|
|
66
|
+
a header file that is part of the Library. You may convey such object
|
|
67
|
+
code under terms of your choice, provided that, if the incorporated
|
|
68
|
+
material is not limited to numerical parameters, data structure
|
|
69
|
+
layouts and accessors, or small macros, inline functions and templates
|
|
70
|
+
(ten or fewer lines in length), you do both of the following:
|
|
71
|
+
|
|
72
|
+
a) Give prominent notice with each copy of the object code that the
|
|
73
|
+
Library is used in it and that the Library and its use are
|
|
74
|
+
covered by this License.
|
|
75
|
+
|
|
76
|
+
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
77
|
+
document.
|
|
78
|
+
|
|
79
|
+
4. Combined Works.
|
|
80
|
+
|
|
81
|
+
You may convey a Combined Work under terms of your choice that,
|
|
82
|
+
taken together, effectively do not restrict modification of the
|
|
83
|
+
portions of the Library contained in the Combined Work and reverse
|
|
84
|
+
engineering for debugging such modifications, if you also do each of
|
|
85
|
+
the following:
|
|
86
|
+
|
|
87
|
+
a) Give prominent notice with each copy of the Combined Work that
|
|
88
|
+
the Library is used in it and that the Library and its use are
|
|
89
|
+
covered by this License.
|
|
90
|
+
|
|
91
|
+
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
92
|
+
document.
|
|
93
|
+
|
|
94
|
+
c) For a Combined Work that displays copyright notices during
|
|
95
|
+
execution, include the copyright notice for the Library among
|
|
96
|
+
these notices, as well as a reference directing the user to the
|
|
97
|
+
copies of the GNU GPL and this license document.
|
|
98
|
+
|
|
99
|
+
d) Do one of the following:
|
|
100
|
+
|
|
101
|
+
0) Convey the Minimal Corresponding Source under the terms of this
|
|
102
|
+
License, and the Corresponding Application Code in a form
|
|
103
|
+
suitable for, and under terms that permit, the user to
|
|
104
|
+
recombine or relink the Application with a modified version of
|
|
105
|
+
the Linked Version to produce a modified Combined Work, in the
|
|
106
|
+
manner specified by section 6 of the GNU GPL for conveying
|
|
107
|
+
Corresponding Source.
|
|
108
|
+
|
|
109
|
+
1) Use a suitable shared library mechanism for linking with the
|
|
110
|
+
Library. A suitable mechanism is one that (a) uses at run time
|
|
111
|
+
a copy of the Library already present on the user's computer
|
|
112
|
+
system, and (b) will operate properly with a modified version
|
|
113
|
+
of the Library that is interface-compatible with the Linked
|
|
114
|
+
Version.
|
|
115
|
+
|
|
116
|
+
e) Provide Installation Information, but only if you would otherwise
|
|
117
|
+
be required to provide such information under section 6 of the
|
|
118
|
+
GNU GPL, and only to the extent that such information is
|
|
119
|
+
necessary to install and execute a modified version of the
|
|
120
|
+
Combined Work produced by recombining or relinking the
|
|
121
|
+
Application with a modified version of the Linked Version. (If
|
|
122
|
+
you use option 4d0, the Installation Information must accompany
|
|
123
|
+
the Minimal Corresponding Source and Corresponding Application
|
|
124
|
+
Code. If you use option 4d1, you must provide the Installation
|
|
125
|
+
Information in the manner specified by section 6 of the GNU GPL
|
|
126
|
+
for conveying Corresponding Source.)
|
|
127
|
+
|
|
128
|
+
5. Combined Libraries.
|
|
129
|
+
|
|
130
|
+
You may place library facilities that are a work based on the
|
|
131
|
+
Library side by side in a single library together with other library
|
|
132
|
+
facilities that are not Applications and are not covered by this
|
|
133
|
+
License, and convey such a combined library under terms of your
|
|
134
|
+
choice, if you do both of the following:
|
|
135
|
+
|
|
136
|
+
a) Accompany the combined library with a copy of the same work based
|
|
137
|
+
on the Library, uncombined with any other library facilities,
|
|
138
|
+
conveyed under the terms of this License.
|
|
139
|
+
|
|
140
|
+
b) Give prominent notice with the combined library that part of it
|
|
141
|
+
is a work based on the Library, and explaining where to find the
|
|
142
|
+
accompanying uncombined form of the same work.
|
|
143
|
+
|
|
144
|
+
6. Revised Versions of the GNU Lesser General Public License.
|
|
145
|
+
|
|
146
|
+
The Free Software Foundation may publish revised and/or new versions
|
|
147
|
+
of the GNU Lesser General Public License from time to time. Such new
|
|
148
|
+
versions will be similar in spirit to the present version, but may
|
|
149
|
+
differ in detail to address new problems or concerns.
|
|
150
|
+
|
|
151
|
+
Each version is given a distinguishing version number. If the
|
|
152
|
+
Library as you received it specifies that a certain numbered version
|
|
153
|
+
of the GNU Lesser General Public License "or any later version"
|
|
154
|
+
applies to it, you have the option of following the terms and
|
|
155
|
+
conditions either of that published version or of any later version
|
|
156
|
+
published by the Free Software Foundation. If the Library as you
|
|
157
|
+
received it does not specify a version number of the GNU Lesser
|
|
158
|
+
General Public License, you may choose any version of the GNU Lesser
|
|
159
|
+
General Public License ever published by the Free Software Foundation.
|
|
160
|
+
|
|
161
|
+
If the Library as you received it specifies that a proxy can decide
|
|
162
|
+
whether future versions of the GNU Lesser General Public License shall
|
|
163
|
+
apply, that proxy's public statement of acceptance of any version is
|
|
164
|
+
permanent authorization for you to choose that version for the
|
|
165
|
+
Library.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
glodformat
|