apify-client 3.2.1b4__tar.gz → 3.2.2b1__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.
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/CHANGELOG.md +9 -2
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/PKG-INFO +2 -2
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/README.md +1 -1
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/pyproject.toml +2 -1
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/pyproject.toml.orig +5 -1
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_consts.py +9 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/actor.py +24 -6
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/key_value_store.py +18 -8
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/run.py +8 -2
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_utils/encoding.py +28 -31
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_clients/__init__.py +2 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_clients/_base.py +119 -32
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_clients/_httpx2.py +3 -2
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_clients/_impit.py +3 -2
- apify_client-3.2.2b1/src/apify_client/http_clients/_streamed_body.py +355 -0
- apify_client-3.2.2b1/src/apify_client/types.py +98 -0
- apify_client-3.2.1b4/src/apify_client/types.py +0 -53
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/CONTRIBUTING.md +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/LICENSE +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/__init__.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_apify_client.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_client_registry.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_docs.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_literals.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_logging.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_models.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_pagination.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/__init__.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/_resource_client.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/actor_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/actor_env_var.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/actor_env_var_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/actor_version.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/actor_version_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/build.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/build_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/dataset.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/dataset_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/key_value_store_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/log.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/request_queue.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/request_queue_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/run_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/schedule.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/schedule_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/store_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/task.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/task_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/user.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/webhook.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/webhook_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/webhook_dispatch.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/webhook_dispatch_collection.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_statistics.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_status_message_watcher.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_streamed_log.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_typeddicts.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_utils/__init__.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_utils/crypto.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_utils/errors.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_utils/http.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_utils/time.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_utils/try_import.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/errors.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_compressors/__init__.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_compressors/_base.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_compressors/_brotli.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_compressors/_gzip.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/http_compressors/_resolve.py +0 -0
- {apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/py.typed +0 -0
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
5
|
<!-- git-cliff-unreleased-start -->
|
|
6
|
-
## 3.2.
|
|
6
|
+
## 3.2.2 - **not yet released**
|
|
7
|
+
|
|
8
|
+
### 🚀 Features
|
|
9
|
+
|
|
10
|
+
- Stream request bodies from files, iterables, and responses ([#1060](https://github.com/apify/apify-client-python/pull/1060)) ([9be215b](https://github.com/apify/apify-client-python/commit/9be215b23a13de0abc4a255a18450cc764e7a6c7)) by [@vdusek](https://github.com/vdusek), closes [#972](https://github.com/apify/apify-client-python/issues/972)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<!-- git-cliff-unreleased-end -->
|
|
14
|
+
## [3.2.1](https://github.com/apify/apify-client-python/releases/tag/v3.2.1) (2026-09-25)
|
|
7
15
|
|
|
8
16
|
### 🐛 Bug Fixes
|
|
9
17
|
|
|
@@ -12,7 +20,6 @@ All notable changes to this project will be documented in this file.
|
|
|
12
20
|
- Make `JsonSerializable` type alias read-only ([#1072](https://github.com/apify/apify-client-python/pull/1072)) ([bd82a26](https://github.com/apify/apify-client-python/commit/bd82a2645d3c64f0e4a30de3a016c16d92d48340)) by [@Pijukatel](https://github.com/Pijukatel)
|
|
13
21
|
|
|
14
22
|
|
|
15
|
-
<!-- git-cliff-unreleased-end -->
|
|
16
23
|
## [3.2.0](https://github.com/apify/apify-client-python/releases/tag/v3.2.0) (2026-09-03)
|
|
17
24
|
|
|
18
25
|
### 🚀 Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apify_client
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.2b1
|
|
4
4
|
Summary: Apify API client for Python
|
|
5
5
|
Keywords: apify,api,client,automation,crawling,scraping
|
|
6
6
|
Author: Apify Technologies s.r.o.
|
|
@@ -170,7 +170,7 @@ For a guided walkthrough — authenticating, running an Actor, and reading its r
|
|
|
170
170
|
- **Fully typed responses** — every method returns a [Pydantic](https://docs.pydantic.dev/) model generated from the Apify OpenAPI spec, with IDE autocomplete and runtime validation ([Typed models](https://docs.apify.com/api/client/python/docs/concepts/typed-models)).
|
|
171
171
|
- **Automatic retries** — exponential backoff for network errors, HTTP 429, and 5xx responses, configurable per client ([Retries](https://docs.apify.com/api/client/python/docs/concepts/retries)).
|
|
172
172
|
- **Tiered timeouts** — short / medium / long tiers picked per endpoint, overridable per call ([Timeouts](https://docs.apify.com/api/client/python/docs/concepts/timeouts)).
|
|
173
|
-
- **Pagination and streaming** — iterate datasets, key-value store keys, or live logs without manual paging or buffering ([Pagination](https://docs.apify.com/api/client/python/docs/concepts/pagination), [Streaming](https://docs.apify.com/api/client/python/docs/concepts/streaming-resources)).
|
|
173
|
+
- **Pagination and streaming** — iterate datasets, key-value store keys, or live logs without manual paging or buffering, and upload large records straight from a file or another stream ([Pagination](https://docs.apify.com/api/client/python/docs/concepts/pagination), [Streaming](https://docs.apify.com/api/client/python/docs/concepts/streaming-resources)).
|
|
174
174
|
- **Convenience methods** — `call()`, `wait_for_finish()`, nested resource access, and other shortcuts that hide platform quirks ([Convenience methods](https://docs.apify.com/api/client/python/docs/concepts/convenience-methods)).
|
|
175
175
|
- **Pluggable HTTP layer** — use the default [Impit](https://github.com/apify/impit)-based client, opt in to the built-in [HTTPX2](https://github.com/pydantic/httpx2) client, or plug in any custom implementation ([HTTP clients](https://docs.apify.com/api/client/python/docs/concepts/custom-http-clients)).
|
|
176
176
|
- **Structured errors** — every API error surfaces as an [`ApifyApiError`](https://docs.apify.com/api/client/python/reference/class/ApifyApiError) with HTTP-specific subclasses for precise handling ([Error handling](https://docs.apify.com/api/client/python/docs/concepts/error-handling)).
|
|
@@ -133,7 +133,7 @@ For a guided walkthrough — authenticating, running an Actor, and reading its r
|
|
|
133
133
|
- **Fully typed responses** — every method returns a [Pydantic](https://docs.pydantic.dev/) model generated from the Apify OpenAPI spec, with IDE autocomplete and runtime validation ([Typed models](https://docs.apify.com/api/client/python/docs/concepts/typed-models)).
|
|
134
134
|
- **Automatic retries** — exponential backoff for network errors, HTTP 429, and 5xx responses, configurable per client ([Retries](https://docs.apify.com/api/client/python/docs/concepts/retries)).
|
|
135
135
|
- **Tiered timeouts** — short / medium / long tiers picked per endpoint, overridable per call ([Timeouts](https://docs.apify.com/api/client/python/docs/concepts/timeouts)).
|
|
136
|
-
- **Pagination and streaming** — iterate datasets, key-value store keys, or live logs without manual paging or buffering ([Pagination](https://docs.apify.com/api/client/python/docs/concepts/pagination), [Streaming](https://docs.apify.com/api/client/python/docs/concepts/streaming-resources)).
|
|
136
|
+
- **Pagination and streaming** — iterate datasets, key-value store keys, or live logs without manual paging or buffering, and upload large records straight from a file or another stream ([Pagination](https://docs.apify.com/api/client/python/docs/concepts/pagination), [Streaming](https://docs.apify.com/api/client/python/docs/concepts/streaming-resources)).
|
|
137
137
|
- **Convenience methods** — `call()`, `wait_for_finish()`, nested resource access, and other shortcuts that hide platform quirks ([Convenience methods](https://docs.apify.com/api/client/python/docs/concepts/convenience-methods)).
|
|
138
138
|
- **Pluggable HTTP layer** — use the default [Impit](https://github.com/apify/impit)-based client, opt in to the built-in [HTTPX2](https://github.com/pydantic/httpx2) client, or plug in any custom implementation ([HTTP clients](https://docs.apify.com/api/client/python/docs/concepts/custom-http-clients)).
|
|
139
139
|
- **Structured errors** — every API error surfaces as an [`ApifyApiError`](https://docs.apify.com/api/client/python/reference/class/ApifyApiError) with HTTP-specific subclasses for precise handling ([Error handling](https://docs.apify.com/api/client/python/docs/concepts/error-handling)).
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "apify_client"
|
|
7
|
-
version = "3.2.
|
|
7
|
+
version = "3.2.2b1"
|
|
8
8
|
description = "Apify API client for Python"
|
|
9
9
|
license = "Apache-2.0"
|
|
10
10
|
license-files = ["LICENSE"]
|
|
@@ -178,6 +178,7 @@ indent-style = "space"
|
|
|
178
178
|
addopts = "-r a --verbose --dist worksteal"
|
|
179
179
|
asyncio_default_fixture_loop_scope = "function"
|
|
180
180
|
asyncio_mode = "auto"
|
|
181
|
+
filterwarnings = ["ignore:Streaming a request body is experimental:UserWarning"]
|
|
181
182
|
pythonpath = ["."]
|
|
182
183
|
timeout = 1800
|
|
183
184
|
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "apify_client"
|
|
7
|
-
version = "3.2.
|
|
7
|
+
version = "3.2.2b1"
|
|
8
8
|
description = "Apify API client for Python"
|
|
9
9
|
authors = [{ name = "Apify Technologies s.r.o.", email = "support@apify.com" }]
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -187,6 +187,10 @@ max-branches = 18
|
|
|
187
187
|
addopts = "-r a --verbose --dist worksteal"
|
|
188
188
|
asyncio_default_fixture_loop_scope = "function"
|
|
189
189
|
asyncio_mode = "auto"
|
|
190
|
+
filterwarnings = [
|
|
191
|
+
# The tests stream request bodies throughout, and the warning has a unit test of its own.
|
|
192
|
+
"ignore:Streaming a request body is experimental:UserWarning",
|
|
193
|
+
]
|
|
190
194
|
pythonpath = ["."]
|
|
191
195
|
timeout = 1800
|
|
192
196
|
|
|
@@ -42,6 +42,15 @@ A smaller body already fits in a single network packet, so compressing it costs
|
|
|
42
42
|
saving a round trip.
|
|
43
43
|
"""
|
|
44
44
|
|
|
45
|
+
STREAMED_BODY_CHUNK_SIZE = 64 * 1024
|
|
46
|
+
"""Size of the chunks a streamed request body reads from an `io.IOBase` source, in bytes from a binary stream and in
|
|
47
|
+
characters from a text-mode one.
|
|
48
|
+
|
|
49
|
+
A chunk is the most of a streamed body that is in memory at once, and in the asynchronous client every chunk costs
|
|
50
|
+
one worker-thread hop, so the size balances memory against per-chunk overhead. It matches the buffer size the
|
|
51
|
+
standard library and common HTTP libraries use to copy files.
|
|
52
|
+
"""
|
|
53
|
+
|
|
45
54
|
ALREADY_COMPRESSED_MEDIA_TYPE_PREFIXES = ('audio/', 'image/', 'video/')
|
|
46
55
|
"""Media type prefixes whose payloads carry their own compression, so compressing the request body is wasted work."""
|
|
47
56
|
|
|
@@ -236,7 +236,10 @@ class ActorClient(ResourceClient):
|
|
|
236
236
|
https://docs.apify.com/api/v2#/reference/actors/run-collection/run-actor
|
|
237
237
|
|
|
238
238
|
Args:
|
|
239
|
-
run_input: The input to pass to the Actor run.
|
|
239
|
+
run_input: The input to pass to the Actor run. Accepts the same values as
|
|
240
|
+
`KeyValueStoreClient.set_record`, including an `io.IOBase` stream such as an open file, an iterable
|
|
241
|
+
of byte chunks, or a streamed `HttpResponse`, which are uploaded in chunks without being held in
|
|
242
|
+
memory. Streaming is experimental, and its behavior may change in future versions.
|
|
240
243
|
content_type: The content type of the input.
|
|
241
244
|
build: Specifies the Actor build to run. It can be either a build tag or build number. By default,
|
|
242
245
|
the run uses the build specified in the default run configuration for the Actor (typically latest).
|
|
@@ -315,7 +318,10 @@ class ActorClient(ResourceClient):
|
|
|
315
318
|
https://docs.apify.com/api/v2#/reference/actors/run-collection/run-actor
|
|
316
319
|
|
|
317
320
|
Args:
|
|
318
|
-
run_input: The input to pass to the Actor run.
|
|
321
|
+
run_input: The input to pass to the Actor run. Accepts the same values as
|
|
322
|
+
`KeyValueStoreClient.set_record`, including an `io.IOBase` stream such as an open file, an iterable
|
|
323
|
+
of byte chunks, or a streamed `HttpResponse`, which are uploaded in chunks without being held in
|
|
324
|
+
memory. Streaming is experimental, and its behavior may change in future versions.
|
|
319
325
|
content_type: The content type of the input.
|
|
320
326
|
build: Specifies the Actor build to run. It can be either a build tag or build number. By default,
|
|
321
327
|
the run uses the build specified in the default run configuration for the Actor (typically latest).
|
|
@@ -540,7 +546,10 @@ class ActorClient(ResourceClient):
|
|
|
540
546
|
"""Validate an input for the Actor that defines an input schema.
|
|
541
547
|
|
|
542
548
|
Args:
|
|
543
|
-
run_input: The input to validate.
|
|
549
|
+
run_input: The input to validate. Accepts the same values as `KeyValueStoreClient.set_record`,
|
|
550
|
+
including an `io.IOBase` stream such as an open file, an iterable of byte chunks, or a streamed
|
|
551
|
+
`HttpResponse`, which are uploaded in chunks without being held in memory. Streaming is experimental,
|
|
552
|
+
and its behavior may change in future versions.
|
|
544
553
|
build_tag: The Actor's build tag.
|
|
545
554
|
content_type: The content type of the input.
|
|
546
555
|
timeout: Timeout for the API HTTP request.
|
|
@@ -738,7 +747,10 @@ class ActorClientAsync(ResourceClientAsync):
|
|
|
738
747
|
https://docs.apify.com/api/v2#/reference/actors/run-collection/run-actor
|
|
739
748
|
|
|
740
749
|
Args:
|
|
741
|
-
run_input: The input to pass to the Actor run.
|
|
750
|
+
run_input: The input to pass to the Actor run. Accepts the same values as
|
|
751
|
+
`KeyValueStoreClientAsync.set_record`, including an `io.IOBase` stream such as an open file, an iterable
|
|
752
|
+
of byte chunks, or a streamed `HttpResponse`, which are uploaded in chunks without being held in
|
|
753
|
+
memory. Streaming is experimental, and its behavior may change in future versions.
|
|
742
754
|
content_type: The content type of the input.
|
|
743
755
|
build: Specifies the Actor build to run. It can be either a build tag or build number. By default,
|
|
744
756
|
the run uses the build specified in the default run configuration for the Actor (typically latest).
|
|
@@ -817,7 +829,10 @@ class ActorClientAsync(ResourceClientAsync):
|
|
|
817
829
|
https://docs.apify.com/api/v2#/reference/actors/run-collection/run-actor
|
|
818
830
|
|
|
819
831
|
Args:
|
|
820
|
-
run_input: The input to pass to the Actor run.
|
|
832
|
+
run_input: The input to pass to the Actor run. Accepts the same values as
|
|
833
|
+
`KeyValueStoreClientAsync.set_record`, including an `io.IOBase` stream such as an open file, an iterable
|
|
834
|
+
of byte chunks, or a streamed `HttpResponse`, which are uploaded in chunks without being held in
|
|
835
|
+
memory. Streaming is experimental, and its behavior may change in future versions.
|
|
821
836
|
content_type: The content type of the input.
|
|
822
837
|
build: Specifies the Actor build to run. It can be either a build tag or build number. By default,
|
|
823
838
|
the run uses the build specified in the default run configuration for the Actor (typically latest).
|
|
@@ -1043,7 +1058,10 @@ class ActorClientAsync(ResourceClientAsync):
|
|
|
1043
1058
|
"""Validate an input for the Actor that defines an input schema.
|
|
1044
1059
|
|
|
1045
1060
|
Args:
|
|
1046
|
-
run_input: The input to validate.
|
|
1061
|
+
run_input: The input to validate. Accepts the same values as `KeyValueStoreClientAsync.set_record`,
|
|
1062
|
+
including an `io.IOBase` stream such as an open file, an iterable of byte chunks, or a streamed
|
|
1063
|
+
`HttpResponse`, which are uploaded in chunks without being held in memory. Streaming is experimental,
|
|
1064
|
+
and its behavior may change in future versions.
|
|
1047
1065
|
build_tag: The Actor's build tag.
|
|
1048
1066
|
content_type: The content type of the input.
|
|
1049
1067
|
timeout: Timeout for the API HTTP request.
|
{apify_client-3.2.1b4 → apify_client-3.2.2b1}/src/apify_client/_resource_clients/key_value_store.py
RENAMED
|
@@ -369,14 +369,19 @@ class KeyValueStoreClient(ResourceClient):
|
|
|
369
369
|
|
|
370
370
|
Args:
|
|
371
371
|
key: The key of the record to save the value to.
|
|
372
|
-
value: The value to save into the record.
|
|
372
|
+
value: The value to save into the record. An `io.IOBase` stream such as an open file, an iterable of byte
|
|
373
|
+
chunks, or a streamed `HttpResponse` is uploaded in chunks as it is read, without being held in memory
|
|
374
|
+
whole or compressed. Any other object with a callable `read` is read whole and sent uncompressed. Only
|
|
375
|
+
a seekable `io.IOBase` value can be retried; any other streamed value gets a single attempt. See
|
|
376
|
+
`StreamedRequestBody` for details. Streaming is experimental, and its behavior may change in future
|
|
377
|
+
versions.
|
|
373
378
|
content_type: The content type of the saved value.
|
|
374
379
|
content_encoding: The encoding already applied to `value`, sent as the `Content-Encoding` header. Pass it
|
|
375
380
|
to upload a pre-compressed value - the client then forwards the bytes as they are instead of
|
|
376
381
|
compressing them itself. The API accepts `gzip`, `br`, `deflate`, and `identity`, and stores the
|
|
377
|
-
record exactly as uploaded, so this also becomes the encoding the record is served with.
|
|
378
|
-
|
|
379
|
-
|
|
382
|
+
record exactly as uploaded, so this also becomes the encoding the record is served with. A `str`, a
|
|
383
|
+
JSON-serializable object, or a text-mode file cannot be carrying a compression and raises
|
|
384
|
+
`TypeError`; a streamed value is taken at its word, since its bytes are only seen as they are sent.
|
|
380
385
|
timeout: Timeout for the API HTTP request.
|
|
381
386
|
"""
|
|
382
387
|
value, content_type = encode_key_value_store_record_value(
|
|
@@ -802,14 +807,19 @@ class KeyValueStoreClientAsync(ResourceClientAsync):
|
|
|
802
807
|
|
|
803
808
|
Args:
|
|
804
809
|
key: The key of the record to save the value to.
|
|
805
|
-
value: The value to save into the record.
|
|
810
|
+
value: The value to save into the record. An `io.IOBase` stream such as an open file, an iterable of byte
|
|
811
|
+
chunks, or a streamed `HttpResponse` is uploaded in chunks as it is read, without being held in memory
|
|
812
|
+
whole or compressed. Any other object with a callable `read` is read whole and sent uncompressed. Only
|
|
813
|
+
a seekable `io.IOBase` value can be retried; any other streamed value gets a single attempt. See
|
|
814
|
+
`StreamedRequestBody` for details. Streaming is experimental, and its behavior may change in future
|
|
815
|
+
versions.
|
|
806
816
|
content_type: The content type of the saved value.
|
|
807
817
|
content_encoding: The encoding already applied to `value`, sent as the `Content-Encoding` header. Pass it
|
|
808
818
|
to upload a pre-compressed value - the client then forwards the bytes as they are instead of
|
|
809
819
|
compressing them itself. The API accepts `gzip`, `br`, `deflate`, and `identity`, and stores the
|
|
810
|
-
record exactly as uploaded, so this also becomes the encoding the record is served with.
|
|
811
|
-
|
|
812
|
-
|
|
820
|
+
record exactly as uploaded, so this also becomes the encoding the record is served with. A `str`, a
|
|
821
|
+
JSON-serializable object, or a text-mode file cannot be carrying a compression and raises
|
|
822
|
+
`TypeError`; a streamed value is taken at its word, since its bytes are only seen as they are sent.
|
|
813
823
|
timeout: Timeout for the API HTTP request.
|
|
814
824
|
"""
|
|
815
825
|
value, content_type = encode_key_value_store_record_value(
|
|
@@ -180,7 +180,10 @@ class RunClient(ResourceClient):
|
|
|
180
180
|
target_actor_build: The build of the target Actor. It can be either a build tag or build number.
|
|
181
181
|
By default, the run uses the build specified in the default run configuration for the target Actor
|
|
182
182
|
(typically the latest build).
|
|
183
|
-
run_input: The input to pass to the new run.
|
|
183
|
+
run_input: The input to pass to the new run. Accepts the same values as
|
|
184
|
+
`KeyValueStoreClient.set_record`, including an `io.IOBase` stream such as an open file, an iterable
|
|
185
|
+
of byte chunks, or a streamed `HttpResponse`, which are uploaded in chunks without being held in
|
|
186
|
+
memory. Streaming is experimental, and its behavior may change in future versions.
|
|
184
187
|
content_type: The content type of the input.
|
|
185
188
|
timeout: Timeout for the API HTTP request.
|
|
186
189
|
|
|
@@ -608,7 +611,10 @@ class RunClientAsync(ResourceClientAsync):
|
|
|
608
611
|
target_actor_build: The build of the target Actor. It can be either a build tag or build number.
|
|
609
612
|
By default, the run uses the build specified in the default run configuration for the target Actor
|
|
610
613
|
(typically the latest build).
|
|
611
|
-
run_input: The input to pass to the new run.
|
|
614
|
+
run_input: The input to pass to the new run. Accepts the same values as
|
|
615
|
+
`KeyValueStoreClientAsync.set_record`, including an `io.IOBase` stream such as an open file, an iterable
|
|
616
|
+
of byte chunks, or a streamed `HttpResponse`, which are uploaded in chunks without being held in
|
|
617
|
+
memory. Streaming is experimental, and its behavior may change in future versions.
|
|
612
618
|
content_type: The content type of the input.
|
|
613
619
|
timeout: Timeout for the API HTTP request.
|
|
614
620
|
|
|
@@ -1,32 +1,35 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import io
|
|
3
4
|
import json
|
|
4
5
|
from base64 import b64encode
|
|
5
6
|
from functools import cache
|
|
6
|
-
from inspect import isawaitable, iscoroutine
|
|
7
7
|
from typing import TYPE_CHECKING, Any
|
|
8
8
|
|
|
9
9
|
from apify_client._models import WebhookCreate, WebhookRepresentation
|
|
10
|
+
from apify_client.http_clients._streamed_body import StreamedRequestBody
|
|
10
11
|
|
|
11
12
|
if TYPE_CHECKING:
|
|
12
|
-
from apify_client.types import WebhooksList
|
|
13
|
+
from apify_client.types import StreamedBodySource, WebhooksList
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def encode_key_value_store_record_value(
|
|
16
17
|
value: Any, *, content_type: str | None = None, content_encoding: str | None = None
|
|
17
|
-
) -> tuple[bytes | bytearray | str, str]:
|
|
18
|
+
) -> tuple[bytes | bytearray | str | StreamedBodySource, str]:
|
|
18
19
|
"""Encode a value for storage in a key-value store record.
|
|
19
20
|
|
|
20
21
|
Args:
|
|
21
|
-
value: The value to encode.
|
|
22
|
-
is
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
content_type: The content type; if None, it's inferred from the value type.
|
|
22
|
+
value: The value to encode. A file-like object (anything with a callable `read`), an iterable of byte chunks,
|
|
23
|
+
or a streamed `HttpResponse` is returned as it is, to be streamed to the API from its current position -
|
|
24
|
+
the object is neither rewound nor closed. See `StreamedRequestBody.is_streamable` for the exact rules. Any
|
|
25
|
+
other value is JSON-serialized unless it is already bytes or a string.
|
|
26
|
+
content_type: The content type; if None, it's inferred from the value type. An `io.TextIOBase`, which is what
|
|
27
|
+
the standard library returns for a file opened in text mode, is `text/plain; charset=utf-8`; any other
|
|
28
|
+
streamed value is `application/octet-stream`.
|
|
26
29
|
content_encoding: The encoding the caller declares the value already carries, if any. Anything other than
|
|
27
|
-
`identity` means the value is compressed, which only a bytes-like payload can be, so
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
`identity` means the value is compressed, which only a bytes-like payload can be, so a string, a
|
|
31
|
+
JSON-serialized object, or a text-mode file is rejected. Any other streamed value is taken at its word,
|
|
32
|
+
since its bytes are only seen as they are sent.
|
|
30
33
|
|
|
31
34
|
Returns:
|
|
32
35
|
A tuple of (encoded_value, content_type).
|
|
@@ -35,29 +38,23 @@ def encode_key_value_store_record_value(
|
|
|
35
38
|
TypeError: If the value cannot be encoded into a body the transport accepts, or if it cannot be carrying
|
|
36
39
|
the declared `content_encoding`.
|
|
37
40
|
"""
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if isawaitable(value):
|
|
46
|
-
if iscoroutine(value):
|
|
47
|
-
value.close() # Prevent a "coroutine was never awaited" warning.
|
|
41
|
+
declared_encoding = (content_encoding or '').strip().lower()
|
|
42
|
+
declares_compression = declared_encoding not in ('', 'identity')
|
|
43
|
+
|
|
44
|
+
if StreamedRequestBody.is_streamable(value):
|
|
45
|
+
is_text = isinstance(value, io.TextIOBase)
|
|
46
|
+
if declares_compression and is_text:
|
|
48
47
|
raise TypeError(
|
|
49
|
-
'
|
|
50
|
-
'
|
|
48
|
+
f'Cannot upload a file-like value opened in text mode with `Content-Encoding: {content_encoding}`. '
|
|
49
|
+
'An encoding other than `identity` declares the value is already compressed, so pass the compressed '
|
|
50
|
+
'bytes, or a binary file-like object that reads them.'
|
|
51
51
|
)
|
|
52
|
+
return (value, content_type or ('text/plain; charset=utf-8' if is_text else 'application/octet-stream'))
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
# text-mode file cannot be carrying one, and would otherwise be stored under a header that misdescribes it -
|
|
58
|
-
# the client forwards the header untouched and never inspects the body.
|
|
59
|
-
declared_encoding = (content_encoding or '').strip().lower()
|
|
60
|
-
if declared_encoding not in ('', 'identity') and not isinstance(value, (bytes, bytearray)):
|
|
54
|
+
# A declared compression describes bytes the caller compressed. A string or a JSON-serializable object cannot
|
|
55
|
+
# be carrying one, and would otherwise be stored under a header that misdescribes it - the client forwards the
|
|
56
|
+
# header untouched and never inspects the body.
|
|
57
|
+
if declares_compression and not isinstance(value, (bytes, bytearray)):
|
|
61
58
|
raise TypeError(
|
|
62
59
|
f'Cannot upload a {type(value).__name__} value with `Content-Encoding: {content_encoding}`. An encoding '
|
|
63
60
|
'other than `identity` declares the value is already compressed, so pass the compressed bytes, or a '
|
|
@@ -2,6 +2,7 @@ from apify_client._utils.try_import import install_import_hook as _install_impor
|
|
|
2
2
|
from apify_client._utils.try_import import try_import as _try_import
|
|
3
3
|
from apify_client.http_clients._base import HttpClient, HttpClientAsync, HttpResponse
|
|
4
4
|
from apify_client.http_clients._impit import ImpitHttpClient, ImpitHttpClientAsync
|
|
5
|
+
from apify_client.http_clients._streamed_body import StreamedRequestBody
|
|
5
6
|
|
|
6
7
|
_install_import_hook(__name__)
|
|
7
8
|
|
|
@@ -22,6 +23,7 @@ __all__ = [
|
|
|
22
23
|
'HttpResponse',
|
|
23
24
|
'ImpitHttpClient',
|
|
24
25
|
'ImpitHttpClientAsync',
|
|
26
|
+
'StreamedRequestBody',
|
|
25
27
|
]
|
|
26
28
|
|
|
27
29
|
if _httpx2_import.available:
|