pygments
Pygments is the standard Python syntax highlighter. You hand it source code as a string, pick a lexer for the language and a formatter for the output, and it returns highlighted text as HTML, LaTeX, RTF, ANSI terminal escapes, or even images. It ships lexers for over 500 languages and text formats plus dozens of color styles, and it powers the code blocks in Sphinx, MkDocs, Jupyter, and the rich terminal library. There is also a pygmentize command line tool for one-off highlighting. Everything is pure Python and regex-based, which is why coverage is so broad and also why it has known performance limits on hostile input.
The default and mostly unquestioned choice for syntax highlighting anywhere in Python, with language coverage nothing else matches. Just do not point it at untrusted input without a timeout, and do not use it as a reason to route browser highlighting through a Python backend.
Use it if
- You render code blocks to HTML server-side in a blog engine, documentation generator, wiki, or code review tool and want one dependency that covers essentially every language
- You need output targets beyond HTML: LaTeX for papers, RTF, SVG, or ANSI escapes for terminal display
- You need lexers for niche or legacy languages (COBOL, VHDL, TOML dialects, config formats) that JavaScript highlighters never bothered with
- You are already inside the Sphinx, MkDocs, or Jupyter ecosystem, where Pygments is the built-in highlighting engine and custom styles or lexers plug straight in
- Highlighting happens in the browser: Pygments is Python, so a JS toolchain should use shiki or highlight.js instead of shipping HTML from a Python service just for colors
- You accept arbitrary user input on a web service without sandboxing: the project's own README warns there are no execution time guarantees, and crafted input can make regex-based lexers run essentially forever, a real denial-of-service vector unless you kill the process on a timeout
- You need editor-grade accuracy for modern TypeScript, JSX, or templating languages: regex lexers are approximations, and TextMate-grammar tools like shiki match what VS Code shows more faithfully
- You just want colored output from your own CLI app: rich wraps Pygments with a much friendlier API and handles terminal capabilities for you
Setup reality
pip install Pygments is pure Python with zero dependencies, so installing is the easy part. The real setup work is the HTML/CSS contract: HtmlFormatter emits span classes by default, so you must generate a stylesheet with get_style_defs() and ship it, or switch to noclasses=True inline styles and accept the bloat. Lexer selection is on you; guess_lexer() is genuinely unreliable, so pass a filename or explicit language whenever possible. If input is untrusted, you need a process-level timeout, which the library will not do for you.
Patterns
Highlight a code string to HTMLhighlight-to-html
from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter
code = 'print("hello")'
html = highlight(code, PythonLexer(), HtmlFormatter())The output is a <div class="highlight"> full of span classes. It is unstyled until you also ship the CSS from get_style_defs().
Generate the stylesheet for a color stylegenerate-css
from pygments.formatters import HtmlFormatter
formatter = HtmlFormatter(style="monokai")
css = formatter.get_style_defs(".highlight")
with open("pygments.css", "w") as f:
f.write(css)Regenerate the CSS whenever you change style=, since class-to-color mappings differ per style. The selector argument scopes the rules.
Pick a lexer from a filenamelexer-by-filename
from pygments.lexers import get_lexer_for_filename
from pygments.util import ClassNotFound
try:
lexer = get_lexer_for_filename("app.tsx")
except ClassNotFound:
from pygments.lexers import TextLexer
lexer = TextLexer()Prefer the filename or get_lexer_by_name over guess_lexer(code), which misidentifies short snippets constantly. Falling back to TextLexer beats crashing.
Highlight for the terminal with ANSI colorsterminal-output
from pygments import highlight
from pygments.lexers import JsonLexer
from pygments.formatters import Terminal256Formatter
print(highlight('{"ok": true}', JsonLexer(), Terminal256Formatter(style="monokai")))Terminal256Formatter covers most modern terminals; TerminalTrueColorFormatter exists for 24-bit color. Neither checks whether stdout is a TTY, that is your job.
Add line numbers to HTML outputline-numbers
from pygments.formatters import HtmlFormatter
formatter = HtmlFormatter(linenos="table", linenostart=10)linenos="table" keeps numbers out of copy-paste selection by using a two-column table; linenos="inline" puts them in the text flow where users will copy them.
Emphasize specific lineshighlight-specific-lines
from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter
formatter = HtmlFormatter(hl_lines=[2, 3])
html = highlight(code, PythonLexer(), formatter)Highlighted lines get a .hll class; the background color comes from the style's CSS, so it only shows once the stylesheet is loaded.
Inline styles for email or CSS-less contextsinline-styles
from pygments.formatters import HtmlFormatter
formatter = HtmlFormatter(noclasses=True, style="default")noclasses=True writes style attributes on every span. Output size grows a lot, but it is the only reliable option for HTML email.
List styles and lexers programmaticallylist-available-styles
from pygments.styles import get_all_styles
from pygments.lexers import get_all_lexers
print(sorted(get_all_styles()))
for name, aliases, filenames, mimetypes in get_all_lexers():
print(name, aliases)Useful for building a theme or language picker. get_all_lexers() yields metadata tuples without importing every lexer module.
Highlight a file from the command linecli-pygmentize
pygmentize -f html -O full,style=monokai -o out.html script.py
# or straight to the terminal:
pygmentize script.py-O full wraps output in a complete HTML document with embedded CSS, handy for one-offs. Without -f, the formatter is guessed from the output filename.
Highlight untrusted input with a hard timeoutguard-untrusted-input
import multiprocessing as mp
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
def work(code, lang, q):
q.put(highlight(code, get_lexer_by_name(lang), HtmlFormatter()))
def safe_highlight(code, lang, timeout=5):
q = mp.Queue()
p = mp.Process(target=work, args=(code, lang, q))
p.start()
p.join(timeout)
if p.is_alive():
p.kill()
return None
return q.get()The README itself says execution time is unbounded on hostile input. A thread cannot be killed mid-regex in Python, so a separate process is the only real guard.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| rich | PyPI | You want highlighted output in the terminal from your own Python app; it uses Pygments internally with a nicer API. |
| shiki | npm | You are in a JS/TS build pipeline and want VS Code-accurate highlighting via TextMate grammars. |
| highlight.js | npm | You want quick client-side highlighting in the browser with automatic language detection. |