Skip to content

Commit

Permalink
Reorg files
Browse files Browse the repository at this point in the history
  • Loading branch information
ghiggi committed Oct 10, 2023
1 parent c37fcb7 commit 22a8d09
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 252 deletions.
4 changes: 2 additions & 2 deletions satpy/_scene_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def to_xarray(scn,
epoch (str):
Reference time for encoding the time coordinates (if available).
Example format: "seconds since 1970-01-01 00:00:00".
If None, the default reference time is retrieved using "from satpy.cf_writer import EPOCH"
If None, the default reference time is retrieved using "from satpy.writers.cf import EPOCH"
flatten_attrs (bool):
If True, flatten dict-type attributes.
exclude_attrs (list):
Expand All @@ -90,8 +90,8 @@ def to_xarray(scn,
A CF-compliant xr.Dataset
"""
from satpy.writers.cf import EPOCH
from satpy.writers.cf.datasets import collect_cf_datasets

Check warning on line 94 in satpy/_scene_converters.py

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Large Method

to_xarray increases from 75 to 76 lines of code, threshold = 70. Large functions with many lines of code are generally harder to understand and lower the code health. Avoid adding more lines to this function.
from satpy.writers.cf.time import EPOCH

if epoch is None:
epoch = EPOCH
Expand Down
2 changes: 1 addition & 1 deletion satpy/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -1128,7 +1128,7 @@ def to_xarray(self,
epoch (str):
Reference time for encoding the time coordinates (if available).
Example format: "seconds since 1970-01-01 00:00:00".
If None, the default reference time is retrieved using "from satpy.cf_writer import EPOCH"
If None, the default reference time is retrieved using "from satpy.writers.cf import EPOCH"
flatten_attrs (bool):
If True, flatten dict-type attributes.
exclude_attrs (list):
Expand Down
15 changes: 15 additions & 0 deletions satpy/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,3 +407,18 @@ def assert_attrs_equal(attrs, attrs_exp, tolerance=0):
)
except TypeError:
assert attrs[key] == attrs_exp[key], err_msg


def assert_dict_array_equality(d1, d2):
"""Check that dicts containing arrays are equal."""
assert set(d1.keys()) == set(d2.keys())
for key, val1 in d1.items():
val2 = d2[key]
if isinstance(val1, np.ndarray):
np.testing.assert_array_equal(val1, val2)
assert val1.dtype == val2.dtype
else:
assert val1 == val2
if isinstance(val1, (np.floating, np.integer, np.bool_)):
assert isinstance(val2, np.generic)
assert val1.dtype == val2.dtype

Check warning on line 424 in satpy/tests/utils.py

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Bumpy Road Ahead

assert_dict_array_equality has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function. The Bumpy Road code smell is a function that contains multiple chunks of nested conditional logic. The deeper the nesting and the more bumps, the lower the code health.
32 changes: 0 additions & 32 deletions satpy/tests/writer_tests/cf_tests/test_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,12 @@
# You should have received a copy of the GNU General Public License along with
# satpy. If not, see <http://www.gnu.org/licenses/>.
"""Tests for the CF Area."""
import logging

import dask.array as da
import numpy as np
import pytest
import xarray as xr
from pyresample import AreaDefinition, SwathDefinition

# NOTE:
# The following fixtures are not defined in this file, but are used and injected by Pytest:
# - caplog


class TestCFArea:
"""Test case for CF Area."""
Expand Down Expand Up @@ -406,32 +400,6 @@ def test__add_lonlat_coords(self):
assert {'name': 'latitude', 'standard_name': 'latitude', 'units': 'degrees_north'}.items() <= lat.attrs.items()
assert {'name': 'longitude', 'standard_name': 'longitude', 'units': 'degrees_east'}.items() <= lon.attrs.items()

def test_is_projected(self, caplog):
"""Tests for private _is_projected function."""
from satpy.writers.cf.crs import _is_projected

# test case with units but no area
da = xr.DataArray(
np.arange(25).reshape(5, 5),
dims=("y", "x"),
coords={"x": xr.DataArray(np.arange(5), dims=("x",), attrs={"units": "m"}),
"y": xr.DataArray(np.arange(5), dims=("y",), attrs={"units": "m"})})
assert _is_projected(da)

da = xr.DataArray(
np.arange(25).reshape(5, 5),
dims=("y", "x"),
coords={"x": xr.DataArray(np.arange(5), dims=("x",), attrs={"units": "degrees_east"}),
"y": xr.DataArray(np.arange(5), dims=("y",), attrs={"units": "degrees_north"})})
assert not _is_projected(da)

da = xr.DataArray(
np.arange(25).reshape(5, 5),
dims=("y", "x"))
with caplog.at_level(logging.WARNING):
assert _is_projected(da)
assert "Failed to tell if data are projected." in caplog.text

@pytest.fixture
def datasets(self):
"""Create test dataset."""
Expand Down
18 changes: 2 additions & 16 deletions satpy/tests/writer_tests/cf_tests/test_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,30 +109,16 @@ def get_test_attrs(self):
'raw_metadata_dict_b': np.array([1, 2, 3], dtype='uint8')}
return attrs, encoded, encoded_flat

Check warning on line 110 in satpy/tests/writer_tests/cf_tests/test_attrs.py

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Large Method

TestCFAttributeEncoding.get_test_attrs has 79 lines, threshold = 70. Large functions with many lines of code are generally harder to understand and lower the code health. Avoid adding more lines to this function.

def assertDictWithArraysEqual(self, d1, d2):
"""Check that dicts containing arrays are equal."""
# TODO: this is also used by test_da2cf
assert set(d1.keys()) == set(d2.keys())
for key, val1 in d1.items():
val2 = d2[key]
if isinstance(val1, np.ndarray):
np.testing.assert_array_equal(val1, val2)
assert val1.dtype == val2.dtype
else:
assert val1 == val2
if isinstance(val1, (np.floating, np.integer, np.bool_)):
assert isinstance(val2, np.generic)
assert val1.dtype == val2.dtype

def test__encode_attrs_nc(self):
"""Test attributes encoding."""
from satpy.tests.utils import assert_dict_array_equality
from satpy.writers.cf.attrs import _encode_attrs_nc

attrs, expected, _ = self.get_test_attrs()

# Test encoding
encoded = _encode_attrs_nc(attrs)
self.assertDictWithArraysEqual(expected, encoded)
assert_dict_array_equality(expected, encoded)

# Test decoding of json-encoded attributes
raw_md_roundtrip = {'recarray': [[0, 0], [0, 0], [0, 0]],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@
# You should have received a copy of the GNU General Public License along with
# satpy. If not, see <http://www.gnu.org/licenses/>.
"""CF processing of time information (coordinates and dimensions)."""
import logging

import numpy as np
import xarray as xr

# NOTE:
# The following fixtures are not defined in this file, but are used and injected by Pytest:
# - caplog


class TestCFtime:
"""Test cases for CF time dimension and coordinates."""

def test_add_time_bounds_dimension(self):
"""Test addition of CF-compliant time attributes."""
from satpy.writers.cf.time import add_time_bounds_dimension
from satpy.writers.cf.coords import add_time_bounds_dimension

test_array = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
times = np.array(['2018-05-30T10:05:00', '2018-05-30T10:05:01',
Expand All @@ -42,3 +48,36 @@ def test_add_time_bounds_dimension(self):
assert "time_bnds" in list(ds.data_vars)
assert "bounds" in ds["time"].attrs
assert "standard_name" in ds["time"].attrs


class TestCFcoords:
"""Test cases for CF spatial dimension and coordinates."""

def test_is_projected(self, caplog):
"""Tests for private _is_projected function."""
from satpy.writers.cf.coords import _is_projected

# test case with units but no area
da = xr.DataArray(
np.arange(25).reshape(5, 5),
dims=("y", "x"),
coords={"x": xr.DataArray(np.arange(5), dims=("x",), attrs={"units": "m"}),
"y": xr.DataArray(np.arange(5), dims=("y",), attrs={"units": "m"})})
assert _is_projected(da)

da = xr.DataArray(
np.arange(25).reshape(5, 5),
dims=("y", "x"),
coords={"x": xr.DataArray(np.arange(5), dims=("x",), attrs={"units": "degrees_east"}),
"y": xr.DataArray(np.arange(5), dims=("y",), attrs={"units": "degrees_north"})})
assert not _is_projected(da)

da = xr.DataArray(
np.arange(25).reshape(5, 5),
dims=("y", "x"))
with caplog.at_level(logging.WARNING):
assert _is_projected(da)
assert "Failed to tell if data are projected." in caplog.text

# add_xy_coords_attrs
# process_time_coord
22 changes: 5 additions & 17 deletions satpy/tests/writer_tests/cf_tests/test_dataaarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,23 +154,9 @@ def get_test_attrs(self):
'raw_metadata_dict_b': np.array([1, 2, 3], dtype='uint8')}
return attrs, encoded, encoded_flat

Check warning on line 155 in satpy/tests/writer_tests/cf_tests/test_dataaarray.py

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Large Method

TestCfDataArray.get_test_attrs has 79 lines, threshold = 70. Large functions with many lines of code are generally harder to understand and lower the code health. Avoid adding more lines to this function.

def assertDictWithArraysEqual(self, d1, d2):
"""Check that dicts containing arrays are equal."""
# TODO: also used by cf/test_attrs.py
assert set(d1.keys()) == set(d2.keys())
for key, val1 in d1.items():
val2 = d2[key]
if isinstance(val1, np.ndarray):
np.testing.assert_array_equal(val1, val2)
assert val1.dtype == val2.dtype
else:
assert val1 == val2
if isinstance(val1, (np.floating, np.integer, np.bool_)):
assert isinstance(val2, np.generic)
assert val1.dtype == val2.dtype

def test_make_cf_dataarray(self):
"""Test the conversion of a DataArray to a CF-compatible DataArray."""
from satpy.tests.utils import assert_dict_array_equality
from satpy.writers.cf.dataarray import make_cf_dataarray

# Create set of test attributes
Expand Down Expand Up @@ -200,12 +186,12 @@ def test_make_cf_dataarray(self):
np.testing.assert_array_equal(res['acq_time'], arr['acq_time'])
assert res['x'].attrs == {'units': 'm', 'standard_name': 'projection_x_coordinate'}
assert res['y'].attrs == {'units': 'm', 'standard_name': 'projection_y_coordinate'}
self.assertDictWithArraysEqual(res.attrs, attrs_expected)
assert_dict_array_equality(res.attrs, attrs_expected)

# Test attribute kwargs
res_flat = make_cf_dataarray(arr, flatten_attrs=True, exclude_attrs=['int'])
attrs_expected_flat.pop('int')
self.assertDictWithArraysEqual(res_flat.attrs, attrs_expected_flat)
assert_dict_array_equality(res_flat.attrs, attrs_expected_flat)

def test_make_cf_dataarray_one_dimensional_array(self):
"""Test the conversion of an 1d DataArray to a CF-compatible DataArray."""
Expand All @@ -214,3 +200,5 @@ def test_make_cf_dataarray_one_dimensional_array(self):
arr = xr.DataArray(np.array([1, 2, 3, 4]), attrs={}, dims=('y',),
coords={'y': [0, 1, 2, 3], 'acq_time': ('y', [0, 1, 2, 3])})
_ = make_cf_dataarray(arr)

# _handle_dataarray_name
27 changes: 15 additions & 12 deletions satpy/tests/writer_tests/cf_tests/test_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#
# You should have received a copy of the GNU General Public License along with
# satpy. If not, see <http://www.gnu.org/licenses/>.
"""Tests CF-compliant DataArray creation."""
"""Tests CF-compliant Dataset(s) creation."""
import datetime

import numpy as np
Expand All @@ -24,18 +24,10 @@
from pyresample import AreaDefinition, create_area_def


def test_empty_collect_cf_datasets():
"""Test that if no DataArrays, collect_cf_datasets raise error."""
from satpy.writers.cf.datasets import collect_cf_datasets

with pytest.raises(RuntimeError):
collect_cf_datasets(list_dataarrays=[])


class TestCollectCfDatasets:
class TestCollectCfDataset:
"""Test case for collect_cf_dataset."""

def test_collect_cf_dataarrays(self):
def test_collect_cf_dataset(self):
"""Test collecting CF datasets from a DataArray objects."""
from satpy.writers.cf.datasets import _collect_cf_dataset

Expand Down Expand Up @@ -75,7 +67,7 @@ def test_collect_cf_dataarrays(self):
assert 'grid_mapping' not in da_var2.attrs
assert da_var2.attrs['long_name'] == 'variable 2'

def test_collect_cf_dataarrays_with_latitude_named_lat(self):
def test_collect_cf_dataset_with_latitude_named_lat(self):
"""Test collecting CF datasets with latitude named lat."""
from satpy.writers.cf.datasets import _collect_cf_dataset

Expand Down Expand Up @@ -148,3 +140,14 @@ def test_geographic_area_coords_attrs(self):
assert ds["mavas"].attrs["longitude_of_prime_meridian"] == 0.0
np.testing.assert_allclose(ds["mavas"].attrs["semi_major_axis"], 6378137.0)
np.testing.assert_allclose(ds["mavas"].attrs["inverse_flattening"], 298.257223563)


class TestCollectCfDatasets:
"""Test case for collect_cf_datasets."""

def test_empty_collect_cf_datasets(self):
"""Test that if no DataArrays, collect_cf_datasets raise error."""
from satpy.writers.cf.datasets import collect_cf_datasets

with pytest.raises(RuntimeError):
collect_cf_datasets(list_dataarrays=[])
4 changes: 2 additions & 2 deletions satpy/tests/writer_tests/cf_tests/test_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import xarray as xr


class TestUpdateDatasetEncodings:
"""Test update of Dataset encodings."""
class TestUpdateEncoding:
"""Test update of dataset encodings."""

@pytest.fixture
def fake_ds(self):
Expand Down
2 changes: 2 additions & 0 deletions satpy/writers/cf/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Code for generation of CF-compliant datasets."""

EPOCH = u"seconds since 1970-01-01 00:00:00"
Loading

0 comments on commit 22a8d09

Please sign in to comment.