Compare commits
28 Commits
v0.1.0
...
2802f10013
| Author | SHA1 | Date | |
|---|---|---|---|
|
2802f10013
|
|||
|
7e66c98f26
|
|||
|
0470200d00
|
|||
|
0763c4a9e1
|
|||
|
30be88e6b4
|
|||
|
6a154429e9
|
|||
|
4c8cbc821d
|
|||
|
9f22304dd8
|
|||
|
53eb34a83e
|
|||
|
06ae9b41f0
|
|||
|
11ff4c0c21
|
|||
|
c59f0d6516
|
|||
| 53f75b44a5 | |||
|
34e8758ff8
|
|||
|
2765e5b86c
|
|||
|
636c65c07c
|
|||
|
a5504b0435
|
|||
|
d400970e8f
|
|||
| b6e57bc1c5 | |||
|
cb4b21ab6c
|
|||
| 250dd4acf4 | |||
|
5d76e49f89
|
|||
| d89124b1e8 | |||
|
f0e5bbeaee
|
|||
|
c51d07cff2
|
|||
|
e5c6282c86
|
|||
| f56d6b6b36 | |||
|
0699791091
|
68
.github/workflows/python-test-and-build.yml
vendored
68
.github/workflows/python-test-and-build.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
# This workflow will install Python dependencies, run tests and lint with a single version of Python
|
||||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
||||||
|
|
||||||
name: Upload DicePlayer to PyPI
|
name: build and upload
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push
|
push
|
||||||
@@ -13,24 +13,35 @@ jobs:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version:
|
||||||
|
- "3.10"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Install poetry
|
|
||||||
run: pipx install poetry
|
|
||||||
|
|
||||||
- name: Set up Python 3.10
|
- name: Set up Python 3.10
|
||||||
uses: actions/setup-python@v3
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
- name: Install uv
|
||||||
poetry self add "poetry-dynamic-versioning[plugin]"
|
uses: astral-sh/setup-uv@v5
|
||||||
if [ -f pyproject.toml ]; then poetry install; fi
|
with:
|
||||||
- name: Run unittest
|
# Install a specific version of uv.
|
||||||
run: |
|
version: "0.9.15"
|
||||||
poetry run python -m unittest
|
enable-cache: true
|
||||||
|
cache-dependency-glob: "uv.lock"
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: uv sync --all-extras --dev
|
||||||
|
|
||||||
|
- name: Run unittest
|
||||||
|
run: |
|
||||||
|
uv run python -m unittest
|
||||||
|
|
||||||
pypi-upload:
|
pypi-upload:
|
||||||
needs: [test]
|
needs: [test]
|
||||||
@@ -40,26 +51,27 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Install poetry
|
|
||||||
run: pipx install poetry
|
|
||||||
|
|
||||||
- name: Set up Python 3.10
|
- name: Set up Python 3.10
|
||||||
uses: actions/setup-python@v3
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
- name: Install uv
|
||||||
poetry self add "poetry-dynamic-versioning[plugin]"
|
uses: astral-sh/setup-uv@v5
|
||||||
if [ -f pyproject.toml ]; then poetry install; fi
|
with:
|
||||||
- name: Build Python Package
|
# Install a specific version of uv.
|
||||||
run: |
|
version: "0.9.15"
|
||||||
poetry build -f sdist
|
enable-cache: true
|
||||||
poetry install
|
cache-dependency-glob: "uv.lock"
|
||||||
echo "Builded DicePlayer - $(poetry version)"
|
python-version: ${{ matrix.python-version }}
|
||||||
- name: Configure PyPI
|
|
||||||
run: |
|
- name: Install dependencies
|
||||||
poetry config repositories.pypi https://upload.pypi.org/legacy/
|
run: uv sync
|
||||||
poetry config pypi-token.pypi ${{secrets.PYPI_TOKEN}}
|
|
||||||
- name: Upload Python Package
|
- name: Build source distribution
|
||||||
run: |
|
run: uv build --sdist
|
||||||
poetry publish --repository pypi
|
|
||||||
|
- name: Upload Python Package
|
||||||
|
run: |
|
||||||
|
uv publish -t ${{ secrets.PYPI_TOKEN }}
|
||||||
184
.gitignore
vendored
184
.gitignore
vendored
@@ -1,20 +1,184 @@
|
|||||||
### Python ###
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
.vscode/settings.json
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# UV
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
#uv.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||||
|
.pdm.toml
|
||||||
|
.pdm-python
|
||||||
|
.pdm-build/
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
# Ruff stuff:
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode
|
||||||
|
|
||||||
*.ljc
|
*.ljc
|
||||||
*.log
|
|
||||||
*.log.backup
|
*.log.backup
|
||||||
|
|
||||||
simfiles/*
|
simfiles/*
|
||||||
|
|
||||||
.vscode/*
|
|
||||||
.idea/*
|
|
||||||
*.pkl
|
*.pkl
|
||||||
|
|
||||||
*.xyz
|
*.xyz
|
||||||
|
|
||||||
dist/
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: 24.4.2
|
# Ruff version.
|
||||||
hooks:
|
rev: v0.14.7
|
||||||
- id: black
|
hooks:
|
||||||
args: [--config=pyproject.toml]
|
# Run the linter.
|
||||||
|
- id: ruff
|
||||||
- repo: https://github.com/pycqa/isort
|
# Run the formatter.
|
||||||
rev: 5.13.2
|
- id: ruff-format
|
||||||
hooks:
|
|
||||||
- id: isort
|
|
||||||
files: "\\.(py)$"
|
|
||||||
args: [--settings-path=pyproject.toml]
|
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
@@ -1,23 +1,26 @@
|
|||||||
diceplayer:
|
diceplayer:
|
||||||
opt: no
|
type: both
|
||||||
|
switch_cyc: 3
|
||||||
|
max_cyc: 5
|
||||||
mem: 24
|
mem: 24
|
||||||
maxcyc: 5
|
ncores: 20
|
||||||
ncores: 5
|
|
||||||
nprocs: 4
|
|
||||||
qmprog: 'g16'
|
qmprog: 'g16'
|
||||||
lps: no
|
lps: no
|
||||||
ghosts: no
|
ghosts: no
|
||||||
altsteps: 2000
|
altsteps: 2000
|
||||||
|
|
||||||
dice:
|
dice:
|
||||||
nmol: [1, 100]
|
nprocs: 1
|
||||||
|
nmol: [1, 200]
|
||||||
dens: 1.5
|
dens: 1.5
|
||||||
nstep: [2000, 3000]
|
nstep: [200, 200]
|
||||||
isave: 1000
|
vstep: 1000
|
||||||
|
isave: 30
|
||||||
outname: 'phb'
|
outname: 'phb'
|
||||||
progname: '~/.local/bin/dice'
|
progname: '/home/hideyoshi/.local/bin/dice'
|
||||||
ljname: 'phb.ljc'
|
ljname: 'phb.ljc.example'
|
||||||
randominit: 'always'
|
randominit: 'always'
|
||||||
|
seed: 12345
|
||||||
|
|
||||||
gaussian:
|
gaussian:
|
||||||
qmprog: 'g16'
|
qmprog: 'g16'
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
from diceplayer.shared.utils.logger import Logger
|
|
||||||
|
|
||||||
from importlib import metadata
|
|
||||||
|
|
||||||
VERSION = metadata.version("diceplayer")
|
|
||||||
|
|
||||||
logger = Logger(__name__)
|
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
from diceplayer import VERSION, logger
|
from diceplayer.cli import ArgsModel, read_input
|
||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
from diceplayer.logger import logger
|
||||||
from diceplayer.player import Player
|
from diceplayer.player import Player
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
from importlib import metadata
|
||||||
|
|
||||||
|
|
||||||
|
VERSION = metadata.version("diceplayer")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
|
||||||
Read and store the arguments passed to the program
|
|
||||||
and set the usage and help messages
|
|
||||||
"""
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(prog="Diceplayer")
|
parser = argparse.ArgumentParser(prog="Diceplayer")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-c", "--continue", dest="opt_continue", default=False, action="store_true"
|
"-v", "--version", action="version", version="diceplayer-" + VERSION
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v", "--version", action="version", version="diceplayer-" + VERSION
|
"-c", "--continue", dest="continuation", default=False, action="store_true"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-i",
|
"-i",
|
||||||
@@ -34,36 +34,26 @@ def main():
|
|||||||
metavar="OUTFILE",
|
metavar="OUTFILE",
|
||||||
help="output file of diceplayer [default = run.log]",
|
help="output file of diceplayer [default = run.log]",
|
||||||
)
|
)
|
||||||
args = parser.parse_args()
|
parser.add_argument(
|
||||||
|
"-f",
|
||||||
|
"--force",
|
||||||
|
dest="force",
|
||||||
|
default=False,
|
||||||
|
action="store_true",
|
||||||
|
help="force overwrite existing state file if it exists [default = False]",
|
||||||
|
)
|
||||||
|
args = ArgsModel.from_args(parser.parse_args())
|
||||||
|
|
||||||
# Open OUTFILE for writing and print keywords and initial info
|
logger.set_output_file(args.outfile)
|
||||||
logger.set_logger(args.outfile, logging.INFO)
|
|
||||||
|
|
||||||
if args.opt_continue:
|
config: PlayerConfig
|
||||||
player = Player.from_save()
|
try:
|
||||||
else:
|
config = read_input(args.infile)
|
||||||
player = Player.from_file(args.infile)
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to read input file: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
player.read_potentials()
|
Player(config).play(continuation=args.continuation, force=args.force)
|
||||||
|
|
||||||
player.create_simulation_dir()
|
|
||||||
player.create_geoms_file()
|
|
||||||
|
|
||||||
player.print_keywords()
|
|
||||||
|
|
||||||
player.print_potentials()
|
|
||||||
|
|
||||||
player.prepare_system()
|
|
||||||
|
|
||||||
player.start()
|
|
||||||
|
|
||||||
logger.info("\n+" + 88 * "-" + "+\n")
|
|
||||||
|
|
||||||
player.print_results()
|
|
||||||
|
|
||||||
logger.info("\n+" + 88 * "-" + "+\n")
|
|
||||||
|
|
||||||
logger.info("Diceplayer finished successfully \n")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
5
diceplayer/cli/__init__.py
Normal file
5
diceplayer/cli/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from .args_model import ArgsModel
|
||||||
|
from .read_input_file import read_input
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["ArgsModel", "read_input"]
|
||||||
12
diceplayer/cli/args_model.py
Normal file
12
diceplayer/cli/args_model.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class ArgsModel(BaseModel):
|
||||||
|
outfile: str
|
||||||
|
infile: str
|
||||||
|
continuation: bool
|
||||||
|
force: bool
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_args(cls, args):
|
||||||
|
return cls(**vars(args))
|
||||||
9
diceplayer/cli/read_input_file.py
Normal file
9
diceplayer/cli/read_input_file.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
def read_input(infile) -> PlayerConfig:
|
||||||
|
with open(infile, "r") as f:
|
||||||
|
values = yaml.safe_load(f)
|
||||||
|
return PlayerConfig.model_validate(values["diceplayer"])
|
||||||
10
diceplayer/config/__init__.py
Normal file
10
diceplayer/config/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from .dice_config import DiceConfig
|
||||||
|
from .gaussian_config import GaussianConfig
|
||||||
|
from .player_config import PlayerConfig
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"DiceConfig",
|
||||||
|
"GaussianConfig",
|
||||||
|
"PlayerConfig",
|
||||||
|
]
|
||||||
60
diceplayer/config/dice_config.py
Normal file
60
diceplayer/config/dice_config.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
from typing_extensions import Literal
|
||||||
|
|
||||||
|
import random
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class DiceConfig(BaseModel):
|
||||||
|
"""
|
||||||
|
Data Transfer Object for the Dice configuration.
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
nprocs: int = Field(
|
||||||
|
..., description="Number of processes to use for the DICE simulations"
|
||||||
|
)
|
||||||
|
|
||||||
|
ljname: Path = 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"
|
||||||
|
)
|
||||||
|
irdf: int = Field(
|
||||||
|
0,
|
||||||
|
description="Controls the interval of Monte Carlo steps at which configurations are used at computation of radial distribution functions",
|
||||||
|
)
|
||||||
|
vstep: int = Field(
|
||||||
|
5000, description="Frequency of volume change moves in NPT simulations"
|
||||||
|
)
|
||||||
|
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 = Field(
|
||||||
|
default_factory=lambda: int(1e6 * random.random()),
|
||||||
|
description="Seed for the random number generator",
|
||||||
|
)
|
||||||
29
diceplayer/config/gaussian_config.py
Normal file
29
diceplayer/config/gaussian_config.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
from typing_extensions import Literal
|
||||||
|
|
||||||
|
|
||||||
|
class GaussianConfig(BaseModel):
|
||||||
|
"""
|
||||||
|
Data Transfer Object for the Gaussian configuration.
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
qmprog: Literal["g03", "g09", "g16"] = Field(
|
||||||
|
"g16", description="QM program to use for the calculations"
|
||||||
|
)
|
||||||
|
level: str = Field(..., description="Level of theory 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 | None = Field(
|
||||||
|
None, description="Additional keywords for the QM calculations"
|
||||||
|
)
|
||||||
90
diceplayer/config/player_config.py
Normal file
90
diceplayer/config/player_config.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
from diceplayer.config.dice_config import DiceConfig
|
||||||
|
from diceplayer.config.gaussian_config import GaussianConfig
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||||
|
from typing_extensions import Any
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
MIN_STEP = 20000
|
||||||
|
STEP_INCREMENT = 1000
|
||||||
|
|
||||||
|
|
||||||
|
class RoutineType(str, Enum):
|
||||||
|
CHARGE = "charge"
|
||||||
|
GEOMETRY = "geometry"
|
||||||
|
BOTH = "both"
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerConfig(BaseModel):
|
||||||
|
"""
|
||||||
|
Configuration for DICEPlayer simulations.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
type: Type of simulation to perform (charge, geometry, or both).
|
||||||
|
max_cyc: Maximum number of cycles for the geometry optimization.
|
||||||
|
switch_cyc: Cycle at which to switch from charge to geometry optimization (if type is "both").
|
||||||
|
mem: Memory configuration for QM calculations.
|
||||||
|
nprocs: Number of processors to use for QM calculations.
|
||||||
|
ncores: Number of cores to use for QM calculations.
|
||||||
|
dice: Configuration parameters specific to DICE simulations.
|
||||||
|
gaussian: Configuration parameters specific to Gaussian calculations.
|
||||||
|
altsteps: Number of steps for the alternate simulation (default: 20000).
|
||||||
|
geoms_file: File name for the geometries output (default: "geoms.xyz").
|
||||||
|
simulation_dir: Directory name for the simulation files (default: "simfiles").
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(
|
||||||
|
frozen=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
type: RoutineType = Field(..., description="Type of simulation to perform")
|
||||||
|
max_cyc: int = Field(
|
||||||
|
..., description="Maximum number of cycles for the geometry optimization", gt=0
|
||||||
|
)
|
||||||
|
switch_cyc: int = Field(..., description="Switch cycle configuration")
|
||||||
|
|
||||||
|
mem: int = Field(None, description="Memory configuration")
|
||||||
|
ncores: int = Field(
|
||||||
|
..., description="Number of cores to use for the QM calculations"
|
||||||
|
)
|
||||||
|
|
||||||
|
dice: DiceConfig = Field(..., description="Dice configuration")
|
||||||
|
gaussian: GaussianConfig = Field(..., description="Gaussian configuration")
|
||||||
|
|
||||||
|
altsteps: int = Field(
|
||||||
|
20000, description="Number of steps for the alternate simulation"
|
||||||
|
)
|
||||||
|
geoms_file: Path = Field(
|
||||||
|
Path("geoms.xyz"), description="File name for the geometries output"
|
||||||
|
)
|
||||||
|
simulation_dir: Path = Field(
|
||||||
|
Path("simfiles"), description="Directory name for the simulation files"
|
||||||
|
)
|
||||||
|
|
||||||
|
@model_validator(mode="before")
|
||||||
|
@staticmethod
|
||||||
|
def validate_altsteps(fields) -> dict[str, Any]:
|
||||||
|
altsteps = fields.pop("altsteps", MIN_STEP)
|
||||||
|
fields["altsteps"] = (
|
||||||
|
round(max(MIN_STEP, altsteps) / STEP_INCREMENT) * STEP_INCREMENT
|
||||||
|
)
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@model_validator(mode="before")
|
||||||
|
@staticmethod
|
||||||
|
def validate_switch_cyc(fields: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
max_cyc = int(fields.get("max_cyc", 0))
|
||||||
|
switch_cyc = int(fields.get("switch_cyc", max_cyc))
|
||||||
|
|
||||||
|
if fields.get("type") == "both" and not switch_cyc < max_cyc:
|
||||||
|
raise ValueError("switch_cyc must be less than max_cyc when type='both'.")
|
||||||
|
|
||||||
|
if fields.get("type") != "both" and switch_cyc != max_cyc:
|
||||||
|
raise ValueError(
|
||||||
|
"switch_cyc must be equal to max_cyc when type is not 'both'."
|
||||||
|
)
|
||||||
|
|
||||||
|
return fields
|
||||||
174
diceplayer/dice/__init__.py
Normal file
174
diceplayer/dice/__init__.py
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
"""
|
||||||
|
DICE Monte Carlo Simulation Interface
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
This package provides utilities for configuring and running simulations with
|
||||||
|
the DICE Monte Carlo molecular simulation program.
|
||||||
|
|
||||||
|
DICE performs statistical sampling of molecular systems using the Metropolis
|
||||||
|
Monte Carlo algorithm. Simulations are defined by text input files containing
|
||||||
|
keywords that control the thermodynamic ensemble, system composition, and
|
||||||
|
simulation parameters.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Simulation Ensembles
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
DICE supports multiple statistical ensembles.
|
||||||
|
|
||||||
|
NVT
|
||||||
|
Canonical ensemble where the following properties remain constant:
|
||||||
|
|
||||||
|
- N: number of molecules
|
||||||
|
- V: system volume
|
||||||
|
- T: temperature
|
||||||
|
|
||||||
|
The system density is fixed and the simulation box volume does not change
|
||||||
|
during the simulation.
|
||||||
|
|
||||||
|
NPT
|
||||||
|
Isothermal–isobaric ensemble where the following properties remain constant:
|
||||||
|
|
||||||
|
- N: number of molecules
|
||||||
|
- P: pressure
|
||||||
|
- T: temperature
|
||||||
|
|
||||||
|
The simulation box volume is allowed to fluctuate in order to maintain the
|
||||||
|
target pressure.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Simulation Stages
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Simulations are typically executed in multiple stages.
|
||||||
|
|
||||||
|
Thermalization (TER)
|
||||||
|
Initial phase where the system relaxes to the desired thermodynamic
|
||||||
|
conditions. Molecular configurations stabilize and the system reaches
|
||||||
|
equilibrium.
|
||||||
|
|
||||||
|
During this stage statistical properties are **not accumulated**.
|
||||||
|
|
||||||
|
Production / Equilibration (EQ)
|
||||||
|
Main sampling phase after the system has equilibrated.
|
||||||
|
|
||||||
|
Statistical properties such as energies, densities, and radial
|
||||||
|
distribution functions are collected and configurations may be saved
|
||||||
|
for later analysis.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Typical Simulation Pipeline
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Two common execution workflows are used.
|
||||||
|
|
||||||
|
NVT Simulation
|
||||||
|
Used when the system density is known.
|
||||||
|
|
||||||
|
1. NVT.ter → thermalization at constant density
|
||||||
|
2. NVT.eq → production sampling
|
||||||
|
|
||||||
|
NPT Simulation
|
||||||
|
Used when the equilibrium density is unknown.
|
||||||
|
|
||||||
|
1. NVT.ter → initial thermalization at approximate density
|
||||||
|
2. NPT.ter → pressure relaxation (volume adjustment)
|
||||||
|
3. NPT.eq → production sampling at target pressure
|
||||||
|
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
DICE Input Keywords
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The following keywords are used in the generated input files.
|
||||||
|
|
||||||
|
title
|
||||||
|
Descriptive title printed in the simulation output.
|
||||||
|
|
||||||
|
ncores
|
||||||
|
Number of CPU cores used by the DICE executable.
|
||||||
|
|
||||||
|
ljname
|
||||||
|
File containing Lennard-Jones parameters and molecular topology.
|
||||||
|
|
||||||
|
outname
|
||||||
|
Prefix used for simulation output files.
|
||||||
|
|
||||||
|
nmol
|
||||||
|
Number of molecules of each species in the system.
|
||||||
|
|
||||||
|
dens
|
||||||
|
System density (g/cm³). Used only in NVT simulations or for
|
||||||
|
initialization of NPT runs.
|
||||||
|
|
||||||
|
press
|
||||||
|
Target pressure used in NPT simulations.
|
||||||
|
|
||||||
|
temp
|
||||||
|
Simulation temperature.
|
||||||
|
|
||||||
|
nstep
|
||||||
|
Number of Monte Carlo cycles executed in the simulation stage.
|
||||||
|
|
||||||
|
init
|
||||||
|
Defines how the simulation initializes molecular coordinates.
|
||||||
|
|
||||||
|
yes
|
||||||
|
Random initial configuration.
|
||||||
|
|
||||||
|
no
|
||||||
|
Continue from a previous configuration.
|
||||||
|
|
||||||
|
yesreadxyz
|
||||||
|
Read coordinates from a previously saved XYZ configuration.
|
||||||
|
|
||||||
|
vstep
|
||||||
|
Frequency of volume-change moves in NPT simulations.
|
||||||
|
|
||||||
|
mstop
|
||||||
|
Molecule displacement control flag used internally by DICE.
|
||||||
|
|
||||||
|
accum
|
||||||
|
Enables or disables accumulation of statistical averages.
|
||||||
|
|
||||||
|
iprint
|
||||||
|
Frequency of simulation information printed to the output.
|
||||||
|
|
||||||
|
isave
|
||||||
|
Frequency at which configurations are written to trajectory files.
|
||||||
|
|
||||||
|
irdf
|
||||||
|
Controls calculation of radial distribution functions.
|
||||||
|
|
||||||
|
seed
|
||||||
|
Random number generator seed used by the Monte Carlo algorithm.
|
||||||
|
|
||||||
|
upbuf
|
||||||
|
Buffer size parameter used internally by DICE during thermalization.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Output Files
|
||||||
|
------------
|
||||||
|
|
||||||
|
Important output files produced during the simulation include:
|
||||||
|
|
||||||
|
phb.xyz
|
||||||
|
XYZ trajectory containing sampled molecular configurations.
|
||||||
|
|
||||||
|
last.xyz
|
||||||
|
Final configuration of the simulation, often used as the starting
|
||||||
|
configuration for the next simulation cycle.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
|
||||||
|
DICE is a Monte Carlo molecular simulation program developed primarily
|
||||||
|
by researchers at the University of São Paulo (USP) for studying liquids,
|
||||||
|
solutions, and solvation phenomena.
|
||||||
|
"""
|
||||||
186
diceplayer/dice/dice_handler.py
Normal file
186
diceplayer/dice/dice_handler.py
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
import warnings
|
||||||
|
|
||||||
|
from diceplayer.dice.dice_input import (
|
||||||
|
NPTEqConfig,
|
||||||
|
NPTTerConfig,
|
||||||
|
NVTEqConfig,
|
||||||
|
NVTTerConfig,
|
||||||
|
)
|
||||||
|
from diceplayer.dice.dice_wrapper import (
|
||||||
|
DiceEnvironment,
|
||||||
|
DiceWrapper,
|
||||||
|
)
|
||||||
|
from diceplayer.environment import Atom, Molecule
|
||||||
|
from diceplayer.logger import logger
|
||||||
|
from diceplayer.state.state_model import StateModel
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
from itertools import batched, chain, islice
|
||||||
|
from pathlib import Path
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
|
||||||
|
class DiceHandler:
|
||||||
|
def __init__(self, step_directory: Path):
|
||||||
|
self.dice_directory = step_directory / "dice"
|
||||||
|
|
||||||
|
def run(self, state: StateModel, cycle: int) -> list[Atom]:
|
||||||
|
if self.dice_directory.exists():
|
||||||
|
logger.info(
|
||||||
|
f"Found dice directory: {self.dice_directory}, this directory will be purged for a clean state"
|
||||||
|
)
|
||||||
|
shutil.rmtree(self.dice_directory)
|
||||||
|
self.dice_directory.mkdir(parents=True)
|
||||||
|
|
||||||
|
return self.run_simulations(state, cycle)
|
||||||
|
|
||||||
|
def run_simulations(self, state: StateModel, cycle: int) -> list[Atom]:
|
||||||
|
results: list[list[Atom]] = []
|
||||||
|
|
||||||
|
threads = []
|
||||||
|
for p in range(state.config.dice.nprocs):
|
||||||
|
t = Thread(target=self._simulation_process, args=(state, cycle, p, results))
|
||||||
|
threads.append(t)
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
for t in threads:
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
if len(results) != state.config.dice.nprocs:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Expected {state.config.dice.nprocs} simulation results, but got {len(results)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return self._aggregate_results(state, results)
|
||||||
|
|
||||||
|
def _simulation_process(
|
||||||
|
self,
|
||||||
|
state: StateModel,
|
||||||
|
cycle: int,
|
||||||
|
proc: int,
|
||||||
|
results: list[list[Atom]],
|
||||||
|
) -> None:
|
||||||
|
proc_directory = self.dice_directory / f"{proc:02d}"
|
||||||
|
if proc_directory.exists():
|
||||||
|
shutil.rmtree(proc_directory)
|
||||||
|
proc_directory.mkdir(parents=True)
|
||||||
|
|
||||||
|
dice = DiceWrapper(state.config.dice, proc_directory)
|
||||||
|
|
||||||
|
self._generate_phb_file(state, proc_directory)
|
||||||
|
|
||||||
|
if state.config.dice.randominit == "first" and cycle >= 0:
|
||||||
|
self._generate_last_xyz(state, proc_directory)
|
||||||
|
else:
|
||||||
|
nvt_ter_config = NVTTerConfig.from_config(state.config)
|
||||||
|
dice.run(nvt_ter_config)
|
||||||
|
|
||||||
|
if len(state.config.dice.nstep) == 2:
|
||||||
|
nvt_eq_config = NVTEqConfig.from_config(state.config)
|
||||||
|
dice.run(nvt_eq_config)
|
||||||
|
|
||||||
|
elif len(state.config.dice.nstep) == 3:
|
||||||
|
npt_ter_config = NPTTerConfig.from_config(state.config)
|
||||||
|
dice.run(npt_ter_config)
|
||||||
|
|
||||||
|
npt_eq_config = NPTEqConfig.from_config(state.config)
|
||||||
|
dice.run(npt_eq_config)
|
||||||
|
|
||||||
|
results.extend(
|
||||||
|
[
|
||||||
|
self._filter_environment_sites(state, environment)
|
||||||
|
for environment in dice.parse_results()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _generate_phb_file(state: StateModel, proc_directory: Path) -> None:
|
||||||
|
fstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f}\n"
|
||||||
|
|
||||||
|
phb_file = proc_directory / state.config.dice.ljname
|
||||||
|
|
||||||
|
with open(phb_file, "w") as f:
|
||||||
|
f.write(f"{state.config.dice.combrule}\n")
|
||||||
|
f.write(f"{len(state.config.dice.nmol)}\n")
|
||||||
|
|
||||||
|
for molecule in state.system.molecule:
|
||||||
|
f.write(f"{len(molecule.atom)} {molecule.molname}\n")
|
||||||
|
for atom in molecule.atom:
|
||||||
|
f.write(
|
||||||
|
fstr.format(
|
||||||
|
atom.lbl,
|
||||||
|
atom.na,
|
||||||
|
atom.rx,
|
||||||
|
atom.ry,
|
||||||
|
atom.rz,
|
||||||
|
atom.chg,
|
||||||
|
atom.eps,
|
||||||
|
atom.sig,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _generate_last_xyz(self, state: StateModel, proc_directory: Path) -> None: ...
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _filter_environment_sites(
|
||||||
|
state: StateModel, environment: DiceEnvironment
|
||||||
|
) -> list[Atom]:
|
||||||
|
picked_environment = []
|
||||||
|
|
||||||
|
ref_molecule = state.system.molecule[0]
|
||||||
|
ref_molecule_sizes = ref_molecule.sizes_of_molecule()
|
||||||
|
ref_n_sites = len(ref_molecule.atom) * state.config.dice.nmol[0]
|
||||||
|
|
||||||
|
min_distance = min(
|
||||||
|
(environment.thickness[i] - ref_molecule_sizes[i]) / 2 for i in range(3)
|
||||||
|
)
|
||||||
|
|
||||||
|
site_iter = iter(environment.items)
|
||||||
|
_ = list(islice(site_iter, ref_n_sites))
|
||||||
|
|
||||||
|
for molecule_index, molecule in enumerate(state.system.molecule[1:], start=1):
|
||||||
|
molecule_n_atoms = len(molecule.atom)
|
||||||
|
molecule_n_sites = molecule_n_atoms * state.config.dice.nmol[molecule_index]
|
||||||
|
|
||||||
|
sites = list(islice(site_iter, molecule_n_sites))
|
||||||
|
|
||||||
|
for molecule_sites in batched(sites, molecule_n_atoms):
|
||||||
|
new_molecule = Molecule("ASEC TMP MOLECULE")
|
||||||
|
|
||||||
|
for site_index, atom_site in enumerate(molecule_sites):
|
||||||
|
new_molecule.add_atom(
|
||||||
|
Atom(
|
||||||
|
molecule.atom[site_index].lbl,
|
||||||
|
molecule.atom[site_index].na,
|
||||||
|
atom_site.x,
|
||||||
|
atom_site.y,
|
||||||
|
atom_site.z,
|
||||||
|
molecule.atom[site_index].chg,
|
||||||
|
molecule.atom[site_index].eps,
|
||||||
|
molecule.atom[site_index].sig,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if molecule.signature() != new_molecule.signature():
|
||||||
|
_message = f"Skipping sites because the molecule signature does not match the reference molecule. Expected {molecule.signature()} but got {new_molecule.signature()}"
|
||||||
|
warnings.warn(_message)
|
||||||
|
logger.warning(_message)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ref_molecule.minimum_distance(new_molecule) >= min_distance:
|
||||||
|
continue
|
||||||
|
|
||||||
|
picked_environment.extend(new_molecule.atom)
|
||||||
|
|
||||||
|
return picked_environment
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _aggregate_results(state: StateModel, results: list[list[Atom]]) -> list[Atom]:
|
||||||
|
norm_factor = round(state.config.dice.nstep[-1] / state.config.dice.isave)
|
||||||
|
|
||||||
|
agg_results = []
|
||||||
|
for atom in chain(*[r for r in results]):
|
||||||
|
atom.chg = atom.chg * norm_factor
|
||||||
|
agg_results.append(atom)
|
||||||
|
|
||||||
|
return agg_results
|
||||||
257
diceplayer/dice/dice_input.py
Normal file
257
diceplayer/dice/dice_input.py
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
from diceplayer.logger import logger
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
import random
|
||||||
|
from enum import StrEnum
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Annotated, Any, Literal, TextIO
|
||||||
|
|
||||||
|
|
||||||
|
_ALLOWED_DICE_KEYWORD_IN_ORDER = [
|
||||||
|
"title",
|
||||||
|
"ncores",
|
||||||
|
"ljname",
|
||||||
|
"outname",
|
||||||
|
"nmol",
|
||||||
|
"dens",
|
||||||
|
"temp",
|
||||||
|
"press",
|
||||||
|
"seed",
|
||||||
|
"init",
|
||||||
|
"nstep",
|
||||||
|
"vstep",
|
||||||
|
"mstop",
|
||||||
|
"accum",
|
||||||
|
"iprint",
|
||||||
|
"isave",
|
||||||
|
"irdf",
|
||||||
|
"upbuf",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class DiceRoutineType(StrEnum):
|
||||||
|
NVT_TER = "nvt.ter"
|
||||||
|
NVT_EQ = "nvt.eq"
|
||||||
|
NPT_TER = "npt.ter"
|
||||||
|
NPT_EQ = "npt.eq"
|
||||||
|
|
||||||
|
|
||||||
|
def get_nstep(config, idx: int) -> int:
|
||||||
|
if len(config.dice.nstep) > idx:
|
||||||
|
return config.dice.nstep[idx]
|
||||||
|
return config.dice.nstep[-1]
|
||||||
|
|
||||||
|
|
||||||
|
def get_seed(config) -> int:
|
||||||
|
return config.dice.seed or random.randint(0, 2**32 - 1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_ncores(config) -> int:
|
||||||
|
return max(1, int(config.ncores / config.dice.nprocs))
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# NVT THERMALIZATION
|
||||||
|
# -----------------------------------------------------
|
||||||
|
class NVTTerConfig(BaseModel):
|
||||||
|
type: Literal[DiceRoutineType.NVT_TER] = DiceRoutineType.NVT_TER
|
||||||
|
|
||||||
|
title: str = "NVT Thermalization"
|
||||||
|
ncores: int
|
||||||
|
ljname: str
|
||||||
|
outname: str
|
||||||
|
nmol: list[int]
|
||||||
|
dens: float
|
||||||
|
temp: float
|
||||||
|
seed: int
|
||||||
|
init: Literal["yes"] = "yes"
|
||||||
|
nstep: int
|
||||||
|
vstep: Literal[0] = 0
|
||||||
|
isave: int
|
||||||
|
upbuf: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
|
||||||
|
return cls(
|
||||||
|
ncores=get_ncores(config),
|
||||||
|
ljname=str(config.dice.ljname),
|
||||||
|
outname=config.dice.outname,
|
||||||
|
nmol=config.dice.nmol,
|
||||||
|
dens=config.dice.dens,
|
||||||
|
temp=config.dice.temp,
|
||||||
|
seed=get_seed(config),
|
||||||
|
nstep=get_nstep(config, 0),
|
||||||
|
isave=config.dice.isave,
|
||||||
|
upbuf=config.dice.upbuf,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# NVT PRODUCTION
|
||||||
|
# -----------------------------------------------------
|
||||||
|
class NVTEqConfig(BaseModel):
|
||||||
|
type: Literal[DiceRoutineType.NVT_EQ] = DiceRoutineType.NVT_EQ
|
||||||
|
|
||||||
|
title: str = "NVT Production"
|
||||||
|
ncores: int
|
||||||
|
ljname: str
|
||||||
|
outname: str
|
||||||
|
nmol: list[int]
|
||||||
|
dens: float
|
||||||
|
temp: float
|
||||||
|
seed: int
|
||||||
|
init: Literal["no", "yesreadxyz"] = "no"
|
||||||
|
nstep: int
|
||||||
|
vstep: int
|
||||||
|
isave: int
|
||||||
|
irdf: Literal[0] = 0
|
||||||
|
upbuf: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
|
||||||
|
return cls(
|
||||||
|
ncores=get_ncores(config),
|
||||||
|
ljname=str(config.dice.ljname),
|
||||||
|
outname=config.dice.outname,
|
||||||
|
nmol=config.dice.nmol,
|
||||||
|
dens=config.dice.dens,
|
||||||
|
temp=config.dice.temp,
|
||||||
|
seed=get_seed(config),
|
||||||
|
nstep=get_nstep(config, 1),
|
||||||
|
vstep=config.dice.vstep,
|
||||||
|
isave=max(1, get_nstep(config, 1) // 10),
|
||||||
|
upbuf=config.dice.upbuf,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# NPT THERMALIZATION
|
||||||
|
# -----------------------------------------------------
|
||||||
|
class NPTTerConfig(BaseModel):
|
||||||
|
type: Literal[DiceRoutineType.NPT_TER] = DiceRoutineType.NPT_TER
|
||||||
|
|
||||||
|
title: str = "NPT Thermalization"
|
||||||
|
ncores: int
|
||||||
|
ljname: str
|
||||||
|
outname: str
|
||||||
|
nmol: list[int]
|
||||||
|
dens: float
|
||||||
|
temp: float
|
||||||
|
press: float
|
||||||
|
seed: int
|
||||||
|
init: Literal["yes", "yesreadxyz"] = "yes"
|
||||||
|
nstep: int
|
||||||
|
vstep: int
|
||||||
|
isave: int
|
||||||
|
upbuf: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
|
||||||
|
return cls(
|
||||||
|
ncores=get_ncores(config),
|
||||||
|
ljname=str(config.dice.ljname),
|
||||||
|
outname=config.dice.outname,
|
||||||
|
nmol=config.dice.nmol,
|
||||||
|
dens=config.dice.dens,
|
||||||
|
temp=config.dice.temp,
|
||||||
|
press=config.dice.press,
|
||||||
|
seed=get_seed(config),
|
||||||
|
nstep=get_nstep(config, 1),
|
||||||
|
vstep=max(1, config.dice.vstep),
|
||||||
|
isave=config.dice.isave,
|
||||||
|
upbuf=config.dice.upbuf,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# NPT PRODUCTION
|
||||||
|
# -----------------------------------------------------
|
||||||
|
class NPTEqConfig(BaseModel):
|
||||||
|
type: Literal[DiceRoutineType.NPT_EQ] = DiceRoutineType.NPT_EQ
|
||||||
|
|
||||||
|
title: str = "NPT Production"
|
||||||
|
ncores: int
|
||||||
|
ljname: str
|
||||||
|
outname: str
|
||||||
|
nmol: list[int]
|
||||||
|
dens: float
|
||||||
|
temp: float
|
||||||
|
press: float
|
||||||
|
seed: int
|
||||||
|
init: Literal["yes", "yesreadxyz"] = "yes"
|
||||||
|
nstep: int
|
||||||
|
vstep: int
|
||||||
|
isave: int
|
||||||
|
irdf: Literal[0] = 0
|
||||||
|
upbuf: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
|
||||||
|
return cls(
|
||||||
|
ncores=get_ncores(config),
|
||||||
|
ljname=str(config.dice.ljname),
|
||||||
|
outname=config.dice.outname,
|
||||||
|
nmol=config.dice.nmol,
|
||||||
|
dens=config.dice.dens,
|
||||||
|
temp=config.dice.temp,
|
||||||
|
press=config.dice.press,
|
||||||
|
seed=get_seed(config),
|
||||||
|
nstep=get_nstep(config, 2),
|
||||||
|
vstep=config.dice.vstep,
|
||||||
|
isave=max(1, get_nstep(config, 2) // 10),
|
||||||
|
upbuf=config.dice.upbuf,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
DiceInputConfig = Annotated[
|
||||||
|
NVTTerConfig | NVTEqConfig | NPTTerConfig | NPTEqConfig,
|
||||||
|
Field(discriminator="type"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _serialize_value(value: Any) -> str:
|
||||||
|
if value is None:
|
||||||
|
raise ValueError("DICE configuration cannot serialize None values")
|
||||||
|
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return "yes" if value else "no"
|
||||||
|
|
||||||
|
if isinstance(value, (list, tuple)):
|
||||||
|
return " ".join(str(v) for v in value)
|
||||||
|
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def write_dice_config(obj: DiceInputConfig, io_writer: TextIO) -> None:
|
||||||
|
values = {f: getattr(obj, f) for f in obj.__class__.model_fields}
|
||||||
|
|
||||||
|
for key in _ALLOWED_DICE_KEYWORD_IN_ORDER:
|
||||||
|
value = values.pop(key, None)
|
||||||
|
if value is None:
|
||||||
|
continue
|
||||||
|
io_writer.write(f"{key} = {_serialize_value(value)}\n")
|
||||||
|
|
||||||
|
io_writer.write("$end\n")
|
||||||
|
|
||||||
|
|
||||||
|
def write_config(config: DiceInputConfig, directory: Path) -> Path:
|
||||||
|
input_path = directory / config.type
|
||||||
|
|
||||||
|
if input_path.exists():
|
||||||
|
logger.info(
|
||||||
|
f"Dice input file {input_path} already exists and will be overwritten"
|
||||||
|
)
|
||||||
|
input_path.unlink()
|
||||||
|
input_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(input_path, "w") as io:
|
||||||
|
write_dice_config(config, io)
|
||||||
|
|
||||||
|
return input_path
|
||||||
103
diceplayer/dice/dice_wrapper.py
Normal file
103
diceplayer/dice/dice_wrapper.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import diceplayer.dice.dice_input as dice_input
|
||||||
|
from diceplayer.config import DiceConfig
|
||||||
|
|
||||||
|
from pydantic import TypeAdapter
|
||||||
|
from pydantic.dataclasses import dataclass
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
from itertools import islice
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Final, List, Self
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True, frozen=True)
|
||||||
|
class DiceEnvironmentItem:
|
||||||
|
atom: str
|
||||||
|
x: float
|
||||||
|
y: float
|
||||||
|
z: float
|
||||||
|
|
||||||
|
|
||||||
|
DiceEnvironmentItemAdapter = TypeAdapter(DiceEnvironmentItem)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True)
|
||||||
|
class DiceEnvironment:
|
||||||
|
number_of_sites: int
|
||||||
|
thickness: List[float]
|
||||||
|
items: List[DiceEnvironmentItem]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def new(cls, thickness: List[float]) -> Self:
|
||||||
|
return cls(number_of_sites=0, thickness=thickness, items=[])
|
||||||
|
|
||||||
|
def add_site(self, site: DiceEnvironmentItem):
|
||||||
|
self.items.append(site)
|
||||||
|
self.number_of_sites += 1
|
||||||
|
|
||||||
|
|
||||||
|
DICE_FLAG_LINE: Final[int] = -2
|
||||||
|
DICE_END_FLAG: Final[str] = "End of simulation"
|
||||||
|
|
||||||
|
|
||||||
|
class DiceWrapper:
|
||||||
|
def __init__(self, dice_config: DiceConfig, working_directory: Path):
|
||||||
|
self.dice_config = dice_config
|
||||||
|
self.working_directory = working_directory
|
||||||
|
|
||||||
|
def run(self, dice_config: dice_input.DiceInputConfig) -> None:
|
||||||
|
input_path = dice_input.write_config(dice_config, self.working_directory)
|
||||||
|
output_path = input_path.parent / (input_path.name + ".out")
|
||||||
|
|
||||||
|
with open(output_path, "w") as outfile, open(input_path, "r") as infile:
|
||||||
|
exit_status = subprocess.call(
|
||||||
|
self.dice_config.progname,
|
||||||
|
stdin=infile,
|
||||||
|
stdout=outfile,
|
||||||
|
cwd=self.working_directory,
|
||||||
|
)
|
||||||
|
|
||||||
|
if exit_status != 0:
|
||||||
|
raise RuntimeError(f"Dice simulation failed with exit status {exit_status}")
|
||||||
|
|
||||||
|
with open(output_path, "r") as outfile:
|
||||||
|
line = outfile.readlines()[DICE_FLAG_LINE]
|
||||||
|
if line.strip() == DICE_END_FLAG:
|
||||||
|
return
|
||||||
|
|
||||||
|
raise RuntimeError(f"Dice simulation failed with exit status {exit_status}")
|
||||||
|
|
||||||
|
def parse_results(self) -> list[DiceEnvironment]:
|
||||||
|
results = []
|
||||||
|
|
||||||
|
positions_file = self.working_directory / "phb.xyz"
|
||||||
|
if not positions_file.exists():
|
||||||
|
raise RuntimeError(f"Positions file not found at {self.working_directory}")
|
||||||
|
|
||||||
|
with open(positions_file, "r") as f:
|
||||||
|
while True:
|
||||||
|
line = f.readline()
|
||||||
|
if not line.startswith(" "):
|
||||||
|
break
|
||||||
|
|
||||||
|
environment = DiceEnvironment(
|
||||||
|
number_of_sites=int(line.strip()),
|
||||||
|
thickness=[float(n) for n in f.readline().split()[-3:]],
|
||||||
|
items=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Skip the comment line
|
||||||
|
|
||||||
|
environment.items.extend(
|
||||||
|
[
|
||||||
|
DiceEnvironmentItemAdapter.validate_python(
|
||||||
|
{"atom": site[0], "x": site[1], "y": site[2], "z": site[3]}
|
||||||
|
)
|
||||||
|
for atom in islice(f, environment.number_of_sites)
|
||||||
|
if (site := atom.strip().split()) and len(site) == 4
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
results.append(environment)
|
||||||
|
|
||||||
|
return results
|
||||||
6
diceplayer/environment/__init__.py
Normal file
6
diceplayer/environment/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from .atom import Atom
|
||||||
|
from .molecule import Molecule
|
||||||
|
from .system import System
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["Atom", "Molecule", "System"]
|
||||||
27
diceplayer/environment/atom.py
Normal file
27
diceplayer/environment/atom.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
from diceplayer.utils.ptable import AtomInfo, PTable
|
||||||
|
|
||||||
|
from pydantic.dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True)
|
||||||
|
class Atom:
|
||||||
|
"""
|
||||||
|
Atom class declaration. This class is used throughout the DicePlayer program to represent atoms.
|
||||||
|
"""
|
||||||
|
|
||||||
|
lbl: int
|
||||||
|
na: int
|
||||||
|
rx: float
|
||||||
|
ry: float
|
||||||
|
rz: float
|
||||||
|
chg: float
|
||||||
|
eps: float
|
||||||
|
sig: float
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mass(self) -> float:
|
||||||
|
return PTable.get_atomic_mass(self.na)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def atom_info(self) -> AtomInfo:
|
||||||
|
return PTable.get_from_atomic_number(self.na)
|
||||||
320
diceplayer/environment/molecule.py
Normal file
320
diceplayer/environment/molecule.py
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from diceplayer.environment import Atom
|
||||||
|
from diceplayer.logger import logger
|
||||||
|
from diceplayer.utils.misc import BOHR2ANG, EA_2_DEBYE
|
||||||
|
from diceplayer.utils.ptable import GHOST_NUMBER
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import numpy.linalg as linalg
|
||||||
|
import numpy.typing as npt
|
||||||
|
from pydantic.dataclasses import dataclass
|
||||||
|
from typing_extensions import List, Self, Tuple
|
||||||
|
|
||||||
|
import math
|
||||||
|
from copy import deepcopy
|
||||||
|
from dataclasses import field
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Molecule:
|
||||||
|
"""
|
||||||
|
Molecule class declaration. This class is used throughout the DicePlayer program to represent molecules.
|
||||||
|
|
||||||
|
Atributes:
|
||||||
|
molname (str): The name of the represented molecule
|
||||||
|
atom (List[Atom]): List of atoms of the represented molecule
|
||||||
|
total_mass (int): The total mass of the molecule
|
||||||
|
com (npt.NDArray[np.float64]): The center of mass of the molecule
|
||||||
|
inertia_tensor (npt.NDArray[np.float64]): The inertia tensor of the molecule
|
||||||
|
"""
|
||||||
|
|
||||||
|
molname: str
|
||||||
|
atom: List[Atom] = field(default_factory=list)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total_mass(self) -> float:
|
||||||
|
return sum(atom.mass for atom in self.atom)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def com(self) -> npt.NDArray[np.float64]:
|
||||||
|
com = np.zeros(3)
|
||||||
|
|
||||||
|
for atom in self.atom:
|
||||||
|
com += atom.mass * np.array([atom.rx, atom.ry, atom.rz])
|
||||||
|
|
||||||
|
com = com / self.total_mass
|
||||||
|
|
||||||
|
return com
|
||||||
|
|
||||||
|
@property
|
||||||
|
def inertia_tensor(self) -> npt.NDArray[np.float64]:
|
||||||
|
"""
|
||||||
|
Calculates the inertia tensor of the molecule.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
npt.NDArray[np.float64]: inertia tensor of the molecule.
|
||||||
|
"""
|
||||||
|
inertia_tensor = np.zeros((3, 3), dtype=np.float64)
|
||||||
|
|
||||||
|
for atom in self.atom:
|
||||||
|
dx = atom.rx - self.com[0]
|
||||||
|
dy = atom.ry - self.com[1]
|
||||||
|
dz = atom.rz - self.com[2]
|
||||||
|
|
||||||
|
inertia_tensor[0, 0] += atom.mass * (dy**2 + dz**2)
|
||||||
|
inertia_tensor[1, 1] += atom.mass * (dz**2 + dx**2)
|
||||||
|
inertia_tensor[2, 2] += atom.mass * (dx**2 + dy**2)
|
||||||
|
|
||||||
|
inertia_tensor[0, 1] -= atom.mass * dx * dy
|
||||||
|
inertia_tensor[0, 2] -= atom.mass * dx * dz
|
||||||
|
inertia_tensor[1, 2] -= atom.mass * dy * dz
|
||||||
|
|
||||||
|
# enforce symmetry
|
||||||
|
inertia_tensor[1, 0] = inertia_tensor[0, 1]
|
||||||
|
inertia_tensor[2, 0] = inertia_tensor[0, 2]
|
||||||
|
inertia_tensor[2, 1] = inertia_tensor[1, 2]
|
||||||
|
|
||||||
|
return inertia_tensor
|
||||||
|
|
||||||
|
def add_atom(self, a: Atom) -> None:
|
||||||
|
"""
|
||||||
|
Adds Atom instance to the molecule.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
a (Atom): Atom instance to be added to atom list.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.atom.append(a)
|
||||||
|
|
||||||
|
def remove_atom(self, a: Atom) -> None:
|
||||||
|
"""
|
||||||
|
Removes Atom instance from the molecule.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
a (Atom): Atom instance to be removed from atom list.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.atom.remove(a)
|
||||||
|
|
||||||
|
def move_center_of_mass_to_origin(self) -> None:
|
||||||
|
"""
|
||||||
|
Updated positions based on the center of mass of the molecule
|
||||||
|
"""
|
||||||
|
for atom in self.atom:
|
||||||
|
atom.rx -= self.com[0]
|
||||||
|
atom.ry -= self.com[1]
|
||||||
|
atom.rz -= self.com[2]
|
||||||
|
|
||||||
|
def rotate_to_standard_orientation(self) -> None:
|
||||||
|
"""
|
||||||
|
Rotates the molecule to the standard orientation
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.move_center_of_mass_to_origin()
|
||||||
|
evals, evecs = self.principal_axes()
|
||||||
|
|
||||||
|
if np.isclose(linalg.det(evecs), -1):
|
||||||
|
evecs[:, 2] *= -1
|
||||||
|
|
||||||
|
if not np.isclose(linalg.det(evecs), 1):
|
||||||
|
raise RuntimeError(
|
||||||
|
"Error: could not make a rotation matrix while adopting the standard orientation"
|
||||||
|
)
|
||||||
|
|
||||||
|
coords = np.array([(a.rx, a.ry, a.rz) for a in self.atom])
|
||||||
|
rotated = coords @ evecs.T
|
||||||
|
|
||||||
|
for atom, pos in zip(self.atom, rotated):
|
||||||
|
atom.rx, atom.ry, atom.rz = pos
|
||||||
|
|
||||||
|
def charges_and_dipole(self) -> List[float]:
|
||||||
|
"""
|
||||||
|
Calculates the charges and dipole of the molecule atoms
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[float]: Respectivly magnitude of the: charge magnitude, first dipole,
|
||||||
|
second dipole, third dipole and total dipole.
|
||||||
|
"""
|
||||||
|
|
||||||
|
charge = 0
|
||||||
|
dipole = np.zeros(3)
|
||||||
|
for atom in self.atom:
|
||||||
|
position = np.array([atom.rx, atom.ry, atom.rz])
|
||||||
|
dipole += atom.chg * position
|
||||||
|
charge += atom.chg
|
||||||
|
|
||||||
|
dipole *= EA_2_DEBYE
|
||||||
|
total_dipole = math.sqrt(dipole[0] ** 2 + dipole[1] ** 2 + dipole[2] ** 2)
|
||||||
|
|
||||||
|
return [charge, dipole[0], dipole[1], dipole[2], total_dipole]
|
||||||
|
|
||||||
|
def distances_between_atoms(self) -> npt.NDArray[np.float64]:
|
||||||
|
"""
|
||||||
|
Calculates distances between the atoms of the molecule
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
NDArray[Shape["Any,Any"],Float]: distances between the atoms.
|
||||||
|
"""
|
||||||
|
coords = np.array([(a.rx, a.ry, a.rz) for a in self.atom], dtype=np.float64)
|
||||||
|
diff = coords[:, None, :] - coords[None, :, :]
|
||||||
|
return np.linalg.norm(diff, axis=-1)
|
||||||
|
|
||||||
|
def principal_axes(self) -> Tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
||||||
|
"""
|
||||||
|
Calculates the principal axes of the molecule
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple[np.ndarray, np.ndarray]: Tuple where the first value is the Eigen Values and the second is the Eigen Vectors,
|
||||||
|
representing the principal axes of the molecule.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
evals, evecs = linalg.eigh(self.inertia_tensor)
|
||||||
|
|
||||||
|
idx = np.argsort(evals)
|
||||||
|
evals = evals[idx]
|
||||||
|
evecs = evecs[:, idx]
|
||||||
|
except ValueError:
|
||||||
|
raise RuntimeError(
|
||||||
|
"Error: diagonalization of inertia tensor did not converge"
|
||||||
|
)
|
||||||
|
|
||||||
|
return evals, evecs
|
||||||
|
|
||||||
|
def read_position(self) -> npt.NDArray[np.float64]:
|
||||||
|
"""Reads the position of the molecule from the position values of the atoms
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
np.ndarray: internal position relative to atoms of the molecule
|
||||||
|
"""
|
||||||
|
coords = np.array([(a.rx, a.ry, a.rz) for a in self.atom], dtype=np.float64)
|
||||||
|
return coords.ravel() * BOHR2ANG
|
||||||
|
|
||||||
|
def update_charges(self, charges: npt.NDArray[np.float64]) -> int:
|
||||||
|
"""
|
||||||
|
Updates the charges of the atoms of the molecule and
|
||||||
|
returns the max difference between the new and old charges
|
||||||
|
"""
|
||||||
|
diff = 0
|
||||||
|
for i, atom in enumerate(self.atom):
|
||||||
|
diff = max(diff, abs(atom.chg - charges[i]))
|
||||||
|
atom.chg = charges[i]
|
||||||
|
|
||||||
|
return diff
|
||||||
|
|
||||||
|
def sizes_of_molecule(self) -> List[float]:
|
||||||
|
"""
|
||||||
|
Calculates sides of the smallest box that the molecule could fit
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[float]: list of the sizes of the molecule
|
||||||
|
"""
|
||||||
|
coords = np.array([(a.rx, a.ry, a.rz) for a in self.atom], dtype=np.float64)
|
||||||
|
return (coords.max(axis=0) - coords.min(axis=0)).tolist()
|
||||||
|
|
||||||
|
def translate(self, vector: np.ndarray) -> Self:
|
||||||
|
"""
|
||||||
|
Creates a new Molecule object where its' atoms has been translated by a vector
|
||||||
|
|
||||||
|
Args:
|
||||||
|
vector (np.ndarray): translation vector
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Molecule: new Molecule object translated by a vector
|
||||||
|
"""
|
||||||
|
vec = np.asarray(vector, dtype=np.float64)
|
||||||
|
if vec.shape != (3,):
|
||||||
|
raise ValueError("translation vector must be shape (3,)")
|
||||||
|
|
||||||
|
new_molecule = deepcopy(self)
|
||||||
|
|
||||||
|
for atom in new_molecule.atom:
|
||||||
|
atom.rx += vector[0]
|
||||||
|
atom.ry += vector[1]
|
||||||
|
atom.rz += vector[2]
|
||||||
|
|
||||||
|
return new_molecule
|
||||||
|
|
||||||
|
def print_mol_info(self) -> None:
|
||||||
|
"""
|
||||||
|
Prints the Molecule information into a Output File
|
||||||
|
"""
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
" Center of mass = ( {:>10.4f} , {:>10.4f} , {:>10.4f} )".format(
|
||||||
|
self.com[0], self.com[1], self.com[2]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
evals, evecs = self.principal_axes()
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
" Moments of inertia = {:>9E} {:>9E} {:>9E}".format(
|
||||||
|
evals[0], evals[1], evals[2]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
" Major principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
|
||||||
|
evecs[0, 0], evecs[1, 0], evecs[2, 0]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
" Inter principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
|
||||||
|
evecs[0, 1], evecs[1, 1], evecs[2, 1]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.info(
|
||||||
|
" Minor principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
|
||||||
|
evecs[0, 2], evecs[1, 2], evecs[2, 2]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
sizes = self.sizes_of_molecule()
|
||||||
|
logger.info(
|
||||||
|
" Characteristic lengths = ( {:>6.2f} , {:>6.2f} , {:>6.2f} )".format(
|
||||||
|
sizes[0], sizes[1], sizes[2]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.info(" Total mass = {:>8.2f} au".format(self.total_mass))
|
||||||
|
|
||||||
|
chg_dip = self.charges_and_dipole()
|
||||||
|
logger.info(" Total charge = {:>8.4f} e".format(chg_dip[0]))
|
||||||
|
logger.info(
|
||||||
|
" Dipole moment = ( {:>9.4f} , {:>9.4f} , {:>9.4f} ) Total = {:>9.4f} Debye".format(
|
||||||
|
chg_dip[1], chg_dip[2], chg_dip[3], chg_dip[4]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def minimum_distance(self, molec: Self) -> float:
|
||||||
|
"""
|
||||||
|
Return the minimum distance between two molecules
|
||||||
|
|
||||||
|
Args:
|
||||||
|
molec (Molecule): Molecule object to be compared
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: minimum distance between the two molecules
|
||||||
|
"""
|
||||||
|
coords_a = np.array(
|
||||||
|
[(a.rx, a.ry, a.rz) for a in self.atom if a.na != GHOST_NUMBER]
|
||||||
|
)
|
||||||
|
coords_b = np.array(
|
||||||
|
[(a.rx, a.ry, a.rz) for a in molec.atom if a.na != GHOST_NUMBER]
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(coords_a) == 0 or len(coords_b) == 0:
|
||||||
|
raise ValueError("No real atoms to compare")
|
||||||
|
|
||||||
|
diff = coords_a[:, None, :] - coords_b[None, :, :]
|
||||||
|
d2 = np.sum(diff**2, axis=-1)
|
||||||
|
return np.sqrt(d2.min())
|
||||||
|
|
||||||
|
def signature(self) -> List[int]:
|
||||||
|
"""
|
||||||
|
Returns the signature of the molecule, which is a list of the number of atoms of each type in the molecule.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List[int]: signature of the molecule
|
||||||
|
"""
|
||||||
|
return [a.lbl for a in self.atom]
|
||||||
30
diceplayer/environment/system.py
Normal file
30
diceplayer/environment/system.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from diceplayer.environment.molecule import Molecule
|
||||||
|
|
||||||
|
from typing_extensions import List
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class System:
|
||||||
|
"""
|
||||||
|
System class declaration. This class is used throughout the DicePlayer program to represent the system containing the molecules.
|
||||||
|
|
||||||
|
Atributes:
|
||||||
|
molecule (List[Molecule]): List of molecules of the system
|
||||||
|
nmols (List[int]): List of number of molecules in the system
|
||||||
|
"""
|
||||||
|
|
||||||
|
nmols: List[int] = field(default_factory=list)
|
||||||
|
molecule: List[Molecule] = field(default_factory=list)
|
||||||
|
|
||||||
|
def add_type(self, m: Molecule) -> None:
|
||||||
|
"""
|
||||||
|
Adds a new molecule type to the system
|
||||||
|
|
||||||
|
Args:
|
||||||
|
m (Molecule): The instance of the new type of molecule
|
||||||
|
"""
|
||||||
|
if not isinstance(m, Molecule):
|
||||||
|
raise TypeError("Error: molecule is not a Molecule instance")
|
||||||
|
self.molecule.append(m)
|
||||||
4
diceplayer/logger.py
Normal file
4
diceplayer/logger.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from diceplayer.utils import RunLogger
|
||||||
|
|
||||||
|
|
||||||
|
logger = RunLogger("diceplayer")
|
||||||
37
diceplayer/optimization/optimization_handler.py
Normal file
37
diceplayer/optimization/optimization_handler.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from diceplayer.config.player_config import RoutineType
|
||||||
|
from diceplayer.dice.dice_wrapper import DiceEnvironmentItem
|
||||||
|
from diceplayer.environment import Atom
|
||||||
|
from diceplayer.logger import logger
|
||||||
|
from diceplayer.state.state_model import StateModel
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class OptimizationHandler:
|
||||||
|
def __init__(self, step_directory: Path):
|
||||||
|
self.optimization_directory = step_directory / "optimization"
|
||||||
|
|
||||||
|
def run(
|
||||||
|
self,
|
||||||
|
state: StateModel,
|
||||||
|
current_cycle: int,
|
||||||
|
dice_environment: list[Atom],
|
||||||
|
) -> StateModel:
|
||||||
|
routine = self._fetch_current_routine(state, current_cycle)
|
||||||
|
logger.info(
|
||||||
|
f"Running Optimization - {current_cycle} - {routine} - {self.optimization_directory}"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(dice_environment)
|
||||||
|
|
||||||
|
return state
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _fetch_current_routine(state: StateModel, current_cycle: int) -> RoutineType:
|
||||||
|
if state.config.type != RoutineType.BOTH:
|
||||||
|
return state.config.type
|
||||||
|
|
||||||
|
if current_cycle < state.config.switch_cyc:
|
||||||
|
return RoutineType.CHARGE
|
||||||
|
|
||||||
|
return RoutineType.GEOMETRY
|
||||||
@@ -1,448 +1,60 @@
|
|||||||
from diceplayer import VERSION, logger
|
from diceplayer.config.player_config import PlayerConfig
|
||||||
from diceplayer.shared.config.dice_config import DiceConfig
|
from diceplayer.dice.dice_handler import DiceHandler
|
||||||
from diceplayer.shared.config.gaussian_config import GaussianDTO
|
from diceplayer.logger import logger
|
||||||
from diceplayer.shared.config.player_config import PlayerConfig
|
from diceplayer.optimization.optimization_handler import OptimizationHandler
|
||||||
from diceplayer.shared.environment.atom import Atom
|
from diceplayer.state.state_handler import StateHandler
|
||||||
from diceplayer.shared.environment.molecule import Molecule
|
from diceplayer.state.state_model import StateModel
|
||||||
from diceplayer.shared.environment.system import System
|
from diceplayer.utils.potential import read_system_from_phb
|
||||||
from diceplayer.shared.interface.dice_interface import DiceInterface
|
|
||||||
from diceplayer.shared.interface.gaussian_interface import GaussianInterface
|
|
||||||
from diceplayer.shared.utils.dataclass_protocol import Dataclass
|
|
||||||
from diceplayer.shared.utils.misc import weekday_date_time
|
|
||||||
from diceplayer.shared.utils.ptable import atomsymb
|
|
||||||
|
|
||||||
import yaml
|
from typing_extensions import TypedDict, Unpack
|
||||||
|
|
||||||
import os
|
|
||||||
import pickle
|
|
||||||
import sys
|
|
||||||
from dataclasses import fields
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Tuple, Type
|
|
||||||
|
|
||||||
ENV = ["OMP_STACKSIZE"]
|
class PlayerFlags(TypedDict):
|
||||||
|
continuation: bool
|
||||||
|
force: bool
|
||||||
|
|
||||||
|
|
||||||
class Player:
|
class Player:
|
||||||
def __init__(self, infile: str = None, optimization: bool = False):
|
def __init__(self, config: PlayerConfig):
|
||||||
if infile is None and optimization is False:
|
self.config = config
|
||||||
raise ValueError("Must specify either infile or optimization")
|
self._state_handler = StateHandler(config.simulation_dir)
|
||||||
|
|
||||||
elif infile is not None:
|
def play(self, **flags: Unpack[PlayerFlags]):
|
||||||
self.config = self.set_config(self.read_keywords(infile))
|
continuation = flags.get("continuation", False)
|
||||||
|
force = flags.get("force", False)
|
||||||
|
|
||||||
self.system = System()
|
state = self._state_handler.get(self.config, force=force)
|
||||||
|
if not continuation and state is not None:
|
||||||
self.initial_cycle = 1
|
logger.info(
|
||||||
|
"Continuation flag is not set. Starting a new simulation and deleting any existing state."
|
||||||
elif optimization is True:
|
)
|
||||||
save = self.load_run_from_pickle()
|
self._state_handler.delete()
|
||||||
|
state = None
|
||||||
self.config = save[0]
|
|
||||||
|
|
||||||
self.system = save[1]
|
|
||||||
|
|
||||||
self.initial_cycle = save[2] + 1
|
|
||||||
|
|
||||||
|
if state is None:
|
||||||
|
system = read_system_from_phb(self.config)
|
||||||
|
state = StateModel(config=self.config, system=system)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Must specify either infile or config")
|
logger.info("Resuming from existing state.")
|
||||||
|
|
||||||
self.dice_interface = DiceInterface()
|
while state.current_cycle < self.config.max_cyc:
|
||||||
self.gaussian_interface = GaussianInterface()
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
logger.info(
|
|
||||||
"==========================================================================================\n"
|
|
||||||
"Starting the iterative process.\n"
|
|
||||||
"==========================================================================================\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
for cycle in range(self.initial_cycle, self.initial_cycle + self.config.maxcyc):
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"------------------------------------------------------------------------------------------\n"
|
f"Starting cycle {state.current_cycle + 1} of {self.config.max_cyc}."
|
||||||
f" Step # {cycle}\n"
|
|
||||||
f"------------------------------------------------------------------------------------------\n"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.dice_start(cycle)
|
step_directory = self.config.simulation_dir / f"{state.current_cycle:02d}"
|
||||||
|
if not step_directory.exists():
|
||||||
|
step_directory.mkdir(parents=True)
|
||||||
|
|
||||||
try:
|
dice_environment = DiceHandler(step_directory).run(
|
||||||
self.gaussian_start(cycle)
|
state, state.current_cycle
|
||||||
except StopIteration:
|
|
||||||
break
|
|
||||||
|
|
||||||
self.save_run_in_pickle(cycle)
|
|
||||||
|
|
||||||
def prepare_system(self):
|
|
||||||
for i, mol in enumerate(self.system.molecule):
|
|
||||||
logger.info(f"Molecule {i + 1} - {mol.molname}")
|
|
||||||
|
|
||||||
mol.print_mol_info()
|
|
||||||
logger.info(
|
|
||||||
"\n Translating and rotating molecule to standard orientation..."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
mol.standard_orientation()
|
state = OptimizationHandler(step_directory).run(
|
||||||
logger.info("\n Done")
|
state, state.current_cycle, dice_environment
|
||||||
logger.info("\nNew values:\n")
|
|
||||||
mol.print_mol_info()
|
|
||||||
|
|
||||||
logger.info("\n")
|
|
||||||
|
|
||||||
def create_simulation_dir(self):
|
|
||||||
simulation_dir_path = Path(self.config.simulation_dir)
|
|
||||||
if simulation_dir_path.exists():
|
|
||||||
raise FileExistsError(
|
|
||||||
f"Error: a file or a directory {self.config.simulation_dir} already exists,"
|
|
||||||
f" move or delete the simfiles directory to continue."
|
|
||||||
)
|
|
||||||
simulation_dir_path.mkdir()
|
|
||||||
|
|
||||||
def create_geoms_file(self):
|
|
||||||
geoms_file_path = Path(self.config.geoms_file)
|
|
||||||
if geoms_file_path.exists():
|
|
||||||
raise FileExistsError(
|
|
||||||
f"Error: a file or a directory {self.config.geoms_file} already exists,"
|
|
||||||
f" move or delete the simfiles directory to continue."
|
|
||||||
)
|
|
||||||
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)}")
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"##########################################################################################\n"
|
|
||||||
f"############# Welcome to DICEPLAYER version {VERSION} #############\n"
|
|
||||||
f"##########################################################################################\n"
|
|
||||||
)
|
|
||||||
logger.info("Your python version is {}\n".format(sys.version))
|
|
||||||
logger.info("Program started on {}\n".format(weekday_date_time()))
|
|
||||||
logger.info("Environment variables:")
|
|
||||||
for var in ENV:
|
|
||||||
logger.info(
|
|
||||||
"{} = {}\n".format(
|
|
||||||
var, (os.environ[var] if var in os.environ else "Not set")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(
|
state.current_cycle += 1
|
||||||
"------------------------------------------------------------------------------------------\n"
|
self._state_handler.save(state)
|
||||||
" DICE variables being used in this run:\n"
|
|
||||||
"------------------------------------------------------------------------------------------\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
log_keywords(self.config.dice, DiceConfig)
|
logger.info("Reached maximum number of cycles. Simulation complete.")
|
||||||
|
|
||||||
logger.info(
|
|
||||||
"------------------------------------------------------------------------------------------\n"
|
|
||||||
" GAUSSIAN variables being used in this run:\n"
|
|
||||||
"------------------------------------------------------------------------------------------\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
log_keywords(self.config.gaussian, GaussianDTO)
|
|
||||||
|
|
||||||
logger.info("\n")
|
|
||||||
|
|
||||||
def read_potentials(self):
|
|
||||||
ljname_path = Path(self.config.dice.ljname)
|
|
||||||
if ljname_path.exists():
|
|
||||||
with open(self.config.dice.ljname) as file:
|
|
||||||
ljc_data = file.readlines()
|
|
||||||
else:
|
|
||||||
raise RuntimeError(f"Potential file {self.config.dice.ljname} not found.")
|
|
||||||
|
|
||||||
combrule = ljc_data.pop(0).split()[0]
|
|
||||||
if combrule not in ("*", "+"):
|
|
||||||
sys.exit(
|
|
||||||
"Error: expected a '*' or a '+' sign in 1st line of file {}".format(
|
|
||||||
self.config.dice.ljname
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.config.dice.combrule = combrule
|
|
||||||
|
|
||||||
ntypes = ljc_data.pop(0).split()[0]
|
|
||||||
if not ntypes.isdigit():
|
|
||||||
sys.exit(
|
|
||||||
"Error: expected an integer in the 2nd line of file {}".format(
|
|
||||||
self.config.dice.ljname
|
|
||||||
)
|
|
||||||
)
|
|
||||||
ntypes = int(ntypes)
|
|
||||||
|
|
||||||
if ntypes != len(self.config.dice.nmol):
|
|
||||||
sys.exit(
|
|
||||||
f"Error: number of molecule types in file {self.config.dice.ljname} "
|
|
||||||
f"must match that of 'nmol' keyword in config file"
|
|
||||||
)
|
|
||||||
|
|
||||||
for i in range(ntypes):
|
|
||||||
try:
|
|
||||||
nsites, molname = ljc_data.pop(0).split()[:2]
|
|
||||||
except ValueError:
|
|
||||||
raise ValueError(
|
|
||||||
f"Error: expected nsites and molname for the molecule type {i + 1}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if not nsites.isdigit():
|
|
||||||
raise ValueError(
|
|
||||||
f"Error: expected nsites to be an integer for molecule type {i + 1}"
|
|
||||||
)
|
|
||||||
|
|
||||||
nsites = int(nsites)
|
|
||||||
self.system.add_type(Molecule(molname))
|
|
||||||
|
|
||||||
atom_fields = ["lbl", "na", "rx", "ry", "rz", "chg", "eps", "sig"]
|
|
||||||
for j in range(nsites):
|
|
||||||
new_atom = dict(zip(atom_fields, ljc_data.pop(0).split()))
|
|
||||||
self.system.molecule[i].add_atom(
|
|
||||||
Atom(**self.validate_atom_dict(i, j, new_atom))
|
|
||||||
)
|
|
||||||
|
|
||||||
def print_potentials(self) -> None:
|
|
||||||
formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}"
|
|
||||||
logger.info(
|
|
||||||
"==========================================================================================\n"
|
|
||||||
f" Potential parameters from file {self.config.dice.ljname}:\n"
|
|
||||||
"------------------------------------------------------------------------------------------"
|
|
||||||
"\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(f"Combination rule: {self.config.dice.combrule}")
|
|
||||||
logger.info(f"Types of molecules: {len(self.system.molecule)}\n")
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
for mol in self.system.molecule:
|
|
||||||
i += 1
|
|
||||||
logger.info("{} atoms in molecule type {}:".format(len(mol.atom), i))
|
|
||||||
logger.info(
|
|
||||||
"---------------------------------------------------------------------------------"
|
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
"Lbl AN X Y Z Charge Epsilon Sigma Mass"
|
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
"---------------------------------------------------------------------------------"
|
|
||||||
)
|
|
||||||
|
|
||||||
for atom in mol.atom:
|
|
||||||
logger.info(
|
|
||||||
formatstr.format(
|
|
||||||
atom.lbl,
|
|
||||||
atom.na,
|
|
||||||
atom.rx,
|
|
||||||
atom.ry,
|
|
||||||
atom.rz,
|
|
||||||
atom.chg,
|
|
||||||
atom.eps,
|
|
||||||
atom.sig,
|
|
||||||
atom.mass,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info("\n")
|
|
||||||
|
|
||||||
def dice_start(self, cycle: int):
|
|
||||||
self.dice_interface.configure(
|
|
||||||
self.config,
|
|
||||||
self.system,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.dice_interface.start(cycle)
|
|
||||||
|
|
||||||
self.dice_interface.reset()
|
|
||||||
|
|
||||||
def gaussian_start(self, cycle: int):
|
|
||||||
self.gaussian_interface.configure(
|
|
||||||
self.config,
|
|
||||||
self.system,
|
|
||||||
)
|
|
||||||
|
|
||||||
result = self.gaussian_interface.start(cycle)
|
|
||||||
|
|
||||||
self.gaussian_interface.reset()
|
|
||||||
|
|
||||||
if self.config.opt:
|
|
||||||
if "position" not in result:
|
|
||||||
raise RuntimeError("Optimization failed. No position found in result.")
|
|
||||||
|
|
||||||
self.system.update_molecule(result["position"])
|
|
||||||
|
|
||||||
else:
|
|
||||||
if "charges" not in result:
|
|
||||||
raise RuntimeError(
|
|
||||||
"Charges optimization failed. No charges found in result."
|
|
||||||
)
|
|
||||||
|
|
||||||
diff = self.system.molecule[0].update_charges(result["charges"])
|
|
||||||
|
|
||||||
self.system.print_charges_and_dipole(cycle)
|
|
||||||
self.print_geoms(cycle)
|
|
||||||
|
|
||||||
if diff < self.config.gaussian.chg_tol:
|
|
||||||
logger.info(f"Charges converged after {cycle} cycles.")
|
|
||||||
raise StopIteration()
|
|
||||||
|
|
||||||
def print_geoms(self, cycle: int):
|
|
||||||
with open(self.config.geoms_file, "a") as file:
|
|
||||||
file.write(f"Cycle # {cycle}\n")
|
|
||||||
|
|
||||||
for atom in self.system.molecule[0].atom:
|
|
||||||
symbol = atomsymb[atom.na]
|
|
||||||
file.write(
|
|
||||||
f"{symbol:<2s} {atom.rx:>10.6f} {atom.ry:>10.6f} {atom.rz:>10.6f}\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
file.write("\n")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def validate_atom_dict(molecule_type, molecule_site, atom_dict: dict) -> dict:
|
|
||||||
molecule_type += 1
|
|
||||||
molecule_site += 1
|
|
||||||
|
|
||||||
if len(atom_dict) < 8:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid number of fields for site {molecule_site} for molecule type {molecule_type}."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
atom_dict["lbl"] = int(atom_dict["lbl"])
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid lbl fields for site {molecule_site} for molecule type {molecule_type}."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
atom_dict["na"] = int(atom_dict["na"])
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid na fields for site {molecule_site} for molecule type {molecule_type}."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
atom_dict["rx"] = float(atom_dict["rx"])
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid rx fields for site {molecule_site} for molecule type {molecule_type}. "
|
|
||||||
f"Value must be a float."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
atom_dict["ry"] = float(atom_dict["ry"])
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid ry fields for site {molecule_site} for molecule type {molecule_type}. "
|
|
||||||
f"Value must be a float."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
atom_dict["rz"] = float(atom_dict["rz"])
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid rz fields for site {molecule_site} for molecule type {molecule_type}. "
|
|
||||||
f"Value must be a float."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
atom_dict["chg"] = float(atom_dict["chg"])
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid chg fields for site {molecule_site} for molecule type {molecule_type}. "
|
|
||||||
f"Value must be a float."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
atom_dict["eps"] = float(atom_dict["eps"])
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid eps fields for site {molecule_site} for molecule type {molecule_type}. "
|
|
||||||
f"Value must be a float."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
atom_dict["sig"] = float(atom_dict["sig"])
|
|
||||||
except Exception:
|
|
||||||
raise ValueError(
|
|
||||||
f"Invalid sig fields for site {molecule_site} for molecule type {molecule_type}. "
|
|
||||||
f"Value must be a float."
|
|
||||||
)
|
|
||||||
|
|
||||||
return atom_dict
|
|
||||||
|
|
||||||
def print_results(self):
|
|
||||||
formatstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f} {:>9.4f}"
|
|
||||||
|
|
||||||
mol = self.system.molecule[0]
|
|
||||||
logger.info("{} atoms in molecule type {}:".format(len(mol.atom), 1))
|
|
||||||
logger.info(
|
|
||||||
"---------------------------------------------------------------------------------"
|
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
"Lbl AN X Y Z Charge Epsilon Sigma Mass"
|
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
"---------------------------------------------------------------------------------"
|
|
||||||
)
|
|
||||||
|
|
||||||
for atom in mol.atom:
|
|
||||||
logger.info(
|
|
||||||
formatstr.format(
|
|
||||||
atom.lbl,
|
|
||||||
atom.na,
|
|
||||||
atom.rx,
|
|
||||||
atom.ry,
|
|
||||||
atom.rz,
|
|
||||||
atom.chg,
|
|
||||||
atom.eps,
|
|
||||||
atom.sig,
|
|
||||||
atom.mass,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info("\n")
|
|
||||||
|
|
||||||
def save_run_in_pickle(self, cycle):
|
|
||||||
try:
|
|
||||||
with open("latest-step.pkl", "wb") as pickle_file:
|
|
||||||
pickle.dump((self.config, self.system, cycle), pickle_file)
|
|
||||||
except Exception:
|
|
||||||
raise RuntimeError(f"Could not save pickle file latest-step.pkl.")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def load_run_from_pickle() -> Tuple[PlayerConfig, System, int]:
|
|
||||||
pickle_path = Path("latest-step.pkl")
|
|
||||||
try:
|
|
||||||
with open(pickle_path, "rb") as pickle_file:
|
|
||||||
save = pickle.load(pickle_file)
|
|
||||||
return save[0], save[1], save[2] + 1
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
raise RuntimeError(f"Could not load pickle file {pickle_path}.")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def set_config(data: dict) -> PlayerConfig:
|
|
||||||
return PlayerConfig.from_dict(data)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def read_keywords(infile) -> dict:
|
|
||||||
with open(infile, "r") as yml_file:
|
|
||||||
config = yaml.load(yml_file, Loader=yaml.SafeLoader)
|
|
||||||
|
|
||||||
if "diceplayer" in config:
|
|
||||||
return config.get("diceplayer")
|
|
||||||
|
|
||||||
raise RuntimeError(f"Could not find diceplayer section in {infile}.")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_file(cls, infile: str) -> "Player":
|
|
||||||
return cls(infile=infile)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_save(cls):
|
|
||||||
return cls(optimization=True)
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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)
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
from diceplayer.shared.config.dice_config import DiceConfig
|
|
||||||
from diceplayer.shared.config.gaussian_config import GaussianDTO
|
|
||||||
from diceplayer.shared.utils.dataclass_protocol import Dataclass
|
|
||||||
|
|
||||||
from dataclasses import dataclass, fields
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PlayerConfig(Dataclass):
|
|
||||||
"""
|
|
||||||
Data Transfer Object for the player configuration.
|
|
||||||
"""
|
|
||||||
|
|
||||||
opt: bool
|
|
||||||
maxcyc: int
|
|
||||||
nprocs: int
|
|
||||||
ncores: int
|
|
||||||
|
|
||||||
dice: DiceConfig
|
|
||||||
gaussian: GaussianDTO
|
|
||||||
|
|
||||||
mem: int = None
|
|
||||||
switchcyc: int = 3
|
|
||||||
qmprog: str = "g16"
|
|
||||||
altsteps: int = 20000
|
|
||||||
geoms_file = "geoms.xyz"
|
|
||||||
simulation_dir = "simfiles"
|
|
||||||
|
|
||||||
def __post_init__(self):
|
|
||||||
MIN_STEP = 20000
|
|
||||||
# altsteps value is always the nearest multiple of 1000
|
|
||||||
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.from_dict(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 = {f.name: params[f.name] for f in fields(cls) if f.name in params}
|
|
||||||
|
|
||||||
return cls(**params)
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
from diceplayer.shared.utils.ptable import atommass
|
|
||||||
|
|
||||||
|
|
||||||
class Atom:
|
|
||||||
"""
|
|
||||||
Atom class declaration. This class is used throughout the DicePlayer program to represent atoms.
|
|
||||||
|
|
||||||
Atributes:
|
|
||||||
lbl (int): Dice derived variable used to represent atoms with identical energies and simetric positions.
|
|
||||||
na (int): Atomic number of the represented atom.
|
|
||||||
rx (float): x cartesian coordinates of the represented atom.
|
|
||||||
ry (float): y cartesian coordinates of the represented atom.
|
|
||||||
rz (float): z cartesian coordinates of the represented atom.
|
|
||||||
chg (float): charge of the represented atom.
|
|
||||||
eps (float): quantum number epsilon of the represented atom.
|
|
||||||
sig (float): quantum number sigma of the represented atom.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
lbl: int,
|
|
||||||
na: int,
|
|
||||||
rx: float,
|
|
||||||
ry: float,
|
|
||||||
rz: float,
|
|
||||||
chg: float,
|
|
||||||
eps: float,
|
|
||||||
sig: float,
|
|
||||||
) -> None:
|
|
||||||
"""
|
|
||||||
The constructor function __init__ is used to create new instances of the Atom class.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
lbl (int): Dice derived variable used to represent atoms with identical energies and simetric positions.
|
|
||||||
na (int): Atomic number of the represented atom.
|
|
||||||
rx (float): x cartesian coordinates of the represented atom.
|
|
||||||
ry (float): y cartesian coordinates of the represented atom.
|
|
||||||
rz (float): z cartesian coordinates of the represented atom.
|
|
||||||
chg (float): charge of the represented atom.
|
|
||||||
eps (float): quantum number epsilon of the represented atom.
|
|
||||||
sig (float): quantum number sigma of the represented atom.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.lbl = lbl
|
|
||||||
self.na = na
|
|
||||||
self.rx = rx
|
|
||||||
self.ry = ry
|
|
||||||
self.rz = rz
|
|
||||||
self.chg = chg
|
|
||||||
self.eps = eps
|
|
||||||
self.sig = sig
|
|
||||||
self.mass = atommass[self.na]
|
|
||||||
@@ -1,384 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from nptyping import Float, NDArray, Shape
|
|
||||||
|
|
||||||
from diceplayer import logger
|
|
||||||
from diceplayer.shared.environment.atom import Atom
|
|
||||||
from diceplayer.shared.utils.misc import BOHR2ANG
|
|
||||||
from diceplayer.shared.utils.ptable import ghost_number
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from numpy.linalg import linalg
|
|
||||||
|
|
||||||
import math
|
|
||||||
from copy import deepcopy
|
|
||||||
from typing import Any, List, Tuple, Union
|
|
||||||
|
|
||||||
|
|
||||||
class Molecule:
|
|
||||||
"""
|
|
||||||
Molecule class declaration. This class is used throughout the DicePlayer program to represent molecules.
|
|
||||||
|
|
||||||
Atributes:
|
|
||||||
molname (str): The name of the represented molecule
|
|
||||||
atom (List[Atom]): List of atoms of the represented molecule
|
|
||||||
position (NDArray[Any, Any]): The position relative to the internal atoms of the represented molecule
|
|
||||||
energy (NDArray[Any, Any]): The energy of the represented molecule
|
|
||||||
gradient (NDArray[Any, Any]): The first derivative of the energy relative to the position
|
|
||||||
hessian (NDArray[Any, Any]): The second derivative of the energy relative to the position
|
|
||||||
total_mass (int): The total mass of the molecule
|
|
||||||
com (NDArray[Any, Any]): The center of mass of the molecule
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, molname: str) -> None:
|
|
||||||
"""
|
|
||||||
The constructor function __init__ is used to create new instances of the Molecule class.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
molname (str): Molecule name
|
|
||||||
"""
|
|
||||||
self.molname: str = molname
|
|
||||||
|
|
||||||
self.atom: List[Atom] = []
|
|
||||||
self.position: NDArray[Any, Any]
|
|
||||||
self.energy: NDArray[Any, Any]
|
|
||||||
self.gradient: NDArray[Any, Any]
|
|
||||||
self.hessian: NDArray[Any, Any]
|
|
||||||
|
|
||||||
self.ghost_atoms: List[Atom] = []
|
|
||||||
self.lp_atoms: List[Atom] = []
|
|
||||||
|
|
||||||
self.total_mass: int = 0
|
|
||||||
self.com: Union[None, NDArray[Any, Any]] = None
|
|
||||||
|
|
||||||
def add_atom(self, a: Atom) -> None:
|
|
||||||
"""
|
|
||||||
Adds Atom instance to the molecule.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
a (Atom): Atom instance to be added to atom list.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.atom.append(a)
|
|
||||||
self.total_mass += a.mass
|
|
||||||
|
|
||||||
self.center_of_mass()
|
|
||||||
|
|
||||||
def center_of_mass(self) -> NDArray[Any, Any]:
|
|
||||||
"""
|
|
||||||
Calculates the center of mass of the molecule
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.com = np.zeros(3)
|
|
||||||
|
|
||||||
for atom in self.atom:
|
|
||||||
self.com += atom.mass * np.array([atom.rx, atom.ry, atom.rz])
|
|
||||||
|
|
||||||
self.com = self.com / self.total_mass
|
|
||||||
|
|
||||||
return self.com
|
|
||||||
|
|
||||||
def center_of_mass_to_origin(self) -> None:
|
|
||||||
"""
|
|
||||||
Updated positions based on the center of mass of the molecule
|
|
||||||
"""
|
|
||||||
for atom in self.atom:
|
|
||||||
atom.rx -= self.com[0]
|
|
||||||
atom.ry -= self.com[1]
|
|
||||||
atom.rz -= self.com[2]
|
|
||||||
|
|
||||||
self.center_of_mass()
|
|
||||||
|
|
||||||
def charges_and_dipole(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Calculates the charges and dipole of the molecule atoms
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List[float]: Respectivly magnitude of the: charge magnitude, first dipole,
|
|
||||||
second dipole, third dipole and total dipole.
|
|
||||||
"""
|
|
||||||
|
|
||||||
eA_to_Debye = 1 / 0.20819434
|
|
||||||
charge = 0
|
|
||||||
dipole = np.zeros(3)
|
|
||||||
for atom in self.atom:
|
|
||||||
position = np.array([atom.rx, atom.ry, atom.rz])
|
|
||||||
dipole += atom.chg * position
|
|
||||||
charge += atom.chg
|
|
||||||
|
|
||||||
dipole *= eA_to_Debye
|
|
||||||
total_dipole = math.sqrt(dipole[0] ** 2 + dipole[1] ** 2 + dipole[2] ** 2)
|
|
||||||
|
|
||||||
return [charge, dipole[0], dipole[1], dipole[2], total_dipole]
|
|
||||||
|
|
||||||
def distances_between_atoms(self) -> NDArray[Shape["Any,Any"], Float]:
|
|
||||||
"""
|
|
||||||
Calculates distances between the atoms of the molecule
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
NDArray[Shape["Any,Any"],Float]: distances between the atoms.
|
|
||||||
"""
|
|
||||||
|
|
||||||
distances = []
|
|
||||||
dim = len(self.atom)
|
|
||||||
for index1, atom1 in enumerate(self.atom):
|
|
||||||
for index2, atom2 in enumerate(self.atom):
|
|
||||||
if index1 != index2:
|
|
||||||
dx = atom1.rx - atom2.rx
|
|
||||||
dy = atom1.ry - atom2.ry
|
|
||||||
dz = atom1.rz - atom2.rz
|
|
||||||
distances.append(math.sqrt(dx**2 + dy**2 + dz**2))
|
|
||||||
|
|
||||||
return np.array(distances).reshape(dim, dim - 1)
|
|
||||||
|
|
||||||
def inertia_tensor(self) -> NDArray[Shape["3, 3"], Float]:
|
|
||||||
"""
|
|
||||||
Calculates the inertia tensor of the molecule.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
NDArray[Shape["3, 3"], Float]: inertia tensor of the molecule.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.center_of_mass()
|
|
||||||
Ixx = Ixy = Ixz = Iyy = Iyz = Izz = 0.0
|
|
||||||
|
|
||||||
for atom in self.atom:
|
|
||||||
dx = atom.rx - self.com[0]
|
|
||||||
dy = atom.ry - self.com[1]
|
|
||||||
dz = atom.rz - self.com[2]
|
|
||||||
|
|
||||||
Ixx += atom.mass * (dy**2 + dz**2)
|
|
||||||
Iyy += atom.mass * (dz**2 + dx**2)
|
|
||||||
Izz += atom.mass * (dx**2 + dy**2)
|
|
||||||
|
|
||||||
Ixy += atom.mass * dx * dy * -1
|
|
||||||
Ixz += atom.mass * dx * dz * -1
|
|
||||||
Iyz += atom.mass * dy * dz * -1
|
|
||||||
|
|
||||||
return np.array([[Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]])
|
|
||||||
|
|
||||||
def principal_axes(self) -> Tuple[np.ndarray, np.ndarray]:
|
|
||||||
"""
|
|
||||||
Calculates the principal axes of the molecule
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Tuple[np.ndarray, np.ndarray]: Tuple where the first value is the Eigen Values and the second is the Eigen Vectors,
|
|
||||||
representing the principal axes of the molecule.
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
evals, evecs = linalg.eigh(self.inertia_tensor())
|
|
||||||
except ValueError:
|
|
||||||
raise RuntimeError(
|
|
||||||
"Error: diagonalization of inertia tensor did not converge"
|
|
||||||
)
|
|
||||||
|
|
||||||
return evals, evecs
|
|
||||||
|
|
||||||
def read_position(self) -> np.ndarray:
|
|
||||||
"""Reads the position of the molecule from the position values of the atoms
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
np.ndarray: internal position relative to atoms of the molecule
|
|
||||||
"""
|
|
||||||
|
|
||||||
position_list = []
|
|
||||||
for atom in self.atom:
|
|
||||||
position_list.extend([atom.rx, atom.ry, atom.rz])
|
|
||||||
position = np.array(position_list)
|
|
||||||
position *= BOHR2ANG
|
|
||||||
|
|
||||||
return position
|
|
||||||
|
|
||||||
def update_charges(self, charges: NDArray) -> int:
|
|
||||||
"""
|
|
||||||
Updates the charges of the atoms of the molecule and
|
|
||||||
returns the max difference between the new and old charges
|
|
||||||
"""
|
|
||||||
diff = 0
|
|
||||||
for i, atom in enumerate(self.atom):
|
|
||||||
diff = max(diff, abs(atom.chg - charges[i]))
|
|
||||||
atom.chg = charges[i]
|
|
||||||
|
|
||||||
return diff
|
|
||||||
|
|
||||||
# @staticmethod
|
|
||||||
# def update_hessian(
|
|
||||||
# step: np.ndarray,
|
|
||||||
# cur_gradient: np.ndarray,
|
|
||||||
# old_gradient: np.ndarray,
|
|
||||||
# hessian: np.ndarray,
|
|
||||||
# ) -> np.ndarray:
|
|
||||||
# """
|
|
||||||
# Updates the Hessian of the molecule based on the current hessian, the current gradient and the previous gradient
|
|
||||||
#
|
|
||||||
# Args:
|
|
||||||
# step (np.ndarray): step value of the iteration
|
|
||||||
# cur_gradient (np.ndarray): current gradient
|
|
||||||
# old_gradient (np.ndarray): previous gradient
|
|
||||||
# hessian (np.ndarray): current hessian
|
|
||||||
#
|
|
||||||
# Returns:
|
|
||||||
# np.ndarray: updated hessian of the molecule
|
|
||||||
# """
|
|
||||||
#
|
|
||||||
# dif_gradient = cur_gradient - old_gradient
|
|
||||||
#
|
|
||||||
# mat1 = 1 / np.dot(dif_gradient, step) * np.matmul(dif_gradient.T, dif_gradient)
|
|
||||||
# mat2 = 1 / np.dot(step, np.matmul(hessian, step.T).T)
|
|
||||||
# mat2 *= np.matmul(np.matmul(hessian, step.T), np.matmul(step, hessian))
|
|
||||||
#
|
|
||||||
# return hessian + mat1 - mat2
|
|
||||||
|
|
||||||
def sizes_of_molecule(self) -> List[float]:
|
|
||||||
"""
|
|
||||||
Calculates sides of the smallest box that the molecule could fit
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List[float]: list of the sizes of the molecule
|
|
||||||
"""
|
|
||||||
|
|
||||||
x_list = []
|
|
||||||
y_list = []
|
|
||||||
z_list = []
|
|
||||||
|
|
||||||
for atom in self.atom:
|
|
||||||
x_list.append(atom.rx)
|
|
||||||
y_list.append(atom.ry)
|
|
||||||
z_list.append(atom.rz)
|
|
||||||
|
|
||||||
x_max = max(x_list)
|
|
||||||
x_min = min(x_list)
|
|
||||||
y_max = max(y_list)
|
|
||||||
y_min = min(y_list)
|
|
||||||
z_max = max(z_list)
|
|
||||||
z_min = min(z_list)
|
|
||||||
|
|
||||||
sizes = [x_max - x_min, y_max - y_min, z_max - z_min]
|
|
||||||
|
|
||||||
return sizes
|
|
||||||
|
|
||||||
def standard_orientation(self) -> None:
|
|
||||||
"""
|
|
||||||
Rotates the molecule to the standard orientation
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.center_of_mass_to_origin()
|
|
||||||
evals, evecs = self.principal_axes()
|
|
||||||
|
|
||||||
if round(linalg.det(evecs)) == -1:
|
|
||||||
evecs[0, 2] *= -1
|
|
||||||
evecs[1, 2] *= -1
|
|
||||||
evecs[2, 2] *= -1
|
|
||||||
|
|
||||||
if round(linalg.det(evecs)) != 1:
|
|
||||||
raise RuntimeError(
|
|
||||||
"Error: could not make a rotation matrix while adopting the standard orientation"
|
|
||||||
)
|
|
||||||
|
|
||||||
rot_matrix = evecs.T
|
|
||||||
|
|
||||||
for atom in self.atom:
|
|
||||||
position = np.array([atom.rx, atom.ry, atom.rz])
|
|
||||||
new_position = np.matmul(rot_matrix, position.T).T
|
|
||||||
|
|
||||||
atom.rx = new_position[0]
|
|
||||||
atom.ry = new_position[1]
|
|
||||||
atom.rz = new_position[2]
|
|
||||||
|
|
||||||
def translate(self, vector: np.ndarray) -> "Molecule":
|
|
||||||
"""
|
|
||||||
Creates a new Molecule object where its' atoms has been translated by a vector
|
|
||||||
|
|
||||||
Args:
|
|
||||||
vector (np.ndarray): translation vector
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Molecule: new Molecule object translated by a vector
|
|
||||||
"""
|
|
||||||
|
|
||||||
new_molecule = deepcopy(self)
|
|
||||||
|
|
||||||
for atom in new_molecule.atom:
|
|
||||||
atom.rx += vector[0]
|
|
||||||
atom.ry += vector[1]
|
|
||||||
atom.rz += vector[2]
|
|
||||||
|
|
||||||
return new_molecule
|
|
||||||
|
|
||||||
def print_mol_info(self) -> None:
|
|
||||||
"""
|
|
||||||
Prints the Molecule information into a Output File
|
|
||||||
"""
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
" Center of mass = ( {:>10.4f} , {:>10.4f} , {:>10.4f} )".format(
|
|
||||||
self.com[0], self.com[1], self.com[2]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
inertia = self.inertia_tensor()
|
|
||||||
evals, evecs = self.principal_axes()
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
" Moments of inertia = {:>9E} {:>9E} {:>9E}".format(
|
|
||||||
evals[0], evals[1], evals[2]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
" Major principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
|
|
||||||
evecs[0, 0], evecs[1, 0], evecs[2, 0]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
" Inter principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
|
|
||||||
evecs[0, 1], evecs[1, 1], evecs[2, 1]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
" Minor principal axis = ( {:>10.6f} , {:>10.6f} , {:>10.6f} )".format(
|
|
||||||
evecs[0, 2], evecs[1, 2], evecs[2, 2]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
sizes = self.sizes_of_molecule()
|
|
||||||
logger.info(
|
|
||||||
" Characteristic lengths = ( {:>6.2f} , {:>6.2f} , {:>6.2f} )".format(
|
|
||||||
sizes[0], sizes[1], sizes[2]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
logger.info(" Total mass = {:>8.2f} au".format(self.total_mass))
|
|
||||||
|
|
||||||
chg_dip = self.charges_and_dipole()
|
|
||||||
logger.info(" Total charge = {:>8.4f} e".format(chg_dip[0]))
|
|
||||||
logger.info(
|
|
||||||
" Dipole moment = ( {:>9.4f} , {:>9.4f} , {:>9.4f} ) Total = {:>9.4f} Debye".format(
|
|
||||||
chg_dip[1], chg_dip[2], chg_dip[3], chg_dip[4]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def minimum_distance(self, molec: "Molecule") -> float:
|
|
||||||
"""
|
|
||||||
Return the minimum distance between two molecules
|
|
||||||
|
|
||||||
Args:
|
|
||||||
molec (Molecule): Molecule object to be compared
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: minimum distance between the two molecules
|
|
||||||
"""
|
|
||||||
|
|
||||||
distances = []
|
|
||||||
for atom1 in self.atom:
|
|
||||||
if atom1.na != ghost_number:
|
|
||||||
for atom2 in molec.atom:
|
|
||||||
if atom2.na != ghost_number:
|
|
||||||
dx = atom1.rx - atom2.rx
|
|
||||||
dy = atom1.ry - atom2.ry
|
|
||||||
dz = atom1.rz - atom2.rz
|
|
||||||
distances.append(math.sqrt(dx**2 + dy**2 + dz**2))
|
|
||||||
|
|
||||||
return min(distances)
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
from diceplayer import logger
|
|
||||||
from diceplayer.shared.environment.molecule import Molecule
|
|
||||||
from diceplayer.shared.utils.misc import BOHR2ANG
|
|
||||||
from diceplayer.shared.utils.ptable import atomsymb
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from numpy import linalg
|
|
||||||
|
|
||||||
import math
|
|
||||||
from copy import deepcopy
|
|
||||||
from typing import List, TextIO, Tuple
|
|
||||||
|
|
||||||
|
|
||||||
class System:
|
|
||||||
"""
|
|
||||||
System class declaration. This class is used throughout the DicePlayer program to represent the system containing the molecules.
|
|
||||||
|
|
||||||
Atributes:
|
|
||||||
molecule (List[Molecule]): List of molecules of the system
|
|
||||||
nmols (List[int]): List of number of molecules in the system
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
"""
|
|
||||||
Initializes an empty system object that will be populated afterwards
|
|
||||||
"""
|
|
||||||
self.nmols: List[int] = []
|
|
||||||
self.molecule: List[Molecule] = []
|
|
||||||
|
|
||||||
def add_type(self, m: Molecule) -> None:
|
|
||||||
"""
|
|
||||||
Adds a new molecule type to the system
|
|
||||||
|
|
||||||
Args:
|
|
||||||
m (Molecule): The instance of the new type of molecule
|
|
||||||
"""
|
|
||||||
if isinstance(m, Molecule) is False:
|
|
||||||
raise TypeError("Error: molecule is not a Molecule instance")
|
|
||||||
self.molecule.append(m)
|
|
||||||
|
|
||||||
def update_molecule(self, position: np.ndarray) -> None:
|
|
||||||
"""Updates the position of the molecule in the Output file
|
|
||||||
|
|
||||||
Args:
|
|
||||||
position (np.ndarray): numpy position vector
|
|
||||||
"""
|
|
||||||
|
|
||||||
position_in_ang = (position * BOHR2ANG).tolist()
|
|
||||||
self.add_type(deepcopy(self.molecule[0]))
|
|
||||||
|
|
||||||
for atom in self.molecule[-1].atom:
|
|
||||||
atom.rx = position_in_ang.pop(0)
|
|
||||||
atom.ry = position_in_ang.pop(0)
|
|
||||||
atom.rz = position_in_ang.pop(0)
|
|
||||||
|
|
||||||
rmsd, self.molecule[0] = self.rmsd_fit(-1, 0)
|
|
||||||
self.molecule.pop(-1)
|
|
||||||
|
|
||||||
logger.info("Projected new conformation of reference molecule with RMSD fit")
|
|
||||||
logger.info(f"RMSD = {rmsd:>8.5f} Angstrom")
|
|
||||||
|
|
||||||
def rmsd_fit(self, p_index: int, r_index: int) -> Tuple[float, Molecule]:
|
|
||||||
projecting_mol = self.molecule[p_index]
|
|
||||||
reference_mol = self.molecule[r_index]
|
|
||||||
|
|
||||||
if len(projecting_mol.atom) != len(reference_mol.atom):
|
|
||||||
raise RuntimeError(
|
|
||||||
"Error in RMSD fit procedure: molecules have different number of atoms"
|
|
||||||
)
|
|
||||||
dim = len(projecting_mol.atom)
|
|
||||||
|
|
||||||
new_projecting_mol = deepcopy(projecting_mol)
|
|
||||||
new_reference_mol = deepcopy(reference_mol)
|
|
||||||
|
|
||||||
new_projecting_mol.center_of_mass_to_origin()
|
|
||||||
new_reference_mol.center_of_mass_to_origin()
|
|
||||||
|
|
||||||
x = []
|
|
||||||
y = []
|
|
||||||
|
|
||||||
for atom in new_projecting_mol.atom:
|
|
||||||
x.extend([atom.rx, atom.ry, atom.rz])
|
|
||||||
|
|
||||||
for atom in new_reference_mol.atom:
|
|
||||||
y.extend([atom.rx, atom.ry, atom.rz])
|
|
||||||
|
|
||||||
x = np.array(x).reshape(dim, 3)
|
|
||||||
y = np.array(y).reshape(dim, 3)
|
|
||||||
|
|
||||||
r = np.matmul(y.T, x)
|
|
||||||
rr = np.matmul(r.T, r)
|
|
||||||
|
|
||||||
try:
|
|
||||||
evals, evecs = linalg.eigh(rr)
|
|
||||||
except:
|
|
||||||
raise RuntimeError("Error: diagonalization of RR matrix did not converge")
|
|
||||||
|
|
||||||
a1 = evecs[:, 2].T
|
|
||||||
a2 = evecs[:, 1].T
|
|
||||||
a3 = np.cross(a1, a2)
|
|
||||||
|
|
||||||
A = np.array([a1[0], a1[1], a1[2], a2[0], a2[1], a2[2], a3[0], a3[1], a3[2]])
|
|
||||||
A = A.reshape(3, 3)
|
|
||||||
|
|
||||||
b1 = np.matmul(r, a1.T).T # or np.dot(r, a1)
|
|
||||||
b1 /= linalg.norm(b1)
|
|
||||||
b2 = np.matmul(r, a2.T).T # or np.dot(r, a2)
|
|
||||||
b2 /= linalg.norm(b2)
|
|
||||||
b3 = np.cross(b1, b2)
|
|
||||||
|
|
||||||
B = np.array([b1[0], b1[1], b1[2], b2[0], b2[1], b2[2], b3[0], b3[1], b3[2]])
|
|
||||||
B = B.reshape(3, 3).T
|
|
||||||
|
|
||||||
rot_matrix = np.matmul(B, A)
|
|
||||||
x = np.matmul(rot_matrix, x.T).T
|
|
||||||
|
|
||||||
rmsd = 0
|
|
||||||
for i in range(dim):
|
|
||||||
rmsd += (
|
|
||||||
(x[i, 0] - y[i, 0]) ** 2
|
|
||||||
+ (x[i, 1] - y[i, 1]) ** 2
|
|
||||||
+ (x[i, 2] - y[i, 2]) ** 2
|
|
||||||
)
|
|
||||||
rmsd = math.sqrt(rmsd / dim)
|
|
||||||
|
|
||||||
for i in range(dim):
|
|
||||||
new_projecting_mol.atom[i].rx = x[i, 0]
|
|
||||||
new_projecting_mol.atom[i].ry = x[i, 1]
|
|
||||||
new_projecting_mol.atom[i].rz = x[i, 2]
|
|
||||||
|
|
||||||
reference_mol.center_of_mass()
|
|
||||||
|
|
||||||
projected_mol = new_projecting_mol.translate(reference_mol.com)
|
|
||||||
|
|
||||||
return rmsd, projected_mol
|
|
||||||
|
|
||||||
# def center_of_mass_distance(self, a: int, b: int) -> float:
|
|
||||||
# """
|
|
||||||
# Calculates the distance between the center of mass of two molecules
|
|
||||||
#
|
|
||||||
# Args:
|
|
||||||
# a (Molecule): First Molecule Instance
|
|
||||||
# b (Molecule): Second Molecule Instance
|
|
||||||
#
|
|
||||||
# Returns:
|
|
||||||
# float: module of the distance between the two center of masses
|
|
||||||
# """
|
|
||||||
#
|
|
||||||
# com1 = self.molecule[a].center_of_mass()
|
|
||||||
# com2 = self.molecule[b].center_of_mass()
|
|
||||||
# dx = com1[0] - com2[0]
|
|
||||||
# dy = com1[1] - com2[1]
|
|
||||||
# dz = com1[2] - com2[2]
|
|
||||||
# distance = math.sqrt(dx**2 + dy**2 + dz**2)
|
|
||||||
#
|
|
||||||
# return distance
|
|
||||||
|
|
||||||
# def nearest_image(
|
|
||||||
# self,
|
|
||||||
# index_r: int,
|
|
||||||
# index_m: int,
|
|
||||||
# lx: float,
|
|
||||||
# ly: float,
|
|
||||||
# lz: float,
|
|
||||||
# criterium=None,
|
|
||||||
# ) -> Tuple[float, Molecule]:
|
|
||||||
#
|
|
||||||
# if criterium in None:
|
|
||||||
# criterium = "com"
|
|
||||||
#
|
|
||||||
# if criterium != "com" and criterium != "min":
|
|
||||||
# raise RuntimeError("Error in value passed to function nearest_image")
|
|
||||||
#
|
|
||||||
# min_dist = 1e20
|
|
||||||
#
|
|
||||||
# for i in range(-1, 2):
|
|
||||||
# for j in range(-1, 2):
|
|
||||||
# for k in range(-1, 2):
|
|
||||||
#
|
|
||||||
# tr_vector = [i * lx, j * ly, k * lz]
|
|
||||||
# self.add_molecule(self.molecule[index_m].translate(tr_vector))
|
|
||||||
#
|
|
||||||
# if criterium == "com":
|
|
||||||
# dist = self.center_of_mass_distance(index_r, -1)
|
|
||||||
# else:
|
|
||||||
# dist = self.minimum_distance(index_r, -1)
|
|
||||||
#
|
|
||||||
# if dist < min_dist:
|
|
||||||
# min_dist = dist
|
|
||||||
# nearestmol = deepcopy(self.molecule[-1])
|
|
||||||
#
|
|
||||||
# self.molecule.pop(-1)
|
|
||||||
#
|
|
||||||
# return min_dist, nearestmol
|
|
||||||
|
|
||||||
# def print_geom(self, cycle: int, fh: TextIO) -> None:
|
|
||||||
# """
|
|
||||||
# Print the geometry of the molecule in the Output file
|
|
||||||
#
|
|
||||||
# Args:
|
|
||||||
# cycle (int): Number of the cycle
|
|
||||||
# fh (TextIO): Output file
|
|
||||||
# """
|
|
||||||
#
|
|
||||||
# fh.write("Cycle # {}\n".format(cycle))
|
|
||||||
# fh.write("Number of site: {}\n".format(len(self.molecule[0].atom)))
|
|
||||||
# for atom in self.molecule[0].atom:
|
|
||||||
# symbol = atomsymb[atom.na]
|
|
||||||
# fh.write(
|
|
||||||
# "{:<2s} {:>10.6f} {:>10.6f} {:>10.6f}\n".format(
|
|
||||||
# symbol, atom.rx, atom.ry, atom.rz
|
|
||||||
# )
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
def print_charges_and_dipole(self, cycle: int) -> None:
|
|
||||||
"""
|
|
||||||
Print the charges and dipole of the molecule in the Output file
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cycle (int): Number of the cycle
|
|
||||||
fh (TextIO): Output file
|
|
||||||
"""
|
|
||||||
|
|
||||||
logger.info("Cycle # {}\n".format(cycle))
|
|
||||||
logger.info("Number of site: {}\n".format(len(self.molecule[0].atom)))
|
|
||||||
|
|
||||||
chargesAndDipole = self.molecule[0].charges_and_dipole()
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
"{:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n".format(
|
|
||||||
chargesAndDipole[0],
|
|
||||||
chargesAndDipole[1],
|
|
||||||
chargesAndDipole[2],
|
|
||||||
chargesAndDipole[3],
|
|
||||||
chargesAndDipole[4],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
from .__interface import Interface
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from diceplayer.shared.config.player_config import PlayerConfig
|
|
||||||
from diceplayer.shared.environment.system import System
|
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
|
|
||||||
class Interface(ABC):
|
|
||||||
__slots__ = ["step", "system"]
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.system: System | None = None
|
|
||||||
self.step: PlayerConfig | None = None
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def configure(self, step: PlayerConfig, system: System):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def start(self, cycle: int):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def reset(self):
|
|
||||||
pass
|
|
||||||
@@ -1,387 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from diceplayer import logger
|
|
||||||
from diceplayer.shared.config.player_config import PlayerConfig
|
|
||||||
from diceplayer.shared.environment.system import System
|
|
||||||
from diceplayer.shared.interface import Interface
|
|
||||||
|
|
||||||
from setproctitle import setproctitle
|
|
||||||
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
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
|
|
||||||
UMAANG3_TO_GCM3: Final[float] = 1.6605
|
|
||||||
|
|
||||||
MAX_SEED: Final[int] = 4294967295
|
|
||||||
|
|
||||||
|
|
||||||
class DiceInterface(Interface):
|
|
||||||
title = "Diceplayer run"
|
|
||||||
|
|
||||||
def configure(self, step: PlayerConfig, system: System):
|
|
||||||
self.step = step
|
|
||||||
self.system = system
|
|
||||||
|
|
||||||
def start(self, cycle: int):
|
|
||||||
procs = []
|
|
||||||
sentinels = []
|
|
||||||
|
|
||||||
for proc in range(1, self.step.nprocs + 1):
|
|
||||||
p = Process(target=self._simulation_process, args=(cycle, proc))
|
|
||||||
p.start()
|
|
||||||
|
|
||||||
procs.append(p)
|
|
||||||
sentinels.append(p.sentinel)
|
|
||||||
|
|
||||||
while procs:
|
|
||||||
finished = connection.wait(sentinels)
|
|
||||||
for proc_sentinel in finished:
|
|
||||||
i = sentinels.index(proc_sentinel)
|
|
||||||
status = procs[i].exitcode
|
|
||||||
procs.pop(i)
|
|
||||||
sentinels.pop(i)
|
|
||||||
if status != 0:
|
|
||||||
for p in procs:
|
|
||||||
p.terminate()
|
|
||||||
sys.exit(status)
|
|
||||||
|
|
||||||
logger.info("\n")
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
del self.step
|
|
||||||
del self.system
|
|
||||||
|
|
||||||
def _simulation_process(self, cycle: int, proc: int):
|
|
||||||
setproctitle(f"diceplayer-step{cycle:0d}-p{proc:0d}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
self._make_proc_dir(cycle, proc)
|
|
||||||
self._make_dice_inputs(cycle, proc)
|
|
||||||
self._run_dice(cycle, proc)
|
|
||||||
except Exception as err:
|
|
||||||
sys.exit(err)
|
|
||||||
|
|
||||||
def _make_proc_dir(self, cycle, proc):
|
|
||||||
simulation_dir = Path(self.step.simulation_dir)
|
|
||||||
if not simulation_dir.exists():
|
|
||||||
simulation_dir.mkdir(parents=True)
|
|
||||||
|
|
||||||
proc_dir = Path(simulation_dir, f"step{cycle:02d}", f"p{proc:02d}")
|
|
||||||
proc_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
def _make_dice_inputs(self, cycle, proc):
|
|
||||||
proc_dir = Path(self.step.simulation_dir, f"step{cycle:02d}", f"p{proc:02d}")
|
|
||||||
|
|
||||||
self._make_potentials(proc_dir)
|
|
||||||
|
|
||||||
random.seed(self._make_dice_seed())
|
|
||||||
|
|
||||||
# This is logic is used to make the initial configuration file
|
|
||||||
# for the next cycle using the last.xyz file from the previous cycle.
|
|
||||||
if self.step.dice.randominit == "first" and cycle > 1:
|
|
||||||
last_xyz = Path(
|
|
||||||
self.step.simulation_dir,
|
|
||||||
f"step{(cycle - 1):02d}",
|
|
||||||
f"p{proc:02d}",
|
|
||||||
"last.xyz",
|
|
||||||
)
|
|
||||||
if not last_xyz.exists():
|
|
||||||
raise FileNotFoundError(f"File {last_xyz} not found.")
|
|
||||||
|
|
||||||
with open(last_xyz, "r") as last_xyz_file:
|
|
||||||
self._make_init_file(proc_dir, last_xyz_file)
|
|
||||||
last_xyz_file.seek(0)
|
|
||||||
self.step.dice.dens = self._new_density(last_xyz_file)
|
|
||||||
|
|
||||||
else:
|
|
||||||
self._make_nvt_ter(cycle, proc_dir)
|
|
||||||
|
|
||||||
if len(self.step.dice.nstep) == 2:
|
|
||||||
self._make_nvt_eq(cycle, proc_dir)
|
|
||||||
|
|
||||||
elif len(self.step.dice.nstep) == 3:
|
|
||||||
self._make_npt_ter(cycle, proc_dir)
|
|
||||||
self._make_npt_eq(proc_dir)
|
|
||||||
|
|
||||||
def _run_dice(self, cycle: int, proc: int):
|
|
||||||
working_dir = os.getcwd()
|
|
||||||
|
|
||||||
proc_dir = Path(self.step.simulation_dir, f"step{cycle:02d}", f"p{proc:02d}")
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"Simulation process {str(proc_dir)} initiated with pid {os.getpid()}"
|
|
||||||
)
|
|
||||||
|
|
||||||
os.chdir(proc_dir)
|
|
||||||
|
|
||||||
if not (self.step.dice.randominit == "first" and cycle > 1):
|
|
||||||
self.run_dice_file(cycle, proc, "NVT.ter")
|
|
||||||
|
|
||||||
if len(self.step.dice.nstep) == 2:
|
|
||||||
self.run_dice_file(cycle, proc, "NVT.eq")
|
|
||||||
|
|
||||||
elif len(self.step.dice.nstep) == 3:
|
|
||||||
self.run_dice_file(cycle, proc, "NPT.ter")
|
|
||||||
self.run_dice_file(cycle, proc, "NPT.eq")
|
|
||||||
|
|
||||||
os.chdir(working_dir)
|
|
||||||
|
|
||||||
xyz_file = Path(proc_dir, "phb.xyz")
|
|
||||||
last_xyz_file = Path(proc_dir, "last.xyz")
|
|
||||||
|
|
||||||
if xyz_file.exists():
|
|
||||||
shutil.copy(xyz_file, last_xyz_file)
|
|
||||||
else:
|
|
||||||
raise FileNotFoundError(f"File {xyz_file} not found.")
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _make_dice_seed() -> int:
|
|
||||||
num = time.time()
|
|
||||||
num = (num - int(num)) * 1e6
|
|
||||||
|
|
||||||
num = int((num - int(num)) * 1e6)
|
|
||||||
|
|
||||||
return (os.getpid() * num) % (MAX_SEED + 1)
|
|
||||||
|
|
||||||
def _make_init_file(self, proc_dir: Path, last_xyz_file: TextIO):
|
|
||||||
xyz_lines = last_xyz_file.readlines()
|
|
||||||
|
|
||||||
SECONDARY_MOLECULE_LENGTH = 0
|
|
||||||
for i in range(1, len(self.step.dice.nmol)):
|
|
||||||
SECONDARY_MOLECULE_LENGTH += self.step.dice.nmol[i] * len(
|
|
||||||
self.system.molecule[i].atom
|
|
||||||
)
|
|
||||||
|
|
||||||
xyz_lines = xyz_lines[-SECONDARY_MOLECULE_LENGTH:]
|
|
||||||
|
|
||||||
input_file = Path(proc_dir, self.step.dice.outname + ".xy")
|
|
||||||
with open(input_file, "w") as f:
|
|
||||||
for atom in self.system.molecule[0].atom:
|
|
||||||
f.write(f"{atom.rx:>10.6f} {atom.ry:>10.6f} {atom.rz:>10.6f}\n")
|
|
||||||
|
|
||||||
for line in xyz_lines:
|
|
||||||
atom = line.split()
|
|
||||||
rx = float(atom[1])
|
|
||||||
ry = float(atom[2])
|
|
||||||
rz = float(atom[3])
|
|
||||||
f.write(f"{rx:>10.6f} {ry:>10.6f} {rz:>10.6f}\n")
|
|
||||||
|
|
||||||
f.write("$end")
|
|
||||||
|
|
||||||
def _new_density(self, last_xyz_file: TextIO):
|
|
||||||
last_xyz_lines = last_xyz_file.readlines()
|
|
||||||
|
|
||||||
box = last_xyz_lines[1].split()
|
|
||||||
volume = float(box[-3]) * float(box[-2]) * float(box[-1])
|
|
||||||
|
|
||||||
total_mass = 0
|
|
||||||
for i in range(len(self.system.molecule)):
|
|
||||||
total_mass += self.system.molecule[i].total_mass * self.step.dice.nmol[i]
|
|
||||||
|
|
||||||
density = (total_mass / volume) * UMAANG3_TO_GCM3
|
|
||||||
|
|
||||||
return density
|
|
||||||
|
|
||||||
def _make_nvt_ter(self, cycle, proc_dir):
|
|
||||||
file = Path(proc_dir, "NVT.ter")
|
|
||||||
with open(file, "w") as f:
|
|
||||||
f.write(f"title = {self.title} - NVT Thermalization\n")
|
|
||||||
f.write(f"ncores = {self.step.ncores}\n")
|
|
||||||
f.write(f"ljname = {self.step.dice.ljname}\n")
|
|
||||||
f.write(f"outname = {self.step.dice.outname}\n")
|
|
||||||
|
|
||||||
mol_string = " ".join(str(x) for x in self.step.dice.nmol)
|
|
||||||
f.write(f"nmol = {mol_string}\n")
|
|
||||||
|
|
||||||
f.write(f"dens = {self.step.dice.dens}\n")
|
|
||||||
f.write(f"temp = {self.step.dice.temp}\n")
|
|
||||||
|
|
||||||
if self.step.dice.randominit == "first" and cycle > 1:
|
|
||||||
f.write(f"init = yesreadxyz\n")
|
|
||||||
f.write(f"nstep = {self.step.altsteps}\n")
|
|
||||||
else:
|
|
||||||
f.write(f"init = yes\n")
|
|
||||||
f.write(f"nstep = {self.step.dice.nstep[0]}\n")
|
|
||||||
|
|
||||||
f.write("vstep = 0\n")
|
|
||||||
f.write("mstop = 1\n")
|
|
||||||
f.write("accum = no\n")
|
|
||||||
f.write("iprint = 1\n")
|
|
||||||
f.write("isave = 0\n")
|
|
||||||
f.write("irdf = 0\n")
|
|
||||||
|
|
||||||
seed = int(1e6 * random.random())
|
|
||||||
f.write(f"seed = {seed}\n")
|
|
||||||
f.write(f"upbuf = {self.step.dice.upbuf}")
|
|
||||||
|
|
||||||
def _make_nvt_eq(self, cycle, proc_dir):
|
|
||||||
file = Path(proc_dir, "NVT.eq")
|
|
||||||
with open(file, "w") as f:
|
|
||||||
f.write(f"title = {self.title} - NVT Production\n")
|
|
||||||
f.write(f"ncores = {self.step.ncores}\n")
|
|
||||||
f.write(f"ljname = {self.step.dice.ljname}\n")
|
|
||||||
f.write(f"outname = {self.step.dice.outname}\n")
|
|
||||||
|
|
||||||
mol_string = " ".join(str(x) for x in self.step.dice.nmol)
|
|
||||||
f.write(f"nmol = {mol_string}\n")
|
|
||||||
|
|
||||||
f.write(f"dens = {self.step.dice.dens}\n")
|
|
||||||
f.write(f"temp = {self.step.dice.temp}\n")
|
|
||||||
|
|
||||||
if self.step.dice.randominit == "first" and cycle > 1:
|
|
||||||
f.write("init = yesreadxyz\n")
|
|
||||||
else:
|
|
||||||
f.write("init = no\n")
|
|
||||||
|
|
||||||
f.write(f"nstep = {self.step.dice.nstep[1]}\n")
|
|
||||||
|
|
||||||
f.write("vstep = 0\n")
|
|
||||||
f.write("mstop = 1\n")
|
|
||||||
f.write("accum = no\n")
|
|
||||||
f.write("iprint = 1\n")
|
|
||||||
|
|
||||||
f.write(f"isave = {self.step.dice.isave}\n")
|
|
||||||
f.write(f"irdf = {10 * self.step.nprocs}\n")
|
|
||||||
|
|
||||||
seed = int(1e6 * random.random())
|
|
||||||
f.write("seed = {}\n".format(seed))
|
|
||||||
|
|
||||||
def _make_npt_ter(self, cycle, proc_dir):
|
|
||||||
file = Path(proc_dir, "NPT.ter")
|
|
||||||
with open(file, "w") as f:
|
|
||||||
f.write(f"title = {self.title} - NPT Thermalization\n")
|
|
||||||
f.write(f"ncores = {self.step.ncores}\n")
|
|
||||||
f.write(f"ljname = {self.step.dice.ljname}\n")
|
|
||||||
f.write(f"outname = {self.step.dice.outname}\n")
|
|
||||||
|
|
||||||
mol_string = " ".join(str(x) for x in self.step.dice.nmol)
|
|
||||||
f.write(f"nmol = {mol_string}\n")
|
|
||||||
|
|
||||||
f.write(f"press = {self.step.dice.press}\n")
|
|
||||||
f.write(f"temp = {self.step.dice.temp}\n")
|
|
||||||
|
|
||||||
if self.step.dice.randominit == "first" and cycle > 1:
|
|
||||||
f.write("init = yesreadxyz\n")
|
|
||||||
f.write(f"dens = {self.step.dice.dens:<8.4f}\n")
|
|
||||||
f.write(f"vstep = {int(self.step.altsteps / 5)}\n")
|
|
||||||
else:
|
|
||||||
f.write("init = no\n")
|
|
||||||
f.write(f"vstep = {int(self.step.dice.nstep[1] / 5)}\n")
|
|
||||||
|
|
||||||
f.write("nstep = 5\n")
|
|
||||||
f.write("mstop = 1\n")
|
|
||||||
f.write("accum = no\n")
|
|
||||||
f.write("iprint = 1\n")
|
|
||||||
f.write("isave = 0\n")
|
|
||||||
f.write("irdf = 0\n")
|
|
||||||
|
|
||||||
seed = int(1e6 * random.random())
|
|
||||||
f.write(f"seed = {seed}\n")
|
|
||||||
|
|
||||||
def _make_npt_eq(self, proc_dir):
|
|
||||||
file = Path(proc_dir, "NPT.eq")
|
|
||||||
with open(file, "w") as f:
|
|
||||||
f.write(f"title = {self.title} - NPT Production\n")
|
|
||||||
f.write(f"ncores = {self.step.ncores}\n")
|
|
||||||
f.write(f"ljname = {self.step.dice.ljname}\n")
|
|
||||||
f.write(f"outname = {self.step.dice.outname}\n")
|
|
||||||
|
|
||||||
mol_string = " ".join(str(x) for x in self.step.dice.nmol)
|
|
||||||
f.write(f"nmol = {mol_string}\n")
|
|
||||||
|
|
||||||
f.write(f"press = {self.step.dice.press}\n")
|
|
||||||
f.write(f"temp = {self.step.dice.temp}\n")
|
|
||||||
|
|
||||||
f.write(f"nstep = 5\n")
|
|
||||||
|
|
||||||
f.write(f"vstep = {int(self.step.dice.nstep[2] / 5)}\n")
|
|
||||||
f.write("init = no\n")
|
|
||||||
f.write("mstop = 1\n")
|
|
||||||
f.write("accum = no\n")
|
|
||||||
f.write("iprint = 1\n")
|
|
||||||
f.write(f"isave = {self.step.dice.isave}\n")
|
|
||||||
f.write(f"irdf = {10 * self.step.nprocs}\n")
|
|
||||||
|
|
||||||
seed = int(1e6 * random.random())
|
|
||||||
f.write(f"seed = {seed}\n")
|
|
||||||
|
|
||||||
def _make_potentials(self, proc_dir):
|
|
||||||
fstr = "{:<3d} {:>3d} {:>10.5f} {:>10.5f} {:>10.5f} {:>10.6f} {:>9.5f} {:>7.4f}\n"
|
|
||||||
|
|
||||||
file = Path(proc_dir, self.step.dice.ljname)
|
|
||||||
with open(file, "w") as f:
|
|
||||||
f.write(f"{self.step.dice.combrule}\n")
|
|
||||||
f.write(f"{len(self.step.dice.nmol)}\n")
|
|
||||||
|
|
||||||
nsites_qm = len(self.system.molecule[0].atom)
|
|
||||||
f.write(f"{nsites_qm} {self.system.molecule[0].molname}\n")
|
|
||||||
|
|
||||||
for atom in self.system.molecule[0].atom:
|
|
||||||
f.write(
|
|
||||||
fstr.format(
|
|
||||||
atom.lbl,
|
|
||||||
atom.na,
|
|
||||||
atom.rx,
|
|
||||||
atom.ry,
|
|
||||||
atom.rz,
|
|
||||||
atom.chg,
|
|
||||||
atom.eps,
|
|
||||||
atom.sig,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for mol in self.system.molecule[1:]:
|
|
||||||
f.write(f"{len(mol.atom)} {mol.molname}\n")
|
|
||||||
for atom in mol.atom:
|
|
||||||
f.write(
|
|
||||||
fstr.format(
|
|
||||||
atom.lbl,
|
|
||||||
atom.na,
|
|
||||||
atom.rx,
|
|
||||||
atom.ry,
|
|
||||||
atom.rz,
|
|
||||||
atom.chg,
|
|
||||||
atom.eps,
|
|
||||||
atom.sig,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
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:
|
|
||||||
if shutil.which("bash") is not None:
|
|
||||||
exit_status = subprocess.call(
|
|
||||||
[
|
|
||||||
"bash",
|
|
||||||
"-c",
|
|
||||||
f"exec -a dice-step{cycle}-p{proc} {self.step.dice.progname} < {infile.name} > {outfile.name}",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
exit_status = subprocess.call(
|
|
||||||
self.step.dice.progname, stdin=infile, stdout=outfile
|
|
||||||
)
|
|
||||||
|
|
||||||
if exit_status != 0:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly"
|
|
||||||
)
|
|
||||||
|
|
||||||
with open(Path(file_name + ".out"), "r") as outfile:
|
|
||||||
flag = outfile.readlines()[DICE_FLAG_LINE].strip()
|
|
||||||
if flag != DICE_END_FLAG:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"Dice process step{cycle:02d}-p{proc:02d} did not exit properly"
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(f"Dice {file_name} - step{cycle:02d}-p{proc:02d} exited properly")
|
|
||||||
@@ -1,359 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from diceplayer import logger
|
|
||||||
from diceplayer.shared.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
|
|
||||||
from diceplayer.shared.interface import Interface
|
|
||||||
from diceplayer.shared.utils.misc import date_time
|
|
||||||
from diceplayer.shared.utils.ptable import atomsymb
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from nptyping import NDArray
|
|
||||||
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import textwrap
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any, Dict, List, Tuple
|
|
||||||
|
|
||||||
|
|
||||||
class GaussianInterface(Interface):
|
|
||||||
def configure(self, step_dto: PlayerConfig, system: System):
|
|
||||||
self.system = system
|
|
||||||
self.step = step_dto
|
|
||||||
|
|
||||||
def start(self, cycle: int) -> Dict[str, NDArray]:
|
|
||||||
self._make_qm_dir(cycle)
|
|
||||||
|
|
||||||
if cycle > 1:
|
|
||||||
self._copy_chk_file_from_previous_step(cycle)
|
|
||||||
|
|
||||||
asec_charges = self.populate_asec_vdw(cycle)
|
|
||||||
self._make_gaussian_input_file(cycle, asec_charges)
|
|
||||||
|
|
||||||
self._run_gaussian(cycle)
|
|
||||||
self._run_formchk(cycle)
|
|
||||||
|
|
||||||
return_value = {}
|
|
||||||
if self.step.opt:
|
|
||||||
# return_value['position'] = np.array(
|
|
||||||
# self._run_optimization(cycle)
|
|
||||||
# )
|
|
||||||
raise NotImplementedError("Optimization not implemented yet.")
|
|
||||||
|
|
||||||
else:
|
|
||||||
return_value["charges"] = np.array(self._read_charges_from_fchk(cycle))
|
|
||||||
|
|
||||||
return return_value
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
del self.step
|
|
||||||
del self.system
|
|
||||||
|
|
||||||
def _make_qm_dir(self, cycle: int):
|
|
||||||
qm_dir_path = Path(self.step.simulation_dir, f"step{cycle:02d}", "qm")
|
|
||||||
if not qm_dir_path.exists():
|
|
||||||
qm_dir_path.mkdir()
|
|
||||||
|
|
||||||
def _copy_chk_file_from_previous_step(self, cycle: int):
|
|
||||||
current_chk_file_path = Path(
|
|
||||||
self.step.simulation_dir, f"step{cycle:02d}", "qm", f"asec.chk"
|
|
||||||
)
|
|
||||||
if current_chk_file_path.exists():
|
|
||||||
raise FileExistsError(f"File {current_chk_file_path} already exists.")
|
|
||||||
|
|
||||||
previous_chk_file_path = Path(
|
|
||||||
self.step.simulation_dir, f"step{(cycle - 1):02d}", "qm", f"asec.chk"
|
|
||||||
)
|
|
||||||
if not previous_chk_file_path.exists():
|
|
||||||
raise FileNotFoundError(f"File {previous_chk_file_path} does not exist.")
|
|
||||||
|
|
||||||
shutil.copy(previous_chk_file_path, current_chk_file_path)
|
|
||||||
|
|
||||||
def populate_asec_vdw(self, cycle: int) -> list[dict]:
|
|
||||||
norm_factor = self._calculate_norm_factor()
|
|
||||||
|
|
||||||
nsitesref = len(self.system.molecule[0].atom)
|
|
||||||
|
|
||||||
nsites_total = self._calculate_total_number_of_sites(nsitesref)
|
|
||||||
|
|
||||||
proc_charges = []
|
|
||||||
for proc in range(1, self.step.nprocs + 1):
|
|
||||||
proc_charges.append(self._read_charges_from_last_step(cycle, proc))
|
|
||||||
|
|
||||||
asec_charges, thickness, picked_mols = self._evaluate_proc_charges(
|
|
||||||
nsites_total, proc_charges
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"In average, {(sum(picked_mols) / norm_factor):^7.2f} molecules\n"
|
|
||||||
f"were selected from each of the {len(picked_mols)} configurations\n"
|
|
||||||
f"of the production simulations to form the ASEC, comprising a shell with\n"
|
|
||||||
f"minimum thickness of {(sum(thickness) / norm_factor):>6.2f} Angstrom\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
for charge in asec_charges:
|
|
||||||
charge["chg"] = charge["chg"] / norm_factor
|
|
||||||
|
|
||||||
return asec_charges
|
|
||||||
|
|
||||||
def _calculate_norm_factor(self) -> int:
|
|
||||||
if self.step.dice.nstep[-1] % self.step.dice.isave == 0:
|
|
||||||
nconfigs = round(self.step.dice.nstep[-1] / self.step.dice.isave)
|
|
||||||
else:
|
|
||||||
nconfigs = int(self.step.dice.nstep[-1] / self.step.dice.isave)
|
|
||||||
|
|
||||||
return nconfigs * self.step.nprocs
|
|
||||||
|
|
||||||
def _calculate_total_number_of_sites(self, nsitesref) -> int:
|
|
||||||
nsites_total = self.step.dice.nmol[0] * nsitesref
|
|
||||||
for i in range(1, len(self.step.dice.nmol)):
|
|
||||||
nsites_total += self.step.dice.nmol[i] * len(self.system.molecule[i].atom)
|
|
||||||
|
|
||||||
return nsites_total
|
|
||||||
|
|
||||||
def _read_charges_from_last_step(self, cycle: int, proc: int) -> list[str]:
|
|
||||||
last_xyz_file_path = Path(
|
|
||||||
self.step.simulation_dir, f"step{cycle:02d}", f"p{proc:02d}", "last.xyz"
|
|
||||||
)
|
|
||||||
if not last_xyz_file_path.exists():
|
|
||||||
raise FileNotFoundError(f"File {last_xyz_file_path} does not exist.")
|
|
||||||
|
|
||||||
with open(last_xyz_file_path, "r") as last_xyz_file:
|
|
||||||
lines = last_xyz_file.readlines()
|
|
||||||
|
|
||||||
return lines
|
|
||||||
|
|
||||||
def _evaluate_proc_charges(
|
|
||||||
self, total_nsites: int, proc_charges: list[list[str]]
|
|
||||||
) -> Tuple[List[Dict[str, float | Any]], List[float], List[int]]:
|
|
||||||
asec_charges = []
|
|
||||||
|
|
||||||
thickness = []
|
|
||||||
picked_mols = []
|
|
||||||
|
|
||||||
for charges in proc_charges:
|
|
||||||
charges_nsites = int(charges.pop(0))
|
|
||||||
if int(charges_nsites) != total_nsites:
|
|
||||||
raise ValueError(
|
|
||||||
f"Number of sites does not match total number of sites."
|
|
||||||
)
|
|
||||||
|
|
||||||
thickness.append(self._calculate_proc_thickness(charges))
|
|
||||||
nsites_ref_mol = len(self.system.molecule[0].atom)
|
|
||||||
charges = charges[nsites_ref_mol:]
|
|
||||||
|
|
||||||
mol_count = 0
|
|
||||||
for type in range(len(self.step.dice.nmol)):
|
|
||||||
if type == 0:
|
|
||||||
# Reference Molecule must be ignored from type 0
|
|
||||||
nmols = self.step.dice.nmol[type] - 1
|
|
||||||
else:
|
|
||||||
nmols = self.step.dice.nmol[type]
|
|
||||||
|
|
||||||
for mol in range(nmols):
|
|
||||||
new_molecule = Molecule("ASEC TMP MOLECULE")
|
|
||||||
for site in range(len(self.system.molecule[type].atom)):
|
|
||||||
line = charges.pop(0).split()
|
|
||||||
|
|
||||||
if (
|
|
||||||
line[0].title()
|
|
||||||
!= atomsymb[
|
|
||||||
self.system.molecule[type].atom[site].na
|
|
||||||
].strip()
|
|
||||||
):
|
|
||||||
raise SyntaxError(
|
|
||||||
f"Error: Invalid Dice Output. Atom type does not match."
|
|
||||||
)
|
|
||||||
|
|
||||||
new_molecule.add_atom(
|
|
||||||
Atom(
|
|
||||||
self.system.molecule[type].atom[site].lbl,
|
|
||||||
self.system.molecule[type].atom[site].na,
|
|
||||||
float(line[1]),
|
|
||||||
float(line[2]),
|
|
||||||
float(line[3]),
|
|
||||||
self.system.molecule[type].atom[site].chg,
|
|
||||||
self.system.molecule[type].atom[site].eps,
|
|
||||||
self.system.molecule[type].atom[site].sig,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
distance = self.system.molecule[0].minimum_distance(new_molecule)
|
|
||||||
|
|
||||||
if distance < thickness[-1]:
|
|
||||||
for atom in new_molecule.atom:
|
|
||||||
asec_charges.append(
|
|
||||||
{
|
|
||||||
"lbl": atomsymb[atom.na],
|
|
||||||
"rx": atom.rx,
|
|
||||||
"ry": atom.ry,
|
|
||||||
"rz": atom.rz,
|
|
||||||
"chg": atom.chg,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
mol_count += 1
|
|
||||||
|
|
||||||
picked_mols.append(mol_count)
|
|
||||||
|
|
||||||
return asec_charges, thickness, picked_mols
|
|
||||||
|
|
||||||
def _calculate_proc_thickness(self, charges: list[str]) -> float:
|
|
||||||
box = charges.pop(0).split()[-3:]
|
|
||||||
box = [float(box[0]), float(box[1]), float(box[2])]
|
|
||||||
sizes = self.system.molecule[0].sizes_of_molecule()
|
|
||||||
|
|
||||||
return min(
|
|
||||||
[
|
|
||||||
(box[0] - sizes[0]) / 2,
|
|
||||||
(box[1] - sizes[1]) / 2,
|
|
||||||
(box[2] - sizes[2]) / 2,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def _make_gaussian_input_file(self, cycle: int, asec_charges: list[dict]) -> None:
|
|
||||||
gaussian_input_file_path = Path(
|
|
||||||
self.step.simulation_dir, f"step{cycle:02d}", "qm", f"asec.gjf"
|
|
||||||
)
|
|
||||||
|
|
||||||
with open(gaussian_input_file_path, "w") as gaussian_input_file:
|
|
||||||
gaussian_input_file.writelines(
|
|
||||||
self._generate_gaussian_input(cycle, asec_charges)
|
|
||||||
)
|
|
||||||
|
|
||||||
def _generate_gaussian_input(
|
|
||||||
self, cycle: int, asec_charges: list[dict]
|
|
||||||
) -> list[str]:
|
|
||||||
gaussian_input = ["%Chk=asec.chk\n"]
|
|
||||||
|
|
||||||
if self.step.mem is not None:
|
|
||||||
gaussian_input.append(f"%Mem={self.step.mem}GB\n")
|
|
||||||
|
|
||||||
gaussian_input.append(f"%Nprocs={self.step.nprocs * self.step.ncores}\n")
|
|
||||||
|
|
||||||
kwords_line = f"#P {self.step.gaussian.level}"
|
|
||||||
|
|
||||||
if self.step.gaussian.keywords:
|
|
||||||
kwords_line += " " + self.step.gaussian.keywords
|
|
||||||
|
|
||||||
if self.step.opt == "yes":
|
|
||||||
kwords_line += " Force"
|
|
||||||
|
|
||||||
kwords_line += " NoSymm"
|
|
||||||
kwords_line += f" Pop={self.step.gaussian.pop} Density=Current"
|
|
||||||
|
|
||||||
if cycle > 1:
|
|
||||||
kwords_line += " Guess=Read"
|
|
||||||
|
|
||||||
gaussian_input.append(textwrap.fill(kwords_line, 90))
|
|
||||||
gaussian_input.append("\n")
|
|
||||||
|
|
||||||
gaussian_input.append("\nForce calculation - Cycle number {}\n".format(cycle))
|
|
||||||
gaussian_input.append("\n")
|
|
||||||
gaussian_input.append(
|
|
||||||
f"{self.step.gaussian.chgmult[0]},{self.step.gaussian.chgmult[1]}\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
for atom in self.system.molecule[0].atom:
|
|
||||||
symbol = atomsymb[atom.na]
|
|
||||||
gaussian_input.append(
|
|
||||||
"{:<2s} {:>10.5f} {:>10.5f} {:>10.5f}\n".format(
|
|
||||||
symbol, atom.rx, atom.ry, atom.rz
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
gaussian_input.append("\n")
|
|
||||||
|
|
||||||
for charge in asec_charges:
|
|
||||||
gaussian_input.append(
|
|
||||||
"{:>10.5f} {:>10.5f} {:>10.5f} {:>11.8f}\n".format(
|
|
||||||
charge["rx"], charge["ry"], charge["rz"], charge["chg"]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
gaussian_input.append("\n")
|
|
||||||
|
|
||||||
return gaussian_input
|
|
||||||
|
|
||||||
def _run_gaussian(self, cycle: int) -> None:
|
|
||||||
qm_dir = Path(self.step.simulation_dir, f"step{(cycle):02d}", "qm")
|
|
||||||
|
|
||||||
working_dir = os.getcwd()
|
|
||||||
os.chdir(qm_dir)
|
|
||||||
|
|
||||||
infile = "asec.gjf"
|
|
||||||
|
|
||||||
operation = None
|
|
||||||
if self.step.opt:
|
|
||||||
operation = "forces"
|
|
||||||
else:
|
|
||||||
operation = "charges"
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
f"Calculation of {operation} initiated with Gaussian on {date_time()}\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
if shutil.which("bash") is not None:
|
|
||||||
exit_status = subprocess.call(
|
|
||||||
[
|
|
||||||
"bash",
|
|
||||||
"-c",
|
|
||||||
"exec -a {}-step{} {} {}".format(
|
|
||||||
self.step.gaussian.qmprog,
|
|
||||||
cycle,
|
|
||||||
self.step.gaussian.qmprog,
|
|
||||||
infile,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
exit_status = subprocess.call([self.step.gaussian.qmprog, infile])
|
|
||||||
|
|
||||||
if exit_status != 0:
|
|
||||||
raise SystemError("Gaussian process did not exit properly")
|
|
||||||
|
|
||||||
logger.info(f"Calculation of {operation} finished on {date_time()}")
|
|
||||||
|
|
||||||
os.chdir(working_dir)
|
|
||||||
|
|
||||||
def _run_formchk(self, cycle: int):
|
|
||||||
qm_dir = Path(self.step.simulation_dir, f"step{(cycle):02d}", "qm")
|
|
||||||
|
|
||||||
work_dir = os.getcwd()
|
|
||||||
os.chdir(qm_dir)
|
|
||||||
|
|
||||||
logger.info("Formatting the checkpoint file... \n")
|
|
||||||
|
|
||||||
exit_status = subprocess.call(
|
|
||||||
["formchk", "asec.chk"], stdout=subprocess.DEVNULL
|
|
||||||
)
|
|
||||||
|
|
||||||
if exit_status != 0:
|
|
||||||
raise SystemError("Formchk process did not exit properly")
|
|
||||||
|
|
||||||
logger.info("Done\n")
|
|
||||||
|
|
||||||
os.chdir(work_dir)
|
|
||||||
|
|
||||||
def _read_charges_from_fchk(self, cycle: int):
|
|
||||||
fchk_file_path = Path("simfiles", f"step{cycle:02d}", "qm", "asec.fchk")
|
|
||||||
with open(fchk_file_path) as fchk:
|
|
||||||
fchkfile = fchk.readlines()
|
|
||||||
|
|
||||||
if self.step.gaussian.pop in ["chelpg", "mk"]:
|
|
||||||
CHARGE_FLAG = "ESP Charges"
|
|
||||||
else:
|
|
||||||
CHARGE_FLAG = "ESP Charges"
|
|
||||||
|
|
||||||
start = fchkfile.pop(0).strip()
|
|
||||||
while start.find(CHARGE_FLAG) != 0: # expression in begining of line
|
|
||||||
start = fchkfile.pop(0).strip()
|
|
||||||
|
|
||||||
charges: List[float] = []
|
|
||||||
while len(charges) < len(self.system.molecule[0].atom):
|
|
||||||
charges.extend([float(x) for x in fchkfile.pop(0).split()])
|
|
||||||
|
|
||||||
return charges
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from typing import Protocol, runtime_checkable
|
|
||||||
|
|
||||||
|
|
||||||
@runtime_checkable
|
|
||||||
class Dataclass(Protocol):
|
|
||||||
__dataclass_fields__: dict
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import logging
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
def valid_logger(func):
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
logger = args[0]
|
|
||||||
assert logger._was_set, "Logger is not set. Please call set_logger() first."
|
|
||||||
|
|
||||||
return func(*args, **kwargs)
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
class Logger:
|
|
||||||
outfile = None
|
|
||||||
|
|
||||||
_logger = None
|
|
||||||
|
|
||||||
_was_set = False
|
|
||||||
|
|
||||||
def __init__(self, logger_name):
|
|
||||||
if self._logger is None:
|
|
||||||
self._logger = logging.getLogger(logger_name)
|
|
||||||
|
|
||||||
def set_logger(self, outfile="run.log", level=logging.INFO, stream=None):
|
|
||||||
outfile_path = None
|
|
||||||
if outfile is not None and stream is None:
|
|
||||||
outfile_path = Path(outfile)
|
|
||||||
if outfile_path.exists():
|
|
||||||
outfile_path.rename(str(outfile_path) + ".backup")
|
|
||||||
|
|
||||||
if level is not None:
|
|
||||||
self._logger.setLevel(level)
|
|
||||||
|
|
||||||
self._create_handlers(outfile_path, stream)
|
|
||||||
|
|
||||||
self._was_set = True
|
|
||||||
|
|
||||||
@valid_logger
|
|
||||||
def info(self, message):
|
|
||||||
self._logger.info(message)
|
|
||||||
|
|
||||||
@valid_logger
|
|
||||||
def debug(self, message):
|
|
||||||
self._logger.debug(message)
|
|
||||||
|
|
||||||
@valid_logger
|
|
||||||
def warning(self, message):
|
|
||||||
self._logger.warning(message)
|
|
||||||
|
|
||||||
@valid_logger
|
|
||||||
def error(self, message):
|
|
||||||
self._logger.error(message)
|
|
||||||
|
|
||||||
def _create_handlers(self, outfile_path: Path, stream):
|
|
||||||
handlers = []
|
|
||||||
if outfile_path is not None:
|
|
||||||
handlers.append(logging.FileHandler(outfile_path, mode="a+"))
|
|
||||||
elif stream is not None:
|
|
||||||
handlers.append(logging.StreamHandler(stream))
|
|
||||||
else:
|
|
||||||
handlers.append(logging.StreamHandler())
|
|
||||||
|
|
||||||
for handler in handlers:
|
|
||||||
handler.setFormatter(logging.Formatter("%(message)s"))
|
|
||||||
self._logger.addHandler(handler)
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
for handler in self._logger.handlers:
|
|
||||||
handler.close()
|
|
||||||
self._logger.removeHandler(handler)
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
#### Label used in Dice for a ghost atom
|
|
||||||
dice_ghost_label = "Xx"
|
|
||||||
|
|
||||||
#### Tuple of atom symbols
|
|
||||||
atomsymb = (
|
|
||||||
"00",
|
|
||||||
"H ",
|
|
||||||
"He",
|
|
||||||
"Li",
|
|
||||||
"Be",
|
|
||||||
"B ",
|
|
||||||
"C ",
|
|
||||||
"N ",
|
|
||||||
"O ",
|
|
||||||
"F ",
|
|
||||||
"Ne",
|
|
||||||
"Na",
|
|
||||||
"Mg",
|
|
||||||
"Al",
|
|
||||||
"Si",
|
|
||||||
"P ",
|
|
||||||
"S ",
|
|
||||||
"Cl",
|
|
||||||
"Ar",
|
|
||||||
"K ",
|
|
||||||
"Ca",
|
|
||||||
"Sc",
|
|
||||||
"Ti",
|
|
||||||
"V ",
|
|
||||||
"Cr",
|
|
||||||
"Mn",
|
|
||||||
"Fe",
|
|
||||||
"Co",
|
|
||||||
"Ni",
|
|
||||||
"Cu",
|
|
||||||
"Zn",
|
|
||||||
"Ga",
|
|
||||||
"Ge",
|
|
||||||
"As",
|
|
||||||
"Se",
|
|
||||||
"Br",
|
|
||||||
"Kr",
|
|
||||||
"Rb",
|
|
||||||
"Sr",
|
|
||||||
"Y ",
|
|
||||||
"Zr",
|
|
||||||
"Nb",
|
|
||||||
"Mo",
|
|
||||||
"Tc",
|
|
||||||
"Ru",
|
|
||||||
"Rh",
|
|
||||||
"Pd",
|
|
||||||
"Ag",
|
|
||||||
"Cd",
|
|
||||||
"In",
|
|
||||||
"Sn",
|
|
||||||
"Sb",
|
|
||||||
"Te",
|
|
||||||
"I ",
|
|
||||||
"Xe",
|
|
||||||
"Cs",
|
|
||||||
"Ba",
|
|
||||||
"La",
|
|
||||||
"Ce",
|
|
||||||
"Pr",
|
|
||||||
"Nd",
|
|
||||||
"Pm",
|
|
||||||
"Sm",
|
|
||||||
"Eu",
|
|
||||||
"Gd",
|
|
||||||
"Tb",
|
|
||||||
"Dy",
|
|
||||||
"Ho",
|
|
||||||
"Er",
|
|
||||||
"Tm",
|
|
||||||
"Yb",
|
|
||||||
"Lu",
|
|
||||||
"Hf",
|
|
||||||
"Ta",
|
|
||||||
"W ",
|
|
||||||
"Re",
|
|
||||||
"Os",
|
|
||||||
"Ir",
|
|
||||||
"Pt",
|
|
||||||
"Au",
|
|
||||||
"Hg",
|
|
||||||
"Ti",
|
|
||||||
"Pb",
|
|
||||||
"Bi",
|
|
||||||
"Po",
|
|
||||||
"At",
|
|
||||||
"Rn",
|
|
||||||
"Fr",
|
|
||||||
"Ra",
|
|
||||||
"Ac",
|
|
||||||
"Th",
|
|
||||||
"Pa",
|
|
||||||
"U ",
|
|
||||||
"Np",
|
|
||||||
"Pu",
|
|
||||||
"Am",
|
|
||||||
"Cm",
|
|
||||||
"Bk",
|
|
||||||
"Cf",
|
|
||||||
"Es",
|
|
||||||
"Fm",
|
|
||||||
"Md",
|
|
||||||
"No",
|
|
||||||
"Lr",
|
|
||||||
dice_ghost_label,
|
|
||||||
)
|
|
||||||
|
|
||||||
#### Tuple of atom masses
|
|
||||||
atommass = (
|
|
||||||
0.0,
|
|
||||||
1.0079,
|
|
||||||
4.0026,
|
|
||||||
6.9410,
|
|
||||||
9.0122,
|
|
||||||
10.811,
|
|
||||||
12.011,
|
|
||||||
14.007,
|
|
||||||
15.999,
|
|
||||||
18.998,
|
|
||||||
20.180,
|
|
||||||
22.990,
|
|
||||||
24.305,
|
|
||||||
26.982,
|
|
||||||
28.086,
|
|
||||||
30.974,
|
|
||||||
32.065,
|
|
||||||
35.453,
|
|
||||||
39.948,
|
|
||||||
39.098,
|
|
||||||
40.078,
|
|
||||||
44.956,
|
|
||||||
47.867,
|
|
||||||
50.942,
|
|
||||||
51.996,
|
|
||||||
54.938,
|
|
||||||
55.845,
|
|
||||||
58.933,
|
|
||||||
58.693,
|
|
||||||
63.546,
|
|
||||||
65.409,
|
|
||||||
69.723,
|
|
||||||
72.640,
|
|
||||||
74.922,
|
|
||||||
78.960,
|
|
||||||
79.904,
|
|
||||||
83.798,
|
|
||||||
85.468,
|
|
||||||
87.620,
|
|
||||||
88.906,
|
|
||||||
91.224,
|
|
||||||
92.906,
|
|
||||||
95.940,
|
|
||||||
98.000,
|
|
||||||
101.07,
|
|
||||||
102.91,
|
|
||||||
106.42,
|
|
||||||
107.87,
|
|
||||||
112.41,
|
|
||||||
114.82,
|
|
||||||
118.71,
|
|
||||||
121.76,
|
|
||||||
127.60,
|
|
||||||
126.90,
|
|
||||||
131.29,
|
|
||||||
132.91,
|
|
||||||
137.33,
|
|
||||||
138.91,
|
|
||||||
140.12,
|
|
||||||
140.91,
|
|
||||||
144.24,
|
|
||||||
145.00,
|
|
||||||
150.36,
|
|
||||||
151.96,
|
|
||||||
157.25,
|
|
||||||
158.93,
|
|
||||||
162.50,
|
|
||||||
164.93,
|
|
||||||
167.26,
|
|
||||||
168.93,
|
|
||||||
173.04,
|
|
||||||
174.97,
|
|
||||||
178.49,
|
|
||||||
180.95,
|
|
||||||
183.84,
|
|
||||||
186.21,
|
|
||||||
190.23,
|
|
||||||
192.22,
|
|
||||||
195.08,
|
|
||||||
196.97,
|
|
||||||
200.59,
|
|
||||||
204.38,
|
|
||||||
207.20,
|
|
||||||
208.98,
|
|
||||||
209.00,
|
|
||||||
210.00,
|
|
||||||
222.00,
|
|
||||||
223.00,
|
|
||||||
226.00,
|
|
||||||
227.00,
|
|
||||||
232.04,
|
|
||||||
231.04,
|
|
||||||
238.03,
|
|
||||||
237.00,
|
|
||||||
244.00,
|
|
||||||
243.00,
|
|
||||||
247.00,
|
|
||||||
247.00,
|
|
||||||
251.00,
|
|
||||||
252.00,
|
|
||||||
257.00,
|
|
||||||
258.00,
|
|
||||||
259.00,
|
|
||||||
262.00,
|
|
||||||
0.000,
|
|
||||||
)
|
|
||||||
|
|
||||||
#### Number of the ghost atom
|
|
||||||
ghost_number = len(atomsymb) - 1
|
|
||||||
37
diceplayer/state/state_handler.py
Normal file
37
diceplayer/state/state_handler.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
from diceplayer.logger import logger
|
||||||
|
from diceplayer.state.state_model import StateModel
|
||||||
|
|
||||||
|
import pickle
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class StateHandler:
|
||||||
|
def __init__(self, sim_dir: Path, state_file: str = "state.pkl"):
|
||||||
|
if not sim_dir.exists():
|
||||||
|
sim_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
self._state_file = sim_dir / state_file
|
||||||
|
|
||||||
|
def get(self, config: PlayerConfig, force=False) -> StateModel | None:
|
||||||
|
if not self._state_file.exists():
|
||||||
|
return None
|
||||||
|
|
||||||
|
with open(self._state_file, mode="rb") as file:
|
||||||
|
data = pickle.load(file)
|
||||||
|
model = StateModel.model_validate(data)
|
||||||
|
|
||||||
|
if config != model.config and not force:
|
||||||
|
logger.warning(
|
||||||
|
"The configuration in the state file does not match the provided configuration."
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return model
|
||||||
|
|
||||||
|
def save(self, state: StateModel) -> None:
|
||||||
|
with self._state_file.open(mode="wb") as f:
|
||||||
|
pickle.dump(state.model_dump(), f)
|
||||||
|
|
||||||
|
def delete(self) -> None:
|
||||||
|
if self._state_file.exists():
|
||||||
|
self._state_file.unlink()
|
||||||
19
diceplayer/state/state_model.py
Normal file
19
diceplayer/state/state_model.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
from diceplayer.environment import System
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
|
||||||
|
class StateModel(BaseModel):
|
||||||
|
config: PlayerConfig
|
||||||
|
system: System
|
||||||
|
current_cycle: int = 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_config(cls, config: PlayerConfig) -> Self:
|
||||||
|
return cls(
|
||||||
|
config=config,
|
||||||
|
system=System(),
|
||||||
|
current_cycle=0,
|
||||||
|
)
|
||||||
21
diceplayer/utils/__init__.py
Normal file
21
diceplayer/utils/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from .logger import RunLogger
|
||||||
|
from .misc import (
|
||||||
|
compress_files_1mb,
|
||||||
|
date_time,
|
||||||
|
make_qm_dir,
|
||||||
|
make_step_dir,
|
||||||
|
weekday_date_time,
|
||||||
|
)
|
||||||
|
from .ptable import AtomInfo, PTable
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"RunLogger",
|
||||||
|
"PTable",
|
||||||
|
"AtomInfo",
|
||||||
|
"weekday_date_time",
|
||||||
|
"date_time",
|
||||||
|
"compress_files_1mb",
|
||||||
|
"make_step_dir",
|
||||||
|
"make_qm_dir",
|
||||||
|
]
|
||||||
29
diceplayer/utils/cache.py
Normal file
29
diceplayer/utils/cache.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from functools import cached_property
|
||||||
|
|
||||||
|
|
||||||
|
def invalidate_computed_properties():
|
||||||
|
"""
|
||||||
|
Decorator function to invalidate the cached properties of the molecule when a new atom is added
|
||||||
|
|
||||||
|
Args:
|
||||||
|
properties (list[str]): list of the names of the properties to be invalidated
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_cached_properies(cls: type) -> set[str]:
|
||||||
|
return {
|
||||||
|
name
|
||||||
|
for name, value in cls.__dict__.items()
|
||||||
|
if isinstance(value, cached_property)
|
||||||
|
}
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
def wrapper(self, *args, **kwargs):
|
||||||
|
result = func(self, *args, **kwargs)
|
||||||
|
for prop in get_cached_properies(self.__class__):
|
||||||
|
if hasattr(self, prop):
|
||||||
|
delattr(self, prop)
|
||||||
|
return result
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorator
|
||||||
44
diceplayer/utils/logger.py
Normal file
44
diceplayer/utils/logger.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
from typing_extensions import TypeVar
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
H = TypeVar("H", bound=logging.Handler)
|
||||||
|
|
||||||
|
|
||||||
|
class RunLogger(logging.Logger):
|
||||||
|
def __init__(self, name, level=logging.INFO, stream=sys.stdout):
|
||||||
|
super().__init__(name, level)
|
||||||
|
|
||||||
|
self.handlers.clear()
|
||||||
|
|
||||||
|
self.handlers.append(
|
||||||
|
self._configure_handler(logging.StreamHandler(stream), level)
|
||||||
|
)
|
||||||
|
|
||||||
|
def set_output_file(self, outfile: Path, level=logging.INFO):
|
||||||
|
for handler in list(self.handlers):
|
||||||
|
if not isinstance(handler, logging.FileHandler):
|
||||||
|
continue
|
||||||
|
self.handlers.remove(handler)
|
||||||
|
|
||||||
|
self.handlers.append(self._create_file_handler(outfile, level))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_file_handler(file: str | Path, level) -> logging.FileHandler:
|
||||||
|
file = Path(file)
|
||||||
|
|
||||||
|
if file.exists():
|
||||||
|
file.rename(file.with_suffix(".log.backup"))
|
||||||
|
|
||||||
|
handler = logging.FileHandler(file)
|
||||||
|
return RunLogger._configure_handler(handler, level)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _configure_handler(handler: H, level) -> H:
|
||||||
|
handler.setLevel(level)
|
||||||
|
formatter = logging.Formatter("%(message)s")
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
return handler
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
|
from typing_extensions import Final
|
||||||
|
|
||||||
import gzip
|
import gzip
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from typing import Final
|
|
||||||
|
|
||||||
####################################### constants ######################################
|
####################################### constants ######################################
|
||||||
|
|
||||||
@@ -11,6 +13,8 @@ from typing import Final
|
|||||||
BOHR2ANG: Final[float] = 0.52917721092
|
BOHR2ANG: Final[float] = 0.52917721092
|
||||||
ANG2BOHR: Final[float] = 1 / BOHR2ANG
|
ANG2BOHR: Final[float] = 1 / BOHR2ANG
|
||||||
|
|
||||||
|
EA_2_DEBYE = 1 / 0.20819434
|
||||||
|
|
||||||
|
|
||||||
####################################### functions ######################################
|
####################################### functions ######################################
|
||||||
|
|
||||||
@@ -35,7 +39,7 @@ def compress_files_1mb(path):
|
|||||||
with open(file, "rb") as f_in:
|
with open(file, "rb") as f_in:
|
||||||
with gzip.open(filegz, "wb") as f_out:
|
with gzip.open(filegz, "wb") as f_out:
|
||||||
shutil.copyfileobj(f_in, f_out)
|
shutil.copyfileobj(f_in, f_out)
|
||||||
except:
|
except Exception as _:
|
||||||
sys.exit("Error: cannot compress file {}".format(file))
|
sys.exit("Error: cannot compress file {}".format(file))
|
||||||
|
|
||||||
os.chdir(working_dir)
|
os.chdir(working_dir)
|
||||||
@@ -51,7 +55,7 @@ def make_step_dir(cycle):
|
|||||||
sys.exit("Error: a file or directory {} already exists".format(step_dir))
|
sys.exit("Error: a file or directory {} already exists".format(step_dir))
|
||||||
try:
|
try:
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
except:
|
except Exception as _:
|
||||||
sys.exit("Error: cannot make directory {}".format(step_dir))
|
sys.exit("Error: cannot make directory {}".format(step_dir))
|
||||||
|
|
||||||
|
|
||||||
@@ -61,5 +65,5 @@ def make_qm_dir(cycle):
|
|||||||
path = sim_dir + os.sep + step_dir + os.sep + "qm"
|
path = sim_dir + os.sep + step_dir + os.sep + "qm"
|
||||||
try:
|
try:
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
except:
|
except Exception as _:
|
||||||
sys.exit("Error: cannot make directory {}".format(path))
|
sys.exit("Error: cannot make directory {}".format(path))
|
||||||
55
diceplayer/utils/potential.py
Normal file
55
diceplayer/utils/potential.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
from diceplayer.environment import Atom, Molecule, System
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def read_system_from_phb(config: PlayerConfig) -> System:
|
||||||
|
phb_file = Path(config.dice.ljname)
|
||||||
|
if not phb_file.exists():
|
||||||
|
raise FileNotFoundError
|
||||||
|
|
||||||
|
ljc_data = phb_file.read_text(encoding="utf-8").splitlines()
|
||||||
|
|
||||||
|
combrule = ljc_data.pop(0).strip()
|
||||||
|
if combrule != config.dice.combrule:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid combrule defined in {phb_file}. Expected the same value configured in the config file"
|
||||||
|
)
|
||||||
|
|
||||||
|
ntypes = ljc_data.pop(0).strip()
|
||||||
|
if not ntypes.isdigit():
|
||||||
|
raise ValueError(f"Invalid ntypes defined in {phb_file}")
|
||||||
|
|
||||||
|
nmol = int(ntypes)
|
||||||
|
if nmol != len(config.dice.nmol):
|
||||||
|
raise ValueError(f"Invalid nmol defined in {phb_file}")
|
||||||
|
|
||||||
|
sys = System()
|
||||||
|
|
||||||
|
for i in range(nmol):
|
||||||
|
nsites, molname = ljc_data.pop(0).split()
|
||||||
|
|
||||||
|
if not nsites.isdigit():
|
||||||
|
raise ValueError(f"Invalid nsites defined in {phb_file}")
|
||||||
|
nsites = int(nsites)
|
||||||
|
|
||||||
|
mol = Molecule(molname)
|
||||||
|
|
||||||
|
for j in range(nsites):
|
||||||
|
_fields = ljc_data.pop(0).split()
|
||||||
|
mol.add_atom(Atom(*_fields))
|
||||||
|
|
||||||
|
sys.add_type(mol)
|
||||||
|
|
||||||
|
return sys
|
||||||
|
|
||||||
|
|
||||||
|
# def write_phb(phb_file: Path, state: StateModel) -> None:
|
||||||
|
# if phb_file.exists():
|
||||||
|
# raise RuntimeError(f"File {phb_file} already exists")
|
||||||
|
#
|
||||||
|
# with open(phb_file, "w") as f:
|
||||||
|
# f.write(f"{state.config.dice.combrule}\n")
|
||||||
|
# f.write(f"{len(state.system.nmols)}\n")
|
||||||
|
# f.write(f"{state.config.dice.nmol}\n")
|
||||||
143
diceplayer/utils/ptable.py
Normal file
143
diceplayer/utils/ptable.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
DICE_GHOST_LABEL = "Xx"
|
||||||
|
|
||||||
|
#### Number of the ghost atom
|
||||||
|
GHOST_NUMBER = 0
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class AtomInfo:
|
||||||
|
atomic_number: int
|
||||||
|
symbol: str
|
||||||
|
mass: float
|
||||||
|
|
||||||
|
|
||||||
|
class PTable(Enum):
|
||||||
|
Xx = AtomInfo(GHOST_NUMBER, DICE_GHOST_LABEL, 0.0)
|
||||||
|
H = AtomInfo(1, "H", 1.0079)
|
||||||
|
He = AtomInfo(2, "He", 4.0026)
|
||||||
|
Li = AtomInfo(3, "Li", 6.9410)
|
||||||
|
Be = AtomInfo(4, "Be", 9.0122)
|
||||||
|
B = AtomInfo(5, "B", 10.811)
|
||||||
|
C = AtomInfo(6, "C", 12.011)
|
||||||
|
N = AtomInfo(7, "N", 14.007)
|
||||||
|
O = AtomInfo(8, "O", 15.999)
|
||||||
|
F = AtomInfo(9, "F", 18.998)
|
||||||
|
Ne = AtomInfo(10, "Ne", 20.180)
|
||||||
|
Na = AtomInfo(11, "Na", 22.990)
|
||||||
|
Mg = AtomInfo(12, "Mg", 24.305)
|
||||||
|
Al = AtomInfo(13, "Al", 26.982)
|
||||||
|
Si = AtomInfo(14, "Si", 28.086)
|
||||||
|
P = AtomInfo(15, "P", 30.974)
|
||||||
|
S = AtomInfo(16, "S", 32.065)
|
||||||
|
Cl = AtomInfo(17, "Cl", 35.453)
|
||||||
|
Ar = AtomInfo(18, "Ar", 39.948)
|
||||||
|
K = AtomInfo(19, "K", 39.098)
|
||||||
|
Ca = AtomInfo(20, "Ca", 40.078)
|
||||||
|
Sc = AtomInfo(21, "Sc", 44.956)
|
||||||
|
Ti = AtomInfo(22, "Ti", 47.867)
|
||||||
|
V = AtomInfo(23, "V", 50.942)
|
||||||
|
Cr = AtomInfo(24, "Cr", 51.996)
|
||||||
|
Mn = AtomInfo(25, "Mn", 54.938)
|
||||||
|
Fe = AtomInfo(26, "Fe", 55.845)
|
||||||
|
Co = AtomInfo(27, "Co", 58.933)
|
||||||
|
Ni = AtomInfo(28, "Ni", 58.693)
|
||||||
|
Cu = AtomInfo(29, "Cu", 63.546)
|
||||||
|
Zn = AtomInfo(30, "Zn", 65.409)
|
||||||
|
Ga = AtomInfo(31, "Ga", 69.723)
|
||||||
|
Ge = AtomInfo(32, "Ge", 72.640)
|
||||||
|
As = AtomInfo(33, "As", 74.922)
|
||||||
|
Se = AtomInfo(34, "Se", 78.960)
|
||||||
|
Br = AtomInfo(35, "Br", 79.904)
|
||||||
|
Kr = AtomInfo(36, "Kr", 83.798)
|
||||||
|
Rb = AtomInfo(37, "Rb", 85.468)
|
||||||
|
Sr = AtomInfo(38, "Sr", 87.620)
|
||||||
|
Y = AtomInfo(39, "Y", 88.906)
|
||||||
|
Zr = AtomInfo(40, "Zr", 91.224)
|
||||||
|
Nb = AtomInfo(41, "Nb", 92.906)
|
||||||
|
Mo = AtomInfo(42, "Mo", 95.940)
|
||||||
|
Tc = AtomInfo(43, "Tc", 98.000)
|
||||||
|
Ru = AtomInfo(44, "Ru", 101.07)
|
||||||
|
Rh = AtomInfo(45, "Rh", 102.91)
|
||||||
|
Pd = AtomInfo(46, "Pd", 106.42)
|
||||||
|
Ag = AtomInfo(47, "Ag", 107.87)
|
||||||
|
Cd = AtomInfo(48, "Cd", 112.41)
|
||||||
|
In = AtomInfo(49, "In", 114.82)
|
||||||
|
Sn = AtomInfo(50, "Sn", 118.71)
|
||||||
|
Sb = AtomInfo(51, "Sb", 121.76)
|
||||||
|
Te = AtomInfo(52, "Te", 127.60)
|
||||||
|
I = AtomInfo(53, "I", 126.90)
|
||||||
|
Xe = AtomInfo(54, "Xe", 131.29)
|
||||||
|
Cs = AtomInfo(55, "Cs", 132.91)
|
||||||
|
Ba = AtomInfo(56, "Ba", 137.33)
|
||||||
|
La = AtomInfo(57, "La", 138.91)
|
||||||
|
Ce = AtomInfo(58, "Ce", 140.12)
|
||||||
|
Pr = AtomInfo(59, "Pr", 140.91)
|
||||||
|
Nd = AtomInfo(60, "Nd", 144.24)
|
||||||
|
Pm = AtomInfo(61, "Pm", 145.00)
|
||||||
|
Sm = AtomInfo(62, "Sm", 150.36)
|
||||||
|
Eu = AtomInfo(63, "Eu", 151.96)
|
||||||
|
Gd = AtomInfo(64, "Gd", 157.25)
|
||||||
|
Tb = AtomInfo(65, "Tb", 158.93)
|
||||||
|
Dy = AtomInfo(66, "Dy", 162.50)
|
||||||
|
Ho = AtomInfo(67, "Ho", 164.93)
|
||||||
|
Er = AtomInfo(68, "Er", 167.26)
|
||||||
|
Tm = AtomInfo(69, "Tm", 168.93)
|
||||||
|
Yb = AtomInfo(70, "Yb", 173.04)
|
||||||
|
Lu = AtomInfo(71, "Lu", 174.97)
|
||||||
|
Hf = AtomInfo(72, "Hf", 178.49)
|
||||||
|
Ta = AtomInfo(73, "Ta", 180.95)
|
||||||
|
W = AtomInfo(74, "W", 183.84)
|
||||||
|
Re = AtomInfo(75, "Re", 186.21)
|
||||||
|
Os = AtomInfo(76, "Os", 190.23)
|
||||||
|
Ir = AtomInfo(77, "Ir", 192.22)
|
||||||
|
Pt = AtomInfo(78, "Pt", 195.08)
|
||||||
|
Au = AtomInfo(79, "Au", 196.97)
|
||||||
|
Hg = AtomInfo(80, "Hg", 200.59)
|
||||||
|
Tl = AtomInfo(81, "Tl", 204.38)
|
||||||
|
Pb = AtomInfo(82, "Pb", 207.20)
|
||||||
|
Bi = AtomInfo(83, "Bi", 208.98)
|
||||||
|
Po = AtomInfo(84, "Po", 209.00)
|
||||||
|
At = AtomInfo(85, "At", 210.00)
|
||||||
|
Rn = AtomInfo(86, "Rn", 222.00)
|
||||||
|
Fr = AtomInfo(87, "Fr", 223.00)
|
||||||
|
Ra = AtomInfo(88, "Ra", 226.00)
|
||||||
|
Ac = AtomInfo(89, "Ac", 227.00)
|
||||||
|
Th = AtomInfo(90, "Th", 232.04)
|
||||||
|
Pa = AtomInfo(91, "Pa", 231.04)
|
||||||
|
U = AtomInfo(92, "U", 238.03)
|
||||||
|
Np = AtomInfo(93, "Np", 237.00)
|
||||||
|
Pu = AtomInfo(94, "Pu", 244.00)
|
||||||
|
Am = AtomInfo(95, "Am", 243.00)
|
||||||
|
Cm = AtomInfo(96, "Cm", 247.00)
|
||||||
|
Bk = AtomInfo(97, "Bk", 247.00)
|
||||||
|
Cf = AtomInfo(98, "Cf", 251.00)
|
||||||
|
Es = AtomInfo(99, "Es", 252.00)
|
||||||
|
Fm = AtomInfo(100, "Fm", 257.00)
|
||||||
|
Md = AtomInfo(101, "Md", 258.00)
|
||||||
|
No = AtomInfo(102, "No", 259.00)
|
||||||
|
Lr = AtomInfo(103, "Lr", 262.00)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_atomic_symbol(cls, atomic_number: int) -> str:
|
||||||
|
for element in cls:
|
||||||
|
if element.value.atomic_number == atomic_number:
|
||||||
|
return element.value.symbol
|
||||||
|
raise ValueError(f"Atomic number {atomic_number} not found in PTable.")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_atomic_mass(cls, atomic_number: int) -> float:
|
||||||
|
for element in cls:
|
||||||
|
if element.value.atomic_number == atomic_number:
|
||||||
|
return element.value.mass
|
||||||
|
raise ValueError(f"Atomic number {atomic_number} not found in PTable.")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_from_atomic_number(cls, atomic_number: int) -> AtomInfo:
|
||||||
|
for element in cls:
|
||||||
|
if element.value.atomic_number == atomic_number:
|
||||||
|
return element.value
|
||||||
|
raise ValueError(f"Atomic number {atomic_number} not found in PTable.")
|
||||||
594
poetry.lock
generated
594
poetry.lock
generated
@@ -1,594 +0,0 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "argparse"
|
|
||||||
version = "1.4.0"
|
|
||||||
description = "Python command-line parsing library"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "argparse-1.4.0-py2.py3-none-any.whl", hash = "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314"},
|
|
||||||
{file = "argparse-1.4.0.tar.gz", hash = "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "black"
|
|
||||||
version = "24.4.2"
|
|
||||||
description = "The uncompromising code formatter."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"},
|
|
||||||
{file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"},
|
|
||||||
{file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"},
|
|
||||||
{file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"},
|
|
||||||
{file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"},
|
|
||||||
{file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"},
|
|
||||||
{file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"},
|
|
||||||
{file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"},
|
|
||||||
{file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"},
|
|
||||||
{file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"},
|
|
||||||
{file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"},
|
|
||||||
{file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"},
|
|
||||||
{file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"},
|
|
||||||
{file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"},
|
|
||||||
{file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"},
|
|
||||||
{file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"},
|
|
||||||
{file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"},
|
|
||||||
{file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"},
|
|
||||||
{file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"},
|
|
||||||
{file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"},
|
|
||||||
{file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"},
|
|
||||||
{file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
click = ">=8.0.0"
|
|
||||||
mypy-extensions = ">=0.4.3"
|
|
||||||
packaging = ">=22.0"
|
|
||||||
pathspec = ">=0.9.0"
|
|
||||||
platformdirs = ">=2"
|
|
||||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
|
||||||
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
colorama = ["colorama (>=0.4.3)"]
|
|
||||||
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
|
|
||||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
|
||||||
uvloop = ["uvloop (>=0.15.2)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfgv"
|
|
||||||
version = "3.4.0"
|
|
||||||
description = "Validate configuration and produce human readable error messages."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
|
|
||||||
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "click"
|
|
||||||
version = "8.1.7"
|
|
||||||
description = "Composable command line interface toolkit"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
|
||||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "colorama"
|
|
||||||
version = "0.4.6"
|
|
||||||
description = "Cross-platform colored terminal text."
|
|
||||||
optional = false
|
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
||||||
files = [
|
|
||||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
|
||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "coverage"
|
|
||||||
version = "7.6.0"
|
|
||||||
description = "Code coverage measurement for Python"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"},
|
|
||||||
{file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"},
|
|
||||||
{file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"},
|
|
||||||
{file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"},
|
|
||||||
{file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"},
|
|
||||||
{file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"},
|
|
||||||
{file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"},
|
|
||||||
{file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
toml = ["tomli"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "distlib"
|
|
||||||
version = "0.3.8"
|
|
||||||
description = "Distribution utilities"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
|
|
||||||
{file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "filelock"
|
|
||||||
version = "3.15.4"
|
|
||||||
description = "A platform independent file lock."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"},
|
|
||||||
{file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
|
||||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"]
|
|
||||||
typing = ["typing-extensions (>=4.8)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "identify"
|
|
||||||
version = "2.6.0"
|
|
||||||
description = "File identification library for Python"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"},
|
|
||||||
{file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
license = ["ukkonen"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "isort"
|
|
||||||
version = "5.13.2"
|
|
||||||
description = "A Python utility / library to sort Python imports."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8.0"
|
|
||||||
files = [
|
|
||||||
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
|
|
||||||
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
colors = ["colorama (>=0.4.6)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mypy-extensions"
|
|
||||||
version = "1.0.0"
|
|
||||||
description = "Type system extensions for programs checked with the mypy type checker."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
files = [
|
|
||||||
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
|
||||||
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nodeenv"
|
|
||||||
version = "1.9.1"
|
|
||||||
description = "Node.js virtual environment builder"
|
|
||||||
optional = false
|
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
||||||
files = [
|
|
||||||
{file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
|
|
||||||
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nptyping"
|
|
||||||
version = "2.5.0"
|
|
||||||
description = "Type hints for NumPy."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8"},
|
|
||||||
{file = "nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
numpy = {version = ">=1.20.0,<2.0.0", markers = "python_version >= \"3.8\""}
|
|
||||||
typing-extensions = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.10\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
build = ["invoke (>=1.6.0)", "pip-tools (>=6.5.0)"]
|
|
||||||
complete = ["pandas", "pandas-stubs-fork"]
|
|
||||||
dev = ["autoflake", "beartype (<0.10.0)", "beartype (>=0.10.0)", "black", "codecov (>=2.1.0)", "coverage", "feedparser", "invoke (>=1.6.0)", "isort", "mypy", "pandas", "pandas-stubs-fork", "pip-tools (>=6.5.0)", "pylint", "pyright", "setuptools", "typeguard", "wheel"]
|
|
||||||
pandas = ["pandas", "pandas-stubs-fork"]
|
|
||||||
qa = ["autoflake", "beartype (<0.10.0)", "beartype (>=0.10.0)", "black", "codecov (>=2.1.0)", "coverage", "feedparser", "isort", "mypy", "pylint", "pyright", "setuptools", "typeguard", "wheel"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "numpy"
|
|
||||||
version = "1.26.4"
|
|
||||||
description = "Fundamental package for array computing in Python"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.9"
|
|
||||||
files = [
|
|
||||||
{file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"},
|
|
||||||
{file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"},
|
|
||||||
{file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"},
|
|
||||||
{file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"},
|
|
||||||
{file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"},
|
|
||||||
{file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"},
|
|
||||||
{file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"},
|
|
||||||
{file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"},
|
|
||||||
{file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"},
|
|
||||||
{file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"},
|
|
||||||
{file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"},
|
|
||||||
{file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"},
|
|
||||||
{file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"},
|
|
||||||
{file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"},
|
|
||||||
{file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"},
|
|
||||||
{file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"},
|
|
||||||
{file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"},
|
|
||||||
{file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"},
|
|
||||||
{file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"},
|
|
||||||
{file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"},
|
|
||||||
{file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"},
|
|
||||||
{file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"},
|
|
||||||
{file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"},
|
|
||||||
{file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"},
|
|
||||||
{file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"},
|
|
||||||
{file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"},
|
|
||||||
{file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"},
|
|
||||||
{file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"},
|
|
||||||
{file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"},
|
|
||||||
{file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"},
|
|
||||||
{file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"},
|
|
||||||
{file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"},
|
|
||||||
{file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"},
|
|
||||||
{file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"},
|
|
||||||
{file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"},
|
|
||||||
{file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "packaging"
|
|
||||||
version = "24.1"
|
|
||||||
description = "Core utilities for Python packages"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
|
||||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pastel"
|
|
||||||
version = "0.2.1"
|
|
||||||
description = "Bring colors to your terminal."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
files = [
|
|
||||||
{file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"},
|
|
||||||
{file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pathspec"
|
|
||||||
version = "0.12.1"
|
|
||||||
description = "Utility library for gitignore style pattern matching of file paths."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
|
|
||||||
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "platformdirs"
|
|
||||||
version = "4.2.2"
|
|
||||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
|
|
||||||
{file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
|
||||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
|
|
||||||
type = ["mypy (>=1.8)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "poethepoet"
|
|
||||||
version = "0.27.0"
|
|
||||||
description = "A task runner that works well with poetry."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "poethepoet-0.27.0-py3-none-any.whl", hash = "sha256:0032d980a623b96e26dc7450ae200b0998be523f27d297d799b97510fe252a24"},
|
|
||||||
{file = "poethepoet-0.27.0.tar.gz", hash = "sha256:907ab4dc1bc6326be5a3b10d2aa39d1acc0ca12024317d9506fbe9c0cdc912c9"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pastel = ">=0.2.1,<0.3.0"
|
|
||||||
tomli = ">=1.2.2"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
poetry-plugin = ["poetry (>=1.0,<2.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pre-commit"
|
|
||||||
version = "3.7.1"
|
|
||||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.9"
|
|
||||||
files = [
|
|
||||||
{file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"},
|
|
||||||
{file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
cfgv = ">=2.0.0"
|
|
||||||
identify = ">=1.0.0"
|
|
||||||
nodeenv = ">=0.11.1"
|
|
||||||
pyyaml = ">=5.1"
|
|
||||||
virtualenv = ">=20.10.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyyaml"
|
|
||||||
version = "6.0.1"
|
|
||||||
description = "YAML parser and emitter for Python"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
|
|
||||||
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "setproctitle"
|
|
||||||
version = "1.3.3"
|
|
||||||
description = "A Python module to customize the process title"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:897a73208da48db41e687225f355ce993167079eda1260ba5e13c4e53be7f754"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c331e91a14ba4076f88c29c777ad6b58639530ed5b24b5564b5ed2fd7a95452"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbbd6c7de0771c84b4aa30e70b409565eb1fc13627a723ca6be774ed6b9d9fa3"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c05ac48ef16ee013b8a326c63e4610e2430dbec037ec5c5b58fcced550382b74"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1342f4fdb37f89d3e3c1c0a59d6ddbedbde838fff5c51178a7982993d238fe4f"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc74e84fdfa96821580fb5e9c0b0777c1c4779434ce16d3d62a9c4d8c710df39"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9617b676b95adb412bb69645d5b077d664b6882bb0d37bfdafbbb1b999568d85"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6a249415f5bb88b5e9e8c4db47f609e0bf0e20a75e8d744ea787f3092ba1f2d0"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:38da436a0aaace9add67b999eb6abe4b84397edf4a78ec28f264e5b4c9d53cd5"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:da0d57edd4c95bf221b2ebbaa061e65b1788f1544977288bdf95831b6e44e44d"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-win32.whl", hash = "sha256:a1fcac43918b836ace25f69b1dca8c9395253ad8152b625064415b1d2f9be4fb"},
|
|
||||||
{file = "setproctitle-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:200620c3b15388d7f3f97e0ae26599c0c378fdf07ae9ac5a13616e933cbd2086"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:334f7ed39895d692f753a443102dd5fed180c571eb6a48b2a5b7f5b3564908c8"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:950f6476d56ff7817a8fed4ab207727fc5260af83481b2a4b125f32844df513a"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:195c961f54a09eb2acabbfc90c413955cf16c6e2f8caa2adbf2237d1019c7dd8"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f05e66746bf9fe6a3397ec246fe481096664a9c97eb3fea6004735a4daf867fd"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5901a31012a40ec913265b64e48c2a4059278d9f4e6be628441482dd13fb8b5"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64286f8a995f2cd934082b398fc63fca7d5ffe31f0e27e75b3ca6b4efda4e353"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:184239903bbc6b813b1a8fc86394dc6ca7d20e2ebe6f69f716bec301e4b0199d"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:664698ae0013f986118064b6676d7dcd28fefd0d7d5a5ae9497cbc10cba48fa5"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e5119a211c2e98ff18b9908ba62a3bd0e3fabb02a29277a7232a6fb4b2560aa0"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:417de6b2e214e837827067048f61841f5d7fc27926f2e43954567094051aff18"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-win32.whl", hash = "sha256:6a143b31d758296dc2f440175f6c8e0b5301ced3b0f477b84ca43cdcf7f2f476"},
|
|
||||||
{file = "setproctitle-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a680d62c399fa4b44899094027ec9a1bdaf6f31c650e44183b50d4c4d0ccc085"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d4460795a8a7a391e3567b902ec5bdf6c60a47d791c3b1d27080fc203d11c9dc"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bdfd7254745bb737ca1384dee57e6523651892f0ea2a7344490e9caefcc35e64"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477d3da48e216d7fc04bddab67b0dcde633e19f484a146fd2a34bb0e9dbb4a1e"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ab2900d111e93aff5df9fddc64cf51ca4ef2c9f98702ce26524f1acc5a786ae7"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088b9efc62d5aa5d6edf6cba1cf0c81f4488b5ce1c0342a8b67ae39d64001120"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6d50252377db62d6a0bb82cc898089916457f2db2041e1d03ce7fadd4a07381"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:87e668f9561fd3a457ba189edfc9e37709261287b52293c115ae3487a24b92f6"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:287490eb90e7a0ddd22e74c89a92cc922389daa95babc833c08cf80c84c4df0a"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe1c49486109f72d502f8be569972e27f385fe632bd8895f4730df3c87d5ac8"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4a6ba2494a6449b1f477bd3e67935c2b7b0274f2f6dcd0f7c6aceae10c6c6ba3"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-win32.whl", hash = "sha256:2df2b67e4b1d7498632e18c56722851ba4db5d6a0c91aaf0fd395111e51cdcf4"},
|
|
||||||
{file = "setproctitle-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:f38d48abc121263f3b62943f84cbaede05749047e428409c2c199664feb6abc7"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:816330675e3504ae4d9a2185c46b573105d2310c20b19ea2b4596a9460a4f674"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f960bc22d8d8e4ac886d1e2e21ccbd283adcf3c43136161c1ba0fa509088e0"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e6e7adff74796ef12753ff399491b8827f84f6c77659d71bd0b35870a17d8f"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53bc0d2358507596c22b02db079618451f3bd720755d88e3cccd840bafb4c41c"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad6d20f9541f5f6ac63df553b6d7a04f313947f550eab6a61aa758b45f0d5657"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c1c84beab776b0becaa368254801e57692ed749d935469ac10e2b9b825dbdd8e"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:507e8dc2891021350eaea40a44ddd887c9f006e6b599af8d64a505c0f718f170"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b1067647ac7aba0b44b591936118a22847bda3c507b0a42d74272256a7a798e9"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e71f6365744bf53714e8bd2522b3c9c1d83f52ffa6324bd7cbb4da707312cd8"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:7f1d36a1e15a46e8ede4e953abb104fdbc0845a266ec0e99cc0492a4364f8c44"},
|
|
||||||
{file = "setproctitle-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9a402881ec269d0cc9c354b149fc29f9ec1a1939a777f1c858cdb09c7a261df"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ff814dea1e5c492a4980e3e7d094286077054e7ea116cbeda138819db194b2cd"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:accb66d7b3ccb00d5cd11d8c6e07055a4568a24c95cf86109894dcc0c134cc89"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554eae5a5b28f02705b83a230e9d163d645c9a08914c0ad921df363a07cf39b1"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a911b26264dbe9e8066c7531c0591cfab27b464459c74385b276fe487ca91c12"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2982efe7640c4835f7355fdb4da313ad37fb3b40f5c69069912f8048f77b28c8"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df3f4274b80709d8bcab2f9a862973d453b308b97a0b423a501bcd93582852e3"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:af2c67ae4c795d1674a8d3ac1988676fa306bcfa1e23fddb5e0bd5f5635309ca"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:af4061f67fd7ec01624c5e3c21f6b7af2ef0e6bab7fbb43f209e6506c9ce0092"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:37a62cbe16d4c6294e84670b59cf7adcc73faafe6af07f8cb9adaf1f0e775b19"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a83ca086fbb017f0d87f240a8f9bbcf0809f3b754ee01cec928fff926542c450"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-win32.whl", hash = "sha256:059f4ce86f8cc92e5860abfc43a1dceb21137b26a02373618d88f6b4b86ba9b2"},
|
|
||||||
{file = "setproctitle-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ab92e51cd4a218208efee4c6d37db7368fdf182f6e7ff148fb295ecddf264287"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7951820b77abe03d88b114b998867c0f99da03859e5ab2623d94690848d3e45"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc94cf128676e8fac6503b37763adb378e2b6be1249d207630f83fc325d9b11"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f5d9027eeda64d353cf21a3ceb74bb1760bd534526c9214e19f052424b37e42"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e4a8104db15d3462e29d9946f26bed817a5b1d7a47eabca2d9dc2b995991503"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32c41ace41f344d317399efff4cffb133e709cec2ef09c99e7a13e9f3b9483c"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf16381c7bf7f963b58fb4daaa65684e10966ee14d26f5cc90f07049bfd8c1e"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e18b7bd0898398cc97ce2dfc83bb192a13a087ef6b2d5a8a36460311cb09e775"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69d565d20efe527bd8a9b92e7f299ae5e73b6c0470f3719bd66f3cd821e0d5bd"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ddedd300cd690a3b06e7eac90ed4452348b1348635777ce23d460d913b5b63c3"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:415bfcfd01d1fbf5cbd75004599ef167a533395955305f42220a585f64036081"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-win32.whl", hash = "sha256:21112fcd2195d48f25760f0eafa7a76510871bbb3b750219310cf88b04456ae3"},
|
|
||||||
{file = "setproctitle-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:5a740f05d0968a5a17da3d676ce6afefebeeeb5ce137510901bf6306ba8ee002"},
|
|
||||||
{file = "setproctitle-1.3.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6b9e62ddb3db4b5205c0321dd69a406d8af9ee1693529d144e86bd43bcb4b6c0"},
|
|
||||||
{file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3b99b338598de0bd6b2643bf8c343cf5ff70db3627af3ca427a5e1a1a90dd9"},
|
|
||||||
{file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ae9a02766dad331deb06855fb7a6ca15daea333b3967e214de12cfae8f0ef5"},
|
|
||||||
{file = "setproctitle-1.3.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:200ede6fd11233085ba9b764eb055a2a191fb4ffb950c68675ac53c874c22e20"},
|
|
||||||
{file = "setproctitle-1.3.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0d3a953c50776751e80fe755a380a64cb14d61e8762bd43041ab3f8cc436092f"},
|
|
||||||
{file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e08e232b78ba3ac6bc0d23ce9e2bee8fad2be391b7e2da834fc9a45129eb87"},
|
|
||||||
{file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1da82c3e11284da4fcbf54957dafbf0655d2389cd3d54e4eaba636faf6d117a"},
|
|
||||||
{file = "setproctitle-1.3.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:aeaa71fb9568ebe9b911ddb490c644fbd2006e8c940f21cb9a1e9425bd709574"},
|
|
||||||
{file = "setproctitle-1.3.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:59335d000c6250c35989394661eb6287187854e94ac79ea22315469ee4f4c244"},
|
|
||||||
{file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3ba57029c9c50ecaf0c92bb127224cc2ea9fda057b5d99d3f348c9ec2855ad3"},
|
|
||||||
{file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d876d355c53d975c2ef9c4f2487c8f83dad6aeaaee1b6571453cb0ee992f55f6"},
|
|
||||||
{file = "setproctitle-1.3.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:224602f0939e6fb9d5dd881be1229d485f3257b540f8a900d4271a2c2aa4e5f4"},
|
|
||||||
{file = "setproctitle-1.3.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d7f27e0268af2d7503386e0e6be87fb9b6657afd96f5726b733837121146750d"},
|
|
||||||
{file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5e7266498cd31a4572378c61920af9f6b4676a73c299fce8ba93afd694f8ae7"},
|
|
||||||
{file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33c5609ad51cd99d388e55651b19148ea99727516132fb44680e1f28dd0d1de9"},
|
|
||||||
{file = "setproctitle-1.3.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:eae8988e78192fd1a3245a6f4f382390b61bce6cfcc93f3809726e4c885fa68d"},
|
|
||||||
{file = "setproctitle-1.3.3.tar.gz", hash = "sha256:c913e151e7ea01567837ff037a23ca8740192880198b7fbb90b16d181607caae"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
test = ["pytest"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tomli"
|
|
||||||
version = "2.0.1"
|
|
||||||
description = "A lil' TOML parser"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
|
||||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typing-extensions"
|
|
||||||
version = "4.12.2"
|
|
||||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
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"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "virtualenv"
|
|
||||||
version = "20.26.3"
|
|
||||||
description = "Virtual Python Environment builder"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"},
|
|
||||||
{file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
distlib = ">=0.3.7,<1"
|
|
||||||
filelock = ">=3.12.2,<4"
|
|
||||||
platformdirs = ">=3.9.1,<5"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
|
||||||
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
|
|
||||||
|
|
||||||
[metadata]
|
|
||||||
lock-version = "2.0"
|
|
||||||
python-versions = ">=3.9,<4.0"
|
|
||||||
content-hash = "80ecbda1b826475e5eef19c940136c907a9687c7f4a6a0577a65ddd9b8a3343b"
|
|
||||||
106
pyproject.toml
106
pyproject.toml
@@ -1,47 +1,83 @@
|
|||||||
[tool.poetry]
|
[project]
|
||||||
name = "diceplayer"
|
name = "diceplayer"
|
||||||
version = "0.0.0"
|
description = "Python Program for Molecular Optimization in Non-Vacuum Mediums"
|
||||||
description = ""
|
authors = [
|
||||||
authors = ["Vitor Hideyoshi <vitor.h.n.batista@gmail.com>", "Herbert Georg <hcgeorg@ufg.br>"]
|
{ name = "Vitor Hideyoshi", email = "vitor.h.n.batista@gmail.com" },
|
||||||
license = "GPL-2.0-only"
|
{ name = "Herbert Georg", email = "hcgeorg@ufg.br" }
|
||||||
|
]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
license = "GPL-2.0-only"
|
||||||
|
scripts = { diceplayer = "diceplayer.__main__:main" }
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dynamic = ["version"]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
python = ">=3.9,<4.0"
|
|
||||||
numpy = "^1.26.4"
|
|
||||||
argparse = "^1.4.0"
|
|
||||||
setproctitle = "^1.3.2"
|
|
||||||
pyyaml = "^6.0"
|
|
||||||
nptyping = "^2.5.0"
|
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
dependencies = [
|
||||||
diceplayer = "diceplayer.__main__:main"
|
"numpy>=2.2.0",
|
||||||
|
"argparse>=1.4.0",
|
||||||
|
"setproctitle>=1.3.2",
|
||||||
|
"pyyaml>=6.0",
|
||||||
|
"pydantic>=2.12.5",
|
||||||
|
"typing-extensions>=4.15.0"
|
||||||
|
]
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
|
||||||
coverage = "^7.2.7"
|
|
||||||
isort = "^5.13.2"
|
|
||||||
black = "^24.4.2"
|
|
||||||
pre-commit = "^3.7.1"
|
|
||||||
poethepoet = "^0.27.0"
|
|
||||||
|
|
||||||
[tool.poetry-dynamic-versioning]
|
[dependency-groups]
|
||||||
enable = true
|
dev = [
|
||||||
vcs = "git"
|
"coverage>=7.2.7",
|
||||||
|
"isort>=5.13.2",
|
||||||
|
"black>=24.4.2",
|
||||||
|
"pre-commit>=3.7.1",
|
||||||
|
"poethepoet>=0.27.0",
|
||||||
|
"ruff>=0.15.2",
|
||||||
|
"pytest>=9.0.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Build system
|
||||||
|
[tool.hatch.version]
|
||||||
|
source = "vcs"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core"]
|
requires = ["hatchling", "hatch-vcs"]
|
||||||
build-backend = "poetry_dynamic_versioning.backend"
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
|
||||||
|
# POE Tasks
|
||||||
[tool.poe.tasks]
|
[tool.poe.tasks]
|
||||||
hooks = "pre-commit install --config .pre-commit-config.yaml"
|
create-hooks = "bash .githooks/set-hooks.sh"
|
||||||
|
tests = "python -m coverage run -m unittest discover -v"
|
||||||
|
tests-report = "python -m coverage xml"
|
||||||
|
|
||||||
[tool.isort]
|
|
||||||
profile = "black"
|
|
||||||
line_length = 79
|
# Tests
|
||||||
sections=[
|
[tool.coverage.run]
|
||||||
"FUTURE",
|
omit = [
|
||||||
"FIRSTPARTY",
|
"tests/*",
|
||||||
"LOCALFOLDER",
|
|
||||||
"THIRDPARTY",
|
|
||||||
"STDLIB",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Linters
|
||||||
|
[tool.ruff.lint]
|
||||||
|
extend-select = ["I"]
|
||||||
|
ignore = [
|
||||||
|
"E741" # ambiguous variable name 'l', 'O', or 'I'
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.lint.isort]
|
||||||
|
known-first-party = ["jambo"]
|
||||||
|
section-order=[
|
||||||
|
"future",
|
||||||
|
"first-party",
|
||||||
|
"local-folder",
|
||||||
|
"third-party",
|
||||||
|
"standard-library",
|
||||||
|
]
|
||||||
|
lines-after-imports = 2
|
||||||
|
|
||||||
|
|
||||||
|
[tool.pyright]
|
||||||
|
venvPath = "."
|
||||||
|
venv = ".venv"
|
||||||
|
|||||||
4
tests/_assets/__init__.py
Normal file
4
tests/_assets/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ASSETS_DIR = Path(__file__).parent
|
||||||
30
tests/cli/test_read_input_file.py
Normal file
30
tests/cli/test_read_input_file.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import diceplayer
|
||||||
|
from diceplayer.cli import read_input
|
||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class TestReadInputFile:
|
||||||
|
@pytest.fixture
|
||||||
|
def example_config(self) -> Path:
|
||||||
|
return Path(diceplayer.__path__[0]).parent / "control.example.yml"
|
||||||
|
|
||||||
|
def test_read_input_file(self, example_config: Path):
|
||||||
|
config = read_input(example_config)
|
||||||
|
|
||||||
|
assert config is not None
|
||||||
|
assert isinstance(config, PlayerConfig)
|
||||||
|
|
||||||
|
def test_read_input_non_existing_file(self):
|
||||||
|
with pytest.raises(FileNotFoundError):
|
||||||
|
read_input("nonexistent_file.yml")
|
||||||
|
|
||||||
|
def test_read_input_invalid_yaml(self, tmp_path: Path):
|
||||||
|
invalid_yaml_file = tmp_path / "invalid.yml"
|
||||||
|
invalid_yaml_file.write_text("This is not valid YAML: [unbalanced brackets")
|
||||||
|
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
read_input(invalid_yaml_file)
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
from diceplayer.shared.config.dice_config import DiceConfig
|
from diceplayer.config.dice_config import DiceConfig
|
||||||
|
|
||||||
import unittest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
class TestDiceDto(unittest.TestCase):
|
class TestDiceConfig:
|
||||||
def test_class_instantiation(self):
|
def test_class_instantiation(self):
|
||||||
dice_dto = DiceConfig(
|
dice_dto = DiceConfig(
|
||||||
|
nprocs=1,
|
||||||
ljname="test",
|
ljname="test",
|
||||||
outname="test",
|
outname="test",
|
||||||
dens=1.0,
|
dens=1.0,
|
||||||
@@ -13,78 +14,77 @@ class TestDiceDto(unittest.TestCase):
|
|||||||
nstep=[1, 1],
|
nstep=[1, 1],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertIsInstance(dice_dto, DiceConfig)
|
assert isinstance(dice_dto, DiceConfig)
|
||||||
|
|
||||||
def test_validate_jname(self):
|
def test_validate_jname(self):
|
||||||
with self.assertRaises(ValueError) as ex:
|
with pytest.raises(ValueError) as ex:
|
||||||
DiceConfig(
|
DiceConfig(
|
||||||
|
nprocs=1,
|
||||||
ljname=None,
|
ljname=None,
|
||||||
outname="test",
|
outname="test",
|
||||||
dens=1.0,
|
dens=1.0,
|
||||||
nmol=[1],
|
nmol=[1],
|
||||||
nstep=[1, 1],
|
nstep=[1, 1],
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
|
||||||
ex.exception, "Error: 'ljname' keyword not specified in config file"
|
assert ex.value == "Error: 'ljname' keyword not specified in config file"
|
||||||
)
|
|
||||||
|
|
||||||
def test_validate_outname(self):
|
def test_validate_outname(self):
|
||||||
with self.assertRaises(ValueError) as ex:
|
with pytest.raises(ValueError) as ex:
|
||||||
DiceConfig(
|
DiceConfig(
|
||||||
|
nprocs=1,
|
||||||
ljname="test",
|
ljname="test",
|
||||||
outname=None,
|
outname=None,
|
||||||
dens=1.0,
|
dens=1.0,
|
||||||
nmol=[1],
|
nmol=[1],
|
||||||
nstep=[1, 1],
|
nstep=[1, 1],
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
|
||||||
ex.exception, "Error: 'outname' keyword not specified in config file"
|
assert ex.value == "Error: 'outname' keyword not specified in config file"
|
||||||
)
|
|
||||||
|
|
||||||
def test_validate_dens(self):
|
def test_validate_dens(self):
|
||||||
with self.assertRaises(ValueError) as ex:
|
with pytest.raises(ValueError) as ex:
|
||||||
DiceConfig(
|
DiceConfig(
|
||||||
|
nprocs=1,
|
||||||
ljname="test",
|
ljname="test",
|
||||||
outname="test",
|
outname="test",
|
||||||
dens=None,
|
dens=None,
|
||||||
nmol=[1],
|
nmol=[1],
|
||||||
nstep=[1, 1],
|
nstep=[1, 1],
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
|
||||||
ex.exception, "Error: 'dens' keyword not specified in config file"
|
assert ex.value == "Error: 'dens' keyword not specified in config file"
|
||||||
)
|
|
||||||
|
|
||||||
def test_validate_nmol(self):
|
def test_validate_nmol(self):
|
||||||
with self.assertRaises(ValueError) as ex:
|
with pytest.raises(ValueError) as ex:
|
||||||
DiceConfig(
|
DiceConfig(
|
||||||
|
nprocs=1,
|
||||||
ljname="test",
|
ljname="test",
|
||||||
outname="test",
|
outname="test",
|
||||||
dens=1.0,
|
dens=1.0,
|
||||||
nmol=0,
|
nmol=0,
|
||||||
nstep=[1, 1],
|
nstep=[1, 1],
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
|
||||||
ex.exception,
|
assert ex.value == "Error: 'nmol' keyword not specified in config file"
|
||||||
"Error: 'nmol' keyword not defined appropriately in config file",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_validate_nstep(self):
|
def test_validate_nstep(self):
|
||||||
with self.assertRaises(ValueError) as ex:
|
with pytest.raises(ValueError) as ex:
|
||||||
DiceConfig(
|
DiceConfig(
|
||||||
|
nprocs=1,
|
||||||
ljname="test",
|
ljname="test",
|
||||||
outname="test",
|
outname="test",
|
||||||
dens=1.0,
|
dens=1.0,
|
||||||
nmol=[1],
|
nmol=[1],
|
||||||
nstep=0,
|
nstep=0,
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
|
||||||
ex.exception,
|
assert ex.value == "Error: 'nstep' keyword not specified in config file"
|
||||||
"Error: 'nstep' keyword not defined appropriately in config file",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_from_dict(self):
|
def test_from_dict(self):
|
||||||
dice_dto = DiceConfig.from_dict(
|
dice_dto = DiceConfig.model_validate(
|
||||||
{
|
{
|
||||||
|
"nprocs": 1,
|
||||||
"ljname": "test",
|
"ljname": "test",
|
||||||
"outname": "test",
|
"outname": "test",
|
||||||
"dens": 1.0,
|
"dens": 1.0,
|
||||||
@@ -93,4 +93,4 @@ class TestDiceDto(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertIsInstance(dice_dto, DiceConfig)
|
assert isinstance(dice_dto, DiceConfig)
|
||||||
@@ -1,36 +1,36 @@
|
|||||||
from diceplayer.shared.config.gaussian_config import GaussianDTO
|
from diceplayer.config.gaussian_config import GaussianConfig
|
||||||
|
|
||||||
import unittest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
class TestGaussianDTO(unittest.TestCase):
|
class TestGaussianConfig:
|
||||||
def test_class_instantiation(self):
|
def test_class_instantiation(self):
|
||||||
gaussian_dto = GaussianDTO(
|
gaussian_dto = GaussianConfig(
|
||||||
level="test",
|
level="test",
|
||||||
qmprog="g16",
|
qmprog="g16",
|
||||||
keywords="test",
|
keywords="test",
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertIsInstance(gaussian_dto, GaussianDTO)
|
assert isinstance(gaussian_dto, GaussianConfig)
|
||||||
|
|
||||||
def test_is_valid_qmprog(self):
|
def test_is_valid_qmprog(self):
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
gaussian_dto = GaussianDTO(
|
GaussianConfig(
|
||||||
level="test",
|
level="test",
|
||||||
qmprog="test",
|
qmprog="test",
|
||||||
keywords="test",
|
keywords="test",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_is_valid_level(self):
|
def test_is_valid_level(self):
|
||||||
with self.assertRaises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
gaussian_dto = GaussianDTO(
|
GaussianConfig(
|
||||||
level=None,
|
level=None,
|
||||||
qmprog="g16",
|
qmprog="g16",
|
||||||
keywords="test",
|
keywords="test",
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_from_dict(self):
|
def test_from_dict(self):
|
||||||
gaussian_dto = GaussianDTO.from_dict(
|
gaussian_dto = GaussianConfig.model_validate(
|
||||||
{
|
{
|
||||||
"level": "test",
|
"level": "test",
|
||||||
"qmprog": "g16",
|
"qmprog": "g16",
|
||||||
@@ -38,8 +38,4 @@ class TestGaussianDTO(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertIsInstance(gaussian_dto, GaussianDTO)
|
assert isinstance(gaussian_dto, GaussianConfig)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
90
tests/config/test_player_config.py
Normal file
90
tests/config/test_player_config.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
from diceplayer.config.dice_config import DiceConfig
|
||||||
|
from diceplayer.config.gaussian_config import GaussianConfig
|
||||||
|
from diceplayer.config.player_config import PlayerConfig, RoutineType
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class TestPlayerConfig:
|
||||||
|
@pytest.fixture
|
||||||
|
def dice_payload(self) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"nprocs": 4,
|
||||||
|
"ljname": "test",
|
||||||
|
"outname": "test",
|
||||||
|
"dens": 1.0,
|
||||||
|
"nmol": [1],
|
||||||
|
"nstep": [1, 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def gaussian_payload(self) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"level": "test",
|
||||||
|
"qmprog": "g16",
|
||||||
|
"keywords": "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def player_payload(
|
||||||
|
self, dice_payload: dict[str, Any], gaussian_payload: dict[str, Any]
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"type": "both",
|
||||||
|
"mem": 12,
|
||||||
|
"max_cyc": 100,
|
||||||
|
"switch_cyc": 50,
|
||||||
|
"ncores": 4,
|
||||||
|
"dice": dice_payload,
|
||||||
|
"gaussian": gaussian_payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def dice_config(self, dice_payload: dict[str, Any]) -> DiceConfig:
|
||||||
|
return DiceConfig.model_validate(dice_payload)
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def gaussian_config(self, gaussian_payload: dict[str, Any]):
|
||||||
|
return GaussianConfig.model_validate(gaussian_payload)
|
||||||
|
|
||||||
|
def test_class_instantiation(
|
||||||
|
self, dice_config: DiceConfig, gaussian_config: GaussianConfig
|
||||||
|
):
|
||||||
|
player_dto = PlayerConfig(
|
||||||
|
type=RoutineType.BOTH,
|
||||||
|
mem=12,
|
||||||
|
max_cyc=100,
|
||||||
|
switch_cyc=50,
|
||||||
|
ncores=4,
|
||||||
|
dice=dice_config,
|
||||||
|
gaussian=gaussian_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert isinstance(player_dto, PlayerConfig)
|
||||||
|
assert isinstance(player_dto.dice, DiceConfig)
|
||||||
|
assert isinstance(player_dto.gaussian, GaussianConfig)
|
||||||
|
|
||||||
|
def test_min_altsteps(
|
||||||
|
self, dice_config: DiceConfig, gaussian_config: GaussianConfig
|
||||||
|
):
|
||||||
|
player_dto = PlayerConfig(
|
||||||
|
type=RoutineType.BOTH,
|
||||||
|
mem=12,
|
||||||
|
max_cyc=100,
|
||||||
|
switch_cyc=50,
|
||||||
|
ncores=4,
|
||||||
|
altsteps=0,
|
||||||
|
dice=dice_config,
|
||||||
|
gaussian=gaussian_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert player_dto.altsteps == 20000
|
||||||
|
|
||||||
|
def test_from_dict(self, player_payload: dict[str, Any]):
|
||||||
|
player_dto = PlayerConfig.model_validate(player_payload)
|
||||||
|
|
||||||
|
assert isinstance(player_dto, PlayerConfig)
|
||||||
|
assert isinstance(player_dto.dice, DiceConfig)
|
||||||
|
assert isinstance(player_dto.gaussian, GaussianConfig)
|
||||||
92
tests/dice/test_dice_handler.py
Normal file
92
tests/dice/test_dice_handler.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
from diceplayer.config import DiceConfig, GaussianConfig, PlayerConfig
|
||||||
|
from diceplayer.dice.dice_handler import DiceHandler
|
||||||
|
from diceplayer.dice.dice_wrapper import DiceWrapper
|
||||||
|
from diceplayer.state.state_model import StateModel
|
||||||
|
from diceplayer.utils.potential import read_system_from_phb
|
||||||
|
from tests._assets import ASSETS_DIR
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class TestDiceHandler:
|
||||||
|
@pytest.fixture
|
||||||
|
def working_directory(self) -> Path:
|
||||||
|
return ASSETS_DIR
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def player_config(self, working_directory: Path) -> PlayerConfig:
|
||||||
|
return PlayerConfig(
|
||||||
|
type="both",
|
||||||
|
mem=12,
|
||||||
|
max_cyc=100,
|
||||||
|
switch_cyc=50,
|
||||||
|
ncores=4,
|
||||||
|
dice=DiceConfig(
|
||||||
|
nprocs=4,
|
||||||
|
ljname=working_directory / "phb.ljc",
|
||||||
|
outname="test",
|
||||||
|
dens=1.0,
|
||||||
|
nmol=[1, 200],
|
||||||
|
nstep=[1000, 1000],
|
||||||
|
),
|
||||||
|
gaussian=GaussianConfig(
|
||||||
|
level="test",
|
||||||
|
qmprog="g16",
|
||||||
|
keywords="test",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def state_model(self, player_config: PlayerConfig) -> StateModel:
|
||||||
|
return StateModel(
|
||||||
|
config=player_config,
|
||||||
|
system=read_system_from_phb(player_config),
|
||||||
|
current_cycle=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def dice_wrapper(
|
||||||
|
self, player_config: PlayerConfig, working_directory: Path
|
||||||
|
) -> DiceWrapper:
|
||||||
|
return DiceWrapper(player_config.dice, working_directory)
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def dice_handler(self, tmp_path) -> DiceHandler:
|
||||||
|
return DiceHandler(tmp_path)
|
||||||
|
|
||||||
|
def test_filter_environment_sites(
|
||||||
|
self,
|
||||||
|
dice_handler: DiceHandler,
|
||||||
|
dice_wrapper: DiceWrapper,
|
||||||
|
state_model: StateModel,
|
||||||
|
) -> None:
|
||||||
|
environment = dice_wrapper.parse_results()[0]
|
||||||
|
|
||||||
|
filtered_environment = dice_handler._filter_environment_sites(
|
||||||
|
state_model, environment
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(filtered_environment) < environment.number_of_sites
|
||||||
|
|
||||||
|
def test_aggregate_results(
|
||||||
|
self,
|
||||||
|
dice_handler: DiceHandler,
|
||||||
|
dice_wrapper: DiceWrapper,
|
||||||
|
state_model: StateModel,
|
||||||
|
) -> None:
|
||||||
|
environments = dice_wrapper.parse_results()
|
||||||
|
|
||||||
|
picked_environments = [
|
||||||
|
dice_handler._filter_environment_sites(state_model, env)
|
||||||
|
for env in environments
|
||||||
|
]
|
||||||
|
|
||||||
|
aggregated_environment = dice_handler._aggregate_results(
|
||||||
|
state_model, picked_environments
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(aggregated_environment) == sum(
|
||||||
|
len(env) for env in picked_environments
|
||||||
|
)
|
||||||
67
tests/dice/test_dice_input.py
Normal file
67
tests/dice/test_dice_input.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
from diceplayer.dice.dice_input import (
|
||||||
|
NPTEqConfig,
|
||||||
|
NPTTerConfig,
|
||||||
|
NVTEqConfig,
|
||||||
|
NVTTerConfig,
|
||||||
|
write_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class TestDiceInput:
|
||||||
|
@pytest.fixture
|
||||||
|
def player_config(self) -> PlayerConfig:
|
||||||
|
return PlayerConfig.model_validate(
|
||||||
|
{
|
||||||
|
"type": "both",
|
||||||
|
"mem": 12,
|
||||||
|
"max_cyc": 100,
|
||||||
|
"switch_cyc": 50,
|
||||||
|
"ncores": 4,
|
||||||
|
"dice": {
|
||||||
|
"nprocs": 4,
|
||||||
|
"ljname": "test",
|
||||||
|
"outname": "test",
|
||||||
|
"dens": 1.0,
|
||||||
|
"nmol": [1],
|
||||||
|
"nstep": [1, 1],
|
||||||
|
},
|
||||||
|
"gaussian": {
|
||||||
|
"level": "test",
|
||||||
|
"qmprog": "g16",
|
||||||
|
"keywords": "test",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_generate_nvt_ter_input(self, player_config: PlayerConfig):
|
||||||
|
dice_input = NVTTerConfig.from_config(player_config)
|
||||||
|
|
||||||
|
assert isinstance(dice_input, NVTTerConfig)
|
||||||
|
|
||||||
|
def test_generate_nvt_eq_input(self, player_config: PlayerConfig):
|
||||||
|
dice_input = NVTEqConfig.from_config(player_config)
|
||||||
|
|
||||||
|
assert isinstance(dice_input, NVTEqConfig)
|
||||||
|
|
||||||
|
def test_generate_npt_ter_input(self, player_config: PlayerConfig):
|
||||||
|
dice_input = NPTTerConfig.from_config(player_config)
|
||||||
|
|
||||||
|
assert isinstance(dice_input, NPTTerConfig)
|
||||||
|
|
||||||
|
def test_generate_npt_eq_input(self, player_config: PlayerConfig):
|
||||||
|
dice_input = NPTEqConfig.from_config(player_config)
|
||||||
|
|
||||||
|
assert isinstance(dice_input, NPTEqConfig)
|
||||||
|
|
||||||
|
def test_write_dice_config(self, player_config: PlayerConfig, tmp_path: Path):
|
||||||
|
dice_input = NVTTerConfig.from_config(player_config)
|
||||||
|
|
||||||
|
output_file = tmp_path / dice_input.type
|
||||||
|
write_config(dice_input, tmp_path)
|
||||||
|
|
||||||
|
assert output_file.exists()
|
||||||
38
tests/dice/test_dice_wrapper.py
Normal file
38
tests/dice/test_dice_wrapper.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from diceplayer.config import DiceConfig
|
||||||
|
from diceplayer.dice.dice_wrapper import DiceEnvironment, DiceWrapper
|
||||||
|
from tests._assets import ASSETS_DIR
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class TestDiceWrapper:
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def dice_config(self) -> DiceConfig:
|
||||||
|
return DiceConfig.model_validate(
|
||||||
|
{
|
||||||
|
"nprocs": 4,
|
||||||
|
"ljname": "test",
|
||||||
|
"outname": "test",
|
||||||
|
"dens": 1.0,
|
||||||
|
"nmol": [1],
|
||||||
|
"nstep": [1, 1],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def working_directory(self) -> Path:
|
||||||
|
return ASSETS_DIR
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def dice_wrapper(
|
||||||
|
self, dice_config: DiceConfig, working_directory: Path
|
||||||
|
) -> DiceWrapper:
|
||||||
|
return DiceWrapper(dice_config, working_directory)
|
||||||
|
|
||||||
|
def test_parse_results(self, dice_wrapper: DiceWrapper) -> None:
|
||||||
|
results = dice_wrapper.parse_results()
|
||||||
|
|
||||||
|
assert isinstance(results, list)
|
||||||
|
assert all(isinstance(env, DiceEnvironment) for env in results)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from diceplayer.shared.environment.atom import Atom
|
from diceplayer.environment import Atom
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
from diceplayer.shared.environment.atom import Atom
|
from diceplayer.environment import Atom, Molecule
|
||||||
from diceplayer.shared.environment.molecule import Molecule
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.testing as npt
|
import numpy.testing as npt
|
||||||
@@ -42,7 +41,7 @@ class TestMolecule(unittest.TestCase):
|
|||||||
Atom(lbl=1, na=1, rx=1.0, ry=1.0, rz=1.0, chg=1.0, eps=1.0, sig=1.0)
|
Atom(lbl=1, na=1, rx=1.0, ry=1.0, rz=1.0, chg=1.0, eps=1.0, sig=1.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
mol.center_of_mass_to_origin()
|
mol.move_center_of_mass_to_origin()
|
||||||
|
|
||||||
npt.assert_equal(mol.com, [0, 0, 0])
|
npt.assert_equal(mol.com, [0, 0, 0])
|
||||||
|
|
||||||
@@ -69,12 +68,10 @@ class TestMolecule(unittest.TestCase):
|
|||||||
Atom(lbl=1, na=1, rx=1.0, ry=1.0, rz=1.0, chg=1.0, eps=1.0, sig=1.0)
|
Atom(lbl=1, na=1, rx=1.0, ry=1.0, rz=1.0, chg=1.0, eps=1.0, sig=1.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_distance_between_atoms = [[1.73205081], [1.73205081]]
|
expected = [[0.0, 1.73205081], [1.73205081, 0.0]]
|
||||||
actual_distance_between_atoms = mol.distances_between_atoms()
|
actual = mol.distances_between_atoms()
|
||||||
|
|
||||||
npt.assert_almost_equal(
|
npt.assert_almost_equal(expected, actual)
|
||||||
expected_distance_between_atoms, actual_distance_between_atoms
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_inertia_tensor(self):
|
def test_inertia_tensor(self):
|
||||||
mol = Molecule("test")
|
mol = Molecule("test")
|
||||||
@@ -92,7 +89,7 @@ class TestMolecule(unittest.TestCase):
|
|||||||
[-0.50395, -0.50395, 1.0079],
|
[-0.50395, -0.50395, 1.0079],
|
||||||
]
|
]
|
||||||
|
|
||||||
actual_inertia_tensor = mol.inertia_tensor()
|
actual_inertia_tensor = mol.inertia_tensor
|
||||||
|
|
||||||
npt.assert_equal(expected_inertia_tensor, actual_inertia_tensor)
|
npt.assert_equal(expected_inertia_tensor, actual_inertia_tensor)
|
||||||
|
|
||||||
@@ -103,11 +100,14 @@ class TestMolecule(unittest.TestCase):
|
|||||||
Atom(lbl=1, na=1, rx=0.0, ry=0.0, rz=0.0, chg=1.0, eps=1.0, sig=1.0)
|
Atom(lbl=1, na=1, rx=0.0, ry=0.0, rz=0.0, chg=1.0, eps=1.0, sig=1.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_evals, expected_evecs = [0.0, 0.0, 0.0], [
|
expected_evals, expected_evecs = (
|
||||||
[1.0, 0.0, 0.0],
|
[0.0, 0.0, 0.0],
|
||||||
[0.0, 1.0, 0.0],
|
[
|
||||||
[0.0, 0.0, 1.0],
|
[1.0, 0.0, 0.0],
|
||||||
]
|
[0.0, 1.0, 0.0],
|
||||||
|
[0.0, 0.0, 1.0],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
evals, evecs = mol.principal_axes()
|
evals, evecs = mol.principal_axes()
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ class TestMolecule(unittest.TestCase):
|
|||||||
Atom(lbl=1, na=1, rx=1.0, ry=1.0, rz=1.0, chg=1.0, eps=1.0, sig=1.0)
|
Atom(lbl=1, na=1, rx=1.0, ry=1.0, rz=1.0, chg=1.0, eps=1.0, sig=1.0)
|
||||||
)
|
)
|
||||||
|
|
||||||
mol.standard_orientation()
|
mol.rotate_to_standard_orientation()
|
||||||
|
|
||||||
expected_position = [0.0, 0.0, 0.0]
|
expected_position = [0.0, 0.0, 0.0]
|
||||||
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
from diceplayer.shared.environment.atom import Atom
|
from diceplayer.environment import Molecule, System
|
||||||
from diceplayer.shared.environment.molecule import Molecule
|
|
||||||
from diceplayer.shared.environment.system import System
|
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
from unittest import mock
|
|
||||||
|
|
||||||
|
|
||||||
def get_config_example():
|
|
||||||
return """
|
|
||||||
diceplayer:
|
|
||||||
opt: no
|
|
||||||
mem: 12
|
|
||||||
maxcyc: 3
|
|
||||||
ncores: 4
|
|
||||||
nprocs: 4
|
|
||||||
qmprog: 'g16'
|
|
||||||
lps: no
|
|
||||||
ghosts: no
|
|
||||||
altsteps: 20000
|
|
||||||
|
|
||||||
dice:
|
|
||||||
nmol: [1, 50]
|
|
||||||
dens: 0.75
|
|
||||||
nstep: [2000, 3000, 4000]
|
|
||||||
isave: 1000
|
|
||||||
outname: 'phb'
|
|
||||||
progname: '~/.local/bin/dice'
|
|
||||||
ljname: 'phb.ljc'
|
|
||||||
randominit: 'first'
|
|
||||||
|
|
||||||
gaussian:
|
|
||||||
qmprog: 'g16'
|
|
||||||
level: 'MP2/aug-cc-pVDZ'
|
|
||||||
keywords: 'freq'
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def get_potentials_exemple():
|
|
||||||
return """\
|
|
||||||
*
|
|
||||||
2
|
|
||||||
1 TEST
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
1 PLACEHOLDER
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def get_potentials_error_combrule():
|
|
||||||
return """\
|
|
||||||
.
|
|
||||||
2
|
|
||||||
1 TEST
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
1 PLACEHOLDER
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def get_potentials_error_ntypes():
|
|
||||||
return """\
|
|
||||||
*
|
|
||||||
a
|
|
||||||
1 TEST
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
1 PLACEHOLDER
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def get_potentials_error_ntypes_config():
|
|
||||||
return """\
|
|
||||||
*
|
|
||||||
3
|
|
||||||
1 TEST
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
1 PLACEHOLDER
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def get_potentials_error_nsites():
|
|
||||||
return """\
|
|
||||||
*
|
|
||||||
2
|
|
||||||
. TEST
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
1 PLACEHOLDER
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def get_potentials_error_molname():
|
|
||||||
return """\
|
|
||||||
*
|
|
||||||
2
|
|
||||||
1
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
1 PLACEHOLDER
|
|
||||||
1 1 0.000000 0.000000 0.000000 0.000000 0.0000 0.0000
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def mock_open(file, *args, **kwargs):
|
|
||||||
values = {
|
|
||||||
"control.test.yml": get_config_example(),
|
|
||||||
"phb.ljc": get_potentials_exemple(),
|
|
||||||
"phb.error.combrule.ljc": get_potentials_error_combrule(),
|
|
||||||
"phb.error.ntypes.ljc": get_potentials_error_ntypes(),
|
|
||||||
"phb.error.ntypes.config.ljc": get_potentials_error_ntypes_config(),
|
|
||||||
"phb.error.nsites.ljc": get_potentials_error_nsites(),
|
|
||||||
"phb.error.molname.ljc": get_potentials_error_molname(),
|
|
||||||
}
|
|
||||||
if file in values:
|
|
||||||
return mock.mock_open(read_data=values[file])()
|
|
||||||
|
|
||||||
return mock.mock_open(read_data="")()
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import itertools
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
|
|
||||||
class MockProc:
|
|
||||||
pid_counter = itertools.count()
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.pid = next(MockProc.pid_counter)
|
|
||||||
|
|
||||||
if "exitcode" in kwargs:
|
|
||||||
self.exitcode = kwargs["exitcode"]
|
|
||||||
else:
|
|
||||||
self.exitcode = 0
|
|
||||||
|
|
||||||
self.sentinel = self.pid
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def terminate(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class MockConnection:
|
|
||||||
@staticmethod
|
|
||||||
def wait(sentinels: List[int]):
|
|
||||||
return sentinels
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
from diceplayer.shared.config.dice_config import DiceConfig
|
|
||||||
from diceplayer.shared.config.gaussian_config import GaussianDTO
|
|
||||||
from diceplayer.shared.config.player_config import PlayerConfig
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
|
|
||||||
def get_config_dict():
|
|
||||||
return {
|
|
||||||
"opt": True,
|
|
||||||
"mem": 12,
|
|
||||||
"maxcyc": 100,
|
|
||||||
"nprocs": 4,
|
|
||||||
"ncores": 4,
|
|
||||||
"dice": {
|
|
||||||
"ljname": "test",
|
|
||||||
"outname": "test",
|
|
||||||
"dens": 1.0,
|
|
||||||
"nmol": [1],
|
|
||||||
"nstep": [1, 1],
|
|
||||||
},
|
|
||||||
"gaussian": {
|
|
||||||
"level": "test",
|
|
||||||
"qmprog": "g16",
|
|
||||||
"keywords": "test",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class TestPlayerDTO(unittest.TestCase):
|
|
||||||
def setUp(self) -> None:
|
|
||||||
self.dice_dto = DiceConfig(
|
|
||||||
ljname="test",
|
|
||||||
outname="test",
|
|
||||||
dens=1.0,
|
|
||||||
nmol=[1],
|
|
||||||
nstep=[1, 1],
|
|
||||||
)
|
|
||||||
self.gaussian_dto = GaussianDTO(
|
|
||||||
level="test",
|
|
||||||
qmprog="g16",
|
|
||||||
keywords="test",
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_class_instantiation(self):
|
|
||||||
player_dto = PlayerConfig(
|
|
||||||
opt=True,
|
|
||||||
mem=12,
|
|
||||||
maxcyc=100,
|
|
||||||
nprocs=4,
|
|
||||||
ncores=4,
|
|
||||||
dice=self.dice_dto,
|
|
||||||
gaussian=self.gaussian_dto,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertIsInstance(player_dto, PlayerConfig)
|
|
||||||
self.assertIsInstance(player_dto.dice, DiceConfig)
|
|
||||||
self.assertIsInstance(player_dto.gaussian, GaussianDTO)
|
|
||||||
|
|
||||||
def test_min_altsteps(self):
|
|
||||||
player_dto = PlayerConfig(
|
|
||||||
opt=True,
|
|
||||||
mem=12,
|
|
||||||
maxcyc=100,
|
|
||||||
nprocs=4,
|
|
||||||
ncores=4,
|
|
||||||
altsteps=100,
|
|
||||||
dice=self.dice_dto,
|
|
||||||
gaussian=self.gaussian_dto,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(player_dto.altsteps, 20000)
|
|
||||||
|
|
||||||
def test_from_dict(self):
|
|
||||||
player_dto = PlayerConfig.from_dict(get_config_dict())
|
|
||||||
|
|
||||||
self.assertIsInstance(player_dto, PlayerConfig)
|
|
||||||
self.assertIsInstance(player_dto.dice, DiceConfig)
|
|
||||||
self.assertIsInstance(player_dto.gaussian, GaussianDTO)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
@@ -1,661 +0,0 @@
|
|||||||
from diceplayer import logger
|
|
||||||
from diceplayer.shared.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
|
|
||||||
from diceplayer.shared.interface.dice_interface import DiceInterface
|
|
||||||
from tests.mocks.mock_inputs import get_config_example
|
|
||||||
from tests.mocks.mock_proc import MockConnection, MockProc
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
import io
|
|
||||||
import unittest
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
|
|
||||||
class TestDiceInterface(unittest.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
logger.set_logger(stream=io.StringIO())
|
|
||||||
|
|
||||||
config = yaml.load(get_config_example(), Loader=yaml.Loader)
|
|
||||||
self.config = PlayerConfig.from_dict(config["diceplayer"])
|
|
||||||
|
|
||||||
def test_class_instantiation(self):
|
|
||||||
dice = DiceInterface()
|
|
||||||
|
|
||||||
self.assertIsInstance(dice, DiceInterface)
|
|
||||||
|
|
||||||
def test_configure(self):
|
|
||||||
dice = DiceInterface()
|
|
||||||
|
|
||||||
self.assertIsNone(dice.step)
|
|
||||||
self.assertIsNone(dice.system)
|
|
||||||
|
|
||||||
# Ignoring the types for testing purposes
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
self.assertIsNotNone(dice.step)
|
|
||||||
self.assertIsNotNone(dice.system)
|
|
||||||
|
|
||||||
def test_reset(self):
|
|
||||||
dice = DiceInterface()
|
|
||||||
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
self.assertTrue(hasattr(dice, "step"))
|
|
||||||
self.assertTrue(hasattr(dice, "system"))
|
|
||||||
|
|
||||||
dice.reset()
|
|
||||||
|
|
||||||
self.assertFalse(hasattr(dice, "step"))
|
|
||||||
self.assertFalse(hasattr(dice, "system"))
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.Process", MockProc())
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.connection", MockConnection)
|
|
||||||
def test_start(self):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.start(1)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.connection", MockConnection)
|
|
||||||
@mock.patch(
|
|
||||||
"diceplayer.shared.interface.dice_interface.Process", MockProc(exitcode=1)
|
|
||||||
)
|
|
||||||
def test_start_with_process_error(self):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
with self.assertRaises(SystemExit):
|
|
||||||
dice.start(1)
|
|
||||||
|
|
||||||
def test_simulation_process_raises_exception(self):
|
|
||||||
dice = DiceInterface()
|
|
||||||
|
|
||||||
with self.assertRaises(SystemExit):
|
|
||||||
dice._simulation_process(1, 1)
|
|
||||||
|
|
||||||
@mock.patch(
|
|
||||||
"diceplayer.shared.interface.dice_interface.DiceInterface._make_proc_dir"
|
|
||||||
)
|
|
||||||
@mock.patch(
|
|
||||||
"diceplayer.shared.interface.dice_interface.DiceInterface._make_dice_inputs"
|
|
||||||
)
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.DiceInterface._run_dice")
|
|
||||||
def test_simulation_process(
|
|
||||||
self, mock_run_dice, mock_make_dice_inputs, mock_make_proc_dir
|
|
||||||
):
|
|
||||||
dice = DiceInterface()
|
|
||||||
|
|
||||||
dice._simulation_process(1, 1)
|
|
||||||
|
|
||||||
self.assertTrue(dice._make_proc_dir.called)
|
|
||||||
self.assertTrue(dice._make_dice_inputs.called)
|
|
||||||
self.assertTrue(dice._run_dice.called)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.Path.mkdir")
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.Path.exists")
|
|
||||||
def test_make_proc_dir_if_simdir_exists(self, mock_path_exists, mock_path_mkdir):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
mock_path_exists.return_value = False
|
|
||||||
|
|
||||||
dice._make_proc_dir(1, 1)
|
|
||||||
|
|
||||||
self.assertEqual(mock_path_mkdir.call_count, 2)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.Path.mkdir")
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.Path.exists")
|
|
||||||
def test_make_proc_dir_if_simdir_doesnt_exists(
|
|
||||||
self, mock_path_exists, mock_path_mkdir
|
|
||||||
):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
mock_path_exists.return_value = False
|
|
||||||
|
|
||||||
dice._make_proc_dir(1, 1)
|
|
||||||
|
|
||||||
self.assertEqual(mock_path_mkdir.call_count, 2)
|
|
||||||
|
|
||||||
def test_make_dice_seed(self):
|
|
||||||
seed = DiceInterface._make_dice_seed()
|
|
||||||
|
|
||||||
self.assertIsInstance(seed, int)
|
|
||||||
|
|
||||||
def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_one(self):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.step.dice.nstep = [1, 1]
|
|
||||||
|
|
||||||
dice._make_potentials = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_init_file = mock.Mock()
|
|
||||||
dice._new_density = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_nvt_ter = mock.Mock()
|
|
||||||
dice._make_nvt_eq = mock.Mock()
|
|
||||||
dice._make_npt_ter = mock.Mock()
|
|
||||||
dice._make_npt_eq = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_dice_inputs(1, 1)
|
|
||||||
|
|
||||||
self.assertTrue(dice._make_potentials.called)
|
|
||||||
|
|
||||||
self.assertFalse(dice._make_init_file.called)
|
|
||||||
self.assertFalse(dice._new_density.called)
|
|
||||||
|
|
||||||
self.assertTrue(dice._make_nvt_ter.called)
|
|
||||||
self.assertTrue(dice._make_nvt_eq.called)
|
|
||||||
|
|
||||||
self.assertFalse(dice._make_npt_ter.called)
|
|
||||||
self.assertFalse(dice._make_npt_eq.called)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open, read_data="test")
|
|
||||||
@mock.patch(
|
|
||||||
"diceplayer.shared.interface.dice_interface.Path.exists", return_value=True
|
|
||||||
)
|
|
||||||
def test_make_dice_inputs_nstep_len_two_with_randoninit_first_cycle_two(
|
|
||||||
self, mock_path_exists, mock_open
|
|
||||||
):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.step.dice.nstep = [1, 1]
|
|
||||||
|
|
||||||
dice._make_potentials = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_init_file = mock.Mock()
|
|
||||||
dice._new_density = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_nvt_ter = mock.Mock()
|
|
||||||
dice._make_nvt_eq = mock.Mock()
|
|
||||||
dice._make_npt_ter = mock.Mock()
|
|
||||||
dice._make_npt_eq = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_dice_inputs(2, 1)
|
|
||||||
|
|
||||||
self.assertTrue(dice._make_potentials.called)
|
|
||||||
|
|
||||||
self.assertTrue(dice._make_init_file.called)
|
|
||||||
self.assertTrue(dice._new_density.called)
|
|
||||||
|
|
||||||
self.assertFalse(dice._make_nvt_ter.called)
|
|
||||||
self.assertTrue(dice._make_nvt_eq.called)
|
|
||||||
|
|
||||||
self.assertFalse(dice._make_npt_ter.called)
|
|
||||||
self.assertFalse(dice._make_npt_eq.called)
|
|
||||||
|
|
||||||
@mock.patch(
|
|
||||||
"diceplayer.shared.interface.dice_interface.Path.exists", return_value=False
|
|
||||||
)
|
|
||||||
def test_make_dice_inputs_raises_exception_on_last_not_found(
|
|
||||||
self, mock_path_exists
|
|
||||||
):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.step.dice.nstep = [1, 1]
|
|
||||||
|
|
||||||
dice._make_potentials = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_init_file = mock.Mock()
|
|
||||||
dice._new_density = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_nvt_ter = mock.Mock()
|
|
||||||
dice._make_nvt_eq = mock.Mock()
|
|
||||||
dice._make_npt_ter = mock.Mock()
|
|
||||||
dice._make_npt_eq = mock.Mock()
|
|
||||||
|
|
||||||
with self.assertRaises(FileNotFoundError):
|
|
||||||
dice._make_dice_inputs(2, 1)
|
|
||||||
|
|
||||||
def test_make_dice_inputs_nstep_len_three_with_randoninit_first_cycle_one(self):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice._make_potentials = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_init_file = mock.Mock()
|
|
||||||
dice._new_density = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_nvt_ter = mock.Mock()
|
|
||||||
dice._make_nvt_eq = mock.Mock()
|
|
||||||
dice._make_npt_ter = mock.Mock()
|
|
||||||
dice._make_npt_eq = mock.Mock()
|
|
||||||
|
|
||||||
dice._make_dice_inputs(1, 1)
|
|
||||||
|
|
||||||
self.assertTrue(dice._make_potentials.called)
|
|
||||||
|
|
||||||
self.assertFalse(dice._make_init_file.called)
|
|
||||||
self.assertFalse(dice._new_density.called)
|
|
||||||
|
|
||||||
self.assertTrue(dice._make_nvt_ter.called)
|
|
||||||
self.assertFalse(dice._make_nvt_eq.called)
|
|
||||||
|
|
||||||
self.assertTrue(dice._make_npt_ter.called)
|
|
||||||
self.assertTrue(dice._make_npt_eq.called)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.os")
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.shutil")
|
|
||||||
@mock.patch(
|
|
||||||
"diceplayer.shared.interface.dice_interface.Path.exists", return_value=True
|
|
||||||
)
|
|
||||||
def test_run_dice_on_first_cycle_run_successful(
|
|
||||||
self, mock_path_exists, mock_shutils, mock_os
|
|
||||||
):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.step.dice.nstep = [1, 1, 1]
|
|
||||||
|
|
||||||
dice.run_dice_file = mock.Mock()
|
|
||||||
|
|
||||||
dice._run_dice(1, 1)
|
|
||||||
|
|
||||||
self.assertTrue(mock_os.getcwd.called)
|
|
||||||
self.assertTrue(mock_os.chdir.called)
|
|
||||||
|
|
||||||
self.assertEqual(dice.run_dice_file.call_count, 3)
|
|
||||||
self.assertTrue(mock_shutils.copy.called)
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.step.dice.nstep = [1, 1]
|
|
||||||
|
|
||||||
dice.run_dice_file = mock.Mock()
|
|
||||||
|
|
||||||
dice._run_dice(1, 1)
|
|
||||||
|
|
||||||
self.assertTrue(mock_os.getcwd.called)
|
|
||||||
self.assertTrue(mock_os.chdir.called)
|
|
||||||
|
|
||||||
self.assertEqual(dice.run_dice_file.call_count, 2)
|
|
||||||
self.assertTrue(mock_shutils.copy.called)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.os")
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.shutil")
|
|
||||||
@mock.patch(
|
|
||||||
"diceplayer.shared.interface.dice_interface.Path.exists", return_value=True
|
|
||||||
)
|
|
||||||
def test_run_dice_on_second_cycle_run_successful(
|
|
||||||
self, mock_path_exists, mock_shutils, mock_os
|
|
||||||
):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.run_dice_file = mock.Mock()
|
|
||||||
|
|
||||||
dice._run_dice(2, 1)
|
|
||||||
|
|
||||||
self.assertTrue(mock_os.getcwd.called)
|
|
||||||
self.assertTrue(mock_os.chdir.called)
|
|
||||||
|
|
||||||
self.assertEqual(dice.run_dice_file.call_count, 2)
|
|
||||||
self.assertTrue(mock_shutils.copy.called)
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.run_dice_file = mock.Mock()
|
|
||||||
|
|
||||||
dice._run_dice(2, 1)
|
|
||||||
|
|
||||||
self.assertTrue(mock_os.getcwd.called)
|
|
||||||
self.assertTrue(mock_os.chdir.called)
|
|
||||||
|
|
||||||
self.assertEqual(dice.run_dice_file.call_count, 1)
|
|
||||||
self.assertTrue(mock_shutils.copy.called)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.os")
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.shutil")
|
|
||||||
@mock.patch(
|
|
||||||
"diceplayer.shared.interface.dice_interface.Path.exists", return_value=False
|
|
||||||
)
|
|
||||||
def test_run_dice_on_second_cycle_run_successful(
|
|
||||||
self, mock_path_exists, mock_shutils, mock_os
|
|
||||||
):
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.run_dice_file = mock.Mock()
|
|
||||||
|
|
||||||
with self.assertRaises(FileNotFoundError):
|
|
||||||
dice._run_dice(1, 1)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
||||||
def test_make_init_file(self, mock_open):
|
|
||||||
example_atom = Atom(
|
|
||||||
lbl=1,
|
|
||||||
na=1,
|
|
||||||
rx=1.0,
|
|
||||||
ry=1.0,
|
|
||||||
rz=1.0,
|
|
||||||
chg=1.0,
|
|
||||||
eps=1.0,
|
|
||||||
sig=1.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
main_molecule = Molecule("main_molecule")
|
|
||||||
main_molecule.add_atom(example_atom)
|
|
||||||
|
|
||||||
secondary_molecule = Molecule("secondary_molecule")
|
|
||||||
secondary_molecule.add_atom(example_atom)
|
|
||||||
|
|
||||||
system = System()
|
|
||||||
system.add_type(main_molecule)
|
|
||||||
system.add_type(secondary_molecule)
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, system)
|
|
||||||
|
|
||||||
dice.step.dice.nmol = [1, 1]
|
|
||||||
|
|
||||||
last_xyz_file = io.StringIO()
|
|
||||||
last_xyz_file.writelines(
|
|
||||||
[
|
|
||||||
" TEST\n",
|
|
||||||
" Configuration number : TEST = TEST TEST TEST\n",
|
|
||||||
" H 1.00000 1.00000 1.00000\n",
|
|
||||||
" H 1.00000 1.00000 1.00000\n",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
last_xyz_file.seek(0)
|
|
||||||
|
|
||||||
dice._make_init_file("test", last_xyz_file)
|
|
||||||
|
|
||||||
mock_handler = mock_open()
|
|
||||||
calls = mock_handler.write.call_args_list
|
|
||||||
|
|
||||||
lines = list(map(lambda x: x[0][0], calls))
|
|
||||||
|
|
||||||
expected_lines = [
|
|
||||||
" 1.000000 1.000000 1.000000\n",
|
|
||||||
" 1.000000 1.000000 1.000000\n",
|
|
||||||
"$end",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(lines, expected_lines)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
||||||
def test_new_density(self, mock_open):
|
|
||||||
example_atom = Atom(
|
|
||||||
lbl=1,
|
|
||||||
na=1,
|
|
||||||
rx=1.0,
|
|
||||||
ry=1.0,
|
|
||||||
rz=1.0,
|
|
||||||
chg=1.0,
|
|
||||||
eps=1.0,
|
|
||||||
sig=1.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
main_molecule = Molecule("main_molecule")
|
|
||||||
main_molecule.add_atom(example_atom)
|
|
||||||
|
|
||||||
secondary_molecule = Molecule("secondary_molecule")
|
|
||||||
secondary_molecule.add_atom(example_atom)
|
|
||||||
|
|
||||||
system = System()
|
|
||||||
system.add_type(main_molecule)
|
|
||||||
system.add_type(secondary_molecule)
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, system)
|
|
||||||
|
|
||||||
last_xyz_file = io.StringIO()
|
|
||||||
last_xyz_file.writelines(
|
|
||||||
[
|
|
||||||
" TEST\n",
|
|
||||||
" Configuration number : TEST = 1 1 1\n",
|
|
||||||
" H 1.00000 1.00000 1.00000\n",
|
|
||||||
" H 1.00000 1.00000 1.00000\n",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
last_xyz_file.seek(0)
|
|
||||||
|
|
||||||
density = dice._new_density(last_xyz_file)
|
|
||||||
|
|
||||||
self.assertEqual(density, 85.35451545000001)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.random")
|
|
||||||
def test_make_nvt_ter(self, mock_random, mock_open):
|
|
||||||
mock_random.random.return_value = 1
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice._make_nvt_ter(1, "test")
|
|
||||||
|
|
||||||
mock_handler = mock_open()
|
|
||||||
calls = mock_handler.write.call_args_list
|
|
||||||
|
|
||||||
lines = list(map(lambda x: x[0][0], calls))
|
|
||||||
|
|
||||||
expected_lines = [
|
|
||||||
"title = Diceplayer run - NVT Thermalization\n",
|
|
||||||
"ncores = 4\n",
|
|
||||||
"ljname = phb.ljc\n",
|
|
||||||
"outname = phb\n",
|
|
||||||
"nmol = 1 50\n",
|
|
||||||
"dens = 0.75\n",
|
|
||||||
"temp = 300.0\n",
|
|
||||||
"init = yes\n",
|
|
||||||
"nstep = 2000\n",
|
|
||||||
"vstep = 0\n",
|
|
||||||
"mstop = 1\n",
|
|
||||||
"accum = no\n",
|
|
||||||
"iprint = 1\n",
|
|
||||||
"isave = 0\n",
|
|
||||||
"irdf = 0\n",
|
|
||||||
"seed = 1000000\n",
|
|
||||||
"upbuf = 360",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(lines, expected_lines)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.random")
|
|
||||||
def test_make_nvt_eq(self, mock_random, mock_open):
|
|
||||||
mock_random.random.return_value = 1
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice._make_nvt_eq(1, "test")
|
|
||||||
|
|
||||||
mock_handler = mock_open()
|
|
||||||
calls = mock_handler.write.call_args_list
|
|
||||||
|
|
||||||
lines = list(map(lambda x: x[0][0], calls))
|
|
||||||
|
|
||||||
expected_lines = [
|
|
||||||
"title = Diceplayer run - NVT Production\n",
|
|
||||||
"ncores = 4\n",
|
|
||||||
"ljname = phb.ljc\n",
|
|
||||||
"outname = phb\n",
|
|
||||||
"nmol = 1 50\n",
|
|
||||||
"dens = 0.75\n",
|
|
||||||
"temp = 300.0\n",
|
|
||||||
"init = no\n",
|
|
||||||
"nstep = 3000\n",
|
|
||||||
"vstep = 0\n",
|
|
||||||
"mstop = 1\n",
|
|
||||||
"accum = no\n",
|
|
||||||
"iprint = 1\n",
|
|
||||||
"isave = 1000\n",
|
|
||||||
"irdf = 40\n",
|
|
||||||
"seed = 1000000\n",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(lines, expected_lines)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.random")
|
|
||||||
def test_make_npt_ter(self, mock_random, mock_open):
|
|
||||||
mock_random.random.return_value = 1
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice._make_npt_ter(1, "test")
|
|
||||||
|
|
||||||
mock_handler = mock_open()
|
|
||||||
calls = mock_handler.write.call_args_list
|
|
||||||
|
|
||||||
lines = list(map(lambda x: x[0][0], calls))
|
|
||||||
|
|
||||||
expected_lines = [
|
|
||||||
"title = Diceplayer run - NPT Thermalization\n",
|
|
||||||
"ncores = 4\n",
|
|
||||||
"ljname = phb.ljc\n",
|
|
||||||
"outname = phb\n",
|
|
||||||
"nmol = 1 50\n",
|
|
||||||
"press = 1.0\n",
|
|
||||||
"temp = 300.0\n",
|
|
||||||
"init = no\n",
|
|
||||||
"vstep = 600\n",
|
|
||||||
"nstep = 5\n",
|
|
||||||
"mstop = 1\n",
|
|
||||||
"accum = no\n",
|
|
||||||
"iprint = 1\n",
|
|
||||||
"isave = 0\n",
|
|
||||||
"irdf = 0\n",
|
|
||||||
"seed = 1000000\n",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(lines, expected_lines)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.random")
|
|
||||||
def test_make_npt_eq(self, mock_random, mock_open):
|
|
||||||
mock_random.random.return_value = 1
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice._make_npt_eq("test")
|
|
||||||
|
|
||||||
mock_handler = mock_open()
|
|
||||||
calls = mock_handler.write.call_args_list
|
|
||||||
|
|
||||||
lines = list(map(lambda x: x[0][0], calls))
|
|
||||||
|
|
||||||
expected_lines = [
|
|
||||||
"title = Diceplayer run - NPT Production\n",
|
|
||||||
"ncores = 4\n",
|
|
||||||
"ljname = phb.ljc\n",
|
|
||||||
"outname = phb\n",
|
|
||||||
"nmol = 1 50\n",
|
|
||||||
"press = 1.0\n",
|
|
||||||
"temp = 300.0\n",
|
|
||||||
"nstep = 5\n",
|
|
||||||
"vstep = 800\n",
|
|
||||||
"init = no\n",
|
|
||||||
"mstop = 1\n",
|
|
||||||
"accum = no\n",
|
|
||||||
"iprint = 1\n",
|
|
||||||
"isave = 1000\n",
|
|
||||||
"irdf = 40\n",
|
|
||||||
"seed = 1000000\n",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(lines, expected_lines)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open)
|
|
||||||
def test_make_potentials(self, mock_open):
|
|
||||||
example_atom = Atom(
|
|
||||||
lbl=1,
|
|
||||||
na=1,
|
|
||||||
rx=1.0,
|
|
||||||
ry=1.0,
|
|
||||||
rz=1.0,
|
|
||||||
chg=1.0,
|
|
||||||
eps=1.0,
|
|
||||||
sig=1.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
main_molecule = Molecule("main_molecule")
|
|
||||||
main_molecule.add_atom(example_atom)
|
|
||||||
|
|
||||||
secondary_molecule = Molecule("secondary_molecule")
|
|
||||||
secondary_molecule.add_atom(example_atom)
|
|
||||||
|
|
||||||
system = System()
|
|
||||||
system.add_type(main_molecule)
|
|
||||||
system.add_type(secondary_molecule)
|
|
||||||
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, system)
|
|
||||||
|
|
||||||
dice._make_potentials("test")
|
|
||||||
|
|
||||||
mock_handler = mock_open()
|
|
||||||
calls = mock_handler.write.call_args_list
|
|
||||||
|
|
||||||
lines = list(map(lambda x: x[0][0], calls))
|
|
||||||
|
|
||||||
expected_lines = [
|
|
||||||
"*\n",
|
|
||||||
"2\n",
|
|
||||||
"1 main_molecule\n",
|
|
||||||
"1 1 1.00000 1.00000 1.00000 1.000000 1.00000 1.0000\n",
|
|
||||||
"1 secondary_molecule\n",
|
|
||||||
"1 1 1.00000 1.00000 1.00000 1.000000 1.00000 1.0000\n",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(lines, expected_lines)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.subprocess")
|
|
||||||
@mock.patch(
|
|
||||||
"builtins.open",
|
|
||||||
new_callable=mock.mock_open,
|
|
||||||
read_data="End of simulation\nBLABLA",
|
|
||||||
)
|
|
||||||
def test_run_dice_file(self, mock_open, mock_subprocess):
|
|
||||||
mock_subprocess.call.return_value = 0
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
dice.run_dice_file(1, 1, "test")
|
|
||||||
|
|
||||||
self.assertTrue(mock_subprocess.call.called)
|
|
||||||
self.assertTrue(mock_open.called)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.subprocess")
|
|
||||||
@mock.patch("builtins.open", new_callable=mock.mock_open, read_data="Error\nBLABLA")
|
|
||||||
def test_run_dice_file_raises_runtime_error_on_dice_file(
|
|
||||||
self, mock_open, mock_subprocess
|
|
||||||
):
|
|
||||||
mock_subprocess.call.return_value = 0
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
with self.assertRaises(RuntimeError):
|
|
||||||
dice.run_dice_file(1, 1, "test")
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.dice_interface.subprocess")
|
|
||||||
@mock.patch(
|
|
||||||
"builtins.open",
|
|
||||||
new_callable=mock.mock_open,
|
|
||||||
read_data="End of simulation\nBLABLA",
|
|
||||||
)
|
|
||||||
def test_run_dice_file_raises_runtime_error_of_dice_exit_code(
|
|
||||||
self, mock_open, mock_subprocess
|
|
||||||
):
|
|
||||||
mock_subprocess.call.return_value = 1
|
|
||||||
dice = DiceInterface()
|
|
||||||
dice.configure(self.config, System())
|
|
||||||
|
|
||||||
with self.assertRaises(RuntimeError):
|
|
||||||
dice.run_dice_file(1, 1, "test")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
from diceplayer import logger
|
|
||||||
from diceplayer.shared.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
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
import io
|
|
||||||
import unittest
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
|
|
||||||
class TestGaussianInterface(unittest.TestCase):
|
|
||||||
def setUp(self) -> None:
|
|
||||||
logger.set_logger(stream=io.StringIO())
|
|
||||||
|
|
||||||
config = yaml.load(get_config_example(), Loader=yaml.Loader)
|
|
||||||
self.config = PlayerConfig.from_dict(config["diceplayer"])
|
|
||||||
|
|
||||||
def test_class_instantiation(self):
|
|
||||||
gaussian_interface = GaussianInterface()
|
|
||||||
self.assertIsInstance(gaussian_interface, GaussianInterface)
|
|
||||||
|
|
||||||
def test_configure(self):
|
|
||||||
gaussian_interface = GaussianInterface()
|
|
||||||
|
|
||||||
self.assertIsNone(gaussian_interface.step)
|
|
||||||
self.assertIsNone(gaussian_interface.system)
|
|
||||||
|
|
||||||
gaussian_interface.configure(self.config, System())
|
|
||||||
|
|
||||||
self.assertIsNotNone(gaussian_interface.step)
|
|
||||||
self.assertIsNotNone(gaussian_interface.system)
|
|
||||||
|
|
||||||
def test_reset(self):
|
|
||||||
gaussian_interface = GaussianInterface()
|
|
||||||
|
|
||||||
gaussian_interface.configure(self.config, System())
|
|
||||||
|
|
||||||
self.assertIsNotNone(gaussian_interface.step)
|
|
||||||
self.assertIsNotNone(gaussian_interface.system)
|
|
||||||
|
|
||||||
gaussian_interface.reset()
|
|
||||||
|
|
||||||
self.assertFalse(hasattr(gaussian_interface, "step"))
|
|
||||||
self.assertFalse(hasattr(gaussian_interface, "system"))
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.gaussian_interface.Path.mkdir")
|
|
||||||
@mock.patch("diceplayer.shared.interface.gaussian_interface.Path.exists")
|
|
||||||
def test_make_qm_dir(self, mock_exists, mock_mkdir):
|
|
||||||
mock_exists.return_value = False
|
|
||||||
|
|
||||||
gaussian_interface = GaussianInterface()
|
|
||||||
gaussian_interface.configure(self.config, System())
|
|
||||||
|
|
||||||
gaussian_interface._make_qm_dir(1)
|
|
||||||
|
|
||||||
mock_exists.assert_called_once()
|
|
||||||
mock_mkdir.assert_called_once()
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.gaussian_interface.shutil.copy")
|
|
||||||
@mock.patch("diceplayer.shared.interface.gaussian_interface.Path.exists")
|
|
||||||
def test_copy_chk_file_from_previous_step(self, mock_exists, mock_copy):
|
|
||||||
gaussian_interface = GaussianInterface()
|
|
||||||
gaussian_interface.configure(self.config, System())
|
|
||||||
|
|
||||||
mock_exists.side_effect = [False, True]
|
|
||||||
|
|
||||||
gaussian_interface._copy_chk_file_from_previous_step(2)
|
|
||||||
|
|
||||||
self.assertTrue(mock_exists.called)
|
|
||||||
self.assertTrue(mock_copy.called)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.gaussian_interface.shutil.copy")
|
|
||||||
@mock.patch("diceplayer.shared.interface.gaussian_interface.Path.exists")
|
|
||||||
def test_copy_chk_file_from_previous_step_no_previous_step(
|
|
||||||
self, mock_exists, mock_copy
|
|
||||||
):
|
|
||||||
gaussian_interface = GaussianInterface()
|
|
||||||
gaussian_interface.configure(self.config, System())
|
|
||||||
|
|
||||||
mock_exists.side_effect = [False, False]
|
|
||||||
|
|
||||||
with self.assertRaises(FileNotFoundError):
|
|
||||||
gaussian_interface._copy_chk_file_from_previous_step(2)
|
|
||||||
|
|
||||||
@mock.patch("diceplayer.shared.interface.gaussian_interface.shutil.copy")
|
|
||||||
@mock.patch("diceplayer.shared.interface.gaussian_interface.Path.exists")
|
|
||||||
def test_copy_chk_file_from_previous_step_current_exists(
|
|
||||||
self, mock_exists, mock_copy
|
|
||||||
):
|
|
||||||
gaussian_interface = GaussianInterface()
|
|
||||||
gaussian_interface.configure(self.config, System())
|
|
||||||
|
|
||||||
mock_exists.side_effect = [True, True]
|
|
||||||
|
|
||||||
with self.assertRaises(FileExistsError):
|
|
||||||
gaussian_interface._copy_chk_file_from_previous_step(2)
|
|
||||||
|
|
||||||
# def test_start(self):
|
|
||||||
# gaussian_interface = GaussianInterface()
|
|
||||||
# gaussian_interface.configure(self.config, System())
|
|
||||||
#
|
|
||||||
# gaussian_interface._make_qm_dir = mock.Mock()
|
|
||||||
# gaussian_interface._copy_chk_file_from_previous_step = mock.Mock()
|
|
||||||
#
|
|
||||||
# gaussian_interface.start(2)
|
|
||||||
#
|
|
||||||
# gaussian_interface._make_qm_dir.assert_called_once_with(2)
|
|
||||||
# gaussian_interface._copy_chk_file_from_previous_step.assert_called_once_with(2)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
from diceplayer.shared.utils.logger import Logger, valid_logger
|
|
||||||
|
|
||||||
import io
|
|
||||||
import logging
|
|
||||||
import unittest
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
|
|
||||||
class TestValidateLogger(unittest.TestCase):
|
|
||||||
def test_validate_logger(self):
|
|
||||||
class MockLogger:
|
|
||||||
_was_set = True
|
|
||||||
|
|
||||||
@valid_logger
|
|
||||||
def test_func(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
MockLogger().test_func()
|
|
||||||
|
|
||||||
def test_validate_logger_exception(self):
|
|
||||||
class MockLogger:
|
|
||||||
_was_set = False
|
|
||||||
|
|
||||||
@valid_logger
|
|
||||||
def test_func(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
with self.assertRaises(AssertionError):
|
|
||||||
MockLogger().test_func()
|
|
||||||
|
|
||||||
|
|
||||||
class TestLogger(unittest.TestCase):
|
|
||||||
def test_class_instantiation(self):
|
|
||||||
logger = Logger("test")
|
|
||||||
|
|
||||||
self.assertIsInstance(logger, Logger)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock.mock_open())
|
|
||||||
def test_set_logger_to_file(self):
|
|
||||||
logger = Logger("test")
|
|
||||||
|
|
||||||
logger.set_logger(stream=io.StringIO())
|
|
||||||
|
|
||||||
self.assertIsNotNone(logger._logger)
|
|
||||||
self.assertEqual(logger._logger.name, "test")
|
|
||||||
|
|
||||||
def test_set_logger_to_stream(self):
|
|
||||||
logger = Logger("test")
|
|
||||||
|
|
||||||
logger.set_logger(stream=io.StringIO())
|
|
||||||
|
|
||||||
self.assertIsNotNone(logger._logger)
|
|
||||||
self.assertEqual(logger._logger.name, "test")
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock.mock_open())
|
|
||||||
@mock.patch("diceplayer.shared.utils.logger.Path.exists")
|
|
||||||
@mock.patch("diceplayer.shared.utils.logger.Path.rename")
|
|
||||||
def test_set_logger_if_file_exists(self, mock_rename, mock_exists):
|
|
||||||
logger = Logger("test")
|
|
||||||
|
|
||||||
mock_exists.return_value = True
|
|
||||||
logger.set_logger()
|
|
||||||
|
|
||||||
self.assertTrue(mock_rename.called)
|
|
||||||
self.assertIsNotNone(logger._logger)
|
|
||||||
self.assertEqual(logger._logger.name, "test")
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock.mock_open())
|
|
||||||
@mock.patch("diceplayer.shared.utils.logger.Path.exists")
|
|
||||||
@mock.patch("diceplayer.shared.utils.logger.Path.rename")
|
|
||||||
def test_set_logger_if_file_not_exists(self, mock_rename, mock_exists):
|
|
||||||
logger = Logger("test")
|
|
||||||
|
|
||||||
mock_exists.return_value = False
|
|
||||||
logger.set_logger()
|
|
||||||
|
|
||||||
self.assertFalse(mock_rename.called)
|
|
||||||
self.assertIsNotNone(logger._logger)
|
|
||||||
self.assertEqual(logger._logger.name, "test")
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock.mock_open())
|
|
||||||
def test_close(self):
|
|
||||||
logger = Logger("test")
|
|
||||||
|
|
||||||
logger.set_logger()
|
|
||||||
logger.close()
|
|
||||||
|
|
||||||
self.assertEqual(len(logger._logger.handlers), 0)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock.mock_open())
|
|
||||||
def test_info(self):
|
|
||||||
logger = Logger("test")
|
|
||||||
logger.set_logger(stream=io.StringIO())
|
|
||||||
|
|
||||||
with self.assertLogs(level="INFO") as cm:
|
|
||||||
logger.info("test")
|
|
||||||
|
|
||||||
self.assertEqual(cm.output, ["INFO:test:test"])
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock.mock_open())
|
|
||||||
def test_debug(self):
|
|
||||||
logger = Logger("test")
|
|
||||||
logger.set_logger(stream=io.StringIO(), level=logging.DEBUG)
|
|
||||||
|
|
||||||
with self.assertLogs(level="DEBUG") as cm:
|
|
||||||
logger.debug("test")
|
|
||||||
|
|
||||||
self.assertEqual(cm.output, ["DEBUG:test:test"])
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock.mock_open())
|
|
||||||
def test_warning(self):
|
|
||||||
logger = Logger("test")
|
|
||||||
logger.set_logger(stream=io.StringIO())
|
|
||||||
|
|
||||||
with self.assertLogs(level="WARNING") as cm:
|
|
||||||
logger.warning("test")
|
|
||||||
|
|
||||||
self.assertEqual(cm.output, ["WARNING:test:test"])
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock.mock_open())
|
|
||||||
def test_error(self):
|
|
||||||
logger = Logger("test")
|
|
||||||
logger.set_logger(stream=io.StringIO())
|
|
||||||
|
|
||||||
with self.assertLogs(level="ERROR") as cm:
|
|
||||||
logger.error("test")
|
|
||||||
|
|
||||||
self.assertEqual(cm.output, ["ERROR:test:test"])
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
118
tests/state/test_state_handler.py
Normal file
118
tests/state/test_state_handler.py
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
from diceplayer.config import DiceConfig, GaussianConfig, PlayerConfig
|
||||||
|
from diceplayer.environment import System
|
||||||
|
from diceplayer.state.state_handler import StateHandler
|
||||||
|
from diceplayer.state.state_model import StateModel
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class TestStateHandler:
|
||||||
|
@pytest.fixture
|
||||||
|
def player_config(self) -> PlayerConfig:
|
||||||
|
return PlayerConfig(
|
||||||
|
type="both",
|
||||||
|
mem=12,
|
||||||
|
max_cyc=100,
|
||||||
|
switch_cyc=50,
|
||||||
|
ncores=4,
|
||||||
|
dice=DiceConfig(
|
||||||
|
nprocs=4,
|
||||||
|
ljname="test",
|
||||||
|
outname="test",
|
||||||
|
dens=1.0,
|
||||||
|
nmol=[1],
|
||||||
|
nstep=[1, 1],
|
||||||
|
),
|
||||||
|
gaussian=GaussianConfig(
|
||||||
|
level="test",
|
||||||
|
qmprog="g16",
|
||||||
|
keywords="test",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_initialization(self, tmp_path: Path):
|
||||||
|
state_handler = StateHandler(tmp_path)
|
||||||
|
|
||||||
|
assert isinstance(state_handler, StateHandler)
|
||||||
|
|
||||||
|
def test_save(self, tmp_path: Path, player_config: PlayerConfig):
|
||||||
|
state_handler = StateHandler(tmp_path)
|
||||||
|
|
||||||
|
state = StateModel(
|
||||||
|
config=player_config,
|
||||||
|
system=System(),
|
||||||
|
current_cycle=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
state_handler.save(state)
|
||||||
|
|
||||||
|
assert (tmp_path / "state.pkl").exists()
|
||||||
|
|
||||||
|
def test_get_when_empty(self, tmp_path: Path, player_config: PlayerConfig):
|
||||||
|
state_handler = StateHandler(tmp_path)
|
||||||
|
|
||||||
|
state = state_handler.get(player_config)
|
||||||
|
|
||||||
|
assert state is None
|
||||||
|
|
||||||
|
def test_get(self, tmp_path: Path, player_config: PlayerConfig):
|
||||||
|
state_handler = StateHandler(tmp_path)
|
||||||
|
|
||||||
|
state = StateModel(
|
||||||
|
config=player_config,
|
||||||
|
system=System(),
|
||||||
|
current_cycle=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
state_handler.save(state)
|
||||||
|
|
||||||
|
retrieved_state = state_handler.get(player_config)
|
||||||
|
|
||||||
|
assert retrieved_state is not None
|
||||||
|
assert retrieved_state.config == state.config
|
||||||
|
assert retrieved_state.system == state.system
|
||||||
|
assert retrieved_state.current_cycle == state.current_cycle
|
||||||
|
|
||||||
|
def test_get_with_different_config(
|
||||||
|
self, tmp_path: Path, player_config: PlayerConfig
|
||||||
|
):
|
||||||
|
state_handler = StateHandler(tmp_path)
|
||||||
|
|
||||||
|
state = StateModel(
|
||||||
|
config=player_config,
|
||||||
|
system=System(),
|
||||||
|
current_cycle=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
state_handler.save(state)
|
||||||
|
|
||||||
|
different_config = player_config.model_copy(update={"max_cyc": 200})
|
||||||
|
|
||||||
|
retrieved_state = state_handler.get(different_config)
|
||||||
|
|
||||||
|
assert retrieved_state is None
|
||||||
|
|
||||||
|
def test_get_with_different_config_force(
|
||||||
|
self, tmp_path: Path, player_config: PlayerConfig
|
||||||
|
):
|
||||||
|
state_handler = StateHandler(tmp_path)
|
||||||
|
|
||||||
|
state = StateModel(
|
||||||
|
config=player_config,
|
||||||
|
system=System(),
|
||||||
|
current_cycle=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
state_handler.save(state)
|
||||||
|
|
||||||
|
different_config = player_config.model_copy(update={"max_cyc": 200})
|
||||||
|
|
||||||
|
retrieved_state = state_handler.get(different_config, force=True)
|
||||||
|
|
||||||
|
assert retrieved_state is not None
|
||||||
|
assert retrieved_state.config == state.config
|
||||||
|
assert retrieved_state.config != different_config
|
||||||
|
assert retrieved_state.system == state.system
|
||||||
|
assert retrieved_state.current_cycle == state.current_cycle
|
||||||
@@ -1,393 +0,0 @@
|
|||||||
from diceplayer import VERSION, logger
|
|
||||||
from diceplayer.player import Player
|
|
||||||
from tests.mocks.mock_inputs import mock_open
|
|
||||||
|
|
||||||
import io
|
|
||||||
import unittest
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
|
|
||||||
class TestPlayer(unittest.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
logger.set_logger(stream=io.StringIO())
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
def test_class_instantiation(self):
|
|
||||||
# This file does not exist and it will be mocked
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
|
|
||||||
self.assertIsInstance(player, Player)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
def test_start(self):
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
|
|
||||||
player.gaussian_start = mock.MagicMock()
|
|
||||||
player.dice_start = mock.MagicMock()
|
|
||||||
|
|
||||||
player.start()
|
|
||||||
|
|
||||||
self.assertEqual(player.dice_start.call_count, 3)
|
|
||||||
self.assertEqual(player.gaussian_start.call_count, 3)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
@mock.patch("diceplayer.player.Path")
|
|
||||||
def test_create_simulation_dir_if_already_exists(self, mock_path):
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
mock_path.return_value.exists.return_value = True
|
|
||||||
|
|
||||||
with self.assertRaises(FileExistsError):
|
|
||||||
player.create_simulation_dir()
|
|
||||||
|
|
||||||
self.assertTrue(mock_path.called)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
@mock.patch("diceplayer.player.Path")
|
|
||||||
def test_create_simulation_dir_if_not_exists(self, mock_path):
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
mock_path.return_value.exists.return_value = False
|
|
||||||
|
|
||||||
player.create_simulation_dir()
|
|
||||||
|
|
||||||
self.assertTrue(mock_path.called)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
@mock.patch("diceplayer.player.VERSION", "test")
|
|
||||||
@mock.patch("diceplayer.player.sys")
|
|
||||||
@mock.patch("diceplayer.player.weekday_date_time")
|
|
||||||
def test_print_keywords(self, mock_date_func, mock_sys):
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
|
|
||||||
mock_sys.version = "TEST"
|
|
||||||
mock_date_func.return_value = "00 Test 0000 at 00:00:00"
|
|
||||||
|
|
||||||
with self.assertLogs() as cm:
|
|
||||||
player.print_keywords()
|
|
||||||
|
|
||||||
expected_output = [
|
|
||||||
"INFO:diceplayer:##########################################################################################\n############# Welcome to DICEPLAYER version test #############\n##########################################################################################\n",
|
|
||||||
"INFO:diceplayer:Your python version is TEST\n",
|
|
||||||
"INFO:diceplayer:Program started on 00 Test 0000 at 00:00:00\n",
|
|
||||||
"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:dens = 0.75",
|
|
||||||
"INFO:diceplayer:isave = 1000",
|
|
||||||
"INFO:diceplayer:ljname = phb.ljc",
|
|
||||||
"INFO:diceplayer:nmol = [ 1 50 ]",
|
|
||||||
"INFO:diceplayer:nstep = [ 2000 3000 4000 ]",
|
|
||||||
"INFO:diceplayer:outname = phb",
|
|
||||||
"INFO:diceplayer:press = 1.0",
|
|
||||||
"INFO:diceplayer:progname = ~/.local/bin/dice",
|
|
||||||
"INFO:diceplayer:randominit = first",
|
|
||||||
"INFO:diceplayer:temp = 300.0",
|
|
||||||
"INFO:diceplayer:------------------------------------------------------------------------------------------\n GAUSSIAN variables being used in this run:\n------------------------------------------------------------------------------------------\n",
|
|
||||||
"INFO:diceplayer:chg_tol = 0.01",
|
|
||||||
"INFO:diceplayer:keywords = freq",
|
|
||||||
"INFO:diceplayer:level = MP2/aug-cc-pVDZ",
|
|
||||||
"INFO:diceplayer:pop = chelpg",
|
|
||||||
"INFO:diceplayer:qmprog = g16",
|
|
||||||
"INFO:diceplayer:\n",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(cm.output, expected_output)
|
|
||||||
|
|
||||||
def test_validate_atom_dict(self):
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": 0,
|
|
||||||
"na": 1,
|
|
||||||
"rx": 1.0,
|
|
||||||
"ry": 1.0,
|
|
||||||
"rz": 1.0,
|
|
||||||
"chg": 1.0,
|
|
||||||
"eps": 1.0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Invalid number of fields for site 1 for molecule type 1.",
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": "",
|
|
||||||
"na": 1,
|
|
||||||
"rx": 1.0,
|
|
||||||
"ry": 1.0,
|
|
||||||
"rz": 1.0,
|
|
||||||
"chg": 1.0,
|
|
||||||
"eps": 1.0,
|
|
||||||
"sig": 1.0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception), "Invalid lbl fields for site 1 for molecule type 1."
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": 1.0,
|
|
||||||
"na": "",
|
|
||||||
"rx": 1.0,
|
|
||||||
"ry": 1.0,
|
|
||||||
"rz": 1.0,
|
|
||||||
"chg": 1.0,
|
|
||||||
"eps": 1.0,
|
|
||||||
"sig": 1.0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception), "Invalid na fields for site 1 for molecule type 1."
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": 1.0,
|
|
||||||
"na": 1,
|
|
||||||
"rx": "",
|
|
||||||
"ry": 1.0,
|
|
||||||
"rz": 1.0,
|
|
||||||
"chg": 1.0,
|
|
||||||
"eps": 1.0,
|
|
||||||
"sig": 1.0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Invalid rx fields for site 1 for molecule type 1. Value must be a float.",
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": 1.0,
|
|
||||||
"na": 1,
|
|
||||||
"rx": 1.0,
|
|
||||||
"ry": "",
|
|
||||||
"rz": 1.0,
|
|
||||||
"chg": 1.0,
|
|
||||||
"eps": 1.0,
|
|
||||||
"sig": 1.0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Invalid ry fields for site 1 for molecule type 1. Value must be a float.",
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": 1.0,
|
|
||||||
"na": 1,
|
|
||||||
"rx": 1.0,
|
|
||||||
"ry": 1.0,
|
|
||||||
"rz": "",
|
|
||||||
"chg": 1.0,
|
|
||||||
"eps": 1.0,
|
|
||||||
"sig": 1.0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Invalid rz fields for site 1 for molecule type 1. Value must be a float.",
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": 1.0,
|
|
||||||
"na": 1,
|
|
||||||
"rx": 1.0,
|
|
||||||
"ry": 1.0,
|
|
||||||
"rz": 1.0,
|
|
||||||
"chg": "",
|
|
||||||
"eps": 1.0,
|
|
||||||
"sig": 1.0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Invalid chg fields for site 1 for molecule type 1. Value must be a float.",
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": 1.0,
|
|
||||||
"na": 1,
|
|
||||||
"rx": 1.0,
|
|
||||||
"ry": 1.0,
|
|
||||||
"rz": 1.0,
|
|
||||||
"chg": 1.0,
|
|
||||||
"eps": "",
|
|
||||||
"sig": 1.0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Invalid eps fields for site 1 for molecule type 1. Value must be a float.",
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
Player.validate_atom_dict(
|
|
||||||
molecule_type=0,
|
|
||||||
molecule_site=0,
|
|
||||||
atom_dict={
|
|
||||||
"lbl": 1.0,
|
|
||||||
"na": 1,
|
|
||||||
"rx": 1.0,
|
|
||||||
"ry": 1.0,
|
|
||||||
"rz": 1.0,
|
|
||||||
"chg": 1.0,
|
|
||||||
"eps": 1.0,
|
|
||||||
"sig": "",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Invalid sig fields for site 1 for molecule type 1. Value must be a float.",
|
|
||||||
)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
@mock.patch("diceplayer.player.Path.exists", return_value=True)
|
|
||||||
def test_read_potentials(self, mock_path_exists):
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
|
|
||||||
player.read_potentials()
|
|
||||||
|
|
||||||
self.assertEqual(player.system.molecule[0].molname, "TEST")
|
|
||||||
self.assertEqual(len(player.system.molecule[0].atom), 1)
|
|
||||||
|
|
||||||
self.assertEqual(player.system.molecule[1].molname, "PLACEHOLDER")
|
|
||||||
self.assertEqual(len(player.system.molecule[1].atom), 1)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
@mock.patch("diceplayer.player.Path.exists")
|
|
||||||
def test_read_potentials_error(self, mock_path_exists):
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
|
|
||||||
# Testing file not found error
|
|
||||||
mock_path_exists.return_value = False
|
|
||||||
with self.assertRaises(RuntimeError) as context:
|
|
||||||
player.read_potentials()
|
|
||||||
|
|
||||||
self.assertEqual(str(context.exception), "Potential file phb.ljc not found.")
|
|
||||||
|
|
||||||
# Enabling file found for next tests
|
|
||||||
mock_path_exists.return_value = True
|
|
||||||
|
|
||||||
# Testing combrule error
|
|
||||||
with self.assertRaises(SystemExit) as context:
|
|
||||||
player.config.dice.ljname = "phb.error.combrule.ljc"
|
|
||||||
player.read_potentials()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Error: expected a '*' or a '+' sign in 1st line of file phb.error.combrule.ljc",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Testing ntypes error
|
|
||||||
with self.assertRaises(SystemExit) as context:
|
|
||||||
player.config.dice.ljname = "phb.error.ntypes.ljc"
|
|
||||||
player.read_potentials()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Error: expected an integer in the 2nd line of file phb.error.ntypes.ljc",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Testing ntypes error on config
|
|
||||||
with self.assertRaises(SystemExit) as context:
|
|
||||||
player.config.dice.ljname = "phb.error.ntypes.config.ljc"
|
|
||||||
player.read_potentials()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Error: number of molecule types in file phb.error.ntypes.config.ljc "
|
|
||||||
"must match that of 'nmol' keyword in config file",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Testing nsite error
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
player.config.dice.ljname = "phb.error.nsites.ljc"
|
|
||||||
player.read_potentials()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Error: expected nsites to be an integer for molecule type 1",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Testing molname error
|
|
||||||
with self.assertRaises(ValueError) as context:
|
|
||||||
player.config.dice.ljname = "phb.error.molname.ljc"
|
|
||||||
player.read_potentials()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
str(context.exception),
|
|
||||||
"Error: expected nsites and molname for the molecule type 1",
|
|
||||||
)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
@mock.patch("diceplayer.player.Path.exists", return_value=True)
|
|
||||||
def test_print_potentials(self, mock_path_exists):
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
player.read_potentials()
|
|
||||||
|
|
||||||
with self.assertLogs(level="INFO") as context:
|
|
||||||
player.print_potentials()
|
|
||||||
|
|
||||||
expected_output = [
|
|
||||||
"INFO:diceplayer:==========================================================================================\n Potential parameters from file phb.ljc:\n------------------------------------------------------------------------------------------\n",
|
|
||||||
"INFO:diceplayer:Combination rule: *",
|
|
||||||
"INFO:diceplayer:Types of molecules: 2\n",
|
|
||||||
"INFO:diceplayer:1 atoms in molecule type 1:",
|
|
||||||
"INFO:diceplayer:---------------------------------------------------------------------------------",
|
|
||||||
"INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass",
|
|
||||||
"INFO:diceplayer:---------------------------------------------------------------------------------",
|
|
||||||
"INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079",
|
|
||||||
"INFO:diceplayer:\n",
|
|
||||||
"INFO:diceplayer:1 atoms in molecule type 2:",
|
|
||||||
"INFO:diceplayer:---------------------------------------------------------------------------------",
|
|
||||||
"INFO:diceplayer:Lbl AN X Y Z Charge Epsilon Sigma Mass",
|
|
||||||
"INFO:diceplayer:---------------------------------------------------------------------------------",
|
|
||||||
"INFO:diceplayer:1 1 0.00000 0.00000 0.00000 0.000000 0.00000 0.0000 1.0079",
|
|
||||||
"INFO:diceplayer:\n",
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(context.output, expected_output)
|
|
||||||
|
|
||||||
@mock.patch("builtins.open", mock_open)
|
|
||||||
def test_dice_start(self):
|
|
||||||
player = Player("control.test.yml")
|
|
||||||
player.dice_interface = mock.MagicMock()
|
|
||||||
player.dice_interface.start = mock.MagicMock()
|
|
||||||
|
|
||||||
player.dice_start(1)
|
|
||||||
|
|
||||||
player.dice_interface.start.assert_called_once()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
||||||
37
tests/utils/test_potential.py
Normal file
37
tests/utils/test_potential.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
from diceplayer.config import PlayerConfig
|
||||||
|
from diceplayer.environment import System
|
||||||
|
from diceplayer.utils.potential import read_system_from_phb
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
class TestPotential:
|
||||||
|
@pytest.fixture
|
||||||
|
def player_config(self) -> PlayerConfig:
|
||||||
|
return PlayerConfig.model_validate(
|
||||||
|
{
|
||||||
|
"type": "both",
|
||||||
|
"mem": 12,
|
||||||
|
"max_cyc": 100,
|
||||||
|
"switch_cyc": 50,
|
||||||
|
"ncores": 4,
|
||||||
|
"dice": {
|
||||||
|
"nprocs": 4,
|
||||||
|
"ljname": "phb.ljc.example",
|
||||||
|
"outname": "test",
|
||||||
|
"dens": 1.0,
|
||||||
|
"nmol": [12, 16],
|
||||||
|
"nstep": [1, 1],
|
||||||
|
},
|
||||||
|
"gaussian": {
|
||||||
|
"level": "test",
|
||||||
|
"qmprog": "g16",
|
||||||
|
"keywords": "test",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_read_phb(self, player_config: PlayerConfig):
|
||||||
|
system = read_system_from_phb(player_config)
|
||||||
|
|
||||||
|
assert isinstance(system, System)
|
||||||
727
uv.lock
generated
Normal file
727
uv.lock
generated
Normal file
@@ -0,0 +1,727 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "annotated-types"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "argparse"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/18/dd/e617cfc3f6210ae183374cd9f6a26b20514bbb5a792af97949c5aacddf0f/argparse-1.4.0.tar.gz", hash = "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4", size = 70508, upload-time = "2015-09-12T20:22:16.217Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/94/3af39d34be01a24a6e65433d19e107099374224905f1e0cc6bbe1fd22a2f/argparse-1.4.0-py2.py3-none-any.whl", hash = "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314", size = 23000, upload-time = "2015-09-14T16:03:16.137Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "black"
|
||||||
|
version = "26.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "mypy-extensions" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pathspec" },
|
||||||
|
{ name = "platformdirs" },
|
||||||
|
{ name = "pytokens" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/13/88/560b11e521c522440af991d46848a2bde64b5f7202ec14e1f46f9509d328/black-26.1.0.tar.gz", hash = "sha256:d294ac3340eef9c9eb5d29288e96dc719ff269a88e27b396340459dd85da4c58", size = 658785, upload-time = "2026-01-18T04:50:11.993Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/13/710298938a61f0f54cdb4d1c0baeb672c01ff0358712eddaf29f76d32a0b/black-26.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6eeca41e70b5f5c84f2f913af857cf2ce17410847e1d54642e658e078da6544f", size = 1878189, upload-time = "2026-01-18T04:59:30.682Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/a6/5179beaa57e5dbd2ec9f1c64016214057b4265647c62125aa6aeffb05392/black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dd39eef053e58e60204f2cdf059e2442e2eb08f15989eefe259870f89614c8b6", size = 1700178, upload-time = "2026-01-18T04:59:32.387Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/04/c96f79d7b93e8f09d9298b333ca0d31cd9b2ee6c46c274fd0f531de9dc61/black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9459ad0d6cd483eacad4c6566b0f8e42af5e8b583cee917d90ffaa3778420a0a", size = 1777029, upload-time = "2026-01-18T04:59:33.767Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/f9/71c161c4c7aa18bdda3776b66ac2dc07aed62053c7c0ff8bbda8c2624fe2/black-26.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a19915ec61f3a8746e8b10adbac4a577c6ba9851fa4a9e9fbfbcf319887a5791", size = 1406466, upload-time = "2026-01-18T04:59:35.177Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4a/8b/a7b0f974e473b159d0ac1b6bcefffeb6bec465898a516ee5cc989503cbc7/black-26.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:643d27fb5facc167c0b1b59d0315f2674a6e950341aed0fc05cf307d22bf4954", size = 1216393, upload-time = "2026-01-18T04:59:37.18Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/04/fa2f4784f7237279332aa735cdfd5ae2e7730db0072fb2041dadda9ae551/black-26.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ba1d768fbfb6930fc93b0ecc32a43d8861ded16f47a40f14afa9bb04ab93d304", size = 1877781, upload-time = "2026-01-18T04:59:39.054Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/ad/5a131b01acc0e5336740a039628c0ab69d60cf09a2c87a4ec49f5826acda/black-26.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b807c240b64609cb0e80d2200a35b23c7df82259f80bef1b2c96eb422b4aac9", size = 1699670, upload-time = "2026-01-18T04:59:41.005Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/7c/b05f22964316a52ab6b4265bcd52c0ad2c30d7ca6bd3d0637e438fc32d6e/black-26.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1de0f7d01cc894066a1153b738145b194414cc6eeaad8ef4397ac9abacf40f6b", size = 1775212, upload-time = "2026-01-18T04:59:42.545Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/a3/e8d1526bea0446e040193185353920a9506eab60a7d8beb062029129c7d2/black-26.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:91a68ae46bf07868963671e4d05611b179c2313301bd756a89ad4e3b3db2325b", size = 1409953, upload-time = "2026-01-18T04:59:44.357Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/5a/d62ebf4d8f5e3a1daa54adaab94c107b57be1b1a2f115a0249b41931e188/black-26.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:be5e2fe860b9bd9edbf676d5b60a9282994c03fbbd40fe8f5e75d194f96064ca", size = 1217707, upload-time = "2026-01-18T04:59:45.719Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/83/be35a175aacfce4b05584ac415fd317dd6c24e93a0af2dcedce0f686f5d8/black-26.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9dc8c71656a79ca49b8d3e2ce8103210c9481c57798b48deeb3a8bb02db5f115", size = 1871864, upload-time = "2026-01-18T04:59:47.586Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/f5/d33696c099450b1274d925a42b7a030cd3ea1f56d72e5ca8bbed5f52759c/black-26.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b22b3810451abe359a964cc88121d57f7bce482b53a066de0f1584988ca36e79", size = 1701009, upload-time = "2026-01-18T04:59:49.443Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/87/670dd888c537acb53a863bc15abbd85b22b429237d9de1b77c0ed6b79c42/black-26.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53c62883b3f999f14e5d30b5a79bd437236658ad45b2f853906c7cbe79de00af", size = 1767806, upload-time = "2026-01-18T04:59:50.769Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/9c/cd3deb79bfec5bcf30f9d2100ffeec63eecce826eb63e3961708b9431ff1/black-26.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:f016baaadc423dc960cdddf9acae679e71ee02c4c341f78f3179d7e4819c095f", size = 1433217, upload-time = "2026-01-18T04:59:52.218Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/29/f3be41a1cf502a283506f40f5d27203249d181f7a1a2abce1c6ce188035a/black-26.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:66912475200b67ef5a0ab665011964bf924745103f51977a78b4fb92a9fc1bf0", size = 1245773, upload-time = "2026-01-18T04:59:54.457Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/3d/51bdb3ecbfadfaf825ec0c75e1de6077422b4afa2091c6c9ba34fbfc0c2d/black-26.1.0-py3-none-any.whl", hash = "sha256:1054e8e47ebd686e078c0bb0eaf31e6ce69c966058d122f2c0c950311f9f3ede", size = 204010, upload-time = "2026-01-18T04:50:09.978Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfgv"
|
||||||
|
version = "3.5.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.3.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coverage"
|
||||||
|
version = "7.13.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/23/aad45061a31677d68e47499197a131eea55da4875d16c1f42021ab963503/coverage-7.13.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b66a2da594b6068b48b2692f043f35d4d3693fb639d5ea8b39533c2ad9ac3ab9", size = 219474, upload-time = "2026-02-09T12:57:19.332Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/70/9b8b67a0945f3dfec1fd896c5cefb7c19d5a3a6d74630b99a895170999ae/coverage-7.13.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3599eb3992d814d23b35c536c28df1a882caa950f8f507cef23d1cbf334995ac", size = 219844, upload-time = "2026-02-09T12:57:20.66Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/fd/7e859f8fab324cef6c4ad7cff156ca7c489fef9179d5749b0c8d321281c2/coverage-7.13.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:93550784d9281e374fb5a12bf1324cc8a963fd63b2d2f223503ef0fd4aa339ea", size = 250832, upload-time = "2026-02-09T12:57:22.007Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/dc/b2442d10020c2f52617828862d8b6ee337859cd8f3a1f13d607dddda9cf7/coverage-7.13.4-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b720ce6a88a2755f7c697c23268ddc47a571b88052e6b155224347389fdf6a3b", size = 253434, upload-time = "2026-02-09T12:57:23.339Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/88/6728a7ad17428b18d836540630487231f5470fb82454871149502f5e5aa2/coverage-7.13.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b322db1284a2ed3aa28ffd8ebe3db91c929b7a333c0820abec3d838ef5b3525", size = 254676, upload-time = "2026-02-09T12:57:24.774Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/bc/21244b1b8cedf0dff0a2b53b208015fe798d5f2a8d5348dbfece04224fff/coverage-7.13.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4594c67d8a7c89cf922d9df0438c7c7bb022ad506eddb0fdb2863359ff78242", size = 256807, upload-time = "2026-02-09T12:57:26.125Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/a0/ddba7ed3251cff51006737a727d84e05b61517d1784a9988a846ba508877/coverage-7.13.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53d133df809c743eb8bce33b24bcababb371f4441340578cd406e084d94a6148", size = 251058, upload-time = "2026-02-09T12:57:27.614Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/55/e289addf7ff54d3a540526f33751951bf0878f3809b47f6dfb3def69c6f7/coverage-7.13.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76451d1978b95ba6507a039090ba076105c87cc76fc3efd5d35d72093964d49a", size = 252805, upload-time = "2026-02-09T12:57:29.066Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/13/4e/cc276b1fa4a59be56d96f1dabddbdc30f4ba22e3b1cd42504c37b3313255/coverage-7.13.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7f57b33491e281e962021de110b451ab8a24182589be17e12a22c79047935e23", size = 250766, upload-time = "2026-02-09T12:57:30.522Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/44/1093b8f93018f8b41a8cf29636c9292502f05e4a113d4d107d14a3acd044/coverage-7.13.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1731dc33dc276dafc410a885cbf5992f1ff171393e48a21453b78727d090de80", size = 254923, upload-time = "2026-02-09T12:57:31.946Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/55/ea2796da2d42257f37dbea1aab239ba9263b31bd91d5527cdd6db5efe174/coverage-7.13.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:bd60d4fe2f6fa7dff9223ca1bbc9f05d2b6697bc5961072e5d3b952d46e1b1ea", size = 250591, upload-time = "2026-02-09T12:57:33.842Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d4/fa/7c4bb72aacf8af5020675aa633e59c1fbe296d22aed191b6a5b711eb2bc7/coverage-7.13.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9181a3ccead280b828fae232df12b16652702b49d41e99d657f46cc7b1f6ec7a", size = 252364, upload-time = "2026-02-09T12:57:35.743Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/38/a8d2ec0146479c20bbaa7181b5b455a0c41101eed57f10dd19a78ab44c80/coverage-7.13.4-cp313-cp313-win32.whl", hash = "sha256:f53d492307962561ac7de4cd1de3e363589b000ab69617c6156a16ba7237998d", size = 222010, upload-time = "2026-02-09T12:57:37.25Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/0c/dbfafbe90a185943dcfbc766fe0e1909f658811492d79b741523a414a6cc/coverage-7.13.4-cp313-cp313-win_amd64.whl", hash = "sha256:e6f70dec1cc557e52df5306d051ef56003f74d56e9c4dd7ddb07e07ef32a84dd", size = 222818, upload-time = "2026-02-09T12:57:38.734Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/d1/934918a138c932c90d78301f45f677fb05c39a3112b96fd2c8e60503cdc7/coverage-7.13.4-cp313-cp313-win_arm64.whl", hash = "sha256:fb07dc5da7e849e2ad31a5d74e9bece81f30ecf5a42909d0a695f8bd1874d6af", size = 221438, upload-time = "2026-02-09T12:57:40.223Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/57/ee93ced533bcb3e6df961c0c6e42da2fc6addae53fb95b94a89b1e33ebd7/coverage-7.13.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40d74da8e6c4b9ac18b15331c4b5ebc35a17069410cad462ad4f40dcd2d50c0d", size = 220165, upload-time = "2026-02-09T12:57:41.639Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c5/e0/969fc285a6fbdda49d91af278488d904dcd7651b2693872f0ff94e40e84a/coverage-7.13.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4223b4230a376138939a9173f1bdd6521994f2aff8047fae100d6d94d50c5a12", size = 220516, upload-time = "2026-02-09T12:57:44.215Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/b8/9531944e16267e2735a30a9641ff49671f07e8138ecf1ca13db9fd2560c7/coverage-7.13.4-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1d4be36a5114c499f9f1f9195e95ebf979460dbe2d88e6816ea202010ba1c34b", size = 261804, upload-time = "2026-02-09T12:57:45.989Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/f3/e63df6d500314a2a60390d1989240d5f27318a7a68fa30ad3806e2a9323e/coverage-7.13.4-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:200dea7d1e8095cc6e98cdabe3fd1d21ab17d3cee6dab00cadbb2fe35d9c15b9", size = 263885, upload-time = "2026-02-09T12:57:47.42Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/67/7654810de580e14b37670b60a09c599fa348e48312db5b216d730857ffe6/coverage-7.13.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8eb931ee8e6d8243e253e5ed7336deea6904369d2fd8ae6e43f68abbf167092", size = 266308, upload-time = "2026-02-09T12:57:49.345Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/6f/39d41eca0eab3cc82115953ad41c4e77935286c930e8fad15eaed1389d83/coverage-7.13.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75eab1ebe4f2f64d9509b984f9314d4aa788540368218b858dad56dc8f3e5eb9", size = 267452, upload-time = "2026-02-09T12:57:50.811Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/6d/39c0fbb8fc5cd4d2090811e553c2108cf5112e882f82505ee7495349a6bf/coverage-7.13.4-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c35eb28c1d085eb7d8c9b3296567a1bebe03ce72962e932431b9a61f28facf26", size = 261057, upload-time = "2026-02-09T12:57:52.447Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/a2/60010c669df5fa603bb5a97fb75407e191a846510da70ac657eb696b7fce/coverage-7.13.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb88b316ec33760714a4720feb2816a3a59180fd58c1985012054fa7aebee4c2", size = 263875, upload-time = "2026-02-09T12:57:53.938Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/d9/63b22a6bdbd17f1f96e9ed58604c2a6b0e72a9133e37d663bef185877cf6/coverage-7.13.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d41eead3cc673cbd38a4417deb7fd0b4ca26954ff7dc6078e33f6ff97bed940", size = 261500, upload-time = "2026-02-09T12:57:56.012Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/bf/69f86ba1ad85bc3ad240e4c0e57a2e620fbc0e1645a47b5c62f0e941ad7f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:fb26a934946a6afe0e326aebe0730cdff393a8bc0bbb65a2f41e30feddca399c", size = 265212, upload-time = "2026-02-09T12:57:57.5Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ae/f2/5f65a278a8c2148731831574c73e42f57204243d33bedaaf18fa79c5958f/coverage-7.13.4-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:dae88bc0fc77edaa65c14be099bd57ee140cf507e6bfdeea7938457ab387efb0", size = 260398, upload-time = "2026-02-09T12:57:59.027Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/80/6e8280a350ee9fea92f14b8357448a242dcaa243cb2c72ab0ca591f66c8c/coverage-7.13.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:845f352911777a8e722bfce168958214951e07e47e5d5d9744109fa5fe77f79b", size = 262584, upload-time = "2026-02-09T12:58:01.129Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/63/01ff182fc95f260b539590fb12c11ad3e21332c15f9799cb5e2386f71d9f/coverage-7.13.4-cp313-cp313t-win32.whl", hash = "sha256:2fa8d5f8de70688a28240de9e139fa16b153cc3cbb01c5f16d88d6505ebdadf9", size = 222688, upload-time = "2026-02-09T12:58:02.736Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/43/89de4ef5d3cd53b886afa114065f7e9d3707bdb3e5efae13535b46ae483d/coverage-7.13.4-cp313-cp313t-win_amd64.whl", hash = "sha256:9351229c8c8407645840edcc277f4a2d44814d1bc34a2128c11c2a031d45a5dd", size = 223746, upload-time = "2026-02-09T12:58:05.362Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/39/7cf0aa9a10d470a5309b38b289b9bb07ddeac5d61af9b664fe9775a4cb3e/coverage-7.13.4-cp313-cp313t-win_arm64.whl", hash = "sha256:30b8d0512f2dc8c8747557e8fb459d6176a2c9e5731e2b74d311c03b78451997", size = 222003, upload-time = "2026-02-09T12:58:06.952Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/11/a9cf762bb83386467737d32187756a42094927150c3e107df4cb078e8590/coverage-7.13.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:300deaee342f90696ed186e3a00c71b5b3d27bffe9e827677954f4ee56969601", size = 219522, upload-time = "2026-02-09T12:58:08.623Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/28/56e6d892b7b052236d67c95f1936b6a7cf7c3e2634bf27610b8cbd7f9c60/coverage-7.13.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29e3220258d682b6226a9b0925bc563ed9a1ebcff3cad30f043eceea7eaf2689", size = 219855, upload-time = "2026-02-09T12:58:10.176Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e5/69/233459ee9eb0c0d10fcc2fe425a029b3fa5ce0f040c966ebce851d030c70/coverage-7.13.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:391ee8f19bef69210978363ca930f7328081c6a0152f1166c91f0b5fdd2a773c", size = 250887, upload-time = "2026-02-09T12:58:12.503Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/90/2cdab0974b9b5bbc1623f7876b73603aecac11b8d95b85b5b86b32de5eab/coverage-7.13.4-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0dd7ab8278f0d58a0128ba2fca25824321f05d059c1441800e934ff2efa52129", size = 253396, upload-time = "2026-02-09T12:58:14.615Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/15/ea4da0f85bf7d7b27635039e649e99deb8173fe551096ea15017f7053537/coverage-7.13.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78cdf0d578b15148b009ccf18c686aa4f719d887e76e6b40c38ffb61d264a552", size = 254745, upload-time = "2026-02-09T12:58:16.162Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/99/11/bb356e86920c655ca4d61daee4e2bbc7258f0a37de0be32d233b561134ff/coverage-7.13.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:48685fee12c2eb3b27c62f2658e7ea21e9c3239cba5a8a242801a0a3f6a8c62a", size = 257055, upload-time = "2026-02-09T12:58:17.892Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/0f/9ae1f8cb17029e09da06ca4e28c9e1d5c1c0a511c7074592e37e0836c915/coverage-7.13.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4e83efc079eb39480e6346a15a1bcb3e9b04759c5202d157e1dd4303cd619356", size = 250911, upload-time = "2026-02-09T12:58:19.495Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/3a/adfb68558fa815cbc29747b553bc833d2150228f251b127f1ce97e48547c/coverage-7.13.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ecae9737b72408d6a950f7e525f30aca12d4bd8dd95e37342e5beb3a2a8c4f71", size = 252754, upload-time = "2026-02-09T12:58:21.064Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/b1/540d0c27c4e748bd3cd0bd001076ee416eda993c2bae47a73b7cc9357931/coverage-7.13.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ae4578f8528569d3cf303fef2ea569c7f4c4059a38c8667ccef15c6e1f118aa5", size = 250720, upload-time = "2026-02-09T12:58:22.622Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/95/383609462b3ffb1fe133014a7c84fc0dd01ed55ac6140fa1093b5af7ebb1/coverage-7.13.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6fdef321fdfbb30a197efa02d48fcd9981f0d8ad2ae8903ac318adc653f5df98", size = 254994, upload-time = "2026-02-09T12:58:24.548Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/ba/1761138e86c81680bfc3c49579d66312865457f9fe405b033184e5793cb3/coverage-7.13.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b0f6ccf3dbe577170bebfce1318707d0e8c3650003cb4b3a9dd744575daa8b5", size = 250531, upload-time = "2026-02-09T12:58:26.271Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/8e/05900df797a9c11837ab59c4d6fe94094e029582aab75c3309a93e6fb4e3/coverage-7.13.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75fcd519f2a5765db3f0e391eb3b7d150cce1a771bf4c9f861aeab86c767a3c0", size = 252189, upload-time = "2026-02-09T12:58:27.807Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/bd/29c9f2db9ea4ed2738b8a9508c35626eb205d51af4ab7bf56a21a2e49926/coverage-7.13.4-cp314-cp314-win32.whl", hash = "sha256:8e798c266c378da2bd819b0677df41ab46d78065fb2a399558f3f6cae78b2fbb", size = 222258, upload-time = "2026-02-09T12:58:29.441Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/4d/1f8e723f6829977410efeb88f73673d794075091c8c7c18848d273dc9d73/coverage-7.13.4-cp314-cp314-win_amd64.whl", hash = "sha256:245e37f664d89861cf2329c9afa2c1fe9e6d4e1a09d872c947e70718aeeac505", size = 223073, upload-time = "2026-02-09T12:58:31.026Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/5b/84100025be913b44e082ea32abcf1afbf4e872f5120b7a1cab1d331b1e13/coverage-7.13.4-cp314-cp314-win_arm64.whl", hash = "sha256:ad27098a189e5838900ce4c2a99f2fe42a0bf0c2093c17c69b45a71579e8d4a2", size = 221638, upload-time = "2026-02-09T12:58:32.599Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/e4/c884a405d6ead1370433dad1e3720216b4f9fd8ef5b64bfd984a2a60a11a/coverage-7.13.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:85480adfb35ffc32d40918aad81b89c69c9cc5661a9b8a81476d3e645321a056", size = 220246, upload-time = "2026-02-09T12:58:34.181Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/5c/4d7ed8b23b233b0fffbc9dfec53c232be2e695468523242ea9fd30f97ad2/coverage-7.13.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:79be69cf7f3bf9b0deeeb062eab7ac7f36cd4cc4c4dd694bd28921ba4d8596cc", size = 220514, upload-time = "2026-02-09T12:58:35.704Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/6f/3284d4203fd2f28edd73034968398cd2d4cb04ab192abc8cff007ea35679/coverage-7.13.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:caa421e2684e382c5d8973ac55e4f36bed6821a9bad5c953494de960c74595c9", size = 261877, upload-time = "2026-02-09T12:58:37.864Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/aa/b672a647bbe1556a85337dc95bfd40d146e9965ead9cc2fe81bde1e5cbce/coverage-7.13.4-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14375934243ee05f56c45393fe2ce81fe5cc503c07cee2bdf1725fb8bef3ffaf", size = 264004, upload-time = "2026-02-09T12:58:39.492Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/a1/aa384dbe9181f98bba87dd23dda436f0c6cf2e148aecbb4e50fc51c1a656/coverage-7.13.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25a41c3104d08edb094d9db0d905ca54d0cd41c928bb6be3c4c799a54753af55", size = 266408, upload-time = "2026-02-09T12:58:41.852Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/53/5e/5150bf17b4019bc600799f376bb9606941e55bd5a775dc1e096b6ffea952/coverage-7.13.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f01afcff62bf9a08fb32b2c1d6e924236c0383c02c790732b6537269e466a72", size = 267544, upload-time = "2026-02-09T12:58:44.093Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/ed/f1de5c675987a4a7a672250d2c5c9d73d289dbf13410f00ed7181d8017dd/coverage-7.13.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eb9078108fbf0bcdde37c3f4779303673c2fa1fe8f7956e68d447d0dd426d38a", size = 260980, upload-time = "2026-02-09T12:58:45.721Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b3/e3/fe758d01850aa172419a6743fe76ba8b92c29d181d4f676ffe2dae2ba631/coverage-7.13.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e086334e8537ddd17e5f16a344777c1ab8194986ec533711cbe6c41cde841b6", size = 263871, upload-time = "2026-02-09T12:58:47.334Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b6/76/b829869d464115e22499541def9796b25312b8cf235d3bb00b39f1675395/coverage-7.13.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:725d985c5ab621268b2edb8e50dfe57633dc69bda071abc470fed55a14935fd3", size = 261472, upload-time = "2026-02-09T12:58:48.995Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/9e/caedb1679e73e2f6ad240173f55218488bfe043e38da577c4ec977489915/coverage-7.13.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3c06f0f1337c667b971ca2f975523347e63ec5e500b9aa5882d91931cd3ef750", size = 265210, upload-time = "2026-02-09T12:58:51.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/10/0dd02cb009b16ede425b49ec344aba13a6ae1dc39600840ea6abcb085ac4/coverage-7.13.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:590c0ed4bf8e85f745e6b805b2e1c457b2e33d5255dd9729743165253bc9ad39", size = 260319, upload-time = "2026-02-09T12:58:53.081Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/8e/234d2c927af27c6d7a5ffad5bd2cf31634c46a477b4c7adfbfa66baf7ebb/coverage-7.13.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eb30bf180de3f632cd043322dad5751390e5385108b2807368997d1a92a509d0", size = 262638, upload-time = "2026-02-09T12:58:55.258Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/64/e5547c8ff6964e5965c35a480855911b61509cce544f4d442caa759a0702/coverage-7.13.4-cp314-cp314t-win32.whl", hash = "sha256:c4240e7eded42d131a2d2c4dec70374b781b043ddc79a9de4d55ca71f8e98aea", size = 223040, upload-time = "2026-02-09T12:58:56.936Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/96/38086d58a181aac86d503dfa9c47eb20715a79c3e3acbdf786e92e5c09a8/coverage-7.13.4-cp314-cp314t-win_amd64.whl", hash = "sha256:4c7d3cc01e7350f2f0f6f7036caaf5673fb56b6998889ccfe9e1c1fe75a9c932", size = 224148, upload-time = "2026-02-09T12:58:58.645Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/72/8d10abd3740a0beb98c305e0c3faf454366221c0f37a8bcf8f60020bb65a/coverage-7.13.4-cp314-cp314t-win_arm64.whl", hash = "sha256:23e3f687cf945070d1c90f85db66d11e3025665d8dafa831301a0e0038f3db9b", size = 222172, upload-time = "2026-02-09T12:59:00.396Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diceplayer"
|
||||||
|
source = { editable = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "argparse" },
|
||||||
|
{ name = "numpy" },
|
||||||
|
{ name = "pydantic" },
|
||||||
|
{ name = "pyyaml" },
|
||||||
|
{ name = "setproctitle" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dev-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "black" },
|
||||||
|
{ name = "coverage" },
|
||||||
|
{ name = "isort" },
|
||||||
|
{ name = "poethepoet" },
|
||||||
|
{ name = "pre-commit" },
|
||||||
|
{ name = "pytest" },
|
||||||
|
{ name = "ruff" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "argparse", specifier = ">=1.4.0" },
|
||||||
|
{ name = "numpy", specifier = ">=2.2.0" },
|
||||||
|
{ name = "pydantic", specifier = ">=2.12.5" },
|
||||||
|
{ name = "pyyaml", specifier = ">=6.0" },
|
||||||
|
{ name = "setproctitle", specifier = ">=1.3.2" },
|
||||||
|
{ name = "typing-extensions", specifier = ">=4.15.0" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [
|
||||||
|
{ name = "black", specifier = ">=24.4.2" },
|
||||||
|
{ name = "coverage", specifier = ">=7.2.7" },
|
||||||
|
{ name = "isort", specifier = ">=5.13.2" },
|
||||||
|
{ name = "poethepoet", specifier = ">=0.27.0" },
|
||||||
|
{ name = "pre-commit", specifier = ">=3.7.1" },
|
||||||
|
{ name = "pytest", specifier = ">=9.0.2" },
|
||||||
|
{ name = "ruff", specifier = ">=0.15.2" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "distlib"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filelock"
|
||||||
|
version = "3.24.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935, upload-time = "2026-02-19T00:48:20.543Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331, upload-time = "2026-02-19T00:48:18.465Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "identify"
|
||||||
|
version = "2.6.16"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/5b/8d/e8b97e6bd3fb6fb271346f7981362f1e04d6a7463abd0de79e1fda17c067/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360, upload-time = "2026-01-12T18:58:58.201Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/58/40fbbcefeda82364720eba5cf2270f98496bdfa19ea75b4cccae79c698e6/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202, upload-time = "2026-01-12T18:58:56.627Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "isort"
|
||||||
|
version = "8.0.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ef/7c/ec4ab396d31b3b395e2e999c8f46dec78c5e29209fac49d1f4dace04041d/isort-8.0.1.tar.gz", hash = "sha256:171ac4ff559cdc060bcfff550bc8404a486fee0caab245679c2abe7cb253c78d", size = 769592, upload-time = "2026-02-28T10:08:20.685Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/95/c7c34aa53c16353c56d0b802fba48d5f5caa2cdee7958acbcb795c830416/isort-8.0.1-py3-none-any.whl", hash = "sha256:28b89bc70f751b559aeca209e6120393d43fbe2490de0559662be7a9787e3d75", size = 89733, upload-time = "2026-02-28T10:08:19.466Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mypy-extensions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nodeenv"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "numpy"
|
||||||
|
version = "2.4.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/51/6e/6f394c9c77668153e14d4da83bcc247beb5952f6ead7699a1a2992613bea/numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a", size = 16667963, upload-time = "2026-01-31T23:10:52.147Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1f/f8/55483431f2b2fd015ae6ed4fe62288823ce908437ed49db5a03d15151678/numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1", size = 14693571, upload-time = "2026-01-31T23:10:54.789Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/20/18026832b1845cdc82248208dd929ca14c9d8f2bac391f67440707fff27c/numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e", size = 5203469, upload-time = "2026-01-31T23:10:57.343Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/33/2eb97c8a77daaba34eaa3fa7241a14ac5f51c46a6bd5911361b644c4a1e2/numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27", size = 6550820, upload-time = "2026-01-31T23:10:59.429Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/91/b97fdfd12dc75b02c44e26c6638241cc004d4079a0321a69c62f51470c4c/numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548", size = 15663067, upload-time = "2026-01-31T23:11:01.291Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f5/c6/a18e59f3f0b8071cc85cbc8d80cd02d68aa9710170b2553a117203d46936/numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f", size = 16619782, upload-time = "2026-01-31T23:11:03.669Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/83/9751502164601a79e18847309f5ceec0b1446d7b6aa12305759b72cf98b2/numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460", size = 17013128, upload-time = "2026-01-31T23:11:05.913Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/c4/c4066322256ec740acc1c8923a10047818691d2f8aec254798f3dd90f5f2/numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba", size = 18345324, upload-time = "2026-01-31T23:11:08.248Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/af/6157aa6da728fa4525a755bfad486ae7e3f76d4c1864138003eb84328497/numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f", size = 5960282, upload-time = "2026-01-31T23:11:10.497Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/0f/7ceaaeaacb40567071e94dbf2c9480c0ae453d5bb4f52bea3892c39dc83c/numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85", size = 12314210, upload-time = "2026-01-31T23:11:12.176Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/a3/56c5c604fae6dd40fa2ed3040d005fca97e91bd320d232ac9931d77ba13c/numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa", size = 10220171, upload-time = "2026-01-31T23:11:14.684Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a1/22/815b9fe25d1d7ae7d492152adbc7226d3eff731dffc38fe970589fcaaa38/numpy-2.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c", size = 16663696, upload-time = "2026-01-31T23:11:17.516Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979", size = 14688322, upload-time = "2026-01-31T23:11:19.883Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98", size = 5198157, upload-time = "2026-01-31T23:11:22.375Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/09/826e4289844eccdcd64aac27d13b0fd3f32039915dd5b9ba01baae1f436c/numpy-2.4.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef", size = 6546330, upload-time = "2026-01-31T23:11:23.958Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/fb/cbfdbfa3057a10aea5422c558ac57538e6acc87ec1669e666d32ac198da7/numpy-2.4.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7", size = 15660968, upload-time = "2026-01-31T23:11:25.713Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499", size = 16607311, upload-time = "2026-01-31T23:11:28.117Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/d9/4b5adfc39a43fa6bf918c6d544bc60c05236cc2f6339847fc5b35e6cb5b0/numpy-2.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb", size = 17012850, upload-time = "2026-01-31T23:11:30.888Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7", size = 18334210, upload-time = "2026-01-31T23:11:33.214Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/0e/0a73b3dff26803a8c02baa76398015ea2a5434d9b8265a7898a6028c1591/numpy-2.4.2-cp313-cp313-win32.whl", hash = "sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110", size = 5958199, upload-time = "2026-01-31T23:11:35.385Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/43/bc/6352f343522fcb2c04dbaf94cb30cca6fd32c1a750c06ad6231b4293708c/numpy-2.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622", size = 12310848, upload-time = "2026-01-31T23:11:38.001Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/8d/6da186483e308da5da1cc6918ce913dcfe14ffde98e710bfeff2a6158d4e/numpy-2.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71", size = 10221082, upload-time = "2026-01-31T23:11:40.392Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262", size = 14815866, upload-time = "2026-01-31T23:11:42.495Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913", size = 5325631, upload-time = "2026-01-31T23:11:44.7Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/46/00/3a490938800c1923b567b3a15cd17896e68052e2145d8662aaf3e1ffc58f/numpy-2.4.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab", size = 6646254, upload-time = "2026-01-31T23:11:46.341Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/e9/fac0890149898a9b609caa5af7455a948b544746e4b8fe7c212c8edd71f8/numpy-2.4.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82", size = 15720138, upload-time = "2026-01-31T23:11:48.082Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f", size = 16655398, upload-time = "2026-01-31T23:11:50.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4d/89/253db0fa0e66e9129c745e4ef25631dc37d5f1314dad2b53e907b8538e6d/numpy-2.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554", size = 17079064, upload-time = "2026-01-31T23:11:52.927Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257", size = 18379680, upload-time = "2026-01-31T23:11:55.22Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/40/62/48f99ae172a4b63d981babe683685030e8a3df4f246c893ea5c6ef99f018/numpy-2.4.2-cp313-cp313t-win32.whl", hash = "sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657", size = 6082433, upload-time = "2026-01-31T23:11:58.096Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/07/38/e054a61cfe48ad9f1ed0d188e78b7e26859d0b60ef21cd9de4897cdb5326/numpy-2.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b", size = 12451181, upload-time = "2026-01-31T23:11:59.782Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/a4/a05c3a6418575e185dd84d0b9680b6bb2e2dc3e4202f036b7b4e22d6e9dc/numpy-2.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1", size = 10290756, upload-time = "2026-01-31T23:12:02.438Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/88/b7df6050bf18fdcfb7046286c6535cabbdd2064a3440fca3f069d319c16e/numpy-2.4.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:444be170853f1f9d528428eceb55f12918e4fda5d8805480f36a002f1415e09b", size = 16663092, upload-time = "2026-01-31T23:12:04.521Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/7a/1fee4329abc705a469a4afe6e69b1ef7e915117747886327104a8493a955/numpy-2.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d1240d50adff70c2a88217698ca844723068533f3f5c5fa6ee2e3220e3bdb000", size = 14698770, upload-time = "2026-01-31T23:12:06.96Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/0b/f9e49ba6c923678ad5bc38181c08ac5e53b7a5754dbca8e581aa1a56b1ff/numpy-2.4.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:7cdde6de52fb6664b00b056341265441192d1291c130e99183ec0d4b110ff8b1", size = 5208562, upload-time = "2026-01-31T23:12:09.632Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/12/d7de8f6f53f9bb76997e5e4c069eda2051e3fe134e9181671c4391677bb2/numpy-2.4.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:cda077c2e5b780200b6b3e09d0b42205a3d1c68f30c6dceb90401c13bff8fe74", size = 6543710, upload-time = "2026-01-31T23:12:11.969Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/63/c66418c2e0268a31a4cf8a8b512685748200f8e8e8ec6c507ce14e773529/numpy-2.4.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d30291931c915b2ab5717c2974bb95ee891a1cf22ebc16a8006bd59cd210d40a", size = 15677205, upload-time = "2026-01-31T23:12:14.33Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/6c/7f237821c9642fb2a04d2f1e88b4295677144ca93285fd76eff3bcba858d/numpy-2.4.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bba37bc29d4d85761deed3954a1bc62be7cf462b9510b51d367b769a8c8df325", size = 16611738, upload-time = "2026-01-31T23:12:16.525Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/a7/39c4cdda9f019b609b5c473899d87abff092fc908cfe4d1ecb2fcff453b0/numpy-2.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b2f0073ed0868db1dcd86e052d37279eef185b9c8db5bf61f30f46adac63c909", size = 17028888, upload-time = "2026-01-31T23:12:19.306Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/b3/e84bb64bdfea967cc10950d71090ec2d84b49bc691df0025dddb7c26e8e3/numpy-2.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7f54844851cdb630ceb623dcec4db3240d1ac13d4990532446761baede94996a", size = 18339556, upload-time = "2026-01-31T23:12:21.816Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/f5/954a291bc1192a27081706862ac62bb5920fbecfbaa302f64682aa90beed/numpy-2.4.2-cp314-cp314-win32.whl", hash = "sha256:12e26134a0331d8dbd9351620f037ec470b7c75929cb8a1537f6bfe411152a1a", size = 6006899, upload-time = "2026-01-31T23:12:24.14Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/cb/eff72a91b2efdd1bc98b3b8759f6a1654aa87612fc86e3d87d6fe4f948c4/numpy-2.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:068cdb2d0d644cdb45670810894f6a0600797a69c05f1ac478e8d31670b8ee75", size = 12443072, upload-time = "2026-01-31T23:12:26.33Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/75/62726948db36a56428fce4ba80a115716dc4fad6a3a4352487f8bb950966/numpy-2.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:6ed0be1ee58eef41231a5c943d7d1375f093142702d5723ca2eb07db9b934b05", size = 10494886, upload-time = "2026-01-31T23:12:28.488Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/2f/ee93744f1e0661dc267e4b21940870cabfae187c092e1433b77b09b50ac4/numpy-2.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:98f16a80e917003a12c0580f97b5f875853ebc33e2eaa4bccfc8201ac6869308", size = 14818567, upload-time = "2026-01-31T23:12:30.709Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/24/6535212add7d76ff938d8bdc654f53f88d35cddedf807a599e180dcb8e66/numpy-2.4.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:20abd069b9cda45874498b245c8015b18ace6de8546bf50dfa8cea1696ed06ef", size = 5328372, upload-time = "2026-01-31T23:12:32.962Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5e/9d/c48f0a035725f925634bf6b8994253b43f2047f6778a54147d7e213bc5a7/numpy-2.4.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e98c97502435b53741540a5717a6749ac2ada901056c7db951d33e11c885cc7d", size = 6649306, upload-time = "2026-01-31T23:12:34.797Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/05/7c73a9574cd4a53a25907bad38b59ac83919c0ddc8234ec157f344d57d9a/numpy-2.4.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da6cad4e82cb893db4b69105c604d805e0c3ce11501a55b5e9f9083b47d2ffe8", size = 15722394, upload-time = "2026-01-31T23:12:36.565Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/fa/4de10089f21fc7d18442c4a767ab156b25c2a6eaf187c0db6d9ecdaeb43f/numpy-2.4.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e4424677ce4b47fe73c8b5556d876571f7c6945d264201180db2dc34f676ab5", size = 16653343, upload-time = "2026-01-31T23:12:39.188Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/f9/d33e4ffc857f3763a57aa85650f2e82486832d7492280ac21ba9efda80da/numpy-2.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2b8f157c8a6f20eb657e240f8985cc135598b2b46985c5bccbde7616dc9c6b1e", size = 17078045, upload-time = "2026-01-31T23:12:42.041Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/b8/54bdb43b6225badbea6389fa038c4ef868c44f5890f95dd530a218706da3/numpy-2.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5daf6f3914a733336dab21a05cdec343144600e964d2fcdabaac0c0269874b2a", size = 18380024, upload-time = "2026-01-31T23:12:44.331Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/55/6e1a61ded7af8df04016d81b5b02daa59f2ea9252ee0397cb9f631efe9e5/numpy-2.4.2-cp314-cp314t-win32.whl", hash = "sha256:8c50dd1fc8826f5b26a5ee4d77ca55d88a895f4e4819c7ecc2a9f5905047a443", size = 6153937, upload-time = "2026-01-31T23:12:47.229Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/45/aa/fa6118d1ed6d776b0983f3ceac9b1a5558e80df9365b1c3aa6d42bf9eee4/numpy-2.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:fcf92bee92742edd401ba41135185866f7026c502617f422eb432cfeca4fe236", size = 12631844, upload-time = "2026-01-31T23:12:48.997Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/32/0a/2ec5deea6dcd158f254a7b372fb09cfba5719419c8d66343bab35237b3fb/numpy-2.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181", size = 10565379, upload-time = "2026-01-31T23:12:51.345Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "26.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pastel"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathspec"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "platformdirs"
|
||||||
|
version = "4.9.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394, upload-time = "2026-02-16T03:56:10.574Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluggy"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "poethepoet"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "pastel" },
|
||||||
|
{ name = "pyyaml" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/05/9b/e717572686bbf23e17483389c1bf3a381ca2427c84c7e0af0cdc0f23fccc/poethepoet-0.42.1.tar.gz", hash = "sha256:205747e276062c2aaba8afd8a98838f8a3a0237b7ab94715fab8d82718aac14f", size = 93209, upload-time = "2026-02-26T22:57:50.883Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/68/75fa0a5ef39718ea6ba7ab6a3d031fa93640e57585580cec85539540bb65/poethepoet-0.42.1-py3-none-any.whl", hash = "sha256:d8d1345a5ca521be9255e7c13bc2c4c8698ed5e5ac5e9e94890d239fcd423d0a", size = 119967, upload-time = "2026-02-26T22:57:49.467Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pre-commit"
|
||||||
|
version = "4.5.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "cfgv" },
|
||||||
|
{ name = "identify" },
|
||||||
|
{ name = "nodeenv" },
|
||||||
|
{ name = "pyyaml" },
|
||||||
|
{ name = "virtualenv" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic"
|
||||||
|
version = "2.12.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "annotated-types" },
|
||||||
|
{ name = "pydantic-core" },
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
{ name = "typing-inspection" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydantic-core"
|
||||||
|
version = "2.41.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.19.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "9.0.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "iniconfig" },
|
||||||
|
{ name = "packaging" },
|
||||||
|
{ name = "pluggy" },
|
||||||
|
{ name = "pygments" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-discovery"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "filelock" },
|
||||||
|
{ name = "platformdirs" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/82/bb/93a3e83bdf9322c7e21cafd092e56a4a17c4d8ef4277b6eb01af1a540a6f/python_discovery-1.1.0.tar.gz", hash = "sha256:447941ba1aed8cc2ab7ee3cb91be5fc137c5bdbb05b7e6ea62fbdcb66e50b268", size = 55674, upload-time = "2026-02-26T09:42:49.668Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/54/82a6e2ef37f0f23dccac604b9585bdcbd0698604feb64807dcb72853693e/python_discovery-1.1.0-py3-none-any.whl", hash = "sha256:a162893b8809727f54594a99ad2179d2ede4bf953e12d4c7abc3cc9cdbd1437b", size = 30687, upload-time = "2026-02-26T09:42:48.548Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytokens"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cb/dc/08b1a080372afda3cceb4f3c0a7ba2bde9d6a5241f1edb02a22a019ee147/pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b", size = 160720, upload-time = "2026-01-30T01:03:13.843Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/64/0c/41ea22205da480837a700e395507e6a24425151dfb7ead73343d6e2d7ffe/pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f", size = 254204, upload-time = "2026-01-30T01:03:14.886Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload-time = "2026-01-30T01:03:15.936Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload-time = "2026-01-30T01:03:17.458Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload-time = "2026-01-30T01:03:18.652Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyyaml"
|
||||||
|
version = "6.0.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ruff"
|
||||||
|
version = "0.15.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/da/31/d6e536cdebb6568ae75a7f00e4b4819ae0ad2640c3604c305a0428680b0c/ruff-0.15.4.tar.gz", hash = "sha256:3412195319e42d634470cc97aa9803d07e9d5c9223b99bcb1518f0c725f26ae1", size = 4569550, upload-time = "2026-02-26T20:04:14.959Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/82/c11a03cfec3a4d26a0ea1e571f0f44be5993b923f905eeddfc397c13d360/ruff-0.15.4-py3-none-linux_armv6l.whl", hash = "sha256:a1810931c41606c686bae8b5b9a8072adac2f611bb433c0ba476acba17a332e0", size = 10453333, upload-time = "2026-02-26T20:04:20.093Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/5d/6a1f271f6e31dffb31855996493641edc3eef8077b883eaf007a2f1c2976/ruff-0.15.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5a1632c66672b8b4d3e1d1782859e98d6e0b4e70829530666644286600a33992", size = 10853356, upload-time = "2026-02-26T20:04:05.808Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/d8/0fab9f8842b83b1a9c2bf81b85063f65e93fb512e60effa95b0be49bfc54/ruff-0.15.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4386ba2cd6c0f4ff75252845906acc7c7c8e1ac567b7bc3d373686ac8c222ba", size = 10187434, upload-time = "2026-02-26T20:03:54.656Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/cc/cc220fd9394eff5db8d94dec199eec56dd6c9f3651d8869d024867a91030/ruff-0.15.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2496488bdfd3732747558b6f95ae427ff066d1fcd054daf75f5a50674411e75", size = 10535456, upload-time = "2026-02-26T20:03:52.738Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/0f/bced38fa5cf24373ec767713c8e4cadc90247f3863605fb030e597878661/ruff-0.15.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f1c4893841ff2d54cbda1b2860fa3260173df5ddd7b95d370186f8a5e66a4ac", size = 10287772, upload-time = "2026-02-26T20:04:08.138Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/90/58a1802d84fed15f8f281925b21ab3cecd813bde52a8ca033a4de8ab0e7a/ruff-0.15.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:820b8766bd65503b6c30aaa6331e8ef3a6e564f7999c844e9a547c40179e440a", size = 11049051, upload-time = "2026-02-26T20:04:03.53Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/ac/b7ad36703c35f3866584564dc15f12f91cb1a26a897dc2fd13d7cb3ae1af/ruff-0.15.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9fb74bab47139c1751f900f857fa503987253c3ef89129b24ed375e72873e85", size = 11890494, upload-time = "2026-02-26T20:04:10.497Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/93/3d/3eb2f47a39a8b0da99faf9c54d3eb24720add1e886a5309d4d1be73a6380/ruff-0.15.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80c98765949c518142b3a50a5db89343aa90f2c2bf7799de9986498ae6176db", size = 11326221, upload-time = "2026-02-26T20:04:12.84Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/90/bf134f4c1e5243e62690e09d63c55df948a74084c8ac3e48a88468314da6/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451a2e224151729b3b6c9ffb36aed9091b2996fe4bdbd11f47e27d8f2e8888ec", size = 11168459, upload-time = "2026-02-26T20:04:00.969Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/e5/a64d27688789b06b5d55162aafc32059bb8c989c61a5139a36e1368285eb/ruff-0.15.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a8f157f2e583c513c4f5f896163a93198297371f34c04220daf40d133fdd4f7f", size = 11104366, upload-time = "2026-02-26T20:03:48.099Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/f6/32d1dcb66a2559763fc3027bdd65836cad9eb09d90f2ed6a63d8e9252b02/ruff-0.15.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:917cc68503357021f541e69b35361c99387cdbbf99bd0ea4aa6f28ca99ff5338", size = 10510887, upload-time = "2026-02-26T20:03:45.771Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ff/92/22d1ced50971c5b6433aed166fcef8c9343f567a94cf2b9d9089f6aa80fe/ruff-0.15.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e9737c8161da79fd7cfec19f1e35620375bd8b2a50c3e77fa3d2c16f574105cc", size = 10285939, upload-time = "2026-02-26T20:04:22.42Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/f4/7c20aec3143837641a02509a4668fb146a642fd1211846634edc17eb5563/ruff-0.15.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:291258c917539e18f6ba40482fe31d6f5ac023994ee11d7bdafd716f2aab8a68", size = 10765471, upload-time = "2026-02-26T20:03:58.924Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/09/6d2f7586f09a16120aebdff8f64d962d7c4348313c77ebb29c566cefc357/ruff-0.15.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3f83c45911da6f2cd5936c436cf86b9f09f09165f033a99dcf7477e34041cbc3", size = 11263382, upload-time = "2026-02-26T20:04:24.424Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/fa/2ef715a1cd329ef47c1a050e10dee91a9054b7ce2fcfdd6a06d139afb7ec/ruff-0.15.4-py3-none-win32.whl", hash = "sha256:65594a2d557d4ee9f02834fcdf0a28daa8b3b9f6cb2cb93846025a36db47ef22", size = 10506664, upload-time = "2026-02-26T20:03:50.56Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/a8/c688ef7e29983976820d18710f955751d9f4d4eb69df658af3d006e2ba3e/ruff-0.15.4-py3-none-win_amd64.whl", hash = "sha256:04196ad44f0df220c2ece5b0e959c2f37c777375ec744397d21d15b50a75264f", size = 11651048, upload-time = "2026-02-26T20:04:17.191Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3e/0a/9e1be9035b37448ce2e68c978f0591da94389ade5a5abafa4cf99985d1b2/ruff-0.15.4-py3-none-win_arm64.whl", hash = "sha256:60d5177e8cfc70e51b9c5fad936c634872a74209f934c1e79107d11787ad5453", size = 10966776, upload-time = "2026-02-26T20:03:56.908Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "setproctitle"
|
||||||
|
version = "1.3.7"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/f0/2dc88e842077719d7384d86cc47403e5102810492b33680e7dadcee64cd8/setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e", size = 18049, upload-time = "2025-09-05T12:49:36.241Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/b4/50940504466689cda65680c9e9a1e518e5750c10490639fa687489ac7013/setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798", size = 13079, upload-time = "2025-09-05T12:49:38.088Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/99/71630546b9395b095f4082be41165d1078204d1696c2d9baade3de3202d0/setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629", size = 32932, upload-time = "2025-09-05T12:49:39.271Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/22/cee06af4ffcfb0e8aba047bd44f5262e644199ae7527ae2c1f672b86495c/setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1", size = 33736, upload-time = "2025-09-05T12:49:40.565Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/00/a5949a8bb06ef5e7df214fc393bb2fb6aedf0479b17214e57750dfdd0f24/setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6", size = 35605, upload-time = "2025-09-05T12:49:42.362Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/3a/50caca532a9343828e3bf5778c7a84d6c737a249b1796d50dd680290594d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c", size = 33143, upload-time = "2025-09-05T12:49:43.515Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/14/b843a251296ce55e2e17c017d6b9f11ce0d3d070e9265de4ecad948b913d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a", size = 34434, upload-time = "2025-09-05T12:49:45.31Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c8/b7/06145c238c0a6d2c4bc881f8be230bb9f36d2bf51aff7bddcb796d5eed67/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739", size = 32795, upload-time = "2025-09-05T12:49:46.419Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/dc/ef76a81fac9bf27b84ed23df19c1f67391a753eed6e3c2254ebcb5133f56/setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f", size = 12552, upload-time = "2025-09-05T12:49:47.635Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e2/5b/a9fe517912cd6e28cf43a212b80cb679ff179a91b623138a99796d7d18a0/setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300", size = 13247, upload-time = "2025-09-05T12:49:49.16Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/2f/fcedcade3b307a391b6e17c774c6261a7166aed641aee00ed2aad96c63ce/setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922", size = 18047, upload-time = "2025-09-05T12:49:50.271Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/ae/afc141ca9631350d0a80b8f287aac79a76f26b6af28fd8bf92dae70dc2c5/setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee", size = 13073, upload-time = "2025-09-05T12:49:51.46Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/ed/0a4f00315bc02510395b95eec3d4aa77c07192ee79f0baae77ea7b9603d8/setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd", size = 33284, upload-time = "2025-09-05T12:49:52.741Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fc/e4/adf3c4c0a2173cb7920dc9df710bcc67e9bcdbf377e243b7a962dc31a51a/setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0", size = 34104, upload-time = "2025-09-05T12:49:54.416Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/4f/6daf66394152756664257180439d37047aa9a1cfaa5e4f5ed35e93d1dc06/setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929", size = 35982, upload-time = "2025-09-05T12:49:56.295Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/62/f2c0595403cf915db031f346b0e3b2c0096050e90e0be658a64f44f4278a/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f", size = 33150, upload-time = "2025-09-05T12:49:58.025Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/29/10dd41cde849fb2f9b626c846b7ea30c99c81a18a5037a45cc4ba33c19a7/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698", size = 34463, upload-time = "2025-09-05T12:49:59.424Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/3c/cedd8eccfaf15fb73a2c20525b68c9477518917c9437737fa0fda91e378f/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c", size = 32848, upload-time = "2025-09-05T12:50:01.107Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/3e/0a0e27d1c9926fecccfd1f91796c244416c70bf6bca448d988638faea81d/setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd", size = 12544, upload-time = "2025-09-05T12:50:15.81Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/36/1b/6bf4cb7acbbd5c846ede1c3f4d6b4ee52744d402e43546826da065ff2ab7/setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f", size = 13235, upload-time = "2025-09-05T12:50:16.89Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e6/a4/d588d3497d4714750e3eaf269e9e8985449203d82b16b933c39bd3fc52a1/setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9", size = 18058, upload-time = "2025-09-05T12:50:02.501Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/05/77/7637f7682322a7244e07c373881c7e982567e2cb1dd2f31bd31481e45500/setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5", size = 13072, upload-time = "2025-09-05T12:50:03.601Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/09/f366eca0973cfbac1470068d1313fa3fe3de4a594683385204ec7f1c4101/setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29", size = 34490, upload-time = "2025-09-05T12:50:04.948Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/36/611fc2ed149fdea17c3677e1d0df30d8186eef9562acc248682b91312706/setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152", size = 35267, upload-time = "2025-09-05T12:50:06.015Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/88/a4/64e77d0671446bd5a5554387b69e1efd915274686844bea733714c828813/setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c", size = 37376, upload-time = "2025-09-05T12:50:07.484Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/bc/ad9c664fe524fb4a4b2d3663661a5c63453ce851736171e454fa2cdec35c/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b", size = 33963, upload-time = "2025-09-05T12:50:09.056Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/01/a36de7caf2d90c4c28678da1466b47495cbbad43badb4e982d8db8167ed4/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18", size = 35550, upload-time = "2025-09-05T12:50:10.791Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/c7/43ac3a98414f91d1b86a276bc2f799ad0b4b010e08497a95750d5bc42803/setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63", size = 18052, upload-time = "2025-09-05T12:50:17.928Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cd/2c/dc258600a25e1a1f04948073826bebc55e18dbd99dc65a576277a82146fa/setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e", size = 13071, upload-time = "2025-09-05T12:50:19.061Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ab/26/8e3bb082992f19823d831f3d62a89409deb6092e72fc6940962983ffc94f/setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f", size = 33180, upload-time = "2025-09-05T12:50:20.395Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f1/af/ae692a20276d1159dd0cf77b0bcf92cbb954b965655eb4a69672099bb214/setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5", size = 34043, upload-time = "2025-09-05T12:50:22.454Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/b2/6a092076324dd4dac1a6d38482bedebbff5cf34ef29f58585ec76e47bc9d/setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17", size = 35892, upload-time = "2025-09-05T12:50:23.937Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1c/1a/8836b9f28cee32859ac36c3df85aa03e1ff4598d23ea17ca2e96b5845a8f/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e", size = 32898, upload-time = "2025-09-05T12:50:25.617Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/22/8fabdc24baf42defb599714799d8445fe3ae987ec425a26ec8e80ea38f8e/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0", size = 34308, upload-time = "2025-09-05T12:50:26.827Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/15/1b/b9bee9de6c8cdcb3b3a6cb0b3e773afdb86bbbc1665a3bfa424a4294fda2/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8", size = 32536, upload-time = "2025-09-05T12:50:28.5Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/0c/75e5f2685a5e3eda0b39a8b158d6d8895d6daf3ba86dec9e3ba021510272/setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed", size = 12731, upload-time = "2025-09-05T12:50:43.955Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/ae/acddbce90d1361e1786e1fb421bc25baeb0c22ef244ee5d0176511769ec8/setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416", size = 13464, upload-time = "2025-09-05T12:50:45.057Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/6d/20886c8ff2e6d85e3cabadab6aab9bb90acaf1a5cfcb04d633f8d61b2626/setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3", size = 18062, upload-time = "2025-09-05T12:50:29.78Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/60/26dfc5f198715f1343b95c2f7a1c16ae9ffa45bd89ffd45a60ed258d24ea/setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309", size = 13075, upload-time = "2025-09-05T12:50:31.604Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/21/9c/980b01f50d51345dd513047e3ba9e96468134b9181319093e61db1c47188/setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b", size = 34744, upload-time = "2025-09-05T12:50:32.777Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/b4/82cd0c86e6d1c4538e1a7eb908c7517721513b801dff4ba3f98ef816a240/setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45", size = 35589, upload-time = "2025-09-05T12:50:34.13Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/4f/9f6b2a7417fd45673037554021c888b31247f7594ff4bd2239918c5cd6d0/setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4", size = 37698, upload-time = "2025-09-05T12:50:35.524Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/92/927b7d4744aac214d149c892cb5fa6dc6f49cfa040cb2b0a844acd63dcaf/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1", size = 34201, upload-time = "2025-09-05T12:50:36.697Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0a/0c/fd4901db5ba4b9d9013e62f61d9c18d52290497f956745cd3e91b0d80f90/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070", size = 35801, upload-time = "2025-09-05T12:50:38.314Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e7/e3/54b496ac724e60e61cc3447f02690105901ca6d90da0377dffe49ff99fc7/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73", size = 33958, upload-time = "2025-09-05T12:50:39.841Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ea/a8/c84bb045ebf8c6fdc7f7532319e86f8380d14bbd3084e6348df56bdfe6fd/setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2", size = 12745, upload-time = "2025-09-05T12:50:41.377Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/08/b6/3a5a4f9952972791a9114ac01dfc123f0df79903577a3e0a7a404a695586/setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a", size = 13469, upload-time = "2025-09-05T12:50:42.67Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "4.15.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-inspection"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "typing-extensions" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "virtualenv"
|
||||||
|
version = "21.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "distlib" },
|
||||||
|
{ name = "filelock" },
|
||||||
|
{ name = "platformdirs" },
|
||||||
|
{ name = "python-discovery" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2f/c9/18d4b36606d6091844daa3bd93cf7dc78e6f5da21d9f21d06c221104b684/virtualenv-21.1.0.tar.gz", hash = "sha256:1990a0188c8f16b6b9cf65c9183049007375b26aad415514d377ccacf1e4fb44", size = 5840471, upload-time = "2026-02-27T08:49:29.702Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/78/55/896b06bf93a49bec0f4ae2a6f1ed12bd05c8860744ac3a70eda041064e4d/virtualenv-21.1.0-py3-none-any.whl", hash = "sha256:164f5e14c5587d170cf98e60378eb91ea35bf037be313811905d3a24ea33cc07", size = 5825072, upload-time = "2026-02-27T08:49:27.516Z" },
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user