Skip to content

Commit d2572fd

Browse files
committed
simplify
1 parent 5d6e83c commit d2572fd

File tree

10 files changed

+33
-90
lines changed

10 files changed

+33
-90
lines changed

layoutlens/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
"""
66

77
# Import the main API
8+
from .analyzer import VisionAnalyzer
89
from .api.core import AnalysisResult, BatchResult, ComparisonResult, LayoutLens
910
from .api.test_suite import UITestCase, UITestResult, UITestSuite
1011
from .cache import AnalysisCache, create_cache
12+
from .capture import Capture
1113
from .config import Config
1214
from .exceptions import (
1315
AnalysisError,
@@ -40,6 +42,8 @@
4042
"UITestCase",
4143
"UITestSuite",
4244
"UITestResult",
45+
"VisionAnalyzer",
46+
"Capture",
4347
"Config",
4448
# Exceptions
4549
"LayoutLensError",
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import openai
1616
from pydantic import BaseModel, Field, ValidationError
1717

18-
from ..logger import get_logger
19-
from ..prompts import Instructions, PromptTemplate
20-
from ..prompts.experts import AccessibilityExpert
18+
from .logger import get_logger
19+
from .prompts import Instructions, PromptTemplate
20+
from .prompts.experts import AccessibilityExpert
2121

2222

2323
class VisionAnalysisResponse(BaseModel):

layoutlens/api/core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
# Import caching
2929
from ..cache import create_cache
3030

31+
# Import vision components
32+
from ..capture import Capture
33+
3134
# Import custom exceptions
3235
from ..exceptions import (
3336
AnalysisError,
@@ -45,9 +48,6 @@
4548
# Import enhanced prompt system
4649
from ..prompts import Instructions, get_expert
4750

48-
# Import vision components
49-
from ..vision.capture import Capture
50-
5151

5252
@dataclass(slots=True)
5353
class AnalysisResult:
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
from playwright.async_api import async_playwright
1515

16-
from ..config import ViewportConfig
17-
from ..logger import get_logger, log_performance_metric
16+
from .config import ViewportConfig
17+
from .logger import get_logger, log_performance_metric
1818

1919

2020
class Capture:

layoutlens/logger.py

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -25,52 +25,6 @@
2525
"DEBUG": logging.DEBUG,
2626
}
2727

28-
# Sensitive data patterns to redact from logs
29-
SENSITIVE_PATTERNS = [
30-
re.compile(r'(api[_-]?key["\']?\s*[:=]\s*["\']?)([a-zA-Z0-9_-]{10,})', re.IGNORECASE),
31-
re.compile(r'(authorization["\']?\s*[:=]\s*["\']?)([a-zA-Z0-9_.-]{10,})', re.IGNORECASE),
32-
re.compile(r"(bearer\s+)([a-zA-Z0-9_.-]{10,})", re.IGNORECASE),
33-
re.compile(r"(sk-[a-zA-Z0-9]{20,})", re.IGNORECASE), # OpenAI API keys
34-
]
35-
36-
37-
class SensitiveDataFilter(logging.Filter):
38-
"""Filter to redact sensitive information from log messages."""
39-
40-
def filter(self, record: logging.LogRecord) -> bool:
41-
"""Filter and sanitize log record."""
42-
if hasattr(record, "msg") and isinstance(record.msg, str):
43-
record.msg = self.redact_sensitive_data(record.msg)
44-
45-
# Also sanitize args if present
46-
if hasattr(record, "args") and record.args:
47-
if isinstance(record.args, dict):
48-
# For dict args, sanitize values
49-
sanitized_args = {}
50-
for k, v in record.args.items():
51-
if isinstance(v, str):
52-
sanitized_args[k] = self.redact_sensitive_data(v)
53-
else:
54-
sanitized_args[k] = v
55-
record.args = sanitized_args
56-
elif isinstance(record.args, tuple):
57-
# For tuple args, sanitize each element
58-
sanitized_args = []
59-
for arg in record.args:
60-
if isinstance(arg, str):
61-
sanitized_args.append(self.redact_sensitive_data(arg))
62-
else:
63-
sanitized_args.append(arg)
64-
record.args = tuple(sanitized_args)
65-
66-
return True
67-
68-
def redact_sensitive_data(self, text: str) -> str:
69-
"""Redact sensitive data from text using regex patterns."""
70-
for pattern in SENSITIVE_PATTERNS:
71-
text = pattern.sub(r"\1***REDACTED***", text)
72-
return text
73-
7428

7529
def get_logger(name: str) -> logging.Logger:
7630
"""Get a configured logger instance for the given name.
@@ -87,10 +41,6 @@ def get_logger(name: str) -> logging.Logger:
8741
"""
8842
logger = logging.getLogger(f"layoutlens.{name}")
8943

90-
# Add sensitive data filter if not already present
91-
if not any(isinstance(f, SensitiveDataFilter) for f in logger.filters):
92-
logger.addFilter(SensitiveDataFilter())
93-
9444
return logger
9545

9646

@@ -146,7 +96,6 @@ def setup_logging(
14696
console_handler = logging.StreamHandler()
14797
console_handler.setLevel(LOG_LEVELS.get(level.upper(), logging.INFO))
14898
console_handler.setFormatter(formatter)
149-
console_handler.addFilter(SensitiveDataFilter())
15099
root_logger.addHandler(console_handler)
151100

152101
# File handler with rotation
@@ -160,7 +109,6 @@ def setup_logging(
160109
)
161110
file_handler.setLevel(LOG_LEVELS.get(file_level.upper(), logging.DEBUG))
162111
file_handler.setFormatter(formatter)
163-
file_handler.addFilter(SensitiveDataFilter())
164112
root_logger.addHandler(file_handler)
165113

166114

layoutlens/vision/__init__.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/integration/test_simple_workflow.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class TestSimpleWorkflow:
1313
"""Test simple LayoutLens workflows with current architecture."""
1414

15-
@patch("layoutlens.vision.capture.Capture.screenshots")
15+
@patch("layoutlens.capture.Capture.screenshots")
1616
@patch("layoutlens.api.core.acompletion")
1717
@pytest.mark.asyncio
1818
async def test_single_page_analysis(self, mock_acompletion, mock_capture):
@@ -56,7 +56,7 @@ async def test_single_page_analysis(self, mock_acompletion, mock_capture):
5656
# Cleanup
5757
Path(temp_file).unlink()
5858

59-
@patch("layoutlens.vision.capture.Capture.screenshots")
59+
@patch("layoutlens.capture.Capture.screenshots")
6060
@patch("layoutlens.api.core.acompletion")
6161
@pytest.mark.asyncio
6262
async def test_page_comparison(self, mock_acompletion, mock_capture):

tests/test_caching.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ def test_invalid_cache_type(self):
342342
class TestLayoutLensCacheIntegration:
343343
"""Test caching integration with LayoutLens."""
344344

345-
@patch("layoutlens.vision.capture.Capture.screenshots")
345+
@patch("layoutlens.capture.Capture.screenshots")
346346
@patch("layoutlens.api.core.acompletion")
347347
@pytest.mark.asyncio
348348
async def test_cache_hit(self, mock_acompletion, mock_capture):
@@ -383,7 +383,7 @@ async def test_cache_hit(self, mock_acompletion, mock_capture):
383383
assert stats["misses"] == 1
384384
assert stats["hit_rate"] == 0.5
385385

386-
@patch("layoutlens.vision.capture.Capture.screenshots")
386+
@patch("layoutlens.capture.Capture.screenshots")
387387
@patch("layoutlens.api.core.acompletion")
388388
@pytest.mark.asyncio
389389
async def test_cache_disabled(self, mock_acompletion, mock_capture):

tests/test_comprehensive.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def test_config_imports(self):
5656
def test_vision_components(self):
5757
"""Test vision components can be imported."""
5858
try:
59-
from layoutlens.vision import Capture, VisionAnalyzer
59+
from layoutlens import Capture, VisionAnalyzer
6060

6161
self.assertTrue(True, "Vision components imported successfully")
6262
except ImportError as e:
@@ -107,7 +107,7 @@ def test_url_detection(self):
107107

108108
@pytest.mark.asyncio
109109
@patch("layoutlens.api.core.acompletion")
110-
@patch("layoutlens.vision.capture.Capture.screenshots")
110+
@patch("layoutlens.capture.Capture.screenshots")
111111
async def test_analyze_url_flow(self, mock_capture, mock_acompletion):
112112
"""Test the full analyze URL workflow."""
113113
from layoutlens.api.core import LayoutLens
@@ -159,7 +159,7 @@ async def test_analyze_screenshot_flow(self):
159159
with self.assertRaises(LayoutFileNotFoundError):
160160
await lens.analyze("/nonexistent/file.png", "Test query")
161161

162-
@patch("layoutlens.vision.analyzer.openai.OpenAI")
162+
@patch("layoutlens.analyzer.openai.OpenAI")
163163
@pytest.mark.asyncio
164164
async def test_compare_method(self, mock_openai):
165165
"""Test the compare method functionality."""
@@ -216,18 +216,18 @@ class TestVisionComponents(unittest.TestCase):
216216
def setUp(self):
217217
self.mock_api_key = "sk-test-key-12345"
218218

219-
@patch("layoutlens.vision.analyzer.openai.OpenAI")
219+
@patch("layoutlens.analyzer.openai.OpenAI")
220220
def test_vision_analyzer_initialization(self, mock_openai):
221221
"""Test VisionAnalyzer initialization."""
222-
from layoutlens.vision.analyzer import VisionAnalyzer
222+
from layoutlens.analyzer import VisionAnalyzer
223223

224224
analyzer = VisionAnalyzer(api_key=self.mock_api_key)
225225
self.assertEqual(analyzer.model, "gpt-4o-mini")
226226

227227
def test_url_capture_viewports(self):
228228
"""Test Capture viewport configurations."""
229+
from layoutlens.capture import Capture
229230
from layoutlens.config import ViewportConfig
230-
from layoutlens.vision.capture import Capture
231231

232232
capture = Capture()
233233

@@ -260,7 +260,8 @@ def test_layout_comparator(self):
260260
# LayoutComparator functionality is now integrated into LayoutLens.compare()
261261
# This test verifies the old separate class is no longer available
262262
with self.assertRaises(ImportError):
263-
from layoutlens.vision.comparator import LayoutComparator
263+
# LayoutComparator was removed in favor of direct API methods
264+
from layoutlens.comparator import LayoutComparator
264265

265266

266267
class TestGitHubIntegration(unittest.TestCase):
@@ -282,9 +283,8 @@ def test_required_files_exist(self):
282283
required_files = [
283284
"layoutlens/api/__init__.py",
284285
"layoutlens/api/core.py",
285-
"layoutlens/vision/__init__.py",
286-
"layoutlens/vision/analyzer.py",
287-
"layoutlens/vision/capture.py",
286+
"layoutlens/analyzer.py",
287+
"layoutlens/capture.py",
288288
]
289289

290290
for file_path in required_files:
@@ -310,8 +310,8 @@ def test_python_files_syntax(self):
310310
"""Test that all Python files have valid syntax."""
311311
python_files = [
312312
"layoutlens/api/core.py",
313-
"layoutlens/vision/analyzer.py",
314-
"layoutlens/vision/capture.py",
313+
"layoutlens/analyzer.py",
314+
"layoutlens/capture.py",
315315
]
316316

317317
for file_path in python_files:
@@ -364,8 +364,8 @@ def test_missing_dependencies_handling(self):
364364
# This test verifies the dependencies are properly declared.
365365

366366
try:
367-
from layoutlens.vision.analyzer import VisionAnalyzer
368-
from layoutlens.vision.capture import Capture
367+
from layoutlens.analyzer import VisionAnalyzer
368+
from layoutlens.capture import Capture
369369

370370
# If we can import these, dependencies are available
371371
self.assertTrue(True, "Core dependencies are available")

tests/test_exceptions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ async def test_file_not_found_error(self):
143143
assert "Error" in result.answer
144144
assert "nonexistent.png" in result.answer
145145

146-
@patch("layoutlens.vision.capture.Capture.screenshots")
146+
@patch("layoutlens.capture.Capture.screenshots")
147147
@pytest.mark.asyncio
148148
async def test_screenshot_error(self, mock_capture):
149149
"""Test graceful handling when screenshot capture fails."""
@@ -160,7 +160,7 @@ async def test_screenshot_error(self, mock_capture):
160160
assert "Error" in result.answer
161161
assert "Browser failed" in result.answer
162162

163-
@patch("layoutlens.vision.capture.Capture.screenshots")
163+
@patch("layoutlens.capture.Capture.screenshots")
164164
@patch("layoutlens.api.core.acompletion")
165165
@pytest.mark.asyncio
166166
async def test_analysis_error(self, mock_acompletion, mock_capture):
@@ -218,7 +218,7 @@ def test_nested_error_information(self):
218218
class TestGracefulDegradation:
219219
"""Test graceful degradation when errors occur."""
220220

221-
@patch("layoutlens.vision.capture.Capture.screenshots")
221+
@patch("layoutlens.capture.Capture.screenshots")
222222
@patch("layoutlens.api.core.acompletion")
223223
@pytest.mark.asyncio
224224
async def test_analysis_failure_handling(self, mock_acompletion, mock_capture):

0 commit comments

Comments
 (0)