Skip to content

Commit 31eb278

Browse files
committed
Copy public interface
1 parent 245455c commit 31eb278

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

src/apify/_actor.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
EventSystemInfoData,
2525
)
2626

27+
from apify._charging import ChargeResult, ChargingManager
2728
from apify._configuration import Configuration
2829
from apify._consts import EVENT_LISTENERS_TIMEOUT
2930
from apify._crypto import decrypt_input_secrets, load_private_key
@@ -97,6 +98,8 @@ def __init__(
9798
)
9899
)
99100

101+
self._charging_manager = ChargingManager(self._configuration, self._apify_client)
102+
100103
self._is_initialized = False
101104

102105
@ignore_docs
@@ -221,6 +224,10 @@ async def init(self) -> None:
221224
# https://github.com/apify/apify-sdk-python/issues/146
222225

223226
await self._event_manager.__aenter__()
227+
self.log.debug('Event manager initialized')
228+
229+
await self._charging_manager.init()
230+
self.log.debug('Charging manager initialized')
224231

225232
self._is_initialized = True
226233

@@ -445,19 +452,45 @@ async def open_request_queue(
445452
storage_client=storage_client,
446453
)
447454

448-
async def push_data(self, data: dict | list[dict]) -> None:
455+
@overload
456+
async def push_data(self, data: dict | list[dict]) -> None: ...
457+
@overload
458+
async def push_data(self, data: dict | list[dict], event_name: str) -> ChargeResult: ...
459+
async def push_data(self, data: dict | list[dict], event_name: str | None = None) -> ChargeResult | None:
449460
"""Store an object or a list of objects to the default dataset of the current Actor run.
450461
451462
Args:
452463
data: The data to push to the default dataset.
464+
event_name: If provided, the method will attempt to charge for the event for each pushed item.
453465
"""
454466
self._raise_if_not_initialized()
455467

456468
if not data:
457-
return
469+
return None
470+
471+
data = data if isinstance(data, list) else [data]
472+
473+
max_charged_count = (
474+
self._charging_manager.calculate_max_event_charge_within_limit(event_name)
475+
if event_name is not None
476+
else None
477+
)
458478

459479
dataset = await self.open_dataset()
460-
await dataset.push_data(data)
480+
481+
if max_charged_count is not None and len(data) > max_charged_count:
482+
# Push as many items as we can charge for
483+
await dataset.push_data(data[:max_charged_count])
484+
else:
485+
await dataset.push_data(data)
486+
487+
if event_name:
488+
return await self._charging_manager.charge(
489+
event_name=event_name,
490+
count=min(max_charged_count, len(data)) if max_charged_count is not None else len(data),
491+
)
492+
493+
return None
461494

462495
async def get_input(self) -> Any:
463496
"""Get the Actor input value from the default key-value store associated with the current Actor run."""
@@ -506,6 +539,15 @@ async def set_value(
506539
key_value_store = await self.open_key_value_store()
507540
return await key_value_store.set_value(key, value, content_type=content_type)
508541

542+
def get_charging_manager(self) -> ChargingManager:
543+
"""Retrieve the charging manager to access granular pricing information."""
544+
self._raise_if_not_initialized()
545+
return self._charging_manager
546+
547+
async def charge(self, event_name: str, count: int = 1) -> ChargeResult:
548+
self._raise_if_not_initialized()
549+
return await self._charging_manager.charge(event_name, count)
550+
509551
@overload
510552
def on(
511553
self, event_name: Literal[Event.PERSIST_STATE], listener: EventListener[EventPersistStateData]

src/apify/_charging.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from __future__ import annotations
2+
3+
from dataclasses import dataclass
4+
from typing import TYPE_CHECKING
5+
6+
if TYPE_CHECKING:
7+
from apify_client import ApifyClientAsync
8+
9+
from apify._configuration import Configuration
10+
11+
12+
class ChargingManager:
13+
def __init__(self, configuration: Configuration, client: ApifyClientAsync) -> None:
14+
pass
15+
16+
async def init(self) -> None:
17+
pass
18+
19+
async def charge(self, event_name: str, count: int = 1) -> ChargeResult:
20+
pass
21+
22+
def calculate_max_event_charge_within_limit(self, event_name: str) -> int:
23+
pass
24+
25+
26+
@dataclass(frozen=True)
27+
class ChargeResult:
28+
event_charge_limit_reached: bool
29+
charged_count: int
30+
chargeable_within_limit: int

0 commit comments

Comments
 (0)