Skip to content

Commit f2f9196

Browse files
committed
ci: added GitHub Actions (tests, import-independence, install) + ruff lint
1 parent b08462b commit f2f9196

3 files changed

Lines changed: 177 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: CI
2+
3+
# Runs on every push to main and every pull request targeting main.
4+
# Scope is deliberate: dependency-light unit tests and import checks only.
5+
# The full experiments (CNN training, DoWhy counterfactuals, cross-domain runs)
6+
# require TensorFlow, DoWhy, a GPU, and licensed datasets that are not available
7+
# in CI. Those are run on a workstation and recorded in EXPERIMENTS.md.
8+
9+
on:
10+
push:
11+
branches: [main]
12+
pull_request:
13+
branches: [main]
14+
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.ref }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
test:
21+
name: tests (py${{ matrix.python-version }})
22+
runs-on: ubuntu-latest
23+
strategy:
24+
fail-fast: false
25+
matrix:
26+
python-version: ["3.11", "3.12", "3.13"]
27+
28+
steps:
29+
- uses: actions/checkout@v4
30+
31+
- name: Set up Python ${{ matrix.python-version }}
32+
uses: actions/setup-python@v5
33+
with:
34+
python-version: ${{ matrix.python-version }}
35+
cache: pip
36+
37+
- name: Install core dependencies
38+
run: |
39+
python -m pip install --upgrade pip
40+
pip install -r requirements.txt
41+
pip install pytest
42+
43+
- name: Run unit tests
44+
run: pytest test/ -v
45+
46+
import-independence:
47+
name: import-independence (no TensorFlow)
48+
runs-on: ubuntu-latest
49+
steps:
50+
- uses: actions/checkout@v4
51+
52+
- name: Set up Python
53+
uses: actions/setup-python@v5
54+
with:
55+
python-version: "3.12"
56+
cache: pip
57+
58+
- name: Install core dependencies only
59+
run: |
60+
python -m pip install --upgrade pip
61+
pip install -r requirements.txt
62+
63+
- name: Assert TensorFlow is absent
64+
run: |
65+
python - <<'PY'
66+
import importlib.util, sys
67+
if importlib.util.find_spec("tensorflow") is not None:
68+
sys.exit("TensorFlow is installed; this job must run without it.")
69+
print("confirmed: TensorFlow not installed")
70+
PY
71+
72+
- name: Import dependency-light subpackages
73+
run: |
74+
python - <<'PY'
75+
import importlib
76+
for mod in ("cnsd.causal", "cnsd.physics", "cnsd.config", "cnsd.scm"):
77+
importlib.import_module(mod)
78+
print(f"imported {mod} without TensorFlow")
79+
PY
80+
81+
install:
82+
name: editable install
83+
runs-on: ubuntu-latest
84+
steps:
85+
- uses: actions/checkout@v4
86+
87+
- name: Set up Python
88+
uses: actions/setup-python@v5
89+
with:
90+
python-version: "3.12"
91+
cache: pip
92+
93+
- name: Install package (editable, core extras)
94+
run: |
95+
python -m pip install --upgrade pip
96+
pip install -e .
97+
98+
- name: Import installed package
99+
run: python -c "import cnsd; print('cnsd installed and importable')"

.github/workflows/lint.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Lint
2+
3+
# Static checks: Ruff handles both linting and formatting in a single tool.
4+
# Fast (seconds), no project dependencies needed, runs on every push and PR.
5+
6+
on:
7+
push:
8+
branches: [main]
9+
pull_request:
10+
branches: [main]
11+
12+
concurrency:
13+
group: lint-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
ruff:
18+
name: ruff (lint + format)
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Set up Python
24+
uses: actions/setup-python@v5
25+
with:
26+
python-version: "3.12"
27+
28+
- name: Install Ruff
29+
run: pip install ruff
30+
31+
# Linting: flags unused imports, undefined names, common bugs.
32+
- name: Ruff lint
33+
run: ruff check .
34+
35+
# Formatting: verifies code matches the formatter (does not modify it).
36+
# Run `ruff format .` locally to fix before pushing.
37+
- name: Ruff format check
38+
run: ruff format --check .

pyproject.toml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Tool configuration only.
2+
#
3+
# Packaging is still handled by setup.py, the developer tooling (Ruff, pytest) in their standard modern location.
4+
5+
[tool.ruff]
6+
line-length = 100
7+
target-version = "py311"
8+
# Directories that are generated, vendored, or not part of the package source.
9+
extend-exclude = ["build", "dist", "*.egg-info", "experiments_archive"]
10+
11+
[tool.ruff.lint]
12+
# A pragmatic, not maximal, rule set. Catches the real bug classes this project
13+
# has actually hit (unused/undefined imports, name errors) without drowning a
14+
# research codebase in stylistic noise.
15+
select = [
16+
"E", # pycodestyle errors
17+
"F", # pyflakes (unused imports, undefined names, the bugs we kept hitting)
18+
"I", # import sorting
19+
"B", # flake8-bugbear (likely-bug patterns)
20+
"UP", # pyupgrade (modernize syntax)
21+
"W", # pycodestyle warnings
22+
]
23+
ignore = [
24+
"E501", # line length is enforced by the formatter, not the linter
25+
"B008", # function calls in argument defaults (common, intentional here)
26+
]
27+
28+
[tool.ruff.lint.per-file-ignores]
29+
# Test files and examples may use imports for side effects / fixtures.
30+
"test/*" = ["F401", "F811"]
31+
"examples/*" = ["F401"]
32+
33+
[tool.ruff.format]
34+
quote-style = "single"
35+
docstring-code-format = true
36+
37+
[tool.pytest.ini_options]
38+
testpaths = ["test"]
39+
python_files = ["test_*.py", "*_test.py"]
40+
addopts = "-v"

0 commit comments

Comments
 (0)