Skip to content

Commit 0e57537

Browse files
committed
update deprecation tests
1 parent ce714df commit 0e57537

File tree

1 file changed

+158
-89
lines changed

1 file changed

+158
-89
lines changed

tests/test_deprecations.py

+158-89
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,181 @@
11
import inspect
2+
from typing import Literal
23

34
import pytest
45

56
from parcels import Field, FieldSet
67
from tests.utils import create_fieldset_unit_mesh
78

8-
fieldset = create_fieldset_unit_mesh()
9-
field = fieldset.U
109

11-
private_field_attrs = [
12-
"_dataFiles",
13-
"_loaded_time_indices",
14-
"_creation_log",
15-
"_data_chunks",
16-
"_c_data_chunks",
17-
"_chunk_set",
10+
class Action:
11+
"""Utility class to help manage, document, and test deprecations."""
12+
13+
def __init__(self, class_: Literal["Field", "FieldSet"], name: str, type_: Literal["read_only", "make_private"]):
14+
if name.startswith("_"):
15+
raise ValueError("name should not start with an underscore")
16+
17+
self.class_ = class_
18+
self._raw_name = name
19+
self.type_ = type_
20+
21+
if type_ == "read_only" and self.is_method:
22+
raise ValueError("read_only attributes should not be methods")
23+
24+
@property
25+
def public_name(self):
26+
return self._raw_name.strip("()")
27+
28+
@property
29+
def private_name(self):
30+
if self.type_ == "make_private":
31+
return f"_{self.public_name}"
32+
return None
33+
34+
@property
35+
def is_method(self):
36+
if self._raw_name.endswith("()"):
37+
return True
38+
return False
39+
40+
def __str__(self):
41+
return f"{self.class_}.{self.public_name}"
42+
43+
def __repr__(self):
44+
return f"Action(class_={self.class_!r}, name={self._raw_name!r}, type_={self.type_!r})"
45+
46+
47+
def test_testing_action_class():
48+
"""Testing the Action class used for testing."""
49+
action = Action("MyClass", "my_attribute", "make_private")
50+
assert not action.is_method
51+
assert action.public_name == "my_attribute"
52+
assert action.private_name == "_my_attribute"
53+
assert action.class_ == "MyClass"
54+
assert action.type_ == "make_private"
55+
56+
action = Action("Field", "my_attribute", "read_only")
57+
assert not action.is_method
58+
assert action.public_name == "my_attribute"
59+
assert action.private_name is None
60+
assert not action.is_method
61+
62+
action = Action("Field", "my_method()", "make_private")
63+
assert action.is_method
64+
assert action.public_name == "my_method"
65+
assert action.private_name == "_my_method"
66+
67+
with pytest.raises(ValueError): # Can't have underscore in name
68+
Action("Field", "_my_attribute", "make_private")
69+
70+
with pytest.raises(ValueError): # Can't have read-only method
71+
Action("Field", "my_method()", "read_only")
72+
73+
74+
# fmt: off
75+
actions = [
76+
Action("Field", "dataFiles", "make_private" ),
77+
Action("Field", "netcdf_engine", "read_only" ),
78+
Action("Field", "loaded_time_indices", "make_private" ),
79+
Action("Field", "creation_log", "make_private" ),
80+
Action("Field", "data_chunks", "make_private" ),
81+
Action("Field", "c_data_chunks", "make_private" ),
82+
Action("Field", "chunk_set", "make_private" ),
83+
Action("Field", "cell_edge_sizes", "read_only" ),
84+
Action("Field", "get_dim_filenames()", "make_private" ),
85+
Action("Field", "collect_timeslices()", "make_private" ),
86+
Action("Field", "reshape()", "make_private" ),
87+
Action("Field", "calc_cell_edge_sizes()", "make_private" ),
88+
Action("Field", "search_indices_vertical_z()", "make_private" ),
89+
Action("Field", "search_indices_vertical_s()", "make_private" ),
90+
Action("Field", "reconnect_bnd_indices()", "make_private" ),
91+
Action("Field", "search_indices_rectilinear()", "make_private" ),
92+
Action("Field", "search_indices_curvilinear()", "make_private" ),
93+
Action("Field", "search_indices()", "make_private" ),
94+
Action("Field", "interpolator2D()", "make_private" ),
95+
Action("Field", "interpolator3D()", "make_private" ),
96+
Action("Field", "spatial_interpolation()", "make_private" ),
97+
Action("Field", "time_index()", "make_private" ),
98+
Action("Field", "ccode_eval()", "make_private" ),
99+
Action("Field", "ccode_convert()", "make_private" ),
100+
Action("Field", "get_block_id()", "make_private" ),
101+
Action("Field", "get_block()", "make_private" ),
102+
Action("Field", "chunk_setup()", "make_private" ),
103+
Action("Field", "chunk_data()", "make_private" ),
104+
Action("Field", "rescale_and_set_minmax()", "make_private" ),
105+
Action("Field", "data_concatenate()", "make_private" ),
106+
Action("FieldSet", "completed", "make_private" ),
107+
Action("FieldSet", "particlefile", "read_only" ),
108+
Action("FieldSet", "add_UVfield()", "make_private" ),
109+
Action("FieldSet", "check_complete()", "make_private" ),
110+
Action("FieldSet", "parse_wildcards()", "make_private" ),
18111
]
112+
# fmt: on
19113

114+
# Create test data dictionary
115+
fieldset = create_fieldset_unit_mesh()
116+
field = fieldset.U
20117

21-
class FieldPrivate:
22-
attributes = [
23-
"_dataFiles",
24-
"_loaded_time_indices",
25-
"_creation_log",
26-
"_data_chunks",
27-
"_c_data_chunks",
28-
"_chunk_set",
29-
]
30-
methods = [
31-
"_get_dim_filenames",
32-
"_collect_timeslices",
33-
"_reshape",
34-
"_calc_cell_edge_sizes",
35-
"_search_indices_vertical_z",
36-
"_search_indices_vertical_s",
37-
"_reconnect_bnd_indices",
38-
"_search_indices_rectilinear",
39-
"_search_indices_curvilinear",
40-
"_search_indices",
41-
"_interpolator2D",
42-
"_interpolator3D",
43-
"_ccode_eval",
44-
"_ccode_convert",
45-
"_get_block_id",
46-
"_get_block",
47-
"_chunk_setup",
48-
"_chunk_data",
49-
"_rescale_and_set_minmax",
50-
"_data_concatenate",
51-
"_spatial_interpolation",
52-
"_time_index",
53-
]
54-
55-
56-
class FieldSetPrivate:
57-
attributes = [
58-
"_completed",
59-
]
60-
methods = [
61-
"_add_UVfield",
62-
"_parse_wildcards",
63-
"_check_complete",
64-
]
65-
66-
67-
def assert_private_public_attribute_equiv(obj, private_attribute: str):
68-
assert private_attribute.startswith("_")
69-
attribute = private_attribute.lstrip("_")
118+
test_data = {
119+
"Field": {
120+
"class": Field,
121+
"object": field,
122+
},
123+
"FieldSet": {
124+
"class": FieldSet,
125+
"object": fieldset,
126+
},
127+
}
128+
129+
130+
@pytest.mark.parametrize(
131+
"private_attribute_action",
132+
filter(lambda action: not action.is_method and action.type_ == "make_private", actions),
133+
ids=str,
134+
)
135+
def test_private_attrib(private_attribute_action: Action):
136+
"""Checks that the public attribute is equivalent to the private attribute."""
137+
action = private_attribute_action
138+
139+
obj = test_data[action.class_]["object"]
70140

71141
with pytest.raises(DeprecationWarning):
72-
assert hasattr(obj, attribute)
73-
assert hasattr(obj, private_attribute)
74-
assert getattr(obj, attribute) is getattr(obj, private_attribute)
142+
assert hasattr(obj, action.public_name)
143+
assert hasattr(obj, action.private_name)
144+
assert getattr(obj, action.public_name) is getattr(obj, action.private_name)
75145

76146

77-
def assert_public_method_calls_private(type_, private_method):
147+
@pytest.mark.parametrize(
148+
"private_method_action",
149+
filter(lambda action: action.is_method and action.type_ == "make_private", actions),
150+
ids=str,
151+
)
152+
def test_private_method(private_method_action: Action):
78153
"""Looks at the source code to ensure that `public_method` calls `private_method`.
79154
80155
Looks for the string `.{method_name}(` in the source code of `public_method`.
81156
"""
82-
assert private_method.startswith("_")
83-
public_method_str = private_method.lstrip("_")
84-
private_method_str = private_method
157+
action = private_method_action
85158

86-
public_method = getattr(type_, public_method_str)
87-
private_method = getattr(type_, private_method_str)
159+
class_ = test_data[action.class_]["class"]
160+
161+
public_method = getattr(class_, action.public_name)
162+
private_method = getattr(class_, action.private_name)
88163

89164
assert callable(public_method)
90165
assert callable(private_method)
91-
92-
assert f".{private_method_str}(" in inspect.getsource(public_method)
93-
94-
95-
@pytest.mark.parametrize("private_attribute", FieldPrivate.attributes)
96-
def test_private_attribute_field(private_attribute):
97-
assert_private_public_attribute_equiv(field, private_attribute)
98-
99-
100-
@pytest.mark.parametrize("private_attribute", FieldSetPrivate.attributes)
101-
def test_private_attribute_fieldset(private_attribute):
102-
assert_private_public_attribute_equiv(fieldset, private_attribute)
103-
104-
105-
@pytest.mark.parametrize("private_method", FieldPrivate.methods)
106-
def test_private_method_field(private_method):
107-
assert_public_method_calls_private(Field, private_method)
108-
109-
110-
@pytest.mark.parametrize("private_method", FieldSetPrivate.methods)
111-
def test_private_method_fieldset(private_method):
112-
assert_public_method_calls_private(FieldSet, private_method)
166+
assert f".{action.private_name}(" in inspect.getsource(public_method)
167+
168+
169+
@pytest.mark.parametrize(
170+
"read_only_attribute_action",
171+
filter(lambda action: not action.is_method and action.type_ == "read_only", actions),
172+
ids=str,
173+
)
174+
def test_read_only_attr(read_only_attribute_action: Action):
175+
"""Tries to store a variable in the read-only attribute."""
176+
action = read_only_attribute_action
177+
obj = test_data[action.class_]["object"]
178+
179+
assert hasattr(obj, action.public_name)
180+
with pytest.raises(AttributeError):
181+
setattr(obj, action.public_name, None)

0 commit comments

Comments
 (0)