GraphAtoms 0.0.2__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- graphatoms-1.0.0/GraphAtoms/common/__init__.py +16 -0
- graphatoms-1.0.0/GraphAtoms/common/_abc.py +52 -0
- graphatoms-1.0.0/GraphAtoms/common/base.py +482 -0
- graphatoms-1.0.0/GraphAtoms/containner/__init__.py +21 -0
- graphatoms-1.0.0/GraphAtoms/containner/_aMixin.py +169 -0
- graphatoms-1.0.0/GraphAtoms/containner/_aOther.py +233 -0
- graphatoms-1.0.0/GraphAtoms/containner/_atomic.py +62 -0
- graphatoms-0.0.2/GraphAtoms/containner/_mDataPyG.py → graphatoms-1.0.0/GraphAtoms/containner/_g2DataPyG.py +8 -6
- graphatoms-0.0.2/GraphAtoms/containner/_mIGraph.py → graphatoms-1.0.0/GraphAtoms/containner/_g2IGraph.py +4 -4
- graphatoms-0.0.2/GraphAtoms/containner/_mNetworkX.py → graphatoms-1.0.0/GraphAtoms/containner/_g2NetworkX.py +1 -1
- graphatoms-0.0.2/GraphAtoms/containner/_mRustworkX.py → graphatoms-1.0.0/GraphAtoms/containner/_g2RustworkX.py +1 -1
- graphatoms-1.0.0/GraphAtoms/containner/_gBonded.py +219 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/GraphAtoms/containner/_graph.py +181 -305
- {graphatoms-0.0.2 → graphatoms-1.0.0}/GraphAtoms/containner/_sysCluster.py +14 -17
- graphatoms-1.0.0/GraphAtoms/containner/_sysGas.py +223 -0
- graphatoms-1.0.0/GraphAtoms/containner/_system.py +16 -0
- graphatoms-1.0.0/GraphAtoms/reaction/__init__.py +9 -0
- graphatoms-1.0.0/GraphAtoms/reaction/_dtSQL.py +279 -0
- graphatoms-1.0.0/GraphAtoms/reaction/_event.py +310 -0
- graphatoms-1.0.0/GraphAtoms/utils/__init__.py +5 -0
- graphatoms-1.0.0/GraphAtoms/utils/_pyarrow.py +90 -0
- graphatoms-1.0.0/GraphAtoms/utils/bytes.py +118 -0
- {graphatoms-0.0.2/GraphAtoms/common → graphatoms-1.0.0/GraphAtoms/utils}/geometry.py +1 -1
- graphatoms-1.0.0/GraphAtoms/utils/ndarray.py +60 -0
- graphatoms-0.0.2/GraphAtoms/containner/_mRDKit.py → graphatoms-1.0.0/GraphAtoms/utils/rdtool.py +8 -12
- graphatoms-1.0.0/GraphAtoms/utils/string.py +71 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/GraphAtoms.egg-info/PKG-INFO +20 -12
- graphatoms-1.0.0/GraphAtoms.egg-info/SOURCES.txt +42 -0
- graphatoms-1.0.0/GraphAtoms.egg-info/requires.txt +28 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/PKG-INFO +20 -12
- graphatoms-1.0.0/pyproject.toml +78 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/tests/test_abc.py +37 -4
- graphatoms-1.0.0/tests/test_container.py +345 -0
- graphatoms-1.0.0/tests/test_reaction.py +55 -0
- graphatoms-0.0.2/tests/test_mRDKit.py → graphatoms-1.0.0/tests/test_uRDtool.py +1 -1
- graphatoms-1.0.0/tests/test_utils.py +116 -0
- graphatoms-0.0.2/GraphAtoms/common/__init__.py +0 -4
- graphatoms-0.0.2/GraphAtoms/common/abc.py +0 -285
- graphatoms-0.0.2/GraphAtoms/common/ndarray.py +0 -3
- graphatoms-0.0.2/GraphAtoms/common/ndarray.pyi +0 -5
- graphatoms-0.0.2/GraphAtoms/common/string.py +0 -33
- graphatoms-0.0.2/GraphAtoms/containner/__init__.py +0 -20
- graphatoms-0.0.2/GraphAtoms/containner/_atomic.py +0 -366
- graphatoms-0.0.2/GraphAtoms/containner/_bonded.py +0 -90
- graphatoms-0.0.2/GraphAtoms/containner/_mConnComp.py +0 -45
- graphatoms-0.0.2/GraphAtoms/containner/_mFreeE.py +0 -117
- graphatoms-0.0.2/GraphAtoms/containner/_mNetworKit.py +0 -12
- graphatoms-0.0.2/GraphAtoms/containner/_sysGas.py +0 -81
- graphatoms-0.0.2/GraphAtoms/containner/_system.py +0 -15
- graphatoms-0.0.2/GraphAtoms.egg-info/SOURCES.txt +0 -36
- graphatoms-0.0.2/GraphAtoms.egg-info/requires.txt +0 -22
- graphatoms-0.0.2/pyproject.toml +0 -58
- graphatoms-0.0.2/tests/test_container.py +0 -270
- graphatoms-0.0.2/tests/test_utils.py +0 -49
- {graphatoms-0.0.2 → graphatoms-1.0.0}/GraphAtoms/__init__.py +0 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/GraphAtoms/common/error.py +0 -0
- {graphatoms-0.0.2/GraphAtoms/common → graphatoms-1.0.0/GraphAtoms/utils}/rotation.py +0 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/GraphAtoms.egg-info/dependency_links.txt +0 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/GraphAtoms.egg-info/top_level.txt +0 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/LICENSE +0 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/README.md +0 -0
- {graphatoms-0.0.2 → graphatoms-1.0.0}/setup.cfg +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""The module for common use.
|
|
2
|
+
|
|
3
|
+
Many other modules depend on this module.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from ._abc import BaseMixin, XxxKeyMixin
|
|
7
|
+
from .base import AllBaseModel, BaseModel, ExtendedBaseModel, NpzPklBaseModel
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"AllBaseModel",
|
|
11
|
+
"BaseMixin",
|
|
12
|
+
"BaseModel",
|
|
13
|
+
"ExtendedBaseModel",
|
|
14
|
+
"NpzPklBaseModel",
|
|
15
|
+
"XxxKeyMixin",
|
|
16
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# ruff: noqa: D100 D102
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from numpy.typing import ArrayLike
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseMixin:
|
|
8
|
+
"""The base mixin class which provides some useful classmethods."""
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def get_mask_or_index(k: ArrayLike, n: int) -> np.ndarray:
|
|
12
|
+
if np.isscalar(k):
|
|
13
|
+
if isinstance(k, bool):
|
|
14
|
+
k = [k] * n
|
|
15
|
+
elif isinstance(k, int):
|
|
16
|
+
k = [k]
|
|
17
|
+
else:
|
|
18
|
+
raise TypeError(f"Unsupported type({type(k)}): {k}.")
|
|
19
|
+
subset = np.asarray(k)
|
|
20
|
+
if subset.dtype == bool:
|
|
21
|
+
if subset.size != n:
|
|
22
|
+
raise KeyError(
|
|
23
|
+
f"Except {n} boolean array, but {subset.size} got."
|
|
24
|
+
)
|
|
25
|
+
else:
|
|
26
|
+
subset = np.unique(subset.astype(int))
|
|
27
|
+
if not 0 <= max(subset) < n:
|
|
28
|
+
raise KeyError(
|
|
29
|
+
f"Except 0-{n - 1} integer array, but the "
|
|
30
|
+
f"max({max(subset)}),min({min(subset)}) got."
|
|
31
|
+
)
|
|
32
|
+
return subset.flatten()
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def get_index(cls, k: ArrayLike, n: int) -> np.ndarray:
|
|
36
|
+
result = cls.get_mask_or_index(k=k, n=n)
|
|
37
|
+
if result.dtype == bool:
|
|
38
|
+
result = np.arange(n)[result]
|
|
39
|
+
return result.astype(int, copy=False)
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_mask(cls, k: ArrayLike, n: int) -> np.ndarray:
|
|
43
|
+
result = cls.get_mask_or_index(k=k, n=n)
|
|
44
|
+
if result.dtype != bool:
|
|
45
|
+
result = np.isin(np.arange(n), result)
|
|
46
|
+
return result.astype(bool, copy=False)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class XxxKeyMixin:
|
|
50
|
+
@property
|
|
51
|
+
def _DICT(self) -> dict[str, str]:
|
|
52
|
+
return {k: getattr(self, k) for k in dir(self) if k[0] != "_"}
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
# ruff: noqa: D100 D102
|
|
2
|
+
from collections.abc import Callable, Hashable, Mapping, Sequence
|
|
3
|
+
from pickle import dumps, loads
|
|
4
|
+
from sys import version_info
|
|
5
|
+
from typing import Annotated, Literal, override
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pydantic
|
|
9
|
+
import tomli_w as toml_w
|
|
10
|
+
import yaml
|
|
11
|
+
from joblib import dump, load
|
|
12
|
+
from pyarrow import Schema
|
|
13
|
+
from typing_extensions import Any, Self
|
|
14
|
+
|
|
15
|
+
from GraphAtoms.utils import bytes as bytesutils
|
|
16
|
+
from GraphAtoms.utils import string as stringutils
|
|
17
|
+
from GraphAtoms.utils._pyarrow import get_pyarrow_schema
|
|
18
|
+
|
|
19
|
+
if version_info < (3, 11):
|
|
20
|
+
import tomli as tomllib # type: ignore
|
|
21
|
+
else:
|
|
22
|
+
import tomllib
|
|
23
|
+
__all__ = [
|
|
24
|
+
"BaseModel",
|
|
25
|
+
"ExtendedBaseModel",
|
|
26
|
+
"NpzPklBaseModel",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class __Json(pydantic.BaseModel):
|
|
31
|
+
@pydantic.validate_call
|
|
32
|
+
def write_json(
|
|
33
|
+
self,
|
|
34
|
+
filename: pydantic.FilePath | pydantic.NewPath,
|
|
35
|
+
indent: int | None = 4,
|
|
36
|
+
**kwargs,
|
|
37
|
+
) -> pydantic.FilePath:
|
|
38
|
+
kwargs["exclude_none"] = True
|
|
39
|
+
text = self.model_dump_json(indent=indent, **kwargs)
|
|
40
|
+
filename.write_text(text, encoding="utf-8")
|
|
41
|
+
return filename
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
@pydantic.validate_call
|
|
45
|
+
def read_json(cls, filename: pydantic.FilePath, **kwargs) -> Self:
|
|
46
|
+
return cls.model_validate_json(filename.read_bytes(), **kwargs)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class __Toml(pydantic.BaseModel):
|
|
50
|
+
@pydantic.validate_call
|
|
51
|
+
def write_toml(
|
|
52
|
+
self,
|
|
53
|
+
filename: pydantic.FilePath | pydantic.NewPath,
|
|
54
|
+
indent: int = 4,
|
|
55
|
+
**kwargs,
|
|
56
|
+
) -> pydantic.FilePath:
|
|
57
|
+
kwargs["exclude_none"] = True
|
|
58
|
+
with filename.open("wb") as f:
|
|
59
|
+
toml_w.dump(
|
|
60
|
+
self.model_dump(mode="python", **kwargs),
|
|
61
|
+
f,
|
|
62
|
+
indent=indent,
|
|
63
|
+
multiline_strings=True,
|
|
64
|
+
)
|
|
65
|
+
return filename
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
@pydantic.validate_call
|
|
69
|
+
def read_toml(cls, filename: pydantic.FilePath, **kwargs) -> Self:
|
|
70
|
+
with filename.open("rb") as f:
|
|
71
|
+
data = tomllib.load(f)
|
|
72
|
+
return cls.model_validate(data, **kwargs)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class __Yaml(pydantic.BaseModel):
|
|
76
|
+
@pydantic.validate_call
|
|
77
|
+
def write_yaml(
|
|
78
|
+
self,
|
|
79
|
+
filename: pydantic.FilePath | pydantic.NewPath,
|
|
80
|
+
indent: int | None = 2,
|
|
81
|
+
**kwargs,
|
|
82
|
+
) -> pydantic.FilePath:
|
|
83
|
+
kwargs["exclude_none"] = True
|
|
84
|
+
with filename.open("w", encoding="utf-8") as f:
|
|
85
|
+
yaml.safe_dump(
|
|
86
|
+
self.model_dump(mode="python", **kwargs),
|
|
87
|
+
f,
|
|
88
|
+
encoding="utf-8",
|
|
89
|
+
default_flow_style=False,
|
|
90
|
+
indent=indent,
|
|
91
|
+
)
|
|
92
|
+
return filename
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
@pydantic.validate_call
|
|
96
|
+
def read_yaml(cls, filename: pydantic.FilePath, **kwargs) -> Self:
|
|
97
|
+
with filename.open(encoding="utf-8") as f:
|
|
98
|
+
data = yaml.safe_load(f)
|
|
99
|
+
return cls.model_validate(data, **kwargs)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class __Npz(pydantic.BaseModel):
|
|
103
|
+
@pydantic.validate_call
|
|
104
|
+
def write_npz(
|
|
105
|
+
self,
|
|
106
|
+
filename: pydantic.FilePath | pydantic.NewPath,
|
|
107
|
+
compress: bool = True,
|
|
108
|
+
**kwargs,
|
|
109
|
+
) -> pydantic.FilePath:
|
|
110
|
+
kwargs["exclude_none"] = True
|
|
111
|
+
(np.savez_compressed if compress else np.savez)(
|
|
112
|
+
filename,
|
|
113
|
+
allow_pickle=False,
|
|
114
|
+
**self.model_dump(mode="python", **kwargs),
|
|
115
|
+
)
|
|
116
|
+
return filename
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
@pydantic.validate_call
|
|
120
|
+
def read_npz(cls, filename: pydantic.FilePath, **kwargs) -> Self:
|
|
121
|
+
return cls.model_validate(np.load(filename), **kwargs)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class __Pickle(pydantic.BaseModel):
|
|
125
|
+
@pydantic.validate_call
|
|
126
|
+
def write_pickle(
|
|
127
|
+
self,
|
|
128
|
+
filename: pydantic.FilePath | pydantic.NewPath,
|
|
129
|
+
compress: bool | int | tuple[str, int] = 3,
|
|
130
|
+
**kwargs,
|
|
131
|
+
) -> pydantic.FilePath:
|
|
132
|
+
"""Persist the dictionary of this object into one file.
|
|
133
|
+
|
|
134
|
+
Read more in the reference:
|
|
135
|
+
https://joblib.readthedocs.io/en/latest/generated/joblib.dump.html
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
filename (str | Path | TextIOWrapper): The file object or path
|
|
139
|
+
of the file in which it is to be stored. The compression
|
|
140
|
+
method corresponding to one of the supported filename
|
|
141
|
+
extensions ('.z', '.gz', '.bz2', '.xz' or '.lzma')
|
|
142
|
+
will be used automatically.
|
|
143
|
+
compress (bool | int | tuple[str, int], optional):
|
|
144
|
+
Optional compression level for the data.
|
|
145
|
+
0 or False is no compression.
|
|
146
|
+
Higher value means more compression, but also
|
|
147
|
+
slower read and write times.
|
|
148
|
+
Using a value of 3 is often a good compromise.
|
|
149
|
+
Defaults to 3.
|
|
150
|
+
exclude_defaults (bool): ...
|
|
151
|
+
exclude_none (bool): ...
|
|
152
|
+
**kwargs: ...
|
|
153
|
+
|
|
154
|
+
Note:
|
|
155
|
+
If compress is True, the compression level used is 3.
|
|
156
|
+
If compress is a 2-tuple, the first element must correspond to
|
|
157
|
+
a string between supported compressors (e.g 'zlib', 'gzip',
|
|
158
|
+
'bz2', 'lzma' 'xz'), the second element must be an integer
|
|
159
|
+
from 0 to 9, corresponding to the compression level.
|
|
160
|
+
"""
|
|
161
|
+
kwargs["exclude_none"] = True
|
|
162
|
+
dump(
|
|
163
|
+
self.model_dump(mode="python", **kwargs),
|
|
164
|
+
filename,
|
|
165
|
+
compress=compress, # type: ignore
|
|
166
|
+
)
|
|
167
|
+
return filename
|
|
168
|
+
|
|
169
|
+
@classmethod
|
|
170
|
+
@pydantic.validate_call
|
|
171
|
+
def read_pickle(cls, filename: pydantic.FilePath, **kwargs) -> Self:
|
|
172
|
+
return cls.model_validate(load(filename), **kwargs)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class _IoFactoryMixin(__Json):
|
|
176
|
+
@classmethod
|
|
177
|
+
def SUPPORTED_IO_FORMATS(cls) -> tuple[str]:
|
|
178
|
+
return ("json",)
|
|
179
|
+
|
|
180
|
+
@classmethod
|
|
181
|
+
@pydantic.validate_call
|
|
182
|
+
def __get_format(cls, fname: pydantic.FilePath | pydantic.NewPath) -> str:
|
|
183
|
+
format: str = fname.name.split(".")[-1].lower()
|
|
184
|
+
assert format in cls.SUPPORTED_IO_FORMATS(), (
|
|
185
|
+
f"Invalid format: {format}. Only "
|
|
186
|
+
f"{cls.SUPPORTED_IO_FORMATS()} are available."
|
|
187
|
+
)
|
|
188
|
+
if format in ("yml", "yaml"):
|
|
189
|
+
format = "yaml"
|
|
190
|
+
elif format == "json":
|
|
191
|
+
format = "json"
|
|
192
|
+
elif format == "toml":
|
|
193
|
+
format = "toml"
|
|
194
|
+
elif format == "npz":
|
|
195
|
+
format = "npz"
|
|
196
|
+
elif format in ("pkl", "pickle"):
|
|
197
|
+
format = "pickle"
|
|
198
|
+
return format
|
|
199
|
+
|
|
200
|
+
@pydantic.validate_call
|
|
201
|
+
def write(
|
|
202
|
+
self,
|
|
203
|
+
fname: pydantic.FilePath | pydantic.NewPath,
|
|
204
|
+
**kwargs,
|
|
205
|
+
) -> pydantic.FilePath:
|
|
206
|
+
"""The factory method for writing file of this object.
|
|
207
|
+
|
|
208
|
+
Support: json, yml/yaml, toml, pkl(pickle).
|
|
209
|
+
"""
|
|
210
|
+
f = getattr(self, f"write_{self.__get_format(fname)}")
|
|
211
|
+
return f(fname, **kwargs)
|
|
212
|
+
|
|
213
|
+
@classmethod
|
|
214
|
+
@pydantic.validate_call
|
|
215
|
+
def read(cls, fname: pydantic.FilePath, **kwargs) -> Self:
|
|
216
|
+
"""The factory classmethod for reading file.
|
|
217
|
+
|
|
218
|
+
Support: json, yml/yaml, toml, pkl(pickle).
|
|
219
|
+
"""
|
|
220
|
+
f = getattr(cls, f"read_{cls.__get_format(fname)}")
|
|
221
|
+
return f(fname, **kwargs)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class __Bytes(pydantic.BaseModel):
|
|
225
|
+
@pydantic.validate_call
|
|
226
|
+
def to_bytes(
|
|
227
|
+
self,
|
|
228
|
+
compressformat: str = "snappy",
|
|
229
|
+
compresslevel: Annotated[int, pydantic.Field(ge=0, le=9)] = 0,
|
|
230
|
+
**kwargs,
|
|
231
|
+
) -> bytes:
|
|
232
|
+
"""Return the json bytes of this object."""
|
|
233
|
+
kwargs["exclude_none"] = True
|
|
234
|
+
return bytesutils.compress(
|
|
235
|
+
dumps(self.model_dump_json(**kwargs)), # type: ignore
|
|
236
|
+
format=compressformat, # type: ignore
|
|
237
|
+
compresslevel=compresslevel,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
@classmethod
|
|
241
|
+
@pydantic.validate_call
|
|
242
|
+
def from_bytes(
|
|
243
|
+
cls,
|
|
244
|
+
data: bytes,
|
|
245
|
+
compressformat: str = "snappy",
|
|
246
|
+
**kw,
|
|
247
|
+
) -> Self:
|
|
248
|
+
return cls.model_validate_json(
|
|
249
|
+
loads(
|
|
250
|
+
bytesutils.decompress(
|
|
251
|
+
data,
|
|
252
|
+
format=compressformat, # type: ignore
|
|
253
|
+
)
|
|
254
|
+
),
|
|
255
|
+
**kw,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class __Str(pydantic.BaseModel):
|
|
260
|
+
@pydantic.validate_call
|
|
261
|
+
def to_str(self, **kwargs) -> str:
|
|
262
|
+
"""Return the json string of this object."""
|
|
263
|
+
kwargs["exclude_none"] = True
|
|
264
|
+
return self.model_dump_json(**kwargs)
|
|
265
|
+
|
|
266
|
+
@classmethod
|
|
267
|
+
@pydantic.validate_call
|
|
268
|
+
def from_str(cls, data: str, **kw) -> Self:
|
|
269
|
+
return cls.model_validate_json(data, **kw)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class _ConvertFactoryMixin(__Bytes, __Str):
|
|
273
|
+
@pydantic.validate_call
|
|
274
|
+
def convert_to(self, format="bytes", **kw) -> Any:
|
|
275
|
+
return getattr(self, f"to_{format}")(**kw)
|
|
276
|
+
|
|
277
|
+
@classmethod
|
|
278
|
+
@pydantic.validate_call
|
|
279
|
+
def convert_from(cls, data: Any, format="bytes", **kw) -> Self:
|
|
280
|
+
return getattr(cls, f"from_{format}")(data, **kw)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class BaseModel(_IoFactoryMixin, _ConvertFactoryMixin, Hashable, __Pickle):
|
|
284
|
+
"""A base class for creating Pydantic models.
|
|
285
|
+
|
|
286
|
+
This class support many file formats:
|
|
287
|
+
json by `pydantic`
|
|
288
|
+
pickle by `joblib`
|
|
289
|
+
And it support many object format:
|
|
290
|
+
bytes
|
|
291
|
+
str
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
model_config = pydantic.ConfigDict(frozen=True)
|
|
295
|
+
|
|
296
|
+
def _string(self) -> str:
|
|
297
|
+
"""The string representation of this class.
|
|
298
|
+
|
|
299
|
+
The expression like `str(obj)` will output
|
|
300
|
+
`f"{self.__class__.__name__}({this_value})"`.
|
|
301
|
+
"""
|
|
302
|
+
return "object"
|
|
303
|
+
|
|
304
|
+
@override
|
|
305
|
+
def model_dump(
|
|
306
|
+
self,
|
|
307
|
+
*,
|
|
308
|
+
mode: Literal["json", "python"] | str = "python",
|
|
309
|
+
include: pydantic.main.IncEx | None = None,
|
|
310
|
+
exclude: pydantic.main.IncEx | None = None,
|
|
311
|
+
context: Any | None = None,
|
|
312
|
+
by_alias: bool | None = None,
|
|
313
|
+
exclude_unset: bool = False,
|
|
314
|
+
exclude_defaults: bool = False,
|
|
315
|
+
exclude_none: bool = False,
|
|
316
|
+
round_trip: bool = False,
|
|
317
|
+
warnings: bool | Literal["none", "warn", "error"] = True,
|
|
318
|
+
fallback: Callable[[Any], Any] | None = None,
|
|
319
|
+
serialize_as_any: bool = False,
|
|
320
|
+
numpy_ndarray_compatible: bool = True,
|
|
321
|
+
) -> dict[str, Any]:
|
|
322
|
+
result = super().model_dump(
|
|
323
|
+
mode=mode,
|
|
324
|
+
include=include,
|
|
325
|
+
exclude=exclude,
|
|
326
|
+
context=context,
|
|
327
|
+
by_alias=by_alias,
|
|
328
|
+
exclude_unset=exclude_unset,
|
|
329
|
+
exclude_defaults=exclude_defaults,
|
|
330
|
+
exclude_none=exclude_none,
|
|
331
|
+
round_trip=round_trip,
|
|
332
|
+
warnings=warnings,
|
|
333
|
+
fallback=fallback,
|
|
334
|
+
serialize_as_any=serialize_as_any,
|
|
335
|
+
)
|
|
336
|
+
if mode == "python" and numpy_ndarray_compatible:
|
|
337
|
+
for k, v0 in result.items():
|
|
338
|
+
v1 = getattr(self, k, None)
|
|
339
|
+
if type(v0) is not type(v1) and isinstance(v1, np.ndarray):
|
|
340
|
+
result[k] = v1
|
|
341
|
+
return result
|
|
342
|
+
|
|
343
|
+
def get_data_hash(self, algo: str = "blake2b", digest_size: int = 6) -> str:
|
|
344
|
+
"""Get the hash of the data of this object."""
|
|
345
|
+
data = bytesutils.hash(self.to_bytes(), True, algo)
|
|
346
|
+
assert isinstance(data, str), "data isn't string."
|
|
347
|
+
return stringutils.hash(data, algo, digest_size)
|
|
348
|
+
|
|
349
|
+
@classmethod
|
|
350
|
+
def get_pyarrow_schema(cls) -> Schema:
|
|
351
|
+
"""Get the pyarrow schema of this class."""
|
|
352
|
+
return get_pyarrow_schema(cls)
|
|
353
|
+
|
|
354
|
+
@classmethod
|
|
355
|
+
@override
|
|
356
|
+
def SUPPORTED_IO_FORMATS(cls) -> tuple[str]:
|
|
357
|
+
result: tuple[str] = super().SUPPORTED_IO_FORMATS()
|
|
358
|
+
return result + ("pickle", "pkl") # type: ignore
|
|
359
|
+
|
|
360
|
+
@override
|
|
361
|
+
def __hash__(self) -> int:
|
|
362
|
+
return hash(self.get_data_hash())
|
|
363
|
+
|
|
364
|
+
@override
|
|
365
|
+
def __str__(self) -> str:
|
|
366
|
+
return f"{self.__class__.__name__}({self._string()})"
|
|
367
|
+
|
|
368
|
+
@override
|
|
369
|
+
def __repr__(self) -> str:
|
|
370
|
+
return super().__repr__()
|
|
371
|
+
|
|
372
|
+
@override
|
|
373
|
+
def __eq__(self, other) -> bool:
|
|
374
|
+
if not isinstance(other, self.__class__):
|
|
375
|
+
return False
|
|
376
|
+
for k in self.__pydantic_fields__:
|
|
377
|
+
v0 = getattr(self, k, None)
|
|
378
|
+
v1 = getattr(other, k, None)
|
|
379
|
+
if (v0 is None) != (v1 is None):
|
|
380
|
+
return False
|
|
381
|
+
elif v0 is None and v1 is None:
|
|
382
|
+
continue
|
|
383
|
+
elif np.isscalar(v0) and np.isscalar(v1):
|
|
384
|
+
if abs(v0 - v1) > 1e-9: # type: ignore
|
|
385
|
+
return False
|
|
386
|
+
else:
|
|
387
|
+
continue
|
|
388
|
+
|
|
389
|
+
type0, type1 = type(v0), type(v1)
|
|
390
|
+
if type0 is not type1:
|
|
391
|
+
return False
|
|
392
|
+
elif issubclass(type0, pydantic.BaseModel | Sequence | Mapping):
|
|
393
|
+
if not v0.__eq__(v1):
|
|
394
|
+
return False
|
|
395
|
+
elif type0 is np.ndarray:
|
|
396
|
+
assert isinstance(v0, np.ndarray)
|
|
397
|
+
assert isinstance(v1, np.ndarray)
|
|
398
|
+
if v0.shape != v1.shape:
|
|
399
|
+
return False
|
|
400
|
+
if not np.allclose(v0, v1):
|
|
401
|
+
return False
|
|
402
|
+
else:
|
|
403
|
+
raise NotImplementedError(
|
|
404
|
+
"Unsupported type for __eq__: ", type0
|
|
405
|
+
)
|
|
406
|
+
return True
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
class ExtendedBaseModel(BaseModel, __Yaml, __Toml):
|
|
410
|
+
"""A extended base class for creating Pydantic models.
|
|
411
|
+
|
|
412
|
+
This class support many file formats:
|
|
413
|
+
json by `pydantic`
|
|
414
|
+
yaml/yml by `pyyaml`
|
|
415
|
+
pickle by `joblib`
|
|
416
|
+
toml by `tomli_w`, `tomli`, & `toml`
|
|
417
|
+
And it support many object format:
|
|
418
|
+
bytes
|
|
419
|
+
str
|
|
420
|
+
"""
|
|
421
|
+
|
|
422
|
+
@override
|
|
423
|
+
def __hash__(self) -> int:
|
|
424
|
+
return super().__hash__()
|
|
425
|
+
|
|
426
|
+
@classmethod
|
|
427
|
+
@override
|
|
428
|
+
def SUPPORTED_IO_FORMATS(cls) -> tuple[str]:
|
|
429
|
+
result: tuple[str] = super().SUPPORTED_IO_FORMATS()
|
|
430
|
+
return result + ("yaml", "yml", "toml") # type: ignore
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
class NpzPklBaseModel(BaseModel, __Npz):
|
|
434
|
+
"""A extended base class for creating Pydantic models.
|
|
435
|
+
|
|
436
|
+
This class support many file formats:
|
|
437
|
+
json by `pydantic`
|
|
438
|
+
pickle by `joblib`
|
|
439
|
+
npz by `numpy`
|
|
440
|
+
And it support many object format:
|
|
441
|
+
bytes
|
|
442
|
+
str
|
|
443
|
+
|
|
444
|
+
Note: only numpy ndarray & numpy-compatible scalar value supported.
|
|
445
|
+
"""
|
|
446
|
+
|
|
447
|
+
@override
|
|
448
|
+
def __hash__(self) -> int:
|
|
449
|
+
return super().__hash__()
|
|
450
|
+
|
|
451
|
+
@classmethod
|
|
452
|
+
@override
|
|
453
|
+
def SUPPORTED_IO_FORMATS(cls) -> tuple[str]:
|
|
454
|
+
result: tuple[str] = super().SUPPORTED_IO_FORMATS()
|
|
455
|
+
return result + ("npz",) # type: ignore
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
class AllBaseModel(ExtendedBaseModel, __Npz):
|
|
459
|
+
"""A extended base class for creating Pydantic models.
|
|
460
|
+
|
|
461
|
+
This class support many file formats:
|
|
462
|
+
json by `pydantic`
|
|
463
|
+
npz by `numpy`
|
|
464
|
+
pickle by `joblib`
|
|
465
|
+
yaml/yml by `pyyaml`
|
|
466
|
+
toml by `tomli_w`, `tomli`, & `toml`
|
|
467
|
+
And it support many object format:
|
|
468
|
+
bytes
|
|
469
|
+
str
|
|
470
|
+
|
|
471
|
+
Note: only numpy ndarray & numpy-compatible scalar value supported.
|
|
472
|
+
"""
|
|
473
|
+
|
|
474
|
+
@override
|
|
475
|
+
def __hash__(self) -> int:
|
|
476
|
+
return super().__hash__()
|
|
477
|
+
|
|
478
|
+
@classmethod
|
|
479
|
+
@override
|
|
480
|
+
def SUPPORTED_IO_FORMATS(cls) -> tuple[str]:
|
|
481
|
+
result: tuple[str] = super().SUPPORTED_IO_FORMATS()
|
|
482
|
+
return result + ("npz",) # type: ignore
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""The Basic Classes For Systems and its Sub Classes."""
|
|
2
|
+
|
|
3
|
+
from GraphAtoms.containner._aOther import OTHER_KEY
|
|
4
|
+
from GraphAtoms.containner._atomic import ATOM_KEY, AtomsWithBoxEng
|
|
5
|
+
from GraphAtoms.containner._gBonded import BOND_KEY, BondsWithComp
|
|
6
|
+
from GraphAtoms.containner._graph import Graph
|
|
7
|
+
from GraphAtoms.containner._sysCluster import Cluster
|
|
8
|
+
from GraphAtoms.containner._sysGas import Gas
|
|
9
|
+
from GraphAtoms.containner._system import System
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"ATOM_KEY",
|
|
13
|
+
"AtomsWithBoxEng",
|
|
14
|
+
"BOND_KEY",
|
|
15
|
+
"BondsWithComp",
|
|
16
|
+
"Cluster",
|
|
17
|
+
"OTHER_KEY",
|
|
18
|
+
"Gas",
|
|
19
|
+
"Graph",
|
|
20
|
+
"System",
|
|
21
|
+
]
|