Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
quote_type = single

[Makefile]
indent_style = tab
Expand Down
83 changes: 83 additions & 0 deletions .github/workflows/_checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ on:
permissions:
contents: read

env:
NODE_VERSION: 24

jobs:
actions_lint_check:
name: Actions lint check
Expand Down Expand Up @@ -46,6 +49,86 @@ jobs:
with:
python_versions: '["3.11", "3.12", "3.13", "3.14"]'

markdown_lint_check:
name: Markdown lint check
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7

- name: Set up Node
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install pnpm and website dependencies
uses: apify/actions/pnpm-install@v1.2.0
with:
working-directory: website

- name: Lint Markdown
run: pnpm lint:md
working-directory: website

website_lint_check:
name: Website lint check
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7

- name: Set up Node
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install pnpm and website dependencies
uses: apify/actions/pnpm-install@v1.2.0
with:
working-directory: website

- name: Lint website code
run: pnpm lint:code
working-directory: website

- name: Check website formatting
run: pnpm format:check
working-directory: website

image_lint_check:
name: Image lint check
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
with:
fetch-depth: 0

# Doc images must be committed as optimized `.webp`. This fails when a PR adds raster
# images in another format so they get converted via `pnpm opt:images` first.
- name: Get changed unoptimized images
id: changed-files
uses: tj-actions/changed-files@v47
with:
files: |
docs/**/*.{png,jpg,jpeg,gif,bmp,tif,tiff,avif}
website/static/**/*.{png,jpg,jpeg,gif,bmp,tif,tiff,avif}
separator: "\n"

- name: Fail on unoptimized images
if: steps.changed-files.outputs.any_changed == 'true'
env:
UNOPTIMIZED_IMAGE_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
echo "Unoptimized images detected! Convert each one to WebP, e.g.:"
echo ""
while IFS= read -r file_path; do
echo " (cd website && pnpm opt:images \"../$file_path\")"
done <<< "$UNOPTIMIZED_IMAGE_FILES"
echo ""
echo "Then reference the resulting .webp files in your Markdown."
exit 1

unit_tests:
name: Unit tests
if: inputs.run_tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/manual_release_docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ permissions:
contents: read

env:
NODE_VERSION: 22
NODE_VERSION: 24
PYTHON_VERSION: 3.14

jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/manual_version_docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ permissions:
contents: read

env:
NODE_VERSION: "22"
NODE_VERSION: "24"
PYTHON_VERSION: "3.14"

jobs:
Expand Down
31 changes: 28 additions & 3 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# markdownlint config for the docs and top-level Markdown files.
# Run via `pnpm lint:md` / `pnpm lint:md:fix` from the `website/` directory.
default: true
line-length:
line_length: 150
ul-style: dash

# Prose is written one sentence per line, so line length is not enforced.
line-length: false

ul-style:
style: dash

# Nested unordered lists use 4-space indentation.
ul-indent:
indent: 4

# Docs are MDX and embed JSX components.
no-inline-html: false

# MDX pages set their title via front matter, so multiple/duplicate H1s are fine.
single-title: false
no-duplicate-heading:
siblings_only: true

# Anchor links into other pages can't be validated locally.
link-fragments: false

no-bare-urls: false
no-trailing-punctuation:
punctuation: ".,;:。,;:"
no-multiple-blanks:
maximum: 2
12 changes: 6 additions & 6 deletions .rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ uv run poe e2e-tests
- Unused imports are allowed in `__init__.py` files (re-exports)
- **Pre-commit hooks**: lint check + type check run automatically on commit
- **Commits**: [Conventional Commits](https://www.conventionalcommits.org/) format. Choose the type based on *what* changed, not just *why*:
- `feat:` / `fix:` / `perf:` / `refactor:` / `style:` — **source code only**; these trigger a release and appear in the changelog
- `test:` — test additions or changes (no release triggered)
- `docs:` — documentation changes; also triggers a doc release on master
- `ci:` — CI/workflow changes
- `chore:` — dependency bumps, tooling, and other housekeeping
- `build:` — build system changes
- `feat:` / `fix:` / `perf:` / `refactor:` / `style:` — **source code only**; these trigger a release and appear in the changelog
- `test:` — test additions or changes (no release triggered)
- `docs:` — documentation changes; also triggers a doc release on master
- `ci:` — CI/workflow changes
- `chore:` — dependency bumps, tooling, and other housekeeping
- `build:` — build system changes

## Architecture

Expand Down
43 changes: 28 additions & 15 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,22 @@ To run the documentation locally (requires Node.js):
uv run poe run-docs
```

### Linting the docs and website

Markdown content (this guide, `README.md`, and the `docs/` folder) is checked with
[markdownlint](https://github.com/DavidAnson/markdownlint). The Docusaurus website code is linted
with [oxlint](https://oxc.rs/) and formatted with [oxfmt](https://oxc.rs/). All of them run in CI.
To run them locally (requires Node.js 22.12 or newer and pnpm), from the `website/` directory:

```sh
pnpm lint # lint Markdown and website code
pnpm lint:fix # auto-fix both
pnpm format # format the website code
```

Doc images are committed as optimized `.webp`. To convert a new image, run
`pnpm opt:images <path-to-image>` from the `website/` directory.

## Commits

We use [Conventional Commits](https://www.conventionalcommits.org/) format for commit messages. This convention is used to automatically determine version bumps during the release process.
Expand Down Expand Up @@ -149,25 +165,22 @@ Publishing new versions to [PyPI](https://pypi.org/project/apify) is automated t

1. **Do not do this unless absolutely necessary.** In all conceivable scenarios, you should use the `release` workflow instead.
2. **Make sure you know what you're doing.**
3. Update the version number by modifying the `version` field under `project` in `pyproject.toml`:

3. Update the version number:

- Modify the `version` field under `project` in `pyproject.toml`.

```toml
[project]
name = "apify"
version = "x.z.y"
```
```toml
[project]
name = "apify"
version = "x.z.y"
```

4. Build the package:

```sh
uv run poe build
```
```sh
uv run poe build
```

5. Upload to PyPI:

```sh
uv publish --token YOUR_API_TOKEN
```
```sh
uv publish --token YOUR_API_TOKEN
```
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ async def main() -> None:
The full SDK documentation lives at **[docs.apify.com/sdk/python](https://docs.apify.com/sdk/python)**. For the Apify platform itself, see the [Apify documentation](https://docs.apify.com/).

| Section | What you'll find |
|---|---|
| --- | --- |
| [Overview](https://docs.apify.com/sdk/python/docs/overview) | What the SDK is, what Actors are, and how the pieces fit together. |
| [Quick start](https://docs.apify.com/sdk/python/docs/quick-start) | Create, run, and deploy your first Python Actor. |
| [Concepts](https://docs.apify.com/sdk/python/docs/concepts/actor-lifecycle) | Actor lifecycle, input, storages, events, proxy management, interacting with other Actors, webhooks, accessing the Apify API, logging, configuration, and pay-per-event. |
Expand Down
3 changes: 0 additions & 3 deletions docs/02_concepts/09_logging.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ You can use the `extra` argument for all log levels, it's not specific to the wa
Result:

<!-- TODO: This is an ugly ugly hack, we should make a component for this in the docs theme -->
<!-- markdownlint-disable no-inline-html -->
<style>{`
.actor-log-block .ansi-blue-fg {
color: rgb(0, 160, 228);
Expand Down Expand Up @@ -87,8 +86,6 @@ Result:
<div> RuntimeError: Ouch!</div>
</pre>

<!-- markdownlint-enable no-inline-html -->

## Redirect logs from other Actor runs

In some situations, one Actor is going to start one or more other Actors and wait for them to finish and produce some results. In such cases, you might want to redirect the logs and status messages of the started Actors runs back to the parent Actor run, so that you can see the progress of the started Actors' runs in the parent Actor's logs. This guide will show possibilities on how to do it.
Expand Down
2 changes: 1 addition & 1 deletion docs/03_guides/06_scrapy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ For further details, see the [Scrapy migration guide](https://docs.apify.com/cli

The following example shows a Scrapy Actor that scrapes page titles and enqueues links found on each page. This example aligns with the structure provided in the Apify Actor templates.

{/* Not runnable from the docs: a Scrapy Actor is a multi-file project, while the "Run on Apify" runner executes a single self-contained snippet. */}
{/*Not runnable from the docs: a Scrapy Actor is a multi-file project, while the "Run on Apify" runner executes a single self-contained snippet.*/}
<Tabs>
<TabItem value="__main__.py" label="__main__.py">
<CodeBlock className="language-python">
Expand Down
2 changes: 1 addition & 1 deletion docs/03_guides/09_browser_use.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ The following Actor runs a Browser Use agent for a single task and stores its st

The whole Actor fits in a single file. A `run_agent_task` helper holds the Browser Use-specific logic: it defines the output schema and builds the LLM, browser, and agent. The `main` coroutine handles the [Actor](https://docs.apify.com/platform/actors) lifecycle, reads the input, sets up [Apify Proxy](https://docs.apify.com/platform/proxy), runs the agent, and stores the result:

{/* Not runnable from the docs: the agent needs an LLM API key (OPENAI_API_KEY) that the shared example runner does not provide. */}
{/*Not runnable from the docs: the agent needs an LLM API key (OPENAI_API_KEY) that the shared example runner does not provide.*/}
<CodeBlock className="language-python">
{BrowserUseExample}
</CodeBlock>
Expand Down
4 changes: 4 additions & 0 deletions docs/04_upgrading/upgrading_to_v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ Some changes in the related model classes:
- `RequestQueueHead` - replaced by `RequestQueueHeadWithLocks`.

## Removed Actor.config property

- `Actor.config` property has been removed. Use `Actor.configuration` instead.

## Default storage ids in configuration changed to None

- `Configuration.default_key_value_store_id` changed from `'default'` to `None`.
- `Configuration.default_dataset_id` changed from `'default'` to `None`.
- `Configuration.default_request_queue_id` changed from `'default'` to `None`.
Expand All @@ -80,6 +82,7 @@ Previously using the default storage without specifying its `id` in `Configurati
## Actor initialization and ServiceLocator changes

`Actor` initialization and global `service_locator` services setup is more strict and predictable.

- Services in `Actor` can't be changed after calling `Actor.init`, entering the `async with Actor` context manager or after requesting them from the `Actor`.
- Services in `Actor` can be different from services in Crawler.

Expand Down Expand Up @@ -115,6 +118,7 @@ async def main():
Apify SDK v3.0 also reworks how storage clients are configured, giving you explicit control over which client the `Actor` uses.

### Explicit control over storage clients used in Actor

- It is now possible to have full control over which storage clients are used by the `Actor`. To make development of Actors convenient, the `Actor` has two storage clients. One that is used when running on Apify platform or when opening storages with `force_cloud=True` and the other client that is used when running outside the Apify platform. The `Actor` has reasonable defaults and for the majority of use-cases there is no need to change it. However, if you need to use a different storage client, you can set it up before entering `Actor` context through `service_locator`.

**Now (v3.0):**
Expand Down
2 changes: 2 additions & 0 deletions docs/04_upgrading/upgrading_to_v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Support for Python 3.10 has been dropped. The Apify Python SDK v4.x now requires
## Keyword-only arguments

Secondary parameters in these signatures can no longer be passed positionally:

- `Actor``get_value`, `push_data`, `charge`, `use_state`.
- `ChargingManager``charge`.

Expand Down Expand Up @@ -66,6 +67,7 @@ run = await Actor.call('user/actor', timeout='inherit')
### Deprecated Configuration fields

The deprecated `latest_sdk_version`, `log_format`, and `standby_port` fields have been removed from `Configuration`:

- In place of `standby_port`, use `web_server_port`.
- `latest_sdk_version` and `log_format` don't have replacement. SDK version checking isn't supported for the Python SDK and the log format should be adjusted in code instead.

Expand Down
27 changes: 0 additions & 27 deletions website/.eslintrc.json

This file was deleted.

20 changes: 20 additions & 0 deletions website/.oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"printWidth": 120,
"singleQuote": true,
"ignorePatterns": [
"**/*.md",
"**/*.mdx",
"**/*.json",
"**/*.jsonc",
"**/*.yaml",
"**/*.yml",
"**/*.css",
"**/*.scss",
"**/*.html",
"**/node_modules",
"build",
".docusaurus",
"versioned_docs",
"versioned_sidebars"
]
}
6 changes: 2 additions & 4 deletions website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,8 @@ module.exports = {
useCssCascadeLayers: false, // this breaks styles on homepage and link colors everywhere
},
},
onBrokenLinks:
/** @type {import('@docusaurus/types').ReportingSeverity} */ ('warn'),
onBrokenMarkdownLinks:
/** @type {import('@docusaurus/types').ReportingSeverity} */ ('warn'),
onBrokenLinks: /** @type {import('@docusaurus/types').ReportingSeverity} */ ('warn'),
onBrokenMarkdownLinks: /** @type {import('@docusaurus/types').ReportingSeverity} */ ('warn'),
themes: [
[
'@apify/docs-theme',
Expand Down
Loading
Loading