Skip to content

Commit 89ceca8

Browse files
authored
Merge branch 'main' into updated-vsc-extension
2 parents fa07342 + ce486ec commit 89ceca8

File tree

4 files changed

+560
-7
lines changed

4 files changed

+560
-7
lines changed

code_to_optimize/topological_sort.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import uuid
12
from collections import defaultdict
23

34

@@ -21,9 +22,10 @@ def topologicalSortUtil(self, v, visited, stack):
2122
def topologicalSort(self):
2223
visited = [False] * self.V
2324
stack = []
25+
sorting_id = uuid.uuid4()
2426

2527
for i in range(self.V):
2628
if visited[i] == False:
2729
self.topologicalSortUtil(i, visited, stack)
2830

29-
return stack
31+
return stack, str(sorting_id)

codeflash/verification/pytest_plugin.py

Lines changed: 126 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import platform
1010
import re
1111
import sys
12-
import time
12+
import time as _time_module
1313
import warnings
1414
from pathlib import Path
1515
from typing import TYPE_CHECKING, Any, Callable
@@ -74,6 +74,125 @@ class UnexpectedError(Exception):
7474
resource.setrlimit(resource.RLIMIT_AS, (memory_limit, memory_limit))
7575

7676

77+
# Store references to original functions before any patching
78+
_ORIGINAL_TIME_TIME = _time_module.time
79+
_ORIGINAL_PERF_COUNTER = _time_module.perf_counter
80+
_ORIGINAL_TIME_SLEEP = _time_module.sleep
81+
82+
83+
# Apply deterministic patches for reproducible test execution
84+
def _apply_deterministic_patches() -> None:
85+
"""Apply patches to make all sources of randomness deterministic."""
86+
import datetime
87+
import random
88+
import time
89+
import uuid
90+
91+
# Store original functions (these are already saved globally above)
92+
_original_time = time.time
93+
_original_perf_counter = time.perf_counter
94+
_original_datetime_now = datetime.datetime.now
95+
_original_datetime_utcnow = datetime.datetime.utcnow
96+
_original_uuid4 = uuid.uuid4
97+
_original_uuid1 = uuid.uuid1
98+
_original_random = random.random
99+
100+
# Fixed deterministic values
101+
fixed_timestamp = 1609459200.0 # 2021-01-01 00:00:00 UTC
102+
fixed_datetime = datetime.datetime(2021, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
103+
fixed_uuid = uuid.UUID("12345678-1234-5678-9abc-123456789012")
104+
105+
# Counter for perf_counter to maintain relative timing
106+
_perf_counter_start = fixed_timestamp
107+
_perf_counter_calls = 0
108+
109+
def mock_time_time() -> float:
110+
"""Return fixed timestamp while preserving performance characteristics."""
111+
_original_time() # Maintain performance characteristics
112+
return fixed_timestamp
113+
114+
def mock_perf_counter() -> float:
115+
"""Return incrementing counter for relative timing."""
116+
nonlocal _perf_counter_calls
117+
_original_perf_counter() # Maintain performance characteristics
118+
_perf_counter_calls += 1
119+
return _perf_counter_start + (_perf_counter_calls * 0.001) # Increment by 1ms each call
120+
121+
def mock_datetime_now(tz: datetime.timezone | None = None) -> datetime.datetime:
122+
"""Return fixed datetime while preserving performance characteristics."""
123+
_original_datetime_now(tz) # Maintain performance characteristics
124+
if tz is None:
125+
return fixed_datetime
126+
return fixed_datetime.replace(tzinfo=tz)
127+
128+
def mock_datetime_utcnow() -> datetime.datetime:
129+
"""Return fixed UTC datetime while preserving performance characteristics."""
130+
_original_datetime_utcnow() # Maintain performance characteristics
131+
return fixed_datetime
132+
133+
def mock_uuid4() -> uuid.UUID:
134+
"""Return fixed UUID4 while preserving performance characteristics."""
135+
_original_uuid4() # Maintain performance characteristics
136+
return fixed_uuid
137+
138+
def mock_uuid1(node: int | None = None, clock_seq: int | None = None) -> uuid.UUID:
139+
"""Return fixed UUID1 while preserving performance characteristics."""
140+
_original_uuid1(node, clock_seq) # Maintain performance characteristics
141+
return fixed_uuid
142+
143+
def mock_random() -> float:
144+
"""Return deterministic random value while preserving performance characteristics."""
145+
_original_random() # Maintain performance characteristics
146+
return 0.123456789 # Fixed random value
147+
148+
# Apply patches
149+
time.time = mock_time_time
150+
time.perf_counter = mock_perf_counter
151+
uuid.uuid4 = mock_uuid4
152+
uuid.uuid1 = mock_uuid1
153+
154+
# Seed random module for other random functions
155+
random.seed(42)
156+
random.random = mock_random
157+
158+
# For datetime, we need to use a different approach since we can't patch class methods
159+
# Store original methods for potential later use
160+
import builtins
161+
162+
builtins._original_datetime_now = _original_datetime_now # noqa: SLF001
163+
builtins._original_datetime_utcnow = _original_datetime_utcnow # noqa: SLF001
164+
builtins._mock_datetime_now = mock_datetime_now # noqa: SLF001
165+
builtins._mock_datetime_utcnow = mock_datetime_utcnow # noqa: SLF001
166+
167+
# Patch numpy.random if available
168+
try:
169+
import numpy as np
170+
171+
# Use modern numpy random generator approach
172+
np.random.default_rng(42)
173+
np.random.seed(42) # Keep legacy seed for compatibility # noqa: NPY002
174+
except ImportError:
175+
pass
176+
177+
# Patch os.urandom if needed
178+
try:
179+
import os
180+
181+
_original_urandom = os.urandom
182+
183+
def mock_urandom(n: int) -> bytes:
184+
_original_urandom(n) # Maintain performance characteristics
185+
return b"\x42" * n # Fixed bytes
186+
187+
os.urandom = mock_urandom
188+
except (ImportError, AttributeError):
189+
pass
190+
191+
192+
# Note: Deterministic patches are applied conditionally, not globally
193+
# They should only be applied when running CodeFlash optimization tests
194+
195+
77196
def pytest_addoption(parser: Parser) -> None:
78197
"""Add command line options."""
79198
pytest_loops = parser.getgroup("loops")
@@ -137,6 +256,9 @@ def pytest_configure(config: Config) -> None:
137256
config.addinivalue_line("markers", "loops(n): run the given test function `n` times.")
138257
config.pluginmanager.register(PytestLoops(config), PytestLoops.name)
139258

259+
# Apply deterministic patches when the plugin is configured
260+
_apply_deterministic_patches()
261+
140262

141263
class PytestLoops:
142264
name: str = "pytest-loops"
@@ -157,7 +279,7 @@ def pytest_runtestloop(self, session: Session) -> bool:
157279
if session.config.option.collectonly:
158280
return True
159281

160-
start_time: float = time.time()
282+
start_time: float = _ORIGINAL_TIME_TIME()
161283
total_time: float = self._get_total_time(session)
162284

163285
count: int = 0
@@ -184,7 +306,7 @@ def pytest_runtestloop(self, session: Session) -> bool:
184306
raise session.Interrupted(session.shouldstop)
185307
if self._timed_out(session, start_time, count):
186308
break # exit loop
187-
time.sleep(self._get_delay_time(session))
309+
_ORIGINAL_TIME_SLEEP(self._get_delay_time(session))
188310
return True
189311

190312
def _clear_lru_caches(self, item: pytest.Item) -> None:
@@ -283,7 +405,7 @@ def _timed_out(self, session: Session, start_time: float, count: int) -> bool:
283405
"""
284406
return count >= session.config.option.codeflash_max_loops or (
285407
count >= session.config.option.codeflash_min_loops
286-
and time.time() - start_time > self._get_total_time(session)
408+
and _ORIGINAL_TIME_TIME() - start_time > self._get_total_time(session)
287409
)
288410

289411
@pytest.fixture

tests/scripts/end_to_end_test_topological_sort.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import os
22
import pathlib
3-
import tomlkit
43

54
from codeflash.code_utils.code_utils import add_addopts_to_pyproject
65
from end_to_end_test_utilities import CoverageExpectation, TestConfig, run_codeflash_command, run_with_retries
@@ -17,7 +16,7 @@ def run_test(expected_improvement_pct: int) -> bool:
1716
CoverageExpectation(
1817
function_name="Graph.topologicalSort",
1918
expected_coverage=100.0,
20-
expected_lines=[24, 25, 26, 27, 28, 29],
19+
expected_lines=[25, 26, 27, 28, 29, 30, 31],
2120
)
2221
],
2322
)

0 commit comments

Comments
 (0)