Skip to content

Commit 66acc5d

Browse files
committed
makes model and classlist printing more flexible via a display_fields property
1 parent 92c6d67 commit 66acc5d

File tree

4 files changed

+119
-34
lines changed

4 files changed

+119
-34
lines changed

RATapi/classlist.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,40 @@ def __init__(self, init_list: Union[Sequence[T], T] = None, name_field: str = "n
5757
super().__init__(init_list)
5858

5959
def __str__(self):
60+
# `display_fields` gives more control over the items displayed from the list if available
61+
if not self.data:
62+
return str([])
6063
try:
61-
[model.__dict__ for model in self.data]
64+
model_display_fields = [model.display_fields for model in self.data]
65+
# get all items included in at least one list
66+
# the list comprehension ensures they are in the order that they're in in the model
67+
required_fields = list(set().union(*model_display_fields))
68+
table_fields = ["index"] + [i for i in list(self.data[0].__dict__) if i in required_fields]
6269
except AttributeError:
63-
output = str(self.data)
70+
try:
71+
model_display_fields = [model.__dict__ for model in self.data]
72+
table_fields = ["index"] + list(self.data[0].__dict__)
73+
except AttributeError:
74+
return str(self.data)
75+
76+
if any(model_display_fields):
77+
table = prettytable.PrettyTable()
78+
table.field_names = [field.replace("_", " ") for field in table_fields]
79+
rows = []
80+
for index, model in enumerate(self.data):
81+
row = [index]
82+
for field in table_fields[1:]:
83+
value = getattr(model, field, "")
84+
if isinstance(value, np.ndarray):
85+
value = f"{'Data array: ['+' x '.join(str(i) for i in value.shape) if value.size > 0 else '['}]"
86+
elif field == "model":
87+
value = "\n".join(str(element) for element in value)
88+
else:
89+
value = str(value)
90+
row.append(value)
91+
rows.append(row)
92+
table.add_rows(rows)
93+
output = table.get_string()
6494
else:
6595
if any(model.__dict__ for model in self.data):
6696
table = prettytable.PrettyTable()

RATapi/models.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,15 @@ def __repr__(self):
4040

4141
def __str__(self):
4242
table = prettytable.PrettyTable()
43-
table.field_names = [key.replace("_", " ") for key in self.__dict__]
44-
table.add_row(list(self.__dict__.values()))
43+
table.field_names = [key.replace("_", " ") for key in self.display_fields]
44+
table.add_row(list(self.display_fields.values()))
4545
return table.get_string()
4646

47+
@property
48+
def display_fields(self) -> dict:
49+
"""A dictionary of which fields should be displayed by this model and their values."""
50+
return self.__dict__
51+
4752

4853
class Signal(RATModel):
4954
"""Base model for background & resolution signals."""
@@ -525,6 +530,8 @@ class Parameter(RATModel):
525530
mu: float = 0.0
526531
sigma: float = np.inf
527532

533+
show_priors: bool = False
534+
528535
@model_validator(mode="after")
529536
def check_min_max(self) -> "Parameter":
530537
"""The maximum value of a parameter must be greater than the minimum."""
@@ -539,6 +546,16 @@ def check_value_in_range(self) -> "Parameter":
539546
raise ValueError(f"value {self.value} is not within the defined range: {self.min} <= value <= {self.max}")
540547
return self
541548

549+
@property
550+
def display_fields(self) -> dict:
551+
visible_fields = ["name", "min", "value", "max", "fit"]
552+
if self.show_priors:
553+
visible_fields.append("prior_type")
554+
if self.prior_type == Priors.Gaussian:
555+
visible_fields.extend(["mu", "sigma"])
556+
557+
return {f: getattr(self, f) for f in visible_fields}
558+
542559

543560
class ProtectedParameter(Parameter):
544561
"""A Parameter with a fixed name."""

tests/test_classlist.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from collections.abc import Iterable, Sequence
88
from typing import Any, Union
99

10+
import prettytable
1011
import pytest
1112

1213
from RATapi.classlist import ClassList
@@ -44,6 +45,23 @@ def three_name_class_list():
4445
return ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob"), InputAttributes(name="Eve")])
4546

4647

48+
class DisplayFieldsClass:
49+
"""A classlist with four attributes and a display_fields property."""
50+
51+
def __init__(self, display_range):
52+
self.a = 1
53+
self.b = 2
54+
self.c = 3
55+
self.d = 4
56+
57+
self.display_range = display_range
58+
59+
@property
60+
def display_fields(self):
61+
fields = ["a", "b", "c", "d"][self.display_range[0] : self.display_range[1]]
62+
return {f: getattr(self, f) for f in fields}
63+
64+
4765
class TestInitialisation:
4866
@pytest.mark.parametrize(
4967
"input_object",
@@ -174,6 +192,26 @@ def test_str_empty_classlist() -> None:
174192
assert str(ClassList()) == str([])
175193

176194

195+
@pytest.mark.parametrize(
196+
"display_ranges, expected_header",
197+
(
198+
([(1, 3), (1, 3), (1, 3)], ["b", "c"]),
199+
([(1, 2), (0, 4), (2, 3)], ["a", "b", "c", "d"]),
200+
([(0, 2), (0, 1), (2, 3)], ["a", "b", "c"]),
201+
),
202+
)
203+
def test_str_display_fields(display_ranges, expected_header):
204+
"""If a class has the `display_fields` property, the ClassList should print with the minimal required attributes."""
205+
class_list = ClassList([DisplayFieldsClass(dr) for dr in display_ranges])
206+
expected_table = prettytable.PrettyTable()
207+
expected_table.field_names = ["index"] + expected_header
208+
expected_vals = {"a": 1, "b": 2, "c": 3, "d": 4}
209+
row = [expected_vals[v] for v in expected_header]
210+
expected_table.add_rows([[0] + row, [1] + row, [2] + row])
211+
212+
assert str(class_list) == expected_table.get_string()
213+
214+
177215
@pytest.mark.parametrize(
178216
["new_item", "expected_classlist"],
179217
[

tests/test_project.py

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -80,47 +80,47 @@ def default_project_str():
8080
"Geometry: ------------------------------------------------------------------------------------------\n\n"
8181
"air/substrate\n\n"
8282
"Parameters: ----------------------------------------------------------------------------------------\n\n"
83-
"+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n"
84-
"| index | name | min | value | max | fit | prior type | mu | sigma |\n"
85-
"+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n"
86-
"| 0 | Substrate Roughness | 1.0 | 3.0 | 5.0 | True | uniform | 0.0 | inf |\n"
87-
"+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n\n"
83+
"+-------+---------------------+-----+-------+-----+------+\n"
84+
"| index | name | min | value | max | fit |\n"
85+
"+-------+---------------------+-----+-------+-----+------+\n"
86+
"| 0 | Substrate Roughness | 1.0 | 3.0 | 5.0 | True |\n"
87+
"+-------+---------------------+-----+-------+-----+------+\n\n"
8888
"Bulk In: -------------------------------------------------------------------------------------------\n\n"
89-
"+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n"
90-
"| index | name | min | value | max | fit | prior type | mu | sigma |\n"
91-
"+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n"
92-
"| 0 | SLD Air | 0.0 | 0.0 | 0.0 | False | uniform | 0.0 | inf |\n"
93-
"+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n\n"
89+
"+-------+---------+-----+-------+-----+-------+\n"
90+
"| index | name | min | value | max | fit |\n"
91+
"+-------+---------+-----+-------+-----+-------+\n"
92+
"| 0 | SLD Air | 0.0 | 0.0 | 0.0 | False |\n"
93+
"+-------+---------+-----+-------+-----+-------+\n\n"
9494
"Bulk Out: ------------------------------------------------------------------------------------------\n\n"
95-
"+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n"
96-
"| index | name | min | value | max | fit | prior type | mu | sigma |\n"
97-
"+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n"
98-
"| 0 | SLD D2O | 6.2e-06 | 6.35e-06 | 6.35e-06 | False | uniform | 0.0 | inf |\n"
99-
"+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n\n"
95+
"+-------+---------+---------+----------+----------+-------+\n"
96+
"| index | name | min | value | max | fit |\n"
97+
"+-------+---------+---------+----------+----------+-------+\n"
98+
"| 0 | SLD D2O | 6.2e-06 | 6.35e-06 | 6.35e-06 | False |\n"
99+
"+-------+---------+---------+----------+----------+-------+\n\n"
100100
"Scalefactors: --------------------------------------------------------------------------------------\n\n"
101-
"+-------+---------------+------+-------+------+-------+------------+-----+-------+\n"
102-
"| index | name | min | value | max | fit | prior type | mu | sigma |\n"
103-
"+-------+---------------+------+-------+------+-------+------------+-----+-------+\n"
104-
"| 0 | Scalefactor 1 | 0.02 | 0.23 | 0.25 | False | uniform | 0.0 | inf |\n"
105-
"+-------+---------------+------+-------+------+-------+------------+-----+-------+\n\n"
101+
"+-------+---------------+------+-------+------+-------+\n"
102+
"| index | name | min | value | max | fit |\n"
103+
"+-------+---------------+------+-------+------+-------+\n"
104+
"| 0 | Scalefactor 1 | 0.02 | 0.23 | 0.25 | False |\n"
105+
"+-------+---------------+------+-------+------+-------+\n\n"
106106
"Background Parameters: -----------------------------------------------------------------------------\n\n"
107-
"+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n"
108-
"| index | name | min | value | max | fit | prior type | mu | sigma |\n"
109-
"+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n"
110-
"| 0 | Background Param 1 | 1e-07 | 1e-06 | 1e-05 | False | uniform | 0.0 | inf |\n"
111-
"+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n\n"
107+
"+-------+--------------------+-------+-------+-------+-------+\n"
108+
"| index | name | min | value | max | fit |\n"
109+
"+-------+--------------------+-------+-------+-------+-------+\n"
110+
"| 0 | Background Param 1 | 1e-07 | 1e-06 | 1e-05 | False |\n"
111+
"+-------+--------------------+-------+-------+-------+-------+\n\n"
112112
"Backgrounds: ---------------------------------------------------------------------------------------\n\n"
113113
"+-------+--------------+----------+--------------------+---------+---------+---------+---------+---------+\n"
114114
"| index | name | type | source | value 1 | value 2 | value 3 | value 4 | value 5 |\n"
115115
"+-------+--------------+----------+--------------------+---------+---------+---------+---------+---------+\n"
116116
"| 0 | Background 1 | constant | Background Param 1 | | | | | |\n"
117117
"+-------+--------------+----------+--------------------+---------+---------+---------+---------+---------+\n\n"
118118
"Resolution Parameters: -----------------------------------------------------------------------------\n\n"
119-
"+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n"
120-
"| index | name | min | value | max | fit | prior type | mu | sigma |\n"
121-
"+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n"
122-
"| 0 | Resolution Param 1 | 0.01 | 0.03 | 0.05 | False | uniform | 0.0 | inf |\n"
123-
"+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n\n"
119+
"+-------+--------------------+------+-------+------+-------+\n"
120+
"| index | name | min | value | max | fit |\n"
121+
"+-------+--------------------+------+-------+------+-------+\n"
122+
"| 0 | Resolution Param 1 | 0.01 | 0.03 | 0.05 | False |\n"
123+
"+-------+--------------------+------+-------+------+-------+\n\n"
124124
"Resolutions: ---------------------------------------------------------------------------------------\n\n"
125125
"+-------+--------------+----------+--------------------+---------+---------+---------+---------+---------+\n"
126126
"| index | name | type | source | value 1 | value 2 | value 3 | value 4 | value 5 |\n"

0 commit comments

Comments
 (0)