diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..956cf2d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + pre-commit: + name: Checks via pre-commit + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v7 + + - name: Install uv + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 + with: + enable-cache: true + + - name: Install dependencies + run: uv sync --locked + + - name: Run pre-commit + run: uv run pre-commit run --all-files diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c6af73..cef9089 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: - id: end-of-file-fixer - id: check-added-large-files -# Run tests, including doctests +# Project checks - repo: local hooks: - id: copyright-header @@ -22,6 +22,13 @@ repos: types: [python] always_run: true pass_filenames: false + - id: mypy + name: mypy + entry: uv run mypy dcaf/ + language: system + types: [python] + always_run: true + pass_filenames: false # Linting and formatting - repo: https://github.com/astral-sh/ruff-pre-commit @@ -29,4 +36,3 @@ repos: hooks: - id: ruff-check - id: ruff-format - args: [ --check ] diff --git a/LICENSE b/LICENSE index 94554cf..a19484d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 Battelle Energy Alliance, LLC +Copyright (c) 2026 Battelle Energy Alliance, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/dcaf/finance/opex.py b/dcaf/finance/opex.py index 9e489ed..4534271 100644 --- a/dcaf/finance/opex.py +++ b/dcaf/finance/opex.py @@ -10,7 +10,13 @@ from datetime import date from dcaf.finance.escalation import EscalationPolicy -from dcaf.shared.types import DayCountConvention, Period, ProFormaCategory, TaxTreatment, TimingConvention +from dcaf.shared.types import ( + DayCountConvention, + Period, + ProFormaCategory, + TaxTreatment, + TimingConvention, +) from dcaf.shared.validation import validate_finite from dcaf.streams.cashflows import CashFlowStream diff --git a/dcaf/project/contracts.py b/dcaf/project/contracts.py index f3a96fc..1466bf8 100644 --- a/dcaf/project/contracts.py +++ b/dcaf/project/contracts.py @@ -1,3 +1,5 @@ +# © 2026 Battelle Energy Alliance, LLC +# ALL RIGHTS RESERVED """Generation-linked contract terms for project-level revenue policies.""" from __future__ import annotations diff --git a/dcaf/project/policies.py b/dcaf/project/policies.py index a17a506..0d59132 100644 --- a/dcaf/project/policies.py +++ b/dcaf/project/policies.py @@ -1,3 +1,5 @@ +# © 2026 Battelle Energy Alliance, LLC +# ALL RIGHTS RESERVED """Public protocol for generation-linked project cash-flow policies.""" from __future__ import annotations diff --git a/tests/unit/test_cashflow_stream.py b/tests/unit/test_cashflow_stream.py index 29af78b..ce7d71a 100644 --- a/tests/unit/test_cashflow_stream.py +++ b/tests/unit/test_cashflow_stream.py @@ -134,8 +134,7 @@ def test_from_recurring_annual_escalation_is_date_based(): ) expected_dates = [date(2026, 4, 4), date(2026, 5, 4), date(2026, 6, 4)] expected_amounts = [ - -200.0 * _annual_factor(date(2026, 3, 5), flow_date, 0.1) - for flow_date in expected_dates + -200.0 * _annual_factor(date(2026, 3, 5), flow_date, 0.1) for flow_date in expected_dates ] for i, flow in enumerate(cf_stream.entries): assert flow.date == expected_dates[i] diff --git a/tests/unit/test_generation.py b/tests/unit/test_generation.py index ce19862..3284a20 100644 --- a/tests/unit/test_generation.py +++ b/tests/unit/test_generation.py @@ -183,7 +183,7 @@ def test_from_capacity_rejects_capacity_factor_outside_unit_interval(capacity_fa periods=1, ) - + def test_from_capacity_supports_timing_conventions(): begin = GenerationStream.from_capacity(1.0, 1.0, date(2030, 1, 1), 1, timing="begin") middle = GenerationStream.from_capacity(1.0, 1.0, date(2030, 1, 1), 1, timing="middle") diff --git a/tests/unit/test_generation_linked_policies.py b/tests/unit/test_generation_linked_policies.py index 4c3ac23..fea4fc9 100644 --- a/tests/unit/test_generation_linked_policies.py +++ b/tests/unit/test_generation_linked_policies.py @@ -1,3 +1,5 @@ +# © 2026 Battelle Energy Alliance, LLC +# ALL RIGHTS RESERVED from datetime import date from math import inf, nan from typing import cast @@ -279,7 +281,9 @@ def test_generation_revenue_callable_receives_whole_project_settlement_context() events: list[GenerationSettlementEvent] = [] def price(event: GenerationSettlementEvent) -> float: - events.append(event) # creates an external artifact that the `price` function was called for every generation event + events.append( + event + ) # creates an external artifact that the `price` function was called for every generation event return prices[event.date] analysis = (