Skip to content

Commit bde6b15

Browse files
committed
Improve tests/docs for main MarkdownIt class
1 parent 5cd47f5 commit bde6b15

File tree

6 files changed

+279
-53
lines changed

6 files changed

+279
-53
lines changed

.github/workflows/tests.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ jobs:
3333
- name: Test with pytest
3434
run: |
3535
pip install pytest
36-
pytest tests/
36+
pytest --cov=markdown_it --cov-report=
37+
- name: Upload to coveralls
38+
run: |
39+
pip install coveralls
40+
coveralls
3741
3842
publish:
3943

markdown_it/main.py

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from typing import Callable, List, Optional, Union
1+
from typing import Any, Callable, Dict, List, Optional, Union
22

33
from . import helpers, presets # noqa F401
44
from .common import utils # noqa F401
5+
from .token import Token
56
from .parser_core import ParserCore # noqa F401
67
from .parser_block import ParserBlock # noqa F401
78
from .parser_inline import ParserInline # noqa F401
@@ -104,13 +105,22 @@ def configure(self, presets: Union[str, AttrDict]):
104105

105106
return self
106107

107-
def enable(self, names: Union[str, List[str]], ignoreInvalid: bool = False):
108-
""" chainable
109-
MarkdownIt.enable(list, ignoreInvalid)
110-
- list (String|Array): rule name or list of rule names to enable
111-
- ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
108+
def get_active_rules(self) -> Dict[str, List[str]]:
109+
"""Return the names of all active rules."""
110+
return {
111+
chain: self[chain].ruler.get_active_rules()
112+
for chain in ["core", "block", "inline"]
113+
}
114+
115+
def enable(
116+
self, names: Union[str, List[str]], ignoreInvalid: bool = False
117+
) -> "MarkdownIt":
118+
"""Enable list or rules. (chainable)
112119
113-
Enable list or rules. It will automatically find appropriate components,
120+
:param names: rule name or list of rule names to enable.
121+
:param ignoreInvalid: set `true` to ignore errors when rule not found.
122+
123+
It will automatically find appropriate components,
114124
containing rules with given names. If rule not found, and `ignoreInvalid`
115125
not set - throws exception.
116126
@@ -135,13 +145,14 @@ def enable(self, names: Union[str, List[str]], ignoreInvalid: bool = False):
135145

136146
return self
137147

138-
def disable(self, names: Union[str, List[str]], ignoreInvalid: bool = False):
139-
""" chainable
140-
MarkdownIt.disable(list, ignoreInvalid)
141-
- names (String|Array): rule name or list of rule names to disable.
142-
- ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
148+
def disable(
149+
self, names: Union[str, List[str]], ignoreInvalid: bool = False
150+
) -> "MarkdownIt":
151+
"""The same as [[MarkdownIt.enable]], but turn specified rules off. (chainable)
152+
153+
:param names: rule name or list of rule names to disable.
154+
:param ignoreInvalid: set `true` to ignore errors when rule not found.
143155
144-
The same as [[MarkdownIt.enable]], but turn specified rules off.
145156
"""
146157
result = []
147158

@@ -157,88 +168,94 @@ def disable(self, names: Union[str, List[str]], ignoreInvalid: bool = False):
157168
raise ValueError(f"MarkdownIt. Failed to disable unknown rule(s): {missed}")
158169
return self
159170

160-
def add_render_rule(self, name, function, fmt="html"):
171+
def add_render_rule(self, name: str, function: Callable, fmt="html"):
172+
"""Add a rule for rendering a particular Token type.
173+
174+
Only applied when ``renderer.__output__ == fmt``
175+
"""
161176
if self.renderer.__output__ == fmt:
162177
self.renderer.rules[name] = function
163178

164-
def use(self, plugin: Callable, *params):
165-
""" chainable
179+
def use(self, plugin: Callable, *params) -> "MarkdownIt":
180+
"""Load specified plugin with given params into current parser instance. (chainable)
166181
167-
Load specified plugin with given params into current parser instance.
168182
It's just a sugar to call `plugin(md, params)` with curring.
169183
170-
##### Example
184+
Example::
185+
186+
def func(tokens, idx):
187+
tokens[idx].content = tokens[idx].content.replace('foo', 'bar')
188+
md = MarkdownIt().use(plugin, 'foo_replace', 'text', func)
171189
172-
```python
173-
def func(tokens, idx):
174-
tokens[idx].content = tokens[idx].content.replace('foo', 'bar')
175-
md = MarkdownIt().use(plugin, 'foo_replace', 'text', func)
176-
```
177190
"""
178191
plugin(self, *params)
179192
return self
180193

181-
def parse(self, src: str, env: Optional[dict] = None):
182-
""" internal
183-
MarkdownIt.parse(src, env) -> Array
184-
- src (String): source string
185-
- env (Object): environment sandbox
194+
def parse(self, src: str, env: Optional[AttrDict] = None) -> List[Token]:
195+
"""Parse the source string to a token stream
196+
197+
:param src: source string
198+
:param env: environment sandbox
186199
187200
Parse input string and returns list of block tokens (special token type
188-
"inline" will contain list of inline tokens). You should not call this
189-
method directly, until you write custom renderer (for example, to produce
190-
AST).
201+
"inline" will contain list of inline tokens).
191202
192203
`env` is used to pass data between "distributed" rules and return additional
193204
metadata like reference info, needed for the renderer. It also can be used to
194205
inject data in specific cases. Usually, you will be ok to pass `{}`,
195206
and then pass updated object to renderer.
196207
"""
197-
env = AttrDict(env or {})
208+
env = AttrDict() if env is None else env
209+
if not isinstance(env, AttrDict):
210+
raise TypeError(f"Input data should be an AttrDict, not {type(env)}")
198211
if not isinstance(src, str):
199-
raise TypeError("Input data should be a string")
212+
raise TypeError(f"Input data should be a string, not {type(src)}")
200213
state = StateCore(src, self, env)
201214
self.core.process(state)
202215
return state.tokens
203216

204-
def render(self, src: str, env: Optional[dict] = None):
205-
"""
206-
MarkdownIt.render(src [, env]) -> String
207-
- src (String): source string
208-
- env (Object): environment sandbox
217+
def render(self, src: str, env: Optional[AttrDict] = None) -> Any:
218+
"""Render markdown string into html. It does all magic for you :).
209219
210-
Render markdown string into html. It does all magic for you :).
220+
:param src: source string
221+
:param env: environment sandbox
222+
:returns: The output of the loaded renderer
211223
212224
`env` can be used to inject additional metadata (`{}` by default).
213225
But you will not need it with high probability. See also comment
214226
in [[MarkdownIt.parse]].
215227
"""
216-
env = AttrDict(env or {})
228+
env = env or AttrDict()
217229
return self.renderer.render(self.parse(src, env), self.options, env)
218230

219-
def parseInline(self, src: str, env: Optional[dict] = None):
220-
""" internal
221-
MarkdownIt.parseInline(src, env) -> Array
222-
- src (String): source string
223-
- env (Object): environment sandbox
231+
def parseInline(self, src: str, env: Optional[AttrDict] = None) -> List[Token]:
232+
"""The same as [[MarkdownIt.parse]] but skip all block rules.
224233
225-
The same as [[MarkdownIt.parse]] but skip all block rules. It returns the
234+
:param src: source string
235+
:param env: environment sandbox
236+
237+
It returns the
226238
block tokens list with the single `inline` element, containing parsed inline
227239
tokens in `children` property. Also updates `env` object.
228240
"""
241+
env = AttrDict() if env is None else env
242+
if not isinstance(env, AttrDict):
243+
raise TypeError(f"Input data should be an AttrDict, not {type(env)}")
244+
if not isinstance(src, str):
245+
raise TypeError(f"Input data should be a string, not {type(src)}")
229246
state = self.core.State(src, self, env)
230247
state.inlineMode = True
231248
self.core.process(state)
232249
return state.tokens
233250

234-
def renderInline(self, src: str, env: Optional[dict] = None):
235-
"""
236-
MarkdownIt.renderInline(src [, env]) -> String
237-
- src (String): source string
238-
- env (Object): environment sandbox
251+
def renderInline(self, src: str, env: Optional[AttrDict] = None) -> Any:
252+
"""Similar to [[MarkdownIt.render]] but for single paragraph content.
253+
254+
:param src: source string
255+
:param env: environment sandbox
239256
240257
Similar to [[MarkdownIt.render]] but for single paragraph content. Result
241258
will NOT be wrapped into `<p>` tags.
242259
"""
243-
env = AttrDict(env or {})
260+
env = AttrDict() if env is None else env
244261
return self.renderer.render(self.parseInline(src, env), self.options, env)

markdown_it/ruler.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,7 @@ def getRules(self, chainName: str) -> List[RuleFunc]:
203203
self.__compile__()
204204
# Chain can be empty, if rules disabled. But we still have to return Array.
205205
return self.__cache__.get(chainName, []) or []
206+
207+
def get_active_rules(self) -> List[str]:
208+
"""Return the active rule names."""
209+
return [r.name for r in self.__rules__ if r.enabled]

tests/test_api/__init__.py

Whitespace-only changes.

tests/test_api/test_main.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from markdown_it import MarkdownIt
2+
3+
4+
def test_load_presets():
5+
md = MarkdownIt("zero")
6+
assert md.get_active_rules() == {
7+
"block": ["paragraph"],
8+
"core": ["normalize", "block", "inline"],
9+
"inline": ["text"],
10+
}
11+
md = MarkdownIt("commonmark")
12+
assert md.get_active_rules() == {
13+
"core": ["normalize", "block", "inline"],
14+
"block": [
15+
"code",
16+
"fence",
17+
"blockquote",
18+
"hr",
19+
"list",
20+
"reference",
21+
"heading",
22+
"lheading",
23+
"html_block",
24+
"paragraph",
25+
],
26+
"inline": [
27+
"text",
28+
"newline",
29+
"escape",
30+
"backticks",
31+
"emphasis",
32+
"link",
33+
"image",
34+
"autolink",
35+
"html_inline",
36+
"entity",
37+
],
38+
}
39+
40+
41+
def test_enable():
42+
md = MarkdownIt("zero").enable("heading")
43+
assert md.get_active_rules() == {
44+
"block": ["heading", "paragraph"],
45+
"core": ["normalize", "block", "inline"],
46+
"inline": ["text"],
47+
}
48+
md.enable(["backticks", "autolink"])
49+
assert md.get_active_rules() == {
50+
"block": ["heading", "paragraph"],
51+
"core": ["normalize", "block", "inline"],
52+
"inline": ["text", "backticks", "autolink"],
53+
}
54+
55+
56+
def test_disable():
57+
md = MarkdownIt("zero").disable("inline")
58+
assert md.get_active_rules() == {
59+
"block": ["paragraph"],
60+
"core": ["normalize", "block"],
61+
"inline": ["text"],
62+
}
63+
md.disable(["text"])
64+
assert md.get_active_rules() == {
65+
"block": ["paragraph"],
66+
"core": ["normalize", "block"],
67+
"inline": [],
68+
}

0 commit comments

Comments
 (0)