Skip to content
Merged
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
61 changes: 36 additions & 25 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[build-system]
requires = ["setuptools>=64", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"
requires = ["hatchling>=1.27", "hatch-vcs>=0.4"]
build-backend = "hatchling.build"

[project]
name = "rmi.dispatch"
Expand All @@ -20,44 +20,50 @@ classifiers = [
]
requires-python = ">=3.12,<3.15"
dependencies = [
"bottleneck >= 1.6.0,< 1.6.1",
"numba >= 0.65.0,< 0.66",
"numexpr >= 2.8, < 2.14.2",
"numpy >= 1.18.5,< 3",
"pandas >= 1.4,< 3.0",
"pandera >= 0.20.1, < 0.31",
"pyarrow>=7, <25",
"bottleneck>=1.6.0,<2",
"numba>=0.65.0,<0.66",
"numexpr>=2.8,<3",
"numpy>=1.18.5,<3",
"pandas>= 1.4,<4",
"pandera>=0.20.1,<0.31",
"pyarrow>=7,<25",
]

[project.optional-dependencies]
dev = [
"coverage>=5.3,<7.15", # Lets us track what code is being tested
"pytest>=6.2,<9.1", # test framework
"coverage>=5.3,<8", # Lets us track what code is being tested
"pytest>=6.2,<10", # test framework
"datazip",
]
doc = [
"doc8>=2.0.0,<2.1",
"doc8>=2.0.0,<3",
"furo>=2025.12.19",
"rstcheck[sphinx,toml]>=5.0,<6.3",
"sphinx>=4,!=5.1.0,<9.1.1",
"sphinx-autoapi>=1.8,<3.9",
"sphinx-issues>=1.2,<6.1",
"sphinx-autodoc-typehints>1.19,<3.11.0",
"sphinxcontrib-mermaid>0.7,<2.1.0",
"rstcheck[sphinx,toml]>=5.0,<7",
"sphinx>=4,!=5.1.0,<10",
"sphinx-autoapi>=1.8,<4",
"sphinx-issues>=1.2,<7",
"sphinx-autodoc-typehints>1.19,<4",
"sphinxcontrib-mermaid>0.7,<3",
]
qa = []
tooling = []
tests = []
viz = [
"plotly>5.10,<6.8",
"plotly>5.10,<7",
"kaleido>0.2,<2",
]

[tool.setuptools.dynamic]
version = {attr = "dispatch._version.__version__"}
[tool.hatch.version]
source = "vcs"

[tool.setuptools_scm]
version_file = "src/dispatch/_version.py"
[tool.hatch.build.hooks.vcs]
version-file = "src/dispatch/_version.py"

[tool.hatch.build.targets.wheel]
packages = ["src/dispatch"]

[tool.hatch.build.targets.sdist]
include = ["src/dispatch", "README.rst", "LICENSE.txt"]

[tool.uv]
constraint-dependencies = ["kaleido!=0.2.1.post1"]
Expand Down Expand Up @@ -176,7 +182,7 @@ pydocstyle.convention = "google"
"tests/engine_test.py" = ["E501"]

[tool.tox]
env_list = [ "linters", "docs", "prep", "3.13", "3.14", "coverage" ]
env_list = [ "linters", "docs", "prep", "3.13", "3.14", "3.14-pandas2", "coverage" ]

[tool.tox.env.prep]
skip_install = true
Expand All @@ -188,11 +194,16 @@ allowlist_externals = [ "bash", "ruff", "prek" ]
runner = "uv-venv-runner"
extras = [ "dev", "viz" ]
commands = [
[ "python", "-c", 'import importlib.metadata as m; [print(f"{d.name}=={d.version}") for d in sorted(m.distributions(), key=lambda x: (x.name or "").lower())]' ],
[ "coverage", "run", "--source={envsitepackagesdir}/dispatch", "-m", "pytest", "--doctest-modules", "{envsitepackagesdir}/dispatch", "tests" ],
]

[tool.tox.env."3.14-pandas2"]
description = "Run tests on Python 3.14 against the pandas <3 line to verify back-compat."
deps = [ "pandas<3.0" ]

[tool.tox.env.coverage]
depends = [ "3.13", "3.14" ]
depends = [ "3.13", "3.14", "3.14-pandas2" ]
skip_install = true
deps = "coverage"
commands = [
Expand Down
31 changes: 23 additions & 8 deletions src/dispatch/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
import numpy as np
import pandas as pd

from dispatch import __version__
from dispatch.constants import COLOR_MAP, MTDF, PLOT_MAP
from dispatch.engine import dispatch_engine, dispatch_engine_auto
from dispatch.helpers import dispatch_key, zero_profiles_outside_operating_dates
from dispatch.metadata import LOAD_PROFILE_SCHEMA, Validator

try:
import plotly.express as px
from plotly.graph_objects import Figure
Expand All @@ -21,6 +27,12 @@
Figure = Any
PLOTLY_INSTALLED = False

# pandas 3.0 removed the ``dropna`` argument from ``DataFrame.stack`` because the
# new implementation never introduces NA rows. To keep one code path that works
# under both pandas <3 (old default stack behavior) and pandas >=3 (new default),
# we branch on the major version.
_PANDAS_MAJOR_VERSION = int(pd.__version__.split(".", 1)[0])

__all__ = ["DispatchModel"]

try:
Expand All @@ -41,12 +53,6 @@ def to_file(self, *args, **kwargs) -> None:
raise NotImplementedError("datazip is required for this functionality")


from dispatch import __version__
from dispatch.constants import COLOR_MAP, MTDF, PLOT_MAP
from dispatch.engine import dispatch_engine, dispatch_engine_auto
from dispatch.helpers import dispatch_key, zero_profiles_outside_operating_dates
from dispatch.metadata import LOAD_PROFILE_SCHEMA, Validator

LOGGER = logging.getLogger(__name__)


Expand Down Expand Up @@ -991,9 +997,18 @@ def strict_grouper(
dropna = False
if col_name is None:
return out
if _PANDAS_MAJOR_VERSION >= 3:
# pandas >=3 dropped the ``dropna`` kwarg and never introduces NA
# rows in stack. Replicate the legacy ``dropna=True`` behavior by
# dropping after the fact; ``dropna=False`` is already the new
# default so it needs no extra work.
stacked = out.stack(level=out.columns.names)
if dropna:
stacked = stacked.dropna()
else:
stacked = out.stack(level=out.columns.names, dropna=dropna)
return (
out.stack(level=out.columns.names, dropna=dropna)
.reorder_levels(order=[*out.columns.names, "datetime"])
stacked.reorder_levels(order=[*out.columns.names, "datetime"])
.to_frame(name=col_name)
.sort_index()
)
Expand Down
6 changes: 3 additions & 3 deletions tests/helper_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,19 @@ def zero_profiles_outside_operating_dates_slow(
dt_idx = pd.concat(
[profiles.index.to_series()] * profiles.shape[1],
axis=1,
).to_numpy(dtype=np.datetime64)
).to_numpy(dtype="datetime64[ns]")
return pd.DataFrame(
(
(
dt_idx
<= retirement_date.fillna(profiles.index.max()).to_numpy(
dtype=np.datetime64
dtype="datetime64[ns]"
)
)
& (
dt_idx
>= operating_date.fillna(profiles.index.min()).to_numpy(
dtype=np.datetime64
dtype="datetime64[ns]"
)
)
)
Expand Down
Loading