crawlee 1.0.5b12__tar.gz → 1.0.5b13__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.
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/CHANGELOG.md +1 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/PKG-INFO +4 -1
- crawlee-1.0.5b13/docs/guides/code_examples/storage_clients/redis_storage_client_basic_example.py +10 -0
- crawlee-1.0.5b13/docs/guides/code_examples/storage_clients/redis_storage_client_configuration_example.py +27 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/storage_clients.mdx +175 -3
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/pyproject.toml +4 -2
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/__init__.py +4 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/__init__.py +6 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/_client_mixin.py +295 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/_dataset_client.py +325 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/_key_value_store_client.py +264 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/_request_queue_client.py +586 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/_storage_client.py +146 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/_utils.py +23 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/lua_scripts/atomic_bloom_add_requests.lua +36 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/lua_scripts/atomic_fetch_request.lua +49 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/lua_scripts/atomic_set_add_requests.lua +37 -0
- crawlee-1.0.5b13/src/crawlee/storage_clients/_redis/lua_scripts/reclaim_stale_requests.lua +34 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/conftest.py +6 -0
- crawlee-1.0.5b13/tests/unit/storage_clients/_redis/test_redis_dataset_client.py +146 -0
- crawlee-1.0.5b13/tests/unit/storage_clients/_redis/test_redis_kvs_client.py +217 -0
- crawlee-1.0.5b13/tests/unit/storage_clients/_redis/test_redis_rq_client.py +252 -0
- crawlee-1.0.5b13/tests/unit/storages/conftest.py +39 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/uv.lock +251 -3
- crawlee-1.0.5b13/website/static/.nojekyll +0 -0
- crawlee-1.0.5b12/tests/unit/storages/conftest.py +0 -18
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.editorconfig +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/CODEOWNERS +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/pull_request_template.md +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/workflows/build_and_deploy_docs.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/workflows/check_pr_title.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/workflows/pre_release.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/workflows/release.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/workflows/run_code_checks.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/workflows/templates_e2e_tests.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.github/workflows/update_new_issue.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.gitignore +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.markdownlint.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/.pre-commit-config.yaml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/CONTRIBUTING.md +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/LICENSE +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/Makefile +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/README.md +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/apify_platform.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/code_examples/apify/crawler_as_actor_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/code_examples/apify/get_public_url.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/code_examples/apify/log_with_config_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/code_examples/apify/proxy_advanced_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/code_examples/apify/proxy_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/code_examples/google/cloud_run_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/code_examples/google/google_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/google_cloud.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/deployment/google_cloud_run.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/add_data_to_dataset.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/beautifulsoup_crawler.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/capture_screenshot_using_playwright.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/capturing_page_snapshots_with_error_snapshotter.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/adaptive_playwright_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/add_data_to_dataset_bs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/add_data_to_dataset_dataset.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/add_data_to_dataset_pw.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/beautifulsoup_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/beautifulsoup_crawler_keep_alive.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/beautifulsoup_crawler_stop.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/capture_screenshot_using_playwright.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/configure_json_logging.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_all_links_on_website_bs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_all_links_on_website_pw.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_multiple_urls_bs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_multiple_urls_pw.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_specific_links_on_website_bs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_specific_links_on_website_pw.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_website_with_relative_links_all_links.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_website_with_relative_links_same_domain.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_website_with_relative_links_same_hostname.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/crawl_website_with_relative_links_same_origin.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/export_entire_dataset_to_file_csv.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/export_entire_dataset_to_file_json.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/extract_and_add_specific_links_on_website_bs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/extract_and_add_specific_links_on_website_pw.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/fill_and_submit_web_form_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/fill_and_submit_web_form_request.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/parsel_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/parsel_crawler_with_error_snapshotter.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/playwright_block_requests.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/playwright_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/playwright_crawler_with_camoufox.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/playwright_crawler_with_error_snapshotter.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/playwright_crawler_with_fingerprint_generator.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/respect_robots_on_skipped_request.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/respect_robots_txt_file.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/resuming_paused_crawl.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/using_browser_profiles_chrome.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/code_examples/using_browser_profiles_firefox.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/crawl_all_links_on_website.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/crawl_multiple_urls.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/crawl_specific_links_on_website.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/crawl_website_with_relative_links.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/crawler_keep_alive.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/crawler_stop.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/export_entire_dataset_to_file.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/fill_and_submit_web_form.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/json_logging.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/parsel_crawler.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/playwright_crawler.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/playwright_crawler_adaptive.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/playwright_crawler_with_block_requests.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/playwright_crawler_with_camoufox.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/playwright_crawler_with_fingerprint_generator.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/respect_robots_txt_file.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/resuming_paused_crawl.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/examples/using_browser_profile.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/architecture_overview.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/avoid_blocking.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/avoid_blocking/default_fingerprint_generator_with_args.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/avoid_blocking/playwright_with_fingerprint_generator.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/creating_web_archive/manual_archiving_parsel_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/creating_web_archive/manual_archiving_playwright_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/creating_web_archive/simple_pw_through_proxy_pywb_server.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/error_handling/change_handle_error_status.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/error_handling/disable_retry.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/error_handling/handle_proxy_error.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/http_clients/parsel_curl_impersonate_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/http_clients/parsel_httpx_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/http_clients/parsel_impit_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/http_crawlers/beautifulsoup_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/http_crawlers/custom_crawler_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/http_crawlers/http_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/http_crawlers/parsel_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/login_crawler/http_login.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/login_crawler/playwright_login.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler/browser_configuration_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler/multiple_launch_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler/plugin_browser_configuration_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler/pre_navigation_hook_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_adaptive/handler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_adaptive/init_beautifulsoup.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_adaptive/init_parsel.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_adaptive/init_prediction.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_adaptive/pre_nav_hooks.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_stagehand/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_stagehand/browser_classes.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_stagehand/stagehand_run.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/playwright_crawler_stagehand/support_classes.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/inspecting_bs_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/inspecting_pw_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/integration_bs_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/integration_pw_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/quick_start_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/session_bs_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/session_pw_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/tiers_bs_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/proxy_management/tiers_pw_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_loaders/rl_basic_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_loaders/rl_basic_example_with_persist.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_loaders/rl_tandem_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_loaders/rl_tandem_example_explicit.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_loaders/sitemap_basic_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_loaders/sitemap_example_with_persist.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_loaders/sitemap_tandem_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_loaders/sitemap_tandem_example_explicit.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_router/adaptive_crawler_handlers.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_router/basic_request_handlers.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_router/custom_router_default_only.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_router/error_handler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_router/failed_request_handler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_router/http_pre_navigation.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_router/playwright_pre_navigation.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/request_router/simple_default_handler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/running_in_web_server/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/running_in_web_server/crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/running_in_web_server/server.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/scaling_crawlers/max_tasks_per_minute_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/scaling_crawlers/min_and_max_concurrency_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_conflicts.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_crawler_configuration.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_crawler_event_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_crawler_storage_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_locator_configuration.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_locator_event_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_locator_storage_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_storage_configuration.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/service_locator/service_storage_storage_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/session_management/multi_sessions_http.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/session_management/one_session_http.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/session_management/sm_basic.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/session_management/sm_beautifulsoup.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/session_management/sm_http.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/session_management/sm_parsel.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/session_management/sm_playwright.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/session_management/sm_standalone.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storage_clients/custom_storage_client_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storage_clients/file_system_storage_client_basic_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storage_clients/file_system_storage_client_configuration_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storage_clients/memory_storage_client_basic_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storage_clients/registering_storage_clients_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storage_clients/sql_storage_client_basic_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storage_clients/sql_storage_client_configuration_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/cleaning_do_not_purge_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/cleaning_purge_explicitly_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/dataset_basic_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/dataset_with_crawler_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/dataset_with_crawler_explicit_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/helper_add_requests_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/helper_enqueue_links_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/kvs_basic_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/kvs_with_crawler_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/kvs_with_crawler_explicit_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/opening.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/rq_basic_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/rq_with_crawler_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/storages/rq_with_crawler_explicit_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/code_examples/trace_and_monitor_crawlers/instrument_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/crawler_login.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/creating_web_archive.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/error_handling.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/http_clients.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/http_crawlers.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/playwright_crawler.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/playwright_crawler_adaptive.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/playwright_crawler_stagehand.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/proxy_management.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/request_loaders.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/request_router.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/running_in_web_server.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/scaling_crawlers.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/service_locator.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/session_management.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/storages.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/guides/trace_and_monitor_crawlers.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/01_setting_up.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/02_first_crawler.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/03_adding_more_urls.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/04_real_world_project.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/05_crawling.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/06_scraping.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/07_saving_data.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/08_refactoring.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/09_running_in_cloud.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/02_bs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/02_bs_better.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/02_request_queue.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/03_enqueue_strategy.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/03_finding_new_links.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/03_globs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/03_original_code.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/03_transform_request.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/04_sanity_check.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/05_crawling_detail.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/05_crawling_listing.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/06_scraping.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/07_final_code.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/07_first_code.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/08_main.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/08_routes.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/09_apify_sdk.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/code_examples/routes.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/introduction/index.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/pyproject.toml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/quick-start/code_examples/beautifulsoup_crawler_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/quick-start/code_examples/parsel_crawler_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/quick-start/code_examples/playwright_crawler_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/quick-start/code_examples/playwright_crawler_headful_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/quick-start/index.mdx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/upgrading/upgrading_to_v0x.md +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/docs/upgrading/upgrading_to_v1.md +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/renovate.json +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_autoscaling/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_autoscaling/_types.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_autoscaling/autoscaled_pool.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_autoscaling/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_autoscaling/snapshotter.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_autoscaling/system_status.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_browserforge_workaround.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_cli.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_consts.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_log_config.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_request.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_service_locator.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_types.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/blocked.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/byte_size.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/console.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/crypto.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/docs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/file.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/globs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/html_to_text.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/models.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/raise_if_too_many_kwargs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/recoverable_state.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/recurring_task.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/requests.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/robots.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/sitemap.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/system.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/time.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/try_import.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/urls.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/wait.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/_utils/web.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/_browser_controller.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/_browser_plugin.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/_browser_pool.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/_playwright_browser.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/_playwright_browser_controller.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/_playwright_browser_plugin.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/_types.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/browsers/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/configuration.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_abstract_http/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_abstract_http/_abstract_http_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_abstract_http/_abstract_http_parser.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_abstract_http/_http_crawling_context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_abstract_http/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_adaptive_playwright/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_adaptive_playwright/_adaptive_playwright_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_adaptive_playwright/_adaptive_playwright_crawler_statistics.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_adaptive_playwright/_adaptive_playwright_crawling_context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_adaptive_playwright/_rendering_type_predictor.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_adaptive_playwright/_result_comparator.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_adaptive_playwright/_utils.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_basic/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_basic/_basic_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_basic/_basic_crawling_context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_basic/_context_pipeline.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_basic/_logging_utils.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_basic/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_beautifulsoup/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_beautifulsoup/_beautifulsoup_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_beautifulsoup/_beautifulsoup_crawling_context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_beautifulsoup/_beautifulsoup_parser.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_beautifulsoup/_utils.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_beautifulsoup/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_http/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_http/_http_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_http/_http_parser.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_parsel/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_parsel/_parsel_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_parsel/_parsel_crawling_context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_parsel/_parsel_parser.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_parsel/_utils.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_playwright/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_playwright/_playwright_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_playwright/_playwright_crawling_context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_playwright/_playwright_http_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_playwright/_playwright_pre_nav_crawling_context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_playwright/_types.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_playwright/_utils.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/_types.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/crawlers/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/errors.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/events/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/events/_event_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/events/_local_event_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/events/_types.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/events/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/fingerprint_suite/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/fingerprint_suite/_browserforge_adapter.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/fingerprint_suite/_consts.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/fingerprint_suite/_fingerprint_generator.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/fingerprint_suite/_header_generator.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/fingerprint_suite/_types.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/fingerprint_suite/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/http_clients/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/http_clients/_base.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/http_clients/_curl_impersonate.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/http_clients/_httpx.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/http_clients/_impit.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/otel/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/otel/crawler_instrumentor.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/cookiecutter.json +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/hooks/post_gen_project.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/hooks/pre_gen_project.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/main.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/main_beautifulsoup.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/main_parsel.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/main_playwright.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/main_playwright_camoufox.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/routes_beautifulsoup.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/routes_camoufox.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/routes_parsel.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/routes_playwright.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/templates/routes_playwright_camoufox.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/.dockerignore +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/Dockerfile +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/README.md +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/pyproject.toml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/requirements.txt +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/{{cookiecutter.__package_name}}/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/{{cookiecutter.__package_name}}/__main__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/{{cookiecutter.__package_name}}/main.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/project_template/{{cookiecutter.project_name}}/{{cookiecutter.__package_name}}/routes.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/proxy_configuration.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/request_loaders/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/request_loaders/_request_list.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/request_loaders/_request_loader.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/request_loaders/_request_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/request_loaders/_request_manager_tandem.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/request_loaders/_sitemap_request_loader.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/router.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/sessions/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/sessions/_cookies.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/sessions/_models.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/sessions/_session.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/sessions/_session_pool.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/sessions/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/statistics/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/statistics/_error_snapshotter.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/statistics/_error_tracker.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/statistics/_models.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/statistics/_statistics.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_base/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_base/_dataset_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_base/_key_value_store_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_base/_request_queue_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_base/_storage_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_base/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_file_system/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_file_system/_dataset_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_file_system/_key_value_store_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_file_system/_request_queue_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_file_system/_storage_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_file_system/_utils.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_file_system/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_memory/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_memory/_dataset_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_memory/_key_value_store_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_memory/_request_queue_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_memory/_storage_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_memory/py.typed +0 -0
- {crawlee-1.0.5b12/src/crawlee/storage_clients/_sql → crawlee-1.0.5b13/src/crawlee/storage_clients/_redis}/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_sql/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_sql/_client_mixin.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_sql/_dataset_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_sql/_db_models.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_sql/_key_value_store_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_sql/_request_queue_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/_sql/_storage_client.py +0 -0
- {crawlee-1.0.5b12/src/crawlee/storage_clients → crawlee-1.0.5b13/src/crawlee/storage_clients/_sql}/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storage_clients/models.py +0 -0
- {crawlee-1.0.5b12/src/crawlee/storages → crawlee-1.0.5b13/src/crawlee/storage_clients}/py.typed +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storages/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storages/_base.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storages/_dataset.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storages/_key_value_store.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storages/_request_queue.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storages/_storage_instance_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/src/crawlee/storages/_utils.py +0 -0
- /crawlee-1.0.5b12/tests/__init__.py → /crawlee-1.0.5b13/src/crawlee/storages/py.typed +0 -0
- {crawlee-1.0.5b12/tests/e2e → crawlee-1.0.5b13/tests}/__init__.py +0 -0
- {crawlee-1.0.5b12/tests/unit → crawlee-1.0.5b13/tests/e2e}/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/e2e/conftest.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/e2e/project_template/test_static_crawlers_templates.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/e2e/project_template/utils.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/README.md +0 -0
- /crawlee-1.0.5b12/tests/unit/crawlers/_adaptive_playwright/test_adaptive_playwright_crawling_context.py → /crawlee-1.0.5b13/tests/unit/__init__.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_autoscaling/test_autoscaled_pool.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_autoscaling/test_snapshotter.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_autoscaling/test_system_status.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_statistics/test_error_tracker.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_statistics/test_periodic_logging.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_statistics/test_persistence.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_statistics/test_request_processing_record.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_byte_size.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_console.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_crypto.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_file.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_globs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_html_to_text.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_measure_time.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_raise_if_too_many_kwargs.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_recurring_task.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_requests.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_robots.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_sitemap.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_system.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_timedelata_ms.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/_utils/test_urls.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/browsers/test_browser_pool.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/browsers/test_playwright_browser.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/browsers/test_playwright_browser_controller.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/browsers/test_playwright_browser_plugin.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_adaptive_playwright/test_adaptive_playwright_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_adaptive_playwright/test_adaptive_playwright_crawler_statistics.py +0 -0
- /crawlee-1.0.5b12/website/static/.nojekyll → /crawlee-1.0.5b13/tests/unit/crawlers/_adaptive_playwright/test_adaptive_playwright_crawling_context.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_adaptive_playwright/test_predictor.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_basic/test_basic_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_basic/test_context_pipeline.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_beautifulsoup/test_beautifulsoup_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_http/test_http_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_parsel/test_parsel_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/crawlers/_playwright/test_playwright_crawler.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/events/test_event_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/events/test_local_event_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/fingerprint_suite/test_adapters.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/fingerprint_suite/test_header_generator.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/http_clients/test_http_clients.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/http_clients/test_httpx.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/otel/test_crawler_instrumentor.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/proxy_configuration/test_new_proxy_info.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/proxy_configuration/test_tiers.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/request_loaders/test_request_list.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/request_loaders/test_sitemap_request_loader.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/server.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/server_endpoints.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/sessions/test_cookies.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/sessions/test_models.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/sessions/test_session.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/sessions/test_session_pool.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_file_system/test_fs_dataset_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_file_system/test_fs_kvs_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_file_system/test_fs_rq_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_memory/test_memory_dataset_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_memory/test_memory_kvs_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_memory/test_memory_rq_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_sql/test_sql_dataset_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_sql/test_sql_kvs_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storage_clients/_sql/test_sql_rq_client.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storages/test_dataset.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storages/test_key_value_store.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storages/test_request_manager_tandem.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storages/test_request_queue.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/storages/test_storage_instance_manager.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/test_cli.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/test_configuration.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/test_log_config.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/test_router.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/tests/unit/test_service_locator.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/.eslintrc.json +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/.yarnrc.yml +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/babel.config.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/build_api_reference.sh +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/docusaurus.config.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/generate_module_shortcuts.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/package.json +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/patches/@docusaurus+core+3.4.0.patch +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/patches/@docusaurus+core+3.5.2.patch +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/roa-loader/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/roa-loader/package.json +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/sidebars.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/ApiLink.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Button.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Button.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/CopyButton.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/CopyButton.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Gradients.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Highlights.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Highlights.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/HomepageCliExample.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/HomepageCliExample.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/HomepageCtaSection.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/HomepageCtaSection.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/HomepageHeroSection.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/HomepageHeroSection.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/LanguageInfoWidget.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/LanguageInfoWidget.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/LanguageSwitch.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/LanguageSwitch.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/RiverSection.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/RiverSection.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/ThreeCardsWithIcon.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/ThreeCardsWithIcon.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/animated-crawlee-logo-dark.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/Homepage/animated-crawlee-logo-light.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/RunnableCodeBlock.jsx +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/components/RunnableCodeBlock.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/css/custom.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/pages/home_page_example.py +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/pages/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/pages/index.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/ColorModeToggle/dark-mode-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/ColorModeToggle/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/ColorModeToggle/light-mode-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/ColorModeToggle/styles.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/DocItem/Layout/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/DocItem/Layout/styles.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Footer/LinkItem/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Footer/LinkItem/index.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Footer/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Footer/index.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/MDXComponents/A.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/Content/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/Content/styles.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/Logo/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/Logo/index.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/MobileSidebar/Header/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/MobileSidebar/Header/index.module.css +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/MobileSidebar/Layout/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/Navbar/MobileSidebar/index.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/src/theme/NavbarItem/ComponentTypes.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/font/lota.woff +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/font/lota.woff2 +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/API.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/arrow_right.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/auto-scaling-dark.webp +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/auto-scaling-light.webp +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/check.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/chrome-scrape-dark.gif +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/chrome-scrape-light.gif +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/cloud_icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/community-dark-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/community-light-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-dark-new.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-dark.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-javascript-dark.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-javascript-light.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-light-new.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-light.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-logo-monocolor.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-logo.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-python-dark.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-python-light.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/crawlee-python-og.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/defaults-dark-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/defaults-light-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/discord-brand-dark.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/discord-brand.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/docusaurus.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/external-link.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/favicon.ico +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/favorite-tools-dark.webp +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/favorite-tools-light.webp +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/features/auto-scaling.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/features/automate-everything.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/features/fingerprints.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/features/node-requests.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/features/runs-on-py.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/features/storage.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/features/works-everywhere.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/fill-and-submit-web-form/00.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/fill-and-submit-web-form/01.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/fill-and-submit-web-form/02.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/fill-and-submit-web-form/03.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/getting-started/current-price.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/getting-started/scraping-practice.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/getting-started/select-an-element.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/getting-started/selected-element.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/getting-started/sku.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/getting-started/title.jpg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/github-brand-dark.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/github-brand.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/guides/jaeger_otel_search_view_example.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/guides/jaeger_otel_trace_example.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/hearth copy.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/hearth.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/javascript_logo.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/js_file.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/logo-big.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/logo-blur.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/logo-blur.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/logo-zoom.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/menu-arrows.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/oss_logo.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/puppeteer-live-view-dashboard.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/puppeteer-live-view-detail.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/queue-dark-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/queue-light-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/resuming-paused-crawl/00.webp +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/resuming-paused-crawl/01.webp +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/robot.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/routing-dark-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/routing-light-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/scraping-utils-dark-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/scraping-utils-light-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/smart-proxy-dark.webp +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/smart-proxy-light.webp +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/source_code.png +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/system.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/triangles_dark.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/triangles_light.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/workflow.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/zero-setup-dark-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/img/zero-setup-light-icon.svg +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/js/custom.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/static/robots.txt +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/tools/docs-prettier.config.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/tools/utils/externalLink.js +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/tools/website_gif/chrome-scrape-dark.gif +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/tools/website_gif/chrome-scrape-dark.mp4 +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/tools/website_gif/chrome-scrape-light.gif +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/tools/website_gif/chrome-scrape-light.mp4 +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/tools/website_gif/website_gif.mjs +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/tsconfig.eslint.json +0 -0
- {crawlee-1.0.5b12 → crawlee-1.0.5b13}/website/yarn.lock +0 -0
|
@@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
|
|
|
8
8
|
### 🚀 Features
|
|
9
9
|
|
|
10
10
|
- Add `chrome` `BrowserType` for `PlaywrightCrawler` to use the Chrome browser ([#1487](https://github.com/apify/crawlee-python/pull/1487)) ([b06937b](https://github.com/apify/crawlee-python/commit/b06937bbc3afe3c936b554bfc503365c1b2c526b)) by [@Mantisus](https://github.com/Mantisus), closes [#1071](https://github.com/apify/crawlee-python/issues/1071)
|
|
11
|
+
- Add `RedisStorageClient` based on Redis v8.0+ ([#1406](https://github.com/apify/crawlee-python/pull/1406)) ([d08d13d](https://github.com/apify/crawlee-python/commit/d08d13d39203c24ab61fe254b0956d6744db3b5f)) by [@Mantisus](https://github.com/Mantisus)
|
|
11
12
|
|
|
12
13
|
### 🐛 Bug Fixes
|
|
13
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crawlee
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5b13
|
|
4
4
|
Summary: Crawlee for Python
|
|
5
5
|
Project-URL: Apify Homepage, https://apify.com
|
|
6
6
|
Project-URL: Changelog, https://crawlee.dev/python/docs/changelog
|
|
@@ -263,6 +263,7 @@ Requires-Dist: opentelemetry-sdk>=1.34.1; extra == 'all'
|
|
|
263
263
|
Requires-Dist: opentelemetry-semantic-conventions>=0.54; extra == 'all'
|
|
264
264
|
Requires-Dist: parsel>=1.10.0; extra == 'all'
|
|
265
265
|
Requires-Dist: playwright>=1.27.0; extra == 'all'
|
|
266
|
+
Requires-Dist: redis[hiredis]>=7.0.0; extra == 'all'
|
|
266
267
|
Requires-Dist: rich>=13.9.0; extra == 'all'
|
|
267
268
|
Requires-Dist: scikit-learn>=1.6.0; extra == 'all'
|
|
268
269
|
Requires-Dist: sqlalchemy[asyncio]<3.0.0,>=2.0.0; extra == 'all'
|
|
@@ -296,6 +297,8 @@ Provides-Extra: playwright
|
|
|
296
297
|
Requires-Dist: apify-fingerprint-datapoints>=0.0.2; extra == 'playwright'
|
|
297
298
|
Requires-Dist: browserforge>=1.2.3; extra == 'playwright'
|
|
298
299
|
Requires-Dist: playwright>=1.27.0; extra == 'playwright'
|
|
300
|
+
Provides-Extra: redis
|
|
301
|
+
Requires-Dist: redis[hiredis]>=7.0.0; extra == 'redis'
|
|
299
302
|
Provides-Extra: sql-postgres
|
|
300
303
|
Requires-Dist: asyncpg>=0.24.0; extra == 'sql-postgres'
|
|
301
304
|
Requires-Dist: sqlalchemy[asyncio]<3.0.0,>=2.0.0; extra == 'sql-postgres'
|
crawlee-1.0.5b13/docs/guides/code_examples/storage_clients/redis_storage_client_basic_example.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from crawlee.crawlers import ParselCrawler
|
|
2
|
+
from crawlee.storage_clients import RedisStorageClient
|
|
3
|
+
|
|
4
|
+
# Create a new instance of storage client using connection string.
|
|
5
|
+
# 'redis://localhost:6379' is the just placeholder, replace it with your actual
|
|
6
|
+
# connection string.
|
|
7
|
+
storage_client = RedisStorageClient(connection_string='redis://localhost:6379')
|
|
8
|
+
|
|
9
|
+
# And pass it to the crawler.
|
|
10
|
+
crawler = ParselCrawler(storage_client=storage_client)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from redis.asyncio import Redis
|
|
2
|
+
|
|
3
|
+
from crawlee.configuration import Configuration
|
|
4
|
+
from crawlee.crawlers import ParselCrawler
|
|
5
|
+
from crawlee.storage_clients import RedisStorageClient
|
|
6
|
+
|
|
7
|
+
# Create a new instance of storage client using a Redis client with custom settings.
|
|
8
|
+
# Replace host and port with your actual Redis server configuration.
|
|
9
|
+
# Other Redis client settings can be adjusted as needed.
|
|
10
|
+
storage_client = RedisStorageClient(
|
|
11
|
+
redis=Redis(
|
|
12
|
+
host='localhost',
|
|
13
|
+
port=6379,
|
|
14
|
+
retry_on_timeout=True,
|
|
15
|
+
socket_keepalive=True,
|
|
16
|
+
socket_connect_timeout=10,
|
|
17
|
+
)
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# Create a configuration with custom settings.
|
|
21
|
+
configuration = Configuration(purge_on_start=False)
|
|
22
|
+
|
|
23
|
+
# And pass them to the crawler.
|
|
24
|
+
crawler = ParselCrawler(
|
|
25
|
+
storage_client=storage_client,
|
|
26
|
+
configuration=configuration,
|
|
27
|
+
)
|
|
@@ -17,6 +17,8 @@ import CustomStorageClientExample from '!!raw-loader!roa-loader!./code_examples/
|
|
|
17
17
|
import RegisteringStorageClientsExample from '!!raw-loader!roa-loader!./code_examples/storage_clients/registering_storage_clients_example.py';
|
|
18
18
|
import SQLStorageClientBasicExample from '!!raw-loader!roa-loader!./code_examples/storage_clients/sql_storage_client_basic_example.py';
|
|
19
19
|
import SQLStorageClientConfigurationExample from '!!raw-loader!./code_examples/storage_clients/sql_storage_client_configuration_example.py';
|
|
20
|
+
import RedisStorageClientBasicExample from '!!raw-loader!./code_examples/storage_clients/redis_storage_client_basic_example.py';
|
|
21
|
+
import RedisStorageClientConfigurationExample from '!!raw-loader!./code_examples/storage_clients/redis_storage_client_configuration_example.py';
|
|
20
22
|
|
|
21
23
|
Storage clients provide a unified interface for interacting with <ApiLink to="class/Dataset">`Dataset`</ApiLink>, <ApiLink to="class/KeyValueStore">`KeyValueStore`</ApiLink>, and <ApiLink to="class/RequestQueue">`RequestQueue`</ApiLink>, regardless of the underlying implementation. They handle operations like creating, reading, updating, and deleting storage instances, as well as managing data persistence and cleanup. This abstraction makes it easy to switch between different environments, such as local development and cloud production setups.
|
|
22
24
|
|
|
@@ -26,7 +28,8 @@ Crawlee provides three main storage client implementations:
|
|
|
26
28
|
|
|
27
29
|
- <ApiLink to="class/FileSystemStorageClient">`FileSystemStorageClient`</ApiLink> - Provides persistent file system storage with in-memory caching.
|
|
28
30
|
- <ApiLink to="class/MemoryStorageClient">`MemoryStorageClient`</ApiLink> - Stores data in memory with no persistence.
|
|
29
|
-
- <ApiLink to="class/SqlStorageClient">`SqlStorageClient`</ApiLink>
|
|
31
|
+
- <ApiLink to="class/SqlStorageClient">`SqlStorageClient`</ApiLink> - Provides persistent storage using a SQL database ([SQLite](https://sqlite.org/) or [PostgreSQL](https://www.postgresql.org/)). Requires installing the extra dependency: `crawlee[sql_sqlite]` for SQLite or `crawlee[sql_postgres]` for PostgreSQL.
|
|
32
|
+
- <ApiLink to="class/RedisStorageClient">`RedisStorageClient`</ApiLink> - Provides persistent storage using a [Redis](https://redis.io/) database v8.0+. Requires installing the extra dependency `crawlee[redis]`.
|
|
30
33
|
- [`ApifyStorageClient`](https://docs.apify.com/sdk/python/reference/class/ApifyStorageClient) - Manages storage on the [Apify platform](https://apify.com), implemented in the [Apify SDK](https://github.com/apify/apify-sdk-python).
|
|
31
34
|
|
|
32
35
|
```mermaid
|
|
@@ -56,6 +59,8 @@ class MemoryStorageClient
|
|
|
56
59
|
|
|
57
60
|
class SqlStorageClient
|
|
58
61
|
|
|
62
|
+
class RedisStorageClient
|
|
63
|
+
|
|
59
64
|
class ApifyStorageClient
|
|
60
65
|
|
|
61
66
|
%% ========================
|
|
@@ -65,6 +70,7 @@ class ApifyStorageClient
|
|
|
65
70
|
StorageClient --|> FileSystemStorageClient
|
|
66
71
|
StorageClient --|> MemoryStorageClient
|
|
67
72
|
StorageClient --|> SqlStorageClient
|
|
73
|
+
StorageClient --|> RedisStorageClient
|
|
68
74
|
StorageClient --|> ApifyStorageClient
|
|
69
75
|
```
|
|
70
76
|
|
|
@@ -304,8 +310,8 @@ Configuration options for the <ApiLink to="class/SqlStorageClient">`SqlStorageCl
|
|
|
304
310
|
|
|
305
311
|
Configuration options for the <ApiLink to="class/SqlStorageClient">`SqlStorageClient`</ApiLink> can be set via constructor arguments:
|
|
306
312
|
|
|
307
|
-
- **`connection_string`** (default: SQLite in <ApiLink to="class/Configuration">`Configuration`</ApiLink> storage dir)
|
|
308
|
-
- **`engine`**
|
|
313
|
+
- **`connection_string`** (default: SQLite in <ApiLink to="class/Configuration">`Configuration`</ApiLink> storage dir) - SQLAlchemy connection string, e.g. `sqlite+aiosqlite:///my.db` or `postgresql+asyncpg://user:pass@host/db`.
|
|
314
|
+
- **`engine`** - Pre-configured SQLAlchemy AsyncEngine (optional).
|
|
309
315
|
|
|
310
316
|
For advanced scenarios, you can configure <ApiLink to="class/SqlStorageClient">`SqlStorageClient`</ApiLink> with a custom SQLAlchemy engine and additional options via the <ApiLink to="class/Configuration">`Configuration`</ApiLink> class. This is useful, for example, when connecting to an external PostgreSQL database or customizing connection pooling.
|
|
311
317
|
|
|
@@ -313,6 +319,172 @@ For advanced scenarios, you can configure <ApiLink to="class/SqlStorageClient">`
|
|
|
313
319
|
{SQLStorageClientConfigurationExample}
|
|
314
320
|
</CodeBlock>
|
|
315
321
|
|
|
322
|
+
### Redis storage client
|
|
323
|
+
|
|
324
|
+
:::warning Experimental feature
|
|
325
|
+
The <ApiLink to="class/RedisStorageClient">`RedisStorageClient`</ApiLink> is experimental. Its API and behavior may change in future releases.
|
|
326
|
+
:::
|
|
327
|
+
|
|
328
|
+
The <ApiLink to="class/RedisStorageClient">`RedisStorageClient`</ApiLink> provides persistent storage using [Redis](https://redis.io/) database. It supports concurrent access from multiple independent clients or processes and uses Redis native data structures for efficient operations.
|
|
329
|
+
|
|
330
|
+
:::note dependencies
|
|
331
|
+
The <ApiLink to="class/RedisStorageClient">`RedisStorageClient`</ApiLink> is not included in the core Crawlee package.
|
|
332
|
+
To use it, you need to install Crawlee with the Redis extra dependency:
|
|
333
|
+
|
|
334
|
+
<code>pip install 'crawlee[redis]'</code>
|
|
335
|
+
|
|
336
|
+
Additionally, Redis version 8.0 or higher is required.
|
|
337
|
+
:::
|
|
338
|
+
|
|
339
|
+
:::note Redis persistence
|
|
340
|
+
Data persistence in Redis depends on your [database configuration](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/).
|
|
341
|
+
:::
|
|
342
|
+
|
|
343
|
+
The client requires either a Redis connection string or a pre-configured Redis client instance. Use a pre-configured client when you need custom Redis settings such as connection pooling, timeouts, or SSL/TLS encryption.
|
|
344
|
+
|
|
345
|
+
<CodeBlock className="language-python" language="python">
|
|
346
|
+
{RedisStorageClientBasicExample}
|
|
347
|
+
</CodeBlock>
|
|
348
|
+
|
|
349
|
+
Data is organized using Redis key patterns. Below are the main data structures used for each storage type:
|
|
350
|
+
|
|
351
|
+
```mermaid
|
|
352
|
+
---
|
|
353
|
+
config:
|
|
354
|
+
class:
|
|
355
|
+
hideEmptyMembersBox: true
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
classDiagram
|
|
359
|
+
|
|
360
|
+
%% ========================
|
|
361
|
+
%% Storage Client
|
|
362
|
+
%% ========================
|
|
363
|
+
|
|
364
|
+
class RedisDatasetClient {
|
|
365
|
+
<<Dataset>>
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
%% ========================
|
|
369
|
+
%% Dataset Keys
|
|
370
|
+
%% ========================
|
|
371
|
+
|
|
372
|
+
class DatasetKeys {
|
|
373
|
+
datasets:[name]:items - JSON Array
|
|
374
|
+
datasets:[name]:metadata - JSON Object
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
class DatasetsIndexes {
|
|
378
|
+
datasets:id_to_name - Hash
|
|
379
|
+
datasets:name_to_id - Hash
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
%% ========================
|
|
383
|
+
%% Client to Keys arrows
|
|
384
|
+
%% ========================
|
|
385
|
+
|
|
386
|
+
RedisDatasetClient --> DatasetKeys
|
|
387
|
+
RedisDatasetClient --> DatasetsIndexes
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
```mermaid
|
|
391
|
+
---
|
|
392
|
+
config:
|
|
393
|
+
class:
|
|
394
|
+
hideEmptyMembersBox: true
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
classDiagram
|
|
398
|
+
|
|
399
|
+
%% ========================
|
|
400
|
+
%% Storage Clients
|
|
401
|
+
%% ========================
|
|
402
|
+
|
|
403
|
+
class RedisKeyValueStoreClient {
|
|
404
|
+
<<Key-value store>>
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
%% ========================
|
|
408
|
+
%% Key-Value Store Keys
|
|
409
|
+
%% ========================
|
|
410
|
+
|
|
411
|
+
class KeyValueStoreKeys {
|
|
412
|
+
key_value_stores:[name]:items - Hash
|
|
413
|
+
key_value_stores:[name]:metadata_items - Hash
|
|
414
|
+
key_value_stores:[name]:metadata - JSON Object
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
class KeyValueStoresIndexes {
|
|
418
|
+
key_value_stores:id_to_name - Hash
|
|
419
|
+
key_value_stores:name_to_id - Hash
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
%% ========================
|
|
423
|
+
%% Client to Keys arrows
|
|
424
|
+
%% ========================
|
|
425
|
+
|
|
426
|
+
RedisKeyValueStoreClient --> KeyValueStoreKeys
|
|
427
|
+
RedisKeyValueStoreClient --> KeyValueStoresIndexes
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
```mermaid
|
|
431
|
+
---
|
|
432
|
+
config:
|
|
433
|
+
class:
|
|
434
|
+
hideEmptyMembersBox: true
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
classDiagram
|
|
438
|
+
|
|
439
|
+
%% ========================
|
|
440
|
+
%% Storage Clients
|
|
441
|
+
%% ========================
|
|
442
|
+
|
|
443
|
+
class RedisRequestQueueClient {
|
|
444
|
+
<<Request queue>>
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
%% ========================
|
|
448
|
+
%% Request Queue Keys
|
|
449
|
+
%% ========================
|
|
450
|
+
|
|
451
|
+
class RequestQueueKeys{
|
|
452
|
+
request_queues:[name]:queue - List
|
|
453
|
+
request_queues:[name]:data - Hash
|
|
454
|
+
request_queues:[name]:in_progress - Hash
|
|
455
|
+
request_queues:[name]:added_bloom_filter - Bloom Filter | bloom queue_dedup_strategy
|
|
456
|
+
request_queues:[name]:handled_bloom_filter - Bloom Filter | bloom queue_dedup_strategy
|
|
457
|
+
request_queues:[name]:pending_set - Set | default queue_dedup_strategy
|
|
458
|
+
request_queues:[name]:handled_set - Set | default queue_dedup_strategy
|
|
459
|
+
request_queues:[name]:metadata - JSON Object
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
class RequestQueuesIndexes {
|
|
463
|
+
request_queues:id_to_name - Hash
|
|
464
|
+
request_queues:name_to_id - Hash
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
%% ========================
|
|
468
|
+
%% Client to Keys arrows
|
|
469
|
+
%% ========================
|
|
470
|
+
|
|
471
|
+
RedisRequestQueueClient --> RequestQueueKeys
|
|
472
|
+
RedisRequestQueueClient --> RequestQueuesIndexes
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
Configuration options for the <ApiLink to="class/RedisStorageClient">`RedisStorageClient`</ApiLink> can be set through environment variables or the <ApiLink to="class/Configuration">`Configuration`</ApiLink> class:
|
|
476
|
+
|
|
477
|
+
- **`purge_on_start`** (env: `CRAWLEE_PURGE_ON_START`, default: `True`) - Whether to purge default storages on start.
|
|
478
|
+
|
|
479
|
+
Configuration options for the <ApiLink to="class/RedisStorageClient">`RedisStorageClient`</ApiLink> can be set via constructor arguments:
|
|
480
|
+
|
|
481
|
+
- **`connection_string`** - Redis connection string, e.g. `redis://localhost:6379/0`.
|
|
482
|
+
- **`redis`** - Pre-configured Redis client instance (optional).
|
|
483
|
+
|
|
484
|
+
<CodeBlock className="language-python" language="python">
|
|
485
|
+
{RedisStorageClientConfigurationExample}
|
|
486
|
+
</CodeBlock>
|
|
487
|
+
|
|
316
488
|
## Creating a custom storage client
|
|
317
489
|
|
|
318
490
|
A storage client consists of two parts: the storage client factory and individual storage type clients. The <ApiLink to="class/StorageClient">`StorageClient`</ApiLink> acts as a factory that creates specific clients (<ApiLink to="class/DatasetClient">`DatasetClient`</ApiLink>, <ApiLink to="class/KeyValueStoreClient">`KeyValueStoreClient`</ApiLink>, <ApiLink to="class/RequestQueueClient">`RequestQueueClient`</ApiLink>) where the actual storage logic is implemented.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "crawlee"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.5b13"
|
|
8
8
|
description = "Crawlee for Python"
|
|
9
9
|
authors = [{ name = "Apify Technologies s.r.o.", email = "support@apify.com" }]
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -48,7 +48,7 @@ dependencies = [
|
|
|
48
48
|
]
|
|
49
49
|
|
|
50
50
|
[project.optional-dependencies]
|
|
51
|
-
all = ["crawlee[adaptive-crawler,beautifulsoup,cli,curl-impersonate,httpx,parsel,playwright,otel,sql_sqlite,sql_postgres]"]
|
|
51
|
+
all = ["crawlee[adaptive-crawler,beautifulsoup,cli,curl-impersonate,httpx,parsel,playwright,otel,sql_sqlite,sql_postgres,redis]"]
|
|
52
52
|
adaptive-crawler = [
|
|
53
53
|
"jaro-winkler>=2.0.3",
|
|
54
54
|
"playwright>=1.27.0",
|
|
@@ -79,6 +79,7 @@ sql_sqlite = [
|
|
|
79
79
|
"sqlalchemy[asyncio]>=2.0.0,<3.0.0",
|
|
80
80
|
"aiosqlite>=0.21.0",
|
|
81
81
|
]
|
|
82
|
+
redis = ["redis[hiredis] >= 7.0.0"]
|
|
82
83
|
|
|
83
84
|
[project.scripts]
|
|
84
85
|
crawlee = "crawlee._cli:cli"
|
|
@@ -98,6 +99,7 @@ dev = [
|
|
|
98
99
|
"apify_client", # For e2e tests.
|
|
99
100
|
"build<2.0.0", # For e2e tests.
|
|
100
101
|
"dycw-pytest-only<3.0.0",
|
|
102
|
+
"fakeredis[probabilistic,json,lua]<3.0.0",
|
|
101
103
|
"mypy~=1.18.0",
|
|
102
104
|
"pre-commit<5.0.0",
|
|
103
105
|
"proxy-py<3.0.0",
|
|
@@ -13,9 +13,13 @@ _install_import_hook(__name__)
|
|
|
13
13
|
with _try_import(__name__, 'SqlStorageClient'):
|
|
14
14
|
from ._sql import SqlStorageClient
|
|
15
15
|
|
|
16
|
+
with _try_import(__name__, 'RedisStorageClient'):
|
|
17
|
+
from ._redis import RedisStorageClient
|
|
18
|
+
|
|
16
19
|
__all__ = [
|
|
17
20
|
'FileSystemStorageClient',
|
|
18
21
|
'MemoryStorageClient',
|
|
22
|
+
'RedisStorageClient',
|
|
19
23
|
'SqlStorageClient',
|
|
20
24
|
'StorageClient',
|
|
21
25
|
]
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from ._dataset_client import RedisDatasetClient
|
|
2
|
+
from ._key_value_store_client import RedisKeyValueStoreClient
|
|
3
|
+
from ._request_queue_client import RedisRequestQueueClient
|
|
4
|
+
from ._storage_client import RedisStorageClient
|
|
5
|
+
|
|
6
|
+
__all__ = ['RedisDatasetClient', 'RedisKeyValueStoreClient', 'RedisRequestQueueClient', 'RedisStorageClient']
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from contextlib import asynccontextmanager
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from logging import getLogger
|
|
7
|
+
from typing import TYPE_CHECKING, Any, ClassVar, TypedDict, overload
|
|
8
|
+
|
|
9
|
+
from crawlee._utils.crypto import crypto_random_object_id
|
|
10
|
+
|
|
11
|
+
from ._utils import await_redis_response, read_lua_script
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import AsyncIterator
|
|
15
|
+
|
|
16
|
+
from redis.asyncio import Redis
|
|
17
|
+
from redis.asyncio.client import Pipeline
|
|
18
|
+
from redis.commands.core import AsyncScript
|
|
19
|
+
from typing_extensions import NotRequired, Self
|
|
20
|
+
|
|
21
|
+
from crawlee.storage_clients.models import DatasetMetadata, KeyValueStoreMetadata, RequestQueueMetadata
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
logger = getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MetadataUpdateParams(TypedDict, total=False):
|
|
28
|
+
"""Parameters for updating metadata."""
|
|
29
|
+
|
|
30
|
+
update_accessed_at: NotRequired[bool]
|
|
31
|
+
update_modified_at: NotRequired[bool]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class RedisClientMixin:
|
|
35
|
+
"""Mixin class for Redis clients.
|
|
36
|
+
|
|
37
|
+
This mixin provides common Redis operations and basic methods for Redis storage clients.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
_DEFAULT_NAME = 'default'
|
|
41
|
+
"""Default storage name in key prefix when none provided."""
|
|
42
|
+
|
|
43
|
+
_MAIN_KEY: ClassVar[str]
|
|
44
|
+
"""Main Redis key prefix for this storage type."""
|
|
45
|
+
|
|
46
|
+
_CLIENT_TYPE: ClassVar[str]
|
|
47
|
+
"""Human-readable client type for error messages."""
|
|
48
|
+
|
|
49
|
+
def __init__(self, storage_name: str, storage_id: str, redis: Redis) -> None:
|
|
50
|
+
self._storage_name = storage_name
|
|
51
|
+
self._storage_id = storage_id
|
|
52
|
+
self._redis = redis
|
|
53
|
+
|
|
54
|
+
self._scripts_loaded = False
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def redis(self) -> Redis:
|
|
58
|
+
"""Return the Redis client instance."""
|
|
59
|
+
return self._redis
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def metadata_key(self) -> str:
|
|
63
|
+
"""Return the Redis key for the metadata of this storage."""
|
|
64
|
+
return f'{self._MAIN_KEY}:{self._storage_name}:metadata'
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
async def _get_metadata_by_name(cls, name: str, redis: Redis, *, with_wait: bool = False) -> dict | None:
|
|
68
|
+
"""Retrieve metadata by storage name.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
name: The name of the storage.
|
|
72
|
+
redis: The Redis client instance.
|
|
73
|
+
with_wait: Whether to wait for the storage to be created if it doesn't exist.
|
|
74
|
+
"""
|
|
75
|
+
if with_wait:
|
|
76
|
+
# Wait for the creation signal (max 30 seconds)
|
|
77
|
+
await await_redis_response(redis.blpop([f'{cls._MAIN_KEY}:{name}:created_signal'], timeout=30))
|
|
78
|
+
# Signal consumed, push it back for other waiters
|
|
79
|
+
await await_redis_response(redis.lpush(f'{cls._MAIN_KEY}:{name}:created_signal', 1))
|
|
80
|
+
|
|
81
|
+
response = await await_redis_response(redis.json().get(f'{cls._MAIN_KEY}:{name}:metadata'))
|
|
82
|
+
data = response[0] if response is not None and isinstance(response, list) else response
|
|
83
|
+
if data is not None and not isinstance(data, dict):
|
|
84
|
+
raise TypeError('The metadata data was received in an incorrect format.')
|
|
85
|
+
return data
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
async def _get_metadata_name_by_id(cls, id: str, redis: Redis) -> str | None:
|
|
89
|
+
"""Retrieve storage name by ID from id_to_name index.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
id: The ID of the storage.
|
|
93
|
+
redis: The Redis client instance.
|
|
94
|
+
"""
|
|
95
|
+
name = await await_redis_response(redis.hget(f'{cls._MAIN_KEY}:id_to_name', id))
|
|
96
|
+
if isinstance(name, str) or name is None:
|
|
97
|
+
return name
|
|
98
|
+
if isinstance(name, bytes):
|
|
99
|
+
return name.decode('utf-8')
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
async def _open(
|
|
104
|
+
cls,
|
|
105
|
+
*,
|
|
106
|
+
id: str | None,
|
|
107
|
+
name: str | None,
|
|
108
|
+
alias: str | None,
|
|
109
|
+
metadata_model: type[DatasetMetadata | KeyValueStoreMetadata | RequestQueueMetadata],
|
|
110
|
+
redis: Redis,
|
|
111
|
+
extra_metadata_fields: dict[str, Any],
|
|
112
|
+
instance_kwargs: dict[str, Any],
|
|
113
|
+
) -> Self:
|
|
114
|
+
"""Open or create a new Redis storage client.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
id: The ID of the storage. If not provided, a random ID will be generated.
|
|
118
|
+
name: The name of the storage for named (global scope) storages.
|
|
119
|
+
alias: The alias of the storage for unnamed (run scope) storages.
|
|
120
|
+
redis: Redis client instance.
|
|
121
|
+
metadata_model: Pydantic model for metadata validation.
|
|
122
|
+
extra_metadata_fields: Storage-specific metadata fields.
|
|
123
|
+
instance_kwargs: Additional arguments for the client constructor.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
An instance for the opened or created storage client.
|
|
127
|
+
"""
|
|
128
|
+
internal_name = name or alias or cls._DEFAULT_NAME
|
|
129
|
+
storage_id: str | None = None
|
|
130
|
+
# Determine if storage exists by ID or name
|
|
131
|
+
if id:
|
|
132
|
+
storage_name = await cls._get_metadata_name_by_id(id=id, redis=redis)
|
|
133
|
+
storage_id = id
|
|
134
|
+
if storage_name is None:
|
|
135
|
+
raise ValueError(f'{cls._CLIENT_TYPE} with ID "{id}" does not exist.')
|
|
136
|
+
else:
|
|
137
|
+
metadata_data = await cls._get_metadata_by_name(name=internal_name, redis=redis)
|
|
138
|
+
storage_name = internal_name if metadata_data is not None else None
|
|
139
|
+
storage_id = metadata_data['id'] if metadata_data is not None else None
|
|
140
|
+
# If both storage_name and storage_id are found, open existing storage
|
|
141
|
+
if storage_name and storage_id:
|
|
142
|
+
client = cls(storage_name=storage_name, storage_id=storage_id, redis=redis, **instance_kwargs)
|
|
143
|
+
async with client._get_pipeline() as pipe:
|
|
144
|
+
await client._update_metadata(pipe, update_accessed_at=True)
|
|
145
|
+
# Otherwise, create a new storage
|
|
146
|
+
else:
|
|
147
|
+
now = datetime.now(timezone.utc)
|
|
148
|
+
metadata = metadata_model(
|
|
149
|
+
id=crypto_random_object_id(),
|
|
150
|
+
name=name,
|
|
151
|
+
created_at=now,
|
|
152
|
+
accessed_at=now,
|
|
153
|
+
modified_at=now,
|
|
154
|
+
**extra_metadata_fields,
|
|
155
|
+
)
|
|
156
|
+
client = cls(storage_name=internal_name, storage_id=metadata.id, redis=redis, **instance_kwargs)
|
|
157
|
+
created = await client._create_metadata_and_storage(internal_name, metadata.model_dump())
|
|
158
|
+
# The client was probably not created due to a race condition. Let's try to open it using the name.
|
|
159
|
+
if not created:
|
|
160
|
+
metadata_data = await cls._get_metadata_by_name(name=internal_name, redis=redis, with_wait=True)
|
|
161
|
+
client = cls(storage_name=internal_name, storage_id=metadata.id, redis=redis, **instance_kwargs)
|
|
162
|
+
|
|
163
|
+
# Ensure Lua scripts are loaded
|
|
164
|
+
await client._ensure_scripts_loaded()
|
|
165
|
+
return client
|
|
166
|
+
|
|
167
|
+
async def _load_scripts(self) -> None:
|
|
168
|
+
"""Load Lua scripts in Redis."""
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
async def _ensure_scripts_loaded(self) -> None:
|
|
172
|
+
"""Ensure Lua scripts are loaded in Redis."""
|
|
173
|
+
if not self._scripts_loaded:
|
|
174
|
+
await self._load_scripts()
|
|
175
|
+
self._scripts_loaded = True
|
|
176
|
+
|
|
177
|
+
@asynccontextmanager
|
|
178
|
+
async def _get_pipeline(self, *, with_execute: bool = True) -> AsyncIterator[Pipeline]:
|
|
179
|
+
"""Create a new Redis pipeline."""
|
|
180
|
+
async with self._redis.pipeline() as pipe:
|
|
181
|
+
try:
|
|
182
|
+
pipe.multi() # type: ignore[no-untyped-call]
|
|
183
|
+
yield pipe
|
|
184
|
+
finally:
|
|
185
|
+
if with_execute:
|
|
186
|
+
await pipe.execute()
|
|
187
|
+
|
|
188
|
+
async def _create_storage(self, pipeline: Pipeline) -> None:
|
|
189
|
+
"""Create the actual storage structure in Redis."""
|
|
190
|
+
_ = pipeline # To avoid unused variable mypy error
|
|
191
|
+
|
|
192
|
+
async def _create_script(self, script_name: str) -> AsyncScript:
|
|
193
|
+
"""Load a Lua script from a file and return a Script object."""
|
|
194
|
+
script_content = await asyncio.to_thread(read_lua_script, script_name)
|
|
195
|
+
|
|
196
|
+
return self._redis.register_script(script_content)
|
|
197
|
+
|
|
198
|
+
async def _create_metadata_and_storage(self, storage_name: str, metadata: dict) -> bool:
|
|
199
|
+
index_id_to_name = f'{self._MAIN_KEY}:id_to_name'
|
|
200
|
+
index_name_to_id = f'{self._MAIN_KEY}:name_to_id'
|
|
201
|
+
metadata['created_at'] = metadata['created_at'].isoformat()
|
|
202
|
+
metadata['accessed_at'] = metadata['accessed_at'].isoformat()
|
|
203
|
+
metadata['modified_at'] = metadata['modified_at'].isoformat()
|
|
204
|
+
|
|
205
|
+
# Try to create name_to_id index entry, if it already exists, return False.
|
|
206
|
+
name_to_id = await await_redis_response(self._redis.hsetnx(index_name_to_id, storage_name, metadata['id']))
|
|
207
|
+
# If name already exists, return False. Probably an attempt at parallel creation.
|
|
208
|
+
if not name_to_id:
|
|
209
|
+
return False
|
|
210
|
+
|
|
211
|
+
# Create id_to_name index entry, metadata, and storage structure in a transaction.
|
|
212
|
+
async with self._get_pipeline() as pipe:
|
|
213
|
+
await await_redis_response(pipe.hsetnx(index_id_to_name, metadata['id'], storage_name))
|
|
214
|
+
await await_redis_response(pipe.json().set(self.metadata_key, '$', metadata))
|
|
215
|
+
await await_redis_response(pipe.lpush(f'{self._MAIN_KEY}:{storage_name}:created_signal', 1))
|
|
216
|
+
|
|
217
|
+
await self._create_storage(pipe)
|
|
218
|
+
|
|
219
|
+
return True
|
|
220
|
+
|
|
221
|
+
async def _drop(self, extra_keys: list[str]) -> None:
|
|
222
|
+
async with self._get_pipeline() as pipe:
|
|
223
|
+
await pipe.delete(self.metadata_key)
|
|
224
|
+
await pipe.delete(f'{self._MAIN_KEY}:id_to_name', self._storage_id)
|
|
225
|
+
await pipe.delete(f'{self._MAIN_KEY}:name_to_id', self._storage_name)
|
|
226
|
+
await pipe.delete(f'{self._MAIN_KEY}:{self._storage_name}:created_signal')
|
|
227
|
+
for key in extra_keys:
|
|
228
|
+
await pipe.delete(key)
|
|
229
|
+
|
|
230
|
+
async def _purge(self, extra_keys: list[str], metadata_kwargs: MetadataUpdateParams) -> None:
|
|
231
|
+
async with self._get_pipeline() as pipe:
|
|
232
|
+
for key in extra_keys:
|
|
233
|
+
await pipe.delete(key)
|
|
234
|
+
await self._update_metadata(pipe, **metadata_kwargs)
|
|
235
|
+
await self._create_storage(pipe)
|
|
236
|
+
|
|
237
|
+
@overload
|
|
238
|
+
async def _get_metadata(self, metadata_model: type[DatasetMetadata]) -> DatasetMetadata: ...
|
|
239
|
+
@overload
|
|
240
|
+
async def _get_metadata(self, metadata_model: type[KeyValueStoreMetadata]) -> KeyValueStoreMetadata: ...
|
|
241
|
+
@overload
|
|
242
|
+
async def _get_metadata(self, metadata_model: type[RequestQueueMetadata]) -> RequestQueueMetadata: ...
|
|
243
|
+
|
|
244
|
+
async def _get_metadata(
|
|
245
|
+
self, metadata_model: type[DatasetMetadata | KeyValueStoreMetadata | RequestQueueMetadata]
|
|
246
|
+
) -> DatasetMetadata | KeyValueStoreMetadata | RequestQueueMetadata:
|
|
247
|
+
"""Retrieve client metadata."""
|
|
248
|
+
metadata_dict = await self._get_metadata_by_name(name=self._storage_name, redis=self._redis)
|
|
249
|
+
if metadata_dict is None:
|
|
250
|
+
raise ValueError(f'{self._CLIENT_TYPE} with name "{self._storage_name}" does not exist.')
|
|
251
|
+
async with self._get_pipeline() as pipe:
|
|
252
|
+
await self._update_metadata(pipe, update_accessed_at=True)
|
|
253
|
+
|
|
254
|
+
return metadata_model.model_validate(metadata_dict)
|
|
255
|
+
|
|
256
|
+
async def _specific_update_metadata(self, pipeline: Pipeline, **kwargs: Any) -> None:
|
|
257
|
+
"""Pipeline operations storage-specific metadata updates.
|
|
258
|
+
|
|
259
|
+
Must be implemented by concrete classes.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
pipeline: The Redis pipeline to use for the update.
|
|
263
|
+
**kwargs: Storage-specific update parameters.
|
|
264
|
+
"""
|
|
265
|
+
_ = pipeline # To avoid unused variable mypy error
|
|
266
|
+
_ = kwargs
|
|
267
|
+
|
|
268
|
+
async def _update_metadata(
|
|
269
|
+
self,
|
|
270
|
+
pipeline: Pipeline,
|
|
271
|
+
*,
|
|
272
|
+
update_accessed_at: bool = False,
|
|
273
|
+
update_modified_at: bool = False,
|
|
274
|
+
**kwargs: Any,
|
|
275
|
+
) -> None:
|
|
276
|
+
"""Update storage metadata combining common and specific fields.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
pipeline: The Redis pipeline to use for the update.
|
|
280
|
+
update_accessed_at: Whether to update accessed_at timestamp.
|
|
281
|
+
update_modified_at: Whether to update modified_at timestamp.
|
|
282
|
+
**kwargs: Additional arguments for _specific_update_metadata.
|
|
283
|
+
"""
|
|
284
|
+
now = datetime.now(timezone.utc)
|
|
285
|
+
|
|
286
|
+
if update_accessed_at:
|
|
287
|
+
await await_redis_response(
|
|
288
|
+
pipeline.json().set(self.metadata_key, '$.accessed_at', now.isoformat(), nx=False, xx=True)
|
|
289
|
+
)
|
|
290
|
+
if update_modified_at:
|
|
291
|
+
await await_redis_response(
|
|
292
|
+
pipeline.json().set(self.metadata_key, '$.modified_at', now.isoformat(), nx=False, xx=True)
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
await self._specific_update_metadata(pipeline, **kwargs)
|