Skip to content
Merged
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
11 changes: 10 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,14 @@ jobs:
else
uv python install
uv sync --extra test
uv run pytest -n auto --tb=short
uv run pytest -n auto --tb=short \
--cov=delaynet --cov-branch \
--cov-report=xml --cov-report=term-missing
fi

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
if: matrix.python-version == 'latest'
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<a href="">[![CI](https://github.com/cbueth/delaynet/actions/workflows/test.yml/badge.svg)](https://github.com/cbueth/delaynet/actions/workflows/test.yml)</a>
<a href="">[![Lint](https://github.com/cbueth/delaynet/actions/workflows/lint.yml/badge.svg)](https://github.com/cbueth/delaynet/actions/workflows/lint.yml)</a>
<a href="">[![CodSpeed Badge](https://img.shields.io/endpoint?url=https://app.codspeed.io//badge.json)](https://app.codspeed.io//cbueth/delaynet?utm_source=badge)</a>
<a href="">[![codecov](https://codecov.io/gh/cbueth/delaynet/branch/main/graph/badge.svg)](https://codecov.io/gh/cbueth/delaynet)</a>

</div>

Expand Down
13 changes: 13 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
coverage:
status:
project:
default:
target: auto
threshold: 2%
patch:
default:
target: 100%

comment:
layout: header, diff
behavior: default
3 changes: 1 addition & 2 deletions delaynet/network_analysis/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ def betweenness_centrality(
# For undirected graphs: max betweenness = (n-1)*(n-2)/2
max_betweenness = (n_nodes - 1) * (n_nodes - 2) / 2.0

if max_betweenness > 0:
centrality = centrality / max_betweenness
centrality = centrality / max_betweenness

return centrality

Expand Down
24 changes: 24 additions & 0 deletions tests/connectivities/test_granger.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,27 @@ def test_stronger_causal_signal_lower_pvalue(rng):
assert p_strong < p_weak, (
f"Stronger signal should have lower p-value (strong: {p_strong}, weak: {p_weak})"
)


def test_gt_single_lag_lstsq_fallback():
"""Test lstsq fallback when solve raises LinAlgError at line 92."""
from unittest.mock import patch

ts1 = np.random.normal(0, 1, size=100)
ts2 = np.random.normal(0, 1, size=100)

original_solve = np.linalg.solve
solve_calls = []

def mock_solve(a, b):
solve_calls.append((a, b))
if len(solve_calls) == 2:
raise np.linalg.LinAlgError(
"Simulating singular R_vcov_R for test coverage"
)
return original_solve(a, b)

with patch("numpy.linalg.solve", mock_solve):
p_value = gt_single_lag(ts1, ts2, lag_step=2)
assert isinstance(p_value, float)
assert 0 <= p_value <= 1
55 changes: 55 additions & 0 deletions tests/test_network_reconstruction.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tests for the network reconstruction module."""

import numpy as np
import pytest
from time import time
from numpy import (
Expand All @@ -26,6 +27,8 @@
format_time,
print_progress,
update_progress,
_compute_pair_connectivity_shared,
_compute_with_progress,
)


Expand Down Expand Up @@ -663,3 +666,55 @@ def __init__(self, value):
# Verify print_progress was called with explicit parameter
assert called[0] is True
assert sphinx_mode_value[0] is True


def test_compute_pair_connectivity_shared():
"""Test the shared-memory worker function directly."""
from multiprocessing import shared_memory

data = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [7.0, 8.0]])
shm = shared_memory.SharedMemory(create=True, size=data.nbytes)
shared_array = ndarray(data.shape, dtype=data.dtype, buffer=shm.buf)
shared_array[:] = data
try:
args = (0, 1, shm.name, data.shape, data.dtype, "linear_correlation", 1, {})
i, j, p, lag = _compute_pair_connectivity_shared(args)
assert i == 0
assert j == 1
assert isinstance(p, float)
assert isinstance(lag, int)
finally:
shm.close()
shm.unlink()


def test_compute_with_progress(monkeypatch):
"""Test the _compute_with_progress worker wrapper."""
from multiprocessing import shared_memory, Manager

monkeypatch.setattr("sys.stdout.write", lambda x: None)
monkeypatch.setattr("sys.stdout.flush", lambda: None)

data = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [7.0, 8.0]])
shm = shared_memory.SharedMemory(create=True, size=data.nbytes)
shared_array = ndarray(data.shape, dtype=data.dtype, buffer=shm.buf)
shared_array[:] = data
try:
args = (0, 1, shm.name, data.shape, data.dtype, "linear_correlation", 1, {})
with Manager() as manager:
counter = manager.Value("i", 0)
lock = manager.Lock()
result = _compute_with_progress(
args,
counter,
lock,
total_pairs=1,
start_time=time(),
sphinx_mode=True,
)
assert result is not None
assert result[0] == 0
assert result[1] == 1
finally:
shm.close()
shm.unlink()
Loading