diff --git a/Makefile b/Makefile index 6b6158b..4dbd615 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ build := uv build publish := uv publish --username=__token__ --keyring-provider=subprocess python := $(run) python ruff := $(run) ruff -lint := $(ruff) check --select I +lint := $(ruff) check fmt := $(ruff) format mypy := $(run) mypy spell := $(run) codespell diff --git a/pyproject.toml b/pyproject.toml index e587702..26cb259 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,3 +95,26 @@ explicit = true venvPath="." venv=".venv" exclude=[".venv"] + +[tool.ruff.lint] +select = [ + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # flake8-simplify + "SIM", + # isort + "I", +] +ignore = [ + # I think try...expect...pass reads far better. + "SIM105", +] + +[tool.ruff.lint.pycodestyle] +max-line-length = 120 diff --git a/src/aging/data/config.py b/src/aging/data/config.py index cb6b999..9402357 100644 --- a/src/aging/data/config.py +++ b/src/aging/data/config.py @@ -2,12 +2,12 @@ ############################################################################## # Python imports. +from collections.abc import Iterator from contextlib import contextmanager from dataclasses import asdict, dataclass, field -from functools import lru_cache +from functools import cache from json import dumps, loads from pathlib import Path -from typing import Iterator ############################################################################## # Local imports. @@ -84,7 +84,7 @@ def save_configuration(configuration: Configuration) -> Configuration: ############################################################################## -@lru_cache(maxsize=None) +@cache def load_configuration() -> Configuration: """Load the configuration. diff --git a/src/aging/screens/main.py b/src/aging/screens/main.py index 34b3a9d..53e5334 100644 --- a/src/aging/screens/main.py +++ b/src/aging/screens/main.py @@ -3,8 +3,8 @@ ############################################################################## # Python imports. from argparse import Namespace +from collections.abc import Iterator from pathlib import Path -from typing import Iterator ############################################################################## # NGDB imports. @@ -396,7 +396,7 @@ def _open_guide(self, message: OpenGuide) -> None: # actually is a guide. try: new_guide = NortonGuide(message.location) - except IOError as error: + except OSError as error: self.notify( str(error), title=f"Error opening {message.location}", severity="error" ) diff --git a/src/aging/screens/search.py b/src/aging/screens/search.py index 4998d33..ff0434f 100644 --- a/src/aging/screens/search.py +++ b/src/aging/screens/search.py @@ -1,9 +1,10 @@ """Provides the search screen.""" ############################################################################## -# NGDB imports. +# Python imports. +from collections.abc import Iterator from dataclasses import dataclass -from typing import Iterator, NamedTuple +from typing import NamedTuple ############################################################################## # Humanize imports. @@ -525,7 +526,7 @@ def _search_guide( return self._search_entry(search, entry, worker, needle, ignore_case) self.post_message(self.FinishedGuide()) - except (IOError, NGDBError) as error: + except (OSError, NGDBError) as error: self.notify( str(error), title=f"Failed to search {guide.location}", severity="error" ) diff --git a/src/aging/widgets/entry_viewer/entry_content.py b/src/aging/widgets/entry_viewer/entry_content.py index e7d9e9f..3bf88f7 100644 --- a/src/aging/widgets/entry_viewer/entry_content.py +++ b/src/aging/widgets/entry_viewer/entry_content.py @@ -313,34 +313,35 @@ def render_line(self, y: int) -> Strip: option_index, _ = self._lines[self.scroll_offset.y + y] except IndexError: return strip - if option_index == self.highlighted: - if highlight := self.get_visual_style("option-list--option-highlighted"): - highlight_style = highlight.rich_style - # Despite its name, Style.without_color removes more than - # colour; one of the things it removes it `meta`. The - # OptionList uses meta to know which option was clicked on. - # So we need to peek into the highlight strip and pull out - # an example of the style so we can get the meta for later. - borrowed_style = next(iter(strip)).style - strip = Strip( - [ - Segment( - text, - style.without_color + highlight_style - if style is not None - else None, - control, - ) - for text, style, control in strip - ] - ).simplify() - # So here, if we have a borrowed style, and if it has meta - # information, we apply it to the new strip we created so - # that the `option` value is retained. Without it the user - # wouldn't be able to cause an `OptionSelected` message from - # clicking on a highlighted option. - if borrowed_style is not None and borrowed_style.meta: - strip = strip.apply_meta(borrowed_style.meta) + if option_index == self.highlighted and ( + highlight := self.get_visual_style("option-list--option-highlighted") + ): + highlight_style = highlight.rich_style + # Despite its name, Style.without_color removes more than + # colour; one of the things it removes it `meta`. The + # OptionList uses meta to know which option was clicked on. + # So we need to peek into the highlight strip and pull out + # an example of the style so we can get the meta for later. + borrowed_style = next(iter(strip)).style + strip = Strip( + [ + Segment( + text, + style.without_color + highlight_style + if style is not None + else None, + control, + ) + for text, style, control in strip + ] + ).simplify() + # So here, if we have a borrowed style, and if it has meta + # information, we apply it to the new strip we created so + # that the `option` value is retained. Without it the user + # wouldn't be able to cause an `OptionSelected` message from + # clicking on a highlighted option. + if borrowed_style is not None and borrowed_style.meta: + strip = strip.apply_meta(borrowed_style.meta) return strip def search_next(self) -> None: diff --git a/src/aging/widgets/guide_directory.py b/src/aging/widgets/guide_directory.py index 466f40c..241beac 100644 --- a/src/aging/widgets/guide_directory.py +++ b/src/aging/widgets/guide_directory.py @@ -12,7 +12,6 @@ ############################################################################## # Textual imports. from textual import on, work -from textual.binding import Binding from textual.reactive import var from textual.widgets.option_list import Option, OptionDoesNotExist @@ -193,7 +192,7 @@ def _refresh_guides(self, new_guides: Guides) -> None: """ try: save_guides(new_guides) - except IOError as error: + except OSError as error: self.notify(str(error), title="Unable to save guides", severity="error") return self.post_message(GuidesUpdated())