MDit 0.0.0.dev1__tar.gz → 0.0.0.dev3__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.
Files changed (32) hide show
  1. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/PKG-INFO +12 -9
  2. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/pyproject.toml +12 -10
  3. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/MDit.egg-info/PKG-INFO +12 -9
  4. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/MDit.egg-info/SOURCES.txt +5 -2
  5. mdit-0.0.0.dev3/src/MDit.egg-info/requires.txt +23 -0
  6. mdit-0.0.0.dev3/src/mdit/__init__.py +220 -0
  7. mdit-0.0.0.dev3/src/mdit/container.py +209 -0
  8. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/data/schema.py +7 -2
  9. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/display.py +13 -0
  10. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/document.py +60 -69
  11. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/element.py +1425 -482
  12. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/generate.py +8 -6
  13. mdit-0.0.0.dev3/src/mdit/protocol.py +47 -0
  14. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/render.py +33 -45
  15. mdit-0.0.0.dev3/src/mdit/renderable.py +69 -0
  16. mdit-0.0.0.dev3/src/mdit/target/__init__.py +315 -0
  17. mdit-0.0.0.dev3/src/mdit/target/md.py +166 -0
  18. mdit-0.0.0.dev3/src/mdit/target/rich.py +502 -0
  19. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/template.py +1 -1
  20. mdit-0.0.0.dev1/src/MDit.egg-info/requires.txt +0 -20
  21. mdit-0.0.0.dev1/src/mdit/__init__.py +0 -133
  22. mdit-0.0.0.dev1/src/mdit/container.py +0 -195
  23. mdit-0.0.0.dev1/src/mdit/protocol.py +0 -90
  24. mdit-0.0.0.dev1/src/mdit/target.py +0 -202
  25. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/README.md +0 -0
  26. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/setup.cfg +0 -0
  27. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/MDit.egg-info/dependency_links.txt +0 -0
  28. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/MDit.egg-info/not-zip-safe +0 -0
  29. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/MDit.egg-info/top_level.txt +0 -0
  30. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/data/__init__.py +0 -0
  31. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/data/file.py +0 -0
  32. {mdit-0.0.0.dev1 → mdit-0.0.0.dev3}/src/mdit/parse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: MDit
3
- Version: 0.0.0.dev1
3
+ Version: 0.0.0.dev3
4
4
  Requires-Python: >=3.10
5
5
  Requires-Dist: sphinx<8
6
6
  Requires-Dist: myst-parser<4,>3
@@ -13,12 +13,15 @@ Requires-Dist: linkify-it-py
13
13
  Requires-Dist: readme-renderer
14
14
  Requires-Dist: cmarkgfm
15
15
  Requires-Dist: zundler
16
- Requires-Dist: PkgData
17
- Requires-Dist: PySerials
18
- Requires-Dist: PyLinks
19
- Requires-Dist: PyBadger
20
- Requires-Dist: PyColorIt
21
16
  Requires-Dist: IPython
22
- Requires-Dist: PyProtocol
23
- Requires-Dist: HTMP
24
- Requires-Dist: ansi-sgr
17
+ Requires-Dist: jupyterlab_myst
18
+ Requires-Dist: pygments
19
+ Requires-Dist: rich
20
+ Requires-Dist: PkgData==0.0.0.dev3
21
+ Requires-Dist: PySerials==0.0.0.dev7
22
+ Requires-Dist: PyLinks==0.0.0.dev27
23
+ Requires-Dist: PyBadger==0.0.0.dev8
24
+ Requires-Dist: PyColorIt==0.0.0.dev5
25
+ Requires-Dist: ProtocolMan==0.0.0.dev2
26
+ Requires-Dist: HTMP==0.0.0.dev3
27
+ Requires-Dist: ANSI-SGR==0.0.0.dev9
@@ -17,7 +17,7 @@ namespaces = true
17
17
  # ----------------------------------------- Project Metadata -------------------------------------
18
18
  #
19
19
  [project]
20
- version = "0.0.0.dev1"
20
+ version = "0.0.0.dev3"
21
21
  name = "MDit"
22
22
  requires-python = ">=3.10"
23
23
  dependencies = [
@@ -32,14 +32,16 @@ dependencies = [
32
32
  "readme-renderer",
33
33
  "cmarkgfm",
34
34
  "zundler",
35
- "PkgData",
36
- "PySerials",
37
- "PyLinks",
38
- "PyBadger",
39
- "PyColorIt",
40
35
  "IPython",
41
- "PyProtocol",
42
- "HTMP",
43
- "ansi-sgr",
44
-
36
+ "jupyterlab_myst",
37
+ "pygments",
38
+ "rich",
39
+ "PkgData == 0.0.0.dev3",
40
+ "PySerials == 0.0.0.dev7",
41
+ "PyLinks == 0.0.0.dev27",
42
+ "PyBadger == 0.0.0.dev8",
43
+ "PyColorIt == 0.0.0.dev5",
44
+ "ProtocolMan == 0.0.0.dev2",
45
+ "HTMP == 0.0.0.dev3",
46
+ "ANSI-SGR == 0.0.0.dev9",
45
47
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: MDit
3
- Version: 0.0.0.dev1
3
+ Version: 0.0.0.dev3
4
4
  Requires-Python: >=3.10
5
5
  Requires-Dist: sphinx<8
6
6
  Requires-Dist: myst-parser<4,>3
@@ -13,12 +13,15 @@ Requires-Dist: linkify-it-py
13
13
  Requires-Dist: readme-renderer
14
14
  Requires-Dist: cmarkgfm
15
15
  Requires-Dist: zundler
16
- Requires-Dist: PkgData
17
- Requires-Dist: PySerials
18
- Requires-Dist: PyLinks
19
- Requires-Dist: PyBadger
20
- Requires-Dist: PyColorIt
21
16
  Requires-Dist: IPython
22
- Requires-Dist: PyProtocol
23
- Requires-Dist: HTMP
24
- Requires-Dist: ansi-sgr
17
+ Requires-Dist: jupyterlab_myst
18
+ Requires-Dist: pygments
19
+ Requires-Dist: rich
20
+ Requires-Dist: PkgData==0.0.0.dev3
21
+ Requires-Dist: PySerials==0.0.0.dev7
22
+ Requires-Dist: PyLinks==0.0.0.dev27
23
+ Requires-Dist: PyBadger==0.0.0.dev8
24
+ Requires-Dist: PyColorIt==0.0.0.dev5
25
+ Requires-Dist: ProtocolMan==0.0.0.dev2
26
+ Requires-Dist: HTMP==0.0.0.dev3
27
+ Requires-Dist: ANSI-SGR==0.0.0.dev9
@@ -15,8 +15,11 @@ src/mdit/generate.py
15
15
  src/mdit/parse.py
16
16
  src/mdit/protocol.py
17
17
  src/mdit/render.py
18
- src/mdit/target.py
18
+ src/mdit/renderable.py
19
19
  src/mdit/template.py
20
20
  src/mdit/data/__init__.py
21
21
  src/mdit/data/file.py
22
- src/mdit/data/schema.py
22
+ src/mdit/data/schema.py
23
+ src/mdit/target/__init__.py
24
+ src/mdit/target/md.py
25
+ src/mdit/target/rich.py
@@ -0,0 +1,23 @@
1
+ sphinx<8
2
+ myst-parser<4,>3
3
+ pydata-sphinx-theme
4
+ sphinx-togglebutton
5
+ sphinx-design
6
+ markdown-it-py
7
+ mdit-py-plugins
8
+ linkify-it-py
9
+ readme-renderer
10
+ cmarkgfm
11
+ zundler
12
+ IPython
13
+ jupyterlab_myst
14
+ pygments
15
+ rich
16
+ PkgData==0.0.0.dev3
17
+ PySerials==0.0.0.dev7
18
+ PyLinks==0.0.0.dev27
19
+ PyBadger==0.0.0.dev8
20
+ PyColorIt==0.0.0.dev5
21
+ ProtocolMan==0.0.0.dev2
22
+ HTMP==0.0.0.dev3
23
+ ANSI-SGR==0.0.0.dev9
@@ -0,0 +1,220 @@
1
+ """Generate and process Markdown content.
2
+
3
+ References
4
+ ----------
5
+ - [GitHub Flavored Markdown Spec](https://github.github.com/gfm/)
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import TYPE_CHECKING as _TYPE_CHECKING
11
+
12
+ from mdit import display
13
+ from mdit.container import Container, MDContainer
14
+ from mdit.document import Document
15
+ from mdit.generate import DocumentGenerator
16
+ from mdit import render, target, element, parse, protocol, template
17
+
18
+ if _TYPE_CHECKING:
19
+ from typing import Callable
20
+ from mdit.protocol import ContainerContentType, ContainerContentInputType, ContainerContentSingleInputType, Stringable, TargetConfig, TargetConfigs, MDTargetConfig, RichTargetConfig, ContainerContentInputType
21
+
22
+
23
+ def generate(config: dict | list):
24
+ return DocumentGenerator().generate(config)
25
+
26
+
27
+ def document(
28
+ heading: element.Heading | MDContainer | ContainerContentInputType = None,
29
+ body: MDContainer | ContainerContentInputType = None,
30
+ section: Container | None = None,
31
+ footer: MDContainer | ContainerContentInputType = None,
32
+ frontmatter: dict | element.FrontMatter | None = None,
33
+ frontmatter_conditions: list[str] | None = None,
34
+ separate_sections: bool = False,
35
+ current_section_key: list[str | int] | None = None,
36
+ toctree_args: dict[str, str] | None = None,
37
+ toctree_dirhtml: bool = True,
38
+ target_configs_md: dict[str, MDTargetConfig | dict] | None = None,
39
+ target_configs_rich: dict[str, RichTargetConfig | dict] | None = None,
40
+ target_default: str = "sphinx",
41
+ deep_section_generator: Callable[[Document], str] | None = None,
42
+ content_separator_heading: str = "",
43
+ ):
44
+ # Process target configs
45
+ target_configs = {}
46
+ for key, config in (target_configs_md or {}).items():
47
+ config_obj = config if isinstance(config, protocol.MDTargetConfig) else target.md.Config(**config)
48
+ target_configs[key] = config_obj
49
+ for key, config in (target_configs_rich or {}).items():
50
+ config_obj = config if isinstance(config, protocol.RichTargetConfig) else target.rich.Config(**config)
51
+ if key in target_configs:
52
+ raise ValueError(f"Target config key '{key}' already exists.")
53
+ target_configs[key] = config_obj
54
+ # Process heading
55
+ if heading and not isinstance(heading, element.Heading):
56
+ heading = element.heading(
57
+ content=heading,
58
+ target_configs=target_configs,
59
+ target_default=target_default,
60
+ )
61
+ body = to_block_container(body)
62
+ if isinstance(section, Container):
63
+ pass
64
+ elif not section:
65
+ section = section_container()
66
+ elif isinstance(section, dict):
67
+ section = section_container(**section)
68
+ elif isinstance(section, (list, tuple)):
69
+ section = section_container(*section)
70
+ else:
71
+ section = section_container(section)
72
+ footer = to_block_container(footer)
73
+ if isinstance(frontmatter, dict):
74
+ frontmatter = element.frontmatter(frontmatter)
75
+ return Document(
76
+ heading=heading,
77
+ body=body,
78
+ section=section,
79
+ footer=footer,
80
+ frontmatter=frontmatter,
81
+ frontmatter_conditions=frontmatter_conditions,
82
+ separate_sections=separate_sections,
83
+ current_section_key=current_section_key,
84
+ toctree_args=toctree_args,
85
+ toctree_dirhtml=toctree_dirhtml,
86
+ target_configs=target_configs,
87
+ target_default=target_default,
88
+ deep_section_generator=deep_section_generator,
89
+ )
90
+
91
+ def block_container(
92
+ *contents: ContainerContentInputType,
93
+ html_container: Stringable | None = None,
94
+ html_container_attrs: dict | None = None,
95
+ html_container_conditions: list[str] | None = None,
96
+ target_configs: TargetConfigs = None,
97
+ target_default: str = "sphinx",
98
+ ) -> MDContainer:
99
+ return container(
100
+ *contents,
101
+ content_separator="\n\n",
102
+ html_container=html_container,
103
+ html_container_attrs=html_container_attrs,
104
+ html_container_conditions=html_container_conditions,
105
+ target_configs=target_configs,
106
+ target_default=target_default,
107
+ )
108
+
109
+
110
+ def inline_container(
111
+ *contents: ContainerContentInputType,
112
+ separator: str = "",
113
+ html_container: Stringable | None = None,
114
+ html_container_attrs: dict | None = None,
115
+ html_container_conditions: list[str] | None = None,
116
+ target_configs: TargetConfigs = None,
117
+ target_default: str = "sphinx",
118
+ ) -> MDContainer:
119
+ return container(
120
+ *contents,
121
+ content_separator=separator,
122
+ html_container=html_container,
123
+ html_container_attrs=html_container_attrs,
124
+ html_container_conditions=html_container_conditions,
125
+ target_configs=target_configs,
126
+ target_default=target_default,
127
+ )
128
+
129
+
130
+ def container(
131
+ *contents: ContainerContentInputType,
132
+ content_separator: str,
133
+ html_container: Stringable | None = None,
134
+ html_container_attrs: dict | None = None,
135
+ html_container_conditions: list[str] | None = None,
136
+ target_configs: TargetConfigs = None,
137
+ target_default: str = "sphinx",
138
+ ) -> MDContainer:
139
+ container_ = MDContainer(
140
+ content_separator=content_separator,
141
+ html_container=html_container,
142
+ html_container_attrs=html_container_attrs,
143
+ html_container_conditions=html_container_conditions,
144
+ target_configs=target_configs,
145
+ target_default=target_default,
146
+ )
147
+ container_.extend(list(contents))
148
+ return container_
149
+
150
+
151
+ def section_container(
152
+ *unlabeled_contents: ContainerContentInputType,
153
+ **labeled_contents: ContainerContentInputType,
154
+ ) -> Container:
155
+ container_ = Container()
156
+ container_.extend(*unlabeled_contents, **labeled_contents)
157
+ return container_
158
+
159
+
160
+ def to_block_container(
161
+ content: MDContainer | ContainerContentInputType,
162
+ separator: str = "\n\n",
163
+ html_container: Stringable | None = None,
164
+ html_container_attrs: dict | None = None,
165
+ html_container_conditions: list[str] | None = None,
166
+ target_configs: TargetConfigs = None,
167
+ target_default: str = "sphinx",
168
+ ) -> MDContainer:
169
+ return to_md_container(
170
+ content,
171
+ content_separator=separator,
172
+ html_container=html_container,
173
+ html_container_attrs=html_container_attrs,
174
+ html_container_conditions=html_container_conditions,
175
+ target_configs=target_configs,
176
+ target_default=target_default,
177
+ )
178
+
179
+
180
+ def to_inline_container(
181
+ content: MDContainer | ContainerContentInputType,
182
+ separator: str = "",
183
+ html_container: Stringable | None = None,
184
+ html_container_attrs: dict | None = None,
185
+ html_container_conditions: list[str] | None = None,
186
+ target_configs: TargetConfigs = None,
187
+ target_default: str = "sphinx",
188
+ ) -> MDContainer:
189
+ return to_md_container(
190
+ content,
191
+ content_separator=separator,
192
+ html_container=html_container,
193
+ html_container_attrs=html_container_attrs,
194
+ html_container_conditions=html_container_conditions,
195
+ target_configs=target_configs,
196
+ target_default=target_default,
197
+ )
198
+
199
+
200
+ def to_md_container(
201
+ content: MDContainer | ContainerContentInputType,
202
+ content_separator: str,
203
+ html_container: Stringable | None = None,
204
+ html_container_attrs: dict | None = None,
205
+ html_container_conditions: list[str] | None = None,
206
+ target_configs: TargetConfigs = None,
207
+ target_default: str = "sphinx",
208
+ ) -> MDContainer:
209
+ if isinstance(content, MDContainer):
210
+ return content
211
+ container_ = MDContainer(
212
+ content_separator=content_separator,
213
+ html_container=html_container,
214
+ html_container_attrs=html_container_attrs,
215
+ html_container_conditions=html_container_conditions,
216
+ target_configs=target_configs,
217
+ target_default=target_default,
218
+ )
219
+ container_.extend(content)
220
+ return container_
@@ -0,0 +1,209 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING as _TYPE_CHECKING, NamedTuple as _NamedTuple
4
+
5
+ import htmp as _htmp
6
+ import rich
7
+ import rich.text
8
+ import rich.markdown
9
+
10
+ from mdit.protocol import MDITRenderable as _MDCode
11
+ from mdit.renderable import Renderable as _Renderable
12
+
13
+ if _TYPE_CHECKING:
14
+ from rich.console import RenderableType
15
+ from mdit.protocol import ContainerContentType, ContainerContentConditionType, ContainerContentInputType, TargetConfigs, Stringable, MDTargetConfig, RichTargetConfig
16
+
17
+
18
+ class ContainerContent(_NamedTuple):
19
+ content: ContainerContentType
20
+ conditions: list[str]
21
+
22
+
23
+ class Container:
24
+
25
+ def __init__(
26
+ self,
27
+ data: dict[str | int, ContainerContent] | None = None,
28
+ *args,
29
+ **kwargs
30
+ ):
31
+ self._data = data or {}
32
+ super().__init__(*args, **kwargs)
33
+ return
34
+
35
+ def append(
36
+ self,
37
+ content: ContainerContentType,
38
+ conditions: ContainerContentConditionType = None,
39
+ key: str | int | None = None
40
+ ) -> str | int:
41
+ if not key:
42
+ key = max((key for key in self._data.keys() if isinstance(key, int)), default=-1) + 1
43
+ if key in self._data:
44
+ raise ValueError("Key already exists in content.")
45
+ if not conditions:
46
+ conditions = []
47
+ elif isinstance(conditions, str):
48
+ conditions = [conditions]
49
+ else:
50
+ conditions = list(conditions)
51
+ self._data[key] = ContainerContent(content=content, conditions=conditions)
52
+ return key
53
+
54
+ def extend(self, *unlabeled_contents: ContainerContentInputType, **labeled_contents: ContainerContentInputType) -> list[str | int]:
55
+
56
+ def resolve_value(input_values):
57
+ if not input_values:
58
+ return
59
+ if isinstance(input_values, list):
60
+ for input_value in input_values:
61
+ yield from resolve_value(input_value)
62
+ elif isinstance(input_values, tuple):
63
+ val = input_values[0]
64
+ cond = input_values[1] if len(input_values) > 1 else None
65
+ key = input_values[2] if len(input_values) > 2 else None
66
+ yield val, cond, key
67
+ elif isinstance(input_values, dict):
68
+ for k, v in input_values.items():
69
+ key = k
70
+ if isinstance(v, (list, tuple)):
71
+ val = v[0]
72
+ cond = v[1] if len(v) > 1 else None
73
+ else:
74
+ val = v
75
+ cond = None
76
+ yield val, cond, key
77
+ else:
78
+ yield input_values, None, None
79
+
80
+ added_keys = []
81
+ if unlabeled_contents:
82
+ first_available_key = max(
83
+ (key for key in self._data.keys() if isinstance(key, int)), default=-1
84
+ ) + 1
85
+ for idx, value in enumerate(unlabeled_contents):
86
+ for content, conditions, key in resolve_value(value):
87
+ added_keys.append(self.append(content, conditions, key or first_available_key + idx))
88
+ if labeled_contents:
89
+ for key, value in labeled_contents.items():
90
+ for content, conditions, sub_key in resolve_value(value):
91
+ final_key = key if sub_key is None else f"{key}.{sub_key}"
92
+ added_keys.append(self.append(content, conditions, final_key))
93
+ return added_keys
94
+
95
+ def elements(
96
+ self,
97
+ target: TargetConfigs | None = None,
98
+ filters: str | list[str] | None = None,
99
+ source: bool = False,
100
+ ) -> list:
101
+ elements = []
102
+ if isinstance(filters, str):
103
+ filters = [filters]
104
+ for content, conditions in self.values():
105
+ if not filters or not conditions or any(filter in conditions for filter in filters):
106
+ if not source:
107
+ elements.append(content)
108
+ elif isinstance(content, _MDCode):
109
+ elements.append(content.source(target=target, filters=filters))
110
+ else:
111
+ elements.append(str(content))
112
+ return elements
113
+
114
+ def get(self, key: str | int, default=None):
115
+ return self._data.get(key, default)
116
+
117
+ def keys(self):
118
+ return self._data.keys()
119
+
120
+ def values(self):
121
+ return self._data.values()
122
+
123
+ def items(self):
124
+ return self._data.items()
125
+
126
+ def __getitem__(self, item):
127
+ return self._data[item]
128
+
129
+ def __setitem__(self, key, value):
130
+ self._data[key] = value
131
+ return
132
+
133
+ def __contains__(self, item):
134
+ return item in self._data
135
+
136
+ def __bool__(self):
137
+ return bool(self._data)
138
+
139
+ def __len__(self):
140
+ return len(self._data)
141
+
142
+
143
+ class MDContainer(Container, _Renderable):
144
+ # Multiple inheritance: https://stackoverflow.com/questions/9575409/calling-parent-class-init-with-multiple-inheritance-whats-the-right-way
145
+ def __init__(
146
+ self,
147
+ content: dict[str | int, ContainerContent] | None = None,
148
+ content_separator: str = "\n\n",
149
+ html_container: Stringable | None = None,
150
+ html_container_attrs: dict | None = None,
151
+ html_container_conditions: list[str] | None = None,
152
+ target_configs: TargetConfigs = None,
153
+ target_default: str = "sphinx"
154
+ ):
155
+ super().__init__(
156
+ data=content,
157
+ target_configs=target_configs,
158
+ target_default=target_default
159
+ )
160
+ self.content_separator = content_separator
161
+ self.html_container = html_container
162
+ self.html_container_attrs = html_container_attrs or {}
163
+ self.html_container_conditions = html_container_conditions or []
164
+ return
165
+
166
+ @property
167
+ def code_fence_count(self) -> int:
168
+ return max(
169
+ (
170
+ content.code_fence_count if isinstance(content, _MDCode)
171
+ else self._count_code_fence(str(content))
172
+ for content, _ in self._data.values()
173
+ ),
174
+ default=0,
175
+ )
176
+
177
+ def _source_rich(self, target: RichTargetConfig, filters: str | list[str] | None = None) -> RenderableType:
178
+ block_container = "\n" in self.content_separator
179
+ elements = self.elements(target=target, filters=filters, source=True)
180
+ if not elements:
181
+ return ""
182
+ if block_container:
183
+ group = [
184
+ rich.markdown.Markdown(element) if isinstance(element, str) else element
185
+ for element in elements
186
+ ]
187
+ return rich.console.Group(*group) if len(group) > 1 else group[0]
188
+ text = rich.text.Text()
189
+ for element in elements[:-1]:
190
+ text.append(element)
191
+ text.append(self.content_separator)
192
+ text.append(elements[-1])
193
+ return text
194
+
195
+ def _source_md(self, target: MDTargetConfig, filters: str | list[str] | None = None) -> str:
196
+ elements = self.elements(target=target, filters=filters, source=True)
197
+ elements_str = self.content_separator.join(elements)
198
+ if self.html_container and self.html_container_attrs and (
199
+ not filters
200
+ or not self.html_container_conditions
201
+ or any(filter in self.html_container_conditions for filter in filters)
202
+ ):
203
+ container_func = getattr(_htmp.element, str(self.html_container))
204
+ return container_func(_htmp.elementor.markdown(elements_str), self.html_container_attrs).source(
205
+ indent=-1)
206
+ return elements_str
207
+
208
+ def __str__(self) -> str:
209
+ return self.source()
@@ -10,6 +10,10 @@ import pyserials as _ps
10
10
  from mdit.data import file as _file
11
11
 
12
12
 
13
+ _REGISTRY = None
14
+ _SCHEMATA = None
15
+
16
+
13
17
  def make_registry(
14
18
  dynamic: bool = False,
15
19
  crawl: bool = True,
@@ -33,6 +37,9 @@ def make_registry(
33
37
 
34
38
 
35
39
  def validate(data: dict, schema_id: str):
40
+ global _REGISTRY, _SCHEMATA
41
+ if not _REGISTRY:
42
+ _REGISTRY, _SCHEMATA = make_registry()
36
43
  _ps.validate.jsonschema(
37
44
  data=data,
38
45
  schema=_SCHEMATA[schema_id],
@@ -41,5 +48,3 @@ def validate(data: dict, schema_id: str):
41
48
  )
42
49
  return
43
50
 
44
-
45
- # _REGISTRY, _SCHEMATA = make_registry()
@@ -1,11 +1,18 @@
1
1
  """Display HTML and Markdown content in web browser or IPython notebook."""
2
+ from __future__ import annotations as _annotations
3
+
4
+ from typing import TYPE_CHECKING as _TYPE_CHECKING
2
5
 
3
6
  import webbrowser as _webbrowser
4
7
  import tempfile as _tempfile
5
8
  import time as _time
6
9
 
10
+ import rich as _rich
7
11
  from IPython import display as _display
8
12
 
13
+ if _TYPE_CHECKING:
14
+ from rich.console import Console
15
+
9
16
 
10
17
  def browser(content: str) -> None:
11
18
  """Display HTML content in a web browser.
@@ -44,3 +51,9 @@ def ipython(content: str, as_md: bool = True) -> None:
44
51
  renderer = _display.Markdown if as_md else _display.HTML
45
52
  _display.display(renderer(content))
46
53
  return
54
+
55
+
56
+ def console(content, output: Console | None = None) -> None:
57
+ writer = output or _rich
58
+ writer.print(content)
59
+ return