diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 4a65b6c..fc44d47 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -9,4 +9,6 @@ # open_collective: # Replace with a single Open Collective username # otechie: # Replace with a single Otechie username # patreon: # Replace with a single Patreon username +custom: ["https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama¤cy_code=USD"] tidelift: "pypi/colorama" + diff --git a/.gitignore b/.gitignore index 202551b..b8d794f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,11 +2,12 @@ *.egg-info .coverage .tox/ -MANIFEST -dist -tags +/MANIFEST +/build/ +/dist/ +/sandbox/ +/tags virtualenv -build # PyCharm .idea diff --git a/.travis.yml b/.travis.yml index 7e11b00..706b55c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ cache: pip matrix: include: - python: 2.7 + - python: 3.9 - python: 3.8 - arch: arm64 python: 3.7 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f88f449..555941c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,23 @@ +0.4.6 + * Support reverse video and underline on Windows 10 +0.4.5 In progress, unreleased + * Create README-hacking.md, for Colorama contributors. + * Tweak some README unicode characters that don't render correctly on PyPI. + * Fix some tests that were failing on some operating systems. + * Add support for Python 3.9. +0.4.4 Current release + * Re-org of README, to put the most insteresting parts near the top. + * Added Linux makefile targets and Windows powershell scripts to + automate bootstrapping a development environment, and automate the + process of testing wheels before they are uploaded to PyPI. + * Use stdlib unittest.mock where available + * Travis CI now also builds on arm64 + * Demo06 demonstrates existing cursor positioning feature + * Fix OSC regex & handling to prevent hang or crash + * Document enterprise support by Tidelift 0.4.3 * Fix release 0.4.2 which was uploaded with missing files. -0.4.2 +0.4.2 BROKEN DO NOT USE * #228: Drop support for EOL Python 3.4, and add 3.7 and 3.8. Thanks to hugovk. * Several additions and fixes to documentation and metadata. diff --git a/Makefile b/Makefile index 312bd5e..a0b8987 100644 --- a/Makefile +++ b/Makefile @@ -10,24 +10,56 @@ help: ## Display help for documented make targets. @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-7s\033[0m %s\n", $$1, $$2}' -clean: ## Remove build artifacts and .pyc files - -rm -rf build dist MANIFEST colorama.egg-info + +# bootstrap environment + +virtualenv=~/.virtualenvs/colorama +pip=$(virtualenv)/bin/pip +syspython=python3.8 +python=$(virtualenv)/bin/python +twine=$(virtualenv)/bin/twine +version=$(shell $(python) setup.py --version) + +clean: ## Remove build artifacts, .pyc files, virtualenv + -rm -rf build dist MANIFEST colorama.egg-info $(virtualenv) -find . -type f -name '*.py[co]' -delete -o -type d -name __pycache__ -delete .PHONY: clean -build: clean ## Build an sdist and wheel - python setup.py sdist bdist_wheel -.PHONY: sdist +$(virtualenv): + $(syspython) -m venv --clear $(virtualenv) + $(pip) install --upgrade pip -upload: ## Upload our sdist and wheel - twine upload dist/* -.PHONY: release +venv: $(virtualenv) ## Create or clear a virtualenv +.PHONY: venv + +bootstrap: venv ## Populate the virtualenv + $(pip) install -r requirements.txt -r requirements-dev.txt +.PHONY: bootstrap -test: ## Run tests - python -m unittest discover -p *_test.py -.PHONY: test + +# development tags: ## Create tags file ctags -R ${NAME} .PHONY: tags +test: ## Run tests + $(python) -m unittest discover -p *_test.py +.PHONY: test + + +# build packages + +build: ## Build a release (sdist and wheel) + $(python) -m pip install --upgrade setuptools wheel + $(python) setup.py sdist bdist_wheel +.PHONY: build + +test-release: build ## Test a built release + ./test-release +.PHONY: test-release + +release: ## Upload a built release + $(twine) upload dist/colorama-$(version)*{.whl,.tar.gz} +.PHONY: release + diff --git a/README-hacking.md b/README-hacking.md new file mode 100644 index 0000000..8cc5b55 --- /dev/null +++ b/README-hacking.md @@ -0,0 +1,83 @@ +# Colorama Development + +Help and fixes are welcome! + +Although Colorama has no requirements other than the Python standard library, +development requires some Python packages, which are captured in +requirements-dev.txt. + +Throughout, if you're on a Mac, you can probably do something similar to the +Linux instructions. Either use the makefile directly, or look in it to see +what commands it executes, and manually execute something similar. PRs to +automate for Mac appreciated! Especially if they just made the existing Linux +Makefile targets work on Mac too. + +## Makefile and PowerShell scripts + +Some common commands are captured as Linux makefile targets (which could +perhaps be coaxed into running on OSX in Bash), and as Windows PowerShell +scripts. + +| Task | Linux | Windows | +|---------------------------------|---------------------|----------------------| +| Create & populate virtualenv. | `make bootstrap` | `.\bootstrap.ps1` | +| Run tests. | `make test` | `.\test.ps1` | +| Build a wheel. | `make build` | `.\build.ps1` | +| Test the wheel. | `make test-release` | `.\test-release.ps1` | +| Release the wheel on PyPI | `make release` | `.\release.ps1` | +| Clean generated files & builds. | `make clean` | `.\clean.ps1` | + +The Makefile is self-documenting, so 'make' with no args will describe each +target. + +## Release checklist + +1. Check the CHANGELOG is updated with everything since the last release. +2. Remove the '-pre' suffix from `__version__` in `colorama/__init.py__.py`. +3. Run the tests locally on your preferred OS, just to save you from doing + the following time-consuming steps while there are still obvious problems + in the code: + + * Windows: `./test.ps1` + * Linux: `make test` + +4. Verify you're all committed, merged to master, and pushed to origin (This + triggers a Travis build, which we'll check later on) + +5. Build the distributables (sdist and wheel), on either OS: + + * Windows: `.\build.ps1` + * Linux: `make build` + +6. Test the distributables on both OS. Whichever one you do 2nd will get an + HTTP 400 response on uploading to test.pypi.org, but outputs a message + saying this is expected and carries on: + + * Windows: `./clean.ps1 && .\bootstrap.ps1 && .\build.ps1 && + .\test-release.ps1` + * Linux: `make clean bootstrap build test-release` + + (This currently only tests the wheel, but + [should soon test the sdist too](https://github.com/tartley/colorama/issues/286).) + +7. Check the [Travis builds](https://travis-ci.org/github/tartley/colorama) + are complete and all passing. (This currently only tests on Linux, but + [should soon run on Windows too](https://github.com/tartley/colorama/issues/283).) + +8. Upload the distributables to PyPI: + + * On Windows: `.\release.ps1` + * On Linux: `make release` + + This [should soon tag the release for you](https://github.com/tartley/colorama/issues/282). Until then: + +9. Tag the current commit with the `__version__` from `colorama/__init__.py`. + We should start using + [annotated tags for releases](https://www.tartley.com/posts/til-git-annotated-tags/), so: + + git tag -a -m "" $version + git push --follow-tags + +10. Bump the version number in `colorama/__init__.py`, and add the '-pre' + suffix again, ready for the next release. Commit and push this (directly to + master is fine.) diff --git a/README.rst b/README.rst index 9a5f7d0..e03e51f 100644 --- a/README.rst +++ b/README.rst @@ -10,19 +10,41 @@ :target: https://travis-ci.org/tartley/colorama :alt: Build Status -Download and docs: - https://pypi.org/project/colorama/ -Source code & Development: - https://github.com/tartley/colorama -Colorama for Enterprise: - https://github.com/tartley/colorama/blob/master/ENTERPRISE.md -Description -=========== +Colorama +======== Makes ANSI escape character sequences (for producing colored terminal text and cursor positioning) work under MS Windows. +.. |donate| image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama¤cy_code=USD + :alt: Donate with Paypal + +`PyPI for releases `_ | +`Github for source `_ | +`Colorama for enterprise on Tidelift `_ + +If you find Colorama useful, please |donate| to the authors. Thank you! + + +Installation +------------ + +Tested on CPython 2.7, 3.5, 3.6, 3.7, 3.8 and 3.9 and Pypy 2.7. + +No requirements other than the standard library. + +.. code-block:: bash + + pip install colorama + # or + conda install -c anaconda colorama + + +Description +----------- + ANSI escape character sequences have long been used to produce colored terminal text and cursor positioning on Unix and Macs. Colorama makes this work on Windows, too, by wrapping ``stdout``, stripping ANSI sequences it finds (which @@ -30,11 +52,6 @@ would appear as gobbledygook in the output), and converting them into the appropriate win32 calls to modify the state of the terminal. On other platforms, Colorama does nothing. -Colorama also provides some shortcuts to help generate ANSI sequences -but works fine in conjunction with any other ANSI sequence generation library, -such as the venerable Termcolor (https://pypi.org/project/termcolor/) -or the fabulous Blessings (https://pypi.org/project/blessings/). - This has the upshot of providing a simple cross-platform API for printing colored terminal text from Python, and has the happy side-effect that existing applications or libraries which use ANSI sequences to produce colored output on @@ -60,26 +77,14 @@ handling, versus on Windows Command-Prompt using Colorama: :height: 325 :alt: Same ANSI sequences on Windows, using Colorama. -These screengrabs show that, on Windows, Colorama does not support ANSI 'dim +These screenshots show that, on Windows, Colorama does not support ANSI 'dim text'; it looks the same as 'normal text'. - -License -======= - -Copyright Jonathan Hartley & Arnon Yaari, 2013. BSD 3-Clause license; see LICENSE file. - - -Dependencies -============ - -None, other than Python. Tested on Python 2.7, 3.5, 3.6, 3.7 and 3.8. - Usage -===== +----- Initialisation --------------- +.............. Applications should initialise Colorama using: @@ -97,14 +102,14 @@ optional functionality; see "Init Keyword Args", below). By design, this permits applications to call ``init()`` unconditionally on all platforms, after which ANSI output should just work. -To stop using colorama before your program exits, simply call ``deinit()``. +To stop using Colorama before your program exits, simply call ``deinit()``. This will restore ``stdout`` and ``stderr`` to their original values, so that Colorama is disabled. To resume using Colorama again, call ``reinit()``; it is cheaper than calling ``init()`` again (but does the same thing). Colored Output --------------- +.............. Cross-platform printing of colored text can then be done using Colorama's constant shorthand for ANSI escape sequences: @@ -125,8 +130,10 @@ constant shorthand for ANSI escape sequences: print('\033[31m' + 'some red text') print('\033[39m') # and reset to default color -...or, Colorama can be used happily in conjunction with existing ANSI libraries -such as Termcolor: +...or, Colorama can be used in conjunction with existing ANSI libraries +such as the venerable `Termcolor `_ +or the fabulous `Blessings `_. +This is highly recommended for anything more than trivial coloring: .. code-block:: python @@ -150,14 +157,14 @@ perform this reset automatically on program exit. Cursor Positioning ------------------- +.................. ANSI codes to reposition the cursor are supported. See ``demos/demo06.py`` for an example of how to generate them. Init Keyword Args ------------------ +................. ``init()`` accepts some ``**kwargs`` to override default behaviour. @@ -174,7 +181,7 @@ init(autoreset=False): print('automatically back to default color again') init(strip=None): - Pass ``True`` or ``False`` to override whether ansi codes should be + Pass ``True`` or ``False`` to override whether ANSI codes should be stripped from the output. The default behaviour is to strip if on Windows or if output is redirected (not a tty). @@ -184,7 +191,7 @@ init(convert=None): and output is to a tty (terminal). init(wrap=True): - On Windows, colorama works by replacing ``sys.stdout`` and ``sys.stderr`` + On Windows, Colorama works by replacing ``sys.stdout`` and ``sys.stderr`` with proxy objects, which override the ``.write()`` method to do their work. If this wrapping causes you problems, then this can be disabled by passing ``init(wrap=False)``. The default behaviour is to wrap if ``autoreset`` or @@ -208,39 +215,10 @@ init(wrap=True): print(Fore.BLUE + 'blue text on stderr', file=stream) -Installation -======================= -colorama is currently installable from PyPI: - - pip install colorama - -colorama also can be installed by the conda package manager: - - conda install -c anaconda colorama - - -Status & Known Problems -======================= - -I've personally only tested it on Windows XP (CMD, Console2), Ubuntu -(gnome-terminal, xterm), and OS X. - -Some presumably valid ANSI sequences aren't recognised (see details below), -but to my knowledge nobody has yet complained about this. Puzzling. - -See outstanding issues and wishlist: -https://github.com/tartley/colorama/issues - -If anything doesn't work for you, or doesn't do what you expected or hoped for, -I'd love to hear about it on that issues list, would be delighted by patches, -and would be happy to grant commit access to anyone who submits a working patch -or two. - - Recognised ANSI Sequences -========================= +......................... -ANSI sequences generally take the form: +ANSI sequences generally take the form:: ESC [ ; ... @@ -249,7 +227,7 @@ more params are passed to a ````. If no params are passed, it is generally synonymous with passing a single zero. No spaces exist in the sequence; they have been inserted here simply to read more easily. -The only ANSI sequences that colorama converts into win32 calls are:: +The only ANSI sequences that Colorama converts into win32 calls are:: ESC [ 0 m # reset all (colors and brightness) ESC [ 1 m # bright @@ -306,29 +284,37 @@ them though. Let me know if it would be useful for you, via the Issues on GitHub. -Development -=========== +Status & Known Problems +----------------------- + +I've personally only tested it on Windows XP (CMD, Console2), Ubuntu +(gnome-terminal, xterm), and OS X. + +Some presumably valid ANSI sequences aren't recognised (see details below), +but to my knowledge nobody has yet complained about this. Puzzling. -Help and fixes welcome! +See outstanding issues and wish-list: +https://github.com/tartley/colorama/issues -Running tests requires: +If anything doesn't work for you, or doesn't do what you expected or hoped for, +I'd love to hear about it on that issues list, would be delighted by patches, +and would be happy to grant commit access to anyone who submits a working patch +or two. -- Michael Foord's ``mock`` module to be installed on Python < 3.3. -- Tests are written using 2010-era updates to ``unittest`` +If you're hacking on the code, see `README-hacking.md`_. -To run tests:: +.. _README-hacking.md: README-hacking.md - python -m unittest discover -p *_test.py -This, like a few other handy commands, is captured in a ``Makefile``. +License +------- -If you use nose to run the tests, you must pass the ``-s`` flag; otherwise, -``nosetests`` applies its own proxy to ``stdout``, which confuses the unit -tests. +Copyright Jonathan Hartley & Arnon Yaari, 2013-2020. BSD 3-Clause license; see +LICENSE file. Professional support -==================== +-------------------- .. |tideliftlogo| image:: https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png :alt: Tidelift @@ -349,7 +335,8 @@ Professional support Thanks -====== +------ + * Marc Schlaich (schlamar) for a ``setup.py`` fix for Python2.5. * Marc Abramowitz, reported & fixed a crash on exit with closed ``stdout``, providing a solution to issue #7's setuptools/distutils debate, diff --git a/bootstrap.ps1 b/bootstrap.ps1 new file mode 100644 index 0000000..3260f8b --- /dev/null +++ b/bootstrap.ps1 @@ -0,0 +1,9 @@ +$syspython="python3.8.exe" +$ve="$HOME\.virtualenvs\colorama" +$bin="$ve\Scripts" + +echo "Create $syspython virtualenv $ve" +& $syspython -m venv --clear "$ve" +& $bin\python.exe -m pip install --upgrade pip +& $bin\python.exe -m pip install -r requirements.txt -r requirements-dev.txt + diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..a48e357 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,6 @@ +$ve="$HOME\.virtualenvs\colorama" +$bin="$ve\Scripts" + +& $bin\python.exe -m pip install --upgrade setuptools wheel +& $bin\python.exe setup.py sdist bdist_wheel + diff --git a/clean.ps1 b/clean.ps1 new file mode 100644 index 0000000..de9ba5a --- /dev/null +++ b/clean.ps1 @@ -0,0 +1,6 @@ +$syspython="python3.8.exe" +$ve="$HOME\.virtualenvs\colorama" + +remove-item -r -fo * -I build,dist,MANIFEST,colorama.egg-info,$ve,sandbox +& $syspython -Bc "import pathlib, shutil; [shutil.rmtree(p) for p in pathlib.Path('.').rglob('__pycache__')]" + diff --git a/colorama/__init__.py b/colorama/__init__.py index b149ed7..6502bed 100644 --- a/colorama/__init__.py +++ b/colorama/__init__.py @@ -3,4 +3,4 @@ from .ansi import Fore, Back, Style, Cursor from .ansitowin32 import AnsiToWin32 -__version__ = '0.4.4' +__version__ = '0.4.6-pre' diff --git a/colorama/ansi.py b/colorama/ansi.py index 11ec695..1c8aba9 100644 --- a/colorama/ansi.py +++ b/colorama/ansi.py @@ -91,10 +91,17 @@ class AnsiBack(AnsiCodes): class AnsiStyle(AnsiCodes): - BRIGHT = 1 - DIM = 2 - NORMAL = 22 - RESET_ALL = 0 + BRIGHT = 1 + DIM = 2 + BRIGHT_OFF = 21 # Produces double-underline on some terminals. + NORMAL = 22 + RESET_ALL = 0 + + UNDERLINE = 4 + UNDERLINE_OFF = 24 + REVERSE = 7 + REVERSE_OFF = 27 + Fore = AnsiFore() Back = AnsiBack() diff --git a/colorama/ansitowin32.py b/colorama/ansitowin32.py index 6039a05..38abb6d 100644 --- a/colorama/ansitowin32.py +++ b/colorama/ansitowin32.py @@ -2,16 +2,21 @@ import re import sys import os +import platform from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style, BEL from .winterm import WinTerm, WinColor, WinStyle -from .win32 import windll, winapi_test - +from .win32 import windll, winapi_test, STDOUT, ENABLE_VIRTUAL_TERMINAL_PROCESSING winterm = None if windll is not None: winterm = WinTerm() +# Track whether we've enabled Win 10 virtual terminal, and +# what the original mode was set to. +we_enabled_windows_vt = False +old_mode_value = None + class StreamWrapper(object): ''' @@ -25,6 +30,7 @@ def __init__(self, wrapped, converter): self.__wrapped = wrapped self.__convertor = converter + def __getattr__(self, name): return getattr(self.__wrapped, name) @@ -71,6 +77,8 @@ class AnsiToWin32(object): ANSI_OSC_RE = re.compile('\001?\033\\]([^\a]*)(\a)\002?') # Operating System Command def __init__(self, wrapped, convert=None, strip=None, autoreset=False): + global old_mode_value + global we_enabled_windows_vt # The wrapped stream (normally sys.stdout or sys.stderr) self.wrapped = wrapped @@ -80,12 +88,38 @@ def __init__(self, wrapped, convert=None, strip=None, autoreset=False): # create the proxy wrapping our output stream self.stream = StreamWrapper(wrapped, self) + conversion_supported = True on_windows = os.name == 'nt' # We test if the WinAPI works, because even if we are on Windows # we may be using a terminal that doesn't support the WinAPI # (e.g. Cygwin Terminal). In this case it's up to the terminal # to support the ANSI codes. - conversion_supported = on_windows and winapi_test() + if on_windows and platform.release().startswith('10'): + # Windows 10 supports ANSI sequences using virtual terminal mode. + # However, this has been turned off by default from an early Windows 10 version. + # We turn virtual terminal support back on, then set + # `conversion_supported` to False. Behaviour will then be the same + # as for Linux - colorama doesn't use win32 calls. + from ctypes import wintypes, byref # import wintypes now we know we're on Windows. + old_mode = wintypes.DWORD() + + stdout_handle = windll.kernel32.GetStdHandle(STDOUT) + # If the next call failed, we may be running on Windows pre 10.0.10586. + # Leave ANSI handling to colorama, there's no virtual terminal support available. + if windll.kernel32.GetConsoleMode(stdout_handle, byref(old_mode)): + if not (old_mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING): + if old_mode_value is None: + # Don't set this again. __init__ gets called twice, for stdout and stderr. + old_mode_value = old_mode.value + # Only enable if it's not already enabled + if windll.kernel32.SetConsoleMode(stdout_handle, old_mode_value | ENABLE_VIRTUAL_TERMINAL_PROCESSING): + we_enabled_windows_vt = True + + conversion_supported = False + + # If not on Windows 10, we have colorama's previous behaviour. + # Make sure we don't stomp on `conversion_supported` if it was set False above. + conversion_supported = conversion_supported and on_windows and winapi_test() # should we strip ANSI sequences from our output? if strip is None: @@ -120,6 +154,13 @@ def get_win32_calls(self): AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), + AnsiStyle.BRIGHT_OFF: (winterm.style, WinStyle.NORMAL), + + AnsiStyle.UNDERLINE: (winterm.not_implemented, WinStyle.UNDERLINE), + AnsiStyle.UNDERLINE_OFF: (winterm.not_implemented, WinStyle.UNDERLINE_OFF), + AnsiStyle.REVERSE: (winterm.not_implemented, WinStyle.REVERSE), + AnsiStyle.REVERSE_OFF: (winterm.not_implemented, WinStyle.REVERSE_OFF), + AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), AnsiFore.RED: (winterm.fore, WinColor.RED), AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), @@ -168,11 +209,21 @@ def write(self, text): def reset_all(self): + global we_enabled_windows_vt if self.convert: self.call_win32('m', (0,)) elif not self.strip and not self.stream.closed: self.wrapped.write(Style.RESET_ALL) + print("AnsiToWin32.reset_all() called") + if we_enabled_windows_vt: + stdout_handle = windll.kernel32.GetStdHandle(STDOUT) + # We enabled it, so turn it off again. + windll.kernel32.SetConsoleMode(stdout_handle, old_mode_value) + we_enabled_windows_vt = False + print("disabled virtual terminal on " + str(self.stream)) + print("restored to " + str(old_mode_value)) + def write_and_convert(self, text): ''' diff --git a/colorama/tests/ansitowin32_test.py b/colorama/tests/ansitowin32_test.py index 99ebd29..bbe99f4 100644 --- a/colorama/tests/ansitowin32_test.py +++ b/colorama/tests/ansitowin32_test.py @@ -170,13 +170,19 @@ def test_reset_all_shouldnt_raise_on_closed_orig_stdout(self): def test_wrap_shouldnt_raise_on_closed_orig_stdout(self): stream = StringIO() stream.close() - converter = AnsiToWin32(stream) - self.assertFalse(converter.strip) + with \ + patch("colorama.ansitowin32.os.name", "nt"), \ + patch("colorama.ansitowin32.winapi_test", lambda: True): + converter = AnsiToWin32(stream) + self.assertTrue(converter.strip) self.assertFalse(converter.convert) def test_wrap_shouldnt_raise_on_missing_closed_attr(self): - converter = AnsiToWin32(object()) - self.assertFalse(converter.strip) + with \ + patch("colorama.ansitowin32.os.name", "nt"), \ + patch("colorama.ansitowin32.winapi_test", lambda: True): + converter = AnsiToWin32(object()) + self.assertTrue(converter.strip) self.assertFalse(converter.convert) def testExtractParams(self): diff --git a/colorama/tests/undrev_test.py b/colorama/tests/undrev_test.py new file mode 100644 index 0000000..4271da5 --- /dev/null +++ b/colorama/tests/undrev_test.py @@ -0,0 +1,50 @@ +import colorama +# some ANSI escape sequence for colours and effects. +BLACK = '\u001b[30m' +RED = '\u001b[31m' +GREEN = '\u001b[32m' +YELLOW = '\u001b[33m' +BLUE = '\u001b[34m' +MAGENTA = '\u001b[35m' +CYAN = '\u001b[36m' +WHITE = '\u001b[37m' +RESET = '\u001b[0m' + +BOLD = '\u001b[1m' +UNDERLINE = '\u001b[4m' +REVERSE = '\u001b[7m' + + +print(RED, "this will be in red") +print(" and this one also") + +print() + +def colour_print(text: str, effect: str) -> None: + """ + Print 'text' using the ANSI sequence to change colour, etc + :param text: The text we want to print + :param effect: The effect we want. One of the constants + defined at the start of this module. + """ + output_string = "{0}{1}{2}".format(effect, text, RESET) + print(output_string) + + +# colorama.init() +colour_print("Hello, red", RED) +# Check that the colour was reset. +print("This should be in the default terminal colour") +colour_print("Hello, Blue", BLUE) +colour_print("Hello, Yellow", YELLOW) +colour_print("Hello, Bold", BOLD) +colour_print("Hello, Underline", UNDERLINE) +colour_print("Hello, Reverse", REVERSE) +colour_print("Hello, Black", BLACK) + +print(colorama.Style.REVERSE_OFF + colorama.Back.GREEN + "off?" + colorama.Style.RESET_ALL) +print(colorama.Style.REVERSE + colorama.Back.GREEN + "off?" + colorama.Style.RESET_ALL) + +print(colorama.Style.REVERSE + colorama.Style.REVERSE_OFF + colorama.Back.GREEN + "off?" + colorama.Style.RESET_ALL) + +# colorama.deinit() diff --git a/colorama/win32.py b/colorama/win32.py index c2d8360..5242ffe 100644 --- a/colorama/win32.py +++ b/colorama/win32.py @@ -3,6 +3,7 @@ # from winbase.h STDOUT = -11 STDERR = -12 +ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 try: import ctypes diff --git a/colorama/winterm.py b/colorama/winterm.py index 0fdb4ec..a63503b 100644 --- a/colorama/winterm.py +++ b/colorama/winterm.py @@ -13,11 +13,18 @@ class WinColor(object): YELLOW = 6 GREY = 7 + # from wincon.h class WinStyle(object): - NORMAL = 0x00 # dim text, dim background - BRIGHT = 0x08 # bright text, dim background - BRIGHT_BACKGROUND = 0x80 # dim text, bright background + NORMAL = 0x00 # dim text, dim background + BRIGHT = 0x08 # bright text, dim background + BRIGHT_BACKGROUND = 0x80 # dim text, bright background + + REVERSE = 0x4000 + REVERSE_OFF = REVERSE + UNDERLINE = 0x8000 + UNDERLINE_OFF = UNDERLINE + class WinTerm(object): @@ -167,3 +174,6 @@ def erase_line(self, mode=0, on_stderr=False): def set_title(self, title): win32.SetConsoleTitle(title) + + def not_implemented(self, *args, **kwargs): + pass diff --git a/demos/demo01.py b/demos/demo01.py index 99d896a..3f58b3d 100644 --- a/demos/demo01.py +++ b/demos/demo01.py @@ -18,7 +18,7 @@ # the foreground, background and style. The don't have any magic of their own. FORES = [ Fore.BLACK, Fore.RED, Fore.GREEN, Fore.YELLOW, Fore.BLUE, Fore.MAGENTA, Fore.CYAN, Fore.WHITE ] BACKS = [ Back.BLACK, Back.RED, Back.GREEN, Back.YELLOW, Back.BLUE, Back.MAGENTA, Back.CYAN, Back.WHITE ] -STYLES = [ Style.DIM, Style.NORMAL, Style.BRIGHT ] +STYLES = [ Style.DIM, Style.NORMAL, Style.BRIGHT, Style.UNDERLINE, Style.REVERSE ] NAMES = { Fore.BLACK: 'black', Fore.RED: 'red', Fore.GREEN: 'green', Fore.YELLOW: 'yellow', Fore.BLUE: 'blue', Fore.MAGENTA: 'magenta', Fore.CYAN: 'cyan', Fore.WHITE: 'white' @@ -30,7 +30,7 @@ # show the color names sys.stdout.write(' ') for foreground in FORES: - sys.stdout.write('%s%-7s' % (foreground, NAMES[foreground])) + sys.stdout.write('%s%-11s' % (foreground, NAMES[foreground])) print() # make a row for each background color diff --git a/release.ps1 b/release.ps1 new file mode 100644 index 0000000..ac4e268 --- /dev/null +++ b/release.ps1 @@ -0,0 +1,7 @@ +$ve="$HOME\.virtualenvs\colorama" +$bin="$ve\Scripts" +$version="$(& $bin\python.exe setup.py --version)" + +# Upload to PyPI. +& $bin\twine.exe upload dist\colorama-$version*.tar.gz dist\colorama-$version-*.whl + diff --git a/screenshots/ubuntu-demo.png b/screenshots/ubuntu-demo.png index 140a6ca..af70b2e 100644 Binary files a/screenshots/ubuntu-demo.png and b/screenshots/ubuntu-demo.png differ diff --git a/screenshots/windows-demo.png b/screenshots/windows-demo.png index efe5a60..485d348 100644 Binary files a/screenshots/windows-demo.png and b/screenshots/windows-demo.png differ diff --git a/setup.py b/setup.py index 31720d0..4e75c12 100644 --- a/setup.py +++ b/setup.py @@ -57,6 +57,7 @@ def get_version(path): 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Terminals', diff --git a/test-release b/test-release new file mode 100644 index 0000000..15812ef --- /dev/null +++ b/test-release @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# Test the currently built release of Colorama from the dist/ dir. +# Run this before making a release. +# +# This should be run on Windows, because Colorama is mostly a no-op elsewhere. +# Hmmm, this script should probably be a .bat file then? Nah, WSL FTW. +# +# Uploads package from the dist/ directory to the *test* PyPI. +# Create a fresh virtualenvironment and install colorama from test PyPI. +# Import Colorama and make trivial use of it. + +# Exit on error +set -eu -o pipefail + +syspython=python3.8 +bin="$HOME/.virtualenvs/colorama/bin" +version=$($bin/python setup.py --version) +sandbox=test-release-playground + +# Upload to the test PyPI. +$bin/twine upload --repository testpypi dist/colorama-$version-* \ + || echo " > Expect a 400 if package was already uploaded." + +# cd elsewhere so we cannot import from local source. +mkdir -p $sandbox +( + cd $sandbox + + # Create a temporary disposable virtualenv. + $syspython -m venv --clear venv + + # Install the package we just uploaded. + # (--extra-index-url for this project's requirements) + venv/bin/python -m pip --quiet install --index-url https://test.pypi.org/simple --extra-index-url https://pypi.org/simple colorama==$version + + # Import and use Colorama from the temp virtualenv. + venv/bin/python -c "import colorama; colorama.init(); print(colorama.Fore.GREEN + \"OK: Colorama\", colorama.__version__, \"from test pypi install.\")" +) + +# Tidy up +rm -rf $sandbox + diff --git a/test-release.ps1 b/test-release.ps1 new file mode 100644 index 0000000..19c6967 --- /dev/null +++ b/test-release.ps1 @@ -0,0 +1,30 @@ +$syspython="python3.8.exe" +$ve="$HOME\.virtualenvs\colorama" +$bin="$ve\Scripts" +$version="$(& $bin\python.exe setup.py --version)" + +# Upload to the test PyPI. +& $bin\twine.exe upload --repository testpypi dist\colorama-$version-* +if(!$?) { + write-host " > Expect a 400 if package was already uploaded" +} + +# cd elsewhere so we cannot import from local source. +mkdir -force sandbox | out-null +cd sandbox + +# Create a temporary disposable virtualenv. +& $syspython -m venv --clear venv + +# Install the package we just uploaded. +# (--extra-index-url for this project's requirements) +venv\Scripts\python -m pip --quiet install --index-url https://test.pypi.org/simple --extra-index-url https://pypi.org/simple colorama==$version +# Import and use colorama from the temp virtualenv. +venv\Scripts\python.exe -c @" +import colorama; +colorama.init(); +print(colorama.Fore.GREEN + ""OK Colorama "" + colorama.__version__ + "" from test pypi install."") +"@ + +cd .. + diff --git a/test.ps1 b/test.ps1 new file mode 100644 index 0000000..03ea144 --- /dev/null +++ b/test.ps1 @@ -0,0 +1,5 @@ +$ve="$HOME\.virtualenvs\colorama" +$bin="$ve\Scripts" + +& $bin\python.exe -m unittest discover -p *_test.py + diff --git a/tox.ini b/tox.ini index aa8c783..1588d99 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, py35, py36, py37, py38, pypy +envlist = py27, py35, py36, py37, py38, py39, pypy [testenv] deps = py27,pypy: mock