pyscan¶
Package pyscan analyses Python source statically, through tree-sitter: modules and their docstrings, __all__, and imports; classes with their bases, decorators, and members in source order; functions with their parameters as written; and the attribute documentation Sphinx’s ModuleAnalyzer finds (#: comments and docstrings after assignments). Names resolve across the modules of the configured source roots, so a class re-exported by a package is found where it is defined. Nothing is executed.
It is a host library: it reads files (through a reader the host may confine) and allocates with the context allocator, freeing none of it, so a host runs it in an arena: the project and every module, class, and string it returns live until the arena is freed. destroy frees what tree-sitter holds, which no arena can.
Types
- pyscan.All :: struct¶
-
All is a module’s __all__ when it can be read without running code.
- names: [dynamic]string¶
- defined: bool¶
-
the module assigns __all__.
- known: bool¶
-
and its value was read: literal lists, +=, append, extend.
- pyscan.Analysis :: struct¶
-
Analysis is what Sphinx’s ModuleAnalyzer (sphinx.pycode.parser.Parser) finds in a module, keyed as it keys them: attribute documentation from #: comments and from string literals after assignments, annotations, definition order, @final, @overload.
- tagorder: map[string]int¶
-
dotted qualname -> order of its last definition.
- counter: int¶
- finals: map[string]bool¶
- pyscan.Attr_Key :: struct¶
-
Attr_Key is (scope, name): scope is „“ at module level, else the class’s qualname.
- scope: string¶
- name: string¶
- pyscan.Def :: struct¶
-
Def is one binding of a name in a module or class body, in source order.
- name: string¶
- runtime: bool¶
-
false under
if TYPE_CHECKING:.
- target: string¶
-
imports: the absolute module imported from, or imported.
- member: string¶
-
Import_From: the name imported; „*“ for a wildcard.
- tuple: bool¶
-
bound by unpacking: its value is one part of value.
- line: int¶
-
1-based line of the statement.
- pyscan.Def_Kind :: enum u8¶
-
- Class¶
- Function¶
- Assign¶
-
name = value, name: type = value.
- Annotation¶
-
name: type, with no value.
- Import¶
-
import a.b [as c].
- Import_From¶
-
from m import name [as alias].
- Type_Alias¶
-
type Name = value (PEP 695).
- pyscan.Doc :: struct¶
-
Doc is a docstring as Python evaluates it (escapes processed), or none.
- text: string¶
- ok: bool¶
- pyscan.File_Reader :: struct¶
-
File_Reader reads a file for the analyser. The host confines reads to what it may read; ok is false for a file that is missing or refused.
- procedure: proc(user: rawptr, path: string) -> (text: string, ok: bool)¶
- user: rawptr¶
- pyscan.Function :: struct¶
-
- name: string¶
- qualname: string¶
- is_async: bool¶
- is_lambda: bool¶
- type_comment: bool¶
-
A PEP 484 type comment after the header, „# type: (int, str) -> bool“: the parameter types as written („…“ alone when elided) and the return type.
- type_args: [dynamic]string¶
- type_returns: string¶
- pyscan.Module :: struct¶
-
- name: string¶
-
dotted.
- kind: Module_Kind¶
- path: string¶
-
the file read; the folder of a namespace package.
- source: string¶
-
with line breaks normalised to \n.
- broken: bool¶
-
tree-sitter found syntax errors.
- too_deep: bool¶
-
it nests past MAX_SYNTAX_DEPTH, so it is not analysed (kind .Native).
- pyscan.Module_Kind :: enum u8¶
-
- Source¶
-
a .py file.
- Package¶
-
a folder with __init__.py.
- Namespace¶
-
a folder without __init__.py (PEP 420).
- Native¶
-
a compiled extension (.so, .pyd): it cannot be read.
- pyscan.Mro_Entry :: struct¶
-
Mro_Entry is one class of a method resolution order: a class in the roots, or one outside them known by path.
- path: string¶
-
for a class outside the roots: „builtins.object“, „werkzeug.X“.
- pyscan.Object :: struct¶
-
- kind: Object_Kind¶
- tuple: bool¶
-
.Value: bound by unpacking, so value is only its source.
- path: string¶
-
.External, .Builtin: the dotted name.
- abstract: bool¶
-
decorated with abstractmethod.
- decorator: string¶
-
.Unknown wrapper: the decorator as written.
- class_property: bool¶
-
a property under classmethod: a property of the class.
- partial_args: int¶
-
functools.partial and partialmethod: how many leading parameters (after self, for partialmethod) the call already gave, which the signature leaves out.
- partial: bool¶
- partial_method: bool¶
-
partialmethod: as got from the class, a function with no docstring.
- pyscan.Object_Kind :: enum u8¶
-
- None¶
-
not found.
- Module¶
- Class¶
- Function¶
- Value¶
-
anything an assignment made: value is its expression.
- External¶
-
from a module outside the source roots: only path is known.
- Builtin¶
-
a builtin such as str or Exception: path is „builtins.<name>“.
- pyscan.Param :: struct¶
-
- name: string¶
- kind: Param_Kind¶
- type_comment: string¶
-
„a, # type: str“: a per-parameter type comment, or „“.
- pyscan.Param_Kind :: enum u8¶
-
- Positional_Only¶
- Positional_Or_Keyword¶
- Var_Positional¶
- Keyword_Only¶
- Var_Keyword¶
- pyscan.Project :: struct¶
-
Project finds and analyses modules below its source roots, each once.
- roots: []string¶
- reader: File_Reader¶
-
a nil procedure reads with core:os.
- steps: int¶
-
The lookup in progress: its steps (MAX_STEPS), where its stack starts (LOOKUP_STACK_BYTES), and how deep lookups and MRO computations are nested.
- stack_base: uintptr¶
- resolving: int¶
- mro_depth: int¶
- pyscan.Slot :: struct¶
-
Slot is one entry of a class’s __slots__, with the docstring a dictionary gives it.
- name: string¶
- pyscan.Unparse_Mode :: enum u8¶
-
Unparse_Mode chooses whose unparser to follow.
- Sphinx¶
-
Sphinx’s sphinx.pycode.ast.unparse, which preserve_defaults and @overload signatures use: numbers as written when source is given, lambda bodies as „…“, and no parentheses added for precedence.
- Sphinx_Repr¶
-
Sphinx’s unparser without the source, as for overload signatures: numbers as repr.
- Python¶
-
Python’s own ast.unparse, which makes the annotation strings of
from __future__ import annotations: parentheses kept, every expression.
- pyscan.Wrapper :: enum u8¶
-
Wrapper is what the decorators of a function made of it.
- None¶
- Staticmethod¶
- Classmethod¶
- Property¶
- Cached_Property¶
- Unknown¶
-
a decorator from outside the source roots that is not known to keep functions.
Procedures
- pyscan.base_objects :: proc(c: ^Class) -> [dynamic]Object¶
-
base_objects resolves the bases a class statement lists; subscripted generics give their origin.
- pyscan.class_attr :: proc(c: ^Class, name: string, depth := 0) -> Object¶
-
class_attr is getattr(cls, name): the first class along the MRO whose body binds name.
- pyscan.def_object :: proc(m: ^Module, owner: ^Class, d: ^Def, depth: int) -> Object¶
-
def_object turns a binding into the object it holds.
- pyscan.destroy :: proc(p: ^Project)¶
-
destroy frees the trees and the parser. Everything else is in the caller’s allocator.
- pyscan.exported :: proc(m: ^Module, name: string) -> bool¶
-
exported is whether
from m import *binds name: __all__ when m has one, else the public names.
- pyscan.find_def :: proc(s: ^Scope, name: string) -> ^Def¶
-
find_def returns the binding of name that is in force when the body has run: the last runtime one; nil when there is none.
- pyscan.get_attr :: proc(obj: Object, name: string, depth := 0) -> Object¶
-
get_attr is getattr(obj, name) as far as the source tells.
- pyscan.init :: proc(p: ^Project, roots: []string, reader := File_Reader{}) -> bool¶
-
init prepares a project over roots (folders, absolute or relative to the working directory). It returns false when tree-sitter cannot read the Python grammar.
- pyscan.is_builtin :: proc(name: string) -> bool¶
-
is_builtin lists the names of Python’s builtins module that matter to documentation.
- pyscan.is_builtin_exception :: proc(name: string) -> bool¶
-
is_builtin_exception lists the builtin exception classes.
- pyscan.is_exception :: proc(c: ^Class) -> bool¶
-
is_exception is whether a class derives from BaseException, as far as its MRO is known.
- pyscan.lookup_name :: proc(code: ^Module, scope: ^Class, name: string, depth := 0) -> Object¶
-
lookup_name resolves a name where a class body (scope) or the module runs: the class body first, then the module, then builtins.
- pyscan.module :: proc(p: ^Project, name: string) -> ^Module¶
-
module finds, reads, and analyses a module by dotted name, once; nil when no root has it.
- pyscan.module_attr :: proc(m: ^Module, name: string, depth := 0) -> Object¶
-
module_attr looks a name up in a module’s namespace, then among its submodules.
- pyscan.mro :: proc(c: ^Class) -> (order: [dynamic]Mro_Entry, complete: bool)¶
-
mro is the class’s method resolution order, by C3 linearisation, ending with object. complete is false when a base could not be resolved or lies outside the roots (it then appears by path, and what it defines is unknown).
- pyscan.number_repr :: proc(literal: string) -> string¶
-
number_repr is Python’s repr of a numeric literal: integers in decimal, floats in their shortest round-trip form, imaginary numbers with j.
- pyscan.parse_expression :: proc(m: ^Module, s: string) -> (^Module, ts.Node, bool)¶
-
parse_expression parses text, such as a string annotation, as an expression whose names resolve in m. The module returned holds the snippet’s source.
- pyscan.prepare_docstring :: proc(s: string, tab_width := 8) -> [dynamic]string¶
-
prepare_docstring is Sphinx’s sphinx.util.docstrings.prepare_docstring: lines of reST with the common indentation of the lines after the first removed, the first line stripped, leading blank lines dropped, and a blank line at the end.
- pyscan.reference :: proc(m: ^Module, scope: ^Class, n: ts.Node, depth := 0) -> Object¶
-
reference evaluates an expression that names an object: a name, or attributes of one, or a subscripted generic (its origin). Other expressions give None.
- pyscan.repr_bytes :: proc(s: string) -> string¶
-
repr_bytes is Python’s repr of bytes.
- pyscan.repr_str :: proc(s: string) -> string¶
-
repr_str is Python’s repr of a str: single quotes unless the text has one and no double quote, and escapes for what is not printable.
- pyscan.slots :: proc(c: ^Class) -> (out: [dynamic]Slot, ok: bool)¶
-
slots is inspect’s getslots: the __slots__ the class has (its own, or the nearest base’s), as a list, tuple, dictionary, or single string of names. ok is false when there are none, or they are computed.
- pyscan.split_lines :: proc(s: string) -> [dynamic]string¶
-
split_lines is str.splitlines for \n, \r\n, \r and the other line boundaries Python knows; a final line break does not start another line.
- pyscan.str_value :: proc(m: ^Module, n: ts.Node) -> (string, bool)¶
-
str_value is string_value for str constants only.
- pyscan.string_value :: proc(m: ^Module, n: ts.Node) -> (value: string, kind: String_Kind, ok: bool)¶
-
string_value evaluates a string or concatenated_string node as Python does: prefixes, escape sequences, and adjacent literals joined. ok is false for other nodes.