kele 0.0.1a2__tar.gz → 0.0.1b1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kele-0.0.1b1/.driftcheck.toml +27 -0
- kele-0.0.1b1/.github/workflows/driftcheck.yml +35 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/.github/workflows/lint.yml +18 -2
- kele-0.0.1b1/.github/workflows/pr_agent.yml +34 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/.github/workflows/release.yml +1 -1
- {kele-0.0.1a2 → kele-0.0.1b1}/.github/workflows/test.yml +15 -6
- kele-0.0.1b1/.pr_agent.toml +13 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/PKG-INFO +11 -2
- {kele-0.0.1a2 → kele-0.0.1b1}/README.md +8 -1
- {kele-0.0.1a2 → kele-0.0.1b1}/README.zh.md +8 -1
- kele-0.0.1b1/assets/cola-icon.svg +129 -0
- kele-0.0.1b1/kele/_version.py +1 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/config.py +6 -1
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/builtin_hooks.py +22 -16
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/callback.py +33 -2
- kele-0.0.1b1/kele/control/grounding_selector/_rule_strategies/_scc_sort_strategy.py +110 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/executer/executing.py +1 -1
- kele-0.0.1b1/kele/grounder/grounded_rule_ds/_nodes/_assertion.py +538 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/_term.py +1 -1
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/_tupletable.py +23 -12
- kele-0.0.1b1/kele/grounder/grounded_rule_ds/grounded_class.py +810 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/rule_check.py +8 -8
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/builtin_base/builtin_operators.py +23 -1
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/main.py +3 -3
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/base_classes.py +65 -31
- kele-0.0.1b1/kele/utils.py +60 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/pyproject.toml +3 -1
- {kele-0.0.1a2 → kele-0.0.1b1}/uv.lock +16 -12
- kele-0.0.1a2/kele/_version.py +0 -1
- kele-0.0.1a2/kele/grounder/grounded_rule_ds/_nodes/_assertion.py +0 -366
- kele-0.0.1a2/kele/grounder/grounded_rule_ds/grounded_class.py +0 -504
- {kele-0.0.1a2 → kele-0.0.1b1}/.gitattributes +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/.github/dependabot.yml +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/.github/workflows/license_check.yml +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/.gitignore +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/.pre-commit-config.yaml +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/.ruff.toml +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/CONTRIBUTING.md +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/Cargo.lock +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/Cargo.toml +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/LICENSE +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/_scripts/ci/examples_static_comment.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/_scripts/ci/run_examples_static_ci.sh +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/hatch_build.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/_utils.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/README_metrics.md +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_rule_strategies/README.md +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_rule_strategies/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_rule_strategies/_sequential_strategy.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_rule_strategies/strategy_protocol.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_selector_utils.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_term_strategies/README.md +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_term_strategies/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_term_strategies/_exhausted_strategy.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/_term_strategies/strategy_protocol.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/rule_selector.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/grounding_selector/term_selector.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/infer_path.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/metrics.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/registry.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/control/status.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/egg_equiv.pyi +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/equality/README.md +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/equality/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/equality/_egg_equiv/src/lib.rs +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/equality/_equiv_elem.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/equality/_utils.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/equality/equivalence.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/executer/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/README.md +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/_conn.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/_op.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/_root.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/_rule.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/_tftable.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/_nodes/_typing_polars.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounded_rule_ds/grounded_ds_utils.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/grounder/grounding.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/README.md +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/builtin_base/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/builtin_base/builtin_concepts.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/builtin_base/builtin_facts.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/builtin_base/builtin_rules.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/fact_base.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/ontology_base.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/knowledge_bases/rule_base.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/py.typed +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/CONCEPT_README.md +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/__init__.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/_cnf_converter.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/_sat_solver.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/connectives.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/dnf_converter.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/external.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/sub_concept.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/kele/syntax/syntacticsugar.py +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/licensecheck.json +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/mypy.ini +0 -0
- {kele-0.0.1a2 → kele-0.0.1b1}/pytest.ini +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[general]
|
|
2
|
+
enabled = true
|
|
3
|
+
allow_push_on_error = false
|
|
4
|
+
|
|
5
|
+
[docs]
|
|
6
|
+
paths = [
|
|
7
|
+
"README.md",
|
|
8
|
+
"docs/tutorial/zh/**",
|
|
9
|
+
"docs/tutorial/en/**",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[llm]
|
|
13
|
+
base_url = "https://integrate.api.nvidia.com/v1"
|
|
14
|
+
model = "z-ai/glm4.7"
|
|
15
|
+
timeout = 300
|
|
16
|
+
max_retries = 2
|
|
17
|
+
|
|
18
|
+
[tui]
|
|
19
|
+
theme = "default"
|
|
20
|
+
auto_apply = false
|
|
21
|
+
|
|
22
|
+
[cache]
|
|
23
|
+
enabled = true
|
|
24
|
+
dir = ".git/driftcheck_cache"
|
|
25
|
+
ttl = 3600
|
|
26
|
+
|
|
27
|
+
[prompts]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Documentation Check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
driftcheck:
|
|
9
|
+
if: ${{ vars.SUPPRESS_LLM_ACTIONS != 'true' }}
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v6
|
|
13
|
+
with:
|
|
14
|
+
fetch-depth: 0
|
|
15
|
+
|
|
16
|
+
# Optional: checkout tutorial repo into workspace (e.g. docs/tutorial/)
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
with:
|
|
19
|
+
repository: msg-bq/msg-bq.github.io
|
|
20
|
+
path: docs/tutorial
|
|
21
|
+
fetch-depth: 1
|
|
22
|
+
|
|
23
|
+
- name: Install ripgrep
|
|
24
|
+
run: sudo apt-get update && sudo apt-get install -y ripgrep
|
|
25
|
+
|
|
26
|
+
- name: Install driftcheck
|
|
27
|
+
run: |
|
|
28
|
+
curl -L https://github.com/deichrenner/driftcheck/releases/latest/download/driftcheck-linux-x86_64 -o driftcheck
|
|
29
|
+
chmod +x driftcheck
|
|
30
|
+
sudo mv driftcheck /usr/local/bin/
|
|
31
|
+
|
|
32
|
+
- name: Check documentation drift
|
|
33
|
+
env:
|
|
34
|
+
DRIFTCHECK_API_KEY: ${{ secrets.DRIFTCHECK_API_KEY }}
|
|
35
|
+
run: driftcheck check --range origin/${{ github.base_ref }}..HEAD --no-tui
|
|
@@ -31,6 +31,22 @@ jobs:
|
|
|
31
31
|
python-version: 3.13
|
|
32
32
|
enable-cache: true
|
|
33
33
|
- name: Install ruff
|
|
34
|
-
run: uv sync --group ruff
|
|
34
|
+
run: uv sync --only-group ruff
|
|
35
35
|
- name: Run ruff
|
|
36
|
-
run: uv run ruff check
|
|
36
|
+
run: uv run --no-sync ruff check
|
|
37
|
+
|
|
38
|
+
pydoclint:
|
|
39
|
+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
steps:
|
|
42
|
+
- name: Checkout
|
|
43
|
+
uses: actions/checkout@v6
|
|
44
|
+
- name: Install uv
|
|
45
|
+
uses: astral-sh/setup-uv@v7
|
|
46
|
+
with:
|
|
47
|
+
python-version: 3.13
|
|
48
|
+
enable-cache: true
|
|
49
|
+
- name: Install pydoclint
|
|
50
|
+
run: uv sync --only-group pydoclint
|
|
51
|
+
- name: Run pydoclint (Sphinx/reST docstrings)
|
|
52
|
+
run: uv run --no-sync flake8 kele
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: PR Agent
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, reopened, ready_for_review, synchronize]
|
|
6
|
+
issue_comment:
|
|
7
|
+
types: [created]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
pr_agent_job:
|
|
12
|
+
if: ${{ vars.SUPPRESS_LLM_ACTIONS != 'true' && github.event.sender.type != 'Bot' && (github.event_name != 'issue_comment' || github.event.issue.pull_request) }}
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
issues: write
|
|
16
|
+
pull-requests: write
|
|
17
|
+
contents: write
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
- name: PR Agent action step
|
|
22
|
+
uses: qodo-ai/pr-agent@main
|
|
23
|
+
env:
|
|
24
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
25
|
+
NVIDIA_NIM_API_KEY: ${{ secrets.QODO_API_KEY }}
|
|
26
|
+
NVIDIA_NIM_API_BASE: https://integrate.api.nvidia.com/v1/
|
|
27
|
+
config.model: "nvidia_nim/moonshotai/kimi-k2.5"
|
|
28
|
+
config.fallback_models: '["nvidia_nim/moonshotai/kimi-k2.5"]'
|
|
29
|
+
config.custom_model_max_tokens: "128000"
|
|
30
|
+
config.ai_timeout: "600"
|
|
31
|
+
github_action_config.auto_review: "true"
|
|
32
|
+
github_action_config.auto_describe: "false"
|
|
33
|
+
github_action_config.auto_improve: "true"
|
|
34
|
+
github_action_config.pr_actions: '["opened","reopened","ready_for_review","review_requested","synchronize"]'
|
|
@@ -15,7 +15,7 @@ permissions:
|
|
|
15
15
|
|
|
16
16
|
concurrency:
|
|
17
17
|
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number || github.ref }}
|
|
18
|
-
cancel-in-progress: ${{ vars.CANCEL_IN_PROGRESS == 'true' }}
|
|
18
|
+
cancel-in-progress: ${{ vars.CANCEL_IN_PROGRESS == 'true' && !(github.event_name == 'push' && github.ref == 'refs/heads/main') }}
|
|
19
19
|
|
|
20
20
|
jobs:
|
|
21
21
|
precheck:
|
|
@@ -210,14 +210,14 @@ jobs:
|
|
|
210
210
|
run: uv run maturin develop --skip-install
|
|
211
211
|
|
|
212
212
|
- name: Run examples static (current)
|
|
213
|
-
working-directory:
|
|
213
|
+
working-directory: curr
|
|
214
214
|
timeout-minutes: 3
|
|
215
215
|
id: curr_static
|
|
216
216
|
continue-on-error: true
|
|
217
217
|
shell: bash
|
|
218
218
|
run: |
|
|
219
219
|
set +e
|
|
220
|
-
bash
|
|
220
|
+
bash _scripts/ci/run_examples_static_ci.sh . curr_static.log
|
|
221
221
|
code=$?
|
|
222
222
|
set -e
|
|
223
223
|
echo "exit_code=$code" >> "$GITHUB_OUTPUT"
|
|
@@ -232,15 +232,14 @@ jobs:
|
|
|
232
232
|
run: uv run maturin develop --skip-install
|
|
233
233
|
|
|
234
234
|
- name: Run examples static (base/main)
|
|
235
|
-
working-directory:
|
|
235
|
+
working-directory: base
|
|
236
236
|
timeout-minutes: 3
|
|
237
237
|
id: base_static
|
|
238
238
|
continue-on-error: true
|
|
239
239
|
shell: bash
|
|
240
|
-
# HACK: 等主线有了之后,run这里目录换base,然后就可以设置工作路径了
|
|
241
240
|
run: |
|
|
242
241
|
set +e
|
|
243
|
-
bash
|
|
242
|
+
bash _scripts/ci/run_examples_static_ci.sh . base_static.log
|
|
244
243
|
code=$?
|
|
245
244
|
set -e
|
|
246
245
|
echo "exit_code=$code" >> "$GITHUB_OUTPUT"
|
|
@@ -300,3 +299,13 @@ jobs:
|
|
|
300
299
|
comment-id: ${{ steps.fc.outputs.comment-id }}
|
|
301
300
|
body-path: pr_comment.md
|
|
302
301
|
edit-mode: replace
|
|
302
|
+
|
|
303
|
+
- name: Fail if current examples static failed
|
|
304
|
+
if: ${{ always() && steps.curr_static.outputs.exit_code != '' && steps.curr_static.outputs.exit_code != '0' }}
|
|
305
|
+
shell: bash
|
|
306
|
+
run: |
|
|
307
|
+
curr_exit="${{ steps.curr_static.outputs.exit_code }}"
|
|
308
|
+
if [ "$curr_exit" != "0" ]; then
|
|
309
|
+
echo "Current examples static failed with exit code $curr_exit"
|
|
310
|
+
exit "$curr_exit"
|
|
311
|
+
fi
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[config]
|
|
2
|
+
model = "nvidia_nim/moonshotai/kimi-k2.5"
|
|
3
|
+
fallback_models = ["nvidia_nim/moonshotai/kimi-k2.5"]
|
|
4
|
+
custom_model_max_tokens = 128000
|
|
5
|
+
ai_timeout = 600
|
|
6
|
+
|
|
7
|
+
[github_action_config]
|
|
8
|
+
auto_review = true
|
|
9
|
+
auto_describe = false
|
|
10
|
+
auto_improve = true
|
|
11
|
+
|
|
12
|
+
[nvidia_nim]
|
|
13
|
+
api_base = "https://integrate.api.nvidia.com/v1/"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kele
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1b1
|
|
4
4
|
Summary: Knowledge Equations based Logic Engine, a forward chaining inference engine with Assertional Logic
|
|
5
5
|
Author: Bingqian Li, BoYang Zhang, Weiming Hong, Hao Zhang, Yi Zhou
|
|
6
6
|
Maintainer-email: Bingqian Li <libq2022@alumni.shanghaitech.edu.cn>, Yi Zhou <yi_zhou@ustc.edu.cn>
|
|
@@ -11,8 +11,10 @@ Requires-Dist: bidict<1.0,>=0.23
|
|
|
11
11
|
Requires-Dist: dacite<2.0,>=1.9
|
|
12
12
|
Requires-Dist: graphviz==0.20.3
|
|
13
13
|
Requires-Dist: lark<2.0,>=1.0
|
|
14
|
+
Requires-Dist: mpmath<2.0,>=1.3
|
|
14
15
|
Requires-Dist: networkx<4.0,>=3.5
|
|
15
16
|
Requires-Dist: numpy>=2.3.3
|
|
17
|
+
Requires-Dist: pathspec<2.0,>=1.0.4
|
|
16
18
|
Requires-Dist: polars>=1.32
|
|
17
19
|
Requires-Dist: prometheus-client>=0.22
|
|
18
20
|
Requires-Dist: psutil>=7.0
|
|
@@ -29,6 +31,10 @@ Description-Content-Type: text/markdown
|
|
|
29
31
|
|
|
30
32
|
[English](README.md) | [中文](README.zh.md)
|
|
31
33
|
|
|
34
|
+
<p align="center">
|
|
35
|
+
<img src="assets/cola-icon.svg" alt="Cola icon" width="120" />
|
|
36
|
+
</p>
|
|
37
|
+
|
|
32
38
|
<!-- Badges: If services are not configured, badges may show unknown/404; enable as needed. -->
|
|
33
39
|
[](LICENSE)
|
|
34
40
|
[](https://github.com/USTC-KnowledgeComputingLab/KELE/actions/workflows/release.yml)
|
|
@@ -52,7 +58,6 @@ It supports **term-level facts**, **nested terms**, **equivalence axioms**, and
|
|
|
52
58
|
- **Equivalence axioms**: convenient equivalence expressions with internal maintenance
|
|
53
59
|
- **Nested compound terms**: operators can nest to build complex structures
|
|
54
60
|
- **Implement functions for operators**: implement functions for operators (e.g., arithmetic, equation solving)
|
|
55
|
-
- **Built-in hook enabler**: enable built-in hooks for inspection/debugging via `BuiltinHookEnabler`
|
|
56
61
|
|
|
57
62
|
> Implement functions for operators ≈ Prolog meta-predicates / ASP HEX external predicates (not identical semantics, similar usage).
|
|
58
63
|
|
|
@@ -160,6 +165,10 @@ KELE exposes a top-level `register` hub so you can customize internal strategies
|
|
|
160
165
|
* Each task registry supports `register(name)` as a decorator plus `get(name)` helpers.
|
|
161
166
|
* Additional registries may be introduced in the future; today only rule/term selectors are supported.
|
|
162
167
|
|
|
168
|
+
### 🪝 Builtin hooks
|
|
169
|
+
|
|
170
|
+
BuiltinHook provides built-in hook points for inspection/debugging; enable them with the `BuiltinHookEnabler` switch. Other hook utilities (such as `HookMixin` and `CallBack`) are still under development.
|
|
171
|
+
|
|
163
172
|
### 🗺️ Roadmap
|
|
164
173
|
|
|
165
174
|
WIP
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | [中文](README.zh.md)
|
|
4
4
|
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="assets/cola-icon.svg" alt="Cola icon" width="120" />
|
|
7
|
+
</p>
|
|
8
|
+
|
|
5
9
|
<!-- Badges: If services are not configured, badges may show unknown/404; enable as needed. -->
|
|
6
10
|
[](LICENSE)
|
|
7
11
|
[](https://github.com/USTC-KnowledgeComputingLab/KELE/actions/workflows/release.yml)
|
|
@@ -25,7 +29,6 @@ It supports **term-level facts**, **nested terms**, **equivalence axioms**, and
|
|
|
25
29
|
- **Equivalence axioms**: convenient equivalence expressions with internal maintenance
|
|
26
30
|
- **Nested compound terms**: operators can nest to build complex structures
|
|
27
31
|
- **Implement functions for operators**: implement functions for operators (e.g., arithmetic, equation solving)
|
|
28
|
-
- **Built-in hook enabler**: enable built-in hooks for inspection/debugging via `BuiltinHookEnabler`
|
|
29
32
|
|
|
30
33
|
> Implement functions for operators ≈ Prolog meta-predicates / ASP HEX external predicates (not identical semantics, similar usage).
|
|
31
34
|
|
|
@@ -133,6 +136,10 @@ KELE exposes a top-level `register` hub so you can customize internal strategies
|
|
|
133
136
|
* Each task registry supports `register(name)` as a decorator plus `get(name)` helpers.
|
|
134
137
|
* Additional registries may be introduced in the future; today only rule/term selectors are supported.
|
|
135
138
|
|
|
139
|
+
### 🪝 Builtin hooks
|
|
140
|
+
|
|
141
|
+
BuiltinHook provides built-in hook points for inspection/debugging; enable them with the `BuiltinHookEnabler` switch. Other hook utilities (such as `HookMixin` and `CallBack`) are still under development.
|
|
142
|
+
|
|
136
143
|
### 🗺️ Roadmap
|
|
137
144
|
|
|
138
145
|
WIP
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
[中文](README.zh.md) | [English](README.md)
|
|
4
4
|
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="assets/cola-icon.svg" alt="Cola icon" width="120" />
|
|
7
|
+
</p>
|
|
8
|
+
|
|
5
9
|
<!-- Badges: If services are not configured, badges may show unknown/404; enable as needed. -->
|
|
6
10
|
[](LICENSE)
|
|
7
11
|
[](https://github.com/USTC-KnowledgeComputingLab/KELE/actions/workflows/release.yml)
|
|
@@ -25,7 +29,6 @@ KELE 是基于[断言逻辑](https://link.springer.com/chapter/10.1007/978-3-319
|
|
|
25
29
|
- **等词公理**:便捷表达等价关系,引擎内部自行维护
|
|
26
30
|
- **可嵌套复合项**:允许嵌套项,算子可互相嵌套构成更复杂的复合结构
|
|
27
31
|
- **算子的外部实现**:支持使用函数对算子进行自定义“实现”,如加法、解方程等
|
|
28
|
-
- **内置 hook 启用器**:通过 `BuiltinHookEnabler` 启用内置 hooks 用于检查/调试
|
|
29
32
|
|
|
30
33
|
> 外部实现 ≈ Prolog 元谓词 / ASP 中 HEX external predicate(语义不完全相同,但使用体验相近)。
|
|
31
34
|
|
|
@@ -127,6 +130,10 @@ KELE 暴露了顶层 `register` 入口,用于自定义内部策略(如 term
|
|
|
127
130
|
* 每个任务注册表支持 `register(name)` 装饰器与 `available()` 查看已注册策略。
|
|
128
131
|
* 目前仅支持规则/项选择器,后续可能会增加更多注册点。
|
|
129
132
|
|
|
133
|
+
### 🪝 Builtin hooks
|
|
134
|
+
|
|
135
|
+
BuiltinHook 提供内置的 hook 点用于检查/调试,可通过 `BuiltinHookEnabler` 开关启用。其他 hook(如 `HookMixin`、`CallBack`)仍在开发中。
|
|
136
|
+
|
|
130
137
|
### 🗺️ Roadmap
|
|
131
138
|
|
|
132
139
|
WIP
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<svg width="256" height="256" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Polished Soda Cup Icon">
|
|
2
|
+
<defs>
|
|
3
|
+
<!-- Background Card Gradient -->
|
|
4
|
+
<linearGradient id="bgGradNew" x1="32" y1="16" x2="224" y2="240" gradientUnits="userSpaceOnUse">
|
|
5
|
+
<stop offset="0" stop-color="#FFF5E5"/>
|
|
6
|
+
<stop offset="1" stop-color="#FFE0B2"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
|
|
9
|
+
<!-- Deep Plastic Lid Gradient -->
|
|
10
|
+
<linearGradient id="lidGradNew" x1="140" y1="56" x2="140" y2="86" gradientUnits="userSpaceOnUse">
|
|
11
|
+
<stop offset="0" stop-color="#FFEDD5"/>
|
|
12
|
+
<stop offset="0.5" stop-color="#FFD1A3"/>
|
|
13
|
+
<stop offset="1" stop-color="#FFB87A"/>
|
|
14
|
+
</linearGradient>
|
|
15
|
+
|
|
16
|
+
<!-- Rich Cup Body Gradient (Generic Red/Orange) -->
|
|
17
|
+
<linearGradient id="cupGradNew" x1="90" y1="100" x2="190" y2="200" gradientUnits="userSpaceOnUse">
|
|
18
|
+
<stop offset="0" stop-color="#FF7F50"/> <!-- Coral Red -->
|
|
19
|
+
<stop offset="0.6" stop-color="#E04020"/> <!-- Deep Red Orange -->
|
|
20
|
+
<stop offset="1" stop-color="#B82E14"/> <!-- Darker shadow red -->
|
|
21
|
+
</linearGradient>
|
|
22
|
+
|
|
23
|
+
<!-- Syrupy Cola Liquid Gradient -->
|
|
24
|
+
<linearGradient id="colaGradNew" x1="140" y1="120" x2="140" y2="200" gradientUnits="userSpaceOnUse">
|
|
25
|
+
<stop offset="0" stop-color="#9C5A1F"/>
|
|
26
|
+
<stop offset="0.7" stop-color="#63310B"/>
|
|
27
|
+
<stop offset="1" stop-color="#421C05"/>
|
|
28
|
+
</linearGradient>
|
|
29
|
+
|
|
30
|
+
<!-- Translucent Straw Gradient -->
|
|
31
|
+
<linearGradient id="strawGradNew" x1="150" y1="40" x2="170" y2="80" gradientUnits="userSpaceOnUse">
|
|
32
|
+
<stop offset="0" stop-color="#FFF0B3"/>
|
|
33
|
+
<stop offset="1" stop-color="#FFC72E"/>
|
|
34
|
+
</linearGradient>
|
|
35
|
+
|
|
36
|
+
<!-- Sharp Glossy Highlight for Plastic -->
|
|
37
|
+
<linearGradient id="glossHighlight" x1="100" y1="90" x2="115" y2="220" gradientUnits="userSpaceOnUse">
|
|
38
|
+
<stop offset="0" stop-color="#FFFFFF" stop-opacity="0.7"/>
|
|
39
|
+
<stop offset="1" stop-color="#FFFFFF" stop-opacity="0.1"/>
|
|
40
|
+
</linearGradient>
|
|
41
|
+
|
|
42
|
+
<!-- Bubble Gradient -->
|
|
43
|
+
<radialGradient id="bubbleGrad" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(0.5 0.5) scale(0.5)">
|
|
44
|
+
<stop stop-color="white" stop-opacity="0.8"/>
|
|
45
|
+
<stop offset="1" stop-color="white" stop-opacity="0.2"/>
|
|
46
|
+
</radialGradient>
|
|
47
|
+
|
|
48
|
+
<!-- Improved Soft Shadow -->
|
|
49
|
+
<filter id="softShadowNew" x="-40%" y="-40%" width="180%" height="180%">
|
|
50
|
+
<feDropShadow dx="0" dy="8" stdDeviation="10" flood-color="#421C05" flood-opacity="0.25"/>
|
|
51
|
+
</filter>
|
|
52
|
+
|
|
53
|
+
<!-- Inner shadow for depth under the lid -->
|
|
54
|
+
<filter id="rimShadow">
|
|
55
|
+
<feOffset dy="4" dx="0"/>
|
|
56
|
+
<feGaussianBlur stdDeviation="3" result="offset-blur"/>
|
|
57
|
+
<feComposite operator="out" in="SourceGraphic" in2="offset-blur" result="inverse"/>
|
|
58
|
+
<feFlood flood-color="black" flood-opacity="0.3" result="color"/>
|
|
59
|
+
<feComposite operator="in" in="color" in2="inverse" result="shadow"/>
|
|
60
|
+
<feComposite operator="over" in="shadow" in2="SourceGraphic"/>
|
|
61
|
+
</filter>
|
|
62
|
+
|
|
63
|
+
<!-- Clip path for liquid and bubbles -->
|
|
64
|
+
<clipPath id="liquidClip">
|
|
65
|
+
<path d="M112 122 Q 140 118, 168 122 L159.8 188.5C159.2 193.2 155.2 196.8 150.5 196.8H129.5C124.8 196.8 120.8 193.2 120.2 188.5L112 122Z"/>
|
|
66
|
+
</clipPath>
|
|
67
|
+
</defs>
|
|
68
|
+
|
|
69
|
+
<!-- Background Card -->
|
|
70
|
+
<rect width="256" height="256" rx="48" fill="url(#bgGradNew)"/>
|
|
71
|
+
|
|
72
|
+
<!-- Main Icon Group with Shadow -->
|
|
73
|
+
<g filter="url(#softShadowNew)">
|
|
74
|
+
|
|
75
|
+
<!-- Straw (Back part) -->
|
|
76
|
+
<path d="M166 42 L150 86" stroke="url(#strawGradNew)" stroke-width="14" stroke-linecap="round"/>
|
|
77
|
+
<path d="M166 42 L150 86" stroke="#C49000" stroke-opacity="0.3" stroke-width="2" fill="none"/>
|
|
78
|
+
|
|
79
|
+
<!-- Cup Body -->
|
|
80
|
+
<g>
|
|
81
|
+
<!-- Main Body Shape -->
|
|
82
|
+
<path d="M88 88H192L176.6 208.8C175.5 217.2 168.4 224 160 224H120C111.6 224 104.5 217.2 103.4 208.8L88 88Z"
|
|
83
|
+
fill="url(#cupGradNew)"/>
|
|
84
|
+
|
|
85
|
+
<!-- Subtle rim shadow at the top of the cup -->
|
|
86
|
+
<path d="M88 88H192V94C192 94 170 98 140 98C110 98 88 94 88 94V88Z" fill="#000000" opacity="0.15"/>
|
|
87
|
+
|
|
88
|
+
<!-- Liquid Inside (Cola) -->
|
|
89
|
+
<g clip-path="url(#liquidClip)">
|
|
90
|
+
<rect x="100" y="115" width="80" height="90" fill="url(#colaGradNew)"/>
|
|
91
|
+
|
|
92
|
+
<!-- Fizz Bubbles Group -->
|
|
93
|
+
<g fill="url(#bubbleGrad)">
|
|
94
|
+
<!-- Small fizz -->
|
|
95
|
+
<circle cx="120" cy="180" r="2"/>
|
|
96
|
+
<circle cx="135" cy="190" r="1.5"/>
|
|
97
|
+
<circle cx="155" cy="175" r="2.5"/>
|
|
98
|
+
<circle cx="140" cy="160" r="1"/>
|
|
99
|
+
<!-- Medium bubbles -->
|
|
100
|
+
<circle cx="128" cy="150" r="4" opacity="0.7"/>
|
|
101
|
+
<circle cx="148" cy="165" r="3.5" opacity="0.8"/>
|
|
102
|
+
<!-- Larger bubbles near surface -->
|
|
103
|
+
<circle cx="135" cy="135" r="5.5" opacity="0.9"/>
|
|
104
|
+
<circle cx="158" cy="142" r="4.5" opacity="0.85"/>
|
|
105
|
+
</g>
|
|
106
|
+
</g>
|
|
107
|
+
<!-- Liquid Top Surface Line (Meniscus) -->
|
|
108
|
+
<path d="M112 122 Q 140 118, 168 122" stroke="#FFFFFF" stroke-opacity="0.4" stroke-width="2" fill="none" stroke-linecap="round"/>
|
|
109
|
+
|
|
110
|
+
<!-- Sharp Glossy Highlight on Cup Body -->
|
|
111
|
+
<path d="M102 92 C 108 130, 106 190, 112 220 L 122 220 C 116 190, 118 130, 112 92 Z" fill="url(#glossHighlight)" opacity="0.8"/>
|
|
112
|
+
</g>
|
|
113
|
+
|
|
114
|
+
<!-- Lid -->
|
|
115
|
+
<g>
|
|
116
|
+
<path d="M96 72C96 63.1634 103.163 56 112 56H168C176.837 56 184 63.1634 184 72V84C184 86.2 182.2 88 180 88H100C97.8 88 96 86.2 96 84V72Z"
|
|
117
|
+
fill="url(#lidGradNew)"/>
|
|
118
|
+
<!-- Sharp Rim Highlight -->
|
|
119
|
+
<path d="M98 86 H182" stroke="#FFFFFF" stroke-opacity="0.8" stroke-width="2" stroke-linecap="round"/>
|
|
120
|
+
<!-- Top Dome Highlight -->
|
|
121
|
+
<ellipse cx="140" cy="62" rx="30" ry="4" fill="white" opacity="0.3"/>
|
|
122
|
+
</g>
|
|
123
|
+
|
|
124
|
+
<!-- Straw (Top emerging part) -->
|
|
125
|
+
<path d="M162 54 L174 20" stroke="url(#strawGradNew)" stroke-width="14" stroke-linecap="round"/>
|
|
126
|
+
<path d="M162 54 L174 20" stroke="white" stroke-opacity="0.4" stroke-width="4" fill="none" stroke-linecap="round" transform="translate(-3, 0)"/>
|
|
127
|
+
|
|
128
|
+
</g>
|
|
129
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "0.0.1b1"
|
|
@@ -50,7 +50,12 @@ class InferenceStrategyConfig:
|
|
|
50
50
|
select_rules_num: int | Literal[-1] = -1 # Number of rules to select.
|
|
51
51
|
select_facts_num: int | Literal[-1] = -1 # Number of facts to select; -1 means all facts.
|
|
52
52
|
# premise_selection_strategy: Literal[''] = '' # Premise selection algorithm. TODO: Unused.
|
|
53
|
-
grounding_rule_strategy: Literal[
|
|
53
|
+
grounding_rule_strategy: Literal[
|
|
54
|
+
'SequentialCyclic',
|
|
55
|
+
'SequentialCyclicWithPriority',
|
|
56
|
+
'SccSort',
|
|
57
|
+
'ReverseSccSort'
|
|
58
|
+
] = "SequentialCyclic" # Rule selection strategy in grounding.
|
|
54
59
|
# executing_sort_strategy: Literal[''] = '' # Execution order strategy. TODO: Unused.
|
|
55
60
|
grounding_term_strategy: Literal['Exhausted'] = "Exhausted" # Term selection strategy in grounding.
|
|
56
61
|
question_rule_interval: int = 1 # Insert a question rule every N rules; -1 uses total rule count as the interval.
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING, Protocol
|
|
5
|
+
|
|
6
|
+
from kele.utils import format_mapping
|
|
5
7
|
|
|
6
8
|
if TYPE_CHECKING:
|
|
7
9
|
from collections.abc import Callable, Mapping
|
|
8
10
|
|
|
9
|
-
from kele.grounder import GroundedRule
|
|
10
11
|
from kele.grounder.grounded_rule_ds._nodes import _AssertionNode
|
|
11
|
-
from kele.syntax import CompoundTerm, Constant, Rule, Variable
|
|
12
|
+
from kele.syntax import CompoundTerm, Constant, Rule, Variable, Assertion
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
14
15
|
|
|
15
16
|
|
|
17
|
+
class AssertionCheckHookMatch(Protocol):
|
|
18
|
+
"""the protocol of output func (on_match in register_assertion_check_hook) in assertion check hook"""
|
|
19
|
+
def __call__(self, rule: Rule, assertion: Assertion, combination: dict[Variable, Constant | CompoundTerm], *, result: bool) \
|
|
20
|
+
-> None: ... # noqa: D102
|
|
21
|
+
|
|
22
|
+
|
|
16
23
|
def register_assertion_check_hook(
|
|
17
|
-
grounded_rule: GroundedRule,
|
|
18
24
|
*,
|
|
19
25
|
rule_name: str | None = None,
|
|
20
26
|
vars_filter: Mapping[str, str] | None = None,
|
|
21
|
-
on_match:
|
|
27
|
+
on_match: AssertionCheckHookMatch | None = None,
|
|
22
28
|
break_on_match: bool = False,
|
|
23
29
|
) -> None:
|
|
24
30
|
"""
|
|
@@ -33,7 +39,6 @@ def register_assertion_check_hook(
|
|
|
33
39
|
print(rule.name, assertion.content, combination, result)
|
|
34
40
|
|
|
35
41
|
register_assertion_check_hook(
|
|
36
|
-
grounded_rule,
|
|
37
42
|
rule_name="rule_3",
|
|
38
43
|
vars_filter={"p1": "f", "p2": "a", "p13": "b", "p14": "c"},
|
|
39
44
|
on_match=log_match,
|
|
@@ -55,7 +60,7 @@ def register_assertion_check_hook(
|
|
|
55
60
|
combination_str = {str(k): str(v) for k, v in combination.items()}
|
|
56
61
|
if normalized_vars_filter:
|
|
57
62
|
for key, value in normalized_vars_filter.items():
|
|
58
|
-
if combination_str.get(key) != value:
|
|
63
|
+
if combination_str.get(key) != str(value):
|
|
59
64
|
return
|
|
60
65
|
|
|
61
66
|
if on_match is None:
|
|
@@ -63,16 +68,18 @@ def register_assertion_check_hook(
|
|
|
63
68
|
"Assertion check hook: rule=%s content=%s combination=%s result=%s",
|
|
64
69
|
rule,
|
|
65
70
|
assertion.content,
|
|
66
|
-
combination_str,
|
|
71
|
+
format_mapping(combination_str),
|
|
67
72
|
result,
|
|
68
73
|
)
|
|
69
74
|
else:
|
|
70
|
-
on_match(rule, assertion, combination, result)
|
|
75
|
+
on_match(rule, assertion.content, combination, result=result)
|
|
71
76
|
|
|
72
77
|
if break_on_match:
|
|
73
78
|
breakpoint() # noqa: T100
|
|
74
79
|
|
|
75
|
-
|
|
80
|
+
from kele.grounder import GroundedRule # noqa: PLC0415
|
|
81
|
+
|
|
82
|
+
GroundedRule.register_class_hook("assertion_check", _hook)
|
|
76
83
|
|
|
77
84
|
|
|
78
85
|
class BuiltinHookEnabler:
|
|
@@ -80,12 +87,11 @@ class BuiltinHookEnabler:
|
|
|
80
87
|
Enabler for built-in hooks by name.
|
|
81
88
|
|
|
82
89
|
This class does not register hooks by itself. Create an instance and call
|
|
83
|
-
``enable`` to attach a built-in hook to
|
|
90
|
+
``enable`` to attach a built-in hook to every grounded rule instance.
|
|
84
91
|
|
|
85
92
|
Example:
|
|
86
93
|
hooks = BuiltinHookEnabler()
|
|
87
94
|
hooks.enable(
|
|
88
|
-
grounded_rule,
|
|
89
95
|
"assertion_check",
|
|
90
96
|
rule_name="rule_3",
|
|
91
97
|
vars_filter={"p1": "f"},
|
|
@@ -103,17 +109,17 @@ class BuiltinHookEnabler:
|
|
|
103
109
|
"""
|
|
104
110
|
return sorted(self._hooks)
|
|
105
111
|
|
|
106
|
-
def enable(self,
|
|
112
|
+
def enable(self, name: str, **kwargs: object) -> None:
|
|
107
113
|
"""
|
|
108
114
|
Enable a built-in hook by name.
|
|
109
115
|
"""
|
|
110
116
|
if name not in self._hooks:
|
|
111
117
|
raise KeyError(f"Unknown built-in hook: {name}")
|
|
112
|
-
self._hooks[name](
|
|
118
|
+
self._hooks[name](**kwargs)
|
|
113
119
|
|
|
114
|
-
def enable_many(self,
|
|
120
|
+
def enable_many(self, names: list[str], **kwargs: object) -> None:
|
|
115
121
|
"""
|
|
116
122
|
Enable multiple built-in hooks by name.
|
|
117
123
|
"""
|
|
118
124
|
for hook_name in names:
|
|
119
|
-
self.enable(
|
|
125
|
+
self.enable(hook_name, **kwargs)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections import defaultdict
|
|
4
|
-
from
|
|
4
|
+
from threading import RLock
|
|
5
|
+
from typing import TYPE_CHECKING, Any, ClassVar
|
|
5
6
|
|
|
6
7
|
if TYPE_CHECKING:
|
|
7
8
|
from collections.abc import Callable
|
|
@@ -18,9 +19,36 @@ class HookMixin:
|
|
|
18
19
|
|
|
19
20
|
:ivar _hooks: 事件名称到钩子函数列表的映射。
|
|
20
21
|
"""
|
|
22
|
+
_class_hooks: ClassVar[dict[str, list[Callable[..., None]]]]
|
|
23
|
+
_hooks_lock: ClassVar[RLock] = RLock()
|
|
24
|
+
|
|
25
|
+
def __init_subclass__(cls, **kwargs: object) -> None:
|
|
26
|
+
super().__init_subclass__(**kwargs)
|
|
27
|
+
parent_hooks = getattr(cls, "_class_hooks", None)
|
|
28
|
+
class_hooks: dict[str, list[Callable[..., None]]] = defaultdict(list)
|
|
29
|
+
if parent_hooks:
|
|
30
|
+
for event_name, hooks in parent_hooks.items():
|
|
31
|
+
class_hooks[event_name] = list(hooks)
|
|
32
|
+
cls._class_hooks = class_hooks
|
|
33
|
+
|
|
21
34
|
def __init__(self) -> None:
|
|
22
35
|
self._hooks: dict[str, list[Callable[..., None]]] = defaultdict(list)
|
|
23
36
|
|
|
37
|
+
@classmethod
|
|
38
|
+
def register_class_hook(cls, event_name: str, hook_fn: Callable[..., None], *, unique: bool = True) -> None:
|
|
39
|
+
"""
|
|
40
|
+
在类级别注册 hook,所有实例触发事件时都会执行该 hook。
|
|
41
|
+
|
|
42
|
+
:param event_name: 要监听的事件名称。
|
|
43
|
+
:param hook_fn: 接受任意参数的可调用钩子函数。
|
|
44
|
+
:param unique: 是否防止同一 hook 重复注册。
|
|
45
|
+
"""
|
|
46
|
+
with cls._hooks_lock:
|
|
47
|
+
hooks = cls._class_hooks[event_name]
|
|
48
|
+
if unique and any(fn is hook_fn for fn in hooks):
|
|
49
|
+
return
|
|
50
|
+
hooks.append(hook_fn)
|
|
51
|
+
|
|
24
52
|
def register_hook(self, event_name: str, hook_fn: Callable[..., None]) -> None:
|
|
25
53
|
"""
|
|
26
54
|
为指定事件注册钩子函数。
|
|
@@ -38,7 +66,10 @@ class HookMixin:
|
|
|
38
66
|
:param args: 传递给钩子的所有位置参数。
|
|
39
67
|
:param kwargs: 传递给钩子的所有关键字参数。
|
|
40
68
|
"""
|
|
41
|
-
|
|
69
|
+
with self._hooks_lock:
|
|
70
|
+
class_hooks = list(self.__class__._class_hooks.get(event_name, [])) # noqa: SLF001
|
|
71
|
+
instance_hooks = list(self._hooks.get(event_name, []))
|
|
72
|
+
for hook in class_hooks + instance_hooks:
|
|
42
73
|
hook(*args, **kwargs)
|
|
43
74
|
|
|
44
75
|
def run_hooks(self, event_name: str, *args: Any, **kwargs: Any) -> None: # noqa: ANN401
|