Guidedog 手册 0.2.0
语言
本页内容
Guidedog / 文档 0.2.0

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.

attr_docs: map[Attr_Key][dynamic]string

lines, ending with “”.

attr_order: [dynamic]Attr_Key

first-insertion order of attr_docs.

annotations: map[Attr_Key]string
annotation_order: [dynamic]Attr_Key

first-insertion order of annotations.

tagorder: map[string]int

dotted qualname -> order of its last definition.

counter: int
finals: map[string]bool
overloads: map[string][dynamic]^Function
pyscan.Attr_Key :: struct

Attr_Key is (scope, name): scope is “” at module level, else the class’s qualname.

scope: string
name: string
pyscan.Class :: struct
module: ^Module
name: string
qualname: string
node: ts.Node
bases: [dynamic]ts.Node

positional arguments of the class statement.

keywords: [dynamic]Keyword

metaclass=…, and others.

decorators: [dynamic]ts.Node

the decorator expressions.

doc: Doc
scope: Scope
outer: ^Class

the class it is nested in, or nil.

mro_done: bool
mro_complete: bool
mro_order: [dynamic]Mro_Entry
pyscan.Def :: struct

Def is one binding of a name in a module or class body, in source order.

name: string
kind: Def_Kind
node: ts.Node

the statement, or the definition.

runtime: bool

false under if TYPE_CHECKING:.

class: ^Class
function: ^Function
value: ts.Node

right-hand side; null when there is none.

annotation: ts.Node

the type node of an annotated assignment.

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_Read :: struct
path: string
text: string
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
module: ^Module
name: string
qualname: string
node: ts.Node

the function_definition, or the lambda.

is_async: bool
is_lambda: bool
decorators: [dynamic]ts.Node
params: [dynamic]Param
returns: ts.Node

the return type node, or null.

doc: Doc
class: ^Class

the class whose body defines it, or nil.

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.Keyword :: struct
name: string
value: ts.Node
pyscan.Module :: struct
project: ^Project
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.

tree: ^ts.Tree
root: ts.Node
doc: Doc
scope: Scope
all: All
info: Analysis

what Sphinx’s ModuleAnalyzer finds.

broken: bool

tree-sitter found syntax errors.

too_deep: bool

it nests past MAX_SYNTAX_DEPTH, so it is not analysed (kind .Native).

origin: ^Module

A parsed snippet (parse_expression) names things in the namespace of origin.

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.

class: ^Class
path: string

for a class outside the roots: “builtins.object”, “werkzeug.X”.

pyscan.Object :: struct
kind: Object_Kind
module: ^Module

.Module: the module itself; else the module that defines it.

class: ^Class
function: ^Function
value: ts.Node

.Value: the expression assigned.

tuple: bool

.Value: bound by unpacking, so value is only its source.

path: string

.External, .Builtin: the dotted name.

wrapper: Wrapper
abstract: bool

decorated with abstractmethod.

owner: ^Class

the class whose body defines it, when found in one.

def: ^Def

the binding it was found through.

decorator: string

.Unknown wrapper: the decorator as written.

doc: Doc

a docstring given explicitly: property(fget, doc=”…”).

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
annotation: ts.Node

the type node, or null.

default: ts.Node

the default expression, or null.

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.

parser: ^ts.Parser
modules: map[string]^Module

by dotted name; nil records a module not found.

files: [dynamic]File_Read

every source read, in order: a build’s dependencies.

trees: [dynamic]^ts.Tree
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.Scope :: struct
defs: [dynamic]Def
pyscan.Slot :: struct

Slot is one entry of a class’s __slots__, with the docstring a dictionary gives it.

name: string
doc: Doc
pyscan.String_Kind :: enum u8
Str
Bytes
Formatted

an f-string or t-string: not a constant.

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.module_object :: proc(m: ^Module) -> Object

module_object is the object of a module.

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.

pyscan.text :: proc(m: ^Module, n: ts.Node) -> string

text is the source a node spans.

pyscan.try_unparse :: proc(m: ^Module, n: ts.Node, mode := Unparse_Mode.Sphinx) -> (string, bool)

try_unparse is unparse that reports expressions Sphinx’s unparser refuses (comparisons, comprehensions, f-strings, conditional expressions…).

pyscan.unparse :: proc(m: ^Module, n: ts.Node, mode := Unparse_Mode.Sphinx) -> string

unparse writes an expression back as Sphinx’s unparser does (Sphinx mode).