Skip to content

Commit b78975c

Browse files
chore: json output schema
1 parent 22cc614 commit b78975c

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

src/importguard/core.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def run_import_timing(
163163
def check_import(
164164
module: str,
165165
max_ms: float | None = None,
166-
banned: set[str] | None = None,
166+
banned: set[str] | list[str] | None = None,
167167
python_path: str | None = None,
168168
repeat: int = 1,
169169
) -> ImportResult:
@@ -173,14 +173,23 @@ def check_import(
173173
Args:
174174
module: The module to check
175175
max_ms: Maximum allowed import time in milliseconds
176-
banned: Set of banned module names
176+
banned: Set or list of banned module names
177177
python_path: Path to Python interpreter
178178
repeat: Number of times to repeat the measurement
179179
180180
Returns:
181181
ImportResult with timing and violation information
182+
183+
Example:
184+
>>> from importguard import check_import
185+
>>> result = check_import("json", max_ms=100)
186+
>>> print(f"Import took {result.total_ms:.1f}ms")
187+
>>> if not result.passed:
188+
... for v in result.violations:
189+
... print(f"FAIL: {v}")
182190
"""
183-
banned = banned or set()
191+
# Convert list to set if needed
192+
banned_set: set[str] = set(banned) if banned else set()
184193
all_times_us: list[int] = []
185194
all_timings: list[ImportTiming] = []
186195
last_subprocess_result: SubprocessResult | None = None
@@ -252,8 +261,8 @@ def check_import(
252261
)
253262

254263
# Check banned imports
255-
if banned and not result.import_failed:
256-
banned_found = find_banned_imports(all_timings, banned)
264+
if banned_set and not result.import_failed:
265+
banned_found = find_banned_imports(all_timings, banned_set)
257266
result.banned_found = banned_found
258267
for banned_module in banned_found:
259268
violations.append(
@@ -265,4 +274,21 @@ def check_import(
265274
)
266275

267276
result.violations = violations
277+
278+
# Generate warnings (non-fatal issues)
279+
warnings: list[str] = []
280+
281+
# Warn if using wall-time fallback (importtime failed to parse)
282+
if last_subprocess_result:
283+
if last_subprocess_result.importtime_us == 0 and last_subprocess_result.wall_time_us > 0:
284+
warnings.append("Using wall-clock time (importtime parsing failed)")
285+
286+
# Warn if import time is close to budget (within 20%)
287+
if max_ms is not None and not result.import_failed:
288+
final_ms = final_time_us / 1000.0
289+
if final_ms <= max_ms and final_ms > max_ms * 0.8:
290+
headroom = max_ms - final_ms
291+
warnings.append(f"Import time is close to budget ({headroom:.0f}ms headroom)")
292+
293+
result.warnings = warnings
268294
return result

src/importguard/models.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class ImportResult:
8181
total_time_us: int # total import time in microseconds
8282
imports: list[ImportTiming] = field(default_factory=list)
8383
violations: list[Violation] = field(default_factory=list)
84+
warnings: list[str] = field(default_factory=list) # Non-fatal warnings
8485
banned_found: list[str] = field(default_factory=list)
8586

8687
# For --repeat functionality
@@ -126,7 +127,16 @@ def top_imports(self, n: int = 10) -> list[ImportTiming]:
126127
return sorted(self.imports, key=lambda x: x.self_time_us, reverse=True)[:n]
127128

128129
def to_dict(self) -> dict[str, object]:
129-
"""Convert to dictionary for JSON output."""
130+
"""Convert to dictionary for JSON output.
131+
132+
Returns a machine-readable schema with:
133+
- module: str
134+
- total_ms: float
135+
- top_imports: list[{module, self_ms, cumulative_ms}]
136+
- passed: bool
137+
- violations: list[{type, message, module}]
138+
- warnings: list[str]
139+
"""
130140
result: dict[str, object] = {
131141
"module": self.module,
132142
"total_ms": self.total_ms,
@@ -140,6 +150,7 @@ def to_dict(self) -> dict[str, object]:
140150
{"type": v.type.value, "message": v.message, "module": v.module}
141151
for v in self.violations
142152
],
153+
"warnings": self.warnings,
143154
"banned_found": self.banned_found,
144155
"top_imports": [
145156
{

0 commit comments

Comments
 (0)