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
23 changes: 16 additions & 7 deletions .github/hooks/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ repos:
args:
- --fix=lf
- id: name-tests-test
exclude: "hyperbench/tests/mock/"
exclude: "hyperbench/tests/mock/|hyperbench/tests/integration/common.py"
- id: pretty-format-json
args:
- --autofix
Expand All @@ -32,18 +32,27 @@ repos:

- repo: local
hooks:
- id: uvx-ruff-format
name: uvx ruff format
entry: bash -c 'uvx ruff format'
- id: uv-run-typecheker
name: uv run ty check
language: system
entry: bash -c 'uv run ty check'
types_or: [python, pyi]
require_serial: true

- repo: local
hooks:
- id: uvx-ty-check
name: uvx ty check
entry: bash -c 'uvx ty check'
- id: uv-ruff-linter
name: uv run ruff check
language: system
entry: bash -c 'uv run ruff check'
types_or: [python, pyi]
require_serial: true

- repo: local
hooks:
- id: uv-ruff-formatter
name: uv run ruff format
language: system
entry: bash -c 'uv run ruff format'
types_or: [python, pyi]
require_serial: true
4 changes: 4 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ jobs:
run: |
make test
- name: Run integration tests with pytest
run: |
make integration-test
test-arm:
runs-on: ${{ matrix.os }}
strategy:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:

- name: Run tests with coverage
run: |
uv run pytest --cov --cov-branch --cov-report=xml
uv run pytest -n auto --cov --cov-branch --cov-report=xml -m "not integration"

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
Expand All @@ -38,7 +38,7 @@ jobs:

- name: Test with pytest
run: |
uv run pytest --cov --junitxml=junit.xml
uv run pytest -n auto --cov --junitxml=junit.xml -m "not integration"

- name: Upload test results to Codecov
uses: codecov/codecov-action@v5
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/issues.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ on:

jobs:
validate-issue-labels:
environment:
name: management
runs-on: ubuntu-latest
permissions:
issues: write
Expand Down
4 changes: 0 additions & 4 deletions .github/workflows/pull_requests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ on:

jobs:
label:
environment:
name: management
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -20,8 +18,6 @@ jobs:
sync-labels: true

assignees:
environment:
name: management
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
23 changes: 18 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: all build setup setup-tensorboard clean destroy \
test stest run \
.PHONY: all release build setup setup-tensorboard clean destroy \
test stest integration-test run \
check format typecheck lint lint-fix lint-rule lint-rule-fix \
docs docs-build docs-serve \
loc help
Expand All @@ -14,6 +14,8 @@ DOCS_ADDR=127.0.0.1:8000

all: clean setup check test

release: clean setup check test integration-test

build: clean setup

setup:
Expand Down Expand Up @@ -56,13 +58,21 @@ lint-rule-fix:
$(UV) run $(LINTER) check --select $(R) --fix

test:
@echo '=== Tests ==='
$(UV) run $(PYTEST) --cov=$(PROJECT_NAME) --cov-report=term-missing
@echo '=== Running tests in parallel ==='
$(UV) run $(PYTEST) -n auto --cov=$(PROJECT_NAME) --cov-report=term-missing -m "not integration"

stest:
@echo '=== Test for $(T) ==='
$(UV) run $(PYTEST) -s $(PROJECT_NAME)/tests/$(T)

integration-test:
@echo '=== Running integration tests in parallel ==='
$(UV) run $(PYTEST) -n auto -m "integration"

s-integration-test:
@echo '=== Single integration test for $(T) ==='
$(UV) run $(PYTEST) -s $(PROJECT_NAME)/integration_tests/$(T) -m "integration"

# If the first argument is run...
ifeq ($(firstword $(MAKECMDGOALS)),run)
# use the rest as arguments for run...
Expand Down Expand Up @@ -104,6 +114,7 @@ help:
@echo "Usage: make [target]"
@echo "Targets:"
@echo " all - Clean, setup, lint, typecheck, test"
@echo " release - Clean, setup, lint, typecheck, test, integration-test"
@echo " build - Clean and setup"
@echo " setup - Install dependencies"
@echo " setup-tensorboard - Install optional TensorBoard dependency"
Expand All @@ -115,8 +126,10 @@ help:
@echo " lint-fix - Run linting and fix issues"
@echo " lint-rule R=<rule> - Run linting for a specific rule (e.g., R=E501)"
@echo " lint-rule-fix R=<rule> - Run linting for a specific rule and fix issues"
@echo " test - Run all tests"
@echo " test - Run all tests in parallel"
@echo " stest T=<test_name> - Run a single test"
@echo " integration-test - Run integration tests in parallel"
@echo " sintegration-test T=<test_name> - Run a single integration test"
@echo " run <file.py> - Run a single file"
@echo " docs - Build and serve documentation"
@echo " docs-build - Build documentation without serving"
Expand Down
2 changes: 2 additions & 0 deletions docs/agents/references/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- Prefer Makefile targets:
- `make test`
- `make stest T=<path-within-hyperbench/tests>`
- `make integration-test`
- `make sintegration-test T=<path-within-hyperbench/integration_tests>`
- Use `uv run pytest` only for targeted one-off runs.
- Run `make test` to see coverage reports and identify untested lines.

Expand Down
6 changes: 5 additions & 1 deletion docs/development/makefile.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ You can always run `make help` to see the latest list.
> Notes
>
> - These are the explicit CLI commands that each `make` target runs.
> - `make all`, `make build`, `make check`, `make docs` are composites (they run multiple steps).
> - `make all`, `make release`, `make build`, `make check`, `make docs` are composites (they run multiple steps).

| Target | Description |
|---|---|
| `make help` | Print available targets |
| `make all` | Clean, setup, check, test |
| `make release` | Clean, setup, check, test, integration-test |
| `make build` | Clean and setup |
| `make setup` | Install dependencies (via `uv`) and install HyperBench in editable mode |
| `make setup-tensorboard` | Install optional TensorBoard extra |
Expand All @@ -26,6 +27,8 @@ You can always run `make help` to see the latest list.
| `make docstring-check` | Check docstring formatting |
| `make test` | Run all tests (with coverage) |
| `make stest T=<test_path>` | Run a single test file/folder under `hyperbench/tests/` |
| `make integration-test` | Run all integration tests |
| `make sintegration-test T=<test_path>` | Run a single integration test file/folder under `hyperbench/integration_tests/` |
| `make run <file.py>` | Run a single Python file (for example: `make run examples/gcn.py`) |
| `make docs` | Build and serve documentation |
| `make docs-build` | Build documentation without serving |
Expand Down Expand Up @@ -197,6 +200,7 @@ You can always run `make help` to see the latest list.
Utility targets that run multiple steps in sequence.

- `make all`: Clean, setup, check, test
- `make release`: Clean, setup, check, test, integration-test
- `make build`: Clean and setup
- `make check`: Run lint + format + typecheck
- `make docs`: Build and serve documentation
3 changes: 0 additions & 3 deletions examples/hgnn.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@
print(f"Val dataset:\n {val_dataset.hdata}\n")
print(f"Test dataset:\n {test_dataset.hdata}\n")

# Save train hyperedge index before adding negatives (for CommonNeighbors)
train_hyperedge_index = train_dataset.hdata.hyperedge_index

# Add negative samples to all splits
for name, ds in [("Train", train_dataset), ("Val", val_dataset), ("Test", test_dataset)]:
num_negative_samples = (
Expand Down
2 changes: 0 additions & 2 deletions examples/hgnnp.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@
print(f"Val dataset:\n {val_dataset.hdata}\n")
print(f"Test dataset:\n {test_dataset.hdata}\n")

train_hyperedge_index = train_dataset.hdata.hyperedge_index

for name, ds in [("Train", train_dataset), ("Val", val_dataset), ("Test", test_dataset)]:
num_negative_samples = (
ds.hdata.num_hyperedges
Expand Down
2 changes: 2 additions & 0 deletions hyperbench/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
ThreadsMathsxDataset,
TwitterDataset,
VegasBarsReviewsDataset,
list_datasets,
)

from .loader import DataLoader
Expand Down Expand Up @@ -116,4 +117,5 @@
"VilLainEnricher",
"VilLainHyperedgeAttrsEnricher",
"create_sampler_from_strategy",
"list_datasets",
]
2 changes: 1 addition & 1 deletion hyperbench/data/hif.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def load_by_name(

@classmethod
def __extract_hif(cls, json_file: str) -> HIFHypergraph:
with open(json_file) as f:
with open(json_file, encoding="utf-8") as f:
hiftext = json.load(f)
if not validate_hif_json(json_file):
raise ValueError(f"Dataset from file '{json_file}' is not HIF-compliant.")
Expand Down
24 changes: 24 additions & 0 deletions hyperbench/data/supported_datasets.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
import inspect
import sys

from hyperbench.data.hif import HIFLoader
from hyperbench.data.dataset import Dataset
from hyperbench.data.sampler import SamplingStrategy


def list_datasets():
"""
Return a sorted list of available dataset names discovered from the
classes exported in this module.

This inspects the module for classes that subclass `_PreloadedDataset`
and expose a non-empty `DATASET_NAME` attribute. It avoids requiring an
explicit exported mapping.
"""
mod = sys.modules[__name__]
names: list[str] = []
for _, obj in inspect.getmembers(mod, inspect.isclass):
if issubclass(obj, _PreloadedDataset) and obj is not _PreloadedDataset:
ds_name = getattr(obj, "DATASET_NAME", None)
if isinstance(ds_name, str) and ds_name:
names.append(ds_name)

# Return deterministic ordering
return sorted(set(names))


class _PreloadedDataset(Dataset):
"""
Base class for datasets that use default loading.
Expand Down
21 changes: 21 additions & 0 deletions hyperbench/integration_tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from .common import (
common_standard_metrics,
loaders,
model_configs,
multi_model_trainer,
splits_dataset,
datasets_enrichers,
add_negatives,
add_model_configs,
)

__all__ = [
"add_model_configs",
"add_negatives",
"common_standard_metrics",
"datasets_enrichers",
"loaders",
"model_configs",
"multi_model_trainer",
"splits_dataset",
]
Loading
Loading