Skip to content

Commit b8b7831

Browse files
aniketpaluntkathole
authored andcommitted
Moved check_warnings decorator in utils for resusability purpose
Signed-off-by: Aniket Paluskar <[email protected]>
1 parent 6c6899f commit b8b7831

File tree

2 files changed

+104
-104
lines changed

2 files changed

+104
-104
lines changed

sdk/python/tests/unit/online_store/test_online_writes.py

Lines changed: 1 addition & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import shutil
1818
import tempfile
1919
import unittest
20-
import warnings
2120
from datetime import datetime, timedelta
2221
from typing import Any
2322

@@ -37,109 +36,7 @@
3736
from feast.infra.online_stores.sqlite import SqliteOnlineStoreConfig
3837
from feast.on_demand_feature_view import on_demand_feature_view
3938
from feast.types import Array, Float32, Float64, Int64, PdfBytes, String, ValueType
40-
41-
42-
def check_warnings(
43-
expected_warnings=None, # List of warnings that MUST be present
44-
forbidden_warnings=None, # List of warnings that MUST NOT be present
45-
match_type="contains", # "exact", "contains", "regex"
46-
capture_all=True, # Capture all warnings or just specific types
47-
fail_on_unexpected=False, # Fail if unexpected warnings appear
48-
min_count=None, # Minimum number of expected warnings
49-
max_count=None, # Maximum number of expected warnings
50-
):
51-
"""
52-
Decorator to automatically capture and validate warnings in test methods.
53-
54-
Args:
55-
expected_warnings: List of warning messages that MUST be present
56-
forbidden_warnings: List of warning messages that MUST NOT be present
57-
match_type: How to match warnings ("exact", "contains", "regex")
58-
capture_all: Whether to capture all warnings
59-
fail_on_unexpected: Whether to fail if unexpected warnings appear
60-
min_count: Minimum number of warnings expected
61-
max_count: Maximum number of warnings expected
62-
"""
63-
64-
def decorator(test_func):
65-
def wrapper(*args, **kwargs):
66-
# Setup warning capture
67-
with warnings.catch_warnings(record=True) as warning_list:
68-
warnings.simplefilter("always")
69-
70-
# Execute the test function
71-
result = test_func(*args, **kwargs)
72-
73-
# Convert warnings to string messages
74-
captured_messages = [str(w.message) for w in warning_list]
75-
76-
# Validate expected warnings are present
77-
if expected_warnings:
78-
for expected_warning in expected_warnings:
79-
if not _warning_matches(
80-
expected_warning, captured_messages, match_type
81-
):
82-
raise AssertionError(
83-
f"Expected warning '{expected_warning}' not found. "
84-
f"Captured warnings: {captured_messages}"
85-
)
86-
87-
# Validate forbidden warnings are NOT present
88-
if forbidden_warnings:
89-
for forbidden_warning in forbidden_warnings:
90-
if _warning_matches(
91-
forbidden_warning, captured_messages, match_type
92-
):
93-
raise AssertionError(
94-
f"Forbidden warning '{forbidden_warning}' was found. "
95-
f"Captured warnings: {captured_messages}"
96-
)
97-
98-
# Validate warning count constraints
99-
if min_count is not None and len(warning_list) < min_count:
100-
raise AssertionError(
101-
f"Expected at least {min_count} warnings, got {len(warning_list)}"
102-
)
103-
104-
if max_count is not None and len(warning_list) > max_count:
105-
raise AssertionError(
106-
f"Expected at most {max_count} warnings, got {len(warning_list)}"
107-
)
108-
109-
# Validate no unexpected warnings (if enabled)
110-
if fail_on_unexpected and expected_warnings:
111-
all_expected = expected_warnings + (forbidden_warnings or [])
112-
for message in captured_messages:
113-
if not any(
114-
_warning_matches(exp, [message], match_type)
115-
for exp in all_expected
116-
):
117-
raise AssertionError(
118-
f"Unexpected warning found: '{message}'"
119-
)
120-
121-
return result
122-
123-
return wrapper
124-
125-
return decorator
126-
127-
128-
def _warning_matches(pattern, messages, match_type):
129-
"""Helper function to check if pattern matches any message"""
130-
for message in messages:
131-
if match_type == "exact":
132-
if pattern == message:
133-
return True
134-
elif match_type == "contains":
135-
if pattern in message:
136-
return True
137-
elif match_type == "regex":
138-
import re
139-
140-
if re.search(pattern, message):
141-
return True
142-
return False
39+
from tests.utils.test_wrappers import check_warnings
14340

14441

14542
class TestOnlineWrites(unittest.TestCase):

sdk/python/tests/utils/test_wrappers.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,106 @@ def wrapper_no_warnings(*args, **kwargs):
1212
)
1313

1414
return wrapper_no_warnings
15+
16+
17+
def check_warnings(
18+
expected_warnings=None, # List of warnings that MUST be present
19+
forbidden_warnings=None, # List of warnings that MUST NOT be present
20+
match_type="contains", # "exact", "contains", "regex"
21+
capture_all=True, # Capture all warnings or just specific types
22+
fail_on_unexpected=False, # Fail if unexpected warnings appear
23+
min_count=None, # Minimum number of expected warnings
24+
max_count=None, # Maximum number of expected warnings
25+
):
26+
"""
27+
Decorator to automatically capture and validate warnings in test methods.
28+
29+
Args:
30+
expected_warnings: List of warning messages that MUST be present
31+
forbidden_warnings: List of warning messages that MUST NOT be present
32+
match_type: How to match warnings ("exact", "contains", "regex")
33+
capture_all: Whether to capture all warnings
34+
fail_on_unexpected: Whether to fail if unexpected warnings appear
35+
min_count: Minimum number of warnings expected
36+
max_count: Maximum number of warnings expected
37+
"""
38+
39+
def decorator(test_func):
40+
def wrapper(*args, **kwargs):
41+
# Setup warning capture
42+
with warnings.catch_warnings(record=True) as warning_list:
43+
warnings.simplefilter("always")
44+
45+
# Execute the test function
46+
result = test_func(*args, **kwargs)
47+
48+
# Convert warnings to string messages
49+
captured_messages = [str(w.message) for w in warning_list]
50+
51+
# Validate expected warnings are present
52+
if expected_warnings:
53+
for expected_warning in expected_warnings:
54+
if not _warning_matches(
55+
expected_warning, captured_messages, match_type
56+
):
57+
raise AssertionError(
58+
f"Expected warning '{expected_warning}' not found. "
59+
f"Captured warnings: {captured_messages}"
60+
)
61+
62+
# Validate forbidden warnings are NOT present
63+
if forbidden_warnings:
64+
for forbidden_warning in forbidden_warnings:
65+
if _warning_matches(
66+
forbidden_warning, captured_messages, match_type
67+
):
68+
raise AssertionError(
69+
f"Forbidden warning '{forbidden_warning}' was found. "
70+
f"Captured warnings: {captured_messages}"
71+
)
72+
73+
# Validate warning count constraints
74+
if min_count is not None and len(warning_list) < min_count:
75+
raise AssertionError(
76+
f"Expected at least {min_count} warnings, got {len(warning_list)}"
77+
)
78+
79+
if max_count is not None and len(warning_list) > max_count:
80+
raise AssertionError(
81+
f"Expected at most {max_count} warnings, got {len(warning_list)}"
82+
)
83+
84+
# Validate no unexpected warnings (if enabled)
85+
if fail_on_unexpected and expected_warnings:
86+
all_expected = expected_warnings + (forbidden_warnings or [])
87+
for message in captured_messages:
88+
if not any(
89+
_warning_matches(exp, [message], match_type)
90+
for exp in all_expected
91+
):
92+
raise AssertionError(
93+
f"Unexpected warning found: '{message}'"
94+
)
95+
96+
return result
97+
98+
return wrapper
99+
100+
return decorator
101+
102+
103+
def _warning_matches(pattern, messages, match_type):
104+
"""Helper function to check if pattern matches any message"""
105+
for message in messages:
106+
if match_type == "exact":
107+
if pattern == message:
108+
return True
109+
elif match_type == "contains":
110+
if pattern in message:
111+
return True
112+
elif match_type == "regex":
113+
import re
114+
115+
if re.search(pattern, message):
116+
return True
117+
return False

0 commit comments

Comments
 (0)