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
17 changes: 17 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
paths:
.github/workflows/*.yml:
ignore:
# actionlint's bundled metadata for actions/create-github-app-token@v3
# predates the "client-id" input added upstream in v3.1.0 (2026-04-11),
# so it still reports app-id as required and client-id as unknown.
# Remove once actionlint ships a release newer than v1.7.12 with
# updated action metadata for this action.
- 'missing input "app-id" which is required by action "actions/create-github-app-token@v3"'
- 'input "client-id" is not defined in action "actions/create-github-app-token@v3"'
# these are GitHub-hosted but for some reason actionlint couldn't find them
self-hosted-runner:
labels:
- ubuntu-latest-4core
- ubuntu-latest-8core
- blacksmith-4vcpu-ubuntu-2404
- blacksmith-8vcpu-ubuntu-2404
46 changes: 25 additions & 21 deletions .github/workflows/bot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
---
name: bot-auto-merge

# Runs on pull_request_target (not pull_request) so it has access to secrets even for
# PRs opened by Dependabot, which run with a read-only token by default. This is safe
# here because we never check out or execute any code from the PR -- we only call the
# GitHub API by PR URL to approve it and enable auto-merge.
on:
workflow_run:
types: [completed]
workflows: ["tox-pytest"]
pull_request_target:
types: [opened, reopened, synchronize]

permissions: {}

jobs:
bot-auto-merge:
name: Auto-merge passing bot PRs
runs-on: ubuntu-latest
# Gate on who *opened* the PR, not github.actor -- for a `synchronize` event,
# github.actor is whoever pushed the latest commit (e.g. pre-commit-ci fixing up
# a human-authored PR), which must not by itself trigger auto-merge.
if: >-
github.event.pull_request.user.login == 'dependabot[bot]' ||
github.event.pull_request.user.login == 'pre-commit-ci[bot]'
steps:
- name: Impersonate auto merge PR bot
uses: tibdex/github-app-token@v1
uses: actions/create-github-app-token@v3
id: generate-token
with:
app_id: ${{ secrets.BOT_AUTO_MERGE_PRS_APP_ID }}
private_key: ${{ secrets.BOT_AUTO_MERGE_PRS_APP_KEY }}
- name: Auto-merge passing dependabot PRs
if: ${{ github.event.workflow_run.conclusion == 'success' }}
uses: ridedott/merge-me-action@v2
with:
# For clarity only. dependabot is default login.
GITHUB_LOGIN: dependabot
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
ENABLED_FOR_MANUAL_CHANGES: "true"
- name: Auto-merge passing pre-commit-ci PRs
if: ${{ github.event.workflow_run.conclusion == 'success' }}
uses: ridedott/merge-me-action@v2
with:
GITHUB_LOGIN: pre-commit-ci
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
ENABLED_FOR_MANUAL_CHANGES: "true"
client-id: ${{ secrets.BOT_AUTO_MERGE_PRS_CLIENT_ID }}
private-key: ${{ secrets.BOT_AUTO_MERGE_PRS_APP_KEY }}

- name: Approve and enable auto-merge
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr review --approve "$PR_URL"
gh pr merge --merge --auto "$PR_URL"
8 changes: 7 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@ repos:
args: ["--maxkb=800"]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.22
rev: v0.16.3
hooks:
- id: ruff-check
args: [--fix]
types_or: [python, pyi]
- id: ruff-format
types_or: [python, pyi]

# Check Github Actions
- repo: https://github.com/rhysd/actionlint
rev: v1.7.12
hooks:
- id: actionlint
4 changes: 4 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# NOTE (2026-08-15): Jupyter notebooks are synced from Kaggle, which will
# overwrite any lint fixes we make without running our tooling, so there's no
# point linting them here. See .pre-commit-config.yaml for the same rationale.
extend-exclude = ["*.ipynb"]
Empty file modified scripts/export_marimo_notebooks.py
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions scripts/sync_kaggle_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def main() -> None:

package_names = sorted(
str(name)
for name in deps_table.keys()
for name in deps_table
if name not in exempt_from_sync and name != "python"
)
probe_result = probe_kaggle_runtime_dependencies(
Expand Down Expand Up @@ -153,7 +153,7 @@ def apply_kaggle_pins_to_pixi_deps(
kaggle_pins = probe_result["pins"]
kaggle_pins["python"] = f"=={probe_result['python_version']}"

for dep_name in deps_table.keys():
for dep_name in deps_table:
if dep_name in exempt_from_sync:
continue

Expand Down
18 changes: 7 additions & 11 deletions wasm/marimo/plant-explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ def _(mo, selection):
]
)
)
return


@app.cell(hide_code=True)
def _(mo, this_plant):
mo.md(f"# {this_plant.name} (EIA id={this_plant.plant_id_eia})")
return


@app.cell
Expand All @@ -37,12 +35,12 @@ def _():
with mo.status.progress_bar(
total=1, title="Loading subroutines", remove_on_exit=True
) as do_imports:
import itertools
import functools
import itertools

import altair as alt
import pandas as pd
import pyarrow as pa
import altair as alt

do_imports.update(subtitle="Done!")
return alt, functools, itertools, mo, pd
Expand Down Expand Up @@ -239,9 +237,10 @@ def reset_params(**kwargs):

@app.cell
def _(Options, mo, query_params, reset_params):
from pydantic import BaseModel, Field, computed_field
from functools import cached_property

from pydantic import BaseModel, Field, computed_field

class Selection(BaseModel):
"""Store/represent the user's current plant selection.

Expand Down Expand Up @@ -573,7 +572,6 @@ def _(alt, mo, this_plant, this_plant__monthly_generation_fuel_combined):
f"via {table_preview_href('out_eia923__monthly_generation_fuel_combined')}"
)
)
return


@app.cell
Expand Down Expand Up @@ -625,7 +623,6 @@ def _(
mo.output.append(
mo.md(f"via {table_preview_href('out_eia923__monthly_generation')}")
)
return


@app.cell
Expand All @@ -647,7 +644,7 @@ def _(mo, this_plant__generators):
only_option = set()
filter_options = {}
filter_defaults = {}
for k, v in filter_counts.to_dict().items():
for k in filter_counts.to_dict():
available = this_plant__generators[k].value_counts(dropna=False)
available = available.loc[available > 0].index
if available.shape[0] == 1:
Expand All @@ -666,15 +663,15 @@ def _(mo, this_plant__generators):
max_input = max(max(v) for v in option_lengths.values())
columns = math.ceil(80 / max_column)

for k in filter_options:
for k, options in filter_options.items():
filters[k] = mo.Html(
f"""<div data-testid="genselect-{k}" style="display: flex; gap: 0.5rem; {"color: #bbbbbb" if k in only_option else ""}">
<label style="flex: {max_label / max_input} 1 0%; text-align: end;">{k}</label>
<div style="flex: 1 1 0%;">{{multiselect}}</div>
</div>"""
).batch(
multiselect=mo.ui.multiselect(
options=filter_options[k],
options=options,
value=filter_defaults[k],
# label=k,
)
Expand Down Expand Up @@ -799,7 +796,6 @@ def _(
)
)
mo.output.append(mo.md(f"via {table_preview_href('out_eia__yearly_generators')}"))
return


if __name__ == "__main__":
Expand Down
15 changes: 3 additions & 12 deletions wasm/marimo/rate-base-sales-explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ def header(mo):

These tables provide clues about how rates have changed over time, the primary drivers of that change and who bears the impact of that change. It’s important to note that, while informative, the data provide an incomplete and imperfect picture. The rate making process is complex and this dashboard only gives us a snapshot. Nonetheless, we think this information is useful and we encourage you to explore. For more background materials, see the Additional Resources at the bottom of the page.
""")
return


@app.cell
Expand Down Expand Up @@ -222,7 +221,6 @@ def add_columns(
pd.StringDtype()
)
)
return


@app.cell
Expand Down Expand Up @@ -524,7 +522,6 @@ def sidebar(mark_type_selector, mo, selection):
),
]
)
return


@app.cell
Expand All @@ -535,7 +532,6 @@ def no_utilities_1_stop(mo, selection):
"## 🛑 **Choose a utilities the sidebar.** ⬅️\nWe really want to show you some pretty graphs, but you have to select utilities to show. If you happen to choose utilities in the 'To compare' section, you still need to choose utilities above that."
),
)
return


@app.cell
Expand All @@ -547,7 +543,7 @@ def filter_dfs(
):
from typing import TypeVar

PandasDataFrame = TypeVar("pandas.core.frame.DataFrame")
PandasDataFrame = TypeVar("PandasDataFrame")

class GraphInput(BaseModel):
filtered_rate_base: PandasDataFrame
Expand All @@ -562,7 +558,7 @@ class GraphInputs(BaseModel):

graph_inputs = {"opt_1": {}, "opt_2": {}}

for opt_n in graph_inputs.keys():
for opt_n in graph_inputs:
utility_selection = selection.model_dump().get(
f"utilities_{opt_n.removeprefix('opt_')}"
)
Expand Down Expand Up @@ -614,7 +610,7 @@ class GraphInputs(BaseModel):
utility_selection_title_part = f"{util_len} Utilities"
utils_subtitle = " & ".join(utility_selection)
else:
utility_selection_title_part = f"{list(utility_selection)[0]}"
utility_selection_title_part = f"{next(iter(utility_selection))}"
filtered_rate_base = out_ferc1__yearly_rate_base[rate_mask]
filtered_sales = core_eia861__yearly_sales[sales_mask]
graph_inputs[opt_n] = GraphInput(
Expand Down Expand Up @@ -820,7 +816,6 @@ def chart_ferc1(ColumToChart, graph_inputs, make_comparison_charts, mo):
]

make_comparison_charts(cols_to_chart_ferc1, graph_inputs, "filtered_rate_base")
return


@app.cell
Expand Down Expand Up @@ -895,15 +890,13 @@ def chart_eia861(ColumToChart, graph_inputs, make_comparison_charts, mo):
]

make_comparison_charts(cols_to_chart_eia861, graph_inputs, "filtered_sales")
return


@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
## 📚 Additional Resources
""")
return


@app.cell
Expand Down Expand Up @@ -979,15 +972,13 @@ def materials_accordion(mo):
* <a href='https://www.raponline.org/wp-content/uploads/2023/10/rap-improving-utility-performance-incentives-in-the-united-states-2023-october.pdf' target='_blank'>RAP's Improving Utility Performance Incentives in the United States</a>"""),
}
)
return


@app.cell(hide_code=True)
def contact_us(mo):
mo.md(r"""
If you see anything odd in the data, find a bug or just have a question, feel free to reach out to us by emailing us at hello@catalyst.coop or write up a <a href="https://github.com/catalyst-cooperative/pudl/issues/new?template=bug_report.md" target="_blank">github issue</a>. Heck, if you just found this helpful, let us know! As an open-source project we love to hear about your energy data needs.
""")
return


if __name__ == "__main__":
Expand Down
11 changes: 0 additions & 11 deletions wasm/marimo/utility-explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ def _(mo):
'Explore attributes of any utility that reports to <a href="https://docs.catalyst.coop/pudl/data_sources/eia861.html" target="_blank">EIA-861</a>. Select a state and specific utility to explore its attributes and its electricity sources, sales, and reliability over time.'
)
)
return


@app.cell
Expand Down Expand Up @@ -49,15 +48,13 @@ def _(mo, selection):
]
)
)
return


@app.cell
def _(mo, selection):
mo.md(f"""
#**{selection.util_name}**
""")
return


@app.cell
Expand Down Expand Up @@ -662,7 +659,6 @@ def _(fips_set, mo, selection, st_chart, stats_table, table_preview_href):
]
)
util_stats
return


@app.cell
Expand Down Expand Up @@ -780,7 +776,6 @@ def _(mo, selection, status_df, table_preview_href):
mo.md(f"via {table_preview_href('out_eia__yearly_generators')}"),
]
)
return


@app.cell
Expand Down Expand Up @@ -970,7 +965,6 @@ def _(fuel_chart, fuel_long, mo, selection, source_chart, table_preview_href):
]
)
electricity_source
return


@app.cell
Expand Down Expand Up @@ -998,7 +992,6 @@ def _(util_mfrc_df):
fuel_cost_df["fuel_cost_received"] = (
fuel_cost_df["fuel_cost_per_mmbtu"] * fuel_cost_df["fuel_received_mmbtu"]
)
return


@app.cell
Expand Down Expand Up @@ -1073,7 +1066,6 @@ def _(fuel_cost_chart, mo, table_preview_href):
]
)
fuel_cost
return


@app.cell
Expand Down Expand Up @@ -1380,7 +1372,6 @@ def _(
)

customer_facing
return


@app.cell
Expand Down Expand Up @@ -1435,15 +1426,13 @@ def _(mo, summer_v_winter_demand_chart, table_preview_href):
)

demand
return


@app.cell(hide_code=True)
def _(mo):
mo.md(r"""
If you see anything odd in the data, find a bug or just have a question, feel free to reach out to us by emailing us at hello@catalyst.coop or write up a <a href="https://github.com/catalyst-cooperative/pudl/issues/new?template=bug_report.md" target="_blank">github issue</a>. Heck, if you just found this helpful, let us know! As an open-source project we love to hear about your energy data needs.
""")
return


if __name__ == "__main__":
Expand Down
Loading