Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type annotations to the project and run mypy on CI #11

Merged
merged 2 commits into from Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Expand Up @@ -58,5 +58,12 @@ repos:
- id: prettier
args: [--prose-wrap=always, --print-width=88]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.961
hooks:
- id: mypy
args: [--strict, --pretty, --show-error-codes]
additional_dependencies: [pytest, types-setuptools]

ci:
autoupdate_schedule: quarterly
1 change: 1 addition & 0 deletions setup.cfg
Expand Up @@ -40,6 +40,7 @@ project_urls =
[options]
packages = find:
python_requires = >=3.7
include_package_data = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this line, the py.typed file will not be installed to the Python site-packages directory.

Observe:

$ cd termcolor
$ pip install .
$ ls ~/.virtualenvs/termcolor/lib/python3.9/site-packages/termcolor/
... should include py.typed

Adjust the ls to be your virtualenv.

The py.typed file is necessary for PEP-561 compliance. More detail at:
https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-library-stubs-or-py-typed-marker

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff, thanks!

package_dir = =src
setup_requires =
setuptools-scm
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Expand Up @@ -21,6 +21,8 @@
#
# Author: Konstantin Lepa <konstantin.lepa@gmail.com>

from __future__ import annotations

from setuptools import setup


Expand Down
2 changes: 2 additions & 0 deletions src/termcolor/__init__.py
@@ -1,3 +1,5 @@
from __future__ import annotations

from termcolor.termcolor import (
ATTRIBUTES,
COLORS,
Expand Down
Empty file added src/termcolor/py.typed
Empty file.
18 changes: 16 additions & 2 deletions src/termcolor/termcolor.py
Expand Up @@ -22,7 +22,10 @@

"""ANSI color formatting for output in terminal."""

from __future__ import annotations

import os
from typing import Any, Iterable

__ALL__ = ["colored", "cprint"]

Expand Down Expand Up @@ -89,7 +92,12 @@
RESET = "\033[0m"


def colored(text, color=None, on_color=None, attrs=None):
def colored(
text: str,
color: str | None = None,
on_color: str | None = None,
attrs: Iterable[str] | None = None,
) -> str:
"""Colorize text.

Available text colors:
Expand Down Expand Up @@ -122,7 +130,13 @@ def colored(text, color=None, on_color=None, attrs=None):
return text + RESET


def cprint(text, color=None, on_color=None, attrs=None, **kwargs):
def cprint(
text: str,
color: str | None = None,
on_color: str | None = None,
attrs: Iterable[str] | None = None,
**kwargs: Any,
) -> None:
"""Print colorize text.

It accepts arguments of print function.
Expand Down
37 changes: 25 additions & 12 deletions tests/test_termcolor.py
@@ -1,27 +1,30 @@
from __future__ import annotations

import os
from typing import Any

import pytest

from termcolor import ATTRIBUTES, COLORS, HIGHLIGHTS, colored, cprint

ALL_COLORS = list(COLORS) + [None]
ALL_HIGHLIGHTS = list(HIGHLIGHTS) + [None]
ALL_ATTRIBUTES = list(ATTRIBUTES) + [None]
ALL_COLORS = [*COLORS, None]
ALL_HIGHLIGHTS = [*HIGHLIGHTS, None]
ALL_ATTRIBUTES = [*ATTRIBUTES, None]


def setup_module():
def setup_module() -> None:
# By default, make sure no env vars already set for tests
try:
del os.environ["ANSI_COLORS_DISABLED"]
except KeyError: # pragma: no cover
pass


def test_basic():
def test_basic() -> None:
assert colored("text") == "text\x1b[0m"


def test_sanity():
def test_sanity() -> None:
for color in ALL_COLORS:
for highlight in ALL_HIGHLIGHTS:
for attribute in ALL_ATTRIBUTES:
Expand All @@ -31,8 +34,14 @@ def test_sanity():


def assert_cprint(
capsys, expected, text, color=None, on_color=None, attrs=None, **kwargs
):
capsys: pytest.CaptureFixture[str],
expected: str,
text: str,
color: str | None = None,
on_color: str | None = None,
attrs: list[str] | None = None,
**kwargs: Any,
) -> None:
cprint(text, color, on_color, attrs, **kwargs)
captured = capsys.readouterr()
print(captured.out)
Expand All @@ -52,7 +61,7 @@ def assert_cprint(
("white", "\x1b[37mtext\x1b[0m"),
],
)
def test_color(capsys, color, expected):
def test_color(capsys: pytest.CaptureFixture[str], color: str, expected: str) -> None:
assert colored("text", color=color) == expected
assert_cprint(capsys, expected, "text", color=color)

Expand All @@ -70,7 +79,9 @@ def test_color(capsys, color, expected):
("on_white", "\x1b[47mtext\x1b[0m"),
],
)
def test_on_color(capsys, on_color, expected):
def test_on_color(
capsys: pytest.CaptureFixture[str], on_color: str, expected: str
) -> None:
assert colored("text", on_color=on_color) == expected
assert_cprint(capsys, expected, "text", on_color=on_color)

Expand All @@ -86,7 +97,7 @@ def test_on_color(capsys, on_color, expected):
("concealed", "\x1b[8mtext\x1b[0m"),
],
)
def test_attrs(capsys, attr, expected):
def test_attrs(capsys: pytest.CaptureFixture[str], attr: str, expected: str) -> None:
assert colored("text", attrs=[attr]) == expected
assert_cprint(capsys, expected, "text", attrs=[attr])

Expand All @@ -108,7 +119,9 @@ def test_attrs(capsys, attr, expected):
"",
],
)
def test_env_var(monkeypatch, test_env_var, test_value):
def test_env_var(
monkeypatch: pytest.MonkeyPatch, test_env_var: str, test_value: str
) -> None:
"""Assert nothing applied when this env var set, regardless of value."""
monkeypatch.setenv(test_env_var, test_value)
assert colored("text", color="red") == "text"