From 8b61c03d3c5d9ef8146532374a5b598d9b4c7fe6 Mon Sep 17 00:00:00 2001 From: Mannu Date: Thu, 7 May 2026 02:14:45 +0530 Subject: [PATCH] [S0-T02] Set up packages/engine with Poetry, Ruff, mypy strict, pytest --- packages/engine/README.md | 37 ++++++++++ packages/engine/pyproject.toml | 68 +++++++++++++++++++ .../engine/src/remodel_engine/__init__.py | 3 + packages/engine/tests/.gitkeep | 0 .../.gitkeep => tests/__init__.py} | 0 packages/engine/tests/test_version.py | 11 +++ 6 files changed, 119 insertions(+) create mode 100644 packages/engine/README.md create mode 100644 packages/engine/pyproject.toml create mode 100644 packages/engine/src/remodel_engine/__init__.py delete mode 100644 packages/engine/tests/.gitkeep rename packages/engine/{src/remodel_engine/.gitkeep => tests/__init__.py} (100%) create mode 100644 packages/engine/tests/test_version.py diff --git a/packages/engine/README.md b/packages/engine/README.md new file mode 100644 index 0000000..9806577 --- /dev/null +++ b/packages/engine/README.md @@ -0,0 +1,37 @@ +# remodel-engine + +UI-agnostic Python calculation library for hybrid RE (Solar + Wind + BESS) project finance. + +## Setup + +```bash +poetry install +``` + +## Common commands + +```bash +poetry run pytest # run tests with coverage +poetry run ruff check . # lint +poetry run mypy src/ # type-check +poetry run remodel --help # CLI (after implementation) +``` + +## Package layout + +``` +src/remodel_engine/ +├── schemas/ Pydantic models (single source of truth) +├── catalog/ Default values, CostItem catalog, profiles +├── generation/ solar.py, wind.py, bess_state.py +├── dispatch/ hybrid_rtc.py, mcp_settlement.py +├── commercial/ ppa.py, dsm.py, charges.py, losses.py +├── capex/ cost_items.py, phasing.py, idc.py +├── financial/ pnl.py, cfs.py, bs.py, depreciation.py, tax.py +├── debt/ sizing.py, sculpting.py, schedule.py, compliance.py +├── irr/ metrics.py +├── solver/ tariff.py +├── scenarios/ runner.py, sweep.py +├── io/ parquet_io.py, excel_export.py +└── cli.py +``` diff --git a/packages/engine/pyproject.toml b/packages/engine/pyproject.toml new file mode 100644 index 0000000..c974318 --- /dev/null +++ b/packages/engine/pyproject.toml @@ -0,0 +1,68 @@ +[tool.poetry] +name = "remodel-engine" +version = "0.1.0" +description = "RE project finance calculation engine for hybrid solar/wind/BESS projects" +authors = ["Manohar "] +readme = "README.md" +packages = [{include = "remodel_engine", from = "src"}] + +[tool.poetry.dependencies] +python = "^3.12" +pydantic = "^2.7" +numpy = "^2.0" +pandas = "^2.2" +scipy = ">=1.13" +numpy-financial = "^1.0" +pyarrow = ">=19.0" +openpyxl = "^3.1" +typer = "^0.12" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.4" +mypy = "^1.10" +pytest = "^8.2" +pytest-cov = "^5.0" +pre-commit = "^3.7" +pandas-stubs = "^2.2" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +target-version = "py312" +line-length = 100 +src = ["src", "tests"] + +[tool.ruff.lint] +select = ["E", "F", "W", "I", "UP", "B", "SIM", "ANN", "RUF"] +ignore = ["ANN101", "ANN102", "ANN401"] + +[tool.ruff.lint.per-file-ignores] +"tests/**" = ["ANN"] + +[tool.mypy] +python_version = "3.12" +strict = true +warn_return_any = true +warn_unused_configs = true +disallow_untyped_defs = true +disallow_any_generics = true +check_untyped_defs = true +no_implicit_reexport = true +files = ["src"] + +[[tool.mypy.overrides]] +module = ["scipy.*", "numpy_financial.*"] +ignore_missing_imports = true + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "--cov=remodel_engine --cov-report=term-missing --cov-fail-under=85" + +[tool.coverage.run] +source = ["remodel_engine"] +branch = true + +[tool.coverage.report] +exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"] diff --git a/packages/engine/src/remodel_engine/__init__.py b/packages/engine/src/remodel_engine/__init__.py new file mode 100644 index 0000000..92cd1e1 --- /dev/null +++ b/packages/engine/src/remodel_engine/__init__.py @@ -0,0 +1,3 @@ +"""REmodel calculation engine for hybrid RE project finance.""" + +__version__ = "0.1.0" diff --git a/packages/engine/tests/.gitkeep b/packages/engine/tests/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/packages/engine/src/remodel_engine/.gitkeep b/packages/engine/tests/__init__.py similarity index 100% rename from packages/engine/src/remodel_engine/.gitkeep rename to packages/engine/tests/__init__.py diff --git a/packages/engine/tests/test_version.py b/packages/engine/tests/test_version.py new file mode 100644 index 0000000..5424952 --- /dev/null +++ b/packages/engine/tests/test_version.py @@ -0,0 +1,11 @@ +from remodel_engine import __version__ + + +def test_version_is_string() -> None: + assert isinstance(__version__, str) + + +def test_version_format() -> None: + parts = __version__.split(".") + assert len(parts) == 3 + assert all(p.isdigit() for p in parts)