# Migrate from Pygments
URL: /docs/tutorials/migrate-from-pygments/
Section: tutorials
Tags: migration, pygments
--------------------------------------------------------------------------------
# Migrate from Pygments
Switch from Pygments to Rosettes for faster, safer HTML syntax highlighting.
## Prerequisites
- Python 3.14+
- Existing Pygments-based highlighting
- HTML output (Rosettes doesn't support LaTeX, RTF, etc.)
## Step 1: Install Rosettes
```bash
pip install rosettes
```
## Step 2: Update Imports
**Before (Pygments):**
```python
from pygments import highlight
from pygments.lexers import get_lexer_by_name, PythonLexer
from pygments.formatters import HtmlFormatter
```
**After (Rosettes):**
```python
from rosettes import highlight, supports_language
```
## Step 3: Update Highlighting Calls
**Before (Pygments):**
```python
def highlight_code(code: str, language: str) -> str:
try:
lexer = get_lexer_by_name(language)
except ClassNotFound:
lexer = TextLexer()
formatter = HtmlFormatter(cssclass="highlight")
return highlight(code, lexer, formatter)
```
**After (Rosettes):**
```python
def highlight_code(code: str, language: str) -> str:
if not supports_language(language):
language = "plaintext"
return highlight(code, language, css_class_style="pygments")
```
Key differences:
- Single import instead of three
- `css_class_style="pygments"` for theme compatibility
- `supports_language()` for validation
## Step 4: Keep Your CSS
Your existing Pygments CSS theme works unchanged:
```css
/* Your existing Pygments theme */
.highlight { background: #272822; }
.highlight .k { color: #66d9ef; }
.highlight .nf { color: #a6e22e; }
/* ... */
```
Rosettes generates the same CSS classes when using `css_class_style="pygments"`.
## Step 5: Update Line Highlighting (Optional)
**Before (Pygments):**
```python
formatter = HtmlFormatter(
linenos=True,
hl_lines=[2, 3, 4],
)
```
**After (Rosettes):**
```python
html = highlight(
code,
language,
show_linenos=True,
hl_lines={2, 3, 4}, # Note: set, not list
css_class_style="pygments",
)
```
## Step 6: Update Parallel Highlighting (Optional)
**Before (Pygments):**
```python
from concurrent.futures import ThreadPoolExecutor
def highlight_many_pygments(blocks):
with ThreadPoolExecutor(max_workers=4) as executor:
return list(executor.map(
lambda b: highlight_code(b[0], b[1]),
blocks
))
```
**After (Rosettes):**
```python
from rosettes import highlight_many
def highlight_many_rosettes(blocks):
return highlight_many(blocks, css_class_style="pygments")
```
Built-in, optimized, and thread-safe.
## Complete Migration Example
**Before:**
```python
from pygments import highlight
from pygments.lexers import get_lexer_by_name, TextLexer
from pygments.lexers import ClassNotFound
from pygments.formatters import HtmlFormatter
class CodeHighlighter:
def __init__(self):
self.formatter = HtmlFormatter(cssclass="highlight")
def highlight(self, code: str, language: str) -> str:
try:
lexer = get_lexer_by_name(language)
except ClassNotFound:
lexer = TextLexer()
return highlight(code, lexer, self.formatter)
def highlight_with_lines(
self,
code: str,
language: str,
hl_lines: list[int],
) -> str:
try:
lexer = get_lexer_by_name(language)
except ClassNotFound:
lexer = TextLexer()
formatter = HtmlFormatter(
cssclass="highlight",
linenos=True,
hl_lines=hl_lines,
)
return highlight(code, lexer, formatter)
```
**After:**
```python
from rosettes import highlight, highlight_many, supports_language
class CodeHighlighter:
def highlight(self, code: str, language: str) -> str:
if not supports_language(language):
language = "plaintext"
return highlight(code, language, css_class_style="pygments")
def highlight_with_lines(
self,
code: str,
language: str,
hl_lines: set[int],
) -> str:
if not supports_language(language):
language = "plaintext"
return highlight(
code,
language,
show_linenos=True,
hl_lines=hl_lines,
css_class_style="pygments",
)
def highlight_batch(
self,
blocks: list[tuple[str, str]],
) -> list[str]:
# Validate languages
validated = [
(code, lang if supports_language(lang) else "plaintext")
for code, lang in blocks
]
return highlight_many(validated, css_class_style="pygments")
```
## API Mapping
| Pygments | Rosettes |
|----------|----------|
| `get_lexer_by_name(lang)` | `get_lexer(lang)` |
| `ClassNotFound` exception | `LookupError` exception |
| `supports_language()` check | `supports_language(lang)` |
| `HtmlFormatter(cssclass=...)` | `highlight(..., css_class=...)` |
| `HtmlFormatter(linenos=True)` | `highlight(..., show_linenos=True)` |
| `hl_lines=[1,2,3]` | `hl_lines={1,2,3}` (set) |
## Known Differences
| Aspect | Pygments | Rosettes |
|--------|----------|----------|
| Languages | 500+ | 55 |
| Output formats | HTML, LaTeX, RTF, etc. | HTML only |
| `hl_lines` type | `list` | `set` or `frozenset` |
| Line number format | Configurable | Fixed format |
## Verification
After migration, verify:
1. **Output looks the same**: Compare rendered HTML
2. **CSS classes match**: Inspect generated class names
3. **Performance improved**: Benchmark before/after
4. **No errors**: Test with all your languages
```python
# Quick verification
from rosettes import highlight
html = highlight("def foo(): pass", "python", css_class_style="pygments")
assert 'def' in html
assert 'foo' in html
print("✅ Migration successful!")
```
## Next Steps
- [[docs/highlighting/parallel|Parallel Processing]] — Optimize batch highlighting
- [[docs/about/comparison|Comparison]] — Full Rosettes vs Pygments comparison
- [[docs/styling/pygments-themes|Pygments Themes]] — Theme compatibility details
--------------------------------------------------------------------------------
Metadata:
- Word Count: 632
- Reading Time: 3 minutes