apify 3.4.2b29__tar.gz → 3.4.2b30__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. {apify-3.4.2b29 → apify-3.4.2b30}/CHANGELOG.md +1 -0
  2. {apify-3.4.2b29 → apify-3.4.2b30}/PKG-INFO +2 -2
  3. {apify-3.4.2b29 → apify-3.4.2b30}/pyproject.toml +2 -2
  4. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_request_queue_client.py +4 -0
  5. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_request_queue_shared_client.py +12 -2
  6. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_request_queue_single_client.py +5 -2
  7. {apify-3.4.2b29 → apify-3.4.2b30}/.gitignore +0 -0
  8. {apify-3.4.2b29 → apify-3.4.2b30}/CONTRIBUTING.md +0 -0
  9. {apify-3.4.2b29 → apify-3.4.2b30}/LICENSE +0 -0
  10. {apify-3.4.2b29 → apify-3.4.2b30}/README.md +0 -0
  11. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/__init__.py +0 -0
  12. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/_actor.py +0 -0
  13. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/_charging.py +0 -0
  14. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/_configuration.py +0 -0
  15. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/_consts.py +0 -0
  16. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/_crypto.py +0 -0
  17. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/_proxy_configuration.py +0 -0
  18. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/_utils.py +0 -0
  19. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/_webhook.py +0 -0
  20. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/errors.py +0 -0
  21. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/events/__init__.py +0 -0
  22. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/events/_apify_event_manager.py +0 -0
  23. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/events/_types.py +0 -0
  24. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/events/py.typed +0 -0
  25. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/log.py +0 -0
  26. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/py.typed +0 -0
  27. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/request_loaders/__init__.py +0 -0
  28. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/request_loaders/_apify_request_list.py +0 -0
  29. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/request_loaders/py.typed +0 -0
  30. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/__init__.py +0 -0
  31. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/_actor_runner.py +0 -0
  32. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/_async_thread.py +0 -0
  33. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/_logging_config.py +0 -0
  34. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/_serialization.py +0 -0
  35. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/extensions/__init__.py +0 -0
  36. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/extensions/_httpcache.py +0 -0
  37. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/middlewares/__init__.py +0 -0
  38. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/middlewares/apify_proxy.py +0 -0
  39. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/middlewares/py.typed +0 -0
  40. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/pipelines/__init__.py +0 -0
  41. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/pipelines/actor_dataset_push.py +0 -0
  42. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/pipelines/py.typed +0 -0
  43. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/py.typed +0 -0
  44. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/requests.py +0 -0
  45. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/scheduler.py +0 -0
  46. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/scrapy/utils.py +0 -0
  47. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/__init__.py +0 -0
  48. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/__init__.py +0 -0
  49. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_alias_resolving.py +0 -0
  50. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_api_client_creation.py +0 -0
  51. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_dataset_client.py +0 -0
  52. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_key_value_store_client.py +0 -0
  53. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_models.py +0 -0
  54. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_storage_client.py +0 -0
  55. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/_utils.py +0 -0
  56. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_apify/py.typed +0 -0
  57. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_file_system/__init__.py +0 -0
  58. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_file_system/_dataset_client.py +0 -0
  59. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_file_system/_key_value_store_client.py +0 -0
  60. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_file_system/_storage_client.py +0 -0
  61. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_ppe_dataset_mixin.py +0 -0
  62. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_smart_apify/__init__.py +0 -0
  63. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/_smart_apify/_storage_client.py +0 -0
  64. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storage_clients/py.typed +0 -0
  65. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storages/__init__.py +0 -0
  66. {apify-3.4.2b29 → apify-3.4.2b30}/src/apify/storages/py.typed +0 -0
@@ -32,6 +32,7 @@ All notable changes to this project will be documented in this file.
32
32
  - **scrapy:** Avoid mutating request userData during Scrapy-Apify conversion ([#978](https://github.com/apify/apify-sdk-python/pull/978)) ([b0b7df7](https://github.com/apify/apify-sdk-python/commit/b0b7df72eb169778ab88be04d8b30bb0bdc307d3)) by [@vdusek](https://github.com/vdusek)
33
33
  - **scrapy:** Async-thread startup race, shutdown lifecycle, and timeout setting ([#979](https://github.com/apify/apify-sdk-python/pull/979)) ([ae12935](https://github.com/apify/apify-sdk-python/commit/ae1293512f5ee781533dab5b1dd1f0af0fcc2497)) by [@vdusek](https://github.com/vdusek)
34
34
  - Commit request queue dedup cache only after batch_add_requests succeeds ([#975](https://github.com/apify/apify-sdk-python/pull/975)) ([078ab87](https://github.com/apify/apify-sdk-python/commit/078ab8744c96e61a5226a9d19869b5e0df71ab23)) by [@vdusek](https://github.com/vdusek)
35
+ - Prevent request queue softlock by adding `is_finished` and correcting `is_empty` ([#1008](https://github.com/apify/apify-sdk-python/pull/1008)) ([4ead0c6](https://github.com/apify/apify-sdk-python/commit/4ead0c64d2a95263b2fa970f5a8fff9141db62b2)) by [@Mantisus](https://github.com/Mantisus), closes [#987](https://github.com/apify/apify-sdk-python/issues/987)
35
36
 
36
37
  ### 🚜 Refactor
37
38
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: apify
3
- Version: 3.4.2b29
3
+ Version: 3.4.2b30
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
@@ -228,7 +228,7 @@ Classifier: Typing :: Typed
228
228
  Requires-Python: >=3.11
229
229
  Requires-Dist: apify-client<4.0.0,>=3.0.0
230
230
  Requires-Dist: cachetools>=5.5.0
231
- Requires-Dist: crawlee<2.0.0,>=1.0.4
231
+ Requires-Dist: crawlee<2.0.0,>=1.8.0
232
232
  Requires-Dist: cryptography>=42.0.0
233
233
  Requires-Dist: impit>=0.8.0
234
234
  Requires-Dist: lazy-object-proxy>=1.11.0
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "apify"
7
- version = "3.4.2b29"
7
+ version = "3.4.2b30"
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" }
@@ -36,7 +36,7 @@ keywords = [
36
36
  ]
37
37
  dependencies = [
38
38
  "apify-client>=3.0.0,<4.0.0",
39
- "crawlee>=1.0.4,<2.0.0",
39
+ "crawlee>=1.8.0,<2.0.0",
40
40
  "cachetools>=5.5.0",
41
41
  "cryptography>=42.0.0",
42
42
  "impit>=0.8.0",
@@ -198,3 +198,7 @@ class ApifyRequestQueueClient(RequestQueueClient):
198
198
  @override
199
199
  async def is_empty(self) -> bool:
200
200
  return await self._implementation.is_empty()
201
+
202
+ @override
203
+ async def is_finished(self) -> bool:
204
+ return await self._implementation.is_finished()
@@ -338,8 +338,18 @@ class ApifyRequestQueueSharedClient:
338
338
  # Check _list_head.
339
339
  # Without the lock the `is_empty` is prone to falsely report True with some low probability race condition.
340
340
  async with self._fetch_lock:
341
- head = await self._list_head(limit=1)
342
- return len(head.items) == 0 and not self._queue_has_locked_requests
341
+ return await self._is_empty()
342
+
343
+ async def is_finished(self) -> bool:
344
+ """Specific implementation of this method for the RQ shared access mode."""
345
+ async with self._fetch_lock:
346
+ # Order of operations is important here, because affects on `_queue_has_locked_requests`.
347
+ return await self._is_empty() and not self._queue_has_locked_requests
348
+
349
+ async def _is_empty(self) -> bool:
350
+ """Check whether anything is available to fetch. Lock-free core of `is_empty`, caller must hold the lock."""
351
+ head = await self._list_head(limit=1)
352
+ return len(head.items) == 0
343
353
 
344
354
  async def _get_metadata_estimate(self) -> RequestQueueMetadata:
345
355
  """Try to get cached metadata first. If multiple clients, fuse with global metadata.
@@ -324,9 +324,12 @@ class ApifyRequestQueueSingleClient:
324
324
 
325
325
  async def is_empty(self) -> bool:
326
326
  """Specific implementation of this method for the RQ single access mode."""
327
- # Without the lock the `is_empty` is prone to falsely report True with some low probability race condition.
328
327
  await self._ensure_head_is_non_empty()
329
- return not self._head_requests and not self._requests_in_progress
328
+ return not self._head_requests
329
+
330
+ async def is_finished(self) -> bool:
331
+ """Specific implementation of this method for the RQ single access mode."""
332
+ return await self.is_empty() and not self._requests_in_progress
330
333
 
331
334
  async def _ensure_head_is_non_empty(self) -> None:
332
335
  """Ensure that the queue head has requests if they are available in the queue."""
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes