From a11f4f4f8a8b06e79e2a229f7d464129f1bb1864 Mon Sep 17 00:00:00 2001 From: Shengyu Zhang Date: Wed, 13 May 2026 00:43:02 +0800 Subject: [PATCH] refactor: Add env parameter to UnresolvedContext.resolve() UnresolvedContext implementations may need access to the Sphinx build environment during resolution. For example, PendingObject in sphinxnotes-any requires env.get_domain() to look up the object domain without storing an unpicklable domain reference. Co-Authored-By: DeepSeek V4 Pro --- src/sphinxnotes/render/ctx.py | 7 +++++-- src/sphinxnotes/render/ctxnodes.py | 2 +- src/sphinxnotes/render/sources.py | 7 +++++-- tests/test_ctx.py | 8 +++++--- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/sphinxnotes/render/ctx.py b/src/sphinxnotes/render/ctx.py index 32f8c41..25cf5a7 100644 --- a/src/sphinxnotes/render/ctx.py +++ b/src/sphinxnotes/render/ctx.py @@ -4,11 +4,14 @@ """ from __future__ import annotations -from typing import Any +from typing import TYPE_CHECKING, Any from abc import ABC, abstractmethod from collections.abc import Hashable from .data import ParsedData +if TYPE_CHECKING: + from sphinx.environment import BuildEnvironment + type ResolvedContext = ParsedData | dict[str, Any] """Resolved context types used by template rendering.""" @@ -17,7 +20,7 @@ class UnresolvedContext(ABC, Hashable): """An abstract representation of context that will be resolved later.""" @abstractmethod - def resolve(self) -> ResolvedContext: + def resolve(self, env: BuildEnvironment) -> ResolvedContext: """This method will be called when rendering to get the available :py:type:`ResolvedContext`.""" ... diff --git a/src/sphinxnotes/render/ctxnodes.py b/src/sphinxnotes/render/ctxnodes.py index 397cd50..d1790d1 100644 --- a/src/sphinxnotes/render/ctxnodes.py +++ b/src/sphinxnotes/render/ctxnodes.py @@ -114,7 +114,7 @@ def err_report() -> Report: hook(self, pdata) try: - ctx = self.ctx = pdata.resolve() + ctx = self.ctx = pdata.resolve(host.env) except Exception as e: report = err_report() report.text('Failed to resolve unresolved context:') diff --git a/src/sphinxnotes/render/sources.py b/src/sphinxnotes/render/sources.py index 161bc91..3677455 100644 --- a/src/sphinxnotes/render/sources.py +++ b/src/sphinxnotes/render/sources.py @@ -9,7 +9,7 @@ """ from __future__ import annotations -from typing import final, override +from typing import TYPE_CHECKING, final, override from abc import abstractmethod from dataclasses import dataclass @@ -20,6 +20,9 @@ from .template import Template from .pipeline import BaseContextSource, BaseContextDirective, BaseContextRole +if TYPE_CHECKING: + from sphinx.environment import BuildEnvironment + @dataclass class UnparsedData(UnresolvedContext): @@ -32,7 +35,7 @@ class UnparsedData(UnresolvedContext): schema: Schema @override - def resolve(self) -> ResolvedContext: + def resolve(self, env: BuildEnvironment) -> ResolvedContext: return self.schema.parse(self.raw) @override diff --git a/tests/test_ctx.py b/tests/test_ctx.py index 049adf5..19992f3 100644 --- a/tests/test_ctx.py +++ b/tests/test_ctx.py @@ -1,4 +1,5 @@ import pickle +from unittest.mock import MagicMock from sphinxnotes.render.data import RawData, Schema from sphinxnotes.render.sources import UnparsedData @@ -17,6 +18,7 @@ def test_schema_and_unparsed_data_are_picklable(): restored = pickle.loads(pickle.dumps(pending)) - assert restored.resolve().name == 'mimi' - assert restored.resolve().attrs == {'age': 2, 'tags': ['cat', 'cute']} - assert restored.resolve().content == 'hello' + mock_env = MagicMock() + assert restored.resolve(mock_env).name == 'mimi' + assert restored.resolve(mock_env).attrs == {'age': 2, 'tags': ['cat', 'cute']} + assert restored.resolve(mock_env).content == 'hello'