Skip to content

Ruff rules: Stricter code quality rules #879

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

Merged
merged 45 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e5bf115
ci(ruff): Strengthen code quality linting
tony Jul 1, 2023
62eb72c
fix(pytest[zshrc]): Fix skipif condition
tony Jul 8, 2023
e10145e
fix(get_current_pane): Fix try/catch broke by RUF015
tony Sep 2, 2023
53f03e8
chore(ruff): Run automated fixes (97 errors)
tony Aug 26, 2023
2d68c37
refactor(test_cli, get_{teamocil,tmuxinator}_dir): To pathlib
tony Sep 3, 2023
e2b4b36
refactor(workspace.validation): Use dedicated exceptions
tony Sep 3, 2023
f330897
refactor(expandshell): Ignore PTH111 and orient to all strings
tony Sep 3, 2023
8ff85c2
chore(test_cli): Improve resilient of test in small terminals
tony Sep 3, 2023
b3fe526
chore(mypy): Fix before automated tweaks
tony Sep 3, 2023
6538efd
chore(ruff): Manual fixes for tests/workspace/test_finder.py
tony Sep 2, 2023
7398997
chore(ruff): Manual fix for comprehension in tests/workspace/test_con…
tony Sep 2, 2023
58d19bd
chore(ruff): Manual fixes test_builder.py
tony Sep 3, 2023
3d05c00
chore(ruff): Manual fixes in shell_command_before
tony Sep 3, 2023
faaff3c
chore(ruff): Manual fixes for expand1, expand2 examples
tony Sep 3, 2023
461deb1
chore(ruff): Manual fixes fixtures/utils.py
tony Sep 3, 2023
61a8cd5
chore(ruff): Manual fix for test_ls
tony Sep 3, 2023
c5ac660
refactor(ruff): Manual fixes for workspace/loader.py
tony Sep 3, 2023
e855780
chore(ruff): Manual typings for workspace/freezer
tony Sep 3, 2023
d4a5aa0
ci(ruff): Ignore PTH in workspace/finders.py
tony Sep 4, 2023
a851230
chore(ruff): Manual fixes for workspace/finders.py
tony Sep 4, 2023
a6e925a
refactor(builder): Move error message to EmptyWorkspaceException
tony Sep 4, 2023
3ad5cf1
feat: Add SessionMissingWorkspaceException
tony Sep 4, 2023
e570ca6
chore(WorkspaceBuilder): Move to dedicated exception for missing session
tony Sep 4, 2023
64004d9
refactor(exc): Add ActiveSessionMissingWorkspaceException
tony Sep 4, 2023
5f23e3b
chore(WorkspaceBuilder): Add ActiveSessionMissingWorkspaceException
tony Sep 4, 2023
f66d652
chore(ruff): Manual fixes for workspace/builder.py
tony Sep 4, 2023
9cda65a
chore(ruff): Manual fixes for tmuxp/util.py
tony Sep 4, 2023
1232510
feat(exc): {Pane,Window,Session}NotFound
tony Sep 4, 2023
ce9d20b
refactor(util): Consoidate get_{pane,window,session}
tony Sep 4, 2023
27b3518
refactor(util): Use new NotFound exceptions, organize logic
tony Sep 4, 2023
b6621bd
chore(ruff): Manual fixes for shell
tony Sep 4, 2023
d7f6a75
chore(ruff): Manual fixes for plugin
tony Sep 4, 2023
2567747
chore(ruff): Manual fixes for config_reader
tony Sep 4, 2023
40d87b0
feat(cli[utils]): Add UnknownStyleColor
tony Sep 4, 2023
e0dab28
feat(cli[utils]): Extract CLIColour to type
tony Sep 4, 2023
b70188b
ruff(chore): Manual fixes for cli/utils.py via new exceptions
tony Sep 4, 2023
37bf0b1
chore(ruff): Fix typings
tony Sep 4, 2023
3417492
ci(ruff): Ignore cli/*.py, aafig.py
tony Sep 4, 2023
abc4344
chore(ruff): Manual fix for conftest.py
tony Sep 4, 2023
58b6b47
chore(ruff): Manual fixes for cli/load.py
tony Sep 4, 2023
4b1425a
chore(ruff): Manual fixes for cli/freeze.py
tony Sep 4, 2023
1927410
chore(ruff): Manual fixes for cli/freeze.py
tony Sep 4, 2023
01ec331
chore(ruff): Manual fixes for cli/convert.py
tony Sep 4, 2023
33669fe
chore(ruff): Manual fixes aafig.py
tony Sep 4, 2023
08a9c03
docs(CHANGES): Note ruff stringency changes
tony Sep 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ $ pipx install --suffix=@next 'tmuxp' --pip-args '\--pre' --force

<!-- Maintainers, insert changes / features for the next release here -->

### Development

- Code quality improved via [ruff] rules (#879)

This includes fixes made by hand alongside ruff's automated fixes. The more
stringent rules include import sorting, and still runs almost instantly
against the whole codebase.

## tmuxp 1.29.1 (2023-09-02)

### Development
Expand Down
7 changes: 3 additions & 4 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
import typing as t

import pytest

from _pytest.doctest import DoctestItem

from libtmux.test import namer

from tests.fixtures import utils as test_utils
from tmuxp.workspace.finders import get_workspace_dir

Expand All @@ -24,7 +23,7 @@
USING_ZSH = "zsh" in os.getenv("SHELL", "")


@pytest.mark.skipif(USING_ZSH, reason="Using ZSH")
@pytest.mark.skipif(not USING_ZSH, reason="Using ZSH")
@pytest.fixture(autouse=USING_ZSH, scope="session")
def zshrc(user_path: pathlib.Path) -> pathlib.Path:
"""This quiets ZSH default message.
Expand Down Expand Up @@ -70,7 +69,7 @@ def monkeypatch_plugin_test_packages(monkeypatch: pytest.MonkeyPatch) -> None:
"tests/fixtures/pluginsystem/plugins/tmuxp_test_plugin_fail/",
]
for path in paths:
monkeypatch.syspath_prepend(os.path.abspath(os.path.relpath(path)))
monkeypatch.syspath_prepend(str(pathlib.Path(path).resolve()))


@pytest.fixture(scope="function")
Expand Down
55 changes: 30 additions & 25 deletions docs/_ext/aafig.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"""
import logging
import posixpath
import typing as t
from hashlib import sha1 as sha
from os import path

Expand All @@ -28,11 +29,11 @@

logger = logging.getLogger(__name__)

DEFAULT_FORMATS = dict(html="svg", latex="pdf", text=None)
DEFAULT_FORMATS = {"html": "svg", "latex": "pdf", "text": None}


def merge_dict(dst, src):
for (k, v) in src.items():
for k, v in src.items():
if k not in dst:
dst[k] = v
return dst
Expand All @@ -58,22 +59,22 @@ class AafigDirective(images.Image):

has_content = True
required_arguments = 0
own_option_spec = dict(
line_width=float,
background=str,
foreground=str,
fill=str,
aspect=nonnegative_int,
textual=flag,
proportional=flag,
)
own_option_spec: t.ClassVar = {
"line_width": float,
"background": str,
"foreground": str,
"fill": str,
"aspect": nonnegative_int,
"textual": flag,
"proportional": flag,
}
option_spec = images.Image.option_spec.copy()
option_spec.update(own_option_spec)

def run(self):
aafig_options = dict()
own_options_keys = [self.own_option_spec.keys()] + ["scale"]
for (k, v) in self.options.items():
aafig_options = {}
own_options_keys = [self.own_option_spec.keys(), "scale"]
for k, v in self.options.items():
if k in own_options_keys:
# convert flags to booleans
if v is None:
Expand All @@ -88,7 +89,7 @@ def run(self):
if isinstance(image_node, nodes.system_message):
return [image_node]
text = "\n".join(self.content)
image_node.aafig = dict(options=aafig_options, text=text)
image_node.aafig = {"options": aafig_options, "text": text}
return [image_node]


Expand Down Expand Up @@ -138,13 +139,18 @@ def render_aafig_images(app, doctree):
img["height"] = height


class AafigureNotInstalled(AafigError):
def __init__(self, *args: object, **kwargs: object) -> None:
return super().__init__("aafigure module not installed", *args, **kwargs)


def render_aafigure(app, text, options):
"""
Render an ASCII art figure into the requested format output file.
"""

if aafigure is None:
raise AafigError("aafigure module not installed")
raise AafigureNotInstalled()

fname = get_basename(text, options)
fname = "{}.{}".format(get_basename(text, options), options["format"])
Expand Down Expand Up @@ -173,10 +179,10 @@ def render_aafigure(app, text, options):
f = None
try:
try:
f = open(metadata_fname)
extra = f.read()
except Exception:
raise AafigError()
with open(metadata_fname) as f:
extra = f.read()
except Exception as e:
raise AafigError() from e
finally:
if f is not None:
f.close()
Expand All @@ -190,14 +196,13 @@ def render_aafigure(app, text, options):
(visitor, output) = aafigure.render(text, outfn, options)
output.close()
except aafigure.UnsupportedFormatError as e:
raise AafigError(str(e))
raise AafigError(str(e)) from e

extra = None
if options["format"].lower() == "svg":
extra = visitor.get_size_attrs()
f = open(metadata_fname, "w")
f.write(extra)
f.close()
with open(metadata_fname, "w") as f:
f.write(extra)

return relfn, outfn, id, extra

Expand All @@ -206,7 +211,7 @@ def setup(app):
app.add_directive("aafig", AafigDirective)
app.connect("doctree-read", render_aafig_images)
app.add_config_value("aafig_format", DEFAULT_FORMATS, "html")
app.add_config_value("aafig_default_options", dict(), "html")
app.add_config_value("aafig_default_options", {}, "html")


# vim: set expandtab shiftwidth=4 softtabstop=4 :
15 changes: 6 additions & 9 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# flake8: NOQA: E501
import contextlib
import inspect
import pathlib
import sys
import typing as t
from os.path import relpath
import pathlib

import tmuxp

Expand Down Expand Up @@ -172,12 +172,12 @@
}

# aafig format, try to get working with pdf
aafig_format = dict(latex="pdf", html="gif")
aafig_format = {"latex": "pdf", "html": "gif"}

aafig_default_options = dict(scale=0.75, aspect=0.5, proportional=True)
aafig_default_options = {"scale": 0.75, "aspect": 0.5, "proportional": True}


def linkcode_resolve(domain, info): # NOQA: C901
def linkcode_resolve(domain, info):
"""
Determine the URL corresponding to Python object

Expand All @@ -200,7 +200,7 @@ def linkcode_resolve(domain, info): # NOQA: C901
for part in fullname.split("."):
try:
obj = getattr(obj, part)
except Exception:
except Exception: # NOQA: PERF203
return None

# strip decorators, which would resolve to the source of the decorator
Expand All @@ -224,10 +224,7 @@ def linkcode_resolve(domain, info): # NOQA: C901
except Exception:
lineno = None

if lineno:
linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1)
else:
linespec = ""
linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1) if lineno else ""

fn = relpath(fn, start=pathlib.Path(tmuxp.__file__).parent)

Expand Down
29 changes: 29 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,35 @@ module = [
]
ignore_missing_imports = true

[tool.ruff]
target-version = "py37"
select = [
"E", # pycodestyle
"F", # pyflakes
"I", # isort
"UP", # pyupgrade
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"Q", # flake8-quotes
"PTH", # flake8-use-pathlib
"SIM", # flake8-simplify
"TRY", # Trycertatops
"PERF", # Perflint
"RUF" # Ruff-specific rules
]

[tool.ruff.isort]
known-first-party = [
"tmuxp"
]
combine-as-imports = true

[tool.ruff.per-file-ignores]
"*/__init__.py" = ["F401"]
"src/tmuxp/workspace/finders.py" = ["PTH"]
"src/tmuxp/cli/*.py" = ["PTH"]
"docs/_ext/aafig.py" = ["PTH"]

[build-system]
requires = ["poetry_core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
25 changes: 17 additions & 8 deletions src/tmuxp/cli/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from tmuxp.config_reader import ConfigReader
from tmuxp.workspace.finders import find_workspace_file, get_workspace_dir

from .. import exc
from .utils import prompt_yes_no

if t.TYPE_CHECKING:
Expand Down Expand Up @@ -40,6 +41,13 @@ def create_convert_subparser(
return parser


class ConvertUnknownFileType(exc.TmuxpException):
def __init__(self, ext: str, *args: object, **kwargs: object) -> None:
return super().__init__(
f"Unknown filetype: {ext} (valid: [.json, .yaml, .yml])"
)


def command_convert(
workspace_file: t.Union[str, pathlib.Path],
answer_yes: bool,
Expand All @@ -61,7 +69,7 @@ def command_convert(
elif ext in [".yaml", ".yml"]:
to_filetype = "json"
else:
raise Exception(f"Unknown filetype: {ext} (valid: [.json, .yaml, .yml])")
raise ConvertUnknownFileType(ext)

configparser = ConfigReader.from_file(workspace_file)
newfile = workspace_file.parent / (str(workspace_file.stem) + f".{to_filetype}")
Expand All @@ -72,13 +80,14 @@ def command_convert(
**{"default_flow_style": False} if to_filetype == "yaml" else {},
)

if not answer_yes:
if prompt_yes_no(f"Convert to <{workspace_file}> to {to_filetype}?"):
if prompt_yes_no("Save workspace to %s?" % newfile):
answer_yes = True
if (
not answer_yes
and prompt_yes_no(f"Convert to <{workspace_file}> to {to_filetype}?")
and prompt_yes_no("Save workspace to %s?" % newfile)
):
answer_yes = True

if answer_yes:
buf = open(newfile, "w")
buf.write(new_workspace)
buf.close()
with open(newfile, "w") as buf:
buf.write(new_workspace)
print(f"New workspace file saved to <{newfile}>.")
3 changes: 1 addition & 2 deletions src/tmuxp/cli/debug_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import typing as t

from colorama import Fore

from libtmux.__about__ import __version__ as libtmux_version
from libtmux.common import get_version, tmux_cmd

Expand All @@ -34,7 +33,7 @@ def prepend_tab(strings):
"""
Prepend tab to strings in list.
"""
return list(map(lambda x: "\t%s" % x, strings))
return ["\t%s" % x for x in strings]

def output_break():
"""
Expand Down
10 changes: 5 additions & 5 deletions src/tmuxp/cli/freeze.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
import typing as t

from libtmux.server import Server

from tmuxp.config_reader import ConfigReader
from tmuxp.exc import TmuxpException
from tmuxp.workspace.finders import get_workspace_dir

from .. import util
from .. import exc, util
from ..workspace import freezer
from .utils import prompt, prompt_choices, prompt_yes_no

Expand Down Expand Up @@ -105,7 +106,7 @@ def command_freeze(
session = util.get_session(server)

if not session:
raise TmuxpException("Session not found.")
raise exc.SessionNotFound()
except TmuxpException as e:
print(e)
return
Expand Down Expand Up @@ -194,9 +195,8 @@ def extract_workspace_format(
destdir = os.path.dirname(dest)
if not os.path.isdir(destdir):
os.makedirs(destdir)
buf = open(dest, "w")
buf.write(workspace)
buf.close()
with open(dest, "w") as buf:
buf.write(workspace)

if not args.quiet:
print("Saved to %s." % dest)
Loading