From e5c6282c860719cae71cf18ef2b31df09ef9c50c Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Thu, 26 Feb 2026 06:23:30 -0300 Subject: [PATCH 1/3] chore: fixes tests --- diceplayer/{shared => }/config/__init__.py | 0 diceplayer/config/dice_config.py | 27 +++ diceplayer/config/gaussian_config.py | 21 ++ .../{shared => }/config/player_config.py | 10 +- diceplayer/player.py | 31 +-- diceplayer/shared/config/dice_config.py | 51 ----- diceplayer/shared/config/gaussian_config.py | 30 --- diceplayer/shared/interface/__interface.py | 2 +- diceplayer/shared/interface/dice_interface.py | 2 +- .../shared/interface/gaussian_interface.py | 2 +- poetry.lock | 197 +++++++++++++++++- pyproject.toml | 1 + tests/shared/config/test_dice_dto.py | 4 +- tests/shared/config/test_gaussian_dto.py | 14 +- tests/shared/config/test_player_dto.py | 12 +- tests/shared/interface/test_dice_interface.py | 2 +- .../interface/test_gaussian_interface.py | 2 +- tests/test_player.py | 3 + 18 files changed, 284 insertions(+), 127 deletions(-) rename diceplayer/{shared => }/config/__init__.py (100%) create mode 100644 diceplayer/config/dice_config.py create mode 100644 diceplayer/config/gaussian_config.py rename diceplayer/{shared => }/config/player_config.py (78%) delete mode 100644 diceplayer/shared/config/dice_config.py delete mode 100644 diceplayer/shared/config/gaussian_config.py diff --git a/diceplayer/shared/config/__init__.py b/diceplayer/config/__init__.py similarity index 100% rename from diceplayer/shared/config/__init__.py rename to diceplayer/config/__init__.py diff --git a/diceplayer/config/dice_config.py b/diceplayer/config/dice_config.py new file mode 100644 index 0000000..8730ed2 --- /dev/null +++ b/diceplayer/config/dice_config.py @@ -0,0 +1,27 @@ +from pydantic import BaseModel, Field + +from diceplayer.shared.utils.dataclass_protocol import Dataclass + +from dataclasses import dataclass, fields +from typing import List, Literal + + +class DiceConfig(BaseModel): + """ + Data Transfer Object for the Dice configuration. + """ + + ljname: str = Field(..., description="Name of the Lennard-Jones potential file") + outname: str = Field(..., description="Name of the output file for the simulation results") + dens: float = Field(..., description="Density of the system") + nmol: List[int] = Field(..., description="List of the number of molecules for each component") + nstep: List[int] = Field(..., description="List of the number of steps for each component", min_length=2, max_length=3) + + upbuf: int = Field(360, description="Buffer size for the potential energy calculations") + combrule: Literal["+", "*"] = Field("*", description="Combination rule for the Lennard-Jones potential") + isave: int = Field(1000, description="Frequency of saving the simulation results") + press: float = Field(1.0, description="Pressure of the system") + temp: float = Field(300.0, description="Temperature of the system") + progname: str = Field("dice", description="Name of the program to run the simulation") + randominit: str = Field("first", description="Method for initializing the random number generator") + seed: int | None = Field(None, description="Seed for the random number generator") diff --git a/diceplayer/config/gaussian_config.py b/diceplayer/config/gaussian_config.py new file mode 100644 index 0000000..2f9b4c5 --- /dev/null +++ b/diceplayer/config/gaussian_config.py @@ -0,0 +1,21 @@ +from typing import Literal + +from pydantic import BaseModel, Field + +from diceplayer.shared.utils.dataclass_protocol import Dataclass + +from dataclasses import dataclass, fields + + +class GaussianConfig(BaseModel): + """ + Data Transfer Object for the Gaussian configuration. + """ + + level: str = Field(..., description="Level of theory for the QM calculations") + qmprog: Literal["g03", "g09", "g16"] = Field("g16", description="QM program to use for the calculations") + + chgmult: list[int] = Field(default_factory=lambda: [0, 1], description="List of charge and multiplicity for the QM calculations") + pop: str = Field("chelpg", description="Population analysis method for the QM calculations") + chg_tol: float = Field(0.01, description="Charge tolerance for the QM calculations") + keywords: str = Field(None, description="Additional keywords for the QM calculations") diff --git a/diceplayer/shared/config/player_config.py b/diceplayer/config/player_config.py similarity index 78% rename from diceplayer/shared/config/player_config.py rename to diceplayer/config/player_config.py index 288e689..29d1e23 100644 --- a/diceplayer/shared/config/player_config.py +++ b/diceplayer/config/player_config.py @@ -1,5 +1,5 @@ -from diceplayer.shared.config.dice_config import DiceConfig -from diceplayer.shared.config.gaussian_config import GaussianDTO +from diceplayer.config.dice_config import DiceConfig +from diceplayer.config.gaussian_config import GaussianConfig from diceplayer.shared.utils.dataclass_protocol import Dataclass from dataclasses import dataclass, fields @@ -17,7 +17,7 @@ class PlayerConfig(Dataclass): ncores: int dice: DiceConfig - gaussian: GaussianDTO + gaussian: GaussianConfig mem: int = None switchcyc: int = 3 @@ -35,11 +35,11 @@ class PlayerConfig(Dataclass): def from_dict(cls, params: dict): if params["dice"] is None: raise ValueError("Error: 'dice' keyword not specified in config file.") - params["dice"] = DiceConfig.from_dict(params["dice"]) + params["dice"] = DiceConfig.model_validate(params["dice"]) if params["gaussian"] is None: raise ValueError("Error: 'gaussian' keyword not specified in config file.") - params["gaussian"] = GaussianDTO.from_dict(params["gaussian"]) + params["gaussian"] = GaussianConfig.model_validate(params["gaussian"]) params = {f.name: params[f.name] for f in fields(cls) if f.name in params} diff --git a/diceplayer/player.py b/diceplayer/player.py index 5241093..3e77848 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -1,7 +1,9 @@ +from pydantic import BaseModel + from diceplayer import VERSION, logger -from diceplayer.shared.config.dice_config import DiceConfig -from diceplayer.shared.config.gaussian_config import GaussianDTO -from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.config.dice_config import DiceConfig +from diceplayer.config.gaussian_config import GaussianConfig +from diceplayer.config.player_config import PlayerConfig from diceplayer.shared.environment.atom import Atom from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.system import System @@ -16,7 +18,6 @@ import yaml import os import pickle import sys -from dataclasses import fields from pathlib import Path from typing import Tuple, Type @@ -108,14 +109,16 @@ class Player: geoms_file_path.touch() def print_keywords(self) -> None: - def log_keywords(config: Dataclass, dto: Type[Dataclass]): - for key in sorted(list(map(lambda f: f.name, fields(dto)))): - if getattr(config, key) is not None: - if isinstance(getattr(config, key), list): - string = " ".join(str(x) for x in getattr(config, key)) - logger.info(f"{key} = [ {string} ]") - else: - logger.info(f"{key} = {getattr(config, key)}") + def log_keywords(config: BaseModel): + for key, value in sorted(config.model_dump().items()): + if value is None: + continue + if isinstance(value, list): + string = " ".join(str(x) for x in value) + logger.info(f"{key} = [ {string} ]") + else: + logger.info(f"{key} = {value}") + logger.info( f"##########################################################################################\n" @@ -138,7 +141,7 @@ class Player: "------------------------------------------------------------------------------------------\n" ) - log_keywords(self.config.dice, DiceConfig) + log_keywords(self.config.dice) logger.info( "------------------------------------------------------------------------------------------\n" @@ -146,7 +149,7 @@ class Player: "------------------------------------------------------------------------------------------\n" ) - log_keywords(self.config.gaussian, GaussianDTO) + log_keywords(self.config.gaussian) logger.info("\n") diff --git a/diceplayer/shared/config/dice_config.py b/diceplayer/shared/config/dice_config.py deleted file mode 100644 index e218f6d..0000000 --- a/diceplayer/shared/config/dice_config.py +++ /dev/null @@ -1,51 +0,0 @@ -from diceplayer.shared.utils.dataclass_protocol import Dataclass - -from dataclasses import dataclass, fields -from typing import List - - -@dataclass -class DiceConfig(Dataclass): - """ - Data Transfer Object for the Dice configuration. - """ - - ljname: str - outname: str - dens: float - nmol: List[int] - nstep: List[int] - - upbuf = 360 - combrule = "*" - isave: int = 1000 - press: float = 1.0 - temp: float = 300.0 - progname: str = "dice" - randominit: str = "first" - - def __post_init__(self): - if not isinstance(self.ljname, str): - raise ValueError("Error: 'ljname' keyword not specified in config file") - - if not isinstance(self.outname, str): - raise ValueError("Error: 'outname' keyword not specified in config file") - - if not isinstance(self.dens, float): - raise ValueError("Error: 'dens' keyword not specified in config file") - - if not isinstance(self.nmol, list): - raise ValueError( - "Error: 'nmol' keyword not defined appropriately in config file" - ) - - if not isinstance(self.nstep, list) or len(self.nstep) not in (2, 3): - raise ValueError( - "Error: 'nstep' keyword not defined appropriately in config file" - ) - - @classmethod - def from_dict(cls, params: dict): - params = {f.name: params[f.name] for f in fields(cls) if f.name in params} - - return cls(**params) diff --git a/diceplayer/shared/config/gaussian_config.py b/diceplayer/shared/config/gaussian_config.py deleted file mode 100644 index ec65059..0000000 --- a/diceplayer/shared/config/gaussian_config.py +++ /dev/null @@ -1,30 +0,0 @@ -from diceplayer.shared.utils.dataclass_protocol import Dataclass - -from dataclasses import dataclass, fields - - -@dataclass -class GaussianDTO(Dataclass): - """ - Data Transfer Object for the Gaussian configuration. - """ - - level: str - qmprog: str - - chgmult = [0, 1] - pop: str = "chelpg" - chg_tol: float = 0.01 - keywords: str = None - - def __post_init__(self): - if self.qmprog not in ("g03", "g09", "g16"): - raise ValueError("Error: invalid qmprog value.") - if self.level is None: - raise ValueError("Error: 'level' keyword not specified in config file.") - - @classmethod - def from_dict(cls, params: dict): - params = {f.name: params[f.name] for f in fields(cls) if f.name in params} - - return cls(**params) diff --git a/diceplayer/shared/interface/__interface.py b/diceplayer/shared/interface/__interface.py index 89a06e3..bc02d86 100644 --- a/diceplayer/shared/interface/__interface.py +++ b/diceplayer/shared/interface/__interface.py @@ -1,6 +1,6 @@ from __future__ import annotations -from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.config.player_config import PlayerConfig from diceplayer.shared.environment.system import System from abc import ABC, abstractmethod diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index db97999..848661c 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -1,7 +1,7 @@ from __future__ import annotations from diceplayer import logger -from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.config.player_config import PlayerConfig from diceplayer.shared.environment.system import System from diceplayer.shared.interface import Interface diff --git a/diceplayer/shared/interface/gaussian_interface.py b/diceplayer/shared/interface/gaussian_interface.py index 1dd69bb..73b372a 100644 --- a/diceplayer/shared/interface/gaussian_interface.py +++ b/diceplayer/shared/interface/gaussian_interface.py @@ -1,7 +1,7 @@ from __future__ import annotations from diceplayer import logger -from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.config.player_config import PlayerConfig from diceplayer.shared.environment.atom import Atom from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.system import System diff --git a/poetry.lock b/poetry.lock index adbcebe..44ca879 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,17 @@ # This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + [[package]] name = "argparse" version = "1.4.0" @@ -407,6 +419,162 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "pydantic" +version = "2.12.5" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"}, + {file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.41.5" +typing-extensions = ">=4.14.1" +typing-inspection = ">=0.4.2" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146"}, + {file = "pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49"}, + {file = "pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba"}, + {file = "pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9"}, + {file = "pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6"}, + {file = "pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f"}, + {file = "pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7"}, + {file = "pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3"}, + {file = "pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9"}, + {file = "pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd"}, + {file = "pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a"}, + {file = "pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008"}, + {file = "pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf"}, + {file = "pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3"}, + {file = "pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460"}, + {file = "pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51"}, + {file = "pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e"}, +] + +[package.dependencies] +typing-extensions = ">=4.14.1" + [[package]] name = "pyyaml" version = "6.0.1" @@ -583,16 +751,31 @@ files = [ [[package]] name = "typing-extensions" -version = "4.12.2" -description = "Backported and Experimental Type Hints for Python 3.8+" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, ] -markers = {main = "python_version == \"3.9\"", dev = "python_version < \"3.11\""} +markers = {dev = "python_version < \"3.11\""} + +[[package]] +name = "typing-inspection" +version = "0.4.2" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, + {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" [[package]] name = "virtualenv" @@ -618,4 +801,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" python-versions = ">=3.9" -content-hash = "f1adb46e996bb9ce175110b2924da21fb8d5b7e2818dc981fca266ea95d51d3d" +content-hash = "4a1819a86e32881c06191270ef503ebe87ef4ff519052fd8f0852510e31668e1" diff --git a/pyproject.toml b/pyproject.toml index 0bb1df6..c25892c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ argparse = "^1.4.0" setproctitle = "^1.3.2" pyyaml = "^6.0" nptyping = "^2.5.0" +pydantic = "^2.12.5" [tool.poetry.group.dev.dependencies] diff --git a/tests/shared/config/test_dice_dto.py b/tests/shared/config/test_dice_dto.py index 0793582..3cd4f23 100644 --- a/tests/shared/config/test_dice_dto.py +++ b/tests/shared/config/test_dice_dto.py @@ -1,4 +1,4 @@ -from diceplayer.shared.config.dice_config import DiceConfig +from diceplayer.config.dice_config import DiceConfig import unittest @@ -83,7 +83,7 @@ class TestDiceDto(unittest.TestCase): ) def test_from_dict(self): - dice_dto = DiceConfig.from_dict( + dice_dto = DiceConfig.model_validate( { "ljname": "test", "outname": "test", diff --git a/tests/shared/config/test_gaussian_dto.py b/tests/shared/config/test_gaussian_dto.py index f8d7745..f20abf7 100644 --- a/tests/shared/config/test_gaussian_dto.py +++ b/tests/shared/config/test_gaussian_dto.py @@ -1,21 +1,21 @@ -from diceplayer.shared.config.gaussian_config import GaussianDTO +from diceplayer.config.gaussian_config import GaussianConfig import unittest class TestGaussianDTO(unittest.TestCase): def test_class_instantiation(self): - gaussian_dto = GaussianDTO( + gaussian_dto = GaussianConfig( level="test", qmprog="g16", keywords="test", ) - self.assertIsInstance(gaussian_dto, GaussianDTO) + self.assertIsInstance(gaussian_dto, GaussianConfig) def test_is_valid_qmprog(self): with self.assertRaises(ValueError): - gaussian_dto = GaussianDTO( + gaussian_dto = GaussianConfig( level="test", qmprog="test", keywords="test", @@ -23,14 +23,14 @@ class TestGaussianDTO(unittest.TestCase): def test_is_valid_level(self): with self.assertRaises(ValueError): - gaussian_dto = GaussianDTO( + gaussian_dto = GaussianConfig( level=None, qmprog="g16", keywords="test", ) def test_from_dict(self): - gaussian_dto = GaussianDTO.from_dict( + gaussian_dto = GaussianConfig.model_validate( { "level": "test", "qmprog": "g16", @@ -38,7 +38,7 @@ class TestGaussianDTO(unittest.TestCase): } ) - self.assertIsInstance(gaussian_dto, GaussianDTO) + self.assertIsInstance(gaussian_dto, GaussianConfig) if __name__ == "__main__": diff --git a/tests/shared/config/test_player_dto.py b/tests/shared/config/test_player_dto.py index 2c3121c..7a74a95 100644 --- a/tests/shared/config/test_player_dto.py +++ b/tests/shared/config/test_player_dto.py @@ -1,6 +1,6 @@ -from diceplayer.shared.config.dice_config import DiceConfig -from diceplayer.shared.config.gaussian_config import GaussianDTO -from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.config.dice_config import DiceConfig +from diceplayer.config.gaussian_config import GaussianConfig +from diceplayer.config.player_config import PlayerConfig import unittest @@ -36,7 +36,7 @@ class TestPlayerDTO(unittest.TestCase): nmol=[1], nstep=[1, 1], ) - self.gaussian_dto = GaussianDTO( + self.gaussian_dto = GaussianConfig( level="test", qmprog="g16", keywords="test", @@ -55,7 +55,7 @@ class TestPlayerDTO(unittest.TestCase): self.assertIsInstance(player_dto, PlayerConfig) self.assertIsInstance(player_dto.dice, DiceConfig) - self.assertIsInstance(player_dto.gaussian, GaussianDTO) + self.assertIsInstance(player_dto.gaussian, GaussianConfig) def test_min_altsteps(self): player_dto = PlayerConfig( @@ -76,7 +76,7 @@ class TestPlayerDTO(unittest.TestCase): self.assertIsInstance(player_dto, PlayerConfig) self.assertIsInstance(player_dto.dice, DiceConfig) - self.assertIsInstance(player_dto.gaussian, GaussianDTO) + self.assertIsInstance(player_dto.gaussian, GaussianConfig) if __name__ == "__main__": diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index c182149..54ce426 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -1,5 +1,5 @@ from diceplayer import logger -from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.config.player_config import PlayerConfig from diceplayer.shared.environment.atom import Atom from diceplayer.shared.environment.molecule import Molecule from diceplayer.shared.environment.system import System diff --git a/tests/shared/interface/test_gaussian_interface.py b/tests/shared/interface/test_gaussian_interface.py index 4e6e12f..0a7f17f 100644 --- a/tests/shared/interface/test_gaussian_interface.py +++ b/tests/shared/interface/test_gaussian_interface.py @@ -1,5 +1,5 @@ from diceplayer import logger -from diceplayer.shared.config.player_config import PlayerConfig +from diceplayer.config.player_config import PlayerConfig from diceplayer.shared.environment.system import System from diceplayer.shared.interface.gaussian_interface import GaussianInterface from tests.mocks.mock_inputs import get_config_example diff --git a/tests/test_player.py b/tests/test_player.py index b53112b..486c908 100644 --- a/tests/test_player.py +++ b/tests/test_player.py @@ -71,6 +71,7 @@ class TestPlayer(unittest.TestCase): "INFO:diceplayer:Environment variables:", "INFO:diceplayer:OMP_STACKSIZE = Not set\n", "INFO:diceplayer:------------------------------------------------------------------------------------------\n DICE variables being used in this run:\n------------------------------------------------------------------------------------------\n", + "INFO:diceplayer:combrule = *", "INFO:diceplayer:dens = 0.75", "INFO:diceplayer:isave = 1000", "INFO:diceplayer:ljname = phb.ljc", @@ -81,8 +82,10 @@ class TestPlayer(unittest.TestCase): "INFO:diceplayer:progname = ~/.local/bin/dice", "INFO:diceplayer:randominit = first", "INFO:diceplayer:temp = 300.0", + "INFO:diceplayer:upbuf = 360", "INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n", "INFO:diceplayer:chg_tol = 0.01", + "INFO:diceplayer:chgmult = [ 0 1 ]", "INFO:diceplayer:keywords = freq", "INFO:diceplayer:level = MP2/aug-cc-pVDZ", "INFO:diceplayer:pop = chelpg", From c51d07cff281a705e0327340403e10671113e5c7 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Thu, 26 Feb 2026 08:35:59 -0300 Subject: [PATCH 2/3] feat: improved implementation and validations of configs --- diceplayer/config/dice_config.py | 35 +++++++--- diceplayer/config/gaussian_config.py | 22 +++++-- diceplayer/config/player_config.py | 65 ++++++++++--------- diceplayer/player.py | 6 +- diceplayer/shared/interface/dice_interface.py | 7 +- tests/{shared => }/config/__init__.py | 0 tests/{shared => }/config/test_dice_dto.py | 0 .../{shared => }/config/test_gaussian_dto.py | 0 tests/{shared => }/config/test_player_dto.py | 2 +- tests/shared/interface/test_dice_interface.py | 2 +- .../interface/test_gaussian_interface.py | 2 +- 11 files changed, 84 insertions(+), 57 deletions(-) rename tests/{shared => }/config/__init__.py (100%) rename tests/{shared => }/config/test_dice_dto.py (100%) rename tests/{shared => }/config/test_gaussian_dto.py (100%) rename tests/{shared => }/config/test_player_dto.py (96%) diff --git a/diceplayer/config/dice_config.py b/diceplayer/config/dice_config.py index 8730ed2..907d5bf 100644 --- a/diceplayer/config/dice_config.py +++ b/diceplayer/config/dice_config.py @@ -1,7 +1,7 @@ -from pydantic import BaseModel, Field - from diceplayer.shared.utils.dataclass_protocol import Dataclass +from pydantic import BaseModel, Field + from dataclasses import dataclass, fields from typing import List, Literal @@ -12,16 +12,33 @@ class DiceConfig(BaseModel): """ ljname: str = Field(..., description="Name of the Lennard-Jones potential file") - outname: str = Field(..., description="Name of the output file for the simulation results") + outname: str = Field( + ..., description="Name of the output file for the simulation results" + ) dens: float = Field(..., description="Density of the system") - nmol: List[int] = Field(..., description="List of the number of molecules for each component") - nstep: List[int] = Field(..., description="List of the number of steps for each component", min_length=2, max_length=3) + nmol: List[int] = Field( + ..., description="List of the number of molecules for each component" + ) + nstep: List[int] = Field( + ..., + description="List of the number of steps for each component", + min_length=2, + max_length=3, + ) - upbuf: int = Field(360, description="Buffer size for the potential energy calculations") - combrule: Literal["+", "*"] = Field("*", description="Combination rule for the Lennard-Jones potential") + upbuf: int = Field( + 360, description="Buffer size for the potential energy calculations" + ) + combrule: Literal["+", "*"] = Field( + "*", description="Combination rule for the Lennard-Jones potential" + ) isave: int = Field(1000, description="Frequency of saving the simulation results") press: float = Field(1.0, description="Pressure of the system") temp: float = Field(300.0, description="Temperature of the system") - progname: str = Field("dice", description="Name of the program to run the simulation") - randominit: str = Field("first", description="Method for initializing the random number generator") + progname: str = Field( + "dice", description="Name of the program to run the simulation" + ) + randominit: str = Field( + "first", description="Method for initializing the random number generator" + ) seed: int | None = Field(None, description="Seed for the random number generator") diff --git a/diceplayer/config/gaussian_config.py b/diceplayer/config/gaussian_config.py index 2f9b4c5..bc741b2 100644 --- a/diceplayer/config/gaussian_config.py +++ b/diceplayer/config/gaussian_config.py @@ -1,10 +1,9 @@ -from typing import Literal +from diceplayer.shared.utils.dataclass_protocol import Dataclass from pydantic import BaseModel, Field -from diceplayer.shared.utils.dataclass_protocol import Dataclass - from dataclasses import dataclass, fields +from typing import Literal class GaussianConfig(BaseModel): @@ -13,9 +12,18 @@ class GaussianConfig(BaseModel): """ level: str = Field(..., description="Level of theory for the QM calculations") - qmprog: Literal["g03", "g09", "g16"] = Field("g16", description="QM program to use for the calculations") + qmprog: Literal["g03", "g09", "g16"] = Field( + "g16", description="QM program to use for the calculations" + ) - chgmult: list[int] = Field(default_factory=lambda: [0, 1], description="List of charge and multiplicity for the QM calculations") - pop: str = Field("chelpg", description="Population analysis method for the QM calculations") + chgmult: list[int] = Field( + default_factory=lambda: [0, 1], + description="List of charge and multiplicity for the QM calculations", + ) + pop: str = Field( + "chelpg", description="Population analysis method for the QM calculations" + ) chg_tol: float = Field(0.01, description="Charge tolerance for the QM calculations") - keywords: str = Field(None, description="Additional keywords for the QM calculations") + keywords: str = Field( + None, description="Additional keywords for the QM calculations" + ) diff --git a/diceplayer/config/player_config.py b/diceplayer/config/player_config.py index 29d1e23..1ec4993 100644 --- a/diceplayer/config/player_config.py +++ b/diceplayer/config/player_config.py @@ -2,45 +2,48 @@ from diceplayer.config.dice_config import DiceConfig from diceplayer.config.gaussian_config import GaussianConfig from diceplayer.shared.utils.dataclass_protocol import Dataclass +from pydantic import BaseModel, Field, field_validator, model_validator + from dataclasses import dataclass, fields +from pathlib import Path +from typing import Self + +MIN_STEP = 20000 -@dataclass -class PlayerConfig(Dataclass): +class PlayerConfig(BaseModel): """ Data Transfer Object for the player configuration. """ - opt: bool - maxcyc: int - nprocs: int - ncores: int + opt: bool = Field(..., description="Whether to perform geometry optimization") + maxcyc: int = Field( + ..., description="Maximum number of cycles for the geometry optimization" + ) + nprocs: int = Field( + ..., description="Number of processors to use for the QM calculations" + ) + ncores: int = Field( + ..., description="Number of cores to use for the QM calculations" + ) - dice: DiceConfig - gaussian: GaussianConfig + dice: DiceConfig = Field(..., description="Dice configuration") + gaussian: GaussianConfig = Field(..., description="Gaussian configuration") - mem: int = None - switchcyc: int = 3 - qmprog: str = "g16" - altsteps: int = 20000 - geoms_file = "geoms.xyz" - simulation_dir = "simfiles" + mem: int = Field(None, description="Memory configuration") + switchcyc: int = Field(3, description="Switch cycle configuration") + qmprog: str = Field("g16", description="QM program to use for the calculations") + altsteps: int = Field( + 20000, description="Number of steps for the alternate simulation" + ) + geoms_file: Path = Field( + "geoms.xyz", description="File name for the geometries output" + ) + simulation_dir: Path = Field( + "simfiles", description="Directory name for the simulation files" + ) - def __post_init__(self): - MIN_STEP = 20000 - # altsteps value is always the nearest multiple of 1000 + @model_validator(mode="after") + def validate_altsteps(self) -> Self: self.altsteps = round(max(MIN_STEP, self.altsteps) / 1000) * 1000 - - @classmethod - def from_dict(cls, params: dict): - if params["dice"] is None: - raise ValueError("Error: 'dice' keyword not specified in config file.") - params["dice"] = DiceConfig.model_validate(params["dice"]) - - if params["gaussian"] is None: - raise ValueError("Error: 'gaussian' keyword not specified in config file.") - params["gaussian"] = GaussianConfig.model_validate(params["gaussian"]) - - params = {f.name: params[f.name] for f in fields(cls) if f.name in params} - - return cls(**params) + return self diff --git a/diceplayer/player.py b/diceplayer/player.py index 3e77848..5aa2f5b 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -1,5 +1,3 @@ -from pydantic import BaseModel - from diceplayer import VERSION, logger from diceplayer.config.dice_config import DiceConfig from diceplayer.config.gaussian_config import GaussianConfig @@ -14,6 +12,7 @@ from diceplayer.shared.utils.misc import weekday_date_time from diceplayer.shared.utils.ptable import atomsymb import yaml +from pydantic import BaseModel import os import pickle @@ -119,7 +118,6 @@ class Player: else: logger.info(f"{key} = {value}") - logger.info( f"##########################################################################################\n" f"############# Welcome to DICEPLAYER version {VERSION} #############\n" @@ -430,7 +428,7 @@ class Player: @staticmethod def set_config(data: dict) -> PlayerConfig: - return PlayerConfig.from_dict(data) + return PlayerConfig.model_validate(data) @staticmethod def read_keywords(infile) -> dict: diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index 848661c..c13ef63 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -356,9 +356,10 @@ class DiceInterface(Interface): ) def run_dice_file(self, cycle: int, proc: int, file_name: str): - with open(Path(file_name), "r") as infile, open( - Path(file_name + ".out"), "w" - ) as outfile: + with ( + open(Path(file_name), "r") as infile, + open(Path(file_name + ".out"), "w") as outfile, + ): if shutil.which("bash") is not None: exit_status = subprocess.call( [ diff --git a/tests/shared/config/__init__.py b/tests/config/__init__.py similarity index 100% rename from tests/shared/config/__init__.py rename to tests/config/__init__.py diff --git a/tests/shared/config/test_dice_dto.py b/tests/config/test_dice_dto.py similarity index 100% rename from tests/shared/config/test_dice_dto.py rename to tests/config/test_dice_dto.py diff --git a/tests/shared/config/test_gaussian_dto.py b/tests/config/test_gaussian_dto.py similarity index 100% rename from tests/shared/config/test_gaussian_dto.py rename to tests/config/test_gaussian_dto.py diff --git a/tests/shared/config/test_player_dto.py b/tests/config/test_player_dto.py similarity index 96% rename from tests/shared/config/test_player_dto.py rename to tests/config/test_player_dto.py index 7a74a95..883fad0 100644 --- a/tests/shared/config/test_player_dto.py +++ b/tests/config/test_player_dto.py @@ -72,7 +72,7 @@ class TestPlayerDTO(unittest.TestCase): self.assertEqual(player_dto.altsteps, 20000) def test_from_dict(self): - player_dto = PlayerConfig.from_dict(get_config_dict()) + player_dto = PlayerConfig.model_validate(get_config_dict()) self.assertIsInstance(player_dto, PlayerConfig) self.assertIsInstance(player_dto.dice, DiceConfig) diff --git a/tests/shared/interface/test_dice_interface.py b/tests/shared/interface/test_dice_interface.py index 54ce426..b246f08 100644 --- a/tests/shared/interface/test_dice_interface.py +++ b/tests/shared/interface/test_dice_interface.py @@ -19,7 +19,7 @@ class TestDiceInterface(unittest.TestCase): logger.set_logger(stream=io.StringIO()) config = yaml.load(get_config_example(), Loader=yaml.Loader) - self.config = PlayerConfig.from_dict(config["diceplayer"]) + self.config = PlayerConfig.model_validate(config["diceplayer"]) def test_class_instantiation(self): dice = DiceInterface() diff --git a/tests/shared/interface/test_gaussian_interface.py b/tests/shared/interface/test_gaussian_interface.py index 0a7f17f..723de74 100644 --- a/tests/shared/interface/test_gaussian_interface.py +++ b/tests/shared/interface/test_gaussian_interface.py @@ -16,7 +16,7 @@ class TestGaussianInterface(unittest.TestCase): logger.set_logger(stream=io.StringIO()) config = yaml.load(get_config_example(), Loader=yaml.Loader) - self.config = PlayerConfig.from_dict(config["diceplayer"]) + self.config = PlayerConfig.model_validate(config["diceplayer"]) def test_class_instantiation(self): gaussian_interface = GaussianInterface() From f0e5bbeaeed2904a502d0a14cef034c826cc4084 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Thu, 26 Feb 2026 08:39:21 -0300 Subject: [PATCH 3/3] fix: switches typing to typing_extensions for python3.10 compatibility --- diceplayer/config/dice_config.py | 2 +- diceplayer/config/gaussian_config.py | 2 +- diceplayer/config/player_config.py | 2 +- diceplayer/player.py | 2 +- diceplayer/shared/environment/molecule.py | 4 ++-- diceplayer/shared/environment/system.py | 2 +- diceplayer/shared/interface/dice_interface.py | 2 +- diceplayer/shared/interface/gaussian_interface.py | 2 +- diceplayer/shared/utils/dataclass_protocol.py | 2 +- diceplayer/shared/utils/misc.py | 3 ++- poetry.lock | 2 +- pyproject.toml | 1 + tests/mocks/mock_proc.py | 3 ++- 13 files changed, 16 insertions(+), 13 deletions(-) diff --git a/diceplayer/config/dice_config.py b/diceplayer/config/dice_config.py index 907d5bf..a50ed5d 100644 --- a/diceplayer/config/dice_config.py +++ b/diceplayer/config/dice_config.py @@ -1,9 +1,9 @@ from diceplayer.shared.utils.dataclass_protocol import Dataclass from pydantic import BaseModel, Field +from typing_extensions import List, Literal from dataclasses import dataclass, fields -from typing import List, Literal class DiceConfig(BaseModel): diff --git a/diceplayer/config/gaussian_config.py b/diceplayer/config/gaussian_config.py index bc741b2..72c6c9d 100644 --- a/diceplayer/config/gaussian_config.py +++ b/diceplayer/config/gaussian_config.py @@ -1,9 +1,9 @@ from diceplayer.shared.utils.dataclass_protocol import Dataclass from pydantic import BaseModel, Field +from typing_extensions import Literal from dataclasses import dataclass, fields -from typing import Literal class GaussianConfig(BaseModel): diff --git a/diceplayer/config/player_config.py b/diceplayer/config/player_config.py index 1ec4993..da14432 100644 --- a/diceplayer/config/player_config.py +++ b/diceplayer/config/player_config.py @@ -3,10 +3,10 @@ from diceplayer.config.gaussian_config import GaussianConfig from diceplayer.shared.utils.dataclass_protocol import Dataclass from pydantic import BaseModel, Field, field_validator, model_validator +from typing_extensions import Self from dataclasses import dataclass, fields from pathlib import Path -from typing import Self MIN_STEP = 20000 diff --git a/diceplayer/player.py b/diceplayer/player.py index 5aa2f5b..e4cb5e0 100644 --- a/diceplayer/player.py +++ b/diceplayer/player.py @@ -13,12 +13,12 @@ from diceplayer.shared.utils.ptable import atomsymb import yaml from pydantic import BaseModel +from typing_extensions import Tuple, Type import os import pickle import sys from pathlib import Path -from typing import Tuple, Type ENV = ["OMP_STACKSIZE"] diff --git a/diceplayer/shared/environment/molecule.py b/diceplayer/shared/environment/molecule.py index e4003b4..28571c7 100644 --- a/diceplayer/shared/environment/molecule.py +++ b/diceplayer/shared/environment/molecule.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing_extensions import TYPE_CHECKING if TYPE_CHECKING: from nptyping import Float, NDArray, Shape @@ -12,10 +12,10 @@ from diceplayer.shared.utils.ptable import ghost_number import numpy as np from numpy.linalg import linalg +from typing_extensions import Any, List, Tuple, Union import math from copy import deepcopy -from typing import Any, List, Tuple, Union class Molecule: diff --git a/diceplayer/shared/environment/system.py b/diceplayer/shared/environment/system.py index f8e5dd8..8610a00 100644 --- a/diceplayer/shared/environment/system.py +++ b/diceplayer/shared/environment/system.py @@ -5,10 +5,10 @@ from diceplayer.shared.utils.ptable import atomsymb import numpy as np from numpy import linalg +from typing_extensions import List, TextIO, Tuple import math from copy import deepcopy -from typing import List, TextIO, Tuple class System: diff --git a/diceplayer/shared/interface/dice_interface.py b/diceplayer/shared/interface/dice_interface.py index c13ef63..36c852f 100644 --- a/diceplayer/shared/interface/dice_interface.py +++ b/diceplayer/shared/interface/dice_interface.py @@ -6,6 +6,7 @@ from diceplayer.shared.environment.system import System from diceplayer.shared.interface import Interface from setproctitle import setproctitle +from typing_extensions import Final, TextIO import os import random @@ -15,7 +16,6 @@ import sys import time from multiprocessing import Process, connection from pathlib import Path -from typing import Final, TextIO DICE_END_FLAG: Final[str] = "End of simulation" DICE_FLAG_LINE: Final[int] = -2 diff --git a/diceplayer/shared/interface/gaussian_interface.py b/diceplayer/shared/interface/gaussian_interface.py index 73b372a..be203f7 100644 --- a/diceplayer/shared/interface/gaussian_interface.py +++ b/diceplayer/shared/interface/gaussian_interface.py @@ -11,13 +11,13 @@ from diceplayer.shared.utils.ptable import atomsymb import numpy as np from nptyping import NDArray +from typing_extensions import Any, Dict, List, Tuple import os import shutil import subprocess import textwrap from pathlib import Path -from typing import Any, Dict, List, Tuple class GaussianInterface(Interface): diff --git a/diceplayer/shared/utils/dataclass_protocol.py b/diceplayer/shared/utils/dataclass_protocol.py index 7d7c4da..967e7c1 100644 --- a/diceplayer/shared/utils/dataclass_protocol.py +++ b/diceplayer/shared/utils/dataclass_protocol.py @@ -1,4 +1,4 @@ -from typing import Protocol, runtime_checkable +from typing_extensions import Protocol, runtime_checkable @runtime_checkable diff --git a/diceplayer/shared/utils/misc.py b/diceplayer/shared/utils/misc.py index af2ac13..3884b52 100644 --- a/diceplayer/shared/utils/misc.py +++ b/diceplayer/shared/utils/misc.py @@ -1,9 +1,10 @@ +from typing_extensions import Final + import gzip import os import shutil import sys import time -from typing import Final ####################################### constants ###################################### diff --git a/poetry.lock b/poetry.lock index 44ca879..90734f3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -801,4 +801,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" python-versions = ">=3.9" -content-hash = "4a1819a86e32881c06191270ef503ebe87ef4ff519052fd8f0852510e31668e1" +content-hash = "5279a27d4c4f2d07ca08ba879729efb8e7259c64907bbac87e5f574818eb66e2" diff --git a/pyproject.toml b/pyproject.toml index c25892c..0c1c429 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ setproctitle = "^1.3.2" pyyaml = "^6.0" nptyping = "^2.5.0" pydantic = "^2.12.5" +typing-extensions = "^4.15.0" [tool.poetry.group.dev.dependencies] diff --git a/tests/mocks/mock_proc.py b/tests/mocks/mock_proc.py index 3c6310f..2dfa1d1 100644 --- a/tests/mocks/mock_proc.py +++ b/tests/mocks/mock_proc.py @@ -1,5 +1,6 @@ +from typing_extensions import List + import itertools -from typing import List class MockProc: