Skip to content

Commit d902e31

Browse files
committed
still broken
1 parent 2bdf3ef commit d902e31

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed

db_dtypes/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ def __sub__(self, other):
339339

340340

341341
sys_major, sys_minor, sys_micro = _versions_helpers.extract_runtime_version()
342+
print(f"DINOSAUR: {sys_major}.{sys_minor}.{sys_micro}")
342343
if sys_major == 3 and sys_minor in (7, 8):
343344
warnings.warn(
344345
"The python-bigquery library as well as the python-db-dtypes-pandas library no "

tests/unit/test__init__.py

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import sys
2+
import pytest
3+
import warnings
4+
from unittest import mock
5+
6+
# The module where the version check code resides
7+
MODULE_PATH = "db_dtypes"
8+
HELPER_MODULE_PATH = f"{MODULE_PATH}._versions_helpers"
9+
10+
@pytest.fixture(autouse=True)
11+
def cleanup_imports():
12+
"""
13+
Ensures the target module and its helper are removed from sys.modules
14+
before and after each test, allowing for clean imports with patching.
15+
"""
16+
# Store original sys.version_info if it's not already stored
17+
if not hasattr(cleanup_imports, 'original_version_info'):
18+
cleanup_imports.original_version_info = sys.version_info
19+
20+
# Remove modules before test
21+
if MODULE_PATH in sys.modules:
22+
del sys.modules[MODULE_PATH]
23+
if HELPER_MODULE_PATH in sys.modules:
24+
del sys.modules[HELPER_MODULE_PATH]
25+
26+
yield # Run the test
27+
28+
# Restore original sys.version_info after test
29+
sys.version_info = cleanup_imports.original_version_info
30+
31+
# Remove modules after test
32+
if MODULE_PATH in sys.modules:
33+
del sys.modules[MODULE_PATH]
34+
if HELPER_MODULE_PATH in sys.modules:
35+
del sys.modules[HELPER_MODULE_PATH]
36+
37+
38+
@pytest.mark.parametrize(
39+
"mock_version_tuple, version_str",
40+
[
41+
((3, 7, 10), "3.7.10"),
42+
((3, 7, 0), "3.7.0"),
43+
((3, 8, 5), "3.8.5"),
44+
((3, 8, 12), "3.8.12"),
45+
]
46+
)
47+
def test_python_3_7_or_3_8_warning_on_import(mock_version_tuple, version_str):
48+
"""Test that a FutureWarning is raised for Python 3.7 during import."""
49+
# Create a mock object mimicking sys.version_info attributes
50+
# Use spec=sys.version_info to ensure it has the right attributes if needed,
51+
# though just setting major/minor/micro is usually sufficient here.
52+
mock_version_info = mock.Mock(spec=sys.version_info,
53+
major=mock_version_tuple[0],
54+
minor=mock_version_tuple[1],
55+
micro=mock_version_tuple[2])
56+
57+
# Patch sys.version_info *before* importing db_dtypes
58+
with mock.patch('sys.version_info', mock_version_info):
59+
# Use pytest.warns to catch the expected warning during import
60+
with pytest.warns(FutureWarning) as record:
61+
# This import triggers __init__.py, which calls
62+
# _versions_helpers.extract_runtime_version, which reads
63+
# the *mocked* sys.version_info
64+
import db_dtypes
65+
66+
# Assert that exactly one warning was recorded
67+
assert len(record) == 1
68+
warning_message = str(record[0].message)
69+
# Assert the warning message content is correct
70+
assert "longer supports Python 3.7 and Python 3.8" in warning_message
71+
72+
@pytest.mark.parametrize(
73+
"mock_version_tuple",
74+
[
75+
(3, 9, 1), # Supported
76+
(3, 10, 0), # Supported
77+
(3, 11, 2), # Supported
78+
(3, 12, 0), # Supported
79+
]
80+
)
81+
def test_no_warning_for_other_versions_on_import(mock_version_tuple):
82+
"""Test that no FutureWarning is raised for other Python versions during import."""
83+
with mock.patch(f"{MODULE_PATH}._versions_helpers.extract_runtime_version", return_value=mock_version_tuple):
84+
# Use warnings.catch_warnings to check that NO relevant warning is raised
85+
with warnings.catch_warnings(record=True) as record:
86+
warnings.simplefilter("always") # Ensure warnings aren't filtered out by default config
87+
import db_dtypes # Import triggers the code
88+
89+
# Assert that no FutureWarning matching the specific message was recorded
90+
found_warning = False
91+
for w in record:
92+
# Check for the specific warning we want to ensure is NOT present
93+
if (issubclass(w.category, FutureWarning) and
94+
"longer supports Python 3.7 and Python 3.8" in str(w.message)):
95+
found_warning = True
96+
break
97+
assert not found_warning, f"Unexpected FutureWarning raised for Python version {mock_version_tuple}"
98+
99+
100+
@pytest.fixture
101+
def cleanup_imports_for_all(request):
102+
"""
103+
Ensures the target module and its dependencies potentially affecting
104+
__all__ are removed from sys.modules before and after each test,
105+
allowing for clean imports with patching.
106+
"""
107+
# Modules that might be checked or imported in __init__
108+
modules_to_clear = [
109+
MODULE_PATH,
110+
f"{MODULE_PATH}.core",
111+
f"{MODULE_PATH}.json",
112+
f"{MODULE_PATH}.version",
113+
f"{MODULE_PATH}._versions_helpers",
114+
]
115+
original_modules = {}
116+
117+
# Store original modules and remove them
118+
for mod_name in modules_to_clear:
119+
original_modules[mod_name] = sys.modules.get(mod_name)
120+
if mod_name in sys.modules:
121+
del sys.modules[mod_name]
122+
123+
yield # Run the test
124+
125+
# Restore original modules after test
126+
for mod_name, original_mod in original_modules.items():
127+
if original_mod:
128+
sys.modules[mod_name] = original_mod
129+
elif mod_name in sys.modules:
130+
# If it wasn't there before but is now, remove it
131+
del sys.modules[mod_name]
132+
133+
134+
# --- Test Case 1: JSON types available ---
135+
136+
def test_all_includes_json_when_available(cleanup_imports_for_all):
137+
"""
138+
Test that __all__ includes JSON types when JSONArray and JSONDtype are available.
139+
"""
140+
# No patching needed for the 'else' block, assume normal import works
141+
# and JSONArray/JSONDtype are truthy.
142+
import db_dtypes
143+
144+
expected_all = [
145+
"__version__",
146+
"DateArray",
147+
"DateDtype",
148+
"JSONDtype",
149+
"JSONArray",
150+
"JSONArrowType",
151+
"TimeArray",
152+
"TimeDtype",
153+
]
154+
# Use set comparison for order independence, as __all__ order isn't critical
155+
assert set(db_dtypes.__all__) == set(expected_all)
156+
# Explicitly check presence of JSON types
157+
assert "JSONDtype" in db_dtypes.__all__
158+
assert "JSONArray" in db_dtypes.__all__
159+
assert "JSONArrowType" in db_dtypes.__all__
160+
161+
162+
# --- Test Case 2: JSON types unavailable ---
163+
164+
@pytest.mark.parametrize(
165+
"patch_target_name",
166+
[
167+
"JSONArray",
168+
"JSONDtype",
169+
# Add both if needed, though one is sufficient to trigger the 'if'
170+
# ("JSONArray", "JSONDtype"),
171+
]
172+
)
173+
def test_all_excludes_json_when_unavailable(cleanup_imports_for_all, patch_target_name):
174+
"""
175+
Test that __all__ excludes JSON types when JSONArray or JSONDtype is unavailable (falsy).
176+
"""
177+
patch_path = f"{MODULE_PATH}.{patch_target_name}"
178+
179+
# Patch one of the JSON types to be None *before* importing db_dtypes.
180+
# This simulates the condition `if not JSONArray or not JSONDtype:` being true.
181+
with mock.patch(patch_path, None):
182+
# Need to ensure the json submodule itself is loaded if patching its contents
183+
# If the patch target is directly in __init__, this isn't needed.
184+
# Assuming JSONArray/JSONDtype are imported *into* __init__ from .json:
185+
try:
186+
import db_dtypes.json
187+
except ImportError:
188+
# Handle cases where the json module might genuinely be missing
189+
pass
190+
191+
# Now import the main module, which will evaluate __all__
192+
import db_dtypes
193+
194+
expected_all = [
195+
"__version__",
196+
"DateArray",
197+
"DateDtype",
198+
"TimeArray",
199+
"TimeDtype",
200+
]
201+
# Use set comparison for order independence
202+
assert set(db_dtypes.__all__) == set(expected_all)
203+
# Explicitly check absence of JSON types
204+
assert "JSONDtype" not in db_dtypes.__all__
205+
assert "JSONArray" not in db_dtypes.__all__
206+
assert "JSONArrowType" not in db_dtypes.__all__

0 commit comments

Comments
 (0)