Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/gvalkov/python-ansimarkup
Produce colored terminal text with an xml-like markup
https://github.com/gvalkov/python-ansimarkup
ansi-colors ansi-escape-codes
Last synced: 3 days ago
JSON representation
Produce colored terminal text with an xml-like markup
- Host: GitHub
- URL: https://github.com/gvalkov/python-ansimarkup
- Owner: gvalkov
- License: bsd-3-clause
- Created: 2016-10-07T06:41:50.000Z (about 8 years ago)
- Default Branch: main
- Last Pushed: 2023-08-27T12:08:51.000Z (about 1 year ago)
- Last Synced: 2024-08-01T22:55:52.356Z (3 months ago)
- Topics: ansi-colors, ansi-escape-codes
- Language: Python
- Homepage:
- Size: 84 KB
- Stars: 63
- Watchers: 5
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
- starred-awesome - python-ansimarkup - Produce colored terminal text with an xml-like markup (Python)
README
# Ansimarkup
Ansimarkup is an XML-like markup for producing colored terminal text.
``` python
from ansimarkup import ansiprint as printprint("bold text"))
print("red text", "red text on a green background")
print("orange text")
```## Installation
The latest stable version of ansimarkup can be installed from PyPi:
``` bash
python3 -m pip install ansimarkup
```## Usage
### Basic
``` python
from ansimarkup import parse, ansiprint# parse() converts the tags to the corresponding ansi escape sequence.
parse("bold dim")# ansiprint() works exactly like print(), but first runs parse() on all arguments.
ansiprint("bold", "dim")
ansiprint("bold", "dim", sep=":", file=sys.stderr)
```### Colors and styles
``` python
# Colors may be specified in one of several ways.
parse("red foreground")
parse("red background")
parse("red foreground")
parse("red background")# Xterm, hex and rgb colors are accepted by the and tags.
parse("aquamarine foreground")
parse("dark blue background")
parse("dark green foreground")# Tags may be nested.
parse("red text on a yellow foreground")# The above may be more concisely written as:
parse("red text on a yellow background")# This shorthand also supports style tags.
parse("bold red text on a yellow background")
parse("bold red text")
parse("bold regular text on a yellow background")# Unrecognized tags are left as-is.
parse("")
```For a list of markup tags, please refer to [tags.py].
### User-defined tags
Custom tags or overrides for existing tags may be defined by creating a
new `AnsiMarkup` instance:``` python
from ansimarkup import AnsiMarkup, parseuser_tags = {
# Add a new tag (e.g. we want to expand to "").
"info": parse("")# The ansi escape sequence can be used directly.
"info": "e\x1b[32m\x1b[1m",# Tag names may also be callables.
"err": lambda: parse("")# Colors may also be given convenient tag names.
"orange": parse(""),# User-defined tags always take precedence over existing tags.
"bold": parse("")
}am = AnsiMarkup(tags=user_tags)
am.parse("bold green")
am.ansiprint("red")# Calling the instance is equivalent to calling its parse method.
am("bold") == am.parse("bold")
```### Alignment and length
Aligning formatted strings can be challenging because the length of the
rendered string is different that the number of printable characters.
Consider this example:``` pycon
>>> a = '| {:30} |'.format('abc')
>>> b = '| {:30} |'.format(parse('abc'))
>>> print(a, b, sep='\n')
| abc |
| abc |
```This can be addressed by using the `ansistring` function or the
`AnsiMarkup.string(markup)` method, which has the following useful
properties:``` pycon
>>> s = ansistring('abc')
>>> print(repr(s), '->', s)
abc -> abc # abc is printed in bold
>>> len(s), len(am.parse('abc'), s.delta
3, 11, 8
```With the help of the `delta` property, it is easy to align the strings
in the above example:``` pycon
>>> s = ansistring('abc')
>>> a = '| {:{width}} |'.format('abc', width=30)
>>> b = '| {:{width}} |'.format(s, width=(30 + s.delta))
>>> print(a, b, sep='\n')
| abc |
| abc |
```### Escaping raw strings
Both `ansiprint()` and `parse()` pass arguments of type `raw` untouched.
``` pycon
>>> from ansimarkup import ansiprint, parse, raw
>>> ansiprint("", raw("2.0"), "")
2.0 # printed in bold red (note the leading space caused)>>> s = parse("", raw("2.0"), "")
>>> print(s)
2.0 # printed in bold red
```Building a template string may also be sufficient:
``` pycon
>>> from ansimarkup import parse
>>> s = parse("%s")
>>> print(s % "2.0")
2.0 # printed in bold red
```### Other features
The default tag separators can be changed by passing the `tag_sep`
argument to `AnsiMarkup`:``` python
from ansimarkup import AnsiMarkupam = AnsiMarkup(tag_sep="{}")
am.parse("{b}{r}bold red{/b}{/r}")
```Markup tags can be removed using the `strip()` method:
``` python
from ansimarkup import AnsiMarkupam = AnsiMarkup()
am.strip("bold red")
```The `strict` option instructs the parser to raise `MismatchedTag` if
opening tags don\'t have corresponding closing tags:``` python
from ansimarkup import AnsiMarkupam = AnsiMarkup(strict=True)
am.parse("bold red")
# ansimarkup.MismatchedTag: opening tag "" has no corresponding closing tag
```### Command-line
Ansimarkup may also be used on the command-line. This works as if all
arguments were passed to `ansiprint()`:$ python -m ansimarkup
Usage: python -m ansimarkup [ [ ...]]Example usage:
python -m ansimarkup 'Bold' 'Red'
python -m ansimarkup 'Bold Red'
python -m ansimarkup < input-with-markup.txt
echo 'Bold' | python -m ansimarkup### Logging formatter
Ansimarkup also comes with a formatter for the standard library `logging` module. It can be used as:
``` python
import logging
from ansimarkup.logformatter import AnsiMarkupFormatterlog = logging.getLogger()
hdl = logging.StreamHandler()
fmt = AnsiMarkupFormatter()
hdl.setFormatter(fmt)
log.addHandler(hdl)log.info("bold text")
```### Windows
Ansimarkup uses the [colorama] library internally, which means that
Windows support for ansi escape sequences is available by first running:``` python
import colorama
colorama.init()
```For more information on Windows support, consult the \"Usage\" section
of the [colorama] documentation.## Performance
While the focus of ansimarkup is convenience, it does try to keep
processing to a minimum. The [benchmark.py] script attempts to benchmark
different ansi escape code libraries:Benchmark 1: red bold
colorama 0.1959 μs
colr 1.8022 μs
ansimarkup 3.1681 μs
termcolor 5.3734 μs
rich 9.0673 μs
pastel 10.7440 μs
plumbum 14.0620 μs
Benchmark 2: red boldredbold
colorama 0.5360 μs
colr 4.5575 μs
ansimarkup 4.5727 μs
termcolor 15.8462 μs
rich 21.2631 μs
pastel 22.9391 μs
plumbum 33.1179 μs## Limitations
Ansimarkup is a simple wrapper around [colorama]. It does very little in
the way of validating that markup strings are well-formed. This is a
conscious decision with the goal of keeping things simple and fast.Unbalanced nesting, such as in the following example, will produce
incorrect output:12
## Todo
- Many corner cases remain to be fixed.
- More elaborate testing. The current test suite mostly covers the \"happy paths\".
- Replace `tag_list.index` in `sub_end` with something more efficient (i.e. something like an ordered MultiDict).## Similar libraries
- [pastel][]: bring colors to your terminal
- [plumbum.colors][]: small yet feature-rich library for shell script-like programs in Python
- [colr][]: easy terminal colors, with chainable methods
- [rich][]: rich text and beautiful formatting in the terminal (see `rich.print()` and `rich.markup.render()`)## License
Ansimarkup is released under the terms of the [Revised BSD License].
[tags.py]: https://github.com/gvalkov/python-ansimarkup/blob/main/ansimarkup/tags.py
[colorama]: https://pypi.python.org/pypi/colorama
[benchmark.py]: https://github.com/gvalkov/python-ansimarkup/blob/main/tests/benchmark.py
[pastel]: https://github.com/sdispater/pastel
[plumbum.colors]: https://plumbum.readthedocs.io/en/latest/cli.html#colors
[colr]: https://pypi.python.org/pypi/Colr/
[rich]: https://github.com/Textualize/rich
[Revised BSD License]: https://github.com/gvalkov/python-ansimarkup/blob/main/LICENSE.txt