Inline SVG Extension for Markdown
A Python-Markdown extension that enables inline embedding of local SVG
files directly into rendered HTML. Unlike standard Markdown image
syntax—which outputs <img> tags. This extension inserts the actual SVG
markup, enabling:
- full CSS styling of embedded SVGs
- consistent scaling behaviour
figure+figcaptionsupport- improved control over accessibility and semantics
Features
Inline SVG injection
Embed SVG files using a syntax similar to normal images:

or without caption:
!(path/to/image.svg)
Automatic <figure> + <figcaption> wrapping
If a caption is provided, the output becomes:
<figure>
<svg> ... </svg>
<figcaption>Your caption</figcaption>
</figure>
Without a caption, only the SVG element is inserted.
Safe Placeholder Handling
The extension first inserts placeholder tokens, preventing Python-Markdown from escaping the SVG. Placeholders are later replaced with the final SVG markup in the postprocessor phase.
Internal Caching
SVG files are parsed once and stored in a global cache for the lifetime of the process, improving performance.
Installation
pip install markdown isvg
Use the extension:
import markdown
from isvg import InlineSVGExtension
md = markdown.Markdown(extensions=[InlineSVGExtension(root="assets/svg")])
html = md.convert("")
Usage
Basic Inline SVG
!(diagram.svg)
Inline SVG with Caption

Example HTML Output
<figure>
<svg xmlns="http://www.w3.org/2000/svg" ...> ... </svg>
<figcaption>Data Flow</figcaption>
</figure>
Configuration
root
Defines the base directory from which SVG paths are resolved. Defaults to
"", the current working directory.
InlineSVGExtension(root="/var/www/assets/svg")
A Markdown reference such as:

resolves to:
/var/www/assets/svg/ui/menu.svg
remove_prefix
If your Markdown is generated from a web source that prefixes URLs with /,
you can remove that prefix:
InlineSVGExtension(remove_prefix="/")

Becomes reference to:
images/logo.svg
remove_prefex defaults to "", which means no prefix is removed.
How it Works
- Reference detection
A lightweight custom parser matches
and!(file.svg). - Structured extraction
captionandhrefsections are parsed using a bracket-aware tokenizer, not regex grouping. This ensures correct handling of nested brackets. - Path rewriting
remove_prefixandrootare applied. - File validation
- Must exist
- Must end in
.svg - Must not be remote (
http/https///)
- Caching & XML parsing
SVGs are loaded with
xml.etree.ElementTreeand stored in a module-level cache for reuse. - Placeholder emission
A unique stable placeholder token (
\x02path\x03) prevents Markdown from interfering with raw XML. - Postprocessing Placeholders are replaced with the final SVG markup after Markdown rendering is complete.
Error Handling
The extension silently ignores:
- Non-SVG files
- Remote URLs (
http://,https://,//) - Missing paths
- Invalid or malformed SVGs
In such cases, the original Markdown text is left unchanged.
Security Considerations
Inlining SVGs introduces risks if files are not trusted. SVGs can contain:
- JavaScript
- External resource references
- Embedded HTML
- CSS injections
If processing user-provided content, sanitize SVGs beforehand using tools such as: external SVG sanitizers or whitelist-based filtering.
Testing
This project includes pytest-based unit tests located in the test/ directory.
Run the full suite with:
pytest test
The tests cover:
- Correct placeholder insertion
- Proper caption extraction
figure+figcaptiongeneration- SVG loading and caching behavior
- Error-handling paths (invalid SVG, missing files, remote URLs)
- Interactions with other Python-Markdown extensions
If you extend or modify the extension, adding tests in this folder is highly recommended.
Known Limitations
- A global cache is used, which persists for the lifetime of the process.
- Relative links inside SVGs are not rewritten.
- Interactions with other Markdown extensions may affect final output order.
License
This project is licensed under the GNU General Public License v3.0 (GPLv3). You may redistribute and/or modify it under the terms of the GPLv3.
Metadata
Release files for iSVG 1.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| isvg-1.0.3.tar.gz | 18.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| isvg-1.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.1 kB
Release files / isvg-1.0.3.tar.gz
| Download URL | isvg-1.0.3.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f5067c42f06d0ed00a7962face20a596e3322e1955846aaccdb298b01eb1953d
|
|
BLAKE2b-256 checksum How to use checksums |
ebec6f38a89fc0f3e379f513fd3e9b5f3a0a820caf1481cd89bcfdcd051d9471
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.1
|
Release files / isvg-1.0.3-py3-none-any.whl
| Download URL | isvg-1.0.3-py3-none-any.whl |
|---|---|
| Size | 17.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8789c33770202720213fd16c960594ff3594c245df0165c6b22c91e0b4600b97
|
|
BLAKE2b-256 checksum How to use checksums |
2a16a92f23684af036429a6948d285c290088494f235bb06a2939b93e1cde094
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.1
|