From f57ac0291977bf87147c924d34d91a24acbea273 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 10:42:56 +0200 Subject: [PATCH 01/22] ci(typings): Add mypy --- .github/workflows/tests.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 12766fb7066..4892b5b88d0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -90,9 +90,13 @@ jobs: - name: Install python dependencies run: | poetry install -E "test coverage lint" + - name: Lint with flake8 - run: | - poetry run flake8 + run: poetry run flake8 + + - name: Lint with mypy + run: poetry run mypy . + - name: Test with pytest continue-on-error: ${{ matrix.tmux-version == 'master' }} run: | From 954ef414fd59c8ae4bfc84454d4ba1c21422bade Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 08:06:01 +0200 Subject: [PATCH 02/22] chore(util): Use console_to_str from libtmux --- tmuxp/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmuxp/util.py b/tmuxp/util.py index 118345a6110..61c20669a76 100644 --- a/tmuxp/util.py +++ b/tmuxp/util.py @@ -10,10 +10,10 @@ import subprocess import sys +from libtmux._compat import console_to_str from libtmux.exc import LibTmuxException from . import exc -from ._compat import console_to_str logger = logging.getLogger(__name__) From 59ba7796cd2ca9ec0900d822daeb662cc653cfcb Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 08:06:44 +0200 Subject: [PATCH 03/22] refactor!(_compat): Remove console_to_str Use libtmux._compat.console_to_str instead --- tmuxp/_compat.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tmuxp/_compat.py b/tmuxp/_compat.py index a69ba4c793f..1b0009e3a1f 100644 --- a/tmuxp/_compat.py +++ b/tmuxp/_compat.py @@ -18,11 +18,3 @@ console_encoding = sys.__stdout__.encoding implements_to_string = _identity - - -def console_to_str(s): - """From pypa/pip project, pip.backwardwardcompat. License MIT.""" - try: - return s.decode(console_encoding) - except UnicodeDecodeError: - return s.decode("utf_8") From b08e8b597654cc69c62602014d4bfa469dc3848e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 24 Jul 2022 18:53:35 -0500 Subject: [PATCH 04/22] chore(mypy): Override untyped libs --- pyproject.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a2f3d4c16c3..16f0d789e7a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,3 +112,16 @@ lint = ["flake8", "mypy"] [build-system] requires = ["poetry_core>=1.0.0"] build-backend = "poetry.core.masonry.api" + +[[tool.mypy.overrides]] +module = [ + "kaptan", + "docutils", + "aafigure", + "libtmux.*", + "IPython.*", + "ptpython.*", + "prompt_toolkit.*", + "bpython" +] +ignore_missing_imports = true From 2a8f972db17db3a5b020d57aa1ab3e077832214b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 24 Jul 2022 18:57:50 -0500 Subject: [PATCH 05/22] build(deps): Add types-docutils --- poetry.lock | 14 +++++++++++++- pyproject.toml | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 2c6d84551c4..419f052a143 100644 --- a/poetry.lock +++ b/poetry.lock @@ -883,6 +883,14 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "types-docutils" +version = "0.19.0" +description = "Typing stubs for docutils" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "typing-extensions" version = "4.3.0" @@ -937,7 +945,7 @@ test = [] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "fd413df6e46ac6f537f0ae451546c067e85f232c665b985929e84068897f6dd9" +content-hash = "d31fee381728eddff6ad1974b82fc3a41b9202db3eb2b23689067e1b0ff9fe90" [metadata.files] aafigure = [ @@ -1301,6 +1309,10 @@ tornado = [ {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"}, ] typed-ast = [] +types-docutils = [ + {file = "types-docutils-0.19.0.tar.gz", hash = "sha256:94936b1961aacda61ec6bb0acf1169cd7830b5230b645855c1d4789baf19685e"}, + {file = "types_docutils-0.19.0-py3-none-any.whl", hash = "sha256:198ed1c0ef6c1a79411da9e1745514eda433d37770e24f26b0e13a302904cc97"}, +] typing-extensions = [] urllib3 = [] watchdog = [] diff --git a/pyproject.toml b/pyproject.toml index 16f0d789e7a..00111dadf1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,7 @@ isort = "*" ### Lint ### flake8 = "*" mypy = "*" +types-docutils = "^0.19.0" [tool.poetry.extras] docs = [ @@ -107,7 +108,7 @@ docs = [ test = ["pytest", "pytest-rerunfailures", "pytest-mock", "pytest-watcher"] coverage = ["codecov", "coverage", "pytest-cov"] format = ["black", "isort"] -lint = ["flake8", "mypy"] +lint = ["flake8", "mypy", "types-docutils"] [build-system] requires = ["poetry_core>=1.0.0"] From 844f8f753c33d4da144f0f536496aef3f1b66daf Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 24 Jul 2022 18:58:08 -0500 Subject: [PATCH 06/22] build(mypy): Allow docutils again --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 00111dadf1b..3fe69981c47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -117,7 +117,6 @@ build-backend = "poetry.core.masonry.api" [[tool.mypy.overrides]] module = [ "kaptan", - "docutils", "aafigure", "libtmux.*", "IPython.*", From 5031c62047f0e874a7446533ff592f034dfdb8e1 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 24 Jul 2022 18:59:25 -0500 Subject: [PATCH 07/22] build(deps): Add colorama typings --- poetry.lock | 14 +++++++++++++- pyproject.toml | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 419f052a143..1dd6f65dfb6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -883,6 +883,14 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "types-colorama" +version = "0.4.15" +description = "Typing stubs for colorama" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "types-docutils" version = "0.19.0" @@ -945,7 +953,7 @@ test = [] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "d31fee381728eddff6ad1974b82fc3a41b9202db3eb2b23689067e1b0ff9fe90" +content-hash = "8247361fb8db31e108152b0c3fda3aed46f8dca5c8dd5a6dda1b87cb9ee5aef2" [metadata.files] aafigure = [ @@ -1309,6 +1317,10 @@ tornado = [ {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"}, ] typed-ast = [] +types-colorama = [ + {file = "types-colorama-0.4.15.tar.gz", hash = "sha256:fd128b1e32f3fecec5f09df4366d21498ee86ea31fcf8b4e8f1ade6d0bbf9832"}, + {file = "types_colorama-0.4.15-py3-none-any.whl", hash = "sha256:9cdc88dcde9e8ebafb2fdfaf5cee260452f93e5c57eb5d8b2a7f65b836d4e5d0"}, +] types-docutils = [ {file = "types-docutils-0.19.0.tar.gz", hash = "sha256:94936b1961aacda61ec6bb0acf1169cd7830b5230b645855c1d4789baf19685e"}, {file = "types_docutils-0.19.0-py3-none-any.whl", hash = "sha256:198ed1c0ef6c1a79411da9e1745514eda433d37770e24f26b0e13a302904cc97"}, diff --git a/pyproject.toml b/pyproject.toml index 3fe69981c47..16107ebfc21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,7 @@ isort = "*" ### Lint ### flake8 = "*" mypy = "*" +types-colorama = "^0.4.15" types-docutils = "^0.19.0" [tool.poetry.extras] @@ -108,7 +109,7 @@ docs = [ test = ["pytest", "pytest-rerunfailures", "pytest-mock", "pytest-watcher"] coverage = ["codecov", "coverage", "pytest-cov"] format = ["black", "isort"] -lint = ["flake8", "mypy", "types-docutils"] +lint = ["flake8", "mypy", "types-colorama", "types-docutils"] [build-system] requires = ["poetry_core>=1.0.0"] From 06da4573b87da89f07def3ae0af8e2e775dc105a Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 24 Jul 2022 19:00:31 -0500 Subject: [PATCH 08/22] chore(test_cli): Add typings for mypy --- tests/test_cli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 2be26d0e238..426e5abd1b1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,6 +2,7 @@ import json import os import pathlib +import typing as t from unittest.mock import MagicMock import pytest @@ -416,7 +417,7 @@ def test_regression_00132_session_name_with_dots( ): yaml_config = FIXTURE_PATH / "workspacebuilder" / "regression_00132_dots.yaml" cli_args = [str(yaml_config)] - inputs = [] + inputs: t.List[str] = [] runner = CliRunner() result = runner.invoke( cli.command_load, cli_args, input="".join(inputs), standalone_mode=False From af558036ad41eecd29c94c59916f72da4f651246 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 08:09:19 +0200 Subject: [PATCH 09/22] chore(conftest): Basic Typings --- tmuxp/conftest.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tmuxp/conftest.py b/tmuxp/conftest.py index 2a7b6aaf492..b08c6bec33a 100644 --- a/tmuxp/conftest.py +++ b/tmuxp/conftest.py @@ -66,14 +66,15 @@ def monkeypatch_plugin_test_packages(monkeypatch): @pytest.fixture(scope="function") -def socket_name(request): +def socket_name(request) -> str: return "tmuxp_test%s" % next(namer) @pytest.fixture(scope="function") -def server(request: SubRequest, monkeypatch: pytest.MonkeyPatch) -> Server: - tmux = Server() - tmux.socket_name = socket_name +def server( + request: SubRequest, monkeypatch: pytest.MonkeyPatch, socket_name: str +) -> Server: + tmux = Server(socket_name=socket_name) def fin() -> None: tmux.kill_server() @@ -140,7 +141,7 @@ def add_doctest_fixtures( doctest_namespace: t.Dict[str, t.Any], ) -> None: if isinstance(request._pyfuncitem, DoctestItem) and which("tmux"): - doctest_namespace["server"]: "Server" = request.getfixturevalue("server") + doctest_namespace["server"] = request.getfixturevalue("server") session: "Session" = request.getfixturevalue("session") doctest_namespace["session"] = session doctest_namespace["window"] = session.attached_window From e8bf689b59e99ea6db409303bf2fc35f02e56235 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 08:32:17 +0200 Subject: [PATCH 10/22] refactor(test fixtures): Use basic dataclass --- tests/fixtures/structures.py | 13 +++++++++++++ tests/test_config.py | 32 ++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 tests/fixtures/structures.py diff --git a/tests/fixtures/structures.py b/tests/fixtures/structures.py new file mode 100644 index 00000000000..5af93b21464 --- /dev/null +++ b/tests/fixtures/structures.py @@ -0,0 +1,13 @@ +import dataclasses +import typing as t + + +@dataclasses.dataclass +class TestConfigData: + expand1: t.Any + expand2: t.Any + expand_blank: t.Any + sampleconfig: t.Any + shell_command_before: t.Any + shell_command_before_session: t.Any + trickle: t.Any diff --git a/tests/test_config.py b/tests/test_config.py index 5695ae6248d..f956abf4141 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,6 +1,7 @@ """Test for tmuxp configuration import, inlining, expanding and export.""" import os import pathlib +import types import typing from typing import Union @@ -13,7 +14,7 @@ from .constants import EXAMPLE_PATH if typing.TYPE_CHECKING: - from .fixtures import config as ConfigFixture + from .fixtures.structures import TestConfigData @pytest.fixture @@ -23,9 +24,16 @@ def config_fixture(): pytest setup (conftest.py) patches os.environ["HOME"], delay execution of os.path.expanduser until here. """ - from .fixtures import config as config_fixture - - return config_fixture + from .fixtures import config as test_config_data + from .fixtures.structures import TestConfigData + + return TestConfigData( + **{ + k: v + for k, v in test_config_data.__dict__.items() + if isinstance(v, types.ModuleType) + } + ) def load_yaml(path: Union[str, pathlib.Path]) -> str: @@ -44,7 +52,7 @@ def load_config(path: Union[str, pathlib.Path]) -> str: ) -def test_export_json(tmp_path: pathlib.Path, config_fixture: "ConfigFixture"): +def test_export_json(tmp_path: pathlib.Path, config_fixture: "TestConfigData"): json_config_file = tmp_path / "config.json" configparser = kaptan.Kaptan() @@ -59,7 +67,7 @@ def test_export_json(tmp_path: pathlib.Path, config_fixture: "ConfigFixture"): assert config_fixture.sampleconfig.sampleconfigdict == new_config_data -def test_export_yaml(tmp_path: pathlib.Path, config_fixture: "ConfigFixture"): +def test_export_yaml(tmp_path: pathlib.Path, config_fixture: "TestConfigData"): yaml_config_file = tmp_path / "config.yaml" configparser = kaptan.Kaptan() @@ -103,13 +111,13 @@ def test_scan_config(tmp_path: pathlib.Path): assert len(configs) == files -def test_config_expand1(config_fixture: "ConfigFixture"): +def test_config_expand1(config_fixture: "TestConfigData"): """Expand shell commands from string to list.""" test_config = config.expand(config_fixture.expand1.before_config) assert test_config == config_fixture.expand1.after_config() -def test_config_expand2(config_fixture: "ConfigFixture"): +def test_config_expand2(config_fixture: "TestConfigData"): """Expand shell commands from string to list.""" unexpanded_dict = load_yaml(config_fixture.expand2.unexpanded_yaml()) expanded_dict = load_yaml(config_fixture.expand2.expanded_yaml()) @@ -228,7 +236,7 @@ def test_inheritance_config(): assert config == inheritance_config_after -def test_shell_command_before(config_fixture: "ConfigFixture"): +def test_shell_command_before(config_fixture: "TestConfigData"): """Config inheritance for the nested 'start_command'.""" test_config = config_fixture.shell_command_before.config_unexpanded test_config = config.expand(test_config) @@ -239,7 +247,7 @@ def test_shell_command_before(config_fixture: "ConfigFixture"): assert test_config == config_fixture.shell_command_before.config_after() -def test_in_session_scope(config_fixture: "ConfigFixture"): +def test_in_session_scope(config_fixture: "TestConfigData"): sconfig = load_yaml(config_fixture.shell_command_before_session.before) config.validate_schema(sconfig) @@ -250,7 +258,7 @@ def test_in_session_scope(config_fixture: "ConfigFixture"): ) -def test_trickle_relative_start_directory(config_fixture: "ConfigFixture"): +def test_trickle_relative_start_directory(config_fixture: "TestConfigData"): test_config = config.trickle(config_fixture.trickle.before) assert test_config == config_fixture.trickle.expected @@ -273,7 +281,7 @@ def test_trickle_window_with_no_pane_config(): } -def test_expands_blank_panes(config_fixture: "ConfigFixture"): +def test_expands_blank_panes(config_fixture: "TestConfigData"): """Expand blank config into full form. Handle ``NoneType`` and 'blank':: From c20dfc083d191c43a0e9583045fb873d715e384c Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 08:34:46 +0200 Subject: [PATCH 11/22] refactor(aafig): Use hashlib library (sha1 deprecated since 2.5) See also: https://docs.python.org/2.7/library/sha.html --- docs/_ext/aafig.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/_ext/aafig.py b/docs/_ext/aafig.py index 8d4ec5d99f0..77a471885bf 100644 --- a/docs/_ext/aafig.py +++ b/docs/_ext/aafig.py @@ -11,6 +11,7 @@ :license: BOLA, see LICENSE for details """ import posixpath +from hashlib import sha1 as sha from os import path from docutils import nodes @@ -18,12 +19,6 @@ from sphinx.errors import SphinxError from sphinx.util import ensuredir, logging, relative_uri -try: - from hashlib import sha1 as sha -except ImportError: - from sha import sha - - try: import aafigure except ImportError: From 73e3b09c9208a8d2a8ecc9de9020ef711b4a28ef Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 08:37:53 +0200 Subject: [PATCH 12/22] refactor(aafig): Fix import location (pyright) --- docs/_ext/aafig.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/_ext/aafig.py b/docs/_ext/aafig.py index 77a471885bf..0a5c506221a 100644 --- a/docs/_ext/aafig.py +++ b/docs/_ext/aafig.py @@ -17,7 +17,8 @@ from docutils import nodes from docutils.parsers.rst.directives import flag, images, nonnegative_int from sphinx.errors import SphinxError -from sphinx.util import ensuredir, logging, relative_uri +from sphinx.util import logging +from sphinx.util.osutil import ensuredir, relative_uri try: import aafigure From d3a9a9244d3632953f93ffc19c106980fa9de83c Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 08:38:36 +0200 Subject: [PATCH 13/22] chore(aafig): Import from logging from standard library --- docs/_ext/aafig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_ext/aafig.py b/docs/_ext/aafig.py index 0a5c506221a..91a37a66b62 100644 --- a/docs/_ext/aafig.py +++ b/docs/_ext/aafig.py @@ -10,6 +10,7 @@ :author: Leandro Lucarella :license: BOLA, see LICENSE for details """ +import logging import posixpath from hashlib import sha1 as sha from os import path @@ -17,7 +18,6 @@ from docutils import nodes from docutils.parsers.rst.directives import flag, images, nonnegative_int from sphinx.errors import SphinxError -from sphinx.util import logging from sphinx.util.osutil import ensuredir, relative_uri try: From bed670d000eb995a65c228578f48f0fd462cf4e7 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 08:43:30 +0200 Subject: [PATCH 14/22] docs(conf): Basic typings --- docs/conf.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 53d19ed6251..9b686506a83 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,7 @@ # flake8: NOQA E5 import inspect import sys +import typing as t from os.path import dirname, relpath from pathlib import Path @@ -14,7 +15,7 @@ sys.path.insert(0, str(cwd / "_ext")) # package data -about = {} +about: t.Dict[str, str] = {} with open(project_root / "tmuxp" / "__about__.py") as fp: exec(fp.read(), about) @@ -61,8 +62,8 @@ html_static_path = ["_static"] html_favicon = "_static/favicon.ico" html_theme = "furo" -html_theme_path = [] -html_theme_options = { +html_theme_path: t.List[str] = [] +html_theme_options: t.Dict[str, t.Union[str, t.List[t.Dict[str, str]]]] = { "light_logo": "img/tmuxp.svg", "dark_logo": "img/tmuxp.svg", "footer_icons": [ From e3e6472a2fe2785867a05c65e3130754e017f0d4 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 09:04:12 +0200 Subject: [PATCH 15/22] chore(command_freeze): Fix odd type / cycling issue caused by import See also: tmuxp/cli/__init__.py:81: error: Cannot determine type of "command_freeze" --- tmuxp/cli/freeze.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmuxp/cli/freeze.py b/tmuxp/cli/freeze.py index 2b05fc6f57f..80da186d26f 100644 --- a/tmuxp/cli/freeze.py +++ b/tmuxp/cli/freeze.py @@ -5,10 +5,10 @@ import kaptan from libtmux.server import Server +from tmuxp.exc import TmuxpException from .. import config, util from ..workspacebuilder import freeze -from . import exc from .utils import _validate_choices, get_abs_path, get_config_dir @@ -65,8 +65,8 @@ def command_freeze( session = util.get_session(t) if not session: - raise exc.TmuxpException("Session not found.") - except exc.TmuxpException as e: + raise TmuxpException("Session not found.") + except TmuxpException as e: print(e) return From 921e71559ef9600b91806c025e3889cae2c7c893 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 09:56:29 +0200 Subject: [PATCH 16/22] refactor(shell): Import fix --- tmuxp/cli/shell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmuxp/cli/shell.py b/tmuxp/cli/shell.py index eb2821e9b74..6d52a734ed0 100644 --- a/tmuxp/cli/shell.py +++ b/tmuxp/cli/shell.py @@ -84,7 +84,7 @@ def command_shell( exec(command) else: if shell == "pdb" or (os.getenv("PYTHONBREAKPOINT") and PY3 and PYMINOR >= 7): - from ._compat import breakpoint as tmuxp_breakpoint + from tmuxp._compat import breakpoint as tmuxp_breakpoint tmuxp_breakpoint() return From 98b029d998f377ad573b2e38f0e96ec8d3cd974c Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 10:03:59 +0200 Subject: [PATCH 17/22] chore(breakpoint): Ignore workaround --- tmuxp/_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmuxp/_compat.py b/tmuxp/_compat.py index 1b0009e3a1f..805d6c1cc5c 100644 --- a/tmuxp/_compat.py +++ b/tmuxp/_compat.py @@ -12,7 +12,7 @@ else: import pdb - breakpoint = pdb.set_trace + breakpoint = pdb.set_trace # type: ignore console_encoding = sys.__stdout__.encoding From 8ef49a791670d1070074b7ef6ca0d45f0298d132 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 10:41:01 +0200 Subject: [PATCH 18/22] refactor!(logging): mypy updates --- tmuxp/log.py | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/tmuxp/log.py b/tmuxp/log.py index e79edfb2488..1f29da54a15 100644 --- a/tmuxp/log.py +++ b/tmuxp/log.py @@ -7,6 +7,7 @@ """ import logging import time +import typing as t from colorama import Fore, Style @@ -56,7 +57,22 @@ def set_style( return prefix + message + suffix -def default_log_template(self, record, stylized=False): +class LogTemplateFn(t.Protocol): + def template( + self, + record: logging.LogRecord, + stylized: t.Optional[bool], + **kwargs: t.Any, + ) -> str: + ... + + +def default_log_template( + self: t.Type[logging.Formatter], + record: logging.LogRecord, + stylized: t.Optional[bool] = False, + **kwargs: t.Any, +) -> str: """ Return the prefix for the log message. Template for Formatter. @@ -76,7 +92,7 @@ def default_log_template(self, record, stylized=False): levelname = set_style( "(%(levelname)s)", stylized, - style_before=(LEVEL_COLORS.get(record.levelname) + Style.BRIGHT), + style_before=(LEVEL_COLORS.get(record.levelname, "") + Style.BRIGHT), style_after=Style.RESET_ALL, suffix=" ", ) @@ -103,7 +119,7 @@ def default_log_template(self, record, stylized=False): return levelname + asctime + name -class LogFormatter(logging.Formatter): +class LogFormatter(logging.Formatter, LogTemplateFn): template = default_log_template def __init__(self, color=True, *args, **kwargs): @@ -125,7 +141,13 @@ def format(self, record): return formatted.replace("\n", "\n" + parts[0] + " ") -def debug_log_template(self, record): +def debug_log_template( + self: t.Type[logging.Formatter], + record: logging.LogRecord, + stylized: t.Optional[bool] = False, + **kwargs: t.Any, +) -> str: + """ Return the prefix for the log message. Template for Formatter. @@ -143,7 +165,7 @@ def debug_log_template(self, record): reset = Style.RESET_ALL levelname = ( - LEVEL_COLORS.get(record.levelname) + LEVEL_COLORS.get(record.levelname, "") + Style.BRIGHT + "(%(levelname)1.1s)" + Style.RESET_ALL From ca09e80e4adc0443f33d6d76341f61b776c960e1 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 10:55:48 +0200 Subject: [PATCH 19/22] refactor(logging): Remove protocol for now, to avoid typing-extensions Strict mypy may force us to need this --- tmuxp/log.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tmuxp/log.py b/tmuxp/log.py index 1f29da54a15..4f54a5fa588 100644 --- a/tmuxp/log.py +++ b/tmuxp/log.py @@ -57,16 +57,6 @@ def set_style( return prefix + message + suffix -class LogTemplateFn(t.Protocol): - def template( - self, - record: logging.LogRecord, - stylized: t.Optional[bool], - **kwargs: t.Any, - ) -> str: - ... - - def default_log_template( self: t.Type[logging.Formatter], record: logging.LogRecord, @@ -119,7 +109,7 @@ def default_log_template( return levelname + asctime + name -class LogFormatter(logging.Formatter, LogTemplateFn): +class LogFormatter(logging.Formatter): template = default_log_template def __init__(self, color=True, *args, **kwargs): From 54007833704b82a989df4049befb0cc8c16c5e72 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 11:03:03 +0200 Subject: [PATCH 20/22] chore(setup.cfg): Move pytest config down for doc example --- setup.cfg | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.cfg b/setup.cfg index 006953379fb..8e5eeed7830 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,12 +5,6 @@ max-line-length = 88 # Stuff we ignore thanks to black: https://github.com/ambv/black/issues/429 extend-ignore = E203,W503 -[tool:pytest] -filterwarnings = - ignore:distutils Version classes are deprecated. Use packaging.version instead. -addopts = --reruns=0 --tb=short --no-header --showlocals --doctest-modules -doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE - [isort] profile = black combine_as_imports= true @@ -21,3 +15,9 @@ known_pytest = pytest,py known_first_party = libtmux,tmuxp sections = FUTURE,STDLIB,PYTEST,THIRDPARTY,FIRSTPARTY,LOCALFOLDER line_length = 88 + +[tool:pytest] +filterwarnings = + ignore:distutils Version classes are deprecated. Use packaging.version instead. +addopts = --reruns=0 --tb=short --no-header --showlocals --doctest-modules +doctest_optionflags = ELLIPSIS NORMALIZE_WHITESPACE From 04317dbd3e252287974914617df2f47932416a9b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 11:03:46 +0200 Subject: [PATCH 21/22] docs(developing): Note flake8 and mypy --- docs/developing.md | 104 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/docs/developing.md b/docs/developing.md index 21b20be17d1..f12aacbd24b 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -334,6 +334,106 @@ this will load the `.tmuxp.yaml` in the root of the project. ``` +## Formatting + +The project uses [black] and [isort] (one after the other). Configurations are in `pyproject.toml` +and `setup.cfg`: + +- `make black isort`: Run `black` first, then `isort` to handle import nuances + +## Linting + +[flake8] and [mypy] run via CI in our GitHub Actions. See the configuration in `pyproject.toml` and +`setup.cfg`. + +### flake8 + +[flake8] provides fast, reliable, barebones styling and linting. + +````{tab} Command + +poetry: + +```console +$ poetry run flake8 +``` + +If you setup manually: + +```console +$ flake8 +``` + +```` + +````{tab} make + +```console +$ make flake8 +``` + +```` + +````{tab} Watch + +```console +$ make watch_flake8 +``` + +requires [`entr(1)`]. + +```` + +````{tab} Configuration + +See `[flake8]` in setup.cfg. + +```{literalinclude} ../setup.cfg +:language: ini +:start-at: "[flake8]" +:end-before: "[isort]" + +``` + +```` + +### mypy + +[mypy] is used for static type checking. + +````{tab} Command + +poetry: + +```console +$ poetry run mypy . +``` + +If you setup manually: + +```console +$ mypy . +``` + +```` + +````{tab} make + +```console +$ make mypy +``` + +```` + +````{tab} Watch + +```console +$ make watch_mypy +``` + +requires [`entr(1)`]. +```` + (gh-actions)= ## Continuous integration @@ -350,6 +450,10 @@ the [gh build site]. [py.test usage argument]: https://pytest.org/latest/usage.html [entr]: http://entrproject.org/ [`entr(1)`]: http://entrproject.org/ +[black]: https://github.com/psf/black +[isort]: https://pypi.org/project/isort/ +[flake8]: https://flake8.pycqa.org/ +[mypy]: http://mypy-lang.org/ [github actions]: https://github.com/features/actions [gh build site]: https://github.com/tmux-python/tmuxp/actions?query=workflow%3Atests [.github/workflows/tests.yml]: https://github.com/tmux-python/tmuxp/blob/master/.github/workflows/tests.yml From f130e9b95901967d41f1e8b4910b4c712ade1a57 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 14 Aug 2022 11:05:06 +0200 Subject: [PATCH 22/22] docs(CHANGES): Add basic type annotations --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index c826574e06a..2513ed89c50 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,7 @@ $ pipx install --suffix=@next 'tmuxp' --pip-args '\--pre' --force - libtmux updated from v0.12 to v0.14 {issue}`790` - Add [doctest](https://docs.python.org/3/library/doctest.html) w/ [pytest + doctest](https://docs.pytest.org/en/7.1.x/how-to/doctest.html), ({issue}`791`). +- Added basic [mypy](http://mypy-lang.org/) type annotations via {issue}`786` ## tmuxp 1.12.1 (2022-08-04)