Skip to content

Commit 77eb65c

Browse files
committed
Bump mypy and switch from __dict__ to to_dict() method
1 parent f30a802 commit 77eb65c

12 files changed

Lines changed: 94 additions & 48 deletions

File tree

.github/workflows/flake8.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
if: steps.changes.outputs.code == 'true'
3636
uses: "actions/setup-python@v5"
3737
with:
38-
python-version: "3.7"
38+
python-version: "3.9"
3939

4040
- name: Install dependencies 🔧
4141
if: steps.changes.outputs.code == 'true'

.github/workflows/mypy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
if: steps.changes.outputs.code == 'true'
4141
uses: "actions/setup-python@v5"
4242
with:
43-
python-version: "3.7"
43+
python-version: "3.9"
4444

4545
- name: Install dependencies 🔧
4646
run: |

mh_utils/__init__.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,66 @@
2626
# OR OTHER DEALINGS IN THE SOFTWARE.
2727
#
2828

29+
# stdlib
30+
from abc import abstractmethod
31+
from typing import Dict, Iterable, Iterator, Tuple, TypeVar
32+
33+
# 3rd party
34+
from domdf_python_tools._is_match import is_match_with
35+
from domdf_python_tools.doctools import prettify_docstrings
36+
37+
__all__ = ["Dictable"]
38+
2939
__author__: str = "Dominic Davis-Foster"
3040
__copyright__: str = "2020-2021 Dominic Davis-Foster"
3141
__license__: str = "MIT License"
3242
__version__: str = "0.2.2"
3343
__email__: str = "dominic@davis-foster.co.uk"
44+
45+
_V = TypeVar("_V")
46+
47+
48+
@prettify_docstrings
49+
class Dictable(Iterable[Tuple[str, _V]]):
50+
"""
51+
The basic structure of a class that can be converted into a dictionary.
52+
"""
53+
54+
@abstractmethod
55+
def __init__(self, *args, **kwargs):
56+
pass
57+
58+
def __repr__(self) -> str:
59+
return super().__repr__()
60+
61+
def __str__(self) -> str:
62+
return self.__repr__()
63+
64+
def __iter__(self) -> Iterator[Tuple[str, _V]]:
65+
"""
66+
Iterate over the attributes of the class.
67+
"""
68+
69+
yield from self.to_dict().items()
70+
71+
def __getstate__(self) -> Dict[str, _V]:
72+
return self.to_dict()
73+
74+
def __setstate__(self, state):
75+
self.__init__(**state) # type: ignore[misc]
76+
77+
def __copy__(self):
78+
return self.__class__(**self.to_dict())
79+
80+
def __deepcopy__(self, memodict={}):
81+
return self.__copy__()
82+
83+
@abstractmethod
84+
def to_dict(self):
85+
return {} # pragma: no cover (abc)
86+
87+
def __eq__(self, other) -> bool:
88+
if isinstance(other, self.__class__):
89+
return is_match_with(other.to_dict(), self.to_dict())
90+
91+
return NotImplemented

mh_utils/cef_parser/__init__.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,15 @@
7979
from attr_utils.docstrings import add_attrs_doc
8080
from attr_utils.serialise import serde
8181
from chemistry_tools.formulae import Formula
82-
from domdf_python_tools.bases import Dictable, NamedList
82+
from domdf_python_tools.bases import NamedList
8383
from domdf_python_tools.doctools import prettify_docstrings
8484
from domdf_python_tools.pretty_print import FancyPrinter
8585
from domdf_python_tools.stringlist import DelimitedList
8686
from domdf_python_tools.typing import PathLike
8787
from typing_extensions import TypedDict
8888

8989
# this package
90+
from mh_utils import Dictable
9091
from mh_utils.utils import make_timedelta
9192

9293
__all__ = [
@@ -125,8 +126,6 @@ def __init__(
125126
matches: Optional[Dict[str, "Score"]] = None,
126127
):
127128

128-
super().__init__()
129-
130129
self.name = str(name)
131130
if isinstance(formula, Formula):
132131
self.formula = formula
@@ -142,8 +141,7 @@ def __init__(
142141
else:
143142
raise TypeError(f"'matches' must be a dictionary, not {type(matches)}")
144143

145-
@property
146-
def __dict__(self):
144+
def to_dict(self):
147145
return dict(
148146
name=self.name,
149147
formula=self.formula,
@@ -262,7 +260,6 @@ def __init__(
262260
peaks: Optional[Sequence[Peak]] = None,
263261
rt_ranges: Optional[Sequence["RTRange"]] = None,
264262
):
265-
super().__init__()
266263

267264
self.spectrum_type = str(spectrum_type)
268265
self.saturation_limit = int(saturation_limit)
@@ -319,8 +316,7 @@ def __init__(
319316
"rt_ranges",
320317
]
321318

322-
@property
323-
def __dict__(self):
319+
def to_dict(self):
324320
data = {}
325321
for key in self.__slots__:
326322
data[key] = getattr(self, key)
@@ -591,7 +587,6 @@ def __init__(
591587
results: Optional[Sequence[Molecule]] = None,
592588
spectra: Optional[Sequence[Spectrum]] = None,
593589
):
594-
super().__init__()
595590

596591
self.algo = str(algo)
597592

@@ -615,8 +610,7 @@ def __init__(
615610
else:
616611
self.spectra = []
617612

618-
@property
619-
def __dict__(self):
613+
def to_dict(self):
620614
return dict(
621615
algo=self.algo,
622616
location=self.location,

mh_utils/csv_parser/classes.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,13 @@
3939
import sdjson
4040
from cawdrey import AlphaDict
4141
from domdf_python_tools import doctools
42-
from domdf_python_tools.bases import Dictable
4342
from domdf_python_tools.doctools import prettify_docstrings
4443
from domdf_python_tools.paths import PathPlus
4544
from domdf_python_tools.typing import PathLike
4645

46+
# this package
47+
from mh_utils import Dictable
48+
4749
__all__ = [
4850
"Sample",
4951
"Result",
@@ -96,7 +98,6 @@ def __init__(
9698
filename,
9799
results=None,
98100
):
99-
super().__init__()
100101

101102
self.sample_name = sample_name
102103
self.sample_type = sample_type
@@ -202,8 +203,7 @@ def from_series(cls: Type[_S], series) -> _S:
202203
def __repr__(self):
203204
return f"Sample({self.sample_name})"
204205

205-
@property
206-
def __dict__(self):
206+
def to_dict(self):
207207
return AlphaDict(
208208
sample_name=self.sample_name,
209209
sample_type=self.sample_type,
@@ -302,7 +302,6 @@ def __init__(
302302
flag_severity: str = '',
303303
flag_severity_code: int = 0,
304304
):
305-
super().__init__()
306305

307306
# Possible also AL (ID Source) and AM (ID Techniques Applied)
308307
self._cas = cas
@@ -425,8 +424,7 @@ def from_series(cls: Type[_R], series: pandas.Series) -> _R:
425424
def __repr__(self):
426425
return f"Result({self.name}; {self.formula}; {self.rt}; {self.score})"
427426

428-
@property
429-
def __dict__(self):
427+
def to_dict(self):
430428
return AlphaDict(
431429
cas=self._cas,
432430
name=self.name,

mh_utils/worklist_parser/classes.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@
3333

3434
# 3rd party
3535
import attr
36-
import lxml.etree # type: ignore
36+
import lxml # type: ignore
3737
import pandas # type: ignore
3838
from attr_utils.docstrings import add_attrs_doc
3939
from attr_utils.serialise import serde
40-
from domdf_python_tools.bases import Dictable
4140
from domdf_python_tools.doctools import prettify_docstrings
4241

4342
# this package
43+
from mh_utils import Dictable
4444
from mh_utils.utils import element_to_bool, strip_string
4545
from mh_utils.worklist_parser.columns import Column, columns
4646
from mh_utils.worklist_parser.enums import AttributeType
@@ -70,8 +70,6 @@ def __init__(
7070
sample_info: Optional[dict] = None,
7171
):
7272

73-
super().__init__()
74-
7573
if isinstance(id, UUID):
7674
self.id = id
7775
else:
@@ -112,8 +110,7 @@ def from_xml(
112110
sample_info=parse_sample_info(element.SampleInfo, user_columns),
113111
)
114112

115-
@property
116-
def __dict__(self):
113+
def to_dict(self):
117114
data = {}
118115
for key in self.__slots__:
119116
if key == "id":
@@ -153,8 +150,6 @@ def __init__(
153150
checksum: "Checksum",
154151
):
155152

156-
super().__init__()
157-
158153
self.version = float(version)
159154
self.locked_run_mode = bool(locked_run_mode)
160155
self.instrument_name = str(instrument_name)
@@ -165,8 +160,7 @@ def __init__(
165160

166161
__slots__ = ["version", "user_columns", "jobs", "checksum", "locked_run_mode", "instrument_name", "params"]
167162

168-
@property
169-
def __dict__(self):
163+
def to_dict(self):
170164
data = {}
171165
for key in self.__slots__:
172166
data[key] = getattr(self, key)
@@ -332,7 +326,7 @@ def __repr__(self) -> str:
332326
if self.undefined:
333327
return f"{self.__class__.__name__}(Undefined)"
334328
else:
335-
slots = self.__slots__ # type: ignore[attr-defined] # attrs adds __slots__ but mypy doesn't know
329+
slots = self.__slots__
336330
values = ", ".join(f"{x}={getattr(self, x)!r}" for x in slots if x != "__weakref__")
337331
return f"{self.__class__.__name__}({values})"
338332

mh_utils/worklist_parser/columns.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def from_attribute(cls, attribute: "Attribute") -> "Column":
158158
name=attribute.header_name,
159159
attribute_id=attribute.attribute_id,
160160
attribute_type=attribute.attribute_type,
161-
dtype=dtype, # type: ignore
161+
dtype=dtype,
162162
default_value=attribute.default_data_value,
163163
field_type=attribute.field_type,
164164
reorder_id=attribute.reorder_id,

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ autodoc_exclude_members = [
126126
]
127127

128128
[tool.mypy]
129-
python_version = "3.7"
129+
python_version = "3.9"
130130
namespace_packages = true
131131
check_untyped_defs = true
132132
warn_unused_ignores = true

repo_helper.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ use_whey: true
1515
min_coverage: 85
1616
pre_commit_exclude: ^tests/test_xml/.*\.xml$
1717
preserve_custom_theme: true
18-
python_deploy_version: 3.7
18+
mypy_version: 1.16
19+
python_deploy_version: 3.9
1920

2021
conda_channels:
2122
- conda-forge

tests/test_worklist_parser/test_columns.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def test_cast_value_any(self, value, expects):
8585
name="Test Column",
8686
attribute_id=1,
8787
attribute_type=AttributeType.SystemUsed,
88-
dtype=Any, # type: ignore
88+
dtype=Any,
8989
default_value="The Default",
9090
)
9191

0 commit comments

Comments
 (0)