Recursion Error: Process_element / process_tag mutual recursion (infinite loop)
評価
調査の方向性
markdownify/init.py で process_element と process_tag を読むことから始め、循環参照を含む HTML ツリーで RecursionError を再現します。子要素の処理が両方のメソッドを通過する経路を追跡し、通常の HTML 変換を変更せずに、スタックを使い果たすことなく変換が終了することを確認します。
索引モデルが issue の本文から書いたものです。
説明
When converting HTML that contains circular parent-child references in the parsed BeautifulSoup tree (produced by certain PDF-to-HTML pipelines), process_element and process_tag recurse infinitely, crashing with a RecursionError.
Encountered when using markdownify via marker-pdf to convert PDF documents. The HTML produced by the PDF parser contained structures that caused BeautifulSoup's html.parser to create a non-tree graph where a descendant node held a reference back to an ancestor creating an unbounded call stack.
The mutual recursion introduced in 1.2.2 between process_element and process_tag has no cycle guard:
- process_tag iterates node.children and calls process_element for each child
- process_element calls process_tag for any Tag node
RecursionError: maximum recursion depth exceeded
File "markdownify/__init__.py", line 232, in process_element
return self.process_tag(node, parent_tags=parent_tags)
File "markdownify/__init__.py", line 287, in process_tag
child_strings = [
File "markdownify/__init__.py", line 288, in <listcomp>
self.process_element(el, parent_tags=parent_tags_for_children)
File "markdownify/__init__.py", line 232, in process_element
return self.process_tag(node, parent_tags=parent_tags)
... (repeating until stack exhausted)
Suggested fix:
Pass a visited set of node ids through the call chain to detect and break cycles:
def process_element(self, node, parent_tags=None, _visited=None):
if isinstance(node, NavigableString):
return self.process_text(node, parent_tags=parent_tags)
else:
return self.process_tag(node, parent_tags=parent_tags, _visited=_visited)
def process_tag(self, node, parent_tags=None, _visited=None):
if parent_tags is None:
parent_tags = set()
# Cycle detection
if _visited is None:
_visited = set()
node_id = id(node)
if node_id in _visited:
return ''
_visited.add(node_id)
# ... rest of method unchanged, but pass _visited= to process_element calls
child_strings = [
self.process_element(el, parent_tags=parent_tags_for_children, _visited=_visited)
for el in children_to_convert
]
- 主要言語
- Python
- スター
- 2.3k
- フォーク
- 210
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
matthewwithanm/python-markdownify のほかの issue
-
Trailing whitespace strip in <pre> is quadratic on a long whitespace run対応中かも @ac1982 が 5 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
RecursionError on deeply nested HTML (about 330 levels), separate from the cyclic-tree case in #256対応中かも @HardMax71 が 42 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 68/100
-
Image/link attributes containing `]`, `)`, or spaces produce broken Markdown output対応中かも @assinscreedFC が 132 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 52/100
matthewwithanm/python-markdownify#261 · コメント 1 件 · リアクション 1 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 65/100
matthewwithanm/python-markdownify#259 · リアクション 2 件 ·
-
Behavior with strip_pre=mdfy.STRIP_ONE seems incorrect with trailing newlines within the pre対応中かも @oiahoon が 95 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 50/100
matthewwithanm/python-markdownify の issue をすべて見る
似ている issue
-
documentation good first issue
難易度 2/5 半日 初心者へのやさしさ 72/100
sujithputta02/Esapay#13 ·
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
メンテナーはふだん 1 日以内に返信
-
needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
gke-labs/kube-agents#3277 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
jbacalso24/mimry#291 ·
メンテナーはふだん 1 日以内に返信
-
good first issue
難易度 2/5 1時間未満 初心者へのやさしさ 82/100
eli-alvarado/us-watchlist-alerts#14 ·
メンテナーはふだん 1 日以内に返信