Markdown Converter
Python library that loads CommonMark, GitHub Flavored Markdown, or Obsidian Markdown into one document tree, then writes any of those flavours. Conversion is two-pass through that tree — there are no pairwise converters.
The PyPI name is lupaxa-markdown-converter. The import path is
lupaxa.markdown_converter. lupaxa is a namespace package. The
console script is markdown-converter.
Install
pip install lupaxa-markdown-converter
Requires Python 3.10+. The package pulls in markdown-it-py.
You can also run python -m lupaxa.markdown_converter.
Usage
from lupaxa.markdown_converter import MarkdownConverter
source = "[[folder/My Page#Hello World]]\n"
converter = MarkdownConverter(source, flavour="obsidian")
print(converter.to_commonmark())
print(converter.to_github())
print(converter.to_obsidian())
MarkdownConverter accepts a document string. Set flavour to the
flavour of that string (case-insensitive). The value is stored
lower-case on converter.flavour, then any to_* method can write
it out. Same-flavour conversion is supported.
flavour |
Input |
|---|---|
commonmark |
CommonMark (default) |
github |
GitHub Flavored Markdown: tables, tasks, strikethrough, and autolinks |
obsidian |
Those GitHub extras, plus wikilinks, embeds, highlights, and callouts |
from_commonmark = MarkdownConverter("# Title\n", flavour="commonmark")
from_github = MarkdownConverter("- [x] done\n", flavour="github")
from_obsidian = MarkdownConverter("==hi==\n", flavour="OBSIDIAN")
Note: Output is canonical. A same-flavour conversion can still change the source. A setext heading becomes an ATX heading, and a reference link is written inline.
MarkdownConverter("Title\n=====\n", flavour="commonmark").to_commonmark()
# '# Title\n'
Wikilinks and Embeds
An Obsidian wikilink becomes a Markdown link on the way to GitHub or
CommonMark. Each path segment is percent-encoded, .md is added when
the target does not already end in .md, and a heading becomes a
fragment. An image embed becomes an image. A numeric label is a resize
hint and is dropped. Obsidian keeps both forms.
converter = MarkdownConverter("[[folder/My Page#Hello World]]\n", flavour="obsidian")
converter.to_github()
# '[My Page](folder/My%20Page.md#hello-world)\n'
embed = MarkdownConverter("![[shot.png|100]]\n", flavour="obsidian")
embed.to_github()
# '\n'
embed.to_obsidian()
# '![[shot.png|100]]\n'
Tables, Tasks, and Autolinks
GitHub and Obsidian keep pipe tables, task lists, strikethrough, and
bare autolinks. CommonMark receives the nearest CommonMark form: an
HTML table, escaped checkbox text, <del>, and an angle autolink.
Plain CommonMark is left as plain CommonMark. A checkbox written as
ordinary text is escaped, and an HTML table stays HTML.
table = "| A | B |\n| --- | ---: |\n| 1 | 2 |\n"
MarkdownConverter(table, flavour="github").to_obsidian()
# '| A | B |\n| --- | ---: |\n| 1 | 2 |\n'
MarkdownConverter("- [x] done\n", flavour="github").to_github()
# '- [x] done\n'
MarkdownConverter("- [ ] todo\n", flavour="commonmark").to_github()
# '- \\[ \\] todo\n'
MarkdownConverter("~~old~~ and https://example.com\n", flavour="github").to_commonmark()
# '<del>old</del> and <https://example.com>\n'
Highlights and Callouts
Obsidian keeps ==highlights== and [!type] callouts. GitHub and
CommonMark receive <mark> and a blockquote whose first line is the
type and title.
note = MarkdownConverter("==hi==\n", flavour="obsidian")
note.to_obsidian()
# '==hi==\n'
note.to_github()
# '<mark>hi</mark>\n'
callout = MarkdownConverter("> [!tip] Look\n", flavour="obsidian")
callout.to_github()
# '> **Tip:** Look\n'
callout.to_obsidian()
# '> [!tip] Look\n'
Frontmatter
A leading YAML fence is copied through unchanged, including its line endings. The body is converted. The fence is not parsed as Markdown.
source = "---\ntitle: Note\n---\n\n# Title\n"
MarkdownConverter(source, flavour="obsidian").to_commonmark()
# '---\ntitle: Note\n---\n\n# Title\n'
Command Line
--from and --to are required. They take commonmark, github, or
obsidian. Pass a file, or - to read stdin. Omit -o to write
stdout.
markdown-converter --from obsidian --to github note.md -o note.github.md
markdown-converter --from github --to commonmark - < note.md
A missing file, a directory, text that is not UTF-8, or a conversion
error prints one Error: line on stderr and exits 2.
Errors
An unknown flavour, a document that is not a string, and a body that
cannot be parsed raise MarkdownConverterError. The parse failure is
attached as __cause__.
from lupaxa.markdown_converter import MarkdownConverter, MarkdownConverterError
try:
MarkdownConverter("hi\n", flavour="rst")
except MarkdownConverterError as exc:
print(exc)
Metadata
Release files for lupaxa-markdown-converter 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lupaxa_markdown_converter-0.1.1.tar.gz | 15.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lupaxa_markdown_converter-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.7 kB
Release files / lupaxa_markdown_converter-0.1.1.tar.gz
| Download URL | lupaxa_markdown_converter-0.1.1.tar.gz |
|---|---|
| Size | 15.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
68263886fb968e616fb2b14f82e7f17f5bfd6d80af9c0a3413d259ddac951948
|
|
BLAKE2b-256 checksum How to use checksums |
5a89108f3235d9f7e325c6243bf5351bdebc9c6d9a61cbd18e04b1ceb81689e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logRelease files / lupaxa_markdown_converter-0.1.1-py3-none-any.whl
| Download URL | lupaxa_markdown_converter-0.1.1-py3-none-any.whl |
|---|---|
| Size | 19.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
effa1b04ec5800bc116640e379d490293c748e028c2b23f20a0d57021f65867d
|
|
BLAKE2b-256 checksum How to use checksums |
84243477ebb16ca7d2eea3371039cde05a21c506f314377dd1e35a1819068f0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency log