Skip to content
Merged
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 29 additions & 10 deletions src/apify/_charging.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from pydantic import TypeAdapter

from apify._models import ActorRun, PricingModel
from apify._utils import docs_group
from apify.log import logger
from apify.storages import Dataset

Expand All @@ -21,6 +22,7 @@
run_validator: TypeAdapter[ActorRun | None] = TypeAdapter(Union[ActorRun, None])


@docs_group('Classes')
class ChargingManager:
LOCAL_CHARGING_LOG_DATASET_NAME = 'charging_log'

Expand Down Expand Up @@ -185,7 +187,7 @@ def calculate_chargeable() -> dict[str, int | None]:
)

def calculate_total_charged_amount(self) -> Decimal:
"""Calculate the total amount of money charged for pay-per-event events."""
"""Calculate the total amount of money charged for pay-per-event events so far."""
if self._charging_state is None:
raise RuntimeError('Charging manager is not initialized')

Expand Down Expand Up @@ -215,7 +217,10 @@ def calculate_max_event_charge_count_within_limit(self, event_name: str) -> int
return math.floor(result) if result.is_finite() else None

def get_pricing_info(self) -> ActorPricingInfo:
"""Retrieve detailed infor about the effective pricing of the current Actor run."""
"""Retrieve detailed information about the effective pricing of the current Actor run.

This can be used for instance when your code needs to support multiple pricing models in transition periods.
"""
if self._charging_state is None:
raise RuntimeError('Charging manager is not initialized')

Expand All @@ -231,11 +236,33 @@ def get_pricing_info(self) -> ActorPricingInfo:
)


@docs_group('Data structures')
@dataclass(frozen=True)
class ChargeResult:
event_charge_limit_reached: bool
"""If true, no more events of this type can be charged within the limit"""

charged_count: int
"""Total amount of charged events - may be lower than the requested amount"""

chargeable_within_limit: dict[str, int | None]
"""How many events of each known type can still be charged within the limit"""


@docs_group('Data structures')
@dataclass
class ActorPricingInfo:
pricing_model: PricingModel | None
"""The currently effective pricing model"""

max_total_charge_usd: Decimal
"""A configured limit for the total charged amount - if you exceed it, you won't receive more money than this."""

is_pay_per_event: bool
"""A shortcut - true if the Actor runs with the pay-per-event pricing model"""

per_event_prices: dict[str, Decimal]
"""Price of every known event type"""


@dataclass
Expand All @@ -248,11 +275,3 @@ class ChargingStateItem:
class PricingInfoItem:
price: Decimal
title: str


@dataclass
class ActorPricingInfo:
pricing_model: PricingModel | None
max_total_charge_usd: Decimal
is_pay_per_event: bool
per_event_prices: dict[str, Decimal]