Skip to content

Commit 22f6562

Browse files
committed
Make Tool specific information
1 parent 6be6272 commit 22f6562

1 file changed

Lines changed: 102 additions & 13 deletions

File tree

doc/user_guide/Typing.ipynb

Lines changed: 102 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,18 @@
109109
"cell_type": "markdown",
110110
"id": "56c5e6bc-0d3e-4a43-834a-feecb0060ecd",
111111
"metadata": {},
112-
"source": "## Choice of Type Checker\n\nThe Python ecosystem now has a number of different type checking tools. Param itself is type checked against four of the most common popular type checkers, including:\n\n- `mypy`: The default type checker for Python, without a language server.\n- `pyright`: The default type checker for VSCode, including a language server.\n- `pyrefly`: A type checker written in Rust by Meta (still in beta), including a language server.\n- `ty`: A type checker written in Rust by the Astral team (still in beta), including a language server.\n\nIf you are developing a library built on Param, we recommend using pyright as your type checker. Param's type annotations are primarily optimized for pyright, and it is the checker most likely to benefit your users. VSCode (via Pylance) runs pyright automatically, so correct inference will surface in your users' editors without any extra setup on their part."
113-
},
114-
{
115-
"cell_type": "markdown",
116-
"id": "ad1a8098",
117-
"source": "## Mypy Plugin\n\nIf you use mypy, we recommend enabling the param mypy plugin. Add the following to your `pyproject.toml`:\n\n```toml\n[tool.mypy]\nplugins = [\"param.mypy_plugin\"]\n```\n\nOr in `mypy.ini` / `setup.cfg`:\n\n```ini\n[mypy]\nplugins = param.mypy_plugin\n```\n\nThe plugin is needed because param uses a metaclass `__setattr__` to route class-level parameter assignment through the descriptor protocol. Without the plugin, mypy does not recognize this pattern ([mypy #9758](https://github.com/python/mypy/issues/9758)) and rejects valid code like:\n\n```python\nclass MyModel(param.Parameterized):\n flag = param.Boolean(default=False)\n\nMyModel.flag = True # mypy error without the plugin\n```\n\nWith the plugin enabled, mypy correctly understands that the assignment sets the parameter's default value and type-checks it against the parameter's value type. Pyright handles this correctly without any plugin.",
118-
"metadata": {}
119-
},
120-
{
121-
"cell_type": "markdown",
122-
"id": "c46b524d",
123-
"source": "## basedpyright\n\n[basedpyright](https://docs.basedpyright.com/) is a community fork of pyright with stricter default rules. Param does not officially support basedpyright-specific lint rules, but it works fine if you suppress one false positive.\n\nbasedpyright enables `reportUnannotatedClassAttribute` by default, which warns on any class attribute without an explicit type annotation in non-`@final` classes:\n\n```\nwarning: Type annotation for attribute `title` is required because this class\nis not decorated with `@final` (reportUnannotatedClassAttribute)\n```\n\nThis rule is not present in standard pyright, mypy, or any other supported checker. It does not apply well to Param because the Parameter descriptors already encode the full type contract via `__get__`/`__set__` overloads, making the warnings false positives.\n\n**Recommended fix**: suppress the rule project-wide. In `pyproject.toml`:\n\n```toml\n[tool.basedpyright]\nreportUnannotatedClassAttribute = \"none\"\n```\n\nOr in `pyrightconfig.json`:\n\n```json\n{\n \"reportUnannotatedClassAttribute\": \"none\"\n}\n```\n\nNote that this also suppresses the warning for non-Parameterized classes in your project. If you want the rule active elsewhere, you can disable it per-file by adding a comment at the top of files that use Param:\n\n```python\n# pyright: reportUnannotatedClassAttribute=none\n```\n\n**Why not use `@final` or add annotations?** Marking Parameterized classes as `@final` would break Param's fundamental design pattern since these classes are routinely subclassed. Adding redundant type annotations (e.g. `title: str = param.String()`) creates a maintenance burden and a potential source-of-truth mismatch between the annotation and the Parameter's actual type (consider `allow_None=True` being added later without updating the annotation).\n\nTo isolate basedpyright-specific rules when debugging type errors, you can temporarily set all `reportUnannotated*` rules to `\"none\"` so that only standard pyright diagnostics remain.",
124-
"metadata": {}
112+
"source": [
113+
"## Choice of Type Checker\n",
114+
"\n",
115+
"The Python ecosystem now has a number of different type checking tools. Param itself is type checked against four of the most common popular type checkers, including:\n",
116+
"\n",
117+
"- `mypy`: The default type checker for Python, without a language server.\n",
118+
"- `pyright`: The default type checker for VSCode, including a language server.\n",
119+
"- `pyrefly`: A type checker written in Rust by Meta, including a language server.\n",
120+
"- `ty`: A type checker written in Rust by the Astral team (still in beta), including a language server.\n",
121+
"\n",
122+
"If you are developing a library built on Param, we recommend using pyright as your type checker. Param's type annotations are primarily optimized for pyright, and it is the checker most likely to benefit your users. VSCode (via Pylance) runs pyright automatically, so correct inference will surface in your users' editors without any extra setup on their part."
123+
]
125124
},
126125
{
127126
"cell_type": "markdown",
@@ -209,6 +208,96 @@
209208
"- For finite choices today, prefer `Literal[...]` annotations with `Selector`.\n",
210209
"- Run your type checker alongside your tests to get both static and runtime safety."
211210
]
211+
},
212+
{
213+
"cell_type": "markdown",
214+
"id": "851a0c4a-822b-4bf0-832d-1d58e673971b",
215+
"metadata": {},
216+
"source": [
217+
"## Tool specific information\n",
218+
"\n",
219+
"Below is giving tool specific information."
220+
]
221+
},
222+
{
223+
"cell_type": "markdown",
224+
"id": "ad1a8098",
225+
"metadata": {},
226+
"source": [
227+
"### Mypy\n",
228+
"\n",
229+
"If you use mypy, we recommend enabling the param mypy plugin. Add the following to your `pyproject.toml`:\n",
230+
"\n",
231+
"```toml\n",
232+
"[tool.mypy]\n",
233+
"plugins = [\"param.mypy_plugin\"]\n",
234+
"```\n",
235+
"\n",
236+
"Or in `mypy.ini` / `setup.cfg`:\n",
237+
"\n",
238+
"```ini\n",
239+
"[mypy]\n",
240+
"plugins = param.mypy_plugin\n",
241+
"```\n",
242+
"\n",
243+
"The plugin is needed because param uses a metaclass `__setattr__` to route class-level parameter assignment through the descriptor protocol. Without the plugin, mypy does not recognize this pattern ([mypy #9758](https://github.com/python/mypy/issues/9758)) and rejects valid code like:\n",
244+
"\n",
245+
"```python\n",
246+
"class MyModel(param.Parameterized):\n",
247+
" flag = param.Boolean(default=False)\n",
248+
"\n",
249+
"MyModel.flag = True # mypy error without the plugin\n",
250+
"```\n",
251+
"\n",
252+
"With the plugin enabled, mypy correctly understands that the assignment sets the parameter's default value and type-checks it against the parameter's value type. "
253+
]
254+
},
255+
{
256+
"cell_type": "markdown",
257+
"id": "c46b524d",
258+
"metadata": {},
259+
"source": [
260+
"### basedpyright\n",
261+
"\n",
262+
"[basedpyright](https://docs.basedpyright.com/) is a community fork of pyright with stricter default rules. Param does not officially support basedpyright-specific type rules, but it works fine if you suppress one false positive.\n",
263+
"\n",
264+
"basedpyright enables `reportUnannotatedClassAttribute` by default, which warns on any class attribute without an explicit type annotation in non-`@final` classes. \n",
265+
"\n",
266+
"This rule does not apply well to Param because the Parameter descriptors already encode the full type contract via `__get__`/`__set__` overloads, making the warnings false positives. Marking Parameterized classes as `@final` would break Param's fundamental design pattern since these classes are routinely subclassed. Adding redundant type annotations (e.g. `title: str = param.String()`) creates a maintenance burden and a potential source-of-truth mismatch between the annotation and the Parameter's actual type (consider `allow_None=True` being added later without updating the annotation).\n",
267+
"\n",
268+
"The Recommended fix is to suppress the rule project-wide. In `pyproject.toml`:\n",
269+
"\n",
270+
"```toml\n",
271+
"[tool.basedpyright]\n",
272+
"reportUnannotatedClassAttribute = \"none\"\n",
273+
"```\n",
274+
"\n",
275+
"Or in `pyrightconfig.json`:\n",
276+
"\n",
277+
"```json\n",
278+
"{\n",
279+
" \"reportUnannotatedClassAttribute\": \"none\"\n",
280+
"}\n",
281+
"```\n",
282+
"\n",
283+
"Note that this also suppresses the warning for non-Parameterized classes in your project. If you want the rule active elsewhere, you can disable it per-file by adding a comment at the top of files that use Param:\n",
284+
"\n",
285+
"```python\n",
286+
"# pyright: reportUnannotatedClassAttribute=none\n",
287+
"```\n",
288+
"\n",
289+
"To isolate basedpyright-specific rules when debugging type errors, you can temporarily set the following setting:\n",
290+
"\n",
291+
"```toml\n",
292+
"[tool.basedpyright]\n",
293+
"typeCheckingMode = \"standard\"\n",
294+
"reportAny = \"none\"\n",
295+
"reportExplicitAny = \"none\"\n",
296+
"reportUnreachable = \"none\"\n",
297+
"reportUnusedParameter = \"none\"\n",
298+
"reportIgnoreCommentWithoutRule = \"none\"\n",
299+
"```"
300+
]
212301
}
213302
],
214303
"metadata": {

0 commit comments

Comments
 (0)