Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #20 from metachris/colorama
Browse files Browse the repository at this point in the history
Colorama / Color output in Windows
  • Loading branch information
metachris committed Jul 19, 2017
2 parents 37fdfa6 + 8ae23d6 commit 3a1abc5
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 53 deletions.
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ Features
* Easy logging to console and/or (rotating) file.
* Provides a fully configured standard `Python logger object <https://docs.python.org/2/library/logging.html#module-level-functions>`_.
* Pretty formatting, including level-specific colors in the console.
* Windows color output supported by `colorama`_
* Robust against str/bytes encoding problems, works with all kinds of character encodings and special characters.
* Multiple loggers can write to the same logfile (also across multiple Python files).
* Global default logger with `logzero.logger <https://logzero.readthedocs.io/en/latest/#i-logzero-logger>`_ and custom loggers with `logzero.setup_logger(..) <https://logzero.readthedocs.io/en/latest/#i-logzero-setup-logger>`_.
* Compatible with Python 2 and 3.
* All contained in a `single file`_.
* No further Python dependencies.
* Licensed under the MIT license.
* Heavily inspired by the `Tornado web framework`_.

Expand All @@ -53,6 +53,7 @@ Features

.. _single file: https://github.com/metachris/logzero/blob/master/logzero/__init__.py
.. _Tornado web framework: https://github.com/tornadoweb/tornado
.. _colorama: https://github.com/tartley/colorama


Example Usage
Expand Down Expand Up @@ -165,6 +166,7 @@ via https://cookiecutter-pypackage.readthedocs.io/en/latest/pypi_release_checkli
# Run the tests
py.test
make lint
tox
# Update history
vi HISTORY.rst
Expand Down
3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ Robust and effective logging for Python 2 and 3.
* Easy logging to console and/or (rotating) file.
* Provides a fully configured standard `Python logger object <https://docs.python.org/2/library/logging.html#module-level-functions>`_.
* Pretty formatting, including level-specific colors in the console.
* Windows color output supported by `colorama`_
* Robust against str/bytes encoding problems, works with all kinds of character encodings and special characters.
* Multiple loggers can write to the same logfile (also works across multiple Python files).
* Global default logger with `logzero.logger <#i-logzero-logger>`_ and custom loggers with `logzero.setup_logger(..) <#i-logzero-setup-logger>`_.
* Compatible with Python 2 and 3.
* All contained in a `single file`_.
* No further Python dependencies.
* Licensed under the MIT license.
* Heavily inspired by the `Tornado web framework`_.
* Hosted on GitHub: https://github.com/metachris/logzero
Expand Down Expand Up @@ -58,6 +58,7 @@ You can also install `logzero` from the public `Github repo`_:
.. _tarball: https://github.com/metachris/logzero/tarball/master
.. _single file: https://github.com/metachris/logzero/blob/master/logzero/__init__.py
.. _Tornado web framework: https://github.com/tornadoweb/tornado
.. _colorama: https://github.com/tartley/colorama


Example Usage
Expand Down
60 changes: 31 additions & 29 deletions logzero/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
logger.warn("warn")
logger.error("error")
In order to also log to a file, just add a `logfile` parameter:
In order to also log to a file, just use `logzero.logfile(..)`:
logzero.setup_default_logger(logfile="/tmp/test.log")
logzero.logfile("/tmp/test.log")
If you want to use specific loggers instead of the global default logger, use
`setup_logger(..)` instead of `setup_default_logger(..)`:
`setup_logger(..)`:
logger = logzero.setup_logger(logfile="/tmp/test.log")
Expand All @@ -34,8 +34,10 @@
See the documentation for more information: https://logzero.readthedocs.io
"""
import os
import sys
import logging
from logzero.colors import Fore as ForegroundColors
from logging.handlers import RotatingFileHandler

try:
Expand Down Expand Up @@ -75,6 +77,11 @@
_logfile = None
_formatter = None

# Setup colorama on Windows
if os.name == 'nt':
from colorama import init as colorama_init
colorama_init()


def setup_logger(name=None, logfile=None, level=logging.DEBUG, formatter=None, maxBytes=0, backupCount=0, fileLoglevel=None):
"""
Expand Down Expand Up @@ -149,10 +156,10 @@ class LogFormatter(logging.Formatter):
DEFAULT_FORMAT = '%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s'
DEFAULT_DATE_FORMAT = '%y%m%d %H:%M:%S'
DEFAULT_COLORS = {
logging.DEBUG: 4, # Blue
logging.INFO: 2, # Green
logging.WARNING: 3, # Yellow
logging.ERROR: 1, # Red
logging.DEBUG: ForegroundColors.CYAN,
logging.INFO: ForegroundColors.GREEN,
logging.WARNING: ForegroundColors.YELLOW,
logging.ERROR: ForegroundColors.RED
}

def __init__(self,
Expand All @@ -176,27 +183,12 @@ def __init__(self,
logging.Formatter.__init__(self, datefmt=datefmt)

self._fmt = fmt

self._colors = {}
self._normal = ''

if color and _stderr_supports_color():
# The curses module has some str/bytes confusion in
# python3. Until version 3.2.3, most methods return
# bytes, but only accept strings. In addition, we want to
# output these strings with the logging module, which
# works with unicode strings. The explicit calls to
# unicode() below are harmless in python2 but will do the
# right conversion in python 3.
fg_color = (curses.tigetstr("setaf") or curses.tigetstr("setf") or
"")
if (3, 0) < sys.version_info < (3, 2, 3):
fg_color = unicode_type(fg_color, "ascii")

for levelno, code in colors.items():
self._colors[levelno] = unicode_type(
curses.tparm(fg_color, code), "ascii")
self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii")
else:
self._normal = ''
self._colors = colors
self._normal = ForegroundColors.RESET

def format(self, record):
try:
Expand Down Expand Up @@ -248,15 +240,25 @@ def format(self, record):


def _stderr_supports_color():
color = False
# Colors can be forced with an env variable
if os.getenv('LOGZERO_FORCE_COLOR') == '1':
return True

# Windows supports colors with colorama
if os.name == 'nt':
return True

# Detect color support of stderr with curses (Linux/macOS)
if curses and hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():
try:
curses.setupterm()
if curses.tigetnum("colors") > 0:
color = True
return True

except Exception:
pass
return color

return False


_TO_UNICODE_TYPES = (unicode_type, type(None))
Expand Down
109 changes: 109 additions & 0 deletions logzero/colors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""
Source: https://github.com/tartley/colorama/blob/master/colorama/ansi.py
Copyright: Jonathan Hartley 2013. BSD 3-Clause license.
"""

CSI = '\033['
OSC = '\033]'
BEL = '\007'


def code_to_chars(code):
return CSI + str(code) + 'm'


def set_title(title):
return OSC + '2;' + title + BEL


def clear_screen(mode=2):
return CSI + str(mode) + 'J'


def clear_line(mode=2):
return CSI + str(mode) + 'K'


class AnsiCodes(object):
def __init__(self):
# the subclasses declare class attributes which are numbers.
# Upon instantiation we define instance attributes, which are the same
# as the class attributes but wrapped with the ANSI escape sequence
for name in dir(self):
if not name.startswith('_'):
value = getattr(self, name)
setattr(self, name, code_to_chars(value))


class AnsiCursor(object):
def UP(self, n=1):
return CSI + str(n) + 'A'

def DOWN(self, n=1):
return CSI + str(n) + 'B'

def FORWARD(self, n=1):
return CSI + str(n) + 'C'

def BACK(self, n=1):
return CSI + str(n) + 'D'

def POS(self, x=1, y=1):
return CSI + str(y) + ';' + str(x) + 'H'


class AnsiFore(AnsiCodes):
BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
WHITE = 37
RESET = 39

# These are fairly well supported, but not part of the standard.
LIGHTBLACK_EX = 90
LIGHTRED_EX = 91
LIGHTGREEN_EX = 92
LIGHTYELLOW_EX = 93
LIGHTBLUE_EX = 94
LIGHTMAGENTA_EX = 95
LIGHTCYAN_EX = 96
LIGHTWHITE_EX = 97


class AnsiBack(AnsiCodes):
BLACK = 40
RED = 41
GREEN = 42
YELLOW = 43
BLUE = 44
MAGENTA = 45
CYAN = 46
WHITE = 47
RESET = 49

# These are fairly well supported, but not part of the standard.
LIGHTBLACK_EX = 100
LIGHTRED_EX = 101
LIGHTGREEN_EX = 102
LIGHTYELLOW_EX = 103
LIGHTBLUE_EX = 104
LIGHTMAGENTA_EX = 105
LIGHTCYAN_EX = 106
LIGHTWHITE_EX = 107


class AnsiStyle(AnsiCodes):
BRIGHT = 1
DIM = 2
NORMAL = 22
RESET_ALL = 0


Fore = AnsiFore()
Back = AnsiBack()
Style = AnsiStyle()
Cursor = AnsiCursor()
1 change: 1 addition & 0 deletions requirements_windows.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
colorama==0.3.9
26 changes: 6 additions & 20 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,21 @@
with open('HISTORY.rst') as history_file:
history = history_file.read()

requirements = [
# TODO: put package requirements here
]

setup_requirements = [
'pytest-runner',
# TODO(metachris): put setup requirements (distutils extensions, etc.) here
]

test_requirements = [
'pytest',
# TODO: put package test requirements here
]

setup(
name='logzero',
version='1.2.1',
description="Python logging made easy",
description="Robust and effective logging for Python 2 and 3",
long_description=readme + '\n\n' + history,
author="Chris Hager",
author_email='chris@linuxuser.at',
url='https://github.com/metachris/logzero',
packages=find_packages(include=['logzero']),
include_package_data=True,
install_requires=requirements,
license="MIT license",
zip_safe=False,
keywords='logzero',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
Expand All @@ -51,8 +36,9 @@
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
test_suite='tests',
tests_require=test_requirements,
setup_requires=setup_requirements,
extras_require={
':sys_platform=="win32"': ['colorama']
}
)
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ commands =
[testenv]
setenv =
PYTHONPATH = {toxinidir}
deps = pytest
deps =
pytest
commands =
pip install -U pip
py.test --basetemp={envtmpdir}

0 comments on commit 3a1abc5

Please sign in to comment.