Skip to content

Commit 1171f85

Browse files
committed
Address review: keep the /reference/python URL, tighten the generated intro
Rename the generated page to reference/python.mdx so the URL already published on the website stays valid, and redirect the short-lived /reference/python-api to it instead. Split the conventions into one paragraph per subject, move the Session.call and ToolError sentences under the Session heading, and stop rendering the package's module docstring since the guide is already linked as the practical documentation.
1 parent ffa8219 commit 1171f85

6 files changed

Lines changed: 40 additions & 57 deletions

File tree

.github/workflows/python-reference.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ name: python-reference
22

33
# Regenerate the Python SDK API reference page from the lightpanda-python main
44
# branch and open a pull request when the output changed. The page is
5-
# src/content/reference/python-api.mdx, written by
5+
# src/content/reference/python.mdx, written by
66
# scripts/generate-python-reference.py with pdoc's Python API, so it renders
77
# like any other docs page and goes live at
8-
# https://lightpanda.io/docs/reference/python-api once the website bumps its
8+
# https://lightpanda.io/docs/reference/python once the website bumps its
99
# docs submodule like any other docs change. The package imports without a
1010
# browser binary, so none is needed here. Runs daily to pick up new package
1111
# changes, by hand, or as a smoke run when the generator itself changes.
@@ -44,26 +44,26 @@ jobs:
4444
--with "git+https://github.com/lightpanda-io/lightpanda-python@$sha" \
4545
python scripts/generate-python-reference.py
4646
echo "sha=${sha::7}" >> "$GITHUB_OUTPUT"
47-
git status --short src/content/reference/python-api.mdx
47+
git status --short src/content/reference/python.mdx
4848
4949
- name: Open a pull request if the reference changed
5050
if: github.event_name != 'pull_request'
5151
env:
5252
GH_TOKEN: ${{ github.token }}
5353
SHA: ${{ steps.generate.outputs.sha }}
5454
run: |
55-
if [ -z "$(git status --porcelain src/content/reference/python-api.mdx)" ]; then
55+
if [ -z "$(git status --porcelain src/content/reference/python.mdx)" ]; then
5656
echo "reference already matches lightpanda-python $SHA"
5757
exit 0
5858
fi
5959
git config user.name "github-actions[bot]"
6060
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
6161
git checkout -B python-reference
62-
git add src/content/reference/python-api.mdx
62+
git add src/content/reference/python.mdx
6363
git commit -m "Update the Python SDK API reference to lightpanda-python $SHA"
6464
git push --force origin python-reference
6565
if [ -z "$(gh pr list --head python-reference --state open --json number -q '.[].number')" ]; then
6666
gh pr create --base main --head python-reference \
6767
--title "Update the Python SDK API reference to lightpanda-python $SHA" \
68-
--body "Regenerated \`src/content/reference/python-api.mdx\` from lightpanda-python $SHA. Served at https://lightpanda.io/docs/reference/python-api after the website's submodule bump."
68+
--body "Regenerated \`src/content/reference/python.mdx\` from lightpanda-python $SHA. Served at https://lightpanda.io/docs/reference/python after the website's submodule bump."
6969
fi

redirects.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
export const basePath = '/docs'
1111

1212
export const redirects = {
13-
'/python': '/reference/python-api',
14-
'/reference/python': '/reference/python-api',
13+
'/python': '/reference/python',
14+
'/reference/python-api': '/reference/python',
1515
'/quickstart/installation-and-setup': '/quickstart',
1616
'/quickstart/your-first-test': '/quickstart',
1717
'/quickstart/build-your-first-extraction-script': '/quickstart',

scripts/generate-python-reference.py

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
"""Generate the Python SDK API reference page from the lightpanda package.
2-
3-
The hand-written src/content/reference/python.mdx explains how the package fits
4-
together; this script writes the exhaustive companion page,
5-
src/content/reference/python-api.mdx, by walking the installed `lightpanda`
6-
package with pdoc's Python API and emitting one MDX section per public class,
7-
method, property, function and exception, with the signatures and docstrings
8-
shipped in the code. Emitting MDX instead of pdoc's own HTML keeps the page
1+
"""Generate the Python SDK reference page from the lightpanda package.
2+
3+
This script writes src/content/reference/python.mdx by walking the installed
4+
`lightpanda` package with pdoc's Python API and emitting one MDX section per
5+
public class, method, property, function and exception, with the signatures
6+
and docstrings shipped in the code. Emitting MDX instead of pdoc's own HTML keeps the page
97
inside the Nextra site: sidebar, search, dark mode and deep links all work as
108
on any other page.
119
@@ -34,7 +32,7 @@
3432
import lightpanda
3533

3634
ROOT = Path(__file__).resolve().parent.parent
37-
DEFAULT_OUT = ROOT / "src" / "content" / "reference" / "python-api.mdx"
35+
DEFAULT_OUT = ROOT / "src" / "content" / "reference" / "python.mdx"
3836

3937
FRONTMATTER = """---
4038
title: Python SDK
@@ -55,18 +53,25 @@
5553
"awaitable; the async sections below list only what the twin adds."
5654
)
5755

58-
CONVENTIONS = (
56+
CONVENTIONS = [
5957
"Browser actions are keyword-only methods on [`Session`](#session) and "
6058
"[`AsyncSession`](#asyncsession), named in snake_case after the browser's own action "
6159
"names: the `waitForSelector` action is `wait_for_selector`, and its `backendNodeId` "
62-
"argument is `backend_node_id`. Where a method accepts both `selector` and "
63-
"`backend_node_id`, pass one of the two; `selector` is preferred for reproducibility and "
64-
"wins when both are given, and `backend_node_id` takes the values returned by "
65-
"[`tree`](#session-tree), [`links`](#session-links) or "
66-
"[`find_element`](#session-find-element). [`Session.call`](#session-call) is the escape "
67-
"hatch that takes the action and argument names exactly as the browser declares them. "
68-
"A failed action raises [`ToolError`](#toolerror)."
69-
)
60+
"argument is `backend_node_id`.",
61+
"Where a method accepts both `selector` and `backend_node_id`, pass one of the two. "
62+
"`selector` is preferred for reproducibility and wins when both are given; "
63+
"`backend_node_id` takes the values returned by [`tree`](#session-tree), "
64+
"[`links`](#session-links) or [`find_element`](#session-find-element).",
65+
]
66+
67+
# Fixed paragraphs shown under a class heading, after its docstring.
68+
CLASS_NOTES = {
69+
"Session": (
70+
"[`call`](#session-call) is the escape hatch that takes the action and argument "
71+
"names exactly as the browser declares them. A failed action raises "
72+
"[`ToolError`](#toolerror)."
73+
),
74+
}
7075

7176
FENCE_RE = re.compile(r"^\s*```")
7277
CODE_SPAN_RE = re.compile(r"(`+)(.+?)\1", re.DOTALL)
@@ -301,6 +306,7 @@ def class_code(cls: pdoc.doc.Class) -> str:
301306
def emit_class(page: Page, module: pdoc.doc.Module, cls: pdoc.doc.Class, links: dict[str, str]) -> None:
302307
page.heading(2, cls.name, slug(cls.name))
303308
page.para(render_docstring(cls, links))
309+
page.para(CLASS_NOTES.get(cls.name, ""))
304310
page.fence(class_code(cls))
305311
init = cls.members.get("__init__")
306312
if isinstance(init, pdoc.doc.Function) and "__init__" in vars(cls.obj):
@@ -397,8 +403,8 @@ def generate() -> str:
397403
page.lines.append("# Python SDK")
398404
page.lines.append("")
399405
page.para(INTRO)
400-
page.para(CONVENTIONS)
401-
page.para(render_docstring(module, links))
406+
for paragraph in CONVENTIONS:
407+
page.para(paragraph)
402408

403409
exceptions: list[pdoc.doc.Class] = []
404410
for name in names:

src/content/guides/use-python.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ asyncio.run(main())
164164
Every browser action is a `Session` method, typed and documented in your IDE, with the action and its arguments in snake_case (`wait_for_selector`, `backend_node_id`).
165165
</Callout>
166166

167-
Find every method's signature and docstring in the [Python SDK reference](/reference/python-api).
167+
Find every method's signature and docstring in the [Python SDK reference](/reference/python).
168168

169169
## Replay a saved script
170170

src/content/reference/_meta.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const meta: MetaRecord = {
1010
'http-api': 'HTTP API',
1111
'mcp-tools': 'MCP tools',
1212
pandascript: 'PandaScript',
13-
'python-api': 'Python SDK',
13+
python: 'Python SDK',
1414
}
1515

1616
export default meta
Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,9 @@ description: Reference of every public class, method, property and exception in
88

99
Every public class, method, property and exception of the [`lightpanda` package](https://pypi.org/project/lightpanda/), with the signatures and docstrings shipped in the code. See [Use the Python SDK](/guides/use-python) for a practical walkthrough. Every sync class has an asyncio twin with the same methods, awaitable; the async sections below list only what the twin adds.
1010

11-
Browser actions are keyword-only methods on [`Session`](#session) and [`AsyncSession`](#asyncsession), named in snake_case after the browser's own action names: the `waitForSelector` action is `wait_for_selector`, and its `backendNodeId` argument is `backend_node_id`. Where a method accepts both `selector` and `backend_node_id`, pass one of the two; `selector` is preferred for reproducibility and wins when both are given, and `backend_node_id` takes the values returned by [`tree`](#session-tree), [`links`](#session-links) or [`find_element`](#session-find-element). [`Session.call`](#session-call) is the escape hatch that takes the action and argument names exactly as the browser declares them. A failed action raises [`ToolError`](#toolerror).
11+
Browser actions are keyword-only methods on [`Session`](#session) and [`AsyncSession`](#asyncsession), named in snake_case after the browser's own action names: the `waitForSelector` action is `wait_for_selector`, and its `backendNodeId` argument is `backend_node_id`.
1212

13-
Lightpanda for Python: a lightweight headless browser.
14-
15-
```python
16-
from lightpanda import Browser
17-
18-
with Browser() as b:
19-
page = b.new_session()
20-
page.goto(url="https://example.com")
21-
data = page.extract(schema={"title": "h1"})
22-
```
23-
24-
The same API is available for asyncio:
25-
26-
```python
27-
from lightpanda import AsyncBrowser
28-
29-
async with AsyncBrowser() as b:
30-
page = await b.new_session()
31-
await page.goto(url="https://example.com")
32-
data = await page.extract(schema={"title": "h1"})
33-
```
34-
35-
For Playwright or Puppeteer code, [``CDPServer``](#cdpserver) runs the browser's own
36-
Chrome DevTools Protocol server and hands you the endpoint to connect to
37-
(see its docs for an example). For Selenium, [``BiDiServer``](#bidiserver) serves WebDriver
38-
BiDi the same way and hands you the ``command_executor`` URL.
13+
Where a method accepts both `selector` and `backend_node_id`, pass one of the two. `selector` is preferred for reproducibility and wins when both are given; `backend_node_id` takes the values returned by [`tree`](#session-tree), [`links`](#session-links) or [`find_element`](#session-find-element).
3914

4015
## Browser [#browser]
4116

@@ -85,6 +60,8 @@ One isolated browsing context (own page, cookies, memory).
8560

8661
Do not construct directly — use [`Browser.new_session()`](#browser-new-session).
8762

63+
[`call`](#session-call) is the escape hatch that takes the action and argument names exactly as the browser declares them. A failed action raises [`ToolError`](#toolerror).
64+
8865
```python
8966
class Session(browser: Browser, session_id: str)
9067
```

0 commit comments

Comments
 (0)