Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 8 additions & 24 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,29 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.10"]
poetry-version: ["1.3"]
python-version: ["3.11", "3.12"]

steps:
- uses: actions/checkout@v6
with:
submodules: true

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}

- name: Python Poetry Action
uses: abatilo/actions-poetry@v4
with:
poetry-version: ${{ matrix.poetry-version }}

- name: Configure Poetry to use matrix Python version
run: |
poetry env use python${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
poetry install --extras "cli fast solvents"
run: uv sync --all-extras

- name: Lint with Ruff
run: |
poetry run ruff check --output-format=github .
run: uv run ruff check --output-format=github .

- name: Lint with Black
run: |
poetry run black --check .
- name: Format check with Ruff
run: uv run ruff format --check .

- name: Test with pytest
run: |
poetry run pytest --cov=. --cov-report=xml
run: uv run pytest --cov=. --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
Expand Down
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.10.13
3.12
18 changes: 13 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,20 @@ forked repository.
> from [Open Source Guides](https://opensource.guide/) They may even have a
> translation for your native language!

After cloning your fork, we recommend using [Poetry](https://python-poetry.org/)
for managing your contributions:
We use [`uv`](https://docs.astral.sh/uv/) to develop the project, so first make sure it's installed.

After cloning your fork, run:

```console
$ git clone git@github.com:your-username/overreact.git # your-username is your GitHub username
$ git clone --recurse-submodules git@github.com:your-username/overreact.git # your-username is your GitHub username
$ cd overreact
$ poetry install -E cli -E fast -E solvents # all optional features
$ uv sync --all-extras
```

Before submitting any pull requests, make sure all tests pass with:

```console
$ uv run pytest
```

## Recommended practices
Expand Down Expand Up @@ -54,7 +61,8 @@ questions, the discussions are a better place to ask questions 😄.)
- Include tests if your patch solves a bug, and explain clearly
under which circumstances the bug happens. Make sure the test fails without
your patch.
- Use [Black](https://black.readthedocs.io/) to auto-format your code.
- Use [ruff format](https://docs.astral.sh/ruff/formatter/) to auto-format your code.
- Use [ruff check](https://docs.astral.sh/ruff/linter/) to check for code quality issues.
- Use
[Numpydoc documentation strings](https://numpydoc.readthedocs.io/en/latest/format.html)
to document your code.
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,10 @@ output files thanks to [`cclib`](https://cclib.github.io/) (see the

## Installation

**overreact** is a Python package, so you can easily install it with
[`pip`](https://pypi.org/project/pip/):
The preferred method of installation is through [`uv`](https://docs.astral.sh/uv/)

```console
$ pip install "overreact[cli,fast]"
$ uv tool install "overreact[cli,fast]"
```

See the
Expand Down
8 changes: 6 additions & 2 deletions overreact/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,9 @@ def _yield_thermochemistry(self):
temperature=self.temperature,
pressure=self.pressure,
),
), "reaction free energies do not match reaction enthalpies and reaction entropies"
), (
"reaction free energies do not match reaction enthalpies and reaction entropies"
)

delta_activation_mass = rx.get_delta(scheme.B, molecular_masses)
delta_activation_energies = rx.get_delta(scheme.B, energies)
Expand All @@ -413,7 +415,9 @@ def _yield_thermochemistry(self):
temperature=self.temperature,
pressure=self.pressure,
),
), "activation free energies do not match activation enthalpies and activation entropies"
), (
"activation free energies do not match activation enthalpies and activation entropies"
)

circ_table = Table(
Column("no", justify="right"),
Expand Down
29 changes: 9 additions & 20 deletions overreact/_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,22 @@

from __future__ import annotations

import os
from pathlib import Path

import overreact as rx

data_path = os.path.normpath(
os.path.join(os.path.dirname(__file__), "../data/"),
)

data_path = Path(__file__).parent.parent / "data"

logfiles = {}
for name in os.listdir(data_path):
walk_dir = os.path.join(data_path, name)
if os.path.isdir(walk_dir):
for walk_dir in data_path.iterdir():
if walk_dir.is_dir():
name = walk_dir.name
logfiles[name] = rx.io._LazyDict()
logfiles[name]._function = rx.io.read_logfile
for root, _, files in os.walk(walk_dir):
for filename in files:
if filename.endswith(".out"):
logfiles[name][
f"{filename[:-4]}@{os.path.relpath(root, walk_dir)}".replace(
"@.",
"",
)
] = os.path.join(
root,
filename,
)
for filepath in walk_dir.rglob("*.out"):
rel = filepath.parent.relative_to(walk_dir)
key = f"{filepath.stem}@{rel}".replace("@.", "")
logfiles[name][key] = str(filepath)


if __name__ == "__main__":
Expand Down
18 changes: 9 additions & 9 deletions overreact/_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
>>> Np = 3 # point number for central derivative
>>> weights = _central_diff_weights(Np) # weights for first derivative
>>> vals = [f(x + (i - Np/2) * h) for i in range(Np)]
>>> sum(w * v for (w, v) in zip(weights, vals))/h
>>> float(sum(w * v for (w, v) in zip(weights, vals))/h)
11.79999999999998

This value is close to the analytical solution:
Expand Down Expand Up @@ -118,7 +118,7 @@
--------
>>> def f(x):
... return x**3 + x**2
>>> _derivative(f, 1.0, dx=1e-6)
>>> float(_derivative(f, 1.0, dx=1e-6))
4.9999999999217337
"""
first_deriv_weight_map = {
Expand Down Expand Up @@ -196,7 +196,7 @@
"""
if isinstance(obj, np.ndarray):
return (tuple(obj.shape), tuple(obj.ravel()))
elif isinstance(obj, (list, set)):

Check failure on line 199 in overreact/_misc.py

View workflow job for this annotation

GitHub Actions / build (3.12)

Ruff (UP038)

overreact/_misc.py:199:10: UP038 Use `X | Y` in `isinstance` call instead of `(X, Y)`

Check failure on line 199 in overreact/_misc.py

View workflow job for this annotation

GitHub Actions / build (3.11)

Ruff (UP038)

overreact/_misc.py:199:10: UP038 Use `X | Y` in `isinstance` call instead of `(X, Y)`
return tuple(make_hashable(item) for item in obj)
else:
return obj
Expand Down Expand Up @@ -235,7 +235,7 @@
shape, flat_data = arg
if (
isinstance(shape, tuple)
and all(isinstance(dim, (int, np.integer)) for dim in shape)

Check failure on line 238 in overreact/_misc.py

View workflow job for this annotation

GitHub Actions / build (3.12)

Ruff (UP038)

overreact/_misc.py:238:33: UP038 Use `X | Y` in `isinstance` call instead of `(X, Y)`

Check failure on line 238 in overreact/_misc.py

View workflow job for this annotation

GitHub Actions / build (3.11)

Ruff (UP038)

overreact/_misc.py:238:33: UP038 Use `X | Y` in `isinstance` call instead of `(X, Y)`
and isinstance(flat_data, tuple)
):
if len(flat_data) == 0 or any(dim <= 0 for dim in shape):
Expand Down Expand Up @@ -841,7 +841,7 @@
*args,
**kwargs,
)
for xp, yp in zip(x0, y0)
for xp, yp in zip(x0, y0, strict=False)
],
axis=0,
)
Expand Down Expand Up @@ -873,7 +873,7 @@
((2, 2), (2, -2))
"""
# we don't touch some types, and this includes namedtuples
if isinstance(a, (int, float, str, rx.Scheme)):

Check failure on line 876 in overreact/_misc.py

View workflow job for this annotation

GitHub Actions / build (3.12)

Ruff (UP038)

overreact/_misc.py:876:8: UP038 Use `X | Y` in `isinstance` call instead of `(X, Y)`

Check failure on line 876 in overreact/_misc.py

View workflow job for this annotation

GitHub Actions / build (3.11)

Ruff (UP038)

overreact/_misc.py:876:8: UP038 Use `X | Y` in `isinstance` call instead of `(X, Y)`
return a

with contextlib.suppress(AttributeError):
Expand Down Expand Up @@ -932,24 +932,24 @@
estimates done with Halton sequences. Compare the following estimates of
the integral of x between 0 and 1, which is exactly 0.5:

>>> np.mean(halton(100, cranley_patterson=False))
>>> float(np.mean(halton(100, cranley_patterson=False)))
0.489921875
>>> I = [np.mean(halton(100)) for i in range(1000)]
>>> np.mean(I), np.var(I) < 0.00004
>>> float(np.mean(I)), bool(np.var(I) < 0.00004)
(0.500, True)

Now the integral of x**2 between 0 and 1, which is exactly 1/3:

>>> np.mean(halton(100, cranley_patterson=False)**2)
>>> float(np.mean(halton(100, cranley_patterson=False)**2))
0.3222149658203125
>>> I = [np.mean(halton(100)**2) for i in range(1000)]
>>> np.mean(I), np.var(I) < 0.00004
>>> float(np.mean(I)), bool(np.var(I) < 0.00004)
(0.333, True)

>>> x = halton(1500)
>>> np.mean(x) # estimate of the integral of x between 0 and 1
>>> float(np.mean(x)) # estimate of the integral of x between 0 and 1
0.50
>>> np.mean(x**2) # estimate of the integral of x**2 between 0 and 1
>>> float(np.mean(x**2)) # estimate of the integral of x**2 between 0 and 1
0.33
"""
actual_dim = 1 if dim is None else dim
Expand Down
Loading
Loading