Skip to content

Commit 8347eb6

Browse files
committed
Merge remote-tracking branch 'origin/master' into test-new-storage-services-creation-2
2 parents f1ce0d1 + 6e4f55d commit 8347eb6

File tree

3 files changed

+65
-4
lines changed

3 files changed

+65
-4
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file.
1616
- Expose `APIFY_USER_IS_PAYING` env var to the configuration ([#507](https://github.com/apify/apify-sdk-python/pull/507)) ([0801e54](https://github.com/apify/apify-sdk-python/commit/0801e54887317c1280cc6828ecd3f2cc53287e76)) by [@stepskop](https://github.com/stepskop)
1717
- Resolve DeprecationWarning in ApifyEventManager ([#555](https://github.com/apify/apify-sdk-python/pull/555)) ([0c5111d](https://github.com/apify/apify-sdk-python/commit/0c5111dafe19796ec1fb9652a44c031bed9758df)) by [@vdusek](https://github.com/vdusek), closes [#343](https://github.com/apify/apify-sdk-python/issues/343)
1818
- Use same `client_key` for `Actor` created `request_queue` and improve its metadata estimation ([#552](https://github.com/apify/apify-sdk-python/pull/552)) ([7e4e5da](https://github.com/apify/apify-sdk-python/commit/7e4e5da81dd87e84ebeef2bd336c6c1d422cb9a7)) by [@Pijukatel](https://github.com/Pijukatel), closes [#536](https://github.com/apify/apify-sdk-python/issues/536)
19+
- Properly process pre-existing Actor input file ([#591](https://github.com/apify/apify-sdk-python/pull/591)) ([cc5075f](https://github.com/apify/apify-sdk-python/commit/cc5075fab8c72ca5711cfd97932037b34e6997cd)) by [@Pijukatel](https://github.com/Pijukatel), closes [#590](https://github.com/apify/apify-sdk-python/issues/590)
1920

2021
### Chore
2122

@@ -101,6 +102,18 @@ All notable changes to this project will be documented in this file.
101102
- Tagline overlap ([#501](https://github.com/apify/apify-sdk-python/pull/501)) ([bae8340](https://github.com/apify/apify-sdk-python/commit/bae8340c46fea756ea35ea4d591da84c09d478e2)) by [@katzino](https://github.com/katzino)
102103

103104

105+
## [2.7.0](https://github.com/apify/apify-sdk-python/releases/tag/v2.7.0) (2025-07-14)
106+
107+
### 🚀 Features
108+
109+
- **crypto:** Decrypt secret objects ([#482](https://github.com/apify/apify-sdk-python/pull/482)) ([ce9daf7](https://github.com/apify/apify-sdk-python/commit/ce9daf7381212b8dc194e8a643e5ca0dedbc0078)) by [@MFori](https://github.com/MFori)
110+
111+
### 🐛 Bug Fixes
112+
113+
- Sync `@docusaurus` theme version [internal] ([#500](https://github.com/apify/apify-sdk-python/pull/500)) ([a7485e7](https://github.com/apify/apify-sdk-python/commit/a7485e7d2276fde464ce862573d5b95e7d4d836a)) by [@katzino](https://github.com/katzino)
114+
- Tagline overlap ([#501](https://github.com/apify/apify-sdk-python/pull/501)) ([bae8340](https://github.com/apify/apify-sdk-python/commit/bae8340c46fea756ea35ea4d591da84c09d478e2)) by [@katzino](https://github.com/katzino)
115+
116+
104117

105118
## [2.7.3](https://github.com/apify/apify-sdk-python/releases/tag/v2.7.3) (2025-08-11)
106119

src/apify/storage_clients/_file_system/_key_value_store_client.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import asyncio
2+
import json
3+
from pathlib import Path
24

35
from typing_extensions import override
46

@@ -23,9 +25,15 @@ async def purge(self) -> None:
2325
the `INPUT.json` file. It also updates the metadata to reflect that the store has been purged.
2426
"""
2527
kvs_input_key = Configuration.get_global_configuration().input_key
28+
29+
# First try to find the alternative format of the input file and process it if it exists.
30+
for file_path in self.path_to_kvs.glob('*'):
31+
if file_path.name == f'{kvs_input_key}.json':
32+
await self._process_input_json(file_path)
33+
2634
async with self._lock:
2735
for file_path in self.path_to_kvs.glob('*'):
28-
if file_path.name in {METADATA_FILENAME, f'{kvs_input_key}.json'}:
36+
if file_path.name in {METADATA_FILENAME, kvs_input_key, f'{kvs_input_key}.{METADATA_FILENAME}'}:
2937
continue
3038
if file_path.is_file():
3139
await asyncio.to_thread(file_path.unlink, missing_ok=True)
@@ -34,3 +42,16 @@ async def purge(self) -> None:
3442
update_accessed_at=True,
3543
update_modified_at=True,
3644
)
45+
46+
async def _process_input_json(self, path: Path) -> None:
47+
"""Process simple input json file to format expected by the FileSystemKeyValueStoreClient.
48+
49+
For example: INPUT.json -> INPUT, INPUT.json.metadata
50+
"""
51+
try:
52+
f = await asyncio.to_thread(path.open)
53+
input_data = json.load(f)
54+
finally:
55+
f.close()
56+
await asyncio.to_thread(path.unlink, missing_ok=True)
57+
await self.set_value(key=path.stem, value=input_data)

tests/unit/storage_clients/test_file_system.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
from __future__ import annotations
22

33
import asyncio
4+
import json
5+
from typing import TYPE_CHECKING
46

7+
from crawlee import service_locator
58
from crawlee._consts import METADATA_FILENAME
69

7-
from apify import Configuration
8-
from apify.storage_clients._file_system import ApifyFileSystemKeyValueStoreClient
10+
from apify import Actor, Configuration
11+
from apify.storage_clients._file_system import ApifyFileSystemKeyValueStoreClient, ApifyFileSystemStorageClient
12+
13+
if TYPE_CHECKING:
14+
from pathlib import Path
915

1016

1117
async def test_purge_preserves_input_file_and_metadata() -> None:
@@ -23,18 +29,21 @@ async def test_purge_preserves_input_file_and_metadata() -> None:
2329
kvs_path = kvs_storage_client.path_to_kvs
2430

2531
# Create various files
26-
input_file = kvs_path / f'{configuration.input_key}.json'
32+
input_file = kvs_path / f'{configuration.input_key}'
33+
input_metadata_file = kvs_path / f'{configuration.input_key}.{METADATA_FILENAME}.json'
2734
metadata_file = kvs_path / METADATA_FILENAME
2835
regular_file1 = kvs_path / 'regular_file1.json'
2936
regular_file2 = kvs_path / 'another_file.txt'
3037

3138
# Write content to files
3239
await asyncio.to_thread(input_file.write_text, '{"test": "input"}')
40+
await asyncio.to_thread(input_metadata_file.write_text, 'some text content')
3341
await asyncio.to_thread(regular_file1.write_text, '{"test": "data1"}')
3442
await asyncio.to_thread(regular_file2.write_text, 'some text content')
3543

3644
# Verify all files exist before purge
3745
assert input_file.exists()
46+
assert input_metadata_file.exists()
3847
assert metadata_file.exists() # Should exist from client creation
3948
assert regular_file1.exists()
4049
assert regular_file2.exists()
@@ -53,3 +62,21 @@ async def test_purge_preserves_input_file_and_metadata() -> None:
5362
# Verify INPUT.json content is unchanged
5463
input_content = await asyncio.to_thread(input_file.read_text)
5564
assert input_content == '{"test": "input"}'
65+
66+
67+
async def test_pre_existing_input_used_by_actor(tmp_path: Path) -> None:
68+
pre_existing_input = {
69+
'foo': 'bar',
70+
}
71+
72+
configuration = Configuration.get_global_configuration()
73+
# Create pre-existing INPUT.json file
74+
path_to_input = tmp_path / 'key_value_stores' / 'default'
75+
path_to_input.mkdir(parents=True)
76+
(path_to_input / f'{configuration.input_key}.json').write_text(json.dumps(pre_existing_input))
77+
78+
# Remove this line after https://github.com/apify/apify-sdk-python/pull/576
79+
service_locator.set_storage_client(ApifyFileSystemStorageClient())
80+
81+
async with Actor():
82+
assert pre_existing_input == await Actor.get_input()

0 commit comments

Comments
 (0)