Skip to content

Commit

Permalink
update deprecation tests
Browse files Browse the repository at this point in the history
  • Loading branch information
VeckoTheGecko committed Sep 27, 2024
1 parent 13d2e36 commit f174e36
Showing 1 changed file with 158 additions and 89 deletions.
247 changes: 158 additions & 89 deletions tests/test_deprecations.py
Original file line number Diff line number Diff line change
@@ -1,112 +1,181 @@
import inspect
from typing import Literal

import pytest

from parcels import Field, FieldSet
from tests.utils import create_fieldset_unit_mesh

fieldset = create_fieldset_unit_mesh()
field = fieldset.U

private_field_attrs = [
"_dataFiles",
"_loaded_time_indices",
"_creation_log",
"_data_chunks",
"_c_data_chunks",
"_chunk_set",
class Action:
"""Utility class to help manage, document, and test deprecations."""

def __init__(self, class_: Literal["Field", "FieldSet"], name: str, type_: Literal["read_only", "make_private"]):
if name.startswith("_"):
raise ValueError("name should not start with an underscore")

self.class_ = class_
self._raw_name = name
self.type_ = type_

if type_ == "read_only" and self.is_method:
raise ValueError("read_only attributes should not be methods")

@property
def public_name(self):
return self._raw_name.strip("()")

@property
def private_name(self):
if self.type_ == "make_private":
return f"_{self.public_name}"
return None

@property
def is_method(self):
if self._raw_name.endswith("()"):
return True
return False

def __str__(self):
return f"{self.class_}.{self.public_name}"

def __repr__(self):
return f"Action(class_={self.class_!r}, name={self._raw_name!r}, type_={self.type_!r})"

Check warning on line 44 in tests/test_deprecations.py

View check run for this annotation

Codecov / codecov/patch

tests/test_deprecations.py#L44

Added line #L44 was not covered by tests


def test_testing_action_class():
"""Testing the Action class used for testing."""
action = Action("MyClass", "my_attribute", "make_private")
assert not action.is_method
assert action.public_name == "my_attribute"
assert action.private_name == "_my_attribute"
assert action.class_ == "MyClass"
assert action.type_ == "make_private"

action = Action("Field", "my_attribute", "read_only")
assert not action.is_method
assert action.public_name == "my_attribute"
assert action.private_name is None
assert not action.is_method

action = Action("Field", "my_method()", "make_private")
assert action.is_method
assert action.public_name == "my_method"
assert action.private_name == "_my_method"

with pytest.raises(ValueError): # Can't have underscore in name
Action("Field", "_my_attribute", "make_private")

with pytest.raises(ValueError): # Can't have read-only method
Action("Field", "my_method()", "read_only")


# fmt: off
actions = [
Action("Field", "dataFiles", "make_private" ),
Action("Field", "netcdf_engine", "read_only" ),
Action("Field", "loaded_time_indices", "make_private" ),
Action("Field", "creation_log", "make_private" ),
Action("Field", "data_chunks", "make_private" ),
Action("Field", "c_data_chunks", "make_private" ),
Action("Field", "chunk_set", "make_private" ),
Action("Field", "cell_edge_sizes", "read_only" ),
Action("Field", "get_dim_filenames()", "make_private" ),
Action("Field", "collect_timeslices()", "make_private" ),
Action("Field", "reshape()", "make_private" ),
Action("Field", "calc_cell_edge_sizes()", "make_private" ),
Action("Field", "search_indices_vertical_z()", "make_private" ),
Action("Field", "search_indices_vertical_s()", "make_private" ),
Action("Field", "reconnect_bnd_indices()", "make_private" ),
Action("Field", "search_indices_rectilinear()", "make_private" ),
Action("Field", "search_indices_curvilinear()", "make_private" ),
Action("Field", "search_indices()", "make_private" ),
Action("Field", "interpolator2D()", "make_private" ),
Action("Field", "interpolator3D()", "make_private" ),
Action("Field", "spatial_interpolation()", "make_private" ),
Action("Field", "time_index()", "make_private" ),
Action("Field", "ccode_eval()", "make_private" ),
Action("Field", "ccode_convert()", "make_private" ),
Action("Field", "get_block_id()", "make_private" ),
Action("Field", "get_block()", "make_private" ),
Action("Field", "chunk_setup()", "make_private" ),
Action("Field", "chunk_data()", "make_private" ),
Action("Field", "rescale_and_set_minmax()", "make_private" ),
Action("Field", "data_concatenate()", "make_private" ),
Action("FieldSet", "completed", "make_private" ),
Action("FieldSet", "particlefile", "read_only" ),
Action("FieldSet", "add_UVfield()", "make_private" ),
Action("FieldSet", "check_complete()", "make_private" ),
Action("FieldSet", "parse_wildcards()", "make_private" ),
]
# fmt: on

# Create test data dictionary
fieldset = create_fieldset_unit_mesh()
field = fieldset.U

class FieldPrivate:
attributes = [
"_dataFiles",
"_loaded_time_indices",
"_creation_log",
"_data_chunks",
"_c_data_chunks",
"_chunk_set",
]
methods = [
"_get_dim_filenames",
"_collect_timeslices",
"_reshape",
"_calc_cell_edge_sizes",
"_search_indices_vertical_z",
"_search_indices_vertical_s",
"_reconnect_bnd_indices",
"_search_indices_rectilinear",
"_search_indices_curvilinear",
"_search_indices",
"_interpolator2D",
"_interpolator3D",
"_ccode_eval",
"_ccode_convert",
"_get_block_id",
"_get_block",
"_chunk_setup",
"_chunk_data",
"_rescale_and_set_minmax",
"_data_concatenate",
"_spatial_interpolation",
"_time_index",
]


class FieldSetPrivate:
attributes = [
"_completed",
]
methods = [
"_add_UVfield",
"_parse_wildcards",
"_check_complete",
]


def assert_private_public_attribute_equiv(obj, private_attribute: str):
assert private_attribute.startswith("_")
attribute = private_attribute.lstrip("_")
test_data = {
"Field": {
"class": Field,
"object": field,
},
"FieldSet": {
"class": FieldSet,
"object": fieldset,
},
}


@pytest.mark.parametrize(
"private_attribute_action",
filter(lambda action: not action.is_method and action.type_ == "make_private", actions),
ids=str,
)
def test_private_attrib(private_attribute_action: Action):
"""Checks that the public attribute is equivalent to the private attribute."""
action = private_attribute_action

obj = test_data[action.class_]["object"]

with pytest.raises(DeprecationWarning):
assert hasattr(obj, attribute)
assert hasattr(obj, private_attribute)
assert getattr(obj, attribute) is getattr(obj, private_attribute)
assert hasattr(obj, action.public_name)
assert hasattr(obj, action.private_name)
assert getattr(obj, action.public_name) is getattr(obj, action.private_name)

Check warning on line 144 in tests/test_deprecations.py

View check run for this annotation

Codecov / codecov/patch

tests/test_deprecations.py#L143-L144

Added lines #L143 - L144 were not covered by tests


def assert_public_method_calls_private(type_, private_method):
@pytest.mark.parametrize(
"private_method_action",
filter(lambda action: action.is_method and action.type_ == "make_private", actions),
ids=str,
)
def test_private_method(private_method_action: Action):
"""Looks at the source code to ensure that `public_method` calls `private_method`.
Looks for the string `.{method_name}(` in the source code of `public_method`.
"""
assert private_method.startswith("_")
public_method_str = private_method.lstrip("_")
private_method_str = private_method
action = private_method_action

public_method = getattr(type_, public_method_str)
private_method = getattr(type_, private_method_str)
class_ = test_data[action.class_]["class"]

public_method = getattr(class_, action.public_name)
private_method = getattr(class_, action.private_name)

assert callable(public_method)
assert callable(private_method)

assert f".{private_method_str}(" in inspect.getsource(public_method)


@pytest.mark.parametrize("private_attribute", FieldPrivate.attributes)
def test_private_attribute_field(private_attribute):
assert_private_public_attribute_equiv(field, private_attribute)


@pytest.mark.parametrize("private_attribute", FieldSetPrivate.attributes)
def test_private_attribute_fieldset(private_attribute):
assert_private_public_attribute_equiv(fieldset, private_attribute)


@pytest.mark.parametrize("private_method", FieldPrivate.methods)
def test_private_method_field(private_method):
assert_public_method_calls_private(Field, private_method)


@pytest.mark.parametrize("private_method", FieldSetPrivate.methods)
def test_private_method_fieldset(private_method):
assert_public_method_calls_private(FieldSet, private_method)
assert f".{action.private_name}(" in inspect.getsource(public_method)


@pytest.mark.parametrize(
"read_only_attribute_action",
filter(lambda action: not action.is_method and action.type_ == "read_only", actions),
ids=str,
)
def test_read_only_attr(read_only_attribute_action: Action):
"""Tries to store a variable in the read-only attribute."""
action = read_only_attribute_action
obj = test_data[action.class_]["object"]

assert hasattr(obj, action.public_name)
with pytest.raises(AttributeError):
setattr(obj, action.public_name, None)

0 comments on commit f174e36

Please sign in to comment.