markdown-parser-py


Namemarkdown-parser-py JSON
Version 1.0.0 PyPI version JSON
download
home_pageNone
SummaryParse, Manipulate, and Merge Markdown Heading Trees Programmatically.
upload_time2025-08-30 15:40:22
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseMIT
keywords markdown parser tree document
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center">

# markdown-parser-py

Turn raw Markdown into a manipulable heading tree, edit it programmatically, then emit valid Markdown again.

![status](https://img.shields.io/badge/status-experimental-orange)
![python](https://img.shields.io/badge/python-3.10+-blue)

</div>

## ✨ Features

- Parse Markdown into a hierarchical tree of headings (levels 1–6)
- Preserve and round‑trip section body content
- Query sections via simple dot paths (e.g. `Introduction.Installation.Windows`)
- Add / remove sections dynamically
- Attach (merge) whole subtrees across different Markdown documents with automatic heading level adjustment
- Dump back to Markdown or visualize structure in a `tree`-like ASCII output

## πŸ“¦ Installation

```bash
pip install markdown-parser-py
```

or, for an editable install

```bash
git clone https://github.com/VarunGumma/markdown-parser-py
cd markdown-parser-py
pip install -e ./
```

## 🧠 Core Concepts

The model is minimal:

```text
MarkdownTree
└── root (MarkdownNode level=0, title="ROOT")
	β”œβ”€β”€ Child heading (level=1 => '#')
	β”‚   └── Grandchild (level=2 => '##')
	└── ...
```

Each `MarkdownNode` stores:

- `level`: 0 for synthetic root; 1–6 for real headings
- `title`: heading text
- `content`: list of raw paragraph / code / list text blocks under that heading (excluding child headings)
- `children`: nested headings

## πŸš€ Quick Start

```python
from markdown_parser import MarkdownTree

doc = """
# Intro
Some intro text.

## Install
Run `pip install x`.

## Usage
Basic usage here.

### CLI
Run `tool`.
"""

tree = MarkdownTree()
tree.parse(doc)

print('\n=== Visualize ===')
tree.visualize()

print('\n=== Dump Round Trip ===')
print(tree.dump())
```

Output (visualize):

```text
└── # Intro
	β”œβ”€β”€ ## Install
	└── ## Usage
		└── ### CLI
```

## πŸ” Finding Sections

```python
node = tree.find_node_by_path('Intro.Install')  # '# Intro' > '## Install'
if node:
	print('Found:', node.title, 'level', node.level)
```

Dot paths walk downward by titles. A single component path refers to a top‑level heading (level 1). Returns `None` if not found.

## βž• Adding Sections

```python
new = tree.add_section('Intro', 'Advanced', content='Deep dive coming soon.')
print('Added at level', new.level)
```

If `parent_path` is `""` or `"ROOT"`, the new section becomes a top‑level heading.

## βž– Removing Sections

```python
tree.remove_section('Intro.Advanced')  # removes that subtree
```

## πŸ”— Attaching / Merging Subtrees

You can merge content from another parsed Markdown document. Levels auto-adjust so the attached subtree root sits exactly one level below the chosen parent.

```python
from markdown_parser import MarkdownTree

base = MarkdownTree()
base.parse('# A\nIntro text.')

other = MarkdownTree()
other.parse('# Extra\nStuff here.\n\n## Deep\nDetails.')

# Attach ALL top-level sections from other under 'A'
base.attach_subtree('A', other)  # Equivalent to source_path=None

# Or attach only a specific subsection
# base.attach_subtree('A', other, source_path='Extra.Deep')

base.visualize()
print(base.dump())
```

If you attach the full tree (`source_path=None` / `'ROOT'`), each top-level section in the source is cloned with level adjusted: `new_level = parent.level + original_level`.

## πŸ§ͺ Advanced Example: Composing Documents

```python
def compose(product_readme: str, appendix_md: str) -> str:
	main_tree = MarkdownTree()
	main_tree.parse(product_readme)

	appendix_tree = MarkdownTree()
	appendix_tree.parse(appendix_md)

	# Ensure an Appendix section exists
	if not main_tree.find_node_by_path('Appendix'):
		main_tree.add_section('', 'Appendix')

	# Attach all appendix top-level sections under Appendix
	main_tree.attach_subtree('Appendix', appendix_tree)
	return main_tree.dump()
```

## πŸ“ Disclaimer

This is an early/experimental utility. Edge cases (nested fenced code blocks, Setext headings, ATX heading oddities, HTML blocks) are not fully supported yet.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "markdown-parser-py",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "markdown, parser, tree, document",
    "author": null,
    "author_email": "Varun Gumma <varun230999@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/07/2a/621698ebde3f546e6a8756838bdb81a0c55c8a805b7e34ace972284440ac/markdown_parser_py-1.0.0.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\n\n# markdown-parser-py\n\nTurn raw Markdown into a manipulable heading tree, edit it programmatically, then emit valid Markdown again.\n\n![status](https://img.shields.io/badge/status-experimental-orange)\n![python](https://img.shields.io/badge/python-3.10+-blue)\n\n</div>\n\n## \u2728 Features\n\n- Parse Markdown into a hierarchical tree of headings (levels 1\u20136)\n- Preserve and round\u2011trip section body content\n- Query sections via simple dot paths (e.g. `Introduction.Installation.Windows`)\n- Add / remove sections dynamically\n- Attach (merge) whole subtrees across different Markdown documents with automatic heading level adjustment\n- Dump back to Markdown or visualize structure in a `tree`-like ASCII output\n\n## \ud83d\udce6 Installation\n\n```bash\npip install markdown-parser-py\n```\n\nor, for an editable install\n\n```bash\ngit clone https://github.com/VarunGumma/markdown-parser-py\ncd markdown-parser-py\npip install -e ./\n```\n\n## \ud83e\udde0 Core Concepts\n\nThe model is minimal:\n\n```text\nMarkdownTree\n\u2514\u2500\u2500 root (MarkdownNode level=0, title=\"ROOT\")\n\t\u251c\u2500\u2500 Child heading (level=1 => '#')\n\t\u2502   \u2514\u2500\u2500 Grandchild (level=2 => '##')\n\t\u2514\u2500\u2500 ...\n```\n\nEach `MarkdownNode` stores:\n\n- `level`: 0 for synthetic root; 1\u20136 for real headings\n- `title`: heading text\n- `content`: list of raw paragraph / code / list text blocks under that heading (excluding child headings)\n- `children`: nested headings\n\n## \ud83d\ude80 Quick Start\n\n```python\nfrom markdown_parser import MarkdownTree\n\ndoc = \"\"\"\n# Intro\nSome intro text.\n\n## Install\nRun `pip install x`.\n\n## Usage\nBasic usage here.\n\n### CLI\nRun `tool`.\n\"\"\"\n\ntree = MarkdownTree()\ntree.parse(doc)\n\nprint('\\n=== Visualize ===')\ntree.visualize()\n\nprint('\\n=== Dump Round Trip ===')\nprint(tree.dump())\n```\n\nOutput (visualize):\n\n```text\n\u2514\u2500\u2500 # Intro\n\t\u251c\u2500\u2500 ## Install\n\t\u2514\u2500\u2500 ## Usage\n\t\t\u2514\u2500\u2500 ### CLI\n```\n\n## \ud83d\udd0d Finding Sections\n\n```python\nnode = tree.find_node_by_path('Intro.Install')  # '# Intro' > '## Install'\nif node:\n\tprint('Found:', node.title, 'level', node.level)\n```\n\nDot paths walk downward by titles. A single component path refers to a top\u2011level heading (level 1). Returns `None` if not found.\n\n## \u2795 Adding Sections\n\n```python\nnew = tree.add_section('Intro', 'Advanced', content='Deep dive coming soon.')\nprint('Added at level', new.level)\n```\n\nIf `parent_path` is `\"\"` or `\"ROOT\"`, the new section becomes a top\u2011level heading.\n\n## \u2796 Removing Sections\n\n```python\ntree.remove_section('Intro.Advanced')  # removes that subtree\n```\n\n## \ud83d\udd17 Attaching / Merging Subtrees\n\nYou can merge content from another parsed Markdown document. Levels auto-adjust so the attached subtree root sits exactly one level below the chosen parent.\n\n```python\nfrom markdown_parser import MarkdownTree\n\nbase = MarkdownTree()\nbase.parse('# A\\nIntro text.')\n\nother = MarkdownTree()\nother.parse('# Extra\\nStuff here.\\n\\n## Deep\\nDetails.')\n\n# Attach ALL top-level sections from other under 'A'\nbase.attach_subtree('A', other)  # Equivalent to source_path=None\n\n# Or attach only a specific subsection\n# base.attach_subtree('A', other, source_path='Extra.Deep')\n\nbase.visualize()\nprint(base.dump())\n```\n\nIf you attach the full tree (`source_path=None` / `'ROOT'`), each top-level section in the source is cloned with level adjusted: `new_level = parent.level + original_level`.\n\n## \ud83e\uddea Advanced Example: Composing Documents\n\n```python\ndef compose(product_readme: str, appendix_md: str) -> str:\n\tmain_tree = MarkdownTree()\n\tmain_tree.parse(product_readme)\n\n\tappendix_tree = MarkdownTree()\n\tappendix_tree.parse(appendix_md)\n\n\t# Ensure an Appendix section exists\n\tif not main_tree.find_node_by_path('Appendix'):\n\t\tmain_tree.add_section('', 'Appendix')\n\n\t# Attach all appendix top-level sections under Appendix\n\tmain_tree.attach_subtree('Appendix', appendix_tree)\n\treturn main_tree.dump()\n```\n\n## \ud83d\udcdd Disclaimer\n\nThis is an early/experimental utility. Edge cases (nested fenced code blocks, Setext headings, ATX heading oddities, HTML blocks) are not fully supported yet.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Parse, Manipulate, and Merge Markdown Heading Trees Programmatically.",
    "version": "1.0.0",
    "project_urls": {
        "Homepage": "https://github.com/VarunGumma/markdown-parser-py",
        "Issues": "https://github.com/VarunGumma/markdown-parser-py/issues",
        "Repository": "https://github.com/VarunGumma/markdown-parser-py"
    },
    "split_keywords": [
        "markdown",
        " parser",
        " tree",
        " document"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "eb82718cd67b73513727b59d37be8cc0d7a323db4b6309fd4a3baa3c01354413",
                "md5": "3fb6a3731b021389a0d97edfab674332",
                "sha256": "d7de3ccd6a18c38b49a0c52b30c3493afca58670fbb2ef31633c8cc43a6e00d7"
            },
            "downloads": -1,
            "filename": "markdown_parser_py-1.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3fb6a3731b021389a0d97edfab674332",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 7119,
            "upload_time": "2025-08-30T15:40:16",
            "upload_time_iso_8601": "2025-08-30T15:40:16.411380Z",
            "url": "https://files.pythonhosted.org/packages/eb/82/718cd67b73513727b59d37be8cc0d7a323db4b6309fd4a3baa3c01354413/markdown_parser_py-1.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "072a621698ebde3f546e6a8756838bdb81a0c55c8a805b7e34ace972284440ac",
                "md5": "b20c9f8d88af02b847e2390b43dbe178",
                "sha256": "aee2fce3dc15de4f716b51886986b70eb531f49498e223459ba636135bcc273e"
            },
            "downloads": -1,
            "filename": "markdown_parser_py-1.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "b20c9f8d88af02b847e2390b43dbe178",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 6548,
            "upload_time": "2025-08-30T15:40:22",
            "upload_time_iso_8601": "2025-08-30T15:40:22.601589Z",
            "url": "https://files.pythonhosted.org/packages/07/2a/621698ebde3f546e6a8756838bdb81a0c55c8a805b7e34ace972284440ac/markdown_parser_py-1.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-30 15:40:22",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "VarunGumma",
    "github_project": "markdown-parser-py",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "markdown-parser-py"
}
        
Elapsed time: 1.09890s