Skip to content

Commit b3639a4

Browse files
authored
make output colorful (#1114)
* document tox profiles
1 parent 26870e3 commit b3639a4

File tree

6 files changed

+119
-8
lines changed

6 files changed

+119
-8
lines changed

cwltool/main.py

+13-7
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
windows_default_container_id)
6060
from .subgraph import get_subgraph
6161

62+
import coloredlogs
63+
6264
def _terminate_processes():
6365
# type: () -> None
6466
"""Kill all spawned processes.
@@ -495,12 +497,12 @@ def main(argsl=None, # type: List[str]
495497
stdout = cast(TextIO, sys.stdout) # type: ignore
496498

497499
_logger.removeHandler(defaultStreamHandler)
500+
stderr_handler = logger_handler
498501
if logger_handler is not None:
499-
stderr_handler = logger_handler
502+
_logger.addHandler(stderr_handler)
500503
else:
501-
stderr_handler = logging.StreamHandler(stderr)
502-
_logger.addHandler(stderr_handler)
503-
# pre-declared for finally block
504+
coloredlogs.install(logger=_logger, stream=stderr)
505+
stderr_handler = _logger.handlers[-1]
504506
workflowobj = None
505507
prov_log_handler = None # type: Optional[logging.StreamHandler]
506508
try:
@@ -542,12 +544,16 @@ def main(argsl=None, # type: List[str]
542544
if runtimeContext.debug:
543545
# Increase to debug for both stderr and provenance log file
544546
_logger.setLevel(logging.DEBUG)
547+
stderr_handler.setLevel(logging.DEBUG)
545548
rdflib_logger.setLevel(logging.DEBUG)
546549
formatter = None # type: Optional[logging.Formatter]
547550
if args.timestamps:
548-
formatter = logging.Formatter("[%(asctime)s] %(message)s",
549-
"%Y-%m-%d %H:%M:%S")
550-
stderr_handler.setFormatter(formatter)
551+
formatter = coloredlogs.ColoredFormatter(
552+
"[%(asctime)s] %(levelname)s %(message)s",
553+
"%Y-%m-%d %H:%M:%S")
554+
else:
555+
formatter = coloredlogs.ColoredFormatter("%(levelname)s %(message)s")
556+
stderr_handler.setFormatter(formatter)
551557
##
552558

553559
if args.version:

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ psutil
1212
scandir
1313
subprocess32 >= 3.5.0; os.name=="posix" and python_version<"3.5"
1414
typing-extensions
15+
coloredlogs

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
'prov == 1.5.1',
6666
'bagit >= 1.6.4',
6767
'typing-extensions',
68+
'coloredlogs',
6869
],
6970
extras_require={
7071
':os.name=="posix" and python_version<"3.5"': ['subprocess32 >= 3.5.0'],

tests/test_ext.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,6 @@ def test_warn_large_inputs():
191191
main([get_data('tests/wf/listing_v1_0.cwl'), get_data('tests/listing2-job.yml')],
192192
stderr=stream)
193193

194-
assert "Recursive directory listing has resulted in a large number of File objects" in re.sub("\n *", " ", stream.getvalue())
194+
assert "Recursive directory listing has resulted in a large number of File" in re.sub("\n *", " ", stream.getvalue())
195195
finally:
196196
cwltool.process.FILE_COUNT_WARNING = was

tox.ini

+9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ python =
2020
3.8-dev: py38
2121

2222
[testenv]
23+
description =
24+
py{27,35,36,37,38}-unit: Run the unit tests
25+
py{27,35,36,37,38}-lint: Lint the Python code
26+
py{27,35,36,37,38}-bandit: Search for common security issues
27+
py{27,35,36,37,38}-mypy{2,3}: Check for type safety
28+
2329
passenv =
2430
CI
2531
TRAVIS
@@ -57,13 +63,15 @@ whitelist_externals =
5763
py{35,36,36,37,38}-mypy{2,3}: make
5864

5965
[testenv:py27-pipconflictchecker]
66+
description = Ensure that there are no dependency version conflicts
6067
commands = pipconflictchecker
6168
whitelist_externals = pipconflictchecker
6269
deps =
6370
pip-conflict-checker
6471
pip==9.0.3
6572

6673
[testenv:py27-lint-readme]
74+
description = Lint the README.rst->.md conversion
6775
commands =
6876
python setup.py sdist
6977
python setup.py bdist_wheel
@@ -74,6 +82,7 @@ deps =
7482
readme_renderer[md]
7583

7684
[testenv:py27-pydocstyle]
85+
description = docstring style checker
7786
whitelist_externals = make
7887
commands = make diff_pydocstyle_report
7988
deps =
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Stubs for coloredlogs (Python 3.7)
2+
#
3+
# NOTE: This dynamically typed stub was automatically generated by stubgen.
4+
5+
import logging
6+
from typing import Any, Optional
7+
8+
WINDOWS: Any
9+
NEED_COLORAMA = WINDOWS
10+
DEFAULT_LOG_LEVEL: Any
11+
DEFAULT_LOG_FORMAT: str
12+
DEFAULT_DATE_FORMAT: str
13+
CHROOT_FILES: Any
14+
CAN_USE_BOLD_FONT: Any
15+
DEFAULT_FIELD_STYLES: Any
16+
DEFAULT_LEVEL_STYLES: Any
17+
DEFAULT_FORMAT_STYLE: str
18+
FORMAT_STYLE_PATTERNS: Any
19+
20+
def auto_install() -> None: ...
21+
def install(level: Optional[Any] = ..., **kw: Any): ...
22+
def check_style(value: Any): ...
23+
def increase_verbosity() -> None: ...
24+
def decrease_verbosity() -> None: ...
25+
def is_verbose(): ...
26+
def get_level(): ...
27+
def set_level(level: Any) -> None: ...
28+
def adjust_level(logger: Any, level: Any) -> None: ...
29+
def find_defined_levels(): ...
30+
def level_to_number(value: Any): ...
31+
def find_level_aliases(): ...
32+
def parse_encoded_styles(text: Any, normalize_key: Optional[Any] = ...): ...
33+
def find_hostname(use_chroot: bool = ...): ...
34+
def find_program_name(): ...
35+
def replace_handler(logger: Any, match_handler: Any, reconfigure: Any): ...
36+
def find_handler(logger: Any, match_handler: Any): ...
37+
def match_stream_handler(handler: Any, streams: Any = ...): ...
38+
def walk_propagation_tree(logger: Any) -> None: ...
39+
40+
class BasicFormatter(logging.Formatter):
41+
def formatTime(self, record: Any, datefmt: Optional[Any] = ...): ...
42+
43+
class ColoredFormatter(BasicFormatter):
44+
nn: Any = ...
45+
log_record_factory: Any = ...
46+
level_styles: Any = ...
47+
field_styles: Any = ...
48+
def __init__(self, fmt: Optional[Any] = ..., datefmt: Optional[Any] = ..., level_styles: Optional[Any] = ..., field_styles: Optional[Any] = ..., style: Any = ...) -> None: ...
49+
def colorize_format(self, fmt: Any, style: Any = ...): ...
50+
def format(self, record: Any): ...
51+
52+
class Empty: ...
53+
54+
class HostNameFilter(logging.Filter):
55+
@classmethod
56+
def install(cls, handler: Any, fmt: Optional[Any] = ..., use_chroot: bool = ..., style: Any = ...): ...
57+
hostname: Any = ...
58+
def __init__(self, use_chroot: bool = ...) -> None: ...
59+
def filter(self, record: Any): ...
60+
61+
class ProgramNameFilter(logging.Filter):
62+
@classmethod
63+
def install(cls, handler: Any, fmt: Any, programname: Optional[Any] = ..., style: Any = ...): ...
64+
programname: Any = ...
65+
def __init__(self, programname: Optional[Any] = ...) -> None: ...
66+
def filter(self, record: Any): ...
67+
68+
class StandardErrorHandler(logging.StreamHandler):
69+
def __init__(self, level: Any = ...) -> None: ...
70+
@property
71+
def stream(self): ...
72+
73+
class FormatStringParser:
74+
style: Any = ...
75+
capturing_pattern: Any = ...
76+
raw_pattern: Any = ...
77+
tokenize_pattern: Any = ...
78+
name_pattern: Any = ...
79+
def __init__(self, style: Any = ...) -> None: ...
80+
def contains_field(self, format_string: Any, field_name: Any): ...
81+
def get_field_names(self, format_string: Any): ...
82+
def get_grouped_pairs(self, format_string: Any): ...
83+
def get_pairs(self, format_string: Any) -> None: ...
84+
def get_pattern(self, field_name: Any): ...
85+
def get_tokens(self, format_string: Any): ...
86+
87+
class FormatStringToken: ...
88+
89+
class NameNormalizer:
90+
aliases: Any = ...
91+
def __init__(self) -> None: ...
92+
def normalize_name(self, name: Any): ...
93+
def normalize_keys(self, value: Any): ...
94+
def get(self, normalized_dict: Any, name: Any): ...

0 commit comments

Comments
 (0)