Skip to content

Commit 5b4d4fb

Browse files
committed
Address review feedback: remove config option, reduce timeout, fix imports
1 parent 8ca1806 commit 5b4d4fb

File tree

3 files changed

+232
-11
lines changed

3 files changed

+232
-11
lines changed

codeflash/code_utils/version_check.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def get_latest_version_from_pypi() -> Optional[str]:
3030
return _version_cache["version"]
3131

3232
try:
33-
response = requests.get("https://pypi.org/pypi/codeflash/json", timeout=10)
33+
response = requests.get("https://pypi.org/pypi/codeflash/json", timeout=2)
3434
if response.status_code == 200:
3535
data = response.json()
3636
latest_version = data["info"]["version"]
@@ -67,15 +67,13 @@ def check_for_newer_minor_version(*, disable_check: bool = False) -> None:
6767
if disable_check:
6868
return
6969

70-
# Get current version dynamically to handle runtime changes
71-
from codeflash.version import __version__ as current_version
7270
latest_version = get_latest_version_from_pypi()
7371

7472
if not latest_version:
7573
return
7674

7775
try:
78-
current_parsed = version.parse(current_version)
76+
current_parsed = version.parse(__version__)
7977
latest_parsed = version.parse(latest_version)
8078

8179
# Check if there's a newer minor version available
@@ -86,11 +84,11 @@ def check_for_newer_minor_version(*, disable_check: bool = False) -> None:
8684

8785
console.print(
8886
f"[bold blue]ℹ️ A newer version of Codeflash is available![/bold blue]\n"
89-
f"Current version: {current_version} | Latest version: {latest_version}\n"
87+
f"Current version: {__version__} | Latest version: {latest_version}\n"
9088
f"Consider upgrading for better quality optimizations.",
9189
style="blue"
9290
)
9391

9492
except version.InvalidVersion as e:
9593
logger.debug(f"Invalid version format: {e}")
96-
return
94+
return

codeflash/version.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
11
# These version placeholders will be replaced by uv-dynamic-versioning during build.
2-
<<<<<<< HEAD
3-
__version__ = "0.15.6.post8.dev0+52083c4b"
4-
=======
5-
__version__ = "0.16.1"
6-
>>>>>>> 3171bb87187f35c9bd6dbcd3326b09939903898e
2+
__version__ = "0.15.6"

tests/test_version_check.py

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
"""Tests for version checking functionality."""
2+
3+
import unittest
4+
from unittest.mock import Mock, patch, MagicMock
5+
from packaging import version
6+
7+
from codeflash.code_utils.version_check import (
8+
get_latest_version_from_pypi,
9+
check_for_newer_minor_version,
10+
_version_cache,
11+
_cache_duration
12+
)
13+
14+
15+
class TestVersionCheck(unittest.TestCase):
16+
"""Test cases for version checking functionality."""
17+
18+
def setUp(self):
19+
"""Reset version cache before each test."""
20+
_version_cache["version"] = None
21+
_version_cache["timestamp"] = 0
22+
23+
def tearDown(self):
24+
"""Clean up after each test."""
25+
_version_cache["version"] = None
26+
_version_cache["timestamp"] = 0
27+
28+
@patch('codeflash.code_utils.version_check.requests.get')
29+
def test_get_latest_version_from_pypi_success(self, mock_get):
30+
"""Test successful version fetch from PyPI."""
31+
# Mock successful response
32+
mock_response = Mock()
33+
mock_response.status_code = 200
34+
mock_response.json.return_value = {"info": {"version": "1.2.3"}}
35+
mock_get.return_value = mock_response
36+
37+
result = get_latest_version_from_pypi()
38+
39+
self.assertEqual(result, "1.2.3")
40+
mock_get.assert_called_once_with(
41+
"https://pypi.org/pypi/codeflash/json",
42+
timeout=2
43+
)
44+
45+
@patch('codeflash.code_utils.version_check.requests.get')
46+
def test_get_latest_version_from_pypi_http_error(self, mock_get):
47+
"""Test handling of HTTP error responses."""
48+
# Mock HTTP error response
49+
mock_response = Mock()
50+
mock_response.status_code = 404
51+
mock_get.return_value = mock_response
52+
53+
result = get_latest_version_from_pypi()
54+
55+
self.assertIsNone(result)
56+
57+
@patch('codeflash.code_utils.version_check.requests.get')
58+
def test_get_latest_version_from_pypi_network_error(self, mock_get):
59+
"""Test handling of network errors."""
60+
# Mock network error
61+
mock_get.side_effect = Exception("Network error")
62+
63+
result = get_latest_version_from_pypi()
64+
65+
self.assertIsNone(result)
66+
67+
@patch('codeflash.code_utils.version_check.requests.get')
68+
def test_get_latest_version_from_pypi_invalid_response(self, mock_get):
69+
"""Test handling of invalid response format."""
70+
# Mock invalid response format
71+
mock_response = Mock()
72+
mock_response.status_code = 200
73+
mock_response.json.return_value = {"invalid": "format"}
74+
mock_get.return_value = mock_response
75+
76+
result = get_latest_version_from_pypi()
77+
78+
self.assertIsNone(result)
79+
80+
@patch('codeflash.code_utils.version_check.requests.get')
81+
def test_get_latest_version_from_pypi_caching(self, mock_get):
82+
"""Test that version caching works correctly."""
83+
# Mock successful response
84+
mock_response = Mock()
85+
mock_response.status_code = 200
86+
mock_response.json.return_value = {"info": {"version": "1.2.3"}}
87+
mock_get.return_value = mock_response
88+
89+
# First call should hit the network
90+
result1 = get_latest_version_from_pypi()
91+
self.assertEqual(result1, "1.2.3")
92+
self.assertEqual(mock_get.call_count, 1)
93+
94+
# Second call should use cache
95+
result2 = get_latest_version_from_pypi()
96+
self.assertEqual(result2, "1.2.3")
97+
self.assertEqual(mock_get.call_count, 1) # Still only 1 call
98+
99+
@patch('codeflash.code_utils.version_check.requests.get')
100+
def test_get_latest_version_from_pypi_cache_expiry(self, mock_get):
101+
"""Test that cache expires after the specified duration."""
102+
import time
103+
104+
# Mock successful response
105+
mock_response = Mock()
106+
mock_response.status_code = 200
107+
mock_response.json.return_value = {"info": {"version": "1.2.3"}}
108+
mock_get.return_value = mock_response
109+
110+
# First call
111+
result1 = get_latest_version_from_pypi()
112+
self.assertEqual(result1, "1.2.3")
113+
114+
# Manually expire the cache
115+
_version_cache["timestamp"] = time.time() - _cache_duration - 1
116+
117+
# Second call should hit the network again
118+
result2 = get_latest_version_from_pypi()
119+
self.assertEqual(result2, "1.2.3")
120+
self.assertEqual(mock_get.call_count, 2)
121+
122+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
123+
@patch('codeflash.code_utils.version_check.console')
124+
@patch('codeflash.code_utils.version_check.__version__', '1.0.0')
125+
def test_check_for_newer_minor_version_newer_available(self, mock_console, mock_get_version):
126+
"""Test warning message when newer minor version is available."""
127+
mock_get_version.return_value = "1.1.0"
128+
129+
check_for_newer_minor_version()
130+
131+
mock_console.print.assert_called_once()
132+
call_args = mock_console.print.call_args[0][0]
133+
self.assertIn("ℹ️ A newer version of Codeflash is available!", call_args)
134+
self.assertIn("Current version: 1.0.0", call_args)
135+
self.assertIn("Latest version: 1.1.0", call_args)
136+
137+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
138+
@patch('codeflash.code_utils.version_check.console')
139+
@patch('codeflash.code_utils.version_check.__version__', '1.0.0')
140+
def test_check_for_newer_minor_version_newer_major_available(self, mock_console, mock_get_version):
141+
"""Test warning message when newer major version is available."""
142+
mock_get_version.return_value = "2.0.0"
143+
144+
check_for_newer_minor_version()
145+
146+
mock_console.print.assert_called_once()
147+
call_args = mock_console.print.call_args[0][0]
148+
self.assertIn("ℹ️ A newer version of Codeflash is available!", call_args)
149+
150+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
151+
@patch('codeflash.code_utils.version_check.console')
152+
@patch('codeflash.code_utils.version_check.__version__', '1.1.0')
153+
def test_check_for_newer_minor_version_no_newer_available(self, mock_console, mock_get_version):
154+
"""Test no warning when no newer version is available."""
155+
mock_get_version.return_value = "1.0.0"
156+
157+
check_for_newer_minor_version()
158+
159+
mock_console.print.assert_not_called()
160+
161+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
162+
@patch('codeflash.code_utils.version_check.console')
163+
@patch('codeflash.code_utils.version_check.__version__', '1.0.0')
164+
def test_check_for_newer_minor_version_patch_update_ignored(self, mock_console, mock_get_version):
165+
"""Test that patch updates don't trigger warnings."""
166+
mock_get_version.return_value = "1.0.1"
167+
168+
check_for_newer_minor_version()
169+
170+
mock_console.print.assert_not_called()
171+
172+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
173+
@patch('codeflash.code_utils.version_check.console')
174+
@patch('codeflash.code_utils.version_check.__version__', '1.0.0')
175+
def test_check_for_newer_minor_version_same_version(self, mock_console, mock_get_version):
176+
"""Test no warning when versions are the same."""
177+
mock_get_version.return_value = "1.0.0"
178+
179+
check_for_newer_minor_version()
180+
181+
mock_console.print.assert_not_called()
182+
183+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
184+
@patch('codeflash.code_utils.version_check.console')
185+
@patch('codeflash.code_utils.version_check.__version__', '1.0.0')
186+
def test_check_for_newer_minor_version_no_latest_version(self, mock_console, mock_get_version):
187+
"""Test no warning when latest version cannot be fetched."""
188+
mock_get_version.return_value = None
189+
190+
check_for_newer_minor_version()
191+
192+
mock_console.print.assert_not_called()
193+
194+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
195+
@patch('codeflash.code_utils.version_check.console')
196+
@patch('codeflash.code_utils.version_check.__version__', '1.0.0')
197+
def test_check_for_newer_minor_version_invalid_version_format(self, mock_console, mock_get_version):
198+
"""Test handling of invalid version format."""
199+
mock_get_version.return_value = "invalid-version"
200+
201+
check_for_newer_minor_version()
202+
203+
mock_console.print.assert_not_called()
204+
205+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
206+
@patch('codeflash.code_utils.version_check.console')
207+
def test_check_for_newer_minor_version_disable_check(self, mock_console, mock_get_version):
208+
"""Test that version check is skipped when disable_check is True."""
209+
check_for_newer_minor_version(disable_check=True)
210+
211+
mock_get_version.assert_not_called()
212+
mock_console.print.assert_not_called()
213+
214+
@patch('codeflash.code_utils.version_check.get_latest_version_from_pypi')
215+
@patch('codeflash.code_utils.version_check.console')
216+
def test_check_for_newer_minor_version_disable_check_false(self, mock_console, mock_get_version):
217+
"""Test that version check runs when disable_check is False."""
218+
mock_get_version.return_value = None
219+
220+
check_for_newer_minor_version(disable_check=False)
221+
222+
mock_get_version.assert_called_once()
223+
mock_console.print.assert_not_called()
224+
225+
226+
if __name__ == '__main__':
227+
unittest.main()

0 commit comments

Comments
 (0)