From aa57244e71bf7e94f14eb66649ec118f830e9616 Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Fri, 26 Feb 2021 03:28:50 +0200 Subject: [PATCH 01/11] Attempt to make SyntaxTreeNode type annotations work when subclassing --- markdown_it/tree.py | 48 ++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index c0036139..5fe7aa06 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -2,13 +2,27 @@ This module is not part of upstream JavaScript markdown-it. """ -from typing import NamedTuple, Sequence, Tuple, Dict, List, Optional, Any +from typing import ( + NamedTuple, + Sequence, + Tuple, + Dict, + List, + Optional, + Any, + TypeVar, + Type, + Generic, +) from .token import Token from .utils import _removesuffix -class SyntaxTreeNode: +_T = TypeVar("_T", bound="SyntaxTreeNodeBase") + + +class SyntaxTreeNodeBase(Generic[_T]): """A Markdown syntax tree node. A class that can be used to construct a tree representation of a linear @@ -35,17 +49,17 @@ def __init__(self) -> None: self.token: Optional[Token] = None # Only containers have nester tokens - self.nester_tokens: Optional[SyntaxTreeNode._NesterTokens] = None + self.nester_tokens: Optional[SyntaxTreeNodeBase._NesterTokens] = None # Root node does not have self.parent - self.parent: Optional["SyntaxTreeNode"] = None + self.parent: Optional[_T] = None # Empty list unless a non-empty container, or unnested token that has # children (i.e. inline or img) - self.children: List["SyntaxTreeNode"] = [] + self.children: List[_T] = [] @classmethod - def from_tokens(cls, tokens: Sequence[Token]) -> "SyntaxTreeNode": + def from_tokens(cls: Type[_T], tokens: Sequence[Token]) -> _T: """Instantiate a `SyntaxTreeNode` from a token stream. This is the standard method for instantiating `SyntaxTreeNode`. @@ -54,12 +68,10 @@ def from_tokens(cls, tokens: Sequence[Token]) -> "SyntaxTreeNode": root._set_children_from_tokens(tokens) return root - def to_tokens(self) -> List[Token]: + def to_tokens(self: _T) -> List[Token]: """Recover the linear token stream.""" - def recursive_collect_tokens( - node: "SyntaxTreeNode", token_list: List[Token] - ) -> None: + def recursive_collect_tokens(node: _T, token_list: List[Token]) -> None: if node.type == "root": for child in node.children: recursive_collect_tokens(child, token_list) @@ -87,7 +99,7 @@ def is_nested(self) -> bool: return bool(self.nester_tokens) @property - def siblings(self) -> Sequence["SyntaxTreeNode"]: + def siblings(self: _T) -> Sequence[_T]: """Get siblings of the node. Gets the whole group of siblings, including self. @@ -113,7 +125,7 @@ def type(self) -> str: return _removesuffix(self.nester_tokens.opening.type, "_open") @property - def next_sibling(self) -> Optional["SyntaxTreeNode"]: + def next_sibling(self: _T) -> Optional[_T]: """Get the next node in the sequence of siblings. Returns `None` if this is the last sibling. @@ -124,7 +136,7 @@ def next_sibling(self) -> Optional["SyntaxTreeNode"]: return None @property - def previous_sibling(self) -> Optional["SyntaxTreeNode"]: + def previous_sibling(self: _T) -> Optional[_T]: """Get the previous node in the sequence of siblings. Returns `None` if this is the first sibling. @@ -135,11 +147,11 @@ def previous_sibling(self) -> Optional["SyntaxTreeNode"]: return None def _make_child( - self, + self: _T, *, token: Optional[Token] = None, nester_tokens: Optional[_NesterTokens] = None, - ) -> "SyntaxTreeNode": + ) -> _T: """Make and return a child node for `self`.""" if token and nester_tokens or not token and not nester_tokens: raise ValueError("must specify either `token` or `nester_tokens`") @@ -177,7 +189,7 @@ def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: raise ValueError(f"unclosed tokens starting {nested_tokens[0]}") child = self._make_child( - nester_tokens=SyntaxTreeNode._NesterTokens( + nester_tokens=SyntaxTreeNodeBase._NesterTokens( nested_tokens[0], nested_tokens[-1] ) ) @@ -260,3 +272,7 @@ def hidden(self) -> bool: """If it's true, ignore this element when rendering. Used for tight lists to hide paragraphs.""" return self._attribute_token().hidden + + +class SyntaxTreeNode(SyntaxTreeNodeBase["SyntaxTreeNode"]): + pass From fce3d214efc686b03907eea1d543a59edb944e03 Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Fri, 26 Feb 2021 05:34:33 +0200 Subject: [PATCH 02/11] Make _parent and _children properties --- markdown_it/tree.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index 5fe7aa06..9d4259c0 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -12,17 +12,16 @@ Any, TypeVar, Type, - Generic, ) from .token import Token from .utils import _removesuffix -_T = TypeVar("_T", bound="SyntaxTreeNodeBase") +_T = TypeVar("_T", bound="SyntaxTreeNode") -class SyntaxTreeNodeBase(Generic[_T]): +class SyntaxTreeNode: """A Markdown syntax tree node. A class that can be used to construct a tree representation of a linear @@ -49,14 +48,14 @@ def __init__(self) -> None: self.token: Optional[Token] = None # Only containers have nester tokens - self.nester_tokens: Optional[SyntaxTreeNodeBase._NesterTokens] = None + self.nester_tokens: Optional[SyntaxTreeNode._NesterTokens] = None # Root node does not have self.parent - self.parent: Optional[_T] = None + self._parent: Any = None # Optional[_T] # Empty list unless a non-empty container, or unnested token that has # children (i.e. inline or img) - self.children: List[_T] = [] + self._children: list = [] # List[_T] @classmethod def from_tokens(cls: Type[_T], tokens: Sequence[Token]) -> _T: @@ -88,6 +87,14 @@ def recursive_collect_tokens(node: _T, token_list: List[Token]) -> None: recursive_collect_tokens(self, tokens) return tokens + @property + def children(self: _T) -> Sequence[_T]: + return self._children + + @property + def parent(self: _T) -> Optional[_T]: + return self._parent + @property def is_nested(self) -> bool: """Is this node nested?. @@ -160,8 +167,8 @@ def _make_child( child.token = token else: child.nester_tokens = nester_tokens - child.parent = self - self.children.append(child) + child._parent = self + self._children.append(child) return child def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: @@ -189,7 +196,7 @@ def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: raise ValueError(f"unclosed tokens starting {nested_tokens[0]}") child = self._make_child( - nester_tokens=SyntaxTreeNodeBase._NesterTokens( + nester_tokens=SyntaxTreeNode._NesterTokens( nested_tokens[0], nested_tokens[-1] ) ) @@ -272,7 +279,3 @@ def hidden(self) -> bool: """If it's true, ignore this element when rendering. Used for tight lists to hide paragraphs.""" return self._attribute_token().hidden - - -class SyntaxTreeNode(SyntaxTreeNodeBase["SyntaxTreeNode"]): - pass From aea99cedb7157f30f30e177be46f2524319fd4ee Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Sat, 27 Feb 2021 03:30:45 +0200 Subject: [PATCH 03/11] Move _NesterTokens to module level now that SyntaxTreeNode has its own module --- markdown_it/tree.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index 9d4259c0..dbe7b38a 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -18,6 +18,11 @@ from .utils import _removesuffix +class _NesterTokens(NamedTuple): + opening: Token + closing: Token + + _T = TypeVar("_T", bound="SyntaxTreeNode") @@ -35,10 +40,6 @@ class SyntaxTreeNode: between """ - class _NesterTokens(NamedTuple): - opening: Token - closing: Token - def __init__(self) -> None: """Initialize a root node with no children. @@ -48,7 +49,7 @@ def __init__(self) -> None: self.token: Optional[Token] = None # Only containers have nester tokens - self.nester_tokens: Optional[SyntaxTreeNode._NesterTokens] = None + self.nester_tokens: Optional[_NesterTokens] = None # Root node does not have self.parent self._parent: Any = None # Optional[_T] @@ -196,9 +197,7 @@ def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: raise ValueError(f"unclosed tokens starting {nested_tokens[0]}") child = self._make_child( - nester_tokens=SyntaxTreeNode._NesterTokens( - nested_tokens[0], nested_tokens[-1] - ) + nester_tokens=_NesterTokens(nested_tokens[0], nested_tokens[-1]) ) child._set_children_from_tokens(nested_tokens[1:-1]) From 1b4e817faa8549d6ff265f1c2d857a2b4ca11aca Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Sun, 28 Feb 2021 04:40:37 +0200 Subject: [PATCH 04/11] Add setters for `parent` and `children` --- markdown_it/tree.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index dbe7b38a..5acdff2a 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -52,11 +52,11 @@ def __init__(self) -> None: self.nester_tokens: Optional[_NesterTokens] = None # Root node does not have self.parent - self._parent: Any = None # Optional[_T] + self.parent = None # Empty list unless a non-empty container, or unnested token that has # children (i.e. inline or img) - self._children: list = [] # List[_T] + self.children = [] @classmethod def from_tokens(cls: Type[_T], tokens: Sequence[Token]) -> _T: @@ -89,13 +89,21 @@ def recursive_collect_tokens(node: _T, token_list: List[Token]) -> None: return tokens @property - def children(self: _T) -> Sequence[_T]: + def children(self: _T) -> List[_T]: return self._children + @children.setter + def children(self: _T, value: List[_T]) -> None: + self._children = value + @property def parent(self: _T) -> Optional[_T]: return self._parent + @parent.setter + def parent(self: _T, value: Optional[_T]) -> None: + self._parent = value + @property def is_nested(self) -> bool: """Is this node nested?. @@ -168,8 +176,8 @@ def _make_child( child.token = token else: child.nester_tokens = nester_tokens - child._parent = self - self._children.append(child) + child.parent = self + self.children.append(child) return child def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: From 54188a35100751ab74d1745439904fa3d56fe022 Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Sun, 28 Feb 2021 14:36:16 +0200 Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=91=8C=20IMPROVE:=20Use=20regular?= =?UTF-8?q?=20=5F=5Finit=5F=5F=20to=20create=20SyntaxTreeNodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- markdown_it/tree.py | 70 +++++++++++++++++++-------------------------- tests/test_tree.py | 8 +++--- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index 5acdff2a..71da3ca1 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -11,7 +11,6 @@ Optional, Any, TypeVar, - Type, ) from .token import Token @@ -30,8 +29,7 @@ class SyntaxTreeNode: """A Markdown syntax tree node. A class that can be used to construct a tree representation of a linear - `markdown-it-py` token stream. Use `SyntaxTreeNode.from_tokens` to - initialize instead of the `__init__` method. + `markdown-it-py` token stream. Each node in the tree represents either: - root of the Markdown document @@ -40,33 +38,39 @@ class SyntaxTreeNode: between """ - def __init__(self) -> None: - """Initialize a root node with no children. + def __init__( + self, tokens: Sequence[Token] = (), *, create_root: bool = True + ) -> None: + """Initialize a `SyntaxTreeNode` from a token stream. - You probably need `SyntaxTreeNode.from_tokens` instead. + If `create_root` is True, crete a root node for the document. """ # Only nodes representing an unnested token have self.token self.token: Optional[Token] = None - # Only containers have nester tokens self.nester_tokens: Optional[_NesterTokens] = None - # Root node does not have self.parent self.parent = None - # Empty list unless a non-empty container, or unnested token that has # children (i.e. inline or img) self.children = [] - @classmethod - def from_tokens(cls: Type[_T], tokens: Sequence[Token]) -> _T: - """Instantiate a `SyntaxTreeNode` from a token stream. - - This is the standard method for instantiating `SyntaxTreeNode`. - """ - root = cls() - root._set_children_from_tokens(tokens) - return root + if create_root: + self._set_children_from_tokens(tokens) + return + + if not tokens: + raise ValueError("can only create root from empty token sequence") + elif len(tokens) == 1: + tkn = tokens[0] + assert not tkn.nesting + self.token = tkn + if tkn.children: + self._set_children_from_tokens(tkn.children) + return + else: + self.nester_tokens = _NesterTokens(tokens[0], tokens[-1]) + self._set_children_from_tokens(tokens[1:-1]) def to_tokens(self: _T) -> List[Token]: """Recover the linear token stream.""" @@ -162,23 +166,14 @@ def previous_sibling(self: _T) -> Optional[_T]: return self.siblings[self_index - 1] return None - def _make_child( - self: _T, - *, - token: Optional[Token] = None, - nester_tokens: Optional[_NesterTokens] = None, - ) -> _T: - """Make and return a child node for `self`.""" - if token and nester_tokens or not token and not nester_tokens: - raise ValueError("must specify either `token` or `nester_tokens`") - child = type(self)() - if token: - child.token = token - else: - child.nester_tokens = nester_tokens + def _add_child( + self, + tokens: Sequence[Token], + ) -> None: + """Make a child node for `self`.""" + child = type(self)(tokens, create_root=False) child.parent = self self.children.append(child) - return child def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: """Convert the token stream to a tree structure and set the resulting @@ -188,9 +183,7 @@ def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: token = reversed_tokens.pop() if token.nesting == 0: - child = self._make_child(token=token) - if token.children: - child._set_children_from_tokens(token.children) + self._add_child([token]) continue assert token.nesting == 1 @@ -204,10 +197,7 @@ def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: if nesting != 0: raise ValueError(f"unclosed tokens starting {nested_tokens[0]}") - child = self._make_child( - nester_tokens=_NesterTokens(nested_tokens[0], nested_tokens[-1]) - ) - child._set_children_from_tokens(nested_tokens[1:-1]) + self._add_child(nested_tokens) # NOTE: # The values of the properties defined below directly map to properties diff --git a/tests/test_tree.py b/tests/test_tree.py index d6dadec9..b8d7ff01 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -10,14 +10,14 @@ def test_tree_to_tokens_conversion(): tokens = MarkdownIt().parse(EXAMPLE_MARKDOWN) - tokens_after_roundtrip = SyntaxTreeNode.from_tokens(tokens).to_tokens() + tokens_after_roundtrip = SyntaxTreeNode(tokens).to_tokens() assert tokens == tokens_after_roundtrip def test_property_passthrough(): tokens = MarkdownIt().parse(EXAMPLE_MARKDOWN) heading_open = tokens[0] - tree = SyntaxTreeNode.from_tokens(tokens) + tree = SyntaxTreeNode(tokens) heading_node = tree.children[0] assert heading_open.tag == heading_node.tag assert tuple(heading_open.map) == heading_node.map @@ -32,7 +32,7 @@ def test_property_passthrough(): def test_type(): tokens = MarkdownIt().parse(EXAMPLE_MARKDOWN) - tree = SyntaxTreeNode.from_tokens(tokens) + tree = SyntaxTreeNode(tokens) # Root type is "root" assert tree.type == "root" # "_open" suffix must be stripped from nested token type @@ -43,7 +43,7 @@ def test_type(): def test_sibling_traverse(): tokens = MarkdownIt().parse(EXAMPLE_MARKDOWN) - tree = SyntaxTreeNode.from_tokens(tokens) + tree = SyntaxTreeNode(tokens) paragraph_inline_node = tree.children[1].children[0] text_node = paragraph_inline_node.children[0] assert text_node.type == "text" From 50ae360040bfae3c8e3c8a87cb996e4ba39778fa Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Sun, 28 Feb 2021 14:59:53 +0200 Subject: [PATCH 06/11] Improve error message --- markdown_it/tree.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index 71da3ca1..b9f29106 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -60,14 +60,16 @@ def __init__( return if not tokens: - raise ValueError("can only create root from empty token sequence") + raise ValueError( + "Can only create root from empty token sequence." + " Set `create_root=True`." + ) elif len(tokens) == 1: tkn = tokens[0] assert not tkn.nesting self.token = tkn if tkn.children: self._set_children_from_tokens(tkn.children) - return else: self.nester_tokens = _NesterTokens(tokens[0], tokens[-1]) self._set_children_from_tokens(tokens[1:-1]) From 300e53929c6154b55b31a9c8295d067a1b08938a Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Sun, 28 Feb 2021 16:44:00 +0200 Subject: [PATCH 07/11] Minor tweaks --- markdown_it/tree.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index b9f29106..7f150cd6 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -65,11 +65,11 @@ def __init__( " Set `create_root=True`." ) elif len(tokens) == 1: - tkn = tokens[0] - assert not tkn.nesting - self.token = tkn - if tkn.children: - self._set_children_from_tokens(tkn.children) + inline_token = tokens[0] + assert not inline_token.nesting + self.token = inline_token + if inline_token.children: + self._set_children_from_tokens(inline_token.children) else: self.nester_tokens = _NesterTokens(tokens[0], tokens[-1]) self._set_children_from_tokens(tokens[1:-1]) @@ -184,19 +184,19 @@ def _set_children_from_tokens(self, tokens: Sequence[Token]) -> None: while reversed_tokens: token = reversed_tokens.pop() - if token.nesting == 0: + if not token.nesting: self._add_child([token]) continue - - assert token.nesting == 1 + if token.nesting != 1: + raise ValueError("Invalid token nesting") nested_tokens = [token] nesting = 1 - while reversed_tokens and nesting != 0: + while reversed_tokens and nesting: token = reversed_tokens.pop() nested_tokens.append(token) nesting += token.nesting - if nesting != 0: + if nesting: raise ValueError(f"unclosed tokens starting {nested_tokens[0]}") self._add_child(nested_tokens) From e5f709bbc153d791cf6dbdb641ff6ce3c154dd77 Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Thu, 4 Mar 2021 02:28:45 +0200 Subject: [PATCH 08/11] Address PR review --- markdown_it/tree.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index 4c984860..007ed833 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -24,7 +24,7 @@ class _NesterTokens(NamedTuple): closing: Token -_T = TypeVar("_T", bound="SyntaxTreeNode") +_NodeType = TypeVar("_NodeType", bound="SyntaxTreeNode") class SyntaxTreeNode: @@ -53,11 +53,11 @@ def __init__(self) -> None: self.nester_tokens: Optional[_NesterTokens] = None # Root node does not have self.parent - self.parent = None + self._parent: Any = None # Empty list unless a non-empty container, or unnested token that has # children (i.e. inline or img) - self.children = [] + self._children: list = [] def __repr__(self) -> str: return f"{type(self).__name__}({self.type})" @@ -66,7 +66,7 @@ def __getitem__(self, item: int) -> "SyntaxTreeNode": return self.children[item] @classmethod - def from_tokens(cls: Type[_T], tokens: Sequence[Token]) -> _T: + def from_tokens(cls: Type[_NodeType], tokens: Sequence[Token]) -> _NodeType: """Instantiate a `SyntaxTreeNode` from a token stream. This is the standard method for instantiating `SyntaxTreeNode`. @@ -75,10 +75,10 @@ def from_tokens(cls: Type[_T], tokens: Sequence[Token]) -> _T: root._set_children_from_tokens(tokens) return root - def to_tokens(self: _T) -> List[Token]: + def to_tokens(self: _NodeType) -> List[Token]: """Recover the linear token stream.""" - def recursive_collect_tokens(node: _T, token_list: List[Token]) -> None: + def recursive_collect_tokens(node: _NodeType, token_list: List[Token]) -> None: if node.type == "root": for child in node.children: recursive_collect_tokens(child, token_list) @@ -96,19 +96,19 @@ def recursive_collect_tokens(node: _T, token_list: List[Token]) -> None: return tokens @property - def children(self: _T) -> List[_T]: + def children(self: _NodeType) -> List[_NodeType]: return self._children @children.setter - def children(self: _T, value: List[_T]) -> None: + def children(self: _NodeType, value: List[_NodeType]) -> None: self._children = value @property - def parent(self: _T) -> Optional[_T]: + def parent(self: _NodeType) -> Optional[_NodeType]: return self._parent @parent.setter - def parent(self: _T, value: Optional[_T]) -> None: + def parent(self: _NodeType, value: Optional[_NodeType]) -> None: self._parent = value @property @@ -127,7 +127,7 @@ def is_nested(self) -> bool: return bool(self.nester_tokens) @property - def siblings(self: _T) -> Sequence[_T]: + def siblings(self: _NodeType) -> Sequence[_NodeType]: """Get siblings of the node. Gets the whole group of siblings, including self. @@ -153,7 +153,7 @@ def type(self) -> str: return _removesuffix(self.nester_tokens.opening.type, "_open") @property - def next_sibling(self: _T) -> Optional[_T]: + def next_sibling(self: _NodeType) -> Optional[_NodeType]: """Get the next node in the sequence of siblings. Returns `None` if this is the last sibling. @@ -164,7 +164,7 @@ def next_sibling(self: _T) -> Optional[_T]: return None @property - def previous_sibling(self: _T) -> Optional[_T]: + def previous_sibling(self: _NodeType) -> Optional[_NodeType]: """Get the previous node in the sequence of siblings. Returns `None` if this is the first sibling. @@ -175,11 +175,11 @@ def previous_sibling(self: _T) -> Optional[_T]: return None def _make_child( - self: _T, + self: _NodeType, *, token: Optional[Token] = None, nester_tokens: Optional[_NesterTokens] = None, - ) -> _T: + ) -> _NodeType: """Make and return a child node for `self`.""" if token and nester_tokens or not token and not nester_tokens: raise ValueError("must specify either `token` or `nester_tokens`") From 68585afd2be5170c8b2cf145b999aaad25fd830c Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Thu, 4 Mar 2021 02:51:14 +0200 Subject: [PATCH 09/11] Fix `from_tokens` references --- docs/using.md | 2 +- tests/test_tree.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/using.md b/docs/using.md index ec21b6bc..c07f32e7 100644 --- a/docs/using.md +++ b/docs/using.md @@ -265,7 +265,7 @@ Here's some text and an image ![title](image.png) > a *quote* """) -node = SyntaxTreeNode.from_tokens(tokens) +node = SyntaxTreeNode(tokens) print(node.pretty(indent=2, show_text=True)) ``` diff --git a/tests/test_tree.py b/tests/test_tree.py index 754e73d2..6e0fd1ed 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -70,5 +70,5 @@ def test_pretty(file_regression): > a *quote* """ ) - node = SyntaxTreeNode.from_tokens(tokens) + node = SyntaxTreeNode(tokens) file_regression.check(node.pretty(indent=2, show_text=True), extension=".xml") From c0b698af9318ccc8c8c4f3b91a1f5a0a2d4739a4 Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Thu, 4 Mar 2021 16:36:07 +0200 Subject: [PATCH 10/11] Fix __getitem__ type annotation --- markdown_it/tree.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index 007ed833..58398d9a 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -13,6 +13,8 @@ Any, TypeVar, Type, + overload, + Union, ) from .token import Token @@ -62,7 +64,17 @@ def __init__(self) -> None: def __repr__(self) -> str: return f"{type(self).__name__}({self.type})" - def __getitem__(self, item: int) -> "SyntaxTreeNode": + @overload + def __getitem__(self: _NodeType, item: int) -> _NodeType: + ... + + @overload + def __getitem__(self: _NodeType, item: slice) -> List[_NodeType]: + ... + + def __getitem__( + self: _NodeType, item: Union[int, slice] + ) -> Union[_NodeType, List[_NodeType]]: return self.children[item] @classmethod From 48701593f0879729f3992b7bba67efb9cb05ec65 Mon Sep 17 00:00:00 2001 From: Taneli Hukkinen Date: Wed, 10 Mar 2021 16:47:09 +0200 Subject: [PATCH 11/11] Address PR review --- markdown_it/tree.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/markdown_it/tree.py b/markdown_it/tree.py index 810c39f1..fac28dd5 100644 --- a/markdown_it/tree.py +++ b/markdown_it/tree.py @@ -46,7 +46,7 @@ def __init__( ) -> None: """Initialize a `SyntaxTreeNode` from a token stream. - If `create_root` is True, crete a root node for the document. + If `create_root` is True, create a root node for the document. """ # Only nodes representing an unnested token have self.token self.token: Optional[Token] = None @@ -72,7 +72,10 @@ def __init__( ) elif len(tokens) == 1: inline_token = tokens[0] - assert not inline_token.nesting + if inline_token.nesting: + raise ValueError( + "Unequal nesting level at the start and end of token stream." + ) self.token = inline_token if inline_token.children: self._set_children_from_tokens(inline_token.children)