Skip to content
Draft
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
15 changes: 10 additions & 5 deletions .github/workflows/test.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,25 +40,30 @@ jobs:
fetch-depth: 0
submodules: recursive

- name: Sync Python environment
run: |
cd python
uv sync --locked --extra dev

- name: Run Python tests
run: |
cd python
pytest --verbose .
uv run pytest --verbose .

- name: Check formatting
run: |
cd python
black --line-length=90 --extend-exclude=".*(\.pyi|_pb2.py)$" --check .
uv run ruff format --check .

- name: Lint with flake8
- name: Lint with ruff
run: |
cd python
flake8 --max-line-length=90 --extend-exclude="*.pyi,*_pb2.py" .
uv run ruff check .

- name: Type check with mypy
run: |
cd python
mypy --namespace-packages --explicit-package-bases .
uv run mypy --namespace-packages --explicit-package-bases .

cppcheck:
name: CPPCheck
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,8 @@ compile_commands.json

python/dist/
python/.eggs/
python/.venv/
__pycache__/

# YouCompleteMe
.ycm_extra_conf.py
Expand Down
20 changes: 6 additions & 14 deletions .pre-commit-config.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -28,7 +28,7 @@ repos:
- id: check-added-large-files
exclude: ^paper\.md$
- id: pretty-format-json
# black has its own mind of formatting Jupyter notebooks
# ruff-format has its own mind of formatting Jupyter notebooks
exclude: \.ipynb$|^.devcontainer/devcontainer\.json$|package-lock\.json$
args:
- --no-sort-keys
Expand All@@ -51,22 +51,14 @@ repos:
- -exclude
- ^LICENSE$|^LICENSES/|\.ecf$

# Using this mirror lets us use mypyc-compiled black, which is about 2x faster
- repo: https://github.com/psf/black-pre-commit-mirror
rev: "23.3.0"
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.14.10"
hooks:
- id: black-jupyter
- id: ruff
exclude: .*_pb2.pyi?$
args:
- --line-length=90

- repo: https://github.com/pycqa/flake8
rev: "7.3.0"
hooks:
- id: flake8
args: [--fix]
- id: ruff-format
exclude: .*_pb2.pyi?$
args:
- --max-line-length=90

- repo: https://github.com/markdownlint/markdownlint
rev: "v0.13.0"
Expand Down
5 changes: 3 additions & 2 deletions REUSE.toml
Original file line numberDiff line numberDiff line change
Expand Up@@ -28,13 +28,14 @@ path = [
"paper/figures/**",
"paper/paper.md",
"paper/paper.bib",
"python/uv.lock",
]
precedence = "aggregate"
SPDX-FileCopyrightText = "2018-2023, Institute for Automation of Complex Power Systems, RWTH Aachen University"
SPDX-FileCopyrightText = "2018-2026, Institute for Automation of Complex Power Systems, RWTH Aachen University"
SPDX-License-Identifier = "Apache-2.0"

[[annotations]]
path = ["flake.lock", "**.patch"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 OPAL-RT Germany GmbH"
SPDX-FileCopyrightText = "2025-2026 OPAL-RT Germany GmbH"
SPDX-License-Identifier = "Apache-2.0"
74 changes: 73 additions & 1 deletion flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 28 additions & 14 deletions flake.nix
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,12 +14,33 @@

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";

pyproject-nix = {
url = "github:pyproject-nix/pyproject.nix";
inputs.nixpkgs.follows = "nixpkgs";
};

uv2nix = {
url = "github:pyproject-nix/uv2nix";
inputs.pyproject-nix.follows = "pyproject-nix";
inputs.nixpkgs.follows = "nixpkgs";
};

pyproject-build-systems = {
url = "github:pyproject-nix/build-system-pkgs";
inputs.pyproject-nix.follows = "pyproject-nix";
inputs.uv2nix.follows = "uv2nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};

outputs =
{
self,
nixpkgs,
pyproject-nix,
uv2nix,
pyproject-build-systems,
...
}:
let
Expand DownExpand Up@@ -66,7 +87,10 @@
packagesWith = pkgs: rec {
default = villas-node;

villas-node-python = pkgs.callPackage (nixDir + "/python.nix") { src = ./.; };
villas-node-python = pkgs.callPackage (nixDir + "/python.nix") {
src = ./.;
inherit uv2nix pyproject-nix pyproject-build-systems;
};

villas-node-minimal = pkgs.callPackage (nixDir + "/villas.nix") {
src = ./.;
Expand DownExpand Up@@ -190,19 +214,9 @@
gcc = mkShellFor pkgs.stdenv pkgs.villas-node;
clang = mkShellFor pkgs.clangStdenv pkgs.villas-node;

python = pkgs.mkShell {
name = "villas-python-devShell";
hardeningDisable = [ "all" ];
inputsFrom = with pkgs; [ villas-node-python ];
packages =
with pkgs;
packages
++ [
(python3.withPackages (python-pkgs: [
python-pkgs.build
python-pkgs.twine
]))
];
python = pkgs.callPackage (nixDir + "/python-shell.nix") {
inherit (pkgs) villas-node-python;
extraPackages = packages;
};
}
);
Expand Down
14 changes: 10 additions & 4 deletions packaging/docker/Dockerfile.fedora
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,8 @@ RUN dnf -y install \
# Tools for debugging, coverage, profiling
RUN pip install \
gcovr \
protobuf
protobuf \
uv

# Dependencies
RUN dnf -y install \
Expand DownExpand Up@@ -84,10 +85,15 @@ RUN bash /deps/deps.sh
# Workaround for libnl3's search path for netem distributions
RUN ln -s /usr/lib64/tc /usr/lib/tc

# Install Python dev tools for CI
# Pre-install Python dependencies for CI
COPY ./python /python
RUN pip install /python[dev] && \
rm -r /python
RUN cd /python && \
uv sync --locked --extra dev && \
cp -r .venv /opt/villas-python-venv && \
cd / && \
rm -rf /python
ENV VIRTUAL_ENV=/opt/villas-python-venv
ENV PATH="/opt/villas-python-venv/bin:$PATH"

# Expose ports for HTTP and WebSocket frontend
EXPOSE 80
Expand Down
59 changes: 59 additions & 0 deletions packaging/nix/python-shell.nix
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
# SPDX-FileCopyrightText: 2026 OPAL-RT Germany GmbH
# SPDX-License-Identifier: Apache-2.0
#
# Development shell for the VILLASnode Python package.
#
# Provides an editable install of the package (pointing at the checked-out
# source tree) together with its development dependencies, provisioned via
# uv2nix/pyproject.nix from python/uv.lock.
{
pkgs,
villas-node-python,
# Extra packages to make available in the shell.
extraPackages ? [ ],
}:
let
pythonSet = villas-node-python.pythonSet;

# Install the workspace packages in editable mode pointing at the
# checked-out source tree, so changes apply without a rebuild.
editableOverlay = villas-node-python.workspace.mkEditablePyprojectOverlay {
root = "$REPO_ROOT/python";
};

editablePythonSet = pythonSet.overrideScope editableOverlay;

virtualenv = editablePythonSet.mkVirtualEnv "villas-node-dev-env" {
villas-node = [ "dev" ];
};
in
pkgs.mkShell {
name = "villas-python-devShell";
hardeningDisable = [ "all" ];
packages =
with pkgs;
extraPackages
++ [
virtualenv
uv
ruff
];

env = {
# Prevent uv from managing its own virtual environment; uv2nix does.
UV_NO_SYNC = "1";
UV_PYTHON = editablePythonSet.python.interpreter;
UV_PYTHON_DOWNLOADS = "never";
};

shellHook = ''
unset PYTHONPATH
export REPO_ROOT=$(git rev-parse --show-toplevel)

# Activate the uv2nix-provided virtual environment so that
# python/pytest/ruff resolve to it and the editable install of
# villas-node (pointing at $REPO_ROOT/python) is importable.
export VIRTUAL_ENV="${virtualenv}"
export PATH="$VIRTUAL_ENV/bin:$PATH"
'';
}
Loading
Loading