Skip to main content

Convert Markdown to Slack mrkdwn format

Project description

md2mrkdwn

CI pypi downloads versions license

Pure Python library for converting Markdown to Slack's mrkdwn format. Zero dependencies, comprehensive formatting support, and proper handling of edge cases.

Features

  • Zero dependencies - Pure Python implementation with no external packages required
  • Comprehensive formatting - Supports bold, italic, strikethrough, links, images, lists, and more
  • Code block handling - Preserves content inside code blocks without conversion
  • Table support - Wraps markdown tables in code blocks for Slack display
  • Task lists - Converts checkbox syntax to Unicode symbols (☐/☑)
  • Edge case handling - Properly handles nested formatting and special characters

Quick Start

from md2mrkdwn import convert

markdown = "**Hello** *World*! Check out [Slack](https://slack.com)"
mrkdwn = convert(markdown)
print(mrkdwn)
# Output: *Hello* _World_! Check out <https://slack.com|Slack>

Installation

# Install with pip
pip install md2mrkdwn

# Or install with uv
uv add md2mrkdwn

# Or install with pipx (for CLI tools that use this library)
pipx install md2mrkdwn

Usage

Simple Function

The convert() function provides a simple interface for one-off conversions:

from md2mrkdwn import convert

markdown = """
# Hello World

This is **bold** and *italic* text.

- Item 1
- Item 2

Check out [this link](https://example.com)!
"""

mrkdwn = convert(markdown)
print(mrkdwn)

Output:

*Hello World*

This is *bold* and _italic_ text.

• Item 1
• Item 2

Check out <https://example.com|this link>!

Class-based Usage

For multiple conversions, use the MrkdwnConverter class:

from md2mrkdwn import MrkdwnConverter

converter = MrkdwnConverter()

# Convert multiple texts
text1 = converter.convert("**bold** and *italic*")
text2 = converter.convert("# Header\n\n- List item")

print(text1)  # *bold* and _italic_
print(text2)  # *Header*\n\n• List item

Handling Tables

Markdown tables are automatically wrapped in code blocks since Slack doesn't support native table rendering:

from md2mrkdwn import convert

markdown = """
| Name | Age |
|------|-----|
| Alice | 30 |
| Bob | 25 |
"""

print(convert(markdown))

Output:

Name Age
Alice 30
Bob 25

Conversion Reference

Markdown mrkdwn Notes
**bold** or __bold__ *bold* Slack uses single asterisk
*italic* or _italic_ _italic_ Slack uses underscores
***bold+italic*** *_text_* Combined formatting
~~strikethrough~~ ~text~ Single tilde
[text](url) <url|text> Slack link format
![alt](url) <url> Images become plain URLs
# Header (all levels) *Header* Bold (Slack has no headers)
- item / * item • item Bullet character (U+2022)
1. item 1. item Preserved as-is
- [ ] task • ☐ task Unchecked checkbox (U+2610)
- [x] task • ☑ task Checked checkbox (U+2611)
> quote > quote Same syntax
`code` `code` Same syntax
code block code block Same syntax
--- / *** ────────── Horizontal rule (U+2500)
Tables Wrapped in ``` Slack has no native tables

How It Works

Conversion Pipeline

md2mrkdwn processes text through a multi-stage pipeline:

  1. Table extraction - Tables are detected, validated, and replaced with placeholders
  2. Code block tracking - Lines inside code blocks are skipped during conversion
  3. Pattern application - Regex patterns convert formatting using placeholder protection
  4. Placeholder restoration - Tables and temporary markers are replaced with final output

Pattern Interference Prevention

A key challenge in markdown conversion is preventing patterns from interfering with each other. For example, converting **bold** to *bold* could then be matched by the italic pattern.

md2mrkdwn solves this using placeholder substitution:

  1. Bold text is temporarily marked with null-byte placeholders
  2. Italic patterns run without matching the placeholders
  3. Placeholders are replaced with final mrkdwn characters

Table Handling

Tables are detected using these criteria:

  • Lines matching |...| pattern
  • Second row contains separator cells (dashes with optional alignment colons)
  • Header and separator have matching column counts

Valid tables are wrapped in triple-backtick code blocks for monospace display in Slack.

Code Block Protection

Content inside code blocks (both fenced and inline) is protected from conversion:

  • Fenced blocks: State machine tracks opening/closing ``` markers
  • Inline code: Segments are extracted before conversion and restored after

Development

Setup

git clone https://github.com/bigbag/md2mrkdwn.git
cd md2mrkdwn
make install

Commands

make install  # Install all dependencies
make test     # Run tests with coverage
make lint     # Run linters (ruff + mypy)
make format   # Format code with ruff
make clean    # Clean cache and build files

Running Tests

# Run all tests with coverage
uv run pytest --cov=md2mrkdwn --cov-report=term-missing

# Run specific test class
uv run pytest tests/test_converter.py::TestBasicFormatting -v

# Run with verbose output
uv run pytest -v

Project Structure

md2mrkdwn/
├── src/
│   └── md2mrkdwn/
│       ├── __init__.py      # Package exports
│       └── converter.py     # MrkdwnConverter class
├── tests/
│   ├── conftest.py          # Pytest fixtures
│   └── test_converter.py    # Test suite (49 tests)
├── pyproject.toml           # Project configuration
├── Makefile                 # Development commands
└── README.md

API Reference

convert(markdown: str) -> str

Convert Markdown text to Slack mrkdwn format.

Parameters:

  • markdown - Input text in Markdown format

Returns:

  • Text converted to Slack mrkdwn format

MrkdwnConverter

Class for converting Markdown to mrkdwn.

Methods:

  • convert(markdown: str) -> str - Convert Markdown text to mrkdwn

Example:

converter = MrkdwnConverter()
result = converter.convert("**Hello** *World*")

License

MIT License - see LICENSE file.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

md2mrkdwn-0.1.0.tar.gz (8.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

md2mrkdwn-0.1.0-py3-none-any.whl (8.4 kB view details)

Uploaded Python 3

File details

Details for the file md2mrkdwn-0.1.0.tar.gz.

File metadata

  • Download URL: md2mrkdwn-0.1.0.tar.gz
  • Upload date:
  • Size: 8.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for md2mrkdwn-0.1.0.tar.gz
Algorithm Hash digest
SHA256 fa03fd4497ed9fcb14b7e8a68e3c5bc8bb510146aca20e8c85b0efab16a594cd
MD5 893556f2586b6b811c02746cba8b63f4
BLAKE2b-256 4b364bb988298dd58326427bcf9bc8f92875e4d0ca3c0355b7f487ca05e0b705

See more details on using hashes here.

Provenance

The following attestation bundles were made for md2mrkdwn-0.1.0.tar.gz:

Publisher: publish.yml on bigbag/md2mrkdwn

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file md2mrkdwn-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: md2mrkdwn-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for md2mrkdwn-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2772073b37cecda8904f4f65411467762a350d011bd9bc33d9ef5f25886c52ec
MD5 2dda4ea6ac9ef7b526ed8be8e150ee84
BLAKE2b-256 6011c862ef4f5ea8548b0e896cd8e4f701570f1361532592da49cad4c9764a1f

See more details on using hashes here.

Provenance

The following attestation bundles were made for md2mrkdwn-0.1.0-py3-none-any.whl:

Publisher: publish.yml on bigbag/md2mrkdwn

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page