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
Binary file not shown.
Binary file not shown.
113
venv/lib/python3.11/site-packages/mypyc/lower/int_ops.py
Normal file
113
venv/lib/python3.11/site-packages/mypyc/lower/int_ops.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
"""Convert tagged int primitive ops to lower-level ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import NamedTuple
|
||||
|
||||
from mypyc.ir.ops import Assign, BasicBlock, Branch, ComparisonOp, Register, Value
|
||||
from mypyc.ir.rtypes import bool_rprimitive, is_short_int_rprimitive
|
||||
from mypyc.irbuild.ll_builder import LowLevelIRBuilder
|
||||
from mypyc.lower.registry import lower_primitive_op
|
||||
from mypyc.primitives.int_ops import int_equal_, int_less_than_
|
||||
from mypyc.primitives.registry import CFunctionDescription
|
||||
|
||||
|
||||
# Description for building int comparison ops
|
||||
#
|
||||
# Fields:
|
||||
# binary_op_variant: identify which IntOp to use when operands are short integers
|
||||
# c_func_description: the C function to call when operands are tagged integers
|
||||
# c_func_negated: whether to negate the C function call's result
|
||||
# c_func_swap_operands: whether to swap lhs and rhs when call the function
|
||||
class IntComparisonOpDescription(NamedTuple):
|
||||
binary_op_variant: int
|
||||
c_func_description: CFunctionDescription
|
||||
c_func_negated: bool
|
||||
c_func_swap_operands: bool
|
||||
|
||||
|
||||
# Provide mapping from textual op to short int's op variant and boxed int's description.
|
||||
# Note that these are not complete implementations and require extra IR.
|
||||
int_comparison_op_mapping: dict[str, IntComparisonOpDescription] = {
|
||||
"==": IntComparisonOpDescription(ComparisonOp.EQ, int_equal_, False, False),
|
||||
"!=": IntComparisonOpDescription(ComparisonOp.NEQ, int_equal_, True, False),
|
||||
"<": IntComparisonOpDescription(ComparisonOp.SLT, int_less_than_, False, False),
|
||||
"<=": IntComparisonOpDescription(ComparisonOp.SLE, int_less_than_, True, True),
|
||||
">": IntComparisonOpDescription(ComparisonOp.SGT, int_less_than_, False, True),
|
||||
">=": IntComparisonOpDescription(ComparisonOp.SGE, int_less_than_, True, False),
|
||||
}
|
||||
|
||||
|
||||
def compare_tagged(self: LowLevelIRBuilder, lhs: Value, rhs: Value, op: str, line: int) -> Value:
|
||||
"""Compare two tagged integers using given operator (value context)."""
|
||||
# generate fast binary logic ops on short ints
|
||||
if (is_short_int_rprimitive(lhs.type) or is_short_int_rprimitive(rhs.type)) and op in (
|
||||
"==",
|
||||
"!=",
|
||||
):
|
||||
quick = True
|
||||
else:
|
||||
quick = is_short_int_rprimitive(lhs.type) and is_short_int_rprimitive(rhs.type)
|
||||
if quick:
|
||||
return self.comparison_op(lhs, rhs, int_comparison_op_mapping[op][0], line)
|
||||
op_type, c_func_desc, negate_result, swap_op = int_comparison_op_mapping[op]
|
||||
result = Register(bool_rprimitive)
|
||||
short_int_block, int_block, out = BasicBlock(), BasicBlock(), BasicBlock()
|
||||
check_lhs = self.check_tagged_short_int(lhs, line, negated=True)
|
||||
if op in ("==", "!="):
|
||||
self.add(Branch(check_lhs, int_block, short_int_block, Branch.BOOL))
|
||||
else:
|
||||
# for non-equality logical ops (less/greater than, etc.), need to check both sides
|
||||
short_lhs = BasicBlock()
|
||||
self.add(Branch(check_lhs, int_block, short_lhs, Branch.BOOL))
|
||||
self.activate_block(short_lhs)
|
||||
check_rhs = self.check_tagged_short_int(rhs, line, negated=True)
|
||||
self.add(Branch(check_rhs, int_block, short_int_block, Branch.BOOL))
|
||||
self.activate_block(int_block)
|
||||
if swap_op:
|
||||
args = [rhs, lhs]
|
||||
else:
|
||||
args = [lhs, rhs]
|
||||
call = self.call_c(c_func_desc, args, line)
|
||||
if negate_result:
|
||||
# TODO: introduce UnaryIntOp?
|
||||
call_result = self.unary_op(call, "not", line)
|
||||
else:
|
||||
call_result = call
|
||||
self.add(Assign(result, call_result, line))
|
||||
self.goto(out)
|
||||
self.activate_block(short_int_block)
|
||||
eq = self.comparison_op(lhs, rhs, op_type, line)
|
||||
self.add(Assign(result, eq, line))
|
||||
self.goto_and_activate(out)
|
||||
return result
|
||||
|
||||
|
||||
@lower_primitive_op("int_eq")
|
||||
def lower_int_eq(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
return compare_tagged(builder, args[0], args[1], "==", line)
|
||||
|
||||
|
||||
@lower_primitive_op("int_ne")
|
||||
def lower_int_ne(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
return compare_tagged(builder, args[0], args[1], "!=", line)
|
||||
|
||||
|
||||
@lower_primitive_op("int_lt")
|
||||
def lower_int_lt(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
return compare_tagged(builder, args[0], args[1], "<", line)
|
||||
|
||||
|
||||
@lower_primitive_op("int_le")
|
||||
def lower_int_le(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
return compare_tagged(builder, args[0], args[1], "<=", line)
|
||||
|
||||
|
||||
@lower_primitive_op("int_gt")
|
||||
def lower_int_gt(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
return compare_tagged(builder, args[0], args[1], ">", line)
|
||||
|
||||
|
||||
@lower_primitive_op("int_ge")
|
||||
def lower_int_ge(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
return compare_tagged(builder, args[0], args[1], ">=", line)
|
||||
Binary file not shown.
71
venv/lib/python3.11/site-packages/mypyc/lower/list_ops.py
Normal file
71
venv/lib/python3.11/site-packages/mypyc/lower/list_ops.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from mypyc.common import PLATFORM_SIZE
|
||||
from mypyc.ir.ops import GetElementPtr, Integer, IntOp, SetMem, Value
|
||||
from mypyc.ir.rtypes import (
|
||||
PyListObject,
|
||||
c_pyssize_t_rprimitive,
|
||||
object_rprimitive,
|
||||
pointer_rprimitive,
|
||||
)
|
||||
from mypyc.irbuild.ll_builder import LowLevelIRBuilder
|
||||
from mypyc.lower.registry import lower_primitive_op
|
||||
|
||||
|
||||
@lower_primitive_op("buf_init_item")
|
||||
def buf_init_item(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
"""Initialize an item in a buffer of "PyObject *" values at given index.
|
||||
|
||||
This can be used to initialize the data buffer of a freshly allocated list
|
||||
object.
|
||||
"""
|
||||
base = args[0]
|
||||
index_value = args[1]
|
||||
value = args[2]
|
||||
assert isinstance(index_value, Integer), index_value
|
||||
index = index_value.numeric_value()
|
||||
if index == 0:
|
||||
ptr = base
|
||||
else:
|
||||
ptr = builder.add(
|
||||
IntOp(
|
||||
pointer_rprimitive,
|
||||
base,
|
||||
Integer(index * PLATFORM_SIZE, c_pyssize_t_rprimitive),
|
||||
IntOp.ADD,
|
||||
line,
|
||||
)
|
||||
)
|
||||
return builder.add(SetMem(object_rprimitive, ptr, value, line))
|
||||
|
||||
|
||||
@lower_primitive_op("list_items")
|
||||
def list_items(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
ob_item_ptr = builder.add(GetElementPtr(args[0], PyListObject, "ob_item", line))
|
||||
return builder.load_mem(ob_item_ptr, pointer_rprimitive)
|
||||
|
||||
|
||||
def list_item_ptr(builder: LowLevelIRBuilder, obj: Value, index: Value, line: int) -> Value:
|
||||
"""Get a pointer to a list item (index must be valid and non-negative).
|
||||
|
||||
Type of index must be c_pyssize_t_rprimitive, and obj must refer to a list object.
|
||||
"""
|
||||
# List items are represented as an array of pointers. Pointer to the item obj[index] is
|
||||
# <pointer to first item> + index * <pointer size>.
|
||||
items = list_items(builder, [obj], line)
|
||||
delta = builder.add(
|
||||
IntOp(
|
||||
c_pyssize_t_rprimitive,
|
||||
index,
|
||||
Integer(PLATFORM_SIZE, c_pyssize_t_rprimitive),
|
||||
IntOp.MUL,
|
||||
)
|
||||
)
|
||||
return builder.add(IntOp(pointer_rprimitive, items, delta, IntOp.ADD))
|
||||
|
||||
|
||||
@lower_primitive_op("list_get_item_unsafe")
|
||||
def list_get_item_unsafe(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
index = builder.coerce(args[1], c_pyssize_t_rprimitive, line)
|
||||
item_ptr = list_item_ptr(builder, args[0], index, line)
|
||||
return builder.load_mem(item_ptr, object_rprimitive)
|
||||
Binary file not shown.
20
venv/lib/python3.11/site-packages/mypyc/lower/misc_ops.py
Normal file
20
venv/lib/python3.11/site-packages/mypyc/lower/misc_ops.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ComparisonOp, GetElementPtr, Integer, LoadMem, Value
|
||||
from mypyc.ir.rtypes import PyVarObject, c_pyssize_t_rprimitive, object_rprimitive
|
||||
from mypyc.irbuild.ll_builder import LowLevelIRBuilder
|
||||
from mypyc.lower.registry import lower_primitive_op
|
||||
|
||||
|
||||
@lower_primitive_op("var_object_size")
|
||||
def var_object_size(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
elem_address = builder.add(GetElementPtr(args[0], PyVarObject, "ob_size"))
|
||||
return builder.add(LoadMem(c_pyssize_t_rprimitive, elem_address, line))
|
||||
|
||||
|
||||
@lower_primitive_op("propagate_if_error")
|
||||
def propagate_if_error_op(builder: LowLevelIRBuilder, args: list[Value], line: int) -> Value:
|
||||
# Return False on NULL. The primitive uses ERR_FALSE, so this is an error.
|
||||
return builder.add(
|
||||
ComparisonOp(args[0], Integer(0, object_rprimitive), ComparisonOp.NEQ, line)
|
||||
)
|
||||
Binary file not shown.
29
venv/lib/python3.11/site-packages/mypyc/lower/registry.py
Normal file
29
venv/lib/python3.11/site-packages/mypyc/lower/registry.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from typing import Final, TypeVar
|
||||
|
||||
from mypyc.ir.ops import Value
|
||||
from mypyc.irbuild.ll_builder import LowLevelIRBuilder
|
||||
|
||||
LowerFunc = Callable[[LowLevelIRBuilder, list[Value], int], Value]
|
||||
LowerFuncOpt = Callable[[LowLevelIRBuilder, list[Value], int], Value | None]
|
||||
|
||||
lowering_registry: Final[dict[str, LowerFuncOpt]] = {}
|
||||
|
||||
LF = TypeVar("LF", LowerFunc, LowerFuncOpt)
|
||||
|
||||
|
||||
def lower_primitive_op(name: str) -> Callable[[LF], LF]:
|
||||
"""Register a handler that generates low-level IR for a primitive op."""
|
||||
|
||||
def wrapper(f: LF) -> LF:
|
||||
assert name not in lowering_registry
|
||||
lowering_registry[name] = f
|
||||
return f
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
# Import various modules that set up global state.
|
||||
from mypyc.lower import int_ops, list_ops, misc_ops # noqa: F401
|
||||
Loading…
Add table
Add a link
Reference in a new issue