Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
474e7d5
Generate repo contents with `python-template`
alexdewar Jan 23, 2026
d2aabec
Remove unneeded `pip-tools` dep and generate `uv.lock`
alexdewar Jan 23, 2026
32a069c
Bump minimum Python version to 3.14
alexdewar Jan 23, 2026
412c354
Remove entrypoint to Python package
alexdewar Jan 23, 2026
e0ce615
Add functions for finding and running `muse2`
alexdewar Jan 23, 2026
7298513
run_muse2: Set MUSE2_USE_DEFAULT_SETTINGS env var
alexdewar Jan 23, 2026
4c56ed5
pre-commit: Add `nbstripout` hook
alexdewar Jan 23, 2026
c6fce4f
Add some helper functions for notebooks
alexdewar Jan 23, 2026
7d09eb8
pre-commit: Drop `taplo-lint` hook
alexdewar Jan 23, 2026
b457cc1
Add notebooks from MUSE2 repo, using helpers
alexdewar Jan 23, 2026
1e8e3c0
CI: Use lychee cf. Linkspector for checking links
alexdewar Jan 26, 2026
4d7732e
Update README.md
alexdewar Jan 26, 2026
d612d22
MyProject => muse2_data_analysis
alexdewar Jan 26, 2026
273c436
README.md: Missing colon for link
alexdewar Jan 26, 2026
d976d07
Fix: Include existing env vars when invoking `muse2`
alexdewar Jan 26, 2026
304c802
Use `check=True` for `sp.run`
alexdewar Jan 26, 2026
9400210
Remove unnecessary `sys.path.append` from notebooks
alexdewar Jan 26, 2026
a717b9d
Add instructions for activating venv on Windows
alexdewar Jan 27, 2026
3014850
Rename vars in notebooks
alexdewar Jan 27, 2026
3fc289a
VS Code: Recommend Jupyter extension
alexdewar Jan 27, 2026
793fc2a
Provide instructions on viewing notebooks
alexdewar Jan 27, 2026
cb644a8
Add instructions on adding to `PATH` or setting env vars
alexdewar Jan 27, 2026
b05da63
Apply Copilot fixes for wording
alexdewar Jan 28, 2026
9618677
Remove unused `mkdocs.yml` file
alexdewar Jan 28, 2026
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
Empty file added .codespell_ignore.txt
Empty file.
21 changes: 21 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
root = true

[*]
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4
max_line_length = 88

[*.md]
indent_size = 2

[*.yaml]
indent_size = 2

[*.yml]
indent_size = 2

[Makefile]
indent_style = tab
26 changes: 26 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Description

_Please include a summary of the change and which issue is fixed (if any). Please also
include relevant motivation and context. List any dependencies that are required for
this change._

Close # (issue)

## Type of change

- [ ] Documentation (non-breaking change that adds or improves the documentation)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Optimization (non-breaking, back-end change that speeds up the code)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] Breaking change (whatever its nature)

## Key checklist

- [ ] All tests pass (eg. `python -m pytest`)
- [ ] Pre-commit hooks run successfully (eg. `pre-commit run --all-files`)

## Further checks

- [ ] Code is commented, particularly in hard-to-understand areas
- [ ] Tests added or an issue has been opened to tackle that in the future.
(Indicate issue here: # (issue))
15 changes: 15 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: uv
directory: /
schedule:
interval: weekly
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
23 changes: 23 additions & 0 deletions .github/workflows/auto-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Dependabot and Pre-commit auto-merge

on:
pull_request:

permissions:
contents: write
pull-requests: write # Needed if in a private repository

jobs:
auto-merge:
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'pre-commit-ci[bot]' }}
steps:
- name: Enable auto-merge for bot PRs
run: |
gh pr review --approve "$PR_URL"
gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
# GitHub provides this variable in the CI env. You don't
# need to add anything to the secrets vault.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17 changes: 17 additions & 0 deletions .github/workflows/check-links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Check links in Markdown files
on:
schedule:
- cron: 0 0 * * 1 # midnight every Monday
push:
branches: [main]
pull_request:
workflow_dispatch:

jobs:
check-links:
name: Lychee link checker
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- id: lychee
uses: lycheeverse/lychee-action@v2
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Test and build

on:
push:
branches: [main]
pull_request:
workflow_dispatch:
workflow_call:

jobs:
test:
runs-on: ${{matrix.os}}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
- macos-latest
python-version: ['3.14']

steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
with:
enable-cache: true
prune-cache: false
activate-environment: true
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync

- name: Run mypy
run: mypy .

- name: Run tests
run: pytest
Comment on lines +31 to +38
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI workflow runs mypy and pytest but does not run ruff checks, even though ruff is configured in the pre-commit hooks and pyproject.toml. Consider adding a step to run ruff linting in the CI workflow to ensure code style is checked: 'run: ruff check .' This would catch style issues before merge that might otherwise only be caught by pre-commit hooks.

Copilot uses AI. Check for mistakes.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ cython_debug/
.abstra/

# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/

Expand Down
4 changes: 4 additions & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Disable checks here
MD013: false
MD007:
indent: 4
49 changes: 49 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-merge-conflict
- id: debug-statements
- id: trailing-whitespace
- id: end-of-file-fixer
- id: pretty-format-json
args: [--autofix, --indent, '4', --no-sort]
exclude: \.ipynb$
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.14.0
hooks:
- id: pretty-format-yaml
args: [--autofix, --indent, '2', --offset, '2']
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.33.1
hooks:
- id: check-dependabot
- id: check-github-actions
- id: check-github-workflows
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.0
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ruff-pre-commit version v0.12.0 appears to be outdated compared to the ruff version specified in pyproject.toml (0.14.13). Consider updating this to a more recent version that matches or is compatible with the ruff version used in the project to ensure consistent linting behavior.

Suggested change
rev: v0.12.0
rev: v0.14.13

Copilot uses AI. Check for mistakes.
hooks:
- id: ruff-check
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/kynan/nbstripout
rev: 0.8.1
hooks:
- id: nbstripout
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.16.1
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mypy pre-commit hook is using version v1.16.1, but pyproject.toml specifies mypy>=1.19.1 (which doesn't exist). Even accounting for the version issue in pyproject.toml, there should be consistency between the pre-commit hook version and the development dependency version to avoid different behavior in different environments.

Suggested change
rev: v1.16.1
rev: v1.10.0

Copilot uses AI. Check for mistakes.
hooks:
- id: mypy
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.45.0
hooks:
- id: markdownlint-fix
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell
args: [-I, .codespell_ignore.txt]
- repo: https://github.com/ComPWA/taplo-pre-commit
rev: v0.9.3
hooks:
- id: taplo-format # Format TOML files
4 changes: 4 additions & 0 deletions .taplo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[formatting]
compact_inline_tables = true
column_width = 88
indent_string = " "
10 changes: 10 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"recommendations": [
"ms-python.python",
"ms-python.mypy-type-checker",
"ms-toolsai.jupyter",
"editorconfig.editorconfig",
"davidanson.vscode-markdownlint",
"charliermarsh.ruff"
]
}
11 changes: 11 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "charliermarsh.ruff"
},
"editor.rulers": [
88
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,89 @@
# MUSE2 data analysis

> :warning: **Note that this repository is currently a work in progress.** :warning:

This repository contains Python scripts and Jupyter notebooks for analysing and
visualising [MUSE2] data files.

We recommend using [uv] for installing dependencies and managing your virtual
environment.

## Usage

To get started:

1. [Download and install uv] following the instructions for your OS.

1. Install the package and dependencies and set up the virtual environment:

```bash
uv sync

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to run uv python install 3.14 before I could do this (No interpreter found for Python >=3.14 in managed installations, search path, or registry)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, interesting. I'm not seeing the same thing though... It downloads Python for me if it's not present. What version of uv do you have, out of interest?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.8.17 - I guess that's pre-Python 3.14

Maybe just tell people to update uv first

```

1. Activate the virtual environment, or just preface your commands with `uv run` to use
the virtual environment (see [uv docs] for more info).

To activate on Linux/macOS:

```bash
source .venv/bin/activate
<command>
```

To activate on Windows:

```powershell
.venv\Scripts\activate
```

Or run the command directly:

```bash
uv run <command>
```

1. Make sure the Python code can find your MUSE2 installation. (If you have not yet
installed MUSE2, [follow the instructions here][install-muse2].)

There are two ways you can do this:

1. Make sure the `muse2` executable is on your [`PATH`]:

- [Instructions for Windows][windows-path]
- [Instructions for Linux][linux-path]
- [Instructions for macOS][macos-path]

(If you installed MUSE2 with `cargo`, it should already be on your `PATH`.)

1. Set the `MUSE2_PATH` environment variable to the full path of the `muse2`
executable file.

You can either do this by [setting the environment variable from within
Jupyter][jupyter-envvar] or from your shell before you launch Jupyter notebook.

There are some example notebooks in the [`notebooks`] folder to get you started. You can
view these with Jupyter notebook, like so:

```bash
uv run jupyter notebook
```

If you are using Visual Studio Code, you can also view them directly in your IDE with
[the Jupyter extension].

[MUSE2]: https://github.com/EnergySystemsModellingLab/MUSE2
[uv]: https://docs.astral.sh/uv
[Download and install uv]: https://docs.astral.sh/uv/getting-started/installation/
[uv docs]: https://docs.astral.sh/uv/pip/environments/#creating-a-virtual-environment
[install-muse2]: https://energysystemsmodellinglab.github.io/MUSE2/#getting-started
[`PATH`]: https://en.wikipedia.org/wiki/PATH_(variable)
[windows-path]: https://stackoverflow.com/a/41895179
[linux-path]: https://unix.stackexchange.com/questions/3809/how-can-i-make-a-program-executable-from-everywhere
[macos-path]: https://apple.stackexchange.com/a/41586
[jupyter-envvar]: https://stackoverflow.com/a/44251637
[`notebooks`]: ./notebooks
[the Jupyter extension]: https://code.visualstudio.com/docs/datascience/jupyter-notebooks

## Copyright

Copyright © 2026 Imperial College London
3 changes: 3 additions & 0 deletions data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
!README.txt
!.gitignore
1 change: 1 addition & 0 deletions data/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is a placeholder directory for input/output data for example analyses.
9 changes: 9 additions & 0 deletions muse2_data_analysis/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""The main module for MUSE2 data analysis."""

from contextlib import suppress
from importlib.metadata import PackageNotFoundError, version

from .muse2 import find_muse2, run_muse2 # noqa: F401

with suppress(PackageNotFoundError):
__version__ = version(__name__)
38 changes: 38 additions & 0 deletions muse2_data_analysis/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Helper functions for notebooks."""

from pathlib import Path

from . import run_muse2

DATA_DIR = Path(__file__).parent.parent.absolute() / "data"
EXAMPLE_NAME = "muse1_default"
_INPUT_DIR = DATA_DIR / f"{EXAMPLE_NAME}_input"
_OUTPUT_DIR = DATA_DIR / f"{EXAMPLE_NAME}_output"


def get_example_input_dir() -> Path:
"""Get the directory for example input data.

If the folder does not exist, we create it by extracting an example from muse2.
"""
if _INPUT_DIR.exists():
return _INPUT_DIR

run_muse2("example", "extract", EXAMPLE_NAME, str(_INPUT_DIR))
return _INPUT_DIR


def get_example_output_dir() -> Path:
"""Get the directory for example output data.

If the folder does not exist, we create it by running an example model with muse2.
"""
if _OUTPUT_DIR.exists():
return _OUTPUT_DIR

# Ensure INPUT_DIR exists
get_example_input_dir()

# Run the example model
run_muse2("run", str(_INPUT_DIR), "--output-dir", str(_OUTPUT_DIR))
return _OUTPUT_DIR
Comment on lines +25 to +38
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functions check if directories exist but don't handle the case where the directory exists but muse2 execution fails during data generation. If muse2 fails after creating an empty or partial directory, subsequent calls will return the incomplete directory without regenerating the data. Consider adding validation that the expected output files exist, or handle the case where directory creation succeeds but data generation fails.

Copilot uses AI. Check for mistakes.
Loading