selenium-selector-autocorrect 0.1.0__tar.gz → 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (16) hide show
  1. {selenium_selector_autocorrect-0.1.0/src/selenium_selector_autocorrect.egg-info → selenium_selector_autocorrect-0.1.1}/PKG-INFO +1 -1
  2. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/pyproject.toml +5 -4
  3. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect/__init__.py +1 -1
  4. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect/ai_providers.py +9 -8
  5. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect/auto_correct.py +39 -19
  6. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect/correction_tracker.py +44 -19
  7. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect/wait_hook.py +50 -19
  8. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1/src/selenium_selector_autocorrect.egg-info}/PKG-INFO +1 -1
  9. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect.egg-info/SOURCES.txt +0 -1
  10. selenium_selector_autocorrect-0.1.0/src/selenium_selector_autocorrect/py.typed +0 -1
  11. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/LICENSE +0 -0
  12. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/README.md +0 -0
  13. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/setup.cfg +0 -0
  14. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect.egg-info/dependency_links.txt +0 -0
  15. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect.egg-info/requires.txt +0 -0
  16. {selenium_selector_autocorrect-0.1.0 → selenium_selector_autocorrect-0.1.1}/src/selenium_selector_autocorrect.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: selenium-selector-autocorrect
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Automatic Selenium selector correction using AI when elements fail to be found
5
5
  Author-email: Marty Zhou <marty.zhou@example.com>
6
6
  Maintainer-email: Marty Zhou <marty.zhou@example.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "selenium-selector-autocorrect"
7
- version = "0.1.0"
7
+ version = "0.1.1"
8
8
  description = "Automatic Selenium selector correction using AI when elements fail to be found"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -80,11 +80,12 @@ line_length = 120
80
80
  src_paths = ["src"]
81
81
 
82
82
  [tool.mypy]
83
- python_version = "3.8"
83
+ python_version = "3.9"
84
84
  warn_return_any = true
85
85
  warn_unused_configs = true
86
- disallow_untyped_defs = false
87
- ignore_missing_imports = true
86
+ disallow_untyped_defs = true
87
+ strict = true
88
+ ignore_missing_imports = false
88
89
 
89
90
  [tool.ruff]
90
91
  line-length = 120
@@ -15,7 +15,7 @@ Environment Variables:
15
15
  SELENIUM_AUTO_UPDATE_TESTS: Auto-update test files with corrections (default: "0")
16
16
  """
17
17
 
18
- __version__ = "1.0.0"
18
+ __version__ = "0.1.1"
19
19
 
20
20
  from .ai_providers import AIProvider, LocalAIProvider, configure_provider, get_provider
21
21
  from .auto_correct import (
@@ -3,7 +3,7 @@
3
3
  import logging
4
4
  import os
5
5
  from abc import ABC, abstractmethod
6
- from typing import Optional
6
+ from typing import Any, Dict, Optional
7
7
 
8
8
  import requests
9
9
 
@@ -40,9 +40,9 @@ class LocalAIProvider(AIProvider):
40
40
  LOCAL_AI_API_URL environment variable (default: http://localhost:8765)
41
41
  """
42
42
 
43
- def __init__(self, base_url: str = None):
44
- self.base_url = base_url or os.environ.get("LOCAL_AI_API_URL", "http://localhost:8765")
45
- self._available = None
43
+ def __init__(self, base_url: Optional[str] = None) -> None:
44
+ self.base_url: str = base_url or os.environ.get("LOCAL_AI_API_URL", "http://localhost:8765")
45
+ self._available: Optional[bool] = None
46
46
 
47
47
  def is_available(self) -> bool:
48
48
  if self._available is not None:
@@ -83,8 +83,9 @@ class LocalAIProvider(AIProvider):
83
83
  timeout=30
84
84
  )
85
85
  response.raise_for_status()
86
- data = response.json()
87
- return data.get("choices", [{}])[0].get("message", {}).get("content", "")
86
+ data: Dict[str, Any] = response.json()
87
+ content: Optional[str] = data.get("choices", [{}])[0].get("message", {}).get("content", "")
88
+ return content
88
89
  except requests.exceptions.HTTPError as e:
89
90
  if e.response.status_code == 503:
90
91
  logger.info(f"Local AI service unavailable (503). Disabling auto-correction.")
@@ -110,7 +111,7 @@ def get_provider() -> AIProvider:
110
111
  return _provider_instance
111
112
 
112
113
 
113
- def configure_provider(provider: AIProvider):
114
+ def configure_provider(provider: AIProvider) -> None:
114
115
  """Set a custom AI provider.
115
116
 
116
117
  Args:
@@ -120,4 +121,4 @@ def configure_provider(provider: AIProvider):
120
121
  _provider_instance = provider
121
122
 
122
123
 
123
- _provider_instance = None
124
+ _provider_instance: Optional[AIProvider] = None
@@ -4,9 +4,13 @@ import json
4
4
  import logging
5
5
  import os
6
6
  import re
7
- from typing import Any, Dict, Optional, Tuple
7
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple
8
8
 
9
- from .ai_providers import get_provider
9
+ from .ai_providers import AIProvider, get_provider
10
+
11
+ if TYPE_CHECKING:
12
+ from selenium.webdriver.remote.webdriver import WebDriver
13
+ from selenium.webdriver.remote.webelement import WebElement
10
14
 
11
15
  logger = logging.getLogger(__name__)
12
16
 
@@ -18,22 +22,22 @@ class SelectorAutoCorrect:
18
22
  enabled: Whether auto-correction is enabled
19
23
  """
20
24
 
21
- def __init__(self, enabled: bool = True):
22
- self.enabled = enabled
23
- self._provider = None
25
+ def __init__(self, enabled: bool = True) -> None:
26
+ self.enabled: bool = enabled
27
+ self._provider: Optional[AIProvider] = None
24
28
  self._correction_cache: Dict[str, str] = {}
25
29
  self._suggestion_cache: Dict[str, str] = {}
26
- self.suggest_better_selectors = os.environ.get("SELENIUM_SUGGEST_BETTER", "0").lower() in ("1", "true", "yes")
27
- self._confidence_threshold = 50
28
- self._cache_enabled = True
30
+ self.suggest_better_selectors: bool = os.environ.get("SELENIUM_SUGGEST_BETTER", "0").lower() in ("1", "true", "yes")
31
+ self._confidence_threshold: int = 50
32
+ self._cache_enabled: bool = True
29
33
 
30
34
  @property
31
- def provider(self):
35
+ def provider(self) -> AIProvider:
32
36
  if self._provider is None:
33
37
  self._provider = get_provider()
34
38
  return self._provider
35
39
 
36
- def set_provider(self, provider) -> None:
40
+ def set_provider(self, provider: AIProvider) -> None:
37
41
  self._provider = provider
38
42
 
39
43
  def is_service_available(self) -> bool:
@@ -42,7 +46,7 @@ class SelectorAutoCorrect:
42
46
  provider = self.provider
43
47
  return provider is not None and provider.is_available()
44
48
 
45
- def get_visible_elements_summary(self, driver) -> str:
49
+ def get_visible_elements_summary(self, driver: "WebDriver") -> str:
46
50
  try:
47
51
  script = """
48
52
  function getElementSummary() {
@@ -86,7 +90,13 @@ class SelectorAutoCorrect:
86
90
  logger.warning(f"Failed to get element summary: {e}")
87
91
  return "[]"
88
92
 
89
- def suggest_selector(self, driver, failed_by: str, failed_value: str, error_message: str = "") -> Optional[Tuple[str, str]]:
93
+ def suggest_selector(
94
+ self,
95
+ driver: "WebDriver",
96
+ failed_by: str,
97
+ failed_value: str,
98
+ error_message: str = ""
99
+ ) -> Optional[Tuple[str, str]]:
90
100
  if not self.enabled or not self.is_service_available():
91
101
  return None
92
102
 
@@ -139,7 +149,13 @@ Suggest a working selector. Respond with ONLY a JSON object."""
139
149
  logger.warning(f"[AUTO-CORRECT] Failed to get suggestion: {e}")
140
150
  return None
141
151
 
142
- def suggest_better_selector(self, driver, current_by: str, current_value: str, element) -> Optional[Tuple[str, str]]:
152
+ def suggest_better_selector(
153
+ self,
154
+ driver: "WebDriver",
155
+ current_by: str,
156
+ current_value: str,
157
+ element: "WebElement"
158
+ ) -> Optional[Tuple[str, str]]:
143
159
  if not self.suggest_better_selectors or not self.enabled or not self.is_service_available():
144
160
  return None
145
161
 
@@ -182,12 +198,12 @@ Available Elements:
182
198
  if self._cache_enabled:
183
199
  self._suggestion_cache[cache_key] = "OPTIMAL"
184
200
  except Exception as e:
185
- logger.debug(f"[SUGGEST] Failed to get better selector: {e}")
201
+ logger.debug(f"[AUTO-SUGGEST] Failed to get better selector: {e}")
186
202
  return None
187
203
 
188
- def _get_element_info(self, element) -> Dict[str, Any]:
204
+ def _get_element_info(self, element: "WebElement") -> Dict[str, Any]:
189
205
  try:
190
- info = {
206
+ info: Dict[str, Any] = {
191
207
  "tag": element.tag_name,
192
208
  "id": element.get_attribute("id"),
193
209
  "name": element.get_attribute("name"),
@@ -223,7 +239,7 @@ Available Elements:
223
239
  logger.warning(f"[AUTO-CORRECT] Error parsing suggestion: {e}")
224
240
  return None
225
241
 
226
- def clear_cache(self):
242
+ def clear_cache(self) -> None:
227
243
  self._correction_cache.clear()
228
244
  self._suggestion_cache.clear()
229
245
 
@@ -240,12 +256,16 @@ def get_auto_correct() -> SelectorAutoCorrect:
240
256
  return _auto_correct_instance
241
257
 
242
258
 
243
- def set_auto_correct_enabled(enabled: bool):
259
+ def set_auto_correct_enabled(enabled: bool) -> None:
244
260
  """Enable or disable auto-correction globally."""
245
261
  get_auto_correct().enabled = enabled
246
262
 
247
263
 
248
- def configure_auto_correct(provider=None, enabled: bool = True, suggest_better: bool = False):
264
+ def configure_auto_correct(
265
+ provider: Optional[AIProvider] = None,
266
+ enabled: bool = True,
267
+ suggest_better: bool = False
268
+ ) -> None:
249
269
  """Configure auto-correction settings."""
250
270
  auto_correct = get_auto_correct()
251
271
  auto_correct.enabled = enabled
@@ -5,20 +5,40 @@ import logging
5
5
  import os
6
6
  import traceback
7
7
  from datetime import datetime
8
- from typing import Any, Dict, List, Optional
8
+ from typing import Any, Dict, List, Optional, TypedDict
9
9
 
10
10
  import requests
11
11
 
12
12
  logger = logging.getLogger(__name__)
13
13
 
14
14
 
15
+ class CorrectionRecord(TypedDict, total=False):
16
+ """Type definition for a correction record."""
17
+ original_by: str
18
+ original_value: str
19
+ corrected_by: str
20
+ corrected_value: str
21
+ success: bool
22
+ test_file: Optional[str]
23
+ test_line: Optional[int]
24
+ timestamp: str
25
+
26
+
27
+ class ApplyCorrectionsResult(TypedDict):
28
+ """Type definition for apply_all_corrections result."""
29
+ total: int
30
+ success: int
31
+ failed: int
32
+ details: List[Dict[str, Any]]
33
+
34
+
15
35
  class CorrectionTracker:
16
36
  """Tracks selector corrections and manages test file updates."""
17
37
 
18
- def __init__(self):
19
- self._corrections: List[Dict[str, Any]] = []
20
- self._local_ai_url = os.environ.get("LOCAL_AI_API_URL", "http://localhost:8765")
21
- self._auto_update_enabled = os.environ.get("SELENIUM_AUTO_UPDATE_TESTS", "0").lower() in ("1", "true", "yes")
38
+ def __init__(self) -> None:
39
+ self._corrections: List[CorrectionRecord] = []
40
+ self._local_ai_url: str = os.environ.get("LOCAL_AI_API_URL", "http://localhost:8765")
41
+ self._auto_update_enabled: bool = os.environ.get("SELENIUM_AUTO_UPDATE_TESTS", "0").lower() in ("1", "true", "yes")
22
42
 
23
43
  def record_correction(
24
44
  self,
@@ -29,7 +49,7 @@ class CorrectionTracker:
29
49
  success: bool = True,
30
50
  test_file: Optional[str] = None,
31
51
  test_line: Optional[int] = None
32
- ):
52
+ ) -> None:
33
53
  if test_file is None or test_line is None:
34
54
  # Extract from stack trace, prioritizing actual test files
35
55
  for frame in traceback.extract_stack():
@@ -56,7 +76,7 @@ class CorrectionTracker:
56
76
  if 'test_' in filename or 'test_library' in filename:
57
77
  break
58
78
 
59
- correction = {
79
+ correction: CorrectionRecord = {
60
80
  "original_by": original_by,
61
81
  "original_value": original_value,
62
82
  "corrected_by": corrected_by,
@@ -79,16 +99,16 @@ class CorrectionTracker:
79
99
  logger.info(f"[AUTO-UPDATE] Attempting to update {test_file}...")
80
100
  self._auto_update_test_file(correction)
81
101
 
82
- def get_corrections(self) -> List[Dict[str, Any]]:
102
+ def get_corrections(self) -> List[CorrectionRecord]:
83
103
  return self._corrections.copy()
84
104
 
85
- def get_successful_corrections(self) -> List[Dict[str, Any]]:
105
+ def get_successful_corrections(self) -> List[CorrectionRecord]:
86
106
  return [c for c in self._corrections if c.get("success", False)]
87
107
 
88
- def clear_corrections(self):
108
+ def clear_corrections(self) -> None:
89
109
  self._corrections.clear()
90
110
 
91
- def _auto_update_test_file(self, correction: Dict[str, Any]):
111
+ def _auto_update_test_file(self, correction: CorrectionRecord) -> None:
92
112
  try:
93
113
  test_file = correction.get("test_file")
94
114
  if not test_file:
@@ -148,7 +168,8 @@ class CorrectionTracker:
148
168
  timeout=30
149
169
  )
150
170
  edit_response.raise_for_status()
151
- return edit_response.json()
171
+ result: Dict[str, Any] = edit_response.json()
172
+ return result
152
173
  except requests.exceptions.ConnectionError:
153
174
  logger.warning(f"[LOCAL AI SERVICE] Not available at {self._local_ai_url}")
154
175
  return {"success": False, "errors": ["Local AI service not available"]}
@@ -156,7 +177,7 @@ class CorrectionTracker:
156
177
  logger.warning(f"[UPDATE ERROR] {e}")
157
178
  return {"success": False, "errors": [str(e)]}
158
179
 
159
- def export_corrections_report(self, output_file: str = "selector_corrections.json"):
180
+ def export_corrections_report(self, output_file: str = "selector_corrections.json") -> None:
160
181
  with open(output_file, "w") as f:
161
182
  json.dump({
162
183
  "corrections": self._corrections,
@@ -168,8 +189,8 @@ class CorrectionTracker:
168
189
  }, f, indent=2)
169
190
  logger.info(f"[CORRECTIONS REPORT] Exported to {output_file}")
170
191
 
171
- def apply_all_corrections_to_files(self) -> Dict[str, Any]:
172
- results = {"total": 0, "success": 0, "failed": 0, "details": []}
192
+ def apply_all_corrections_to_files(self) -> ApplyCorrectionsResult:
193
+ results: ApplyCorrectionsResult = {"total": 0, "success": 0, "failed": 0, "details": []}
173
194
  for correction in self.get_successful_corrections():
174
195
  test_file = correction.get("test_file")
175
196
  if not test_file:
@@ -208,19 +229,23 @@ def get_correction_tracker() -> CorrectionTracker:
208
229
 
209
230
 
210
231
  def record_correction(
211
- original_by: str, original_value: str, corrected_by: str, corrected_value: str, success: bool = True
212
- ):
232
+ original_by: str,
233
+ original_value: str,
234
+ corrected_by: str,
235
+ corrected_value: str,
236
+ success: bool = True
237
+ ) -> None:
213
238
  """Record a selector correction."""
214
239
  get_correction_tracker().record_correction(
215
240
  original_by, original_value, corrected_by, corrected_value, success
216
241
  )
217
242
 
218
243
 
219
- def apply_corrections_to_test_files() -> Dict[str, Any]:
244
+ def apply_corrections_to_test_files() -> ApplyCorrectionsResult:
220
245
  """Apply all successful corrections to their source test files."""
221
246
  return get_correction_tracker().apply_all_corrections_to_files()
222
247
 
223
248
 
224
- def export_corrections_report(output_file: str = "selector_corrections.json"):
249
+ def export_corrections_report(output_file: str = "selector_corrections.json") -> None:
225
250
  """Export corrections report to JSON file."""
226
251
  get_correction_tracker().export_corrections_report(output_file)
@@ -2,9 +2,10 @@
2
2
 
3
3
  import logging
4
4
  import time
5
- from typing import Callable, Optional
5
+ from typing import Any, Callable, Optional, Tuple, TypeVar, Union, cast
6
6
 
7
7
  from selenium.common.exceptions import TimeoutException
8
+ from selenium.webdriver.remote.webdriver import WebDriver
8
9
  from selenium.webdriver.remote.webelement import WebElement
9
10
  from selenium.webdriver.support.wait import WebDriverWait
10
11
 
@@ -13,19 +14,41 @@ from .correction_tracker import record_correction
13
14
 
14
15
  logger = logging.getLogger(__name__)
15
16
 
16
- _original_until = WebDriverWait.until
17
+ T = TypeVar("T")
18
+ DriverType = Union[WebDriver, WebElement]
17
19
 
20
+ _original_until: Callable[..., Any] = WebDriverWait.until
18
21
 
19
- def _patched_until(self, method: Callable, message: str = ""):
22
+
23
+ def _patched_until(self: WebDriverWait, method: Callable[[WebDriver], T], message: str = "") -> T:
20
24
  """Patched until method with auto-correct support."""
21
- screen = None
22
- stacktrace = None
25
+ screen: Optional[str] = None
26
+ stacktrace: Optional[str] = None
23
27
 
24
28
  end_time = time.monotonic() + self._timeout
25
29
  while True:
26
30
  try:
27
31
  value = method(self._driver)
28
32
  if value:
33
+ # Check if we should suggest a better selector for the found element
34
+ auto_correct = get_auto_correct()
35
+ if auto_correct.suggest_better_selectors and isinstance(value, WebElement):
36
+ locator = _extract_locator_from_method(method)
37
+ if locator:
38
+ by, value_str = locator
39
+ suggest_driver: WebDriver
40
+ if isinstance(self._driver, WebElement):
41
+ suggest_driver = self._driver.parent # type: ignore[attr-defined]
42
+ else:
43
+ suggest_driver = self._driver
44
+
45
+ better_suggestion = auto_correct.suggest_better_selector(
46
+ suggest_driver, by, value_str, value
47
+ )
48
+ if better_suggestion:
49
+ better_by, better_value = better_suggestion
50
+ logger.info(f"[AUTO-SUGGEST] Found element with {by}='{value_str[:50]}...'")
51
+ logger.info(f"[AUTO-SUGGEST] Suggested better selector: {better_by}='{better_value}'")
29
52
  return value
30
53
  except self._ignored_exceptions as exc:
31
54
  screen = getattr(exc, "screen", None)
@@ -43,9 +66,11 @@ def _patched_until(self, method: Callable, message: str = ""):
43
66
  f"[AUTO-CORRECT] Timeout waiting for element {by}='{value_str[:80]}...' - attempting auto-correction"
44
67
  )
45
68
 
46
- driver = self._driver
47
- if isinstance(driver, WebElement):
48
- driver = driver.parent
69
+ driver: WebDriver
70
+ if isinstance(self._driver, WebElement):
71
+ driver = self._driver.parent # type: ignore[attr-defined]
72
+ else:
73
+ driver = self._driver
49
74
 
50
75
  suggestion = auto_correct.suggest_selector(
51
76
  driver,
@@ -71,35 +96,41 @@ def _patched_until(self, method: Callable, message: str = ""):
71
96
  corrected_value=suggested_value,
72
97
  success=True,
73
98
  )
74
- return result
99
+ return cast(T, result)
75
100
  except Exception as e:
76
101
  logger.warning(f"[AUTO-CORRECT] Suggested selector also failed: {e}")
77
102
 
78
103
  raise TimeoutException(message, screen, stacktrace)
79
104
 
80
105
 
81
- def _extract_locator_from_method(method: Callable) -> Optional[tuple]:
106
+ def _extract_locator_from_method(method: Callable[..., Any]) -> Optional[Tuple[str, str]]:
82
107
  """Extract locator tuple (by, value) from an expected_conditions method."""
83
108
  try:
84
109
  if hasattr(method, "locator"):
85
- logger.debug(f"[AUTO-CORRECT] Found locator attribute: {method.locator}")
86
- return method.locator
110
+ locator: Tuple[str, str] = method.locator
111
+ logger.debug(f"[AUTO-CORRECT] Found locator attribute: {locator}")
112
+ return locator
87
113
 
88
114
  if hasattr(method, "__closure__") and method.__closure__:
89
115
  for cell in method.__closure__:
90
116
  cell_contents = cell.cell_contents
91
117
  logger.debug(f"[AUTO-CORRECT] Checking closure cell: {type(cell_contents)} = {cell_contents}")
92
118
  if isinstance(cell_contents, tuple) and len(cell_contents) == 2:
93
- if isinstance(cell_contents[0], str) and isinstance(cell_contents[1], str):
119
+ first, second = cell_contents
120
+ if isinstance(first, str) and isinstance(second, str):
94
121
  logger.debug(f"[AUTO-CORRECT] Extracted locator from closure: {cell_contents}")
95
- return cell_contents
122
+ return (first, second)
96
123
  logger.warning(f"[AUTO-CORRECT] Could not extract locator from method: {method}")
97
124
  except Exception as e:
98
125
  logger.exception(f"[AUTO-CORRECT] Error extracting locator: {e}")
99
126
  return None
100
127
 
101
128
 
102
- def _create_corrected_method(original_method: Callable, new_by: str, new_value: str) -> Optional[Callable]:
129
+ def _create_corrected_method(
130
+ original_method: Callable[..., Any],
131
+ new_by: str,
132
+ new_value: str
133
+ ) -> Optional[Callable[[WebDriver], Any]]:
103
134
  """Create a new expected condition method with corrected locator."""
104
135
  try:
105
136
  from selenium.webdriver.support import expected_conditions as EC
@@ -128,13 +159,13 @@ def _create_corrected_method(original_method: Callable, new_by: str, new_value:
128
159
  return None
129
160
 
130
161
 
131
- def install_auto_correct_hook():
162
+ def install_auto_correct_hook() -> None:
132
163
  """Install the auto-correct hook into WebDriverWait."""
133
- WebDriverWait.until = _patched_until
164
+ WebDriverWait.until = _patched_until # type: ignore[method-assign,assignment]
134
165
  logger.info("[AUTO-CORRECT] Hook installed into WebDriverWait")
135
166
 
136
167
 
137
- def uninstall_auto_correct_hook():
168
+ def uninstall_auto_correct_hook() -> None:
138
169
  """Remove the auto-correct hook from WebDriverWait."""
139
- WebDriverWait.until = _original_until
170
+ WebDriverWait.until = _original_until # type: ignore[method-assign]
140
171
  logger.info("[AUTO-CORRECT] Hook removed from WebDriverWait")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: selenium-selector-autocorrect
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Automatic Selenium selector correction using AI when elements fail to be found
5
5
  Author-email: Marty Zhou <marty.zhou@example.com>
6
6
  Maintainer-email: Marty Zhou <marty.zhou@example.com>
@@ -5,7 +5,6 @@ src/selenium_selector_autocorrect/__init__.py
5
5
  src/selenium_selector_autocorrect/ai_providers.py
6
6
  src/selenium_selector_autocorrect/auto_correct.py
7
7
  src/selenium_selector_autocorrect/correction_tracker.py
8
- src/selenium_selector_autocorrect/py.typed
9
8
  src/selenium_selector_autocorrect/wait_hook.py
10
9
  src/selenium_selector_autocorrect.egg-info/PKG-INFO
11
10
  src/selenium_selector_autocorrect.egg-info/SOURCES.txt
@@ -1 +0,0 @@
1
- # Type hints marker for PEP 561