Skip to content

Commit 47e36a0

Browse files
committed
update
1 parent 984f5b8 commit 47e36a0

6 files changed

Lines changed: 42 additions & 125 deletions

File tree

docs/conf.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
# The theme to use for HTML and HTML Help pages. See the documentation for
5151
# a list of builtin themes.
5252
#
53-
html_theme = 'furo'
53+
# html_theme = 'furo'
5454

5555
html_theme_options = {}
5656

@@ -121,3 +121,5 @@
121121
extensions.append('data')
122122

123123
# CUSTOM CONFIGURATION
124+
125+
keep_warnings = True

docs/index.rst

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,11 @@
55
sphinxnotes-data
66
================
77

8-
.. data:tmpl::
9-
:on: parsed
10-
:debug:
11-
12-
Name: {{ name }}
13-
14-
{% for k, v in attrs.items() %}
15-
:{{ k }}: {{ v }}
16-
{%- endfor %}
17-
18-
Content::
19-
20-
{{ content }}
21-
22-
.. data:schema:: int
23-
:color: bool, required
24-
:size: int, required
25-
26-
lines of int
27-
28-
123
29-
===
8+
FooBar
9+
======
3010

31-
.. data:def::
11+
.. data:autodef::
3212
:color:
3313
:size: 1
3414

35-
12a
36-
37-
38-
123555
39-
======
40-
41-
zzzz
15+
Here2.

src/sphinxnotes/data/__init__.py

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from __future__ import annotations
1010
from typing import cast
11-
from textwrap import dedent
1211

1312
from docutils import nodes
1413
from docutils.parsers.rst import directives
@@ -26,34 +25,9 @@
2625

2726
logger = logging.getLogger(__name__)
2827

29-
DEFAULT_TEMPLATE = Template(
30-
debug=True,
31-
phase=Phase.Parsing,
32-
text=dedent("""
33-
.. note::
34-
35-
This is a default template for rendering the data your deinfed.
36-
Please create your own template using the :rst:dir:`data:tmpl` directive.
37-
38-
:Name: ``{{ name }}``
39-
{% for k, v in attrs.items() %}
40-
:{{ k }}: ``{{ v }}``
41-
{%- endfor %}
42-
:content: ::
43-
44-
{{ content }}"""),
45-
)
46-
47-
DEFAULT_SCHEMA = Schema(
48-
name=Field(),
49-
attrs=Field(),
50-
content=Field(),
51-
)
52-
5328
TEMPLATE_KEY = 'sphinxnotes:template'
5429
SCHEMA_KEY = 'sphinxnotes:data'
5530

56-
5731
class DataNode(nodes.Node):
5832
data: Data
5933
template: Template
@@ -102,7 +76,7 @@ def _complete_external_data(self):
10276
if title := find_titular_node_upward(self.parent):
10377
self.data.name = title.astext()
10478

105-
if not self.data.content:
79+
if not self.data.content and self.parent:
10680
contnodes = []
10781
for i, child in enumerate(self.parent):
10882
if child == self:
@@ -159,11 +133,11 @@ def _extract_data(self) -> Data:
159133
)
160134

161135
def current_template(self) -> Template:
162-
tmpl = self.env.current_document.get(TEMPLATE_KEY, DEFAULT_TEMPLATE)
136+
tmpl = self.env.current_document.get(TEMPLATE_KEY, Template.default())
163137
return cast(Template, tmpl)
164138

165139
def current_schema(self) -> Schema:
166-
schema = self.env.current_document.get(SCHEMA_KEY, DEFAULT_SCHEMA)
140+
schema = self.env.current_document.get(SCHEMA_KEY, Schema.default())
167141
return cast(Schema, schema)
168142

169143
def new_pending_node(self) -> pending_data_node:

src/sphinxnotes/data/data.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@ class Schema(object):
222222
attrs: dict[str, Field] | Field
223223
content: Field | None
224224

225+
@staticmethod
226+
def default() -> Schema:
227+
return Schema(name=Field(), attrs=Field(), content=Field())
228+
229+
225230
def _parse_single(
226231
self, field: tuple[str, Field | None], rawval: str | None
227232
) -> Value:

src/sphinxnotes/data/render.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,23 @@ class Template(object):
8282
phase: Phase
8383
debug: bool
8484

85-
@classmethod
86-
def default(cls) -> Template:
87-
return Template('THIS IS A DEFAULT TEMPLATE', Phase.default(), False)
85+
@staticmethod
86+
def default() -> Template:
87+
return Template(debug=True,phase=Phase.Parsing, text="""
88+
.. note::
89+
90+
This is a default template for rendering the data your deinfed.
91+
Please create your own template using the :rst:dir:`data:tmpl` directive.
92+
93+
:Name: ``{{ name or 'None' }}``
94+
{% for k, v in attrs.items() %}
95+
:{{ k }}: ``{{ v or 'None' }}``
96+
{%- endfor %}
97+
:content:
98+
::
99+
100+
{{ content or 'None' }}""",
101+
)
88102

89103
def render(self, ctx: dict[str, Any]) -> str:
90104
return JinjaEnv().from_string(self.text).render(ctx)
@@ -104,18 +118,18 @@ def render(
104118

105119
if tmpl.debug:
106120
sm = nodes.system_message(
107-
'Template debug report:', type='WARNING', level=2, source=''
121+
'template debug report:', type='DEBUG', level=2, source=''
108122
)
109-
sm += _debug_report_part('data', pformat(data), lang='python')
123+
sm += _debug_report_part('data:', pformat(data), lang='python')
110124
sm += _debug_report_part(
111125
f'template (phase: {tmpl.phase}, debug: {tmpl.debug}):',
112126
tmpl.text,
113127
lang='jinja',
114128
)
115129
sm += _debug_report_part(
116-
'rendered node', '\n'.join(n.pformat() for n in ns), lang='xml'
130+
'rendered nodes:', '\n'.join(n.pformat() for n in ns), lang='xml'
117131
)
118-
ns += sm
132+
ns.append(sm)
119133

120134
return ns
121135

src/sphinxnotes/data/utils.py

Lines changed: 6 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
from typing import TypeVar, Generic, get_args
2-
import dataclasses
1+
from typing import TypeVar, cast
32

43
from docutils import nodes
54
from docutils.frontend import get_default_settings
65
from docutils.parsers.rst import Parser
76
from docutils.utils import new_document
87
from sphinx.util import logging
98

10-
from dacite import from_dict
11-
129
logger = logging.getLogger(__name__)
1310

1411

@@ -23,10 +20,10 @@ def parse_text_to_nodes(text: str) -> list[nodes.Node]:
2320
return document.children
2421

2522

26-
_Node = TypeVar('_Element', bound=nodes.Node)
23+
_Element = TypeVar('_Element', bound=nodes.Node)
2724

2825

29-
def find_parent(node: nodes.Element | None, typ: type[_Node]) -> _Node | None:
26+
def find_parent(node: nodes.Element | None, typ: type[_Element]) -> _Element | None:
3027
if node is None or isinstance(node, typ):
3128
return node
3229
return find_parent(node.parent, typ)
@@ -40,13 +37,13 @@ def find_current_document(node: nodes.Element | None) -> nodes.document | None:
4037
return find_parent(node, nodes.document)
4138

4239

43-
def find_first_child(node: nodes.Element, cls: type[_Node]) -> _Node | None:
40+
def find_first_child(node: nodes.Element, cls: type[_Element]) -> _Element | None:
4441
if (index := node.first_child_matching_class(cls)) is None:
4542
return None
46-
return node[index] # type: ignore
43+
return cast(_Element, node[index])
4744

4845

49-
def find_titular_node_upward(node: nodes.Element | None) -> nodes.Node | None:
46+
def find_titular_node_upward(node: nodes.Element | None) -> nodes.Element | None:
5047
if node is None:
5148
return None
5249
if isinstance(node, (nodes.section, nodes.sidebar)):
@@ -62,52 +59,3 @@ def find_titular_node_upward(node: nodes.Element | None) -> nodes.Node | None:
6259
if para := find_first_child(node, nodes.paragraph):
6360
return para
6461
return find_titular_node_upward(node.parent)
65-
66-
67-
DataT = TypeVar('DataT')
68-
69-
70-
class TempData(Generic[DataT]):
71-
"""A helper class for storing/accessing dataclasses to/from a docutils node."""
72-
73-
KEY = 'sphinxnotes-data'
74-
75-
@classmethod
76-
def _get_data_type(cls) -> type[DataT]:
77-
"""
78-
Dynamically extract the actual type of DataT from the class definition.
79-
80-
Example: For `class MyHelper(TempData[MyStruct])`, this returns `MyStruct`.
81-
"""
82-
# Access the original base classes (including generic type args)
83-
# This attribute is available in Python 3.7+
84-
for base in getattr(cls, '__orig_bases__', []):
85-
origin = getattr(base, '__origin__', None)
86-
# Check if this base is the TempData class itself
87-
if origin is TempData:
88-
args = get_args(base)
89-
if args:
90-
# Return the first generic argument, which corresponds to DataT
91-
return args[0]
92-
raise TypeError(
93-
f'Cannot infer DataT from {cls.__name__}. '
94-
'Ensure you are subclassing TempData[MyType] rather than using it directly.'
95-
)
96-
97-
@classmethod
98-
def _get_type_name(cls) -> str:
99-
return cls._get_data_type().__name__
100-
101-
@classmethod
102-
def set(cls, node: nodes.Element, data: DataT) -> None:
103-
tempdata = node.setdefault(cls.KEY, {})
104-
assert dataclasses.is_dataclass(data)
105-
tempdata[cls._get_type_name()] = dataclasses.asdict(data) # type: ignore
106-
107-
@classmethod
108-
def get(cls, node: nodes.Element) -> DataT | None:
109-
if (tempdata := node.get(cls.KEY)) is None:
110-
return None
111-
if (data := tempdata.get(cls._get_type_name())) is None:
112-
return None
113-
return from_dict(data_class=cls._get_data_type(), data=data)

0 commit comments

Comments
 (0)