9
9
from pydantic import TypeAdapter
10
10
11
11
from apify_shared .utils import ignore_docs
12
+ from crawlee ._utils .context import ensure_context
12
13
13
14
from apify ._models import ActorRun , PricingModel
14
15
from apify ._utils import docs_group
@@ -115,14 +116,15 @@ def __init__(self, configuration: Configuration, client: ApifyClientAsync) -> No
115
116
self ._client = client
116
117
self ._charging_log_dataset : Dataset | None = None
117
118
118
- self ._charging_state : dict [str , ChargingStateItem ] | None = None
119
+ self ._charging_state : dict [str , ChargingStateItem ] = {}
119
120
self ._pricing_info : dict [str , PricingInfoItem ] = {}
120
121
121
122
self ._not_ppe_warning_printed = False
123
+ self .active = False
122
124
123
125
async def __aenter__ (self ) -> None :
124
126
"""Initialize the charging manager - this is called by the `Actor` class and shouldn't be invoked manually."""
125
- self ._charging_state = {}
127
+ self .active = True
126
128
127
129
if self ._is_at_home :
128
130
# Running on the Apify platform - fetch pricing info for the current run.
@@ -169,12 +171,13 @@ async def __aexit__(
169
171
exc_value : BaseException | None ,
170
172
exc_traceback : TracebackType | None ,
171
173
) -> None :
172
- pass
174
+ if not self .active :
175
+ raise RuntimeError ('Exiting an uninitialized ChargingManager' )
173
176
174
- async def charge (self , event_name : str , count : int = 1 ) -> ChargeResult :
175
- if self ._charging_state is None :
176
- raise RuntimeError ('Charging manager is not initialized' )
177
+ self .active = False
177
178
179
+ @ensure_context
180
+ async def charge (self , event_name : str , count : int = 1 ) -> ChargeResult :
178
181
def calculate_chargeable () -> dict [str , int | None ]:
179
182
"""Calculate the maximum number of events of each type that can be charged within the current budget."""
180
183
return {
@@ -265,19 +268,15 @@ def calculate_chargeable() -> dict[str, int | None]:
265
268
chargeable_within_limit = calculate_chargeable (),
266
269
)
267
270
271
+ @ensure_context
268
272
def calculate_total_charged_amount (self ) -> Decimal :
269
- if self ._charging_state is None :
270
- raise RuntimeError ('Charging manager is not initialized' )
271
-
272
273
return sum (
273
274
(item .total_charged_amount for item in self ._charging_state .values ()),
274
275
start = Decimal (),
275
276
)
276
277
278
+ @ensure_context
277
279
def calculate_max_event_charge_count_within_limit (self , event_name : str ) -> int | None :
278
- if self ._charging_state is None :
279
- raise RuntimeError ('Charging manager is not initialized' )
280
-
281
280
pricing_info = self ._pricing_info .get (event_name )
282
281
283
282
if pricing_info is not None :
@@ -293,10 +292,8 @@ def calculate_max_event_charge_count_within_limit(self, event_name: str) -> int
293
292
result = (self ._max_total_charge_usd - self .calculate_total_charged_amount ()) / price
294
293
return math .floor (result ) if result .is_finite () else None
295
294
295
+ @ensure_context
296
296
def get_pricing_info (self ) -> ActorPricingInfo :
297
- if self ._charging_state is None :
298
- raise RuntimeError ('Charging manager is not initialized' )
299
-
300
297
return ActorPricingInfo (
301
298
pricing_model = self ._pricing_model ,
302
299
is_pay_per_event = self ._pricing_model == 'PAY_PER_EVENT' ,
0 commit comments