ho22joshua commited on
Commit
3f91234
·
1 Parent(s): d5cfbf0

ci: add package and runtime smoke checks

Browse files
.github/workflows/ci.yml ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ concurrency:
8
+ group: ci-${{ github.workflow }}-${{ github.ref }}
9
+ cancel-in-progress: true
10
+
11
+ jobs:
12
+ lint:
13
+ name: lint
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: astral-sh/setup-uv@v6
18
+ with:
19
+ version: "0.8.x"
20
+ enable-cache: true
21
+ - run: uv sync --dev
22
+ - run: uv run ruff check .
23
+ - run: uv run ruff format --check .
24
+
25
+ test:
26
+ name: test
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ - uses: astral-sh/setup-uv@v6
31
+ with:
32
+ version: "0.8.x"
33
+ enable-cache: true
34
+ - run: uv sync --dev
35
+ - run: uv run pytest
36
+
37
+ package:
38
+ name: package
39
+ runs-on: ubuntu-latest
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+ - uses: astral-sh/setup-uv@v6
43
+ with:
44
+ version: "0.8.x"
45
+ enable-cache: true
46
+ - run: uv sync --dev
47
+ - run: uv build
48
+ - run: uv run python -m twine check dist/*
49
+ - name: Wheel install smoke test
50
+ shell: bash
51
+ run: |
52
+ set -euo pipefail
53
+ smoke_dir="$(mktemp -d)"
54
+ trap 'rm -rf "$smoke_dir"' EXIT
55
+ uv venv "$smoke_dir/venv"
56
+ uv pip install --python "$smoke_dir/venv/bin/python" dist/*.whl
57
+ (
58
+ cd "$smoke_dir"
59
+ "$smoke_dir/venv/bin/python" -c 'import gnn4colliders; print(gnn4colliders.__version__)'
60
+ "$smoke_dir/venv/bin/gnn4colliders" --help
61
+ "$smoke_dir/venv/bin/gnn4colliders" train --help
62
+ "$smoke_dir/venv/bin/gnn4colliders" export --help
63
+ )
64
+
65
+ onnx:
66
+ name: onnx
67
+ runs-on: ubuntu-latest
68
+ steps:
69
+ - uses: actions/checkout@v4
70
+ - uses: astral-sh/setup-uv@v6
71
+ with:
72
+ version: "0.8.x"
73
+ enable-cache: true
74
+ - run: uv sync --dev --extra root-gnn --extra onnx
75
+ - run: uv run pytest tests/unit/export -v
tests/parity/test_legacy_tracking.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Characterization of the legacy dataset item contract."""
2
+
3
+ import torch
4
+
5
+
6
+ def _dataset_item(legacy_dataset_module_without_dgl, labels, tracking, globals_):
7
+ dataset = object.__new__(legacy_dataset_module_without_dgl.RootDataset)
8
+ dataset.graphs = [object() for _ in labels]
9
+ dataset.labels = torch.as_tensor(labels)
10
+ dataset.tracking = torch.as_tensor(tracking, dtype=torch.float32)
11
+ dataset.global_features = torch.as_tensor(globals_, dtype=torch.float32)
12
+ return dataset
13
+
14
+
15
+ def test_dataset_item_contract_preserves_label_tracking_and_global_shapes(
16
+ legacy_dataset_module_without_dgl,
17
+ ):
18
+ dataset = object.__new__(legacy_dataset_module_without_dgl.RootDataset)
19
+ graph = object()
20
+ dataset.graphs = [graph]
21
+ dataset.labels = torch.tensor([7])
22
+ dataset.tracking = torch.tensor([[3.0, 2.5]], dtype=torch.float32)
23
+ dataset.global_features = torch.empty((1, 0), dtype=torch.float32)
24
+ item = dataset[0]
25
+ assert item[0] is graph
26
+ assert item[1].shape == torch.Size([])
27
+ assert item[1].dtype == torch.int64
28
+ assert item[2].shape == (2,)
29
+ assert item[2].dtype == torch.float32
30
+ assert item[2].tolist() == [3.0, 2.5]
31
+ assert item[3].shape == (0,)
32
+ assert item[3].dtype == torch.float32
33
+
34
+
35
+ def test_dataset_item_contract_preserves_binary_and_multiclass_labels(
36
+ legacy_dataset_module_without_dgl,
37
+ ):
38
+ dataset = _dataset_item(
39
+ legacy_dataset_module_without_dgl,
40
+ labels=[0, 1, 11],
41
+ tracking=[[0.0, 1.0], [3.0, -2.5], [7.0, 0.0]],
42
+ globals_=[[], [], []],
43
+ )
44
+ items = [dataset[index] for index in range(3)]
45
+ assert [item[1].item() for item in items] == [0, 1, 11]
46
+ assert all(item[1].shape == torch.Size([]) for item in items)
47
+ assert all(item[1].dtype == torch.int64 for item in items)
48
+ assert items[1][2].tolist() == [3.0, -2.5]
49
+ assert all(item[3].shape == (0,) for item in items)
50
+
51
+
52
+ def test_dataset_item_contract_preserves_nonempty_global_features(
53
+ legacy_dataset_module_without_dgl,
54
+ ):
55
+ dataset = _dataset_item(
56
+ legacy_dataset_module_without_dgl,
57
+ labels=[1],
58
+ tracking=[[4.0, 2.0]],
59
+ globals_=[[12.5, -3.0]],
60
+ )
61
+ item = dataset[0]
62
+ assert item[3].shape == (2,)
63
+ assert item[3].dtype == torch.float32
64
+ assert item[3].tolist() == [12.5, -3.0]
65
+
66
+
67
+ def test_fold_selection_uses_tracking_column_zero_and_keeps_weights(
68
+ legacy_utils_module,
69
+ ):
70
+ sample = type(
71
+ "Sample",
72
+ (),
73
+ {"tracking": torch.tensor([[0.0, 1.0], [1.0, -2.5], [2.0, 0.0], [3.0, 4.0]])},
74
+ )()
75
+ selection = legacy_utils_module.fold_selection({"n_folds": 2, "test": [1]}, "test")
76
+ assert selection(sample).tolist() == [False, True, False, True]
77
+ assert sample.tracking[:, 1].tolist() == [1.0, -2.5, 0.0, 4.0]
tests/unit/test_package_import.py CHANGED
@@ -5,3 +5,35 @@ def test_package_imports() -> None:
5
  import gnn4colliders
6
 
7
  assert gnn4colliders.__file__ is not None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  import gnn4colliders
6
 
7
  assert gnn4colliders.__file__ is not None
8
+ assert gnn4colliders.__version__ == "0.1.0"
9
+
10
+
11
+ def test_public_import_contract() -> None:
12
+ from gnn4colliders.inference import Predictor
13
+ from gnn4colliders.models.root_gnn import EdgeNetwork, FineTunedEdgeNetwork
14
+ from gnn4colliders.tasks import (
15
+ BinaryClassificationTask,
16
+ MulticlassClassificationTask,
17
+ )
18
+ from gnn4colliders.training import CheckpointManager, Trainer
19
+
20
+ assert all(
21
+ item is not None
22
+ for item in (
23
+ EdgeNetwork,
24
+ FineTunedEdgeNetwork,
25
+ BinaryClassificationTask,
26
+ MulticlassClassificationTask,
27
+ Trainer,
28
+ CheckpointManager,
29
+ Predictor,
30
+ )
31
+ )
32
+
33
+
34
+ def test_hydra_config_is_discoverable_from_package() -> None:
35
+ from gnn4colliders.cli import _config
36
+
37
+ config = _config([])
38
+ assert config.model.name == "edge_network"
39
+ assert config.task.type == "multiclass_classification"