Lint¶
Static checks for the rules of hooks. pn lint is a thin wrapper
around this module: lint_paths finds
and checks the files, and lint_source
checks one module's text. Both return
Finding objects, so you can run the same
checks from a test or an editor integration.
from pythonnative.lint import lint_paths
for finding in lint_paths(["app"]):
print(finding.format())
See the Linting guide for what each rule catches and how to suppress a finding.
Static checks for the rules of hooks, behind pn lint.
The linter parses Python source with the standard library's ast module,
so it has no dependencies and never imports or runs the code it checks.
It reports four rules:
PN101: a hook is called conditionally: inside anif, a loop, atry, amatch, a comprehension, a lambda, a conditional expression, the right side ofand/or, a nested function, or after an earlyreturn.PN102: a hook is called outside a@componentfunction or ause_*custom hook (including at module level).PN103: an effect, memo, or callback reads a local name that its literal dependency list leaves out.PN104:key=is passed to a module-level@component; use.with_key(...)on the returned element instead.
A syntax error is reported as PN000. A trailing # pn: ignore
comment silences every finding on its line, and
# pn: ignore[PN101,PN103] silences only the listed codes.
Example
Classes:
| Name | Description |
|---|---|
Finding |
One problem found by the linter. |
Functions:
| Name | Description |
|---|---|
lint_source |
Lint one module's source text. |
lint_paths |
Lint every Python file under |
Attributes:
| Name | Type | Description |
|---|---|---|
CODES |
dict[str, str]
|
Every code |
CODES
module-attribute
¶
CODES: dict[str, str] = {
"PN000": "the file could not be parsed",
"PN101": "hook called conditionally, in a loop, or in a nested function",
"PN102": "hook called outside a component or custom hook",
"PN103": "dependency list is missing a name the callback reads",
"PN104": "key= passed to a user component",
}
Every code pn lint can report, with a one-line summary.
Finding
dataclass
¶
One problem found by the linter.
Attributes:
| Name | Type | Description |
|---|---|---|
path |
str
|
The file the finding is in, as it was passed to the linter. |
line |
int
|
1-based line number. |
col |
int
|
1-based column number. |
code |
str
|
Rule code, such as |
message |
str
|
Human-readable explanation. |
Methods:
| Name | Description |
|---|---|
format |
Return the finding as |
to_dict |
Return the finding as a JSON-serializable dictionary. |
lint_source
¶
Lint one module's source text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
str
|
The Python source to check. |
required |
filename
|
str
|
The path reported in each finding. The file isn't read. |
required |
Returns:
| Type | Description |
|---|---|
list[Finding]
|
The findings, sorted by position, with suppressed ones removed. |
list[Finding]
|
A syntax error yields a single |
lint_paths
¶
Lint every Python file under paths.
Directories are searched recursively for *.py files, skipping
.git, build, dist, .venv*, __pycache__,
node_modules, and site. A file named directly is linted
whatever its suffix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paths
|
Iterable[str | PathLike[str]]
|
Files and directories to check. |
required |
Returns:
| Type | Description |
|---|---|
list[Finding]
|
All findings, ordered by path and then by position. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If one of |