jonathaneunice / ansiwrap Goto Github PK
View Code? Open in Web Editor NEWtextwrap, but savvy to ANSI colors
License: Other
textwrap, but savvy to ANSI colors
License: Other
python -c 'import ansiwrap; print ansiwrap.fill(open("ansitest-case-nonwrapped.txt").read())'
(the testcase is attached)
Hi, I've just tried ansiwrap and maybe I'm using it wrong but I would expect the line lengths to be 60:
>>> s = '\x1b[32m##############################################################################################################################################################################################################################################################################################################################################################\x1b[0m\x1b[34m##############\x1b[0m\x1b[31m###################################################################################################################################################################################################################################################################################################################################################################################\x1b[0m'
>>> w = ansiwrap.fill(s, width=60)
>>> print(w)
#######################################################
############################################################
############################################################
############################################################
############################################################
#######################################################
###############################################
############################################################
############################################################
############################################################
############################################################
############################################################
######################################
>>> print(repr(w))
'\x1b[32m#######################################################\x1b[0m\n\x1b[32m############################################################\x1b[0m\n\x1b[32m############################################################\x1b[0m\n\x1b[32m############################################################\x1b[0m\n\x1b[32m############################################################\x1b[0m\n\x1b[32m#######################################################\x1b[0m\x1b\n[34m##############\x1b[0m\x1b[31m#################################\x1b[0m\n\x1b[31m############################################################\x1b[0m\n\x1b[31m############################################################\x1b[0m\n\x1b[31m############################################################\x1b[0m\n\x1b[31m############################################################\x1b[0m\n\x1b[31m############################################################\x1b[0m\n\x1b[31m######################################\x1b[0m'
>>> list(map(lambda x: x.count('#'), w.split('\n')))
[55, 60, 60, 60, 60, 55, 47, 60, 60, 60, 60, 60, 38]
I am aware that ANSI code 22 is not explicitly the reset code for bold. However, on Mac Terminal, iTerm2, and CentOS Konsole the reset code 21 doesn't do anything and reset code 22 must be used instead.
from ansiwrap import wrap
# \x1b[1m ... \x1b[0m
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean lorem nisl, \x1b[1mpellentesque\x1b[0m nec pulvinar mollis, rhoncus vel mi. Aliquam nisi ante, ultricies consectetur laoreet in, sodales a elit."
print("ANSI Escape Code 0")
print("\n".join(text))
print("\x1b[0m")
# \x1b[1m ... \x1b[21m
reset_bold = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean lorem nisl, \x1b[1mpellentesque\x1b[21m nec pulvinar mollis, rhoncus vel mi. Aliquam nisi ante, ultricies consectetur laoreet in, sodales a elit."
print("ANSI Escape Code 21")
print("\n".join(wrap(reset_bold)))
print("\x1b[0m")
# \x1b[1m ... \x1b[22m
reset_bold = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean lorem nisl, \x1b[1mpellentesque\x1b[22m nec pulvinar mollis, rhoncus vel mi. Aliquam nisi ante, ultricies consectetur laoreet in, sodales a elit."
print("ANSI Escape Code 22")
print("\n".join(wrap(reset_bold)))
print("\x1b[0m")
I would assume that the quick fix would be to also check for reset code 22 when deciding whether bold needs to continue onto a wrapped line. Or are there additional concerns that need to be considered first?
Deprecation warnings are raised due to invalid escape sequences in Python 3.8 . Below is a log of the warnings raised during compiling all the python files. Using raw strings or escaping them will fix this issue.
find . -iname '*.py' | xargs -P 4 -I{} python -Walways -m py_compile {}
./ansiwrap/core.py:110: DeprecationWarning: invalid escape sequence \[
s = re.sub('\x1b\[K', '', s)
I'm trying to figure out a way to print a string with ansi codes, but only the first, say 300 "normal" characters worth. Is there an easy way to do this with your library?
P.S. What license is your library under?
Thanks!
======================================================= ERRORS =======================================================
_______________________________________ ERROR collecting test/test_ansiwrap.py _______________________________________
test/test_ansiwrap.py:23: in <module>
other_lengths = (random.sample(set(range(20, 120)).difference(LINE_LENGTHS), 2) +
ANSIState = <class 'ansiwrap.ansistate.ANSIState'>
COLORS = ('black', 'red', 'green', 'yellow', 'blue', 'magenta', ...)
LINE_LENGTHS = [20, 27, 40, 41, 42, 43, ...]
STYLES = ('none', 'bold', 'faint', 'italic', 'underline', 'blink', ...)
VERSION = (3, 11)
_PY2 = False
__builtins__ = <builtins>
__cached__ = '/home/ben/src/forks/ansiwrap/test/__pycache__/test_ansiwrap.cpython-311.pyc'
__doc__ = None
__file__ = '/home/ben/src/forks/ansiwrap/test/test_ansiwrap.py'
__loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7facd25b7210>
__name__ = 'test_ansiwrap'
__package__ = ''
__spec__ = ModuleSpec(name='test_ansiwrap', loader=<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7facd25b7210>, origin='/home/ben/src/forks/ansiwrap/test/test_ansiwrap.py')
_ansi_optimize = <function _ansi_optimize at 0x7facd260b7e0>
absolute_import = _Feature((2, 5, 0, 'alpha', 1), (3, 0, 0, 'alpha', 0), 262144)
ansi_terminate_lines = <function ansi_terminate_lines at 0x7facd260b880>
ansilen = <function ansilen at 0x7facd2609b20>
ansistate = <module 'ansiwrap.ansistate' from '/home/ben/src/forks/ansiwrap/.tox/py311/lib/python3.11/site-packages/ansiwrap/ansistate.py'>
black = functools.partial(<function color at 0x7facd2609620>, fg='black')
blink = functools.partial(<function color at 0x7facd2609620>, style='blink')
blink2 = functools.partial(<function color at 0x7facd2609620>, style='blink2')
blue = functools.partial(<function color at 0x7facd2609620>, fg='blue')
bold = functools.partial(<function color at 0x7facd2609620>, style='bold')
color = <function color at 0x7facd2609620>
colors = <module 'colors.colors' from '/home/ben/src/forks/ansiwrap/.tox/py311/lib/python3.11/site-packages/colors/colors.py'>
concealed = functools.partial(<function color at 0x7facd2609620>, style='concealed')
core = <module 'ansiwrap.core' from '/home/ben/src/forks/ansiwrap/.tox/py311/lib/python3.11/site-packages/ansiwrap/core.py'>
crossed = functools.partial(<function color at 0x7facd2609620>, style='crossed')
css_colors = {'aliceblue': (240, 248, 255), 'antiquewhite': (250, 235, 215), 'aqua': (0, 255, 255), 'aquamarine': (127, 255, 212), ...}
csscolors = <module 'colors.csscolors' from '/home/ben/src/forks/ansiwrap/.tox/py311/lib/python3.11/site-packages/colors/csscolors.py'>
cyan = functools.partial(<function color at 0x7facd2609620>, fg='cyan')
faint = functools.partial(<function color at 0x7facd2609620>, style='faint')
fill = <function fill at 0x7facd260b740>
green = functools.partial(<function color at 0x7facd2609620>, fg='green')
is_string = <function is_string at 0x7facd26093a0>
italic = functools.partial(<function color at 0x7facd2609620>, style='italic')
magenta = functools.partial(<function color at 0x7facd2609620>, fg='magenta')
negative = functools.partial(<function color at 0x7facd2609620>, style='negative')
none = functools.partial(<function color at 0x7facd2609620>, style='none')
parse_rgb = <function parse_rgb at 0x7facd26094e0>
partial = <class 'functools.partial'>
print_function = _Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 1048576)
pytest = <module 'pytest' from '/home/ben/src/forks/ansiwrap/.tox/py311/lib/python3.11/site-packages/pytest/__init__.py'>
random = <module 'random' from '/usr/lib64/python3.11/random.py'>
re = <module 're' from '/usr/lib64/python3.11/re/__init__.py'>
red = functools.partial(<function color at 0x7facd2609620>, fg='red')
shorten = <function shorten at 0x7facd260b920>
string_types = <class 'str'>
strip_color = <function strip_color at 0x7facd260ac00>
sys = <module 'sys' (built-in)>
textwrap = <module 'textwrap3' from '/home/ben/src/forks/ansiwrap/.tox/py311/lib/python3.11/site-packages/textwrap3.py'>
underline = functools.partial(<function color at 0x7facd2609620>, style='underline')
version = <module 'colors.version' from '/home/ben/src/forks/ansiwrap/.tox/py311/lib/python3.11/site-packages/colors/version.py'>
white = functools.partial(<function color at 0x7facd2609620>, fg='white')
wrap = <function wrap at 0x7facd260b6a0>
yellow = functools.partial(<function color at 0x7facd2609620>, fg='yellow')
/usr/lib64/python3.11/random.py:436: in sample
raise TypeError("Population must be a sequence. "
E TypeError: Population must be a sequence. For dicts or sets, use sorted(d).
counts = None
k = 2
population = {21, 22, 23, 24, 25, 26, ...}
self = <random.Random object at 0x56475e972100>
The diagnostic is pretty self-explanatory. The problem is in the test, not in the library. PR to follow.
The following warning gets issued when using this library:
.venv/lib/python3.8/site-packages/ansiwrap/core.py:6
.../.venv/lib/python3.8/site-packages/ansiwrap/core.py:6: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
import imp
ansiwrap uses the (now deprecated) imp
module to import its own isolated copy of the textwrap3
module that it can "viciously" monkey-patch. imp
does not support import hooks and therefore ansiwrap
cannot be imported if textwrap3
is in an egg or bundled using zipapp
.
To reproduce (with Python 3.7 on macOS):
mkdir ziptest
echo 'import ansiwrap' > ziptest/__main__.py
pip3 install ansiwrap --target ziptest
python3 -mzipapp ziptest
python3 ziptest.pyz
Result:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "ziptest.pyz/__main__.py", line 1, in <module>
File "ziptest.pyz/ansiwrap/__init__.py", line 1, in <module>
File "ziptest.pyz/ansiwrap/core.py", line 11, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/imp.py", line 296, in find_module
raise ImportError(_ERR_MSG.format(name), name=name)
ImportError: No module named 'textwrap3'
Is there a way to shorten a string, while maintaining the embedded ANSI codes? (so the resulting string is still colored, just shorter)
Don't require textwrap3 on newer version of python (>3.5).
python -c 'import ansiwrap; print ansiwrap.fill(open("ansitest-case-nonwrapped.txt").read())'
(the testcase is attached)
I have noticed that after wrapping, this code is inserting some characters by calling the function ansi_terminate_lines
. As it is disturbing the behavior I would expect, I would like to know why this function is being called at the end of the wrap
function.
Line 92 in 20e2e8c
s
with multiple lines (i.e., multiple '\n'
) with lots of ANSI code all along. When calling ansiwrap.fill(s, replace_whitespace=False)
, it does not work properly, as it is breaking the line before the width
although the next word in the following line would fill properly in the same line.
Then I decided to split s
as s.split('\n')
and apply ansiwrap.fill(line)
as x = [ansiwrap.fill(line, width=columns) for line in s.split('\n')]
for joining the result later: s = '\n'.join(x)
.
In this case, however, some ANSI code in the previous line
that should affect the next line
is not affecting anymore. By removing the ansi_terminate_lines
it works fine for me.
Thank you for the initiative!
Terminal hyperlinks, that use the following notation:
echo -e '\e]8;;http://example.com\e\\This is a link\e]8;;\e\\'
(more on this here: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda )
are currently not supported (i.e. the whole string, including the hyperlink
is considered to be visible, what is generally speaking wrong; because
even the terminals that do not support hyperlinks show only the visible part of the link, the link caption).
Example:
$ # correct
$ python -c 'import ansiwrap; print ansiwrap.fill("This is a link. "*10); '
This is a link. This is a link. This is a link. This is a link. This
is a link. This is a link. This is a link. This is a link. This is a
link. This is a link.
$ # wrong
$ python -c 'import ansiwrap; print ansiwrap.fill("\x1B]8;;http://example.com\x1B\\This is a link\x1B]8;;\x1B\\. "*10); '
This is a link.
This is a link.
This is a link.
This is a link.
This is a link.
This is a link.
This is a link.
This is a link.
This is a link.
This is a link.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.