Skip to content

Commit b6e8a5f

Browse files
committed
Merge branch 'master' into new-apify-storage-clients
2 parents 16b76dd + a3988b7 commit b6e8a5f

File tree

12 files changed

+545
-394
lines changed

12 files changed

+545
-394
lines changed

src/apify/_actor.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from apify_client import ApifyClientAsync
1515
from apify_shared.consts import ActorEnvVars, ActorExitCodes, ApifyEnvVars
16-
from apify_shared.utils import ignore_docs, maybe_extract_enum_member_value
16+
from apify_shared.utils import maybe_extract_enum_member_value
1717
from crawlee import service_locator
1818
from crawlee.events import (
1919
Event,
@@ -56,7 +56,44 @@
5656
@docs_name('Actor')
5757
@docs_group('Actor')
5858
class _ActorType:
59-
"""The class of `Actor`. Only make a new instance if you're absolutely sure you need to."""
59+
"""The core class for building Actors on the Apify platform.
60+
61+
Actors are serverless programs running in the cloud that can perform anything from simple actions
62+
(such as filling out a web form or sending an email) to complex operations (such as crawling an
63+
entire website or removing duplicates from a large dataset). They are packaged as Docker containers
64+
which accept well-defined JSON input, perform an action, and optionally produce well-defined output.
65+
66+
### References
67+
68+
- Apify platform documentation: https://docs.apify.com/platform/actors
69+
- Actor whitepaper: https://whitepaper.actor/
70+
71+
### Usage
72+
73+
```python
74+
import asyncio
75+
76+
import httpx
77+
from apify import Actor
78+
from bs4 import BeautifulSoup
79+
80+
81+
async def main() -> None:
82+
async with Actor:
83+
actor_input = await Actor.get_input()
84+
async with httpx.AsyncClient() as client:
85+
response = await client.get(actor_input['url'])
86+
soup = BeautifulSoup(response.content, 'html.parser')
87+
data = {
88+
'url': actor_input['url'],
89+
'title': soup.title.string if soup.title else None,
90+
}
91+
await Actor.push_data(data)
92+
93+
if __name__ == '__main__':
94+
asyncio.run(main())
95+
```
96+
"""
6097

6198
_is_rebooting = False
6299
_is_any_instance_initialized = False
@@ -108,7 +145,6 @@ def __init__(
108145

109146
self._is_initialized = False
110147

111-
@ignore_docs
112148
async def __aenter__(self) -> Self:
113149
"""Initialize the Actor.
114150
@@ -120,7 +156,6 @@ async def __aenter__(self) -> Self:
120156
await self.init()
121157
return self
122158

123-
@ignore_docs
124159
async def __aexit__(
125160
self,
126161
_exc_type: type[BaseException] | None,

src/apify/_charging.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from pydantic import TypeAdapter
1010

11-
from apify_shared.utils import ignore_docs
1211
from crawlee._utils.context import ensure_context
1312

1413
from apify._models import ActorRun, PricingModel
@@ -28,7 +27,16 @@
2827

2928
@docs_group('Charging')
3029
class ChargingManager(Protocol):
31-
"""Provides fine-grained access to pay-per-event functionality."""
30+
"""Provides fine-grained access to pay-per-event functionality.
31+
32+
The ChargingManager allows you to charge for specific events in your Actor when using
33+
the pay-per-event pricing model. This enables precise cost control and transparent
34+
billing for different operations within your Actor.
35+
36+
### References
37+
38+
- Apify platform documentation: https://docs.apify.com/platform/actors/publishing/monetize
39+
"""
3240

3341
async def charge(self, event_name: str, count: int = 1) -> ChargeResult:
3442
"""Charge for a specified number of events - sub-operations of the Actor.
@@ -90,7 +98,6 @@ class ActorPricingInfo:
9098
"""Price of every known event type."""
9199

92100

93-
@ignore_docs
94101
class ChargingManagerImplementation(ChargingManager):
95102
"""Implementation of the `ChargingManager` Protocol - this is only meant to be instantiated internally."""
96103

src/apify/_crypto.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from cryptography.hazmat.primitives.asymmetric import padding, rsa
1313
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
1414

15-
from apify_shared.utils import ignore_docs
1615
from crawlee._utils.crypto import crypto_random_object_id
1716

1817
from apify._consts import ENCRYPTED_INPUT_VALUE_REGEXP, ENCRYPTED_JSON_VALUE_PREFIX, ENCRYPTED_STRING_VALUE_PREFIX
@@ -22,7 +21,6 @@
2221
ENCRYPTION_AUTH_TAG_LENGTH = 16
2322

2423

25-
@ignore_docs
2624
def public_encrypt(value: str, *, public_key: rsa.RSAPublicKey) -> dict:
2725
"""Encrypts the given value using AES cipher and the password for encryption using the public key.
2826
@@ -66,7 +64,6 @@ def public_encrypt(value: str, *, public_key: rsa.RSAPublicKey) -> dict:
6664
}
6765

6866

69-
@ignore_docs
7067
def private_decrypt(
7168
encrypted_password: str,
7269
encrypted_value: str,
@@ -118,7 +115,6 @@ def private_decrypt(
118115
return decipher_bytes.decode('utf-8')
119116

120117

121-
@ignore_docs
122118
def load_private_key(private_key_file_base64: str, private_key_password: str) -> rsa.RSAPrivateKey:
123119
private_key = serialization.load_pem_private_key(
124120
base64.b64decode(private_key_file_base64.encode('utf-8')),
@@ -138,7 +134,6 @@ def _load_public_key(public_key_file_base64: str) -> rsa.RSAPublicKey:
138134
return public_key
139135

140136

141-
@ignore_docs
142137
def decrypt_input_secrets(private_key: rsa.RSAPrivateKey, input_data: Any) -> Any:
143138
"""Decrypt input secrets."""
144139
if not isinstance(input_data, dict):
@@ -180,7 +175,6 @@ def encode_base62(num: int) -> str:
180175
return res
181176

182177

183-
@ignore_docs
184178
def create_hmac_signature(secret_key: str, message: str) -> str:
185179
"""Generate an HMAC signature and encodes it using Base62. Base62 encoding reduces the signature length.
186180

src/apify/_models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from typing import TypeAlias
1717

1818

19-
@docs_group('Other')
19+
@docs_group('Actor')
2020
class Webhook(BaseModel):
2121
__model_config__ = ConfigDict(populate_by_name=True)
2222

src/apify/_platform_event_manager.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,9 @@
2727

2828
from apify._configuration import Configuration
2929

30-
3130
__all__ = ['EventManager', 'LocalEventManager', 'PlatformEventManager']
3231

3332

34-
@docs_group('Event data')
35-
class PersistStateEvent(BaseModel):
36-
name: Literal[Event.PERSIST_STATE]
37-
data: Annotated[EventPersistStateData, Field(default_factory=lambda: EventPersistStateData(is_migrating=False))]
38-
39-
4033
@docs_group('Event data')
4134
class SystemInfoEventData(BaseModel):
4235
mem_avg_bytes: Annotated[float, Field(alias='memAvgBytes')]
@@ -64,31 +57,37 @@ def to_crawlee_format(self, dedicated_cpus: float) -> EventSystemInfoData:
6457
)
6558

6659

67-
@docs_group('Event data')
60+
@docs_group('Events')
61+
class PersistStateEvent(BaseModel):
62+
name: Literal[Event.PERSIST_STATE]
63+
data: Annotated[EventPersistStateData, Field(default_factory=lambda: EventPersistStateData(is_migrating=False))]
64+
65+
66+
@docs_group('Events')
6867
class SystemInfoEvent(BaseModel):
6968
name: Literal[Event.SYSTEM_INFO]
7069
data: SystemInfoEventData
7170

7271

73-
@docs_group('Event data')
72+
@docs_group('Events')
7473
class MigratingEvent(BaseModel):
7574
name: Literal[Event.MIGRATING]
7675
data: Annotated[EventMigratingData, Field(default_factory=EventMigratingData)]
7776

7877

79-
@docs_group('Event data')
78+
@docs_group('Events')
8079
class AbortingEvent(BaseModel):
8180
name: Literal[Event.ABORTING]
8281
data: Annotated[EventAbortingData, Field(default_factory=EventAbortingData)]
8382

8483

85-
@docs_group('Event data')
84+
@docs_group('Events')
8685
class ExitEvent(BaseModel):
8786
name: Literal[Event.EXIT]
8887
data: Annotated[EventExitData, Field(default_factory=EventExitData)]
8988

9089

91-
@docs_group('Event data')
90+
@docs_group('Events')
9291
class EventWithoutData(BaseModel):
9392
name: Literal[
9493
Event.SESSION_RETIRED,
@@ -101,13 +100,13 @@ class EventWithoutData(BaseModel):
101100
data: Any = None
102101

103102

104-
@docs_group('Event data')
103+
@docs_group('Events')
105104
class DeprecatedEvent(BaseModel):
106105
name: Literal['cpuInfo']
107106
data: Annotated[dict[str, Any], Field(default_factory=dict)]
108107

109108

110-
@docs_group('Event data')
109+
@docs_group('Events')
111110
class UnknownEvent(BaseModel):
112111
name: str
113112
data: Annotated[dict[str, Any], Field(default_factory=dict)]

src/apify/_proxy_configuration.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import httpx
1111

1212
from apify_shared.consts import ApifyEnvVars
13-
from apify_shared.utils import ignore_docs
1413
from crawlee.proxy_configuration import ProxyConfiguration as CrawleeProxyConfiguration
1514
from crawlee.proxy_configuration import ProxyInfo as CrawleeProxyInfo
1615
from crawlee.proxy_configuration import _NewUrlFunction
@@ -29,7 +28,6 @@
2928
SESSION_ID_MAX_LENGTH = 50
3029

3130

32-
@ignore_docs
3331
def is_url(url: str) -> bool:
3432
"""Check if the given string is a valid URL."""
3533
try:
@@ -105,7 +103,6 @@ class ProxyConfiguration(CrawleeProxyConfiguration):
105103

106104
_configuration: Configuration
107105

108-
@ignore_docs
109106
def __init__(
110107
self,
111108
*,

src/apify/_utils.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,18 @@ def is_running_in_ipython() -> bool:
3030
return getattr(builtins, '__IPYTHON__', False)
3131

3232

33-
# The order of the rendered API groups is defined in the docusaurus-plugin-typedoc-api.
33+
# The order of the rendered API groups is defined in the website/docusaurus.config.js file.
3434
GroupName = Literal[
3535
'Actor',
3636
'Charging',
3737
'Configuration',
38-
'Event managers',
3938
'Event data',
39+
'Event managers',
40+
'Events',
41+
'Request loaders',
4042
'Storage clients',
4143
'Storage data',
4244
'Storages',
43-
'Other',
4445
]
4546

4647

src/apify/log.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import logging
44

5-
from apify_shared.utils import ignore_docs
65
from crawlee._log_config import CrawleeLogFormatter, configure_logger, get_configured_log_level
76

87
# Name of the logger used throughout the library (resolves to 'apify')
@@ -12,7 +11,6 @@
1211
logger = logging.getLogger(logger_name)
1312

1413

15-
@ignore_docs
1614
class ActorLogFormatter(CrawleeLogFormatter): # noqa: D101 (Inherited from parent class)
1715
pass
1816

src/apify/storages/_request_list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class _SimpleUrlInput(_RequestDetails):
3838
url_input_adapter = TypeAdapter(list[_RequestsFromUrlInput | _SimpleUrlInput])
3939

4040

41-
@docs_group('Storages')
41+
@docs_group('Request loaders')
4242
class RequestList(CrawleeRequestList):
4343
"""Extends crawlee RequestList.
4444

uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)