Skip to content

Commit cb7e116

Browse files
Use red text when printing errors on command line (#649)
* colorama shorthand ANSI sequence for red error text * ignore colorama imports in mypy config file * update tests and authors list * style * gracefully handle colorama not being available * remove colorama import exception handling * moving colorama.init() & remove local colorama bindings * add no-color flag * add no-color test * f-string colorama formatting in helper method * no-color option working for twine check with updated tests * Move --no-color to base command Co-authored-by: Brian Rutledge <[email protected]>
1 parent b1c2191 commit cb7e116

File tree

6 files changed

+39
-8
lines changed

6 files changed

+39
-8
lines changed

mypy.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ warn_return_any = True
1818
no_implicit_reexport = True
1919
strict_equality = True
2020

21+
[mypy-colorama]
22+
; https://github.com/tartley/colorama/issues/206
23+
ignore_missing_imports = True
24+
2125
[mypy-importlib_metadata]
2226
; https://gitlab.com/python-devs/importlib_metadata/-/issues/10
2327
ignore_missing_imports = True

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ install_requires=
4343
importlib_metadata; python_version < "3.8"
4444
keyring >= 15.1
4545
rfc3986 >= 1.4.0
46+
colorama >= 0.4.3
4647
setup_requires =
4748
setuptools_scm >= 1.15
4849
include_package_data = True

tests/test_main.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,20 @@
1010
# See the License for the specific language governing permissions and
1111
# limitations under the License.
1212

13-
import pretend
13+
import sys
14+
15+
import colorama
1416

1517
from twine import __main__ as dunder_main
16-
from twine import cli
17-
from twine import exceptions
1818

1919

2020
def test_exception_handling(monkeypatch):
21-
replaced_dispatch = pretend.raiser(exceptions.InvalidConfiguration("foo"))
22-
monkeypatch.setattr(cli, "dispatch", replaced_dispatch)
23-
assert dunder_main.main() == "InvalidConfiguration: foo"
21+
monkeypatch.setattr(sys, "argv", ["twine", "upload", "missing.whl"])
22+
message = "InvalidDistribution: Cannot find file (or expand pattern): 'missing.whl'"
23+
assert dunder_main.main() == colorama.Fore.RED + message + colorama.Style.RESET_ALL
24+
25+
26+
def test_no_color_exception(monkeypatch):
27+
monkeypatch.setattr(sys, "argv", ["twine", "--no-color", "upload", "missing.whl"])
28+
message = "InvalidDistribution: Cannot find file (or expand pattern): 'missing.whl'"
29+
assert dunder_main.main() == message

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ deps =
1111
portend
1212
pytest-services
1313
munch
14+
colorama
1415
passenv =
1516
PYTEST_ADDOPTS
1617
commands =

twine/__main__.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import sys
1616
from typing import Any
1717

18+
import colorama
1819
import requests
1920

2021
from twine import cli
@@ -25,7 +26,16 @@ def main() -> Any:
2526
try:
2627
return cli.dispatch(sys.argv[1:])
2728
except (exceptions.TwineException, requests.HTTPError) as exc:
28-
return "{}: {}".format(exc.__class__.__name__, exc.args[0])
29+
return _format_error(f"{exc.__class__.__name__}: {exc.args[0]}")
30+
31+
32+
def _format_error(message: str) -> str:
33+
pre_style, post_style = "", ""
34+
if not cli.args.no_color:
35+
colorama.init()
36+
pre_style, post_style = colorama.Fore.RED, colorama.Style.RESET_ALL
37+
38+
return f"{pre_style}{message}{post_style}"
2939

3040

3141
if __name__ == "__main__":

twine/cli.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import twine
2828
from twine import _installed
2929

30+
args = argparse.Namespace()
31+
3032

3133
def _registered_commands(
3234
group: str = "twine.registered_commands",
@@ -59,14 +61,21 @@ def dispatch(argv: List[str]) -> Any:
5961
action="version",
6062
version="%(prog)s version {} ({})".format(twine.__version__, dep_versions()),
6163
)
64+
parser.add_argument(
65+
"--no-color",
66+
default=False,
67+
required=False,
68+
action="store_true",
69+
help="disable colored output",
70+
)
6271
parser.add_argument(
6372
"command", choices=registered_commands.keys(),
6473
)
6574
parser.add_argument(
6675
"args", help=argparse.SUPPRESS, nargs=argparse.REMAINDER,
6776
)
6877

69-
args = parser.parse_args(argv)
78+
parser.parse_args(argv, namespace=args)
7079

7180
main = registered_commands[args.command].load()
7281

0 commit comments

Comments
 (0)