From 8f7b23176b9454815bc81f870386ce096d1069bd Mon Sep 17 00:00:00 2001 From: Hao Zhang Date: Thu, 12 Mar 2026 10:12:11 +0800 Subject: [PATCH] refactor: add type annotations and clean up code - Add type hints to Python functions and TypeScript modules - Fix variable reference bug in egraph.ts lhs/rhs extraction - Simplify input validation logic in input/load modules - Remove unused imports across modules - Improve database initialization flow in main.ts --- ddss/dump.py | 3 ++- ddss/dump.ts | 8 ++------ ddss/egg.py | 3 ++- ddss/egg.ts | 4 ++-- ddss/egraph.ts | 11 ++++++----- ddss/input.py | 7 +++---- ddss/input.ts | 9 ++++----- ddss/load.py | 7 +++---- ddss/load.ts | 9 ++++----- ddss/main.py | 7 ++++--- ddss/main.ts | 12 ++++++------ ddss/orm.ts | 1 - ddss/output.py | 3 ++- ddss/output.ts | 4 ++-- ddss/search.py | 3 ++- ddss/search.ts | 10 +++++----- ddss/utility.ts | 2 +- 17 files changed, 50 insertions(+), 53 deletions(-) diff --git a/ddss/dump.py b/ddss/dump.py index 58b17cf..38668cb 100644 --- a/ddss/dump.py +++ b/ddss/dump.py @@ -1,10 +1,11 @@ import asyncio from sqlalchemy import select +from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession from apyds_bnf import unparse from .orm import Facts, Ideas -async def main(session): +async def main(session: async_sessionmaker[AsyncSession]) -> None: try: async with session() as sess: for i in await sess.scalars(select(Ideas)): diff --git a/ddss/dump.ts b/ddss/dump.ts index bcb03f6..7bdb762 100644 --- a/ddss/dump.ts +++ b/ddss/dump.ts @@ -1,12 +1,8 @@ import type { Sequelize } from "sequelize"; import { unparse } from "atsds-bnf"; -import { Fact, Idea, initializeDatabase } from "./orm.ts"; - -export async function main(addr: string, sequelize?: Sequelize) { - if (!sequelize) { - sequelize = await initializeDatabase(addr); - } +import { Fact, Idea } from "./orm.ts"; +export async function main(sequelize: Sequelize): Promise { const ideas = await Idea.findAll(); for (const idea of ideas) { console.log("idea:", unparse(idea.data)); diff --git a/ddss/egg.py b/ddss/egg.py index 0c3270c..fa1f6ca 100644 --- a/ddss/egg.py +++ b/ddss/egg.py @@ -1,11 +1,12 @@ import asyncio from sqlalchemy import select +from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession from apyds import Rule from .orm import insert_or_ignore, Facts, Ideas from .egraph import Search -async def main(session): +async def main(session: async_sessionmaker[AsyncSession]) -> None: try: search = Search() pool = [] diff --git a/ddss/egg.ts b/ddss/egg.ts index f31c3cb..90c1788 100644 --- a/ddss/egg.ts +++ b/ddss/egg.ts @@ -1,9 +1,9 @@ import { Op, type Sequelize } from "sequelize"; import { Rule } from "atsds"; import { Search } from "./egraph.ts"; -import { Fact, Idea, initializeDatabase, insertOrIgnore } from "./orm.ts"; +import { Fact, Idea, insertOrIgnore } from "./orm.ts"; -export async function main(sequelize: Sequelize) { +export async function main(sequelize: Sequelize): Promise { const search = new Search(); let pool: Rule[] = []; let maxFact = -1; diff --git a/ddss/egraph.ts b/ddss/egraph.ts index 161558b..cfa61e9 100644 --- a/ddss/egraph.ts +++ b/ddss/egraph.ts @@ -9,15 +9,16 @@ function extractLhsRhsFromRule(data: Rule): [Term, Term] | null { if (data.length() !== 0) { return null; } - const term = data.conclusion(); - const inner = term.term(); - if (!(inner instanceof List)) { + const term = data.conclusion().term(); + if (!(term instanceof List)) { return null; } - if (!(inner.length() === 4 && inner.getitem(0).toString() === "binary" && inner.getitem(1).toString() === "==")) { + if (!(term.length() === 4 && term.getitem(0).toString() === "binary" && term.getitem(1).toString() === "==")) { return null; } - return [inner.getitem(2), inner.getitem(3)]; + const lhs = term.getitem(2); + const rhs = term.getitem(3); + return [lhs, rhs]; } function buildLhsRhsToTerm(lhs: Term, rhs: Term): Term { diff --git a/ddss/input.py b/ddss/input.py index f36a123..543afb0 100644 --- a/ddss/input.py +++ b/ddss/input.py @@ -1,12 +1,13 @@ import asyncio from prompt_toolkit import PromptSession from prompt_toolkit.patch_stdout import patch_stdout +from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession from apyds_bnf import parse from .orm import insert_or_ignore, Facts, Ideas from .utility import str_rule_get_str_idea -async def main(session): +async def main(session: async_sessionmaker[AsyncSession]) -> None: try: prompt = PromptSession() while True: @@ -17,9 +18,7 @@ async def main(session): raise asyncio.CancelledError() data = line.strip() - if data == "": - continue - if data.startswith("//"): + if data == "" or data.startswith("//"): continue try: diff --git a/ddss/input.ts b/ddss/input.ts index 32620d0..bea452f 100644 --- a/ddss/input.ts +++ b/ddss/input.ts @@ -2,10 +2,10 @@ import * as readline from "node:readline/promises"; import { stdin as input, stdout as output } from "node:process"; import type { Sequelize } from "sequelize"; import { parse } from "atsds-bnf"; -import { Fact, Idea, initializeDatabase, insertOrIgnore } from "./orm.ts"; +import { Fact, Idea, insertOrIgnore } from "./orm.ts"; import { patchStdout, strRuleGetStrIdea } from "./utility.ts"; -export async function main(sequelize: Sequelize) { +export async function main(sequelize: Sequelize): Promise { const rl = readline.createInterface({ input, output }); rl.setPrompt("input: "); const unpatch = patchStdout(rl); @@ -21,10 +21,9 @@ export async function main(sequelize: Sequelize) { try { const ds = parse(data); - const dsStr = ds.toString(); - await insertOrIgnore(Fact, dsStr); - const idea = strRuleGetStrIdea(dsStr); + await insertOrIgnore(Fact, ds); + const idea = strRuleGetStrIdea(ds); if (idea) { await insertOrIgnore(Idea, idea); } diff --git a/ddss/load.py b/ddss/load.py index c634fd1..6f784ee 100644 --- a/ddss/load.py +++ b/ddss/load.py @@ -1,18 +1,17 @@ import asyncio import sys +from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession from apyds_bnf import parse from .orm import insert_or_ignore, Facts, Ideas from .utility import str_rule_get_str_idea -async def main(session): +async def main(session: async_sessionmaker[AsyncSession]) -> None: try: async with session() as sess: for line in sys.stdin: data = line.strip() - if data == "": - continue - if data.startswith("//"): + if data == "" or data.startswith("//"): continue try: diff --git a/ddss/load.ts b/ddss/load.ts index 8d982d4..f056cb2 100644 --- a/ddss/load.ts +++ b/ddss/load.ts @@ -2,10 +2,10 @@ import * as readline from "node:readline/promises"; import { stdin as input } from "node:process"; import type { Sequelize } from "sequelize"; import { parse } from "atsds-bnf"; -import { Fact, Idea, initializeDatabase, insertOrIgnore } from "./orm.ts"; +import { Fact, Idea, insertOrIgnore } from "./orm.ts"; import { strRuleGetStrIdea } from "./utility.ts"; -export async function main(sequelize: Sequelize) { +export async function main(sequelize: Sequelize): Promise { const rl = readline.createInterface({ input, terminal: false, @@ -19,10 +19,9 @@ export async function main(sequelize: Sequelize) { try { const ds = parse(data); - const dsStr = ds.toString(); - await insertOrIgnore(Fact, dsStr); - const idea = strRuleGetStrIdea(dsStr); + await insertOrIgnore(Fact, ds); + const idea = strRuleGetStrIdea(ds); if (idea) { await insertOrIgnore(Idea, idea); } diff --git a/ddss/main.py b/ddss/main.py index 21c6b70..d399f2e 100644 --- a/ddss/main.py +++ b/ddss/main.py @@ -1,8 +1,9 @@ import asyncio import tempfile import pathlib -from typing import Annotated, Optional +from typing import Annotated, Optional, Awaitable import tyro +from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession from .orm import initialize_database from .search import main as search from .egg import main as egg @@ -11,7 +12,7 @@ from .load import main as load from .dump import main as dump -component_map = { +component_map: dict[str, callable[[async_sessionmaker[AsyncSession]], Awaitable[None]]] = { "search": search, "egg": egg, "input": input, @@ -29,7 +30,7 @@ async def run(addr: str, components: list[str]) -> None: coroutines = [component_map[component](session) for component in components] except KeyError as e: print(f"error: unsupported component: {str(e)}") - raise asyncio.CancelledError() + return await asyncio.wait( [asyncio.create_task(coro) for coro in coroutines], diff --git a/ddss/main.ts b/ddss/main.ts index e34c19d..ffb001a 100644 --- a/ddss/main.ts +++ b/ddss/main.ts @@ -11,7 +11,7 @@ import { main as load } from "./load.ts"; import { main as output } from "./output.ts"; import { initializeDatabase } from "./orm.ts"; -type ComponentMain = (addr: string, sequelize: Sequelize) => Promise; +type ComponentMain = (sequelize: Sequelize) => Promise; const componentMap: Record = { search, @@ -22,7 +22,9 @@ const componentMap: Record = { dump, }; -async function run(addr: string, components: string[]) { +async function run(addr: string, components: string[]): Promise { + const sequelize = await initializeDatabase(addr); + for (const name of components) { if (!(name in componentMap)) { console.error(`error: unsupported component: ${name}`); @@ -30,11 +32,9 @@ async function run(addr: string, components: string[]) { } } - const sequelize = await initializeDatabase(addr); - const promises = components.map((name) => { const component = componentMap[name]!; - return component(addr, sequelize); + return component(sequelize); }); await Promise.race(promises); @@ -42,7 +42,7 @@ async function run(addr: string, components: string[]) { await sequelize.close(); } -export function cli() { +export async function cli(): Promise { const program = new Command(); program diff --git a/ddss/orm.ts b/ddss/orm.ts index a6777a1..f2016b3 100644 --- a/ddss/orm.ts +++ b/ddss/orm.ts @@ -5,7 +5,6 @@ import { type CreationOptional, type InferAttributes, type InferCreationAttributes, - type ModelStatic, } from "sequelize"; class Fact extends Model, InferCreationAttributes> { diff --git a/ddss/output.py b/ddss/output.py index 4547e93..903642d 100644 --- a/ddss/output.py +++ b/ddss/output.py @@ -1,10 +1,11 @@ import asyncio from sqlalchemy import select +from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession from apyds_bnf import unparse from .orm import Facts, Ideas -async def main(session): +async def main(session: async_sessionmaker[AsyncSession]) -> None: try: max_fact = -1 max_idea = -1 diff --git a/ddss/output.ts b/ddss/output.ts index a308693..df77407 100644 --- a/ddss/output.ts +++ b/ddss/output.ts @@ -1,8 +1,8 @@ import { Op, type Sequelize } from "sequelize"; import { unparse } from "atsds-bnf"; -import { Fact, Idea, initializeDatabase } from "./orm.ts"; +import { Fact, Idea } from "./orm.ts"; -export async function main(sequelize: Sequelize) { +export async function main(sequelize: Sequelize): Promise { let maxFact = -1; let maxIdea = -1; diff --git a/ddss/search.py b/ddss/search.py index 29d1738..3b88475 100644 --- a/ddss/search.py +++ b/ddss/search.py @@ -1,11 +1,12 @@ import asyncio from sqlalchemy import select +from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession from apyds import Search from .orm import insert_or_ignore, Facts, Ideas from .utility import str_rule_get_str_idea -async def main(session): +async def main(session: async_sessionmaker[AsyncSession]) -> None: try: search = Search() max_fact = -1 diff --git a/ddss/search.ts b/ddss/search.ts index 043c223..747a91e 100644 --- a/ddss/search.ts +++ b/ddss/search.ts @@ -1,10 +1,10 @@ import { Op, type Sequelize } from "sequelize"; import { Search } from "atsds"; import type { Rule } from "atsds"; -import { Fact, Idea, initializeDatabase, insertOrIgnore } from "./orm.ts"; +import { Fact, Idea, insertOrIgnore } from "./orm.ts"; import { strRuleGetStrIdea } from "./utility.ts"; -export async function main(sequelize: Sequelize) { +export async function main(sequelize: Sequelize): Promise { const search = new Search(); let maxFact = -1; @@ -21,9 +21,9 @@ export async function main(sequelize: Sequelize) { const tasks: Promise[] = []; const handler = (rule: Rule) => { - const dsStr = rule.toString(); - tasks.push(insertOrIgnore(Fact, dsStr)); - const idea = strRuleGetStrIdea(dsStr); + const ds = rule.toString(); + tasks.push(insertOrIgnore(Fact, ds)); + const idea = strRuleGetStrIdea(ds); if (idea) { tasks.push(insertOrIgnore(Idea, idea)); } diff --git a/ddss/utility.ts b/ddss/utility.ts index 0d9cd18..f5b0283 100644 --- a/ddss/utility.ts +++ b/ddss/utility.ts @@ -10,7 +10,7 @@ export function strRuleGetStrIdea(data: string): string | null { return null; } -export function patchStdout(rl: Interface) { +export function patchStdout(rl: Interface): () => void { const originalWrite = stdout.write; const originalLog = console.log; const originalError = console.error;