Skip to content
Open
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
24 changes: 24 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Pytest configuration for PyPortfolioOpt tests.

Fixes compatibility between pytest-randomly and numpy's legacy
random seed API. See https://github.com/PyPortfolio/PyPortfolioOpt/issues/725
"""

import numpy as np

_original_np_random_seed = np.random.seed


def _safe_np_random_seed(seed=None):
"""Constrain seed to numpy's valid range [0, 2**32 - 1].

pytest-randomly may generate seeds exceeding this range when combining
the base seed with per-test offsets, causing ValueError in numpy's
legacy random API.
"""
if seed is not None and isinstance(seed, (int, np.integer)):
seed = seed % (2**32)
_original_np_random_seed(seed)


np.random.seed = _safe_np_random_seed
46 changes: 46 additions & 0 deletions tests/test_conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Tests for the conftest.py seed safety patch."""

import numpy as np
import pytest


class TestSafeNumpySeed:
"""Verify numpy.random.seed handles oversized seeds from pytest-randomly."""

def test_seed_exceeding_uint32_max(self):
"""Seeds above 2**32 - 1 should not raise ValueError."""
np.random.seed(2**32 + 12345)

def test_seed_at_uint32_boundary(self):
"""Seed exactly at 2**32 should wrap to 0."""
np.random.seed(2**32)

def test_seed_zero(self):
"""Seed 0 should work as normal."""
np.random.seed(0)

def test_seed_max_valid(self):
"""Seed 2**32 - 1 should work as normal."""
np.random.seed(2**32 - 1)

def test_seed_none(self):
"""Seed None should work as normal (random seed)."""
np.random.seed(None)

def test_determinism_preserved(self):
"""Patched seed should still produce deterministic results."""
np.random.seed(42)
a = np.random.rand(5)
np.random.seed(42)
b = np.random.rand(5)
np.testing.assert_array_equal(a, b)

def test_large_seed_determinism(self):
"""Oversized seeds should produce deterministic results."""
large_seed = 2**33 + 99
np.random.seed(large_seed)
a = np.random.rand(5)
np.random.seed(large_seed)
b = np.random.rand(5)
np.testing.assert_array_equal(a, b)