watchdiff-core 0.1.3__tar.gz → 0.1.4__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 (41) hide show
  1. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/PKG-INFO +28 -28
  2. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/README.md +27 -27
  3. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/pyproject.toml +1 -1
  4. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/uv.lock +1 -1
  5. watchdiff_core-0.1.4/watchdiff/cli/main.py +491 -0
  6. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/core.py +147 -55
  7. watchdiff_core-0.1.4/watchdiff/diff/engine.py +239 -0
  8. watchdiff_core-0.1.4/watchdiff/fetcher/fetcher.py +161 -0
  9. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/models.py +77 -19
  10. watchdiff_core-0.1.4/watchdiff/notifier/notifier.py +122 -0
  11. watchdiff_core-0.1.4/watchdiff/scheduler/scheduler.py +523 -0
  12. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/store/sqlite_store.py +10 -0
  13. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/store/store.py +7 -0
  14. watchdiff_core-0.1.3/watchdiff/cli/main.py +0 -362
  15. watchdiff_core-0.1.3/watchdiff/diff/engine.py +0 -149
  16. watchdiff_core-0.1.3/watchdiff/fetcher/fetcher.py +0 -122
  17. watchdiff_core-0.1.3/watchdiff/notifier/notifier.py +0 -81
  18. watchdiff_core-0.1.3/watchdiff/scheduler/scheduler.py +0 -267
  19. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/.github/workflows/ci.yml +0 -0
  20. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/.github/workflows/release-testpypi.yml +0 -0
  21. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/.github/workflows/release.yml +0 -0
  22. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/.gitignore +0 -0
  23. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/.python-version +0 -0
  24. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/LICENSE +0 -0
  25. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/main.py +0 -0
  26. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/tests/__init__.py +0 -0
  27. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/tests/test_watchdiff.py +0 -0
  28. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/__init__.py +0 -0
  29. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/cleaner/__init__.py +0 -0
  30. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/cleaner/cleaner.py +0 -0
  31. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/cli/__init__.py +0 -0
  32. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/diff/__init__.py +0 -0
  33. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/exporter/__init__.py +0 -0
  34. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/exporter/exporter.py +0 -0
  35. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/fetcher/__init__.py +0 -0
  36. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/fetcher/browser.py +0 -0
  37. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/notifier/__init__.py +0 -0
  38. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/parser/__init__.py +0 -0
  39. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/parser/parser.py +0 -0
  40. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/scheduler/__init__.py +0 -0
  41. {watchdiff_core-0.1.3 → watchdiff_core-0.1.4}/watchdiff/store/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: watchdiff-core
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Lightweight web change monitoring library - clean diffs, structured alerts, no AI required.
5
5
  Author: WatchDiff Contributors
6
6
  License: GPL-3.0-or-later
@@ -85,13 +85,13 @@ No noisy HTML diffs. No external services. No AI black boxes.
85
85
 
86
86
  ## Why WatchDiff?
87
87
 
88
- Most change detection tools compare raw HTML which means every minor script reload or ad rotation triggers a false positive. WatchDiff strips the noise first, then diffs only the content that matters.
88
+ Most change detection tools compare raw HTML - which means every minor script reload or ad rotation triggers a false positive. WatchDiff strips the noise first, then diffs only the content that matters.
89
89
 
90
- - **Deterministic** same input always produces the same output
91
- - **Human-readable diffs** "Price changed: $19 → $24", not a wall of HTML
92
- - **Zero external services** snapshots stored locally (JSON or SQLite)
93
- - **Async-ready** sync and async schedulers included
94
- - **Python 3.9+** works on Debian Bullseye, Bookworm, and Trixie
90
+ - **Deterministic** - same input always produces the same output
91
+ - **Human-readable diffs** - "Price changed: $19 → $24", not a wall of HTML
92
+ - **Zero external services** - snapshots stored locally (JSON or SQLite)
93
+ - **Async-ready** - sync and async schedulers included
94
+ - **Python 3.9+** - works on Debian Bullseye, Bookworm, and Trixie
95
95
 
96
96
 
97
97
  ## Install
@@ -194,9 +194,9 @@ wd.start()
194
194
  ```
195
195
 
196
196
  `wait_for` accepts:
197
- - `"load"` default, waits for the `load` event
198
- - `"domcontentloaded"` faster, waits for DOM only
199
- - `"networkidle"` waits until no network requests for 500ms
197
+ - `"load"` - default, waits for the `load` event
198
+ - `"domcontentloaded"` - faster, waits for DOM only
199
+ - `"networkidle"` - waits until no network requests for 500ms
200
200
 
201
201
 
202
202
  ### Proxy rotation and User-Agent rotation
@@ -220,12 +220,12 @@ wd.watch(
220
220
 
221
221
  If `user_agents` is empty, WatchDiff rotates automatically among **4 built-in modern UA strings** (Chrome, Safari, Firefox, Chrome Linux). No configuration required.
222
222
 
223
- Proxies also work in browser mode Playwright passes the selected proxy to Chromium.
223
+ Proxies also work in browser mode - Playwright passes the selected proxy to Chromium.
224
224
 
225
225
 
226
226
  ### Semantic diff mode
227
227
 
228
- By default, WatchDiff diffs line by line. In **semantic mode**, it extracts meaningful HTML blocks `<p>`, `<h1>`-`<h6>`, `<li>`, `<td>`, `<th>`, `<blockquote>` and diffs those instead. This gives cleaner results on content-heavy pages where a single paragraph change doesn't shift dozens of lines.
228
+ By default, WatchDiff diffs line by line. In **semantic mode**, it extracts meaningful HTML blocks - `<p>`, `<h1>`-`<h6>`, `<li>`, `<td>`, `<th>`, `<blockquote>` - and diffs those instead. This gives cleaner results on content-heavy pages where a single paragraph change doesn't shift dozens of lines.
229
229
 
230
230
  ```python
231
231
  wd.watch(
@@ -260,12 +260,12 @@ wd.watch("https://example.com", target="(//h2)[1]") # first <h2> only
260
260
  wd.watch("https://example.com", target="//p[contains(@class,'intro')]")
261
261
  ```
262
262
 
263
- XPath is implemented via `lxml` (already a dependency no extra install needed).
263
+ XPath is implemented via `lxml` (already a dependency - no extra install needed).
264
264
 
265
265
 
266
266
  ### SQLite storage backend
267
267
 
268
- By default, WatchDiff stores data as JSON files. For larger datasets or concurrent access, switch to the built-in SQLite backend no extra dependencies required:
268
+ By default, WatchDiff stores data as JSON files. For larger datasets or concurrent access, switch to the built-in SQLite backend - no extra dependencies required:
269
269
 
270
270
  ```python
271
271
  from watchdiff import WatchDiff
@@ -275,7 +275,7 @@ wd = WatchDiff(store=SqliteStore(".watchdiff.db"))
275
275
  wd.watch("https://example.com").start()
276
276
  ```
277
277
 
278
- `SqliteStore` is a **drop-in replacement** for the default `Store` same interface, same behaviour. It runs in WAL mode for concurrent-read safety.
278
+ `SqliteStore` is a **drop-in replacement** for the default `Store` - same interface, same behaviour. It runs in WAL mode for concurrent-read safety.
279
279
 
280
280
 
281
281
  ### CSV and XLSX export
@@ -298,10 +298,10 @@ path = wd.export_snapshots_xlsx("https://example.com", dest="snapshots.xlsx")
298
298
  ```
299
299
 
300
300
  All export methods accept:
301
- - `url` the watched URL
302
- - `target` CSS/XPath filter (optional, `None` = full page)
303
- - `limit` max rows to include (default 500)
304
- - `dest` file path to write (optional for CSV, required for XLSX)
301
+ - `url` - the watched URL
302
+ - `target` - CSS/XPath filter (optional, `None` = full page)
303
+ - `limit` - max rows to include (default 500)
304
+ - `dest` - file path to write (optional for CSV, required for XLSX)
305
305
 
306
306
 
307
307
  ### Cooldown anti-spam
@@ -320,7 +320,7 @@ wd.watch(
320
320
 
321
321
  Important: **changes are still detected and stored** during the cooldown period. Only the alerts (callbacks, webhooks) are suppressed. The full history remains available via `.history()` and `.reports()`.
322
322
 
323
- `cooldown=0` (default) disables the feature every change triggers an alert immediately.
323
+ `cooldown=0` (default) disables the feature - every change triggers an alert immediately.
324
324
 
325
325
  In the CLI:
326
326
 
@@ -459,7 +459,7 @@ Pass `block=False` to run in the background (daemon threads).
459
459
 
460
460
  #### `await .start_async()`
461
461
 
462
- Async variant use inside an existing event loop (FastAPI, aiohttp, etc.):
462
+ Async variant - use inside an existing event loop (FastAPI, aiohttp, etc.):
463
463
 
464
464
  ```python
465
465
  import asyncio
@@ -578,13 +578,13 @@ Options for check:
578
578
 
579
579
  ## Use cases
580
580
 
581
- - **E-commerce** track product prices and stock availability
582
- - **News monitoring** detect article updates or new publications
583
- - **Documentation** alert when API docs or changelogs change
584
- - **Public APIs** watch JSON endpoints for schema or value changes
585
- - **SPA / React apps** monitor JS-rendered content with `browser=True`
586
- - **Compliance** audit changes on public-facing pages over time
587
- - **Research** collect snapshots for longitudinal content analysis
581
+ - **E-commerce** - track product prices and stock availability
582
+ - **News monitoring** - detect article updates or new publications
583
+ - **Documentation** - alert when API docs or changelogs change
584
+ - **Public APIs** - watch JSON endpoints for schema or value changes
585
+ - **SPA / React apps** - monitor JS-rendered content with `browser=True`
586
+ - **Compliance** - audit changes on public-facing pages over time
587
+ - **Research** - collect snapshots for longitudinal content analysis
588
588
 
589
589
 
590
590
  ## Contributing
@@ -46,13 +46,13 @@ No noisy HTML diffs. No external services. No AI black boxes.
46
46
 
47
47
  ## Why WatchDiff?
48
48
 
49
- Most change detection tools compare raw HTML which means every minor script reload or ad rotation triggers a false positive. WatchDiff strips the noise first, then diffs only the content that matters.
49
+ Most change detection tools compare raw HTML - which means every minor script reload or ad rotation triggers a false positive. WatchDiff strips the noise first, then diffs only the content that matters.
50
50
 
51
- - **Deterministic** same input always produces the same output
52
- - **Human-readable diffs** "Price changed: $19 → $24", not a wall of HTML
53
- - **Zero external services** snapshots stored locally (JSON or SQLite)
54
- - **Async-ready** sync and async schedulers included
55
- - **Python 3.9+** works on Debian Bullseye, Bookworm, and Trixie
51
+ - **Deterministic** - same input always produces the same output
52
+ - **Human-readable diffs** - "Price changed: $19 → $24", not a wall of HTML
53
+ - **Zero external services** - snapshots stored locally (JSON or SQLite)
54
+ - **Async-ready** - sync and async schedulers included
55
+ - **Python 3.9+** - works on Debian Bullseye, Bookworm, and Trixie
56
56
 
57
57
 
58
58
  ## Install
@@ -155,9 +155,9 @@ wd.start()
155
155
  ```
156
156
 
157
157
  `wait_for` accepts:
158
- - `"load"` default, waits for the `load` event
159
- - `"domcontentloaded"` faster, waits for DOM only
160
- - `"networkidle"` waits until no network requests for 500ms
158
+ - `"load"` - default, waits for the `load` event
159
+ - `"domcontentloaded"` - faster, waits for DOM only
160
+ - `"networkidle"` - waits until no network requests for 500ms
161
161
 
162
162
 
163
163
  ### Proxy rotation and User-Agent rotation
@@ -181,12 +181,12 @@ wd.watch(
181
181
 
182
182
  If `user_agents` is empty, WatchDiff rotates automatically among **4 built-in modern UA strings** (Chrome, Safari, Firefox, Chrome Linux). No configuration required.
183
183
 
184
- Proxies also work in browser mode Playwright passes the selected proxy to Chromium.
184
+ Proxies also work in browser mode - Playwright passes the selected proxy to Chromium.
185
185
 
186
186
 
187
187
  ### Semantic diff mode
188
188
 
189
- By default, WatchDiff diffs line by line. In **semantic mode**, it extracts meaningful HTML blocks `<p>`, `<h1>`-`<h6>`, `<li>`, `<td>`, `<th>`, `<blockquote>` and diffs those instead. This gives cleaner results on content-heavy pages where a single paragraph change doesn't shift dozens of lines.
189
+ By default, WatchDiff diffs line by line. In **semantic mode**, it extracts meaningful HTML blocks - `<p>`, `<h1>`-`<h6>`, `<li>`, `<td>`, `<th>`, `<blockquote>` - and diffs those instead. This gives cleaner results on content-heavy pages where a single paragraph change doesn't shift dozens of lines.
190
190
 
191
191
  ```python
192
192
  wd.watch(
@@ -221,12 +221,12 @@ wd.watch("https://example.com", target="(//h2)[1]") # first <h2> only
221
221
  wd.watch("https://example.com", target="//p[contains(@class,'intro')]")
222
222
  ```
223
223
 
224
- XPath is implemented via `lxml` (already a dependency no extra install needed).
224
+ XPath is implemented via `lxml` (already a dependency - no extra install needed).
225
225
 
226
226
 
227
227
  ### SQLite storage backend
228
228
 
229
- By default, WatchDiff stores data as JSON files. For larger datasets or concurrent access, switch to the built-in SQLite backend no extra dependencies required:
229
+ By default, WatchDiff stores data as JSON files. For larger datasets or concurrent access, switch to the built-in SQLite backend - no extra dependencies required:
230
230
 
231
231
  ```python
232
232
  from watchdiff import WatchDiff
@@ -236,7 +236,7 @@ wd = WatchDiff(store=SqliteStore(".watchdiff.db"))
236
236
  wd.watch("https://example.com").start()
237
237
  ```
238
238
 
239
- `SqliteStore` is a **drop-in replacement** for the default `Store` same interface, same behaviour. It runs in WAL mode for concurrent-read safety.
239
+ `SqliteStore` is a **drop-in replacement** for the default `Store` - same interface, same behaviour. It runs in WAL mode for concurrent-read safety.
240
240
 
241
241
 
242
242
  ### CSV and XLSX export
@@ -259,10 +259,10 @@ path = wd.export_snapshots_xlsx("https://example.com", dest="snapshots.xlsx")
259
259
  ```
260
260
 
261
261
  All export methods accept:
262
- - `url` the watched URL
263
- - `target` CSS/XPath filter (optional, `None` = full page)
264
- - `limit` max rows to include (default 500)
265
- - `dest` file path to write (optional for CSV, required for XLSX)
262
+ - `url` - the watched URL
263
+ - `target` - CSS/XPath filter (optional, `None` = full page)
264
+ - `limit` - max rows to include (default 500)
265
+ - `dest` - file path to write (optional for CSV, required for XLSX)
266
266
 
267
267
 
268
268
  ### Cooldown anti-spam
@@ -281,7 +281,7 @@ wd.watch(
281
281
 
282
282
  Important: **changes are still detected and stored** during the cooldown period. Only the alerts (callbacks, webhooks) are suppressed. The full history remains available via `.history()` and `.reports()`.
283
283
 
284
- `cooldown=0` (default) disables the feature every change triggers an alert immediately.
284
+ `cooldown=0` (default) disables the feature - every change triggers an alert immediately.
285
285
 
286
286
  In the CLI:
287
287
 
@@ -420,7 +420,7 @@ Pass `block=False` to run in the background (daemon threads).
420
420
 
421
421
  #### `await .start_async()`
422
422
 
423
- Async variant use inside an existing event loop (FastAPI, aiohttp, etc.):
423
+ Async variant - use inside an existing event loop (FastAPI, aiohttp, etc.):
424
424
 
425
425
  ```python
426
426
  import asyncio
@@ -539,13 +539,13 @@ Options for check:
539
539
 
540
540
  ## Use cases
541
541
 
542
- - **E-commerce** track product prices and stock availability
543
- - **News monitoring** detect article updates or new publications
544
- - **Documentation** alert when API docs or changelogs change
545
- - **Public APIs** watch JSON endpoints for schema or value changes
546
- - **SPA / React apps** monitor JS-rendered content with `browser=True`
547
- - **Compliance** audit changes on public-facing pages over time
548
- - **Research** collect snapshots for longitudinal content analysis
542
+ - **E-commerce** - track product prices and stock availability
543
+ - **News monitoring** - detect article updates or new publications
544
+ - **Documentation** - alert when API docs or changelogs change
545
+ - **Public APIs** - watch JSON endpoints for schema or value changes
546
+ - **SPA / React apps** - monitor JS-rendered content with `browser=True`
547
+ - **Compliance** - audit changes on public-facing pages over time
548
+ - **Research** - collect snapshots for longitudinal content analysis
549
549
 
550
550
 
551
551
  ## Contributing
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "watchdiff-core"
7
- version = "0.1.3"
7
+ version = "0.1.4"
8
8
  description = "Lightweight web change monitoring library - clean diffs, structured alerts, no AI required."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -847,7 +847,7 @@ wheels = [
847
847
 
848
848
  [[package]]
849
849
  name = "watchdiff-core"
850
- version = "0.1.3"
850
+ version = "0.1.4"
851
851
  source = { editable = "." }
852
852
  dependencies = [
853
853
  { name = "beautifulsoup4" },