waitless 0.1.0__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.
@@ -0,0 +1,243 @@
1
+ Metadata-Version: 2.4
2
+ Name: waitless
3
+ Version: 0.1.0
4
+ Summary: Eliminate explicit waits in UI automation by detecting true UI stability
5
+ Author-email: Dhiraj Das <dhirajdas.66@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/godhiraj-code/waitless
8
+ Project-URL: Documentation, https://github.com/godhiraj-code/waitless#readme
9
+ Project-URL: Repository, https://github.com/godhiraj-code/waitless.git
10
+ Project-URL: Issues, https://github.com/godhiraj-code/waitless/issues
11
+ Keywords: selenium,automation,testing,ui-testing,wait,stability,flaky-tests
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Testing
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == "dev"
27
+ Requires-Dist: selenium>=4.0; extra == "dev"
28
+
29
+ # Waitless
30
+
31
+ **Zero-wait UI automation stabilization for Selenium**
32
+
33
+ Eliminate explicit waits and sleeps by automatically detecting true UI stability.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install waitless
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```python
44
+ from selenium import webdriver
45
+ from selenium.webdriver.common.by import By
46
+ from waitless import stabilize
47
+
48
+ # Create driver as usual
49
+ driver = webdriver.Chrome()
50
+
51
+ # Enable automatic stabilization - ONE LINE
52
+ driver = stabilize(driver)
53
+
54
+ # All interactions now auto-wait for stability
55
+ driver.get("https://example.com")
56
+ driver.find_element(By.ID, "login-button").click() # ← Auto-waits!
57
+ driver.find_element(By.ID, "username").send_keys("user") # ← Auto-waits!
58
+ ```
59
+
60
+ ## Why Waitless?
61
+
62
+ ### The Problem
63
+
64
+ Automation tests fail because interactions happen while the UI is still changing:
65
+
66
+ - DOM mutations from React/Vue/Angular updates
67
+ - In-flight AJAX requests
68
+ - CSS animations and transitions
69
+ - Layout shifts from lazy-loaded content
70
+
71
+ ### Traditional Solutions (and why they fail)
72
+
73
+ | Approach | Problem |
74
+ |----------|---------|
75
+ | `time.sleep(2)` | Too slow, still fails sometimes |
76
+ | `WebDriverWait` | Only checks one element, misses page-wide state |
77
+ | Retries | Masks the real problem, adds flakiness |
78
+
79
+ ### The Waitless Solution
80
+
81
+ Waitless monitors the **entire page** for stability signals:
82
+
83
+ - ✅ DOM mutation activity (MutationObserver)
84
+ - ✅ Pending network requests (XHR/fetch interception)
85
+ - ✅ CSS animations and transitions
86
+ - ✅ Layout stability (element movement)
87
+
88
+ When you interact, waitless ensures the page is truly ready.
89
+
90
+ ## Configuration
91
+
92
+ ```python
93
+ from waitless import stabilize, StabilizationConfig
94
+
95
+ config = StabilizationConfig(
96
+ timeout=5, # Max wait time (seconds)
97
+ dom_settle_time=0.1, # DOM quiet period needed
98
+ network_idle_threshold=0, # Max pending requests (0 = all must complete)
99
+ animation_detection=True, # Wait for animations to finish
100
+ strictness='normal', # 'strict' | 'normal' | 'relaxed'
101
+ debug_mode=True # Enable logging
102
+ )
103
+
104
+ driver = stabilize(driver, config=config)
105
+ ```
106
+
107
+ ### Strictness Levels
108
+
109
+ | Level | What It Waits For |
110
+ |-------|-------------------|
111
+ | `strict` | DOM + Network + Animations + Layout |
112
+ | `normal` | DOM + Network (default) |
113
+ | `relaxed` | DOM only |
114
+
115
+ ### Factory Methods
116
+
117
+ ```python
118
+ # For strict testing
119
+ config = StabilizationConfig.strict()
120
+
121
+ # For apps with background traffic
122
+ config = StabilizationConfig.relaxed()
123
+
124
+ # For CI environments
125
+ config = StabilizationConfig.ci()
126
+ ```
127
+
128
+ ## Manual Stabilization
129
+
130
+ If you don't want to wrap the driver:
131
+
132
+ ```python
133
+ from waitless import wait_for_stability
134
+
135
+ wait_for_stability(driver)
136
+ driver.find_element(By.ID, "button").click()
137
+ ```
138
+
139
+ ## Disabling Stabilization
140
+
141
+ ```python
142
+ from waitless import unstabilize
143
+
144
+ driver = unstabilize(driver) # Back to original behavior
145
+ ```
146
+
147
+ ## Diagnostics
148
+
149
+ When tests fail, get detailed analysis:
150
+
151
+ ```python
152
+ from waitless import get_diagnostics, StabilizationTimeout
153
+ from waitless.diagnostics import print_report
154
+
155
+ try:
156
+ driver.find_element(By.ID, "slow-button").click()
157
+ except StabilizationTimeout as e:
158
+ diagnostics = get_diagnostics(driver)
159
+ print_report(engine) # Print detailed report
160
+ ```
161
+
162
+ ### CLI Doctor Command
163
+
164
+ ```bash
165
+ python -m waitless doctor --file diagnostics.json
166
+ ```
167
+
168
+ Sample output:
169
+ ```
170
+ ╔══════════════════════════════════════════════════════════════════╗
171
+ ║ WAITLESS STABILITY REPORT ║
172
+ ╠══════════════════════════════════════════════════════════════════╣
173
+ ║ BLOCKING FACTORS: ║
174
+ ║ ⚠ NETWORK: 2 request(s) still pending ║
175
+ ║ → GET /api/users ║
176
+ ║ ⚠ ANIMATIONS: 1 active animation(s) ║
177
+ ╠══════════════════════════════════════════════════════════════════╣
178
+ ║ SUGGESTIONS: ║
179
+ ║ 1. Set network_idle_threshold=2 for background traffic ║
180
+ ║ 2. Use animation_detection=False for infinite spinners ║
181
+ ╚══════════════════════════════════════════════════════════════════╝
182
+ ```
183
+
184
+ ## Important Notes
185
+
186
+ ### Network Threshold Warning
187
+
188
+ The default `network_idle_threshold=0` means **all** network requests must complete.
189
+
190
+ Many apps have background traffic that never stops:
191
+ - Analytics calls
192
+ - Long polling
193
+ - Feature flags
194
+ - WebSocket heartbeats
195
+
196
+ If tests timeout frequently, try:
197
+ ```python
198
+ config = StabilizationConfig(network_idle_threshold=2)
199
+ ```
200
+
201
+ ### Wrapped Elements
202
+
203
+ The stabilized driver returns wrapped elements that auto-wait. They behave like WebElements but:
204
+
205
+ - `isinstance(element, WebElement)` returns `False`
206
+ - Use `.unwrap()` to get the original element if needed
207
+
208
+ ```python
209
+ element = driver.find_element(By.ID, "button")
210
+ original = element.unwrap() # Gets the real WebElement
211
+ ```
212
+
213
+ ## v0 Limitations
214
+
215
+ - **Selenium only** - Playwright support planned for v1
216
+ - **Sync only** - No async/await support yet
217
+ - **Main frame only** - iframes not monitored
218
+ - **No Shadow DOM** - MutationObserver doesn't see shadow roots
219
+ - **No Service Workers** - SW network requests not intercepted
220
+
221
+ ## API Reference
222
+
223
+ ### Functions
224
+
225
+ | Function | Description |
226
+ |----------|-------------|
227
+ | `stabilize(driver, config=None)` | Enable auto-stabilization |
228
+ | `unstabilize(driver)` | Disable and return original driver |
229
+ | `wait_for_stability(driver, timeout=None)` | Manual one-time wait |
230
+ | `get_diagnostics(driver)` | Get diagnostic data |
231
+
232
+ ### Classes
233
+
234
+ | Class | Description |
235
+ |-------|-------------|
236
+ | `StabilizationConfig` | Configuration options |
237
+ | `StabilizedWebDriver` | Wrapped driver with auto-wait |
238
+ | `StabilizedWebElement` | Wrapped element with auto-wait |
239
+ | `StabilizationTimeout` | Exception when UI doesn't stabilize |
240
+
241
+ ## License
242
+
243
+ MIT
@@ -0,0 +1,215 @@
1
+ # Waitless
2
+
3
+ **Zero-wait UI automation stabilization for Selenium**
4
+
5
+ Eliminate explicit waits and sleeps by automatically detecting true UI stability.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install waitless
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```python
16
+ from selenium import webdriver
17
+ from selenium.webdriver.common.by import By
18
+ from waitless import stabilize
19
+
20
+ # Create driver as usual
21
+ driver = webdriver.Chrome()
22
+
23
+ # Enable automatic stabilization - ONE LINE
24
+ driver = stabilize(driver)
25
+
26
+ # All interactions now auto-wait for stability
27
+ driver.get("https://example.com")
28
+ driver.find_element(By.ID, "login-button").click() # ← Auto-waits!
29
+ driver.find_element(By.ID, "username").send_keys("user") # ← Auto-waits!
30
+ ```
31
+
32
+ ## Why Waitless?
33
+
34
+ ### The Problem
35
+
36
+ Automation tests fail because interactions happen while the UI is still changing:
37
+
38
+ - DOM mutations from React/Vue/Angular updates
39
+ - In-flight AJAX requests
40
+ - CSS animations and transitions
41
+ - Layout shifts from lazy-loaded content
42
+
43
+ ### Traditional Solutions (and why they fail)
44
+
45
+ | Approach | Problem |
46
+ |----------|---------|
47
+ | `time.sleep(2)` | Too slow, still fails sometimes |
48
+ | `WebDriverWait` | Only checks one element, misses page-wide state |
49
+ | Retries | Masks the real problem, adds flakiness |
50
+
51
+ ### The Waitless Solution
52
+
53
+ Waitless monitors the **entire page** for stability signals:
54
+
55
+ - ✅ DOM mutation activity (MutationObserver)
56
+ - ✅ Pending network requests (XHR/fetch interception)
57
+ - ✅ CSS animations and transitions
58
+ - ✅ Layout stability (element movement)
59
+
60
+ When you interact, waitless ensures the page is truly ready.
61
+
62
+ ## Configuration
63
+
64
+ ```python
65
+ from waitless import stabilize, StabilizationConfig
66
+
67
+ config = StabilizationConfig(
68
+ timeout=5, # Max wait time (seconds)
69
+ dom_settle_time=0.1, # DOM quiet period needed
70
+ network_idle_threshold=0, # Max pending requests (0 = all must complete)
71
+ animation_detection=True, # Wait for animations to finish
72
+ strictness='normal', # 'strict' | 'normal' | 'relaxed'
73
+ debug_mode=True # Enable logging
74
+ )
75
+
76
+ driver = stabilize(driver, config=config)
77
+ ```
78
+
79
+ ### Strictness Levels
80
+
81
+ | Level | What It Waits For |
82
+ |-------|-------------------|
83
+ | `strict` | DOM + Network + Animations + Layout |
84
+ | `normal` | DOM + Network (default) |
85
+ | `relaxed` | DOM only |
86
+
87
+ ### Factory Methods
88
+
89
+ ```python
90
+ # For strict testing
91
+ config = StabilizationConfig.strict()
92
+
93
+ # For apps with background traffic
94
+ config = StabilizationConfig.relaxed()
95
+
96
+ # For CI environments
97
+ config = StabilizationConfig.ci()
98
+ ```
99
+
100
+ ## Manual Stabilization
101
+
102
+ If you don't want to wrap the driver:
103
+
104
+ ```python
105
+ from waitless import wait_for_stability
106
+
107
+ wait_for_stability(driver)
108
+ driver.find_element(By.ID, "button").click()
109
+ ```
110
+
111
+ ## Disabling Stabilization
112
+
113
+ ```python
114
+ from waitless import unstabilize
115
+
116
+ driver = unstabilize(driver) # Back to original behavior
117
+ ```
118
+
119
+ ## Diagnostics
120
+
121
+ When tests fail, get detailed analysis:
122
+
123
+ ```python
124
+ from waitless import get_diagnostics, StabilizationTimeout
125
+ from waitless.diagnostics import print_report
126
+
127
+ try:
128
+ driver.find_element(By.ID, "slow-button").click()
129
+ except StabilizationTimeout as e:
130
+ diagnostics = get_diagnostics(driver)
131
+ print_report(engine) # Print detailed report
132
+ ```
133
+
134
+ ### CLI Doctor Command
135
+
136
+ ```bash
137
+ python -m waitless doctor --file diagnostics.json
138
+ ```
139
+
140
+ Sample output:
141
+ ```
142
+ ╔══════════════════════════════════════════════════════════════════╗
143
+ ║ WAITLESS STABILITY REPORT ║
144
+ ╠══════════════════════════════════════════════════════════════════╣
145
+ ║ BLOCKING FACTORS: ║
146
+ ║ ⚠ NETWORK: 2 request(s) still pending ║
147
+ ║ → GET /api/users ║
148
+ ║ ⚠ ANIMATIONS: 1 active animation(s) ║
149
+ ╠══════════════════════════════════════════════════════════════════╣
150
+ ║ SUGGESTIONS: ║
151
+ ║ 1. Set network_idle_threshold=2 for background traffic ║
152
+ ║ 2. Use animation_detection=False for infinite spinners ║
153
+ ╚══════════════════════════════════════════════════════════════════╝
154
+ ```
155
+
156
+ ## Important Notes
157
+
158
+ ### Network Threshold Warning
159
+
160
+ The default `network_idle_threshold=0` means **all** network requests must complete.
161
+
162
+ Many apps have background traffic that never stops:
163
+ - Analytics calls
164
+ - Long polling
165
+ - Feature flags
166
+ - WebSocket heartbeats
167
+
168
+ If tests timeout frequently, try:
169
+ ```python
170
+ config = StabilizationConfig(network_idle_threshold=2)
171
+ ```
172
+
173
+ ### Wrapped Elements
174
+
175
+ The stabilized driver returns wrapped elements that auto-wait. They behave like WebElements but:
176
+
177
+ - `isinstance(element, WebElement)` returns `False`
178
+ - Use `.unwrap()` to get the original element if needed
179
+
180
+ ```python
181
+ element = driver.find_element(By.ID, "button")
182
+ original = element.unwrap() # Gets the real WebElement
183
+ ```
184
+
185
+ ## v0 Limitations
186
+
187
+ - **Selenium only** - Playwright support planned for v1
188
+ - **Sync only** - No async/await support yet
189
+ - **Main frame only** - iframes not monitored
190
+ - **No Shadow DOM** - MutationObserver doesn't see shadow roots
191
+ - **No Service Workers** - SW network requests not intercepted
192
+
193
+ ## API Reference
194
+
195
+ ### Functions
196
+
197
+ | Function | Description |
198
+ |----------|-------------|
199
+ | `stabilize(driver, config=None)` | Enable auto-stabilization |
200
+ | `unstabilize(driver)` | Disable and return original driver |
201
+ | `wait_for_stability(driver, timeout=None)` | Manual one-time wait |
202
+ | `get_diagnostics(driver)` | Get diagnostic data |
203
+
204
+ ### Classes
205
+
206
+ | Class | Description |
207
+ |-------|-------------|
208
+ | `StabilizationConfig` | Configuration options |
209
+ | `StabilizedWebDriver` | Wrapped driver with auto-wait |
210
+ | `StabilizedWebElement` | Wrapped element with auto-wait |
211
+ | `StabilizationTimeout` | Exception when UI doesn't stabilize |
212
+
213
+ ## License
214
+
215
+ MIT
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "waitless"
7
+ version = "0.1.0"
8
+ description = "Eliminate explicit waits in UI automation by detecting true UI stability"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ {name = "Dhiraj Das", email = "dhirajdas.66@gmail.com"}
14
+ ]
15
+ keywords = [
16
+ "selenium",
17
+ "automation",
18
+ "testing",
19
+ "ui-testing",
20
+ "wait",
21
+ "stability",
22
+ "flaky-tests"
23
+ ]
24
+ classifiers = [
25
+ "Development Status :: 4 - Beta",
26
+ "Intended Audience :: Developers",
27
+ "License :: OSI Approved :: MIT License",
28
+ "Operating System :: OS Independent",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.9",
31
+ "Programming Language :: Python :: 3.10",
32
+ "Programming Language :: Python :: 3.11",
33
+ "Programming Language :: Python :: 3.12",
34
+ "Topic :: Software Development :: Testing",
35
+ "Topic :: Software Development :: Quality Assurance",
36
+ ]
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/godhiraj-code/waitless"
40
+ Documentation = "https://github.com/godhiraj-code/waitless#readme"
41
+ Repository = "https://github.com/godhiraj-code/waitless.git"
42
+ Issues = "https://github.com/godhiraj-code/waitless/issues"
43
+
44
+ [project.scripts]
45
+ waitless = "waitless.__main__:main"
46
+
47
+ [project.optional-dependencies]
48
+ dev = [
49
+ "pytest>=7.0",
50
+ "selenium>=4.0",
51
+ ]
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["."]
55
+ include = ["waitless*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,92 @@
1
+ """
2
+ Waitless - Zero-wait UI automation stabilization library.
3
+
4
+ Eliminate explicit waits and sleeps in UI automation by automatically
5
+ waiting for true UI stability instead of time-based conditions.
6
+
7
+ Basic Usage:
8
+ from waitless import stabilize
9
+
10
+ driver = webdriver.Chrome()
11
+ driver = stabilize(driver) # That's it!
12
+
13
+ # All interactions now auto-wait for stability
14
+ driver.find_element(By.ID, "button").click()
15
+
16
+ Configuration:
17
+ from waitless import stabilize, StabilizationConfig
18
+
19
+ config = StabilizationConfig(
20
+ timeout=5, # Max wait time
21
+ strictness='strict', # All signals must be stable
22
+ debug_mode=True # Enable logging
23
+ )
24
+
25
+ driver = stabilize(driver, config=config)
26
+
27
+ Manual Stabilization:
28
+ from waitless import wait_for_stability
29
+
30
+ wait_for_stability(driver) # Explicit wait
31
+ driver.find_element(...).click()
32
+
33
+ Disable:
34
+ from waitless import unstabilize
35
+
36
+ driver = unstabilize(driver) # Back to original behavior
37
+ """
38
+
39
+ __version__ = '0.1.0'
40
+ __author__ = 'Dhiraj Das'
41
+
42
+ # Public API
43
+ from .config import StabilizationConfig, DEFAULT_CONFIG
44
+ from .selenium_integration import (
45
+ stabilize,
46
+ unstabilize,
47
+ wait_for_stability,
48
+ get_diagnostics,
49
+ StabilizedWebDriver,
50
+ StabilizedWebElement,
51
+ )
52
+ from .exceptions import (
53
+ WaitlessError,
54
+ StabilizationTimeout,
55
+ InstrumentationError,
56
+ ConfigurationError,
57
+ NotStabilizedError,
58
+ )
59
+ from .engine import StabilizationEngine
60
+ from .diagnostics import DiagnosticReport, generate_report, print_report
61
+
62
+ __all__ = [
63
+ # Version
64
+ '__version__',
65
+
66
+ # Main API
67
+ 'stabilize',
68
+ 'unstabilize',
69
+ 'wait_for_stability',
70
+ 'get_diagnostics',
71
+
72
+ # Configuration
73
+ 'StabilizationConfig',
74
+ 'DEFAULT_CONFIG',
75
+
76
+ # Types
77
+ 'StabilizedWebDriver',
78
+ 'StabilizedWebElement',
79
+ 'StabilizationEngine',
80
+
81
+ # Exceptions
82
+ 'WaitlessError',
83
+ 'StabilizationTimeout',
84
+ 'InstrumentationError',
85
+ 'ConfigurationError',
86
+ 'NotStabilizedError',
87
+
88
+ # Diagnostics
89
+ 'DiagnosticReport',
90
+ 'generate_report',
91
+ 'print_report',
92
+ ]