Skip to content

Commit ed95675

Browse files
committed
docs: Add runnable code blocks
Closes: #452
1 parent e4d8436 commit ed95675

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+530
-226
lines changed

.github/workflows/build_and_deploy_docs.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ jobs:
6767

6868
- name: Build Docusaurus docs
6969
run: make build-docs
70+
env:
71+
APIFY_SIGNING_TOKEN: ${{ secrets.APIFY_SIGNING_TOKEN }}
7072

7173
- name: Set up GitHub Pages
7274
uses: actions/configure-pages@v5

.github/workflows/run_code_checks.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ jobs:
3232

3333
docs_check:
3434
name: Docs check
35-
uses: apify/workflows/.github/workflows/python_docs_check.yaml@main
35+
uses: apify/workflows/.github/workflows/python_docs_check.yaml@update-python-docs-check
36+
secrets: inherit
3637

3738
integration_tests:
3839
name: Integration tests

docs/01_overview/01_introduction.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ id: introduction
33
title: Introduction
44
---
55

6-
import CodeBlock from '@theme/CodeBlock';
6+
import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock';
77

8-
import IntroductionExample from '!!raw-loader!./code/01_introduction.py';
8+
import IntroductionExample from '!!raw-loader!roa-loader!./code/01_introduction.py';
99

1010
The Apify SDK for Python is the official library for creating [Apify Actors](https://docs.apify.com/platform/actors) using Python.
1111

12-
<CodeBlock className="language-python">
12+
<RunnableCodeBlock className="language-python" language="python">
1313
{IntroductionExample}
14-
</CodeBlock>
14+
</RunnableCodeBlock>
1515

1616
## What are Actors?
1717

docs/01_overview/03_actor_structure.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ id: actor-structure
33
title: Actor structure
44
---
55

6-
import CodeBlock from '@theme/CodeBlock';
76
import Tabs from '@theme/Tabs';
87
import TabItem from '@theme/TabItem';
8+
import CodeBlock from '@theme/CodeBlock';
99

10-
import UnderscoreMainExample from '!!raw-loader!./code/actor_structure/main.py';
11-
import MainExample from '!!raw-loader!./code/actor_structure/__main__.py';
10+
import UnderscoreMainExample from '!!raw-loader!./code/actor_structure/__main__.py';
11+
import MainExample from '!!raw-loader!./code/actor_structure/main.py';
1212

1313
All Python Actor templates follow the same structure.
1414

@@ -20,14 +20,14 @@ which follows the [standard requirements file format](https://pip.pypa.io/en/sta
2020
The Actor's source code is in the `src/` folder. This folder contains two important files: `main.py`, which contains the main function of the Actor, and `__main__.py`, which is the entrypoint of the Actor package, setting up the Actor [logger](../concepts/logging) and executing the Actor's main function via [`asyncio.run`](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run).
2121

2222
<Tabs>
23-
<TabItem value="main.py" label="main.py" default>
23+
<TabItem value="__main__.py" label="__main.py__" default>
2424
<CodeBlock className="language-python">
25-
{MainExample}
25+
{UnderscoreMainExample}
2626
</CodeBlock>
2727
</TabItem>
28-
<TabItem value="__main__.py" label="__main.py__">
28+
<TabItem value="main.py" label="main.py">
2929
<CodeBlock className="language-python">
30-
{UnderscoreMainExample}
30+
{MainExample}
3131
</CodeBlock>
3232
</TabItem>
3333
</Tabs>
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import asyncio
2+
13
import httpx
24
from bs4 import BeautifulSoup
35

@@ -6,12 +8,17 @@
68

79
async def main() -> None:
810
async with Actor:
9-
actor_input = await Actor.get_input()
11+
actor_input = await Actor.get_input() or {}
12+
url = actor_input.get('url', 'https://apify.com')
1013
async with httpx.AsyncClient() as client:
11-
response = await client.get(actor_input['url'])
14+
response = await client.get(url)
1215
soup = BeautifulSoup(response.content, 'html.parser')
1316
data = {
14-
'url': actor_input['url'],
17+
'url': url,
1518
'title': soup.title.string if soup.title else None,
1619
}
1720
await Actor.push_data(data)
21+
22+
23+
if __name__ == '__main__':
24+
asyncio.run(main())

docs/02_concepts/01_actor_lifecycle.mdx

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@ id: actor-lifecycle
33
title: Actor lifecycle
44
---
55

6-
import CodeBlock from '@theme/CodeBlock';
6+
import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock';
77
import Tabs from '@theme/Tabs';
88
import TabItem from '@theme/TabItem';
99

10-
import ClassContextExample from '!!raw-loader!./code/01_class_context.py';
11-
import ClassManualExample from '!!raw-loader!./code/01_class_manual.py';
12-
import InstanceContextExample from '!!raw-loader!./code/01_instance_context.py';
13-
import InstanceManualExample from '!!raw-loader!./code/01_instance_manual.py';
10+
import ClassContextExample from '!!raw-loader!roa-loader!./code/01_class_context.py';
11+
import ClassManualExample from '!!raw-loader!roa-loader!./code/01_class_manual.py';
12+
import InstanceContextExample from '!!raw-loader!roa-loader!./code/01_instance_context.py';
13+
import InstanceManualExample from '!!raw-loader!roa-loader!./code/01_instance_manual.py';
1414

15-
import ErrorHandlingContextExample from '!!raw-loader!./code/01_error_handling_context.py';
16-
import ErrorHandlingManualExample from '!!raw-loader!./code/01_error_handling_manual.py';
15+
import ErrorHandlingContextExample from '!!raw-loader!roa-loader!./code/01_error_handling_context.py';
16+
import ErrorHandlingManualExample from '!!raw-loader!roa-loader!./code/01_error_handling_manual.py';
1717

18-
import RebootExample from '!!raw-loader!./code/01_reboot.py';
18+
import RebootExample from '!!raw-loader!roa-loader!./code/01_reboot.py';
1919

20-
import StatusMessageExample from '!!raw-loader!./code/01_status_message.py';
20+
import StatusMessageExample from '!!raw-loader!roa-loader!./code/01_status_message.py';
2121

2222
This guide explains how an **Apify Actor** starts, runs, and shuts down, describing the complete Actor lifecycle. For information about the core concepts such as Actors, the Apify Console, storages, and events, check out the [Apify platform documentation](https://docs.apify.com/platform).
2323

@@ -31,29 +31,29 @@ When the Actor exits, either normally or due to an exception, the SDK performs a
3131

3232
<Tabs groupId="request_queue">
3333
<TabItem value="actor_class_with_context_manager" label="Actor class with context manager" default>
34-
<CodeBlock className="language-python">
34+
<RunnableCodeBlock className="language-python" language="python">
3535
{ClassContextExample}
36-
</CodeBlock>
36+
</RunnableCodeBlock>
3737
</TabItem>
3838
<TabItem value="actor_class_with_manual_init_exit" label="Actor class with manual init/exit">
39-
<CodeBlock className="language-python">
39+
<RunnableCodeBlock className="language-python" language="python">
4040
{ClassManualExample}
41-
</CodeBlock>
41+
</RunnableCodeBlock>
4242
</TabItem>
4343
</Tabs>
4444

4545
You can also create an [`Actor`](https://docs.apify.com/sdk/python/reference/class/Actor) instance directly. This does not change its capabilities but allows you to specify optional parameters during initialization, such as disabling automatic `sys.exit()` calls or customizing timeouts. The choice between using a context manager or manual initialization depends on how much control you require over the Actor's startup and shutdown sequence.
4646

4747
<Tabs groupId="request_queue">
4848
<TabItem value="actor_instance_with_context_manager" label="Actor instance with context manager" default>
49-
<CodeBlock className="language-python">
49+
<RunnableCodeBlock className="language-python" language="python">
5050
{InstanceContextExample}
51-
</CodeBlock>
51+
</RunnableCodeBlock>
5252
</TabItem>
5353
<TabItem value="actor_instance_with_manual_init_exit" label="Actor instance with manual init/exit">
54-
<CodeBlock className="language-python">
54+
<RunnableCodeBlock className="language-python" language="python">
5555
{InstanceManualExample}
56-
</CodeBlock>
56+
</RunnableCodeBlock>
5757
</TabItem>
5858
</Tabs>
5959

@@ -72,19 +72,19 @@ Catch exceptions only when necessary - for example, to retry network timeouts or
7272

7373
Below is a minimal context-manager example where an unhandled exception automatically fails the run, followed by a manual pattern giving you more control.
7474

75-
<CodeBlock className="language-python">{ErrorHandlingContextExample}</CodeBlock>
75+
<RunnableCodeBlock className="language-python" language="python">{ErrorHandlingContextExample}</RunnableCodeBlock>
7676

7777
If you need explicit control over exit codes or status messages, you can manage the Actor manually using [`Actor.init`](https://docs.apify.com/sdk/python/reference/class/Actor#init), [`Actor.exit`](https://docs.apify.com/sdk/python/reference/class/Actor#exit), and [`Actor.fail`](https://docs.apify.com/sdk/python/reference/class/Actor#fail).
7878

79-
<CodeBlock className="language-python">{ErrorHandlingManualExample}</CodeBlock>
79+
<RunnableCodeBlock className="language-python" language="python">{ErrorHandlingManualExample}</RunnableCodeBlock>
8080

8181
## Reboot
8282

8383
Rebooting (available on the Apify platform only) instructs the platform worker to restart your Actor from the beginning of its execution. Use this mechanism only for transient conditions that are likely to resolve after a fresh start — for example, rotating a blocked proxy pool or recovering from a stuck browser environment.
8484

8585
Before triggering a reboot, persist any essential state externally (e.g., to the key-value store or dataset), as all in-memory data is lost after reboot. The example below tracks a reboot counter in the default key-value store and allows at most three restarts before exiting normally.
8686

87-
<CodeBlock className="language-python">{RebootExample}</CodeBlock>
87+
<RunnableCodeBlock className="language-python" language="python">{RebootExample}</RunnableCodeBlock>
8888

8989
## Status message
9090

@@ -94,7 +94,7 @@ Update the status only when the user's understanding of progress changes - avoid
9494

9595
The SDK optimizes updates by sending an API request only when the message text changes, so repeating the same message incurs no additional cost.
9696

97-
<CodeBlock className="language-python">{StatusMessageExample}</CodeBlock>
97+
<RunnableCodeBlock className="language-python" language="python">{StatusMessageExample}</RunnableCodeBlock>
9898

9999
## Conclusion
100100

docs/02_concepts/02_actor_input.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ id: actor-input
33
title: Actor input
44
---
55

6-
import CodeBlock from '@theme/CodeBlock';
6+
import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock';
77

8-
import InputExample from '!!raw-loader!./code/02_input.py';
8+
import InputExample from '!!raw-loader!roa-loader!./code/02_input.py';
99

1010
The Actor gets its [input](https://docs.apify.com/platform/actors/running/input) from the input record in its default [key-value store](https://docs.apify.com/platform/storage/key-value-store).
1111

1212
To access it, instead of reading the record manually, you can use the [`Actor.get_input`](../../reference/class/Actor#get_input) convenience method. It will get the input record key from the Actor configuration, read the record from the default key-value store,and decrypt any [secret input fields](https://docs.apify.com/platform/actors/development/secret-input).
1313

1414
For example, if an Actor received a JSON input with two fields, `{ "firstNumber": 1, "secondNumber": 2 }`, this is how you might process it:
1515

16-
<CodeBlock className="language-python">
16+
<RunnableCodeBlock className="language-python" language="python">
1717
{InputExample}
18-
</CodeBlock>
18+
</RunnableCodeBlock>

docs/02_concepts/03_storages.mdx

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ id: storages
33
title: Working with storages
44
---
55

6-
import CodeBlock from '@theme/CodeBlock';
6+
import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock';
77

8-
import OpeningStoragesExample from '!!raw-loader!./code/03_opening_storages.py';
9-
import DeletingStoragesExample from '!!raw-loader!./code/03_deleting_storages.py';
10-
import DatasetReadWriteExample from '!!raw-loader!./code/03_dataset_read_write.py';
11-
import DatasetExportsExample from '!!raw-loader!./code/03_dataset_exports.py';
12-
import KvsReadWriteExample from '!!raw-loader!./code/03_kvs_read_write.py';
13-
import KvsIteratingExample from '!!raw-loader!./code/03_kvs_iterating.py';
14-
import KvsPublicRecordExample from '!!raw-loader!./code/03_kvs_public_url.py';
15-
import RqExample from '!!raw-loader!./code/03_rq.py';
8+
import OpeningStoragesExample from '!!raw-loader!roa-loader!./code/03_opening_storages.py';
9+
import DeletingStoragesExample from '!!raw-loader!roa-loader!./code/03_deleting_storages.py';
10+
import DatasetReadWriteExample from '!!raw-loader!roa-loader!./code/03_dataset_read_write.py';
11+
import DatasetExportsExample from '!!raw-loader!roa-loader!./code/03_dataset_exports.py';
12+
import KvsReadWriteExample from '!!raw-loader!roa-loader!./code/03_kvs_read_write.py';
13+
import KvsIteratingExample from '!!raw-loader!roa-loader!./code/03_kvs_iterating.py';
14+
import KvsPublicRecordExample from '!!raw-loader!roa-loader!./code/03_kvs_public_url.py';
15+
import RqExample from '!!raw-loader!roa-loader!./code/03_rq.py';
1616

1717
The `Actor` class provides methods to work either with the default storages of the Actor, or with any other storage, named or unnamed.
1818

@@ -65,18 +65,18 @@ There are several methods for directly working with the default key-value store
6565

6666
The [`Actor.open_dataset`](../../reference/class/Actor#open_dataset), [`Actor.open_key_value_store`](../../reference/class/Actor#open_key_value_store) and [`Actor.open_request_queue`](../../reference/class/Actor#open_request_queue) methods can be used to open any storage for reading and writing. You can either use them without arguments to open the default storages, or you can pass a storage ID or name to open another storage.
6767

68-
<CodeBlock className="language-python">
68+
<RunnableCodeBlock className="language-python" language="python">
6969
{OpeningStoragesExample}
70-
</CodeBlock>
70+
</RunnableCodeBlock>
7171

7272
## Deleting storages
7373

7474
To delete a storage, you can use the [`Dataset.drop`](../../reference/class/Dataset#drop),
7575
[`KeyValueStore.drop`](../../reference/class/KeyValueStore#drop) or [`RequestQueue.drop`](../../reference/class/RequestQueue#drop) methods.
7676

77-
<CodeBlock className="language-python">
77+
<RunnableCodeBlock className="language-python" language="python">
7878
{DeletingStoragesExample}
79-
</CodeBlock>
79+
</RunnableCodeBlock>
8080

8181
## Working with datasets
8282

@@ -90,19 +90,19 @@ To read data from a dataset, you can use the [`Dataset.get_data`](../../referenc
9090

9191
To get an iterator of the data, you can use the [`Dataset.iterate_items`](../../reference/class/Dataset#iterate_items) method.
9292

93-
<CodeBlock className="language-python">
93+
<RunnableCodeBlock className="language-python" language="python">
9494
{DatasetReadWriteExample}
95-
</CodeBlock>
95+
</RunnableCodeBlock>
9696

9797
### Exporting items
9898

9999
You can also export the dataset items into a key-value store, as either a CSV or a JSON record,
100100
using the [`Dataset.export_to_csv`](../../reference/class/Dataset#export_to_csv)
101101
or [`Dataset.export_to_json`](../../reference/class/Dataset#export_to_json) method.
102102

103-
<CodeBlock className="language-python">
103+
<RunnableCodeBlock className="language-python" language="python">
104104
{DatasetExportsExample}
105-
</CodeBlock>
105+
</RunnableCodeBlock>
106106

107107
## Working with key-value stores
108108

@@ -116,27 +116,27 @@ To write records into a key-value store, you can use the [`KeyValueStore.set_val
116116
You can set the content type of a record with the `content_type` argument.
117117
To delete a record, set its value to `None`.
118118

119-
<CodeBlock className="language-python">
119+
<RunnableCodeBlock className="language-python" language="python">
120120
{KvsReadWriteExample}
121-
</CodeBlock>
121+
</RunnableCodeBlock>
122122

123123
### Iterating keys
124124

125125
To get an iterator of the key-value store record keys,
126126
you can use the [`KeyValueStore.iterate_keys`](../../reference/class/KeyValueStore#iterate_keys) method.
127127

128-
<CodeBlock className="language-python">
128+
<RunnableCodeBlock className="language-python" language="python">
129129
{KvsIteratingExample}
130-
</CodeBlock>
130+
</RunnableCodeBlock>
131131

132132
### Public URLs of records
133133

134134
To get a publicly accessible URL of a key-value store record,
135135
you can use the [`KeyValueStore.get_public_url`](../../reference/class/KeyValueStore#get_public_url) method.
136136

137-
<CodeBlock className="language-python">
137+
<RunnableCodeBlock className="language-python" language="python">
138138
{KvsPublicRecordExample}
139-
</CodeBlock>
139+
</RunnableCodeBlock>
140140

141141
## Working with request queues
142142

@@ -168,6 +168,6 @@ To check if all the requests in the queue are handled, you can use the [`Request
168168

169169
### Full example
170170

171-
<CodeBlock className="language-python">
171+
<RunnableCodeBlock className="language-python" language="python">
172172
{RqExample}
173-
</CodeBlock>
173+
</RunnableCodeBlock>

docs/02_concepts/04_actor_events.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ id: actor-events
33
title: Actor events & state persistence
44
---
55

6-
import CodeBlock from '@theme/CodeBlock';
6+
import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock';
77

8-
import ActorEventsExample from '!!raw-loader!./code/04_actor_events.py';
8+
import ActorEventsExample from '!!raw-loader!roa-loader!./code/04_actor_events.py';
99

1010
During its runtime, the Actor receives Actor events sent by the Apify platform or generated by the Apify SDK itself.
1111

@@ -76,6 +76,6 @@ During its runtime, the Actor receives Actor events sent by the Apify platform o
7676
To add handlers to these events, you use the [`Actor.on`](../../reference/class/Actor#on) method,
7777
and to remove them, you use the [`Actor.off`](../../reference/class/Actor#off) method.
7878

79-
<CodeBlock className="language-python">
79+
<RunnableCodeBlock className="language-python" language="python">
8080
{ActorEventsExample}
81-
</CodeBlock>
81+
</RunnableCodeBlock>

0 commit comments

Comments
 (0)