feat: indie status page MVP -- FastAPI + SQLite
- 8 DB models (services, incidents, monitors, subscribers, etc.) - Full CRUD API for services, incidents, monitors - Public status page with live data - Incident detail page with timeline - API key authentication - Uptime monitoring scheduler - 13 tests passing - TECHNICAL_DESIGN.md with full spec
This commit is contained in:
commit
902133edd3
4655 changed files with 1342691 additions and 0 deletions
365
venv/lib/python3.11/site-packages/mypy/checker_shared.py
Normal file
365
venv/lib/python3.11/site-packages/mypy/checker_shared.py
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
"""Shared definitions used by different parts of type checker."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import abstractmethod
|
||||
from collections.abc import Iterator, Sequence, Set as AbstractSet
|
||||
from contextlib import contextmanager
|
||||
from typing import NamedTuple, overload
|
||||
|
||||
from mypy_extensions import trait
|
||||
|
||||
from mypy.errorcodes import ErrorCode
|
||||
from mypy.errors import ErrorWatcher
|
||||
from mypy.message_registry import ErrorMessage
|
||||
from mypy.nodes import (
|
||||
ArgKind,
|
||||
Context,
|
||||
Expression,
|
||||
FuncItem,
|
||||
LambdaExpr,
|
||||
MypyFile,
|
||||
Node,
|
||||
RefExpr,
|
||||
SymbolNode,
|
||||
TypeInfo,
|
||||
Var,
|
||||
)
|
||||
from mypy.plugin import CheckerPluginInterface, Plugin
|
||||
from mypy.types import (
|
||||
CallableType,
|
||||
Instance,
|
||||
LiteralValue,
|
||||
Overloaded,
|
||||
PartialType,
|
||||
TupleType,
|
||||
Type,
|
||||
TypedDictType,
|
||||
TypeType,
|
||||
)
|
||||
from mypy.typevars import fill_typevars
|
||||
|
||||
|
||||
# An object that represents either a precise type or a type with an upper bound;
|
||||
# it is important for correct type inference with isinstance.
|
||||
class TypeRange(NamedTuple):
|
||||
item: Type
|
||||
is_upper_bound: bool # False => precise type
|
||||
|
||||
|
||||
@trait
|
||||
class ExpressionCheckerSharedApi:
|
||||
@abstractmethod
|
||||
def accept(
|
||||
self,
|
||||
node: Expression,
|
||||
type_context: Type | None = None,
|
||||
allow_none_return: bool = False,
|
||||
always_allow_any: bool = False,
|
||||
is_callee: bool = False,
|
||||
) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def check_call(
|
||||
self,
|
||||
callee: Type,
|
||||
args: list[Expression],
|
||||
arg_kinds: list[ArgKind],
|
||||
context: Context,
|
||||
arg_names: Sequence[str | None] | None = None,
|
||||
callable_node: Expression | None = None,
|
||||
callable_name: str | None = None,
|
||||
object_type: Type | None = None,
|
||||
original_type: Type | None = None,
|
||||
) -> tuple[Type, Type]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def transform_callee_type(
|
||||
self,
|
||||
callable_name: str | None,
|
||||
callee: Type,
|
||||
args: list[Expression],
|
||||
arg_kinds: list[ArgKind],
|
||||
context: Context,
|
||||
arg_names: Sequence[str | None] | None = None,
|
||||
object_type: Type | None = None,
|
||||
) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def method_fullname(self, object_type: Type, method_name: str) -> str | None:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def check_method_call_by_name(
|
||||
self,
|
||||
method: str,
|
||||
base_type: Type,
|
||||
args: list[Expression],
|
||||
arg_kinds: list[ArgKind],
|
||||
context: Context,
|
||||
original_type: Type | None = None,
|
||||
) -> tuple[Type, Type]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def visit_typeddict_index_expr(
|
||||
self, td_type: TypedDictType, index: Expression, setitem: bool = False
|
||||
) -> tuple[Type, set[str]]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def infer_literal_expr_type(self, value: LiteralValue, fallback_name: str) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def analyze_static_reference(
|
||||
self,
|
||||
node: SymbolNode,
|
||||
ctx: Context,
|
||||
is_lvalue: bool,
|
||||
*,
|
||||
include_modules: bool = True,
|
||||
suppress_errors: bool = False,
|
||||
) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@trait
|
||||
class TypeCheckerSharedApi(CheckerPluginInterface):
|
||||
plugin: Plugin
|
||||
module_refs: set[str]
|
||||
scope: CheckerScope
|
||||
checking_missing_await: bool
|
||||
allow_constructor_cache: bool
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def expr_checker(self) -> ExpressionCheckerSharedApi:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def named_type(self, name: str) -> Instance:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def lookup_typeinfo(self, fullname: str) -> TypeInfo:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def lookup_type(self, node: Expression) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def handle_cannot_determine_type(self, name: str, context: Context) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def handle_partial_var_type(
|
||||
self, typ: PartialType, is_lvalue: bool, node: Var, context: Context
|
||||
) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
@overload
|
||||
@abstractmethod
|
||||
def check_subtype(
|
||||
self,
|
||||
subtype: Type,
|
||||
supertype: Type,
|
||||
context: Context,
|
||||
msg: str,
|
||||
subtype_label: str | None = None,
|
||||
supertype_label: str | None = None,
|
||||
*,
|
||||
notes: list[str] | None = None,
|
||||
code: ErrorCode | None = None,
|
||||
outer_context: Context | None = None,
|
||||
) -> bool: ...
|
||||
|
||||
@overload
|
||||
@abstractmethod
|
||||
def check_subtype(
|
||||
self,
|
||||
subtype: Type,
|
||||
supertype: Type,
|
||||
context: Context,
|
||||
msg: ErrorMessage,
|
||||
subtype_label: str | None = None,
|
||||
supertype_label: str | None = None,
|
||||
*,
|
||||
notes: list[str] | None = None,
|
||||
outer_context: Context | None = None,
|
||||
) -> bool: ...
|
||||
|
||||
# Unfortunately, mypyc doesn't support abstract overloads yet.
|
||||
@abstractmethod
|
||||
def check_subtype(
|
||||
self,
|
||||
subtype: Type,
|
||||
supertype: Type,
|
||||
context: Context,
|
||||
msg: str | ErrorMessage,
|
||||
subtype_label: str | None = None,
|
||||
supertype_label: str | None = None,
|
||||
*,
|
||||
notes: list[str] | None = None,
|
||||
code: ErrorCode | None = None,
|
||||
outer_context: Context | None = None,
|
||||
) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def get_final_context(self) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@overload
|
||||
@abstractmethod
|
||||
def conditional_types_with_intersection(
|
||||
self,
|
||||
expr_type: Type,
|
||||
type_ranges: list[TypeRange] | None,
|
||||
ctx: Context,
|
||||
default: None = None,
|
||||
) -> tuple[Type | None, Type | None]: ...
|
||||
|
||||
@overload
|
||||
@abstractmethod
|
||||
def conditional_types_with_intersection(
|
||||
self, expr_type: Type, type_ranges: list[TypeRange] | None, ctx: Context, default: Type
|
||||
) -> tuple[Type, Type]: ...
|
||||
|
||||
# Unfortunately, mypyc doesn't support abstract overloads yet.
|
||||
@abstractmethod
|
||||
def conditional_types_with_intersection(
|
||||
self,
|
||||
expr_type: Type,
|
||||
type_ranges: list[TypeRange] | None,
|
||||
ctx: Context,
|
||||
default: Type | None = None,
|
||||
) -> tuple[Type | None, Type | None]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def narrow_type_by_identity_equality(
|
||||
self,
|
||||
operator: str,
|
||||
operands: list[Expression],
|
||||
operand_types: list[Type],
|
||||
expr_indices: list[int],
|
||||
narrowable_indices: AbstractSet[int],
|
||||
) -> tuple[dict[Expression, Type] | None, dict[Expression, Type] | None]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def check_deprecated(self, node: Node | None, context: Context) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def warn_deprecated(self, node: Node | None, context: Context) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def type_is_iterable(self, type: Type) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def iterable_item_type(
|
||||
self, it: Instance | CallableType | TypeType | Overloaded, context: Context
|
||||
) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
@contextmanager
|
||||
def checking_await_set(self) -> Iterator[None]:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def get_precise_awaitable_type(self, typ: Type, local_errors: ErrorWatcher) -> Type | None:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def add_any_attribute_to_type(self, typ: Type, name: str) -> Type:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def is_defined_in_stub(self, typ: Instance, /) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class CheckerScope:
|
||||
# We keep two stacks combined, to maintain the relative order
|
||||
stack: list[TypeInfo | FuncItem | MypyFile]
|
||||
|
||||
def __init__(self, module: MypyFile) -> None:
|
||||
self.stack = [module]
|
||||
|
||||
def current_function(self) -> FuncItem | None:
|
||||
for e in reversed(self.stack):
|
||||
if isinstance(e, FuncItem):
|
||||
return e
|
||||
return None
|
||||
|
||||
def top_level_function(self) -> FuncItem | None:
|
||||
"""Return top-level non-lambda function."""
|
||||
for e in self.stack:
|
||||
if isinstance(e, FuncItem) and not isinstance(e, LambdaExpr):
|
||||
return e
|
||||
return None
|
||||
|
||||
def active_class(self) -> TypeInfo | None:
|
||||
if isinstance(self.stack[-1], TypeInfo):
|
||||
return self.stack[-1]
|
||||
return None
|
||||
|
||||
def enclosing_class(self, func: FuncItem | None = None) -> TypeInfo | None:
|
||||
"""Is there a class *directly* enclosing this function?"""
|
||||
func = func or self.current_function()
|
||||
assert func, "This method must be called from inside a function"
|
||||
index = self.stack.index(func)
|
||||
assert index, "CheckerScope stack must always start with a module"
|
||||
enclosing = self.stack[index - 1]
|
||||
if isinstance(enclosing, TypeInfo):
|
||||
return enclosing
|
||||
return None
|
||||
|
||||
def active_self_type(self) -> Instance | TupleType | None:
|
||||
"""An instance or tuple type representing the current class.
|
||||
|
||||
This returns None unless we are in class body or in a method.
|
||||
In particular, inside a function nested in method this returns None.
|
||||
"""
|
||||
info = self.active_class()
|
||||
if not info and self.current_function():
|
||||
info = self.enclosing_class()
|
||||
if info:
|
||||
return fill_typevars(info)
|
||||
return None
|
||||
|
||||
def current_self_type(self) -> Instance | TupleType | None:
|
||||
"""Same as active_self_type() but handle functions nested in methods."""
|
||||
for item in reversed(self.stack):
|
||||
if isinstance(item, TypeInfo):
|
||||
return fill_typevars(item)
|
||||
return None
|
||||
|
||||
def is_top_level(self) -> bool:
|
||||
"""Is current scope top-level (no classes or functions)?"""
|
||||
return len(self.stack) == 1
|
||||
|
||||
@contextmanager
|
||||
def push_function(self, item: FuncItem) -> Iterator[None]:
|
||||
self.stack.append(item)
|
||||
yield
|
||||
self.stack.pop()
|
||||
|
||||
@contextmanager
|
||||
def push_class(self, info: TypeInfo) -> Iterator[None]:
|
||||
self.stack.append(info)
|
||||
yield
|
||||
self.stack.pop()
|
||||
Loading…
Add table
Add a link
Reference in a new issue