pygments-step
Pygments lexers for EXPRESS (ISO 10303-11) and STEP Part 21 (ISO 10303-21).
| Lexer | Standard | Code fence | File types |
|---|---|---|---|
ExpressLexer |
EXPRESS, ISO 10303-11 | ```express |
*.exp |
StepFileLexer |
Part 21 exchange file, ISO 10303-21 | ```step21 |
*.p21, *.stp, *.step |
Additional aliases: exp, iso-10303-11 for EXPRESS; p21, step, stp,
spf, iso-10303-21 for Part 21.
Both lexers are schema-agnostic. They lex the languages, not any single application protocol, so they work equally well for IFC, AP203, AP214 or any other STEP-based schema without carrying a schema-specific keyword table.
Install
pip install pygments-step
Or, with uv:
uv add pygments-step
The only runtime dependency is Pygments>=2.14. Python 3.9+ is supported.
Installing is all you need to do. The lexers register themselves with Pygments
through pygments.lexers entry points, so every tool that renders code through
Pygments — MkDocs, Sphinx, pygmentize, Rich, Jupyter — picks them up
automatically. There is no configuration step.
Usage
Markdown code fences
Tag a fence with express or step21:
```express
ENTITY cartesian_point
SUBTYPE OF (geometric_representation_item);
coordinates : LIST [1:3] OF length_measure;
DERIVE
dim : INTEGER := HIINDEX(coordinates);
WHERE
valid_dim : SIZEOF(coordinates) <= 3;
END_ENTITY;
```
```step21
ISO-10303-21;
HEADER;
FILE_SCHEMA(('SOME_APPLICATION_PROTOCOL'));
ENDSEC;
DATA;
#1= CARTESIAN_POINT('',(0.,0.,0.));
#4= AXIS2_PLACEMENT_3D('',#1,#3,$);
#6= NAMED_UNIT(.T.,.F.,.UNSPECIFIED.);
ENDSEC;
END-ISO-10303-21;
```
This works out of the box in MkDocs (including Material for MkDocs, whose
pymdownx.highlight extension delegates to Pygments) and in any other
Markdown pipeline backed by Pygments — no mkdocs.yml changes required.
Python API
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import get_lexer_by_name
lexer = get_lexer_by_name("step21")
print(highlight("#1= CARTESIAN_POINT('',(0.,0.,0.));", lexer, HtmlFormatter()))
The classes can also be imported directly:
from pygments_step import ExpressLexer, StepFileLexer
Dispatch by filename works as well:
from pygments.lexers import get_lexer_for_filename
get_lexer_for_filename("schema.exp") # EXPRESS
get_lexer_for_filename("model.stp") # STEP Part 21
Command line
pygmentize -l express schema.exp
pygmentize -l step21 -f html -O full,style=friendly -o model.html model.stp
Because the file extensions are registered, -l can usually be omitted:
pygmentize schema.exp
What the lexers cover
EXPRESS (ISO 10303-11)
- Case-insensitive keywords, per clause 6.1 and annex A.1.1.
- Nested
(* ... (* ... *) ... *)embedded remarks and-- ...tail remarks. - Declaration heads (
SCHEMA,ENTITY,TYPE,FUNCTION,PROCEDURE,RULE,CONSTANT,SUBTYPE_CONSTRAINT) highlight the declared name distinctly from the keyword. - Literals: doubled-quote string escapes (
'it''s'), binary literals (%10110), encoded string literals ("000000E9"), reals and integers. - Built-in functions (
SIZEOF,HIINDEX,EXISTS,TYPEOF, …) and built-in types (INTEGER,LIST,SELECT,LOGICAL, …).
STEP Part 21 (ISO 10303-21)
- Exchange structure keywords:
ISO-10303-21,END-ISO-10303-21,HEADER,DATA,ENDSEC,ANCHOR,REFERENCE,SIGNATURE. - Entity instance definitions (
#1=) are tokenised differently from references (,#1,), so the two read differently in rendered output. - Enumerations (
.T.,.F.,.UNSPECIFIED.), unset values ($) and derived values (*). - String control directives:
\S\,\P?\,\X\,\X2\...\X0\,\X4\...\X0\, plus''escapes. - Print control directives
\N\and\F\, both inside strings and at any position where a token separator may appear. - Binary literals (
"0F3A"), user-defined keywords (!USER_DEFINED_KEYWORD) and/* ... */comments.
A note on IFC
IFC files are Part 21 files, so StepFileLexer handles them — but ifc and
*.ifc are deliberately not claimed as an alias or filename pattern. IFC
is only one of many SPF-based formats, and privileging it in a
standards-level lexer would be arbitrary. Use step21 (or p21 / spf) for
IFC content.
Test
Clone the repository and install with the test extra:
git clone https://github.com/AECVerge/pygments-step.git
cd pygments-step
uv sync --extra test
uv run pytest
Or with pip:
pip install -e ".[test]"
pytest
The suite also runs standalone, without pytest:
python tests/test_lexers.py
Tests cover alias and filename registration, token-level regressions for both
lexers, and assert that neither fixture produces a single Error token.
tests/test_docs_pages.py does the same for the rendered docs/express and
docs/step pages. Those pages are an exhaustive, category-by-category corpus
for the two lexers (keywords, operators, types, literals, comments, …); the test
parses every code fence on them and asserts that the lexer produces zero
Error tokens, and that each page really covers the whole family of tokens it
claims to. The docs build in CI runs with mkdocs build --strict, so a snippet
that stops lexing cleanly blocks the deploy as well.
License
Metadata
Release files for pygments-step 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pygments_step-0.2.0.tar.gz | 13.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pygments_step-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.6 kB
Release files / pygments_step-0.2.0.tar.gz
| Download URL | pygments_step-0.2.0.tar.gz |
|---|---|
| Size | 13.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
921438a411a08f5f21d78cefbf83a774fd90202480bfd9335ee2093226a661db
|
|
BLAKE2b-256 checksum How to use checksums |
24f898297b6e3d5e8931b82ecfa3a0b1912079863212b23c63f6d8bfe255b0e0
|
| 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 Sep 21, 2026.
Transparency logRelease files / pygments_step-0.2.0-py3-none-any.whl
| Download URL | pygments_step-0.2.0-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8784ef110166d691d6115c7a11df22a14fe11eb5e56538fe959fe83dcec5fbc9
|
|
BLAKE2b-256 checksum How to use checksums |
b732ffc80a7a5fd1c7a46f2829fa9d2185dae8d4b1e3bdf80802eaf073c449f3
|
| 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 Sep 21, 2026.
Transparency log