apify 3.0.2b7__tar.gz → 3.0.5b3__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.
Potentially problematic release.
This version of apify might be problematic. Click here for more details.
- {apify-3.0.2b7 → apify-3.0.5b3}/CHANGELOG.md +28 -2
- {apify-3.0.2b7 → apify-3.0.5b3}/PKG-INFO +3 -3
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/12_pay_per_event.mdx +1 -1
- {apify-3.0.2b7 → apify-3.0.5b3}/pyproject.toml +3 -3
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/_actor.py +8 -14
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/_charging.py +89 -37
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/_configuration.py +30 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/request_loaders/_apify_request_list.py +2 -2
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/_dataset_client.py +12 -29
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/_key_value_store_client.py +13 -43
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/_models.py +3 -3
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/_request_queue_client.py +2 -25
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/_request_queue_shared_client.py +45 -35
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/_request_queue_single_client.py +73 -64
- apify-3.0.5b3/src/apify/storage_clients/_apify/_storage_client.py +132 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/_utils.py +27 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_smart_apify/_storage_client.py +40 -33
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/integration/README.md +20 -9
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/conftest.py +8 -103
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_api_helpers.py +1 -1
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_dataset.py +1 -1
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_key_value_store.py +1 -1
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_lifecycle.py +4 -2
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_log.py +8 -10
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_request_queue.py +156 -118
- apify-3.0.5b3/tests/integration/actor/test_apify_storages.py +28 -0
- apify-3.0.5b3/tests/integration/apify_api/conftest.py +70 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/apify_api}/test_apify_storages.py +0 -27
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/apify_api}/test_request_queue.py +135 -161
- apify-3.0.5b3/tests/integration/conftest.py +28 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_actor_env_helpers.py +1 -1
- apify-3.0.5b3/tests/unit/actor/test_actor_log.py +107 -0
- apify-3.0.5b3/tests/unit/storage_clients/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/uv.lock +697 -589
- {apify-3.0.2b7 → apify-3.0.5b3}/website/docusaurus.config.js +4 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/package-lock.json +735 -733
- {apify-3.0.2b7 → apify-3.0.5b3}/website/package.json +2 -1
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/pages/index.js +1 -1
- apify-3.0.5b3/website/static/.nojekyll +0 -0
- apify-3.0.2b7/src/apify/storage_clients/_apify/_storage_client.py +0 -106
- apify-3.0.2b7/tests/unit/actor/test_actor_log.py +0 -112
- {apify-3.0.2b7 → apify-3.0.5b3}/.editorconfig +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.github/CODEOWNERS +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.github/workflows/build_and_deploy_docs.yaml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.github/workflows/check_pr_title.yaml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.github/workflows/pre_release.yaml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.github/workflows/release.yaml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.github/workflows/run_code_checks.yaml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.github/workflows/update_new_issue.yaml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.gitignore +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.markdownlint.yaml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/.pre-commit-config.yaml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/CONTRIBUTING.md +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/LICENSE +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/Makefile +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/README.md +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/01_overview/01_introduction.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/01_overview/02_running_actors_locally.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/01_overview/03_actor_structure.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/01_overview/code/01_introduction.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/01_overview/code/actor_structure/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/01_overview/code/actor_structure/__main__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/01_overview/code/actor_structure/main.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/01_overview/code/actor_structure/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/01_actor_lifecycle.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/02_actor_input.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/03_storages.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/04_actor_events.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/05_proxy_management.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/06_interacting_with_other_actors.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/07_webhooks.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/08_access_apify_api.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/09_running_webserver.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/10_logging.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/11_configuration.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_class_context.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_class_manual.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_context_manager.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_error_handling_context.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_error_handling_manual.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_init_exit.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_instance_context.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_instance_manual.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_reboot.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/01_status_message.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/02_input.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/03_dataset_exports.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/03_dataset_read_write.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/03_deleting_storages.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/03_kvs_iterating.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/03_kvs_public_url.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/03_kvs_read_write.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/03_opening_storages.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/03_rq.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/04_actor_events.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/05_apify_proxy.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/05_apify_proxy_config.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/05_custom_proxy.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/05_custom_proxy_function.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/05_proxy_actor_input.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/05_proxy_httpx.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/05_proxy_rotation.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/06_interacting_call.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/06_interacting_call_task.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/06_interacting_metamorph.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/06_interacting_start.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/07_webhook.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/07_webhook_preventing.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/08_actor_client.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/08_actor_new_client.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/09_webserver.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/10_log_config.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/10_logger_usage.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/10_redirect_log.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/10_redirect_log_existing_run.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/11_config.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/actor_charge.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/02_concepts/code/conditional_actor_charge.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/01_beautifulsoup_httpx.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/02_parsel_impit.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/03_playwright.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/04_selenium.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/05_crawlee.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/06_scrapy.mdx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/01_beautifulsoup_httpx.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/02_parsel_impit.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/03_playwright.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/04_selenium.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/05_crawlee_beautifulsoup.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/05_crawlee_parsel.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/05_crawlee_playwright.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/__main__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/items.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/main.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/settings.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/spiders/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/spiders/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/03_guides/code/scrapy_project/src/spiders/title.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/04_upgrading/upgrading_to_v2.md +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/04_upgrading/upgrading_to_v3.md +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/docs/pyproject.toml +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/renovate.json +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/_consts.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/_crypto.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/_models.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/_proxy_configuration.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/_utils.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/events/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/events/_apify_event_manager.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/events/_types.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/events/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/log.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/request_loaders/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/request_loaders/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/_actor_runner.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/_async_thread.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/_logging_config.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/extensions/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/extensions/_httpcache.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/middlewares/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/middlewares/apify_proxy.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/middlewares/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/pipelines/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/pipelines/actor_dataset_push.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/pipelines/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/requests.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/scheduler.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/scrapy/utils.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_apify/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_file_system/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_file_system/_key_value_store_client.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_file_system/_storage_client.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/_smart_apify/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storage_clients/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storages/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/src/apify/storages/py.typed +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/integration/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/integration/_utils.py +0 -0
- {apify-3.0.2b7/tests/integration/actor_source_base/src → apify-3.0.5b3/tests/integration/actor}/__init__.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/actor_source_base/Dockerfile +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/actor_source_base/requirements.txt +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/actor_source_base/server.py +0 -0
- {apify-3.0.2b7/tests/unit → apify-3.0.5b3/tests/integration/actor/actor_source_base/src}/__init__.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/actor_source_base/src/__main__.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/actor_source_base/src/main.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_call_timeouts.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_charge.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_create_proxy_configuration.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_events.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_actor_scrapy.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_crawlers_with_storages.py +0 -0
- {apify-3.0.2b7/tests/integration → apify-3.0.5b3/tests/integration/actor}/test_fixtures.py +0 -0
- {apify-3.0.2b7/tests/unit/actor → apify-3.0.5b3/tests/integration/apify_api}/__init__.py +0 -0
- {apify-3.0.2b7/tests/unit/events → apify-3.0.5b3/tests/unit}/__init__.py +0 -0
- {apify-3.0.2b7/tests/unit/scrapy → apify-3.0.5b3/tests/unit/actor}/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_actor_create_proxy_configuration.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_actor_dataset.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_actor_helpers.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_actor_key_value_store.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_actor_lifecycle.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_actor_non_default_instance.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_actor_request_queue.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_configuration.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/actor/test_request_list.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/conftest.py +0 -0
- {apify-3.0.2b7/tests/unit/scrapy/extensions → apify-3.0.5b3/tests/unit/events}/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/events/test_apify_event_manager.py +0 -0
- {apify-3.0.2b7/tests/unit/scrapy/middlewares → apify-3.0.5b3/tests/unit/scrapy}/__init__.py +0 -0
- {apify-3.0.2b7/tests/unit/scrapy/pipelines → apify-3.0.5b3/tests/unit/scrapy/extensions}/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/scrapy/extensions/test_httpcache.py +0 -0
- {apify-3.0.2b7/tests/unit/scrapy/requests → apify-3.0.5b3/tests/unit/scrapy/middlewares}/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/scrapy/middlewares/test_apify_proxy.py +0 -0
- {apify-3.0.2b7/tests/unit/scrapy/utils → apify-3.0.5b3/tests/unit/scrapy/pipelines}/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/scrapy/pipelines/test_actor_dataset_push.py +0 -0
- {apify-3.0.2b7/tests/unit/storage_clients → apify-3.0.5b3/tests/unit/scrapy/requests}/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/scrapy/requests/test_to_apify_request.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/scrapy/requests/test_to_scrapy_request.py +0 -0
- /apify-3.0.2b7/website/static/.nojekyll → /apify-3.0.5b3/tests/unit/scrapy/utils/__init__.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/scrapy/utils/test_apply_apify_settings.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/scrapy/utils/test_get_basic_auth_header.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/storage_clients/test_apify_request_queue_client.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/storage_clients/test_file_system.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/test_apify_storages.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/test_crypto.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/tests/unit/test_proxy_configuration.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/.eslintrc.json +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/babel.config.js +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/build_api_reference.sh +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/generate_module_shortcuts.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/sidebars.js +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/components/ApiLink.jsx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/components/Gradients.jsx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/components/Highlights.jsx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/components/Highlights.module.css +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/components/RunnableCodeBlock.jsx +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/components/RunnableCodeBlock.module.css +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/css/custom.css +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/pages/home_page_example.py +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/pages/index.module.css +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/src/theme/DocItem/Content/index.js +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/static/img/docs-og.png +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/static/img/guides/redirected_logs_example.webp +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/tools/docs-prettier.config.js +0 -0
- {apify-3.0.2b7 → apify-3.0.5b3}/website/tools/utils/externalLink.js +0 -0
|
@@ -3,7 +3,34 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
5
|
<!-- git-cliff-unreleased-start -->
|
|
6
|
-
## 3.0.
|
|
6
|
+
## 3.0.5 - **not yet released**
|
|
7
|
+
|
|
8
|
+
### 🐛 Bug Fixes
|
|
9
|
+
|
|
10
|
+
- Fix crash in `Actor.push_data` with PPE and a strict charging limit ([#664](https://github.com/apify/apify-sdk-python/pull/664)) ([8f2e4b2](https://github.com/apify/apify-sdk-python/commit/8f2e4b2cc1f62e9a09656b4d3334caf840338a3a)) by [@janbuchar](https://github.com/janbuchar)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<!-- git-cliff-unreleased-end -->
|
|
14
|
+
## [3.0.4](https://github.com/apify/apify-sdk-python/releases/tag/v3.0.4) (2025-11-03)
|
|
15
|
+
|
|
16
|
+
### 🐛 Bug Fixes
|
|
17
|
+
|
|
18
|
+
- Fix type of `cloud_storage_client` in `SmartApifyStorageClient` ([#642](https://github.com/apify/apify-sdk-python/pull/642)) ([3bf285d](https://github.com/apify/apify-sdk-python/commit/3bf285d60f507730954986a80c19ed2e27a38f9c)) by [@vdusek](https://github.com/vdusek)
|
|
19
|
+
- Fix local charging log dataset name ([#649](https://github.com/apify/apify-sdk-python/pull/649)) ([fdb1276](https://github.com/apify/apify-sdk-python/commit/fdb1276264aee2687596d87c96d19033fe915823)) by [@vdusek](https://github.com/vdusek), closes [#648](https://github.com/apify/apify-sdk-python/issues/648)
|
|
20
|
+
|
|
21
|
+
### ⚡ Performance
|
|
22
|
+
|
|
23
|
+
- Use Apify-provided environment variables to obtain PPE pricing information ([#644](https://github.com/apify/apify-sdk-python/pull/644)) ([0c32f29](https://github.com/apify/apify-sdk-python/commit/0c32f29d6a316f5bacc931595d694f262c925b2b)) by [@Mantisus](https://github.com/Mantisus), closes [#614](https://github.com/apify/apify-sdk-python/issues/614)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
## [3.0.3](https://github.com/apify/apify-sdk-python/releases/tag/v3.0.3) (2025-10-21)
|
|
27
|
+
|
|
28
|
+
### 🐛 Bug Fixes
|
|
29
|
+
|
|
30
|
+
- Cache requests in RQ implementations by `id` ([#633](https://github.com/apify/apify-sdk-python/pull/633)) ([76886ce](https://github.com/apify/apify-sdk-python/commit/76886ce496165346a01f67e018547287c211ea54)) by [@Pijukatel](https://github.com/Pijukatel), closes [#630](https://github.com/apify/apify-sdk-python/issues/630)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## [3.0.2](https://github.com/apify/apify-sdk-python/releases/tag/v3.0.2) (2025-10-17)
|
|
7
34
|
|
|
8
35
|
### 🐛 Bug Fixes
|
|
9
36
|
|
|
@@ -12,7 +39,6 @@ All notable changes to this project will be documented in this file.
|
|
|
12
39
|
- Handle truncated `unique_key` in `list_head` by fetching full request data ([#631](https://github.com/apify/apify-sdk-python/pull/631)) ([4238086](https://github.com/apify/apify-sdk-python/commit/423808678d9155a84a266bf50bb09f1a56466174)) by [@vdusek](https://github.com/vdusek), closes [#627](https://github.com/apify/apify-sdk-python/issues/627)
|
|
13
40
|
|
|
14
41
|
|
|
15
|
-
<!-- git-cliff-unreleased-end -->
|
|
16
42
|
## [3.0.1](https://github.com/apify/apify-sdk-python/releases/tag/v3.0.1) (2025-10-08)
|
|
17
43
|
|
|
18
44
|
### 🐛 Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apify
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.5b3
|
|
4
4
|
Summary: Apify SDK for Python
|
|
5
5
|
Project-URL: Apify Homepage, https://apify.com
|
|
6
6
|
Project-URL: Changelog, https://docs.apify.com/sdk/python/docs/changelog
|
|
@@ -225,10 +225,10 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
225
225
|
Classifier: Programming Language :: Python :: 3.13
|
|
226
226
|
Classifier: Topic :: Software Development :: Libraries
|
|
227
227
|
Requires-Python: >=3.10
|
|
228
|
-
Requires-Dist: apify-client<3.0.0,>=2.
|
|
228
|
+
Requires-Dist: apify-client<3.0.0,>=2.2.0
|
|
229
229
|
Requires-Dist: apify-shared<3.0.0,>=2.0.0
|
|
230
230
|
Requires-Dist: cachetools>=5.5.0
|
|
231
|
-
Requires-Dist: crawlee<2.0.0,>=1.0.
|
|
231
|
+
Requires-Dist: crawlee<2.0.0,>=1.0.4
|
|
232
232
|
Requires-Dist: cryptography>=42.0.0
|
|
233
233
|
Requires-Dist: impit>=0.6.1
|
|
234
234
|
Requires-Dist: lazy-object-proxy>=1.11.0
|
|
@@ -47,6 +47,6 @@ It is encouraged to test your monetization code on your machine before releasing
|
|
|
47
47
|
ACTOR_TEST_PAY_PER_EVENT=true python -m youractor
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
If you also wish to see a log of all the events charged throughout the run, the Apify SDK keeps a log of charged events in a so called charging dataset. Your charging dataset can be found under the `
|
|
50
|
+
If you also wish to see a log of all the events charged throughout the run, the Apify SDK keeps a log of charged events in a so called charging dataset. Your charging dataset can be found under the `charging-log` name (unless you change your storage settings, this dataset is stored in `storage/datasets/charging-log/`). Please note that this log is not available when running the Actor in production on the Apify platform.
|
|
51
51
|
|
|
52
52
|
Because pricing configuration is stored by the Apify platform, all events will have a default price of $1.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "apify"
|
|
7
|
-
version = "3.0.
|
|
7
|
+
version = "3.0.5b3"
|
|
8
8
|
description = "Apify SDK for Python"
|
|
9
9
|
authors = [{ name = "Apify Technologies s.r.o.", email = "support@apify.com" }]
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -34,9 +34,9 @@ keywords = [
|
|
|
34
34
|
"scraping",
|
|
35
35
|
]
|
|
36
36
|
dependencies = [
|
|
37
|
-
"apify-client>=2.
|
|
37
|
+
"apify-client>=2.2.0,<3.0.0",
|
|
38
38
|
"apify-shared>=2.0.0,<3.0.0",
|
|
39
|
-
"crawlee>=1.0.
|
|
39
|
+
"crawlee>=1.0.4,<2.0.0",
|
|
40
40
|
"cachetools>=5.5.0",
|
|
41
41
|
"cryptography>=42.0.0",
|
|
42
42
|
"impit>=0.6.1",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
import os
|
|
5
4
|
import sys
|
|
6
5
|
from contextlib import suppress
|
|
7
6
|
from datetime import datetime, timedelta, timezone
|
|
@@ -48,7 +47,6 @@ if TYPE_CHECKING:
|
|
|
48
47
|
from typing_extensions import Self
|
|
49
48
|
|
|
50
49
|
from crawlee.proxy_configuration import _NewUrlFunction
|
|
51
|
-
from crawlee.storage_clients import StorageClient
|
|
52
50
|
|
|
53
51
|
from apify._models import Webhook
|
|
54
52
|
|
|
@@ -140,7 +138,6 @@ class _ActorType:
|
|
|
140
138
|
# `__init__` method should not be considered final.
|
|
141
139
|
|
|
142
140
|
self._apify_client: ApifyClientAsync | None = None
|
|
143
|
-
self._local_storage_client: StorageClient | None = None
|
|
144
141
|
|
|
145
142
|
self._is_exiting = False
|
|
146
143
|
self._is_initialized = False
|
|
@@ -617,18 +614,20 @@ class _ActorType:
|
|
|
617
614
|
else None
|
|
618
615
|
)
|
|
619
616
|
|
|
617
|
+
# Push as many items as we can charge for
|
|
618
|
+
pushed_items_count = min(max_charged_count, len(data)) if max_charged_count is not None else len(data)
|
|
619
|
+
|
|
620
620
|
dataset = await self.open_dataset()
|
|
621
621
|
|
|
622
|
-
if
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
else:
|
|
622
|
+
if pushed_items_count < len(data):
|
|
623
|
+
await dataset.push_data(data[:pushed_items_count])
|
|
624
|
+
elif pushed_items_count > 0:
|
|
626
625
|
await dataset.push_data(data)
|
|
627
626
|
|
|
628
627
|
if charged_event_name:
|
|
629
628
|
return await self.get_charging_manager().charge(
|
|
630
629
|
event_name=charged_event_name,
|
|
631
|
-
count=
|
|
630
|
+
count=pushed_items_count,
|
|
632
631
|
)
|
|
633
632
|
|
|
634
633
|
return None
|
|
@@ -1290,16 +1289,11 @@ class _ActorType:
|
|
|
1290
1289
|
raise RuntimeError('The Actor was not initialized!')
|
|
1291
1290
|
|
|
1292
1291
|
def _get_default_exit_process(self) -> bool:
|
|
1293
|
-
"""Return False for IPython
|
|
1292
|
+
"""Return False for IPython and Scrapy environments, True otherwise."""
|
|
1294
1293
|
if is_running_in_ipython():
|
|
1295
1294
|
self.log.debug('Running in IPython, setting default `exit_process` to False.')
|
|
1296
1295
|
return False
|
|
1297
1296
|
|
|
1298
|
-
# Check if running in Pytest by detecting the relevant environment variable.
|
|
1299
|
-
if os.getenv('PYTEST_CURRENT_TEST'):
|
|
1300
|
-
self.log.debug('Running in Pytest, setting default `exit_process` to False.')
|
|
1301
|
-
return False
|
|
1302
|
-
|
|
1303
1297
|
# Check if running in Scrapy by attempting to import it.
|
|
1304
1298
|
with suppress(ImportError):
|
|
1305
1299
|
import scrapy # noqa: F401 PLC0415
|
|
@@ -4,13 +4,20 @@ import math
|
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from datetime import datetime, timezone
|
|
6
6
|
from decimal import Decimal
|
|
7
|
-
from typing import TYPE_CHECKING, Protocol
|
|
7
|
+
from typing import TYPE_CHECKING, Protocol, TypedDict
|
|
8
8
|
|
|
9
9
|
from pydantic import TypeAdapter
|
|
10
10
|
|
|
11
11
|
from crawlee._utils.context import ensure_context
|
|
12
12
|
|
|
13
|
-
from apify._models import
|
|
13
|
+
from apify._models import (
|
|
14
|
+
ActorRun,
|
|
15
|
+
FlatPricePerMonthActorPricingInfo,
|
|
16
|
+
FreeActorPricingInfo,
|
|
17
|
+
PayPerEventActorPricingInfo,
|
|
18
|
+
PricePerDatasetItemActorPricingInfo,
|
|
19
|
+
PricingModel,
|
|
20
|
+
)
|
|
14
21
|
from apify._utils import docs_group
|
|
15
22
|
from apify.log import logger
|
|
16
23
|
from apify.storages import Dataset
|
|
@@ -111,24 +118,16 @@ class ActorPricingInfo:
|
|
|
111
118
|
class ChargingManagerImplementation(ChargingManager):
|
|
112
119
|
"""Implementation of the `ChargingManager` Protocol - this is only meant to be instantiated internally."""
|
|
113
120
|
|
|
114
|
-
LOCAL_CHARGING_LOG_DATASET_NAME = '
|
|
121
|
+
LOCAL_CHARGING_LOG_DATASET_NAME = 'charging-log'
|
|
115
122
|
|
|
116
123
|
def __init__(self, configuration: Configuration, client: ApifyClientAsync) -> None:
|
|
117
124
|
self._max_total_charge_usd = configuration.max_total_charge_usd or Decimal('inf')
|
|
125
|
+
self._configuration = configuration
|
|
118
126
|
self._is_at_home = configuration.is_at_home
|
|
119
127
|
self._actor_run_id = configuration.actor_run_id
|
|
120
128
|
self._purge_charging_log_dataset = configuration.purge_on_start
|
|
121
129
|
self._pricing_model: PricingModel | None = None
|
|
122
130
|
|
|
123
|
-
if configuration.test_pay_per_event:
|
|
124
|
-
if self._is_at_home:
|
|
125
|
-
raise ValueError(
|
|
126
|
-
'Using the ACTOR_TEST_PAY_PER_EVENT environment variable is only supported '
|
|
127
|
-
'in a local development environment'
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
self._pricing_model = 'PAY_PER_EVENT'
|
|
131
|
-
|
|
132
131
|
self._client = client
|
|
133
132
|
self._charging_log_dataset: Dataset | None = None
|
|
134
133
|
|
|
@@ -140,37 +139,46 @@ class ChargingManagerImplementation(ChargingManager):
|
|
|
140
139
|
|
|
141
140
|
async def __aenter__(self) -> None:
|
|
142
141
|
"""Initialize the charging manager - this is called by the `Actor` class and shouldn't be invoked manually."""
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
raise RuntimeError('Actor run ID not found even though the Actor is running on Apify')
|
|
142
|
+
# Validate config
|
|
143
|
+
if self._configuration.test_pay_per_event and self._is_at_home:
|
|
144
|
+
raise ValueError(
|
|
145
|
+
'Using the ACTOR_TEST_PAY_PER_EVENT environment variable is only supported '
|
|
146
|
+
'in a local development environment'
|
|
147
|
+
)
|
|
150
148
|
|
|
151
|
-
|
|
152
|
-
if run is None:
|
|
153
|
-
raise RuntimeError('Actor run not found')
|
|
149
|
+
self.active = True
|
|
154
150
|
|
|
155
|
-
|
|
156
|
-
|
|
151
|
+
# Retrieve pricing information from env vars or API
|
|
152
|
+
pricing_data = await self._fetch_pricing_info()
|
|
153
|
+
pricing_info = pricing_data['pricing_info']
|
|
154
|
+
charged_event_counts = pricing_data['charged_event_counts']
|
|
155
|
+
max_total_charge_usd = pricing_data['max_total_charge_usd']
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
157
|
+
# Set pricing model
|
|
158
|
+
if self._configuration.test_pay_per_event:
|
|
159
|
+
self._pricing_model = 'PAY_PER_EVENT'
|
|
160
|
+
else:
|
|
161
|
+
self._pricing_model = pricing_info.pricing_model if pricing_info else None
|
|
162
|
+
|
|
163
|
+
# Load per-event pricing information
|
|
164
|
+
if pricing_info and pricing_info.pricing_model == 'PAY_PER_EVENT':
|
|
165
|
+
for event_name, event_pricing in pricing_info.pricing_per_event.actor_charge_events.items():
|
|
166
|
+
self._pricing_info[event_name] = PricingInfoItem(
|
|
167
|
+
price=event_pricing.event_price_usd,
|
|
168
|
+
title=event_pricing.event_title,
|
|
169
|
+
)
|
|
164
170
|
|
|
165
|
-
|
|
171
|
+
self._max_total_charge_usd = max_total_charge_usd
|
|
166
172
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
# Load charged event counts
|
|
174
|
+
for event_name, count in charged_event_counts.items():
|
|
175
|
+
price = self._pricing_info.get(event_name, PricingInfoItem(Decimal(), title='')).price
|
|
176
|
+
self._charging_state[event_name] = ChargingStateItem(
|
|
177
|
+
charge_count=count,
|
|
178
|
+
total_charged_amount=count * price,
|
|
179
|
+
)
|
|
173
180
|
|
|
181
|
+
# Set up charging log dataset for local development
|
|
174
182
|
if not self._is_at_home and self._pricing_model == 'PAY_PER_EVENT':
|
|
175
183
|
# We are not running on the Apify platform, but PPE is enabled for testing - open a dataset that
|
|
176
184
|
# will contain a log of all charge calls for debugging purposes.
|
|
@@ -328,6 +336,38 @@ class ChargingManagerImplementation(ChargingManager):
|
|
|
328
336
|
def get_max_total_charge_usd(self) -> Decimal:
|
|
329
337
|
return self._max_total_charge_usd
|
|
330
338
|
|
|
339
|
+
async def _fetch_pricing_info(self) -> _FetchedPricingInfoDict:
|
|
340
|
+
"""Fetch pricing information from environment variables or API."""
|
|
341
|
+
# Check if pricing info is available via environment variables
|
|
342
|
+
if self._configuration.actor_pricing_info is not None and self._configuration.charged_event_counts is not None:
|
|
343
|
+
return _FetchedPricingInfoDict(
|
|
344
|
+
pricing_info=self._configuration.actor_pricing_info,
|
|
345
|
+
charged_event_counts=self._configuration.charged_event_counts,
|
|
346
|
+
max_total_charge_usd=self._configuration.max_total_charge_usd or Decimal('inf'),
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# Fall back to API call
|
|
350
|
+
if self._is_at_home:
|
|
351
|
+
if self._actor_run_id is None:
|
|
352
|
+
raise RuntimeError('Actor run ID not found even though the Actor is running on Apify')
|
|
353
|
+
|
|
354
|
+
run = run_validator.validate_python(await self._client.run(self._actor_run_id).get())
|
|
355
|
+
if run is None:
|
|
356
|
+
raise RuntimeError('Actor run not found')
|
|
357
|
+
|
|
358
|
+
return _FetchedPricingInfoDict(
|
|
359
|
+
pricing_info=run.pricing_info,
|
|
360
|
+
charged_event_counts=run.charged_event_counts or {},
|
|
361
|
+
max_total_charge_usd=run.options.max_total_charge_usd or Decimal('inf'),
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
# Local development without environment variables
|
|
365
|
+
return _FetchedPricingInfoDict(
|
|
366
|
+
pricing_info=None,
|
|
367
|
+
charged_event_counts={},
|
|
368
|
+
max_total_charge_usd=self._configuration.max_total_charge_usd or Decimal('inf'),
|
|
369
|
+
)
|
|
370
|
+
|
|
331
371
|
|
|
332
372
|
@dataclass
|
|
333
373
|
class ChargingStateItem:
|
|
@@ -339,3 +379,15 @@ class ChargingStateItem:
|
|
|
339
379
|
class PricingInfoItem:
|
|
340
380
|
price: Decimal
|
|
341
381
|
title: str
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class _FetchedPricingInfoDict(TypedDict):
|
|
385
|
+
pricing_info: (
|
|
386
|
+
FreeActorPricingInfo
|
|
387
|
+
| FlatPricePerMonthActorPricingInfo
|
|
388
|
+
| PricePerDatasetItemActorPricingInfo
|
|
389
|
+
| PayPerEventActorPricingInfo
|
|
390
|
+
| None
|
|
391
|
+
)
|
|
392
|
+
charged_event_counts: dict[str, int]
|
|
393
|
+
max_total_charge_usd: Decimal
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
from datetime import datetime, timedelta
|
|
4
5
|
from decimal import Decimal
|
|
5
6
|
from logging import getLogger
|
|
@@ -14,6 +15,12 @@ from crawlee._utils.models import timedelta_ms
|
|
|
14
15
|
from crawlee._utils.urls import validate_http_url
|
|
15
16
|
from crawlee.configuration import Configuration as CrawleeConfiguration
|
|
16
17
|
|
|
18
|
+
from apify._models import (
|
|
19
|
+
FlatPricePerMonthActorPricingInfo,
|
|
20
|
+
FreeActorPricingInfo,
|
|
21
|
+
PayPerEventActorPricingInfo,
|
|
22
|
+
PricePerDatasetItemActorPricingInfo,
|
|
23
|
+
)
|
|
17
24
|
from apify._utils import docs_group
|
|
18
25
|
|
|
19
26
|
logger = getLogger(__name__)
|
|
@@ -409,6 +416,29 @@ class Configuration(CrawleeConfiguration):
|
|
|
409
416
|
),
|
|
410
417
|
] = None
|
|
411
418
|
|
|
419
|
+
actor_pricing_info: Annotated[
|
|
420
|
+
FreeActorPricingInfo
|
|
421
|
+
| FlatPricePerMonthActorPricingInfo
|
|
422
|
+
| PricePerDatasetItemActorPricingInfo
|
|
423
|
+
| PayPerEventActorPricingInfo
|
|
424
|
+
| None,
|
|
425
|
+
Field(
|
|
426
|
+
alias='apify_actor_pricing_info',
|
|
427
|
+
description='JSON string with prising info of the actor',
|
|
428
|
+
discriminator='pricing_model',
|
|
429
|
+
),
|
|
430
|
+
BeforeValidator(lambda data: json.loads(data) if isinstance(data, str) else data if data else None),
|
|
431
|
+
] = None
|
|
432
|
+
|
|
433
|
+
charged_event_counts: Annotated[
|
|
434
|
+
dict[str, int] | None,
|
|
435
|
+
Field(
|
|
436
|
+
alias='apify_charged_actor_event_counts',
|
|
437
|
+
description='Counts of events that were charged for the actor',
|
|
438
|
+
),
|
|
439
|
+
BeforeValidator(lambda data: json.loads(data) if isinstance(data, str) else data if data else None),
|
|
440
|
+
] = None
|
|
441
|
+
|
|
412
442
|
@model_validator(mode='after')
|
|
413
443
|
def disable_browser_sandbox_on_platform(self) -> Self:
|
|
414
444
|
"""Disable the browser sandbox mode when running on the Apify platform.
|
|
@@ -22,8 +22,8 @@ URL_NO_COMMAS_REGEX = re.compile(
|
|
|
22
22
|
class _RequestDetails(BaseModel):
|
|
23
23
|
method: HttpMethod = 'GET'
|
|
24
24
|
payload: str = ''
|
|
25
|
-
headers: Annotated[dict[str, str], Field(default_factory=dict)]
|
|
26
|
-
user_data: Annotated[dict[str, str], Field(default_factory=dict, alias='userData')]
|
|
25
|
+
headers: Annotated[dict[str, str], Field(default_factory=dict)]
|
|
26
|
+
user_data: Annotated[dict[str, str], Field(default_factory=dict, alias='userData')]
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class _RequestsFromUrlInput(_RequestDetails):
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import warnings
|
|
4
5
|
from logging import getLogger
|
|
5
6
|
from typing import TYPE_CHECKING, Any
|
|
6
7
|
|
|
7
8
|
from typing_extensions import override
|
|
8
9
|
|
|
9
|
-
from apify_client import ApifyClientAsync
|
|
10
10
|
from crawlee._utils.byte_size import ByteSize
|
|
11
11
|
from crawlee._utils.file import json_dumps
|
|
12
12
|
from crawlee.storage_clients._base import DatasetClient
|
|
13
13
|
from crawlee.storage_clients.models import DatasetItemsListPage, DatasetMetadata
|
|
14
14
|
from crawlee.storages import Dataset
|
|
15
15
|
|
|
16
|
-
from ._utils import AliasResolver
|
|
16
|
+
from ._utils import AliasResolver, create_apify_client
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
19
19
|
from collections.abc import AsyncIterator
|
|
@@ -52,12 +52,17 @@ class ApifyDatasetClient(DatasetClient):
|
|
|
52
52
|
self._api_client = api_client
|
|
53
53
|
"""The Apify dataset client for API operations."""
|
|
54
54
|
|
|
55
|
-
self._api_public_base_url = api_public_base_url
|
|
56
|
-
"""The public base URL for accessing the key-value store records."""
|
|
57
|
-
|
|
58
55
|
self._lock = lock
|
|
59
56
|
"""A lock to ensure that only one operation is performed at a time."""
|
|
60
57
|
|
|
58
|
+
if api_public_base_url:
|
|
59
|
+
# Remove in version 4.0, https://github.com/apify/apify-sdk-python/issues/635
|
|
60
|
+
warnings.warn(
|
|
61
|
+
'api_public_base_url argument is deprecated and will be removed in version 4.0.0',
|
|
62
|
+
DeprecationWarning,
|
|
63
|
+
stacklevel=2,
|
|
64
|
+
)
|
|
65
|
+
|
|
61
66
|
@override
|
|
62
67
|
async def get_metadata(self) -> DatasetMetadata:
|
|
63
68
|
metadata = await self._api_client.get()
|
|
@@ -99,29 +104,7 @@ class ApifyDatasetClient(DatasetClient):
|
|
|
99
104
|
if sum(1 for param in [id, name, alias] if param is not None) > 1:
|
|
100
105
|
raise ValueError('Only one of "id", "name", or "alias" can be specified, not multiple.')
|
|
101
106
|
|
|
102
|
-
|
|
103
|
-
if not token:
|
|
104
|
-
raise ValueError(f'Apify storage client requires a valid token in Configuration (token={token}).')
|
|
105
|
-
|
|
106
|
-
api_url = configuration.api_base_url
|
|
107
|
-
if not api_url:
|
|
108
|
-
raise ValueError(f'Apify storage client requires a valid API URL in Configuration (api_url={api_url}).')
|
|
109
|
-
|
|
110
|
-
api_public_base_url = configuration.api_public_base_url
|
|
111
|
-
if not api_public_base_url:
|
|
112
|
-
raise ValueError(
|
|
113
|
-
'Apify storage client requires a valid API public base URL in Configuration '
|
|
114
|
-
f'(api_public_base_url={api_public_base_url}).'
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
# Create Apify client with the provided token and API URL.
|
|
118
|
-
apify_client_async = ApifyClientAsync(
|
|
119
|
-
token=token,
|
|
120
|
-
api_url=api_url,
|
|
121
|
-
max_retries=8,
|
|
122
|
-
min_delay_between_retries_millis=500,
|
|
123
|
-
timeout_secs=360,
|
|
124
|
-
)
|
|
107
|
+
apify_client_async = create_apify_client(configuration)
|
|
125
108
|
apify_datasets_client = apify_client_async.datasets()
|
|
126
109
|
|
|
127
110
|
# Normalize unnamed default storage in cases where not defined in `configuration.default_dataset_id` to unnamed
|
|
@@ -178,7 +161,7 @@ class ApifyDatasetClient(DatasetClient):
|
|
|
178
161
|
|
|
179
162
|
return cls(
|
|
180
163
|
api_client=apify_dataset_client,
|
|
181
|
-
api_public_base_url=
|
|
164
|
+
api_public_base_url='', # Remove in version 4.0, https://github.com/apify/apify-sdk-python/issues/635
|
|
182
165
|
lock=asyncio.Lock(),
|
|
183
166
|
)
|
|
184
167
|
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import warnings
|
|
4
5
|
from logging import getLogger
|
|
5
6
|
from typing import TYPE_CHECKING, Any
|
|
6
7
|
|
|
7
8
|
from typing_extensions import override
|
|
8
|
-
from yarl import URL
|
|
9
9
|
|
|
10
|
-
from apify_client import ApifyClientAsync
|
|
11
10
|
from crawlee.storage_clients._base import KeyValueStoreClient
|
|
12
11
|
from crawlee.storage_clients.models import KeyValueStoreRecord, KeyValueStoreRecordMetadata
|
|
13
12
|
from crawlee.storages import KeyValueStore
|
|
14
13
|
|
|
15
14
|
from ._models import ApifyKeyValueStoreMetadata, KeyValueStoreListKeysPage
|
|
16
|
-
from ._utils import AliasResolver
|
|
17
|
-
from apify._crypto import create_hmac_signature
|
|
15
|
+
from ._utils import AliasResolver, create_apify_client
|
|
18
16
|
|
|
19
17
|
if TYPE_CHECKING:
|
|
20
18
|
from collections.abc import AsyncIterator
|
|
@@ -43,12 +41,17 @@ class ApifyKeyValueStoreClient(KeyValueStoreClient):
|
|
|
43
41
|
self._api_client = api_client
|
|
44
42
|
"""The Apify KVS client for API operations."""
|
|
45
43
|
|
|
46
|
-
self._api_public_base_url = api_public_base_url
|
|
47
|
-
"""The public base URL for accessing the key-value store records."""
|
|
48
|
-
|
|
49
44
|
self._lock = lock
|
|
50
45
|
"""A lock to ensure that only one operation is performed at a time."""
|
|
51
46
|
|
|
47
|
+
if api_public_base_url:
|
|
48
|
+
# Remove in version 4.0, https://github.com/apify/apify-sdk-python/issues/635
|
|
49
|
+
warnings.warn(
|
|
50
|
+
'api_public_base_url argument is deprecated and will be removed in version 4.0.0',
|
|
51
|
+
DeprecationWarning,
|
|
52
|
+
stacklevel=2,
|
|
53
|
+
)
|
|
54
|
+
|
|
52
55
|
@override
|
|
53
56
|
async def get_metadata(self) -> ApifyKeyValueStoreMetadata:
|
|
54
57
|
metadata = await self._api_client.get()
|
|
@@ -90,29 +93,7 @@ class ApifyKeyValueStoreClient(KeyValueStoreClient):
|
|
|
90
93
|
if sum(1 for param in [id, name, alias] if param is not None) > 1:
|
|
91
94
|
raise ValueError('Only one of "id", "name", or "alias" can be specified, not multiple.')
|
|
92
95
|
|
|
93
|
-
|
|
94
|
-
if not token:
|
|
95
|
-
raise ValueError(f'Apify storage client requires a valid token in Configuration (token={token}).')
|
|
96
|
-
|
|
97
|
-
api_url = configuration.api_base_url
|
|
98
|
-
if not api_url:
|
|
99
|
-
raise ValueError(f'Apify storage client requires a valid API URL in Configuration (api_url={api_url}).')
|
|
100
|
-
|
|
101
|
-
api_public_base_url = configuration.api_public_base_url
|
|
102
|
-
if not api_public_base_url:
|
|
103
|
-
raise ValueError(
|
|
104
|
-
'Apify storage client requires a valid API public base URL in Configuration '
|
|
105
|
-
f'(api_public_base_url={api_public_base_url}).'
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
# Create Apify client with the provided token and API URL.
|
|
109
|
-
apify_client_async = ApifyClientAsync(
|
|
110
|
-
token=token,
|
|
111
|
-
api_url=api_url,
|
|
112
|
-
max_retries=8,
|
|
113
|
-
min_delay_between_retries_millis=500,
|
|
114
|
-
timeout_secs=360,
|
|
115
|
-
)
|
|
96
|
+
apify_client_async = create_apify_client(configuration)
|
|
116
97
|
apify_kvss_client = apify_client_async.key_value_stores()
|
|
117
98
|
|
|
118
99
|
# Normalize unnamed default storage in cases where not defined in `configuration.default_key_value_store_id` to
|
|
@@ -170,7 +151,7 @@ class ApifyKeyValueStoreClient(KeyValueStoreClient):
|
|
|
170
151
|
|
|
171
152
|
return cls(
|
|
172
153
|
api_client=apify_kvs_client,
|
|
173
|
-
api_public_base_url=
|
|
154
|
+
api_public_base_url='', # Remove in version 4.0, https://github.com/apify/apify-sdk-python/issues/635
|
|
174
155
|
lock=asyncio.Lock(),
|
|
175
156
|
)
|
|
176
157
|
|
|
@@ -251,15 +232,4 @@ class ApifyKeyValueStoreClient(KeyValueStoreClient):
|
|
|
251
232
|
Returns:
|
|
252
233
|
A public URL that can be used to access the value of the given key in the KVS.
|
|
253
234
|
"""
|
|
254
|
-
|
|
255
|
-
raise ValueError('resource_id cannot be None when generating a public URL')
|
|
256
|
-
|
|
257
|
-
public_url = (
|
|
258
|
-
URL(self._api_public_base_url) / 'v2' / 'key-value-stores' / self._api_client.resource_id / 'records' / key
|
|
259
|
-
)
|
|
260
|
-
metadata = await self.get_metadata()
|
|
261
|
-
|
|
262
|
-
if metadata.url_signing_secret_key is not None:
|
|
263
|
-
public_url = public_url.with_query(signature=create_hmac_signature(metadata.url_signing_secret_key, key))
|
|
264
|
-
|
|
265
|
-
return str(public_url)
|
|
235
|
+
return await self._api_client.get_record_public_url(key=key)
|
|
@@ -94,8 +94,8 @@ class CachedRequest(BaseModel):
|
|
|
94
94
|
Only internal structure.
|
|
95
95
|
"""
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
"""
|
|
97
|
+
id: str
|
|
98
|
+
"""Id of the request."""
|
|
99
99
|
|
|
100
100
|
was_already_handled: bool
|
|
101
101
|
"""Whether the request was already handled."""
|
|
@@ -120,7 +120,7 @@ class RequestQueueStats(BaseModel):
|
|
|
120
120
|
"""The number of request queue reads."""
|
|
121
121
|
|
|
122
122
|
storage_bytes: Annotated[int, Field(alias='storageBytes', default=0)]
|
|
123
|
-
"""Storage size in
|
|
123
|
+
"""Storage size in bytes."""
|
|
124
124
|
|
|
125
125
|
write_count: Annotated[int, Field(alias='writeCount', default=0)]
|
|
126
126
|
"""The number of request queue writes."""
|
|
@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Final, Literal
|
|
|
5
5
|
|
|
6
6
|
from typing_extensions import override
|
|
7
7
|
|
|
8
|
-
from apify_client import ApifyClientAsync
|
|
9
8
|
from crawlee._utils.crypto import crypto_random_object_id
|
|
10
9
|
from crawlee.storage_clients._base import RequestQueueClient
|
|
11
10
|
from crawlee.storage_clients.models import AddRequestsResponse, ProcessedRequest, RequestQueueMetadata
|
|
@@ -14,7 +13,7 @@ from crawlee.storages import RequestQueue
|
|
|
14
13
|
from ._models import ApifyRequestQueueMetadata, RequestQueueStats
|
|
15
14
|
from ._request_queue_shared_client import ApifyRequestQueueSharedClient
|
|
16
15
|
from ._request_queue_single_client import ApifyRequestQueueSingleClient
|
|
17
|
-
from ._utils import AliasResolver
|
|
16
|
+
from ._utils import AliasResolver, create_apify_client
|
|
18
17
|
|
|
19
18
|
if TYPE_CHECKING:
|
|
20
19
|
from collections.abc import Sequence
|
|
@@ -228,29 +227,7 @@ class ApifyRequestQueueClient(RequestQueueClient):
|
|
|
228
227
|
if sum(1 for param in [id, name, alias] if param is not None) > 1:
|
|
229
228
|
raise ValueError('Only one of "id", "name", or "alias" can be specified, not multiple.')
|
|
230
229
|
|
|
231
|
-
|
|
232
|
-
if not token:
|
|
233
|
-
raise ValueError(f'Apify storage client requires a valid token in Configuration (token={token}).')
|
|
234
|
-
|
|
235
|
-
api_url = configuration.api_base_url
|
|
236
|
-
if not api_url:
|
|
237
|
-
raise ValueError(f'Apify storage client requires a valid API URL in Configuration (api_url={api_url}).')
|
|
238
|
-
|
|
239
|
-
api_public_base_url = configuration.api_public_base_url
|
|
240
|
-
if not api_public_base_url:
|
|
241
|
-
raise ValueError(
|
|
242
|
-
'Apify storage client requires a valid API public base URL in Configuration '
|
|
243
|
-
f'(api_public_base_url={api_public_base_url}).'
|
|
244
|
-
)
|
|
245
|
-
|
|
246
|
-
# Create Apify client with the provided token and API URL.
|
|
247
|
-
apify_client_async = ApifyClientAsync(
|
|
248
|
-
token=token,
|
|
249
|
-
api_url=api_url,
|
|
250
|
-
max_retries=8,
|
|
251
|
-
min_delay_between_retries_millis=500,
|
|
252
|
-
timeout_secs=360,
|
|
253
|
-
)
|
|
230
|
+
apify_client_async = create_apify_client(configuration)
|
|
254
231
|
apify_rqs_client = apify_client_async.request_queues()
|
|
255
232
|
|
|
256
233
|
# Normalize unnamed default storage in cases where not defined in `configuration.default_request_queue_id` to
|