scrapely-python 0.1.19__py3-none-any.whl → 0.1.20__py3-none-any.whl

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.
scrapely/__init__.py CHANGED
@@ -132,7 +132,7 @@ from .errors import (
132
132
  raise_for_status,
133
133
  )
134
134
 
135
- __version__ = '0.1.19'
135
+ __version__ = '0.1.20'
136
136
  __all__ = [
137
137
  # Core
138
138
  'Actor',
scrapely/charging.py CHANGED
@@ -246,6 +246,8 @@ class ChargingManager:
246
246
  # grows), so the local budget gates on the run's true remaining budget.
247
247
  self._platform_other_usd: Decimal = Decimal('0')
248
248
  self._last_remaining_budget_nd: Optional[int] = None
249
+ # True once the platform reported a remaining budget (its usage is then in the local budget).
250
+ self._platform_budget_seen = False
249
251
  self._charge_lock = RLock()
250
252
  self._flush_lock = asyncio.Lock()
251
253
  # Serializes budget calculation/reservation with PPE-aware dataset pushes.
@@ -311,6 +313,7 @@ class ChargingManager:
311
313
  self._last_remaining_budget_nd = None
312
314
  if nd is None or self._max_total_charge_usd is None or nd < 0:
313
315
  return
316
+ self._platform_budget_seen = True
314
317
  other = self._max_total_charge_usd - Decimal(nd) / Decimal(1_000_000_000) - self._total_charged_usd
315
318
  if other > self._platform_other_usd:
316
319
  self._platform_other_usd = other
@@ -1717,7 +1720,7 @@ async def push_data_with_charges(
1717
1720
  else:
1718
1721
  await charging_manager._void_charge(name, op_id, charged)
1719
1722
 
1720
- for _attempt in range(4):
1723
+ for _attempt in range(6):
1721
1724
  if rows <= 0:
1722
1725
  break
1723
1726
  ops = []
@@ -1741,10 +1744,25 @@ async def push_data_with_charges(
1741
1744
  if short_to is None:
1742
1745
  break
1743
1746
  # Some event came back short: void this attempt in full and retry with
1744
- # the rows that event can pay for (a void restores the budget).
1747
+ # the whole rows the budget covers at the FULL per-row cost. Sizing
1748
+ # from the short event alone ignores the other events of the row, so
1749
+ # the retry came back short again (appstore 64df0a3608d74af88: 20
1750
+ # details -> 14, retry sized 14, app-item short, 0 saved). What this
1751
+ # attempt was accepted is budget the void gives back; with the
1752
+ # platform's remainingBudgetNd the local budget also knows the rest.
1753
+ attempt_spent = sum(
1754
+ (charging_manager._calculate_event_price(name) or Decimal('0')) * Decimal(charged)
1755
+ for name, charged, _op, _unc in ops
1756
+ )
1745
1757
  await undo(ops)
1746
1758
  ops = []
1747
- rows = short_to # got < n * rows, so short_to < rows
1759
+ fit = int(attempt_spent / row_cost) if row_cost > 0 else 0
1760
+ if charging_manager._platform_budget_seen and charging_manager._max_total_charge_usd is not None and row_cost > 0:
1761
+ fit = max(fit, int(charging_manager._remaining_budget_usd() / row_cost))
1762
+ # At least one more single-row try: without the platform's remaining
1763
+ # budget the leftover after the short answer is unknown, and the last
1764
+ # affordable row may still fit.
1765
+ rows = min(rows - 1, max(fit, 1))
1748
1766
 
1749
1767
  if rows <= 0 or not ops:
1750
1768
  await undo(ops)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scrapely-python
3
- Version: 0.1.19
3
+ Version: 0.1.20
4
4
  Summary: Scrapely Python SDK - A toolkit for building Actors on the Scrapely platform
5
5
  Author-email: Scrapely <support@scrape.ly>
6
6
  License-Expression: MIT AND Apache-2.0
@@ -1,9 +1,9 @@
1
- scrapely/__init__.py,sha256=7AUWixuhrohpSFpDkEHo809IBKI-2u-m4ZWPMorYKSk,5746
1
+ scrapely/__init__.py,sha256=i4A_AaMoKY5cMXqvx7Df9eyucWihcJTRz4ra4HobviI,5746
2
2
  scrapely/_browser_locations.py,sha256=8QVVnkms2bDn3_LDYgYDR59MvFx8757l_JYnZ7xb3oI,145269
3
3
  scrapely/actor.py,sha256=Lsb4_14RCGQy-EWACnqijo7Hz5xvPKSDZcu4B8_ZrHc,81685
4
4
  scrapely/browser_configuration.py,sha256=jAZapNSHLFW05B96df4wNBtcyiiU9DA3ml0yTL1FwfA,5770
5
5
  scrapely/cdp_retry.py,sha256=hdTJEAIKhApM7IOk1DrQEl8NoflSJSmqd4RbNJ2IsgI,8540
6
- scrapely/charging.py,sha256=TxcALWN4hhwJ0i2raYmtHGA1P79lQ1bmhBMtrvNACIw,81862
6
+ scrapely/charging.py,sha256=uba7lPFx7ENY4aPjqQAN-SDY1wjXZ83jLxcnyGxYDTE,83121
7
7
  scrapely/charging_client.py,sha256=-4q-Ww7gu9EZXpM9QIn1Vd4vwAXmgL_WEKqaQIx3ViA,3961
8
8
  scrapely/configuration.py,sha256=Of-lKm7hoPGUQO8d08kV7fAy2co9QTfb8Of_8ds5PSA,17028
9
9
  scrapely/errors.py,sha256=DCAlVvE3jToZuPEG2HVDL7i8D8hLboomQ5JpSOcsXoQ,4107
@@ -39,10 +39,10 @@ scrapely/storage/_file_system/_key_value_store_client.py,sha256=4Ipgbh4qEqAkwQJ9
39
39
  scrapely/storage/_file_system/_storage_client.py,sha256=aaGJ4P0QAtIgEMl6yHpuobeWFD5M4rMC5HwhOOvuGuo,1794
40
40
  scrapely/storage_clients/__init__.py,sha256=cs1YX7JV2_GKBXeiiJgkQFali08b5_y_jH6Yw7iROAA,656
41
41
  scrapely/storages/__init__.py,sha256=4PAELhJNZ3exJ7Uouicn-bCQ58NafKjhLBixQ8ATQc4,173
42
- scrapely_python-0.1.19.dist-info/licenses/LICENSE,sha256=pQGY0XwjIYh-a2HfawxHq1en53bXkFkDj2Q70jKWHr4,1088
43
- scrapely_python-0.1.19.dist-info/licenses/LICENSE-APACHE,sha256=N8m0FzMq8i4UbTgXZvKEZJSD-27OF8pWZYS_atz4kTU,11355
44
- scrapely_python-0.1.19.dist-info/licenses/NOTICE,sha256=DEsNrw6UdSIqdYYqMWVFgJnyt6jUivTD7iFU6YM_e1A,1122
45
- scrapely_python-0.1.19.dist-info/METADATA,sha256=PzFQ4BxF0FgSjgOvSQYimfc5v6Pq2notGIWYHCBa-iQ,3487
46
- scrapely_python-0.1.19.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
47
- scrapely_python-0.1.19.dist-info/top_level.txt,sha256=T4B9UMrs4q99QSAFyD1zdXhl40KnLhBKqrDkPhOTsmY,9
48
- scrapely_python-0.1.19.dist-info/RECORD,,
42
+ scrapely_python-0.1.20.dist-info/licenses/LICENSE,sha256=pQGY0XwjIYh-a2HfawxHq1en53bXkFkDj2Q70jKWHr4,1088
43
+ scrapely_python-0.1.20.dist-info/licenses/LICENSE-APACHE,sha256=N8m0FzMq8i4UbTgXZvKEZJSD-27OF8pWZYS_atz4kTU,11355
44
+ scrapely_python-0.1.20.dist-info/licenses/NOTICE,sha256=DEsNrw6UdSIqdYYqMWVFgJnyt6jUivTD7iFU6YM_e1A,1122
45
+ scrapely_python-0.1.20.dist-info/METADATA,sha256=ilbOda4UXoNvHh1O91s-GUv8aQ9C8gA1HF_48yb2Tp8,3487
46
+ scrapely_python-0.1.20.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
47
+ scrapely_python-0.1.20.dist-info/top_level.txt,sha256=T4B9UMrs4q99QSAFyD1zdXhl40KnLhBKqrDkPhOTsmY,9
48
+ scrapely_python-0.1.20.dist-info/RECORD,,