wavexis 2.2.3__tar.gz → 2.2.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.
- {wavexis-2.2.3 → wavexis-2.2.4}/CHANGELOG.md +7 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/PKG-INFO +1 -1
- {wavexis-2.2.3 → wavexis-2.2.4}/pyproject.toml +1 -1
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/__init__.py +1 -1
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_capture.py +18 -9
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_shared.py +16 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_workflow.py +22 -2
- {wavexis-2.2.3 → wavexis-2.2.4}/.dockerignore +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/.github/workflows/ci.yml +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/.github/workflows/docs.yml +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/.github/workflows/release.yml +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/.gitignore +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/CODE_OF_CONDUCT.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/CONTRIBUTING.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/Dockerfile +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/LICENSE +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/README.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/SECURITY.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/api/actions.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/api/backends.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/api/cli.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/api/config.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/api/exceptions.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/api/multi.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/api/plugins.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/api/serve.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/cookbook/auth.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/cookbook/ci-cd.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/cookbook/css.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/cookbook/debug.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/cookbook/record-replay.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/cookbook/scraping.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/cookbook/screenshots.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/cookbook/serve-mode.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/assert.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/backends.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/commands.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/init.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/installation.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/multi.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/perf.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/plugins.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/quickstart.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/raw.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/repl.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/guide/troubleshooting.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/docs/index.md +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/mkdocs.yml +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/stubs/bidiwave/__init__.pyi +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/stubs/cdpwave/__init__.pyi +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/__init__.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/conftest.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/__init__.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_a11y.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_animation.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_backend_selection.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_browser.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_console.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_css.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_debug.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_dialog.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_dom.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_dom_snapshot.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_emulation.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_emulation_advanced.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_eval.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_har.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_input.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_media.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_multi.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_navigate.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_network.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_network_advanced.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_overlay.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_pdf.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_perf.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_permissions.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_raw.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_record.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_scrape.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_screenshot.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_security.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_serve.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_service_worker.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_storage.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_tabs.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_webaudio.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/integration/test_webauthn.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/__init__.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_abstract_backend_phase5.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_actions.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_actions_phase5.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_animation_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_assert_multi.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_auth.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_backend_manager.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_bidi_backend.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_bidi_phase5.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_bluetooth_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_cast_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_cleanup.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_cli_phase5.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_config.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_config_phase5.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_cookies_headers_actions.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_css_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_debug_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_dom_snapshot_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_download_screencast.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_emulation_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_error_handling.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_exceptions.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_format_record.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_global_options.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_init.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_input_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_interactions_crawl.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_manager.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_media_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_multi.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_multi_improvements.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_new_features.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_output.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_overlay_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_perf_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_perf_console.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_plugins.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_raw.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_record.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_repl.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_serve.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_service_worker_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_storage_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_webaudio_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/tests/unit/test_webauthn_action.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/__main__.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/__init__.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/accessibility.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/animation.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/base.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/bluetooth.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/browser.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/cast.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/console.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/cookies.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/crawl.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/css.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/debug.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/dialog.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/dom.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/dom_snapshot.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/download.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/emulation.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/eval.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/extract.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/form.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/har.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/headers.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/input.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/lighthouse.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/media.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/multi.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/navigate.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/network.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/overlay.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/pdf.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/performance.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/permissions.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/record.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/scrape.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/screencast.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/screenshot.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/security.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/service_worker.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/session.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/storage.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/tabs.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/wait.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/webaudio.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/webauthn.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/actions/websocket.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/auth.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/backend/__init__.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/backend/base.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/backend/bidi.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/backend/cdp.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/backend/manager.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cleanup.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/__init__.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_advanced.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_config.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_debug.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_emulation.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_experimental.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_input.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_navigation.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_network.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_perf.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_serve.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/_session.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/cli/app.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/config.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/exceptions.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/init.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/multi.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/output.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/plugins.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/record.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/repl.py +0 -0
- {wavexis-2.2.3 → wavexis-2.2.4}/wavexis/serve.py +0 -0
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to wavexis are documented in this file.
|
|
4
4
|
|
|
5
|
+
## v2.2.4 — 2026-07-07
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Progress reporting for long-running operations (`batch`, `multi`, `scrape`)
|
|
10
|
+
- `_progress(current, total, label)` helper shows `[n/total] — label` unless `--quiet`
|
|
11
|
+
|
|
5
12
|
## v2.2.3 — 2026-07-07
|
|
6
13
|
|
|
7
14
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wavexis
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.4
|
|
4
4
|
Summary: Browser automation CLI — wraps cdpwave and bidiwave, no Node.js, no Chromium download
|
|
5
5
|
Project-URL: Homepage, https://github.com/MathiasPaulenko/wavexis
|
|
6
6
|
Project-URL: Repository, https://github.com/MathiasPaulenko/wavexis
|
|
@@ -18,7 +18,9 @@ from wavexis.actions.screenshot import ScreenshotAction
|
|
|
18
18
|
from wavexis.cli._shared import (
|
|
19
19
|
Output,
|
|
20
20
|
_browser_options,
|
|
21
|
+
_echo,
|
|
21
22
|
_get_backend,
|
|
23
|
+
_progress,
|
|
22
24
|
_run_async,
|
|
23
25
|
_write_json_output,
|
|
24
26
|
app,
|
|
@@ -376,17 +378,24 @@ async def _scrape(
|
|
|
376
378
|
) -> list[dict[str, Any]]:
|
|
377
379
|
"""Async helper for scraping."""
|
|
378
380
|
backend = _get_backend()
|
|
381
|
+
total = len(urls)
|
|
382
|
+
_echo(f"Scraping {total} URL(s)…")
|
|
379
383
|
try:
|
|
380
384
|
await backend.launch(_browser_options())
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
385
|
+
results: list[dict[str, Any]] = []
|
|
386
|
+
for i, url in enumerate(urls):
|
|
387
|
+
_progress(i + 1, total, url)
|
|
388
|
+
params = ScrapeParams(
|
|
389
|
+
urls=[url],
|
|
390
|
+
expression=expression,
|
|
391
|
+
file=file,
|
|
392
|
+
output_format="json",
|
|
393
|
+
selector=selector,
|
|
394
|
+
wait=WaitStrategy(strategy="load"),
|
|
395
|
+
)
|
|
396
|
+
result = await ScrapeAction(params).execute(backend)
|
|
397
|
+
results.extend(result)
|
|
398
|
+
return results
|
|
390
399
|
finally:
|
|
391
400
|
await backend.close()
|
|
392
401
|
|
|
@@ -48,6 +48,7 @@ __all__ = [
|
|
|
48
48
|
"_get_ctx",
|
|
49
49
|
"_handle_error",
|
|
50
50
|
"_load_global_config",
|
|
51
|
+
"_progress",
|
|
51
52
|
"_run_async",
|
|
52
53
|
"_write_json_output",
|
|
53
54
|
"app",
|
|
@@ -185,6 +186,21 @@ def _echo(msg: str) -> None:
|
|
|
185
186
|
typer.echo(msg)
|
|
186
187
|
|
|
187
188
|
|
|
189
|
+
def _progress(current: int, total: int, label: str = "") -> None:
|
|
190
|
+
"""Print a progress indicator unless quiet mode is active.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
current: Current item index (1-based).
|
|
194
|
+
total: Total number of items.
|
|
195
|
+
label: Optional label to prepend (e.g. URL or action name).
|
|
196
|
+
"""
|
|
197
|
+
ctx = _get_ctx()
|
|
198
|
+
if ctx.quiet:
|
|
199
|
+
return
|
|
200
|
+
suffix = f" — {label}" if label else ""
|
|
201
|
+
typer.echo(f"[{current}/{total}]{suffix}")
|
|
202
|
+
|
|
203
|
+
|
|
188
204
|
def _handle_error(e: Exception) -> None:
|
|
189
205
|
"""Handle a WavexisError with the correct exit code and message.
|
|
190
206
|
|
|
@@ -19,6 +19,7 @@ from wavexis.cli._shared import (
|
|
|
19
19
|
_echo,
|
|
20
20
|
_get_backend,
|
|
21
21
|
_handle_error,
|
|
22
|
+
_progress,
|
|
22
23
|
_run_async,
|
|
23
24
|
app,
|
|
24
25
|
)
|
|
@@ -118,10 +119,20 @@ async def _multi(config_path: Any, parallel: bool = False) -> list[Any]:
|
|
|
118
119
|
from wavexis.multi import execute_actions, parse_yaml
|
|
119
120
|
|
|
120
121
|
actions = parse_yaml(config_path)
|
|
122
|
+
total = len(actions)
|
|
123
|
+
_echo(f"Executing {total} action(s)…")
|
|
121
124
|
backend = _get_backend()
|
|
122
125
|
await backend.launch(_browser_options())
|
|
123
126
|
try:
|
|
124
|
-
|
|
127
|
+
results: list[Any] = []
|
|
128
|
+
if parallel:
|
|
129
|
+
results = await execute_actions(actions, backend, parallel=True)
|
|
130
|
+
else:
|
|
131
|
+
for i, action in enumerate(actions):
|
|
132
|
+
_progress(i + 1, total, str(action))
|
|
133
|
+
result = await execute_actions([action], backend, parallel=False)
|
|
134
|
+
results.extend(result)
|
|
135
|
+
return results
|
|
125
136
|
finally:
|
|
126
137
|
await backend.close()
|
|
127
138
|
|
|
@@ -215,13 +226,22 @@ async def _batch(
|
|
|
215
226
|
List of results (or exceptions) in the same order as urls.
|
|
216
227
|
"""
|
|
217
228
|
semaphore = asyncio.Semaphore(parallel)
|
|
229
|
+
total = len(urls)
|
|
230
|
+
completed = 0
|
|
231
|
+
lock = asyncio.Lock()
|
|
218
232
|
|
|
219
233
|
async def _run_one(url: str) -> Any:
|
|
234
|
+
nonlocal completed
|
|
220
235
|
async with semaphore:
|
|
221
236
|
try:
|
|
222
|
-
|
|
237
|
+
result = await _batch_single(url, action, out_dir, expression)
|
|
238
|
+
return result
|
|
223
239
|
except (WavexisError, OSError) as exc:
|
|
224
240
|
return exc
|
|
241
|
+
finally:
|
|
242
|
+
async with lock:
|
|
243
|
+
completed += 1
|
|
244
|
+
_progress(completed, total, url)
|
|
225
245
|
|
|
226
246
|
tasks = [_run_one(u) for u in urls]
|
|
227
247
|
return await asyncio.gather(*tasks)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|