From 3faee283f3e56f046e106fff5330a756a949618d Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Tue, 23 Dec 2025 21:24:30 +0100 Subject: Improve layout and add ruff configuration --- .ruff.toml | 98 ++++++++++++++++++++++++++++++++++++++++++++++ src/scorecounter/app.py | 102 +++++++++++++++++++++++++++++++----------------- 2 files changed, 165 insertions(+), 35 deletions(-) create mode 100644 .ruff.toml diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..956737c --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,98 @@ +cache-dir = "~/.cache/ruff" +indent-width = 4 +line-length = 79 +target-version = "py314" + +[lint] +select = ["ALL", "D101", "D102", "D103", "D104"] +ignore = [ + "ANN", + "BLE001", + "COM812", + "D", + "EM101", # Exception must not use a string literal, assign to variable first + "EM102", # Exception must not use an f-string literal, assign to variable first + "ERA001", + #"FBT001", + #"FBT002", + #"INP001", + #"ISC001", + #"N802", + #"N806", + #"PLR2004", + # "PTH111", + # "PTH123", + "RUF012", + #"RUF013", + #"S101", + "S308", + #"T201", + "TRY003", + "TRY300", + #"UP020" +] + +# C901 - `outside_temperature` is too complex (12 > 10) +# D101 - Missing docstring in public class +# D102 - Missing docstring in public method +# D200 - One-line docstring should fit on one line +# D203 - 1 blank line required before class docstring +# D205 - 1 blank line required between summary line and description +# D403 - First word of the first line should be capitalized: `str` -> `Str` +# ERA001 - Found commented-out code +# FBT001 - Boolean-typed positional argument in function definition +# FBT002 - Boolean default positional argument in function definition +# INP001 - File `beinc_weechat.py` is part of an implicit namespace package. Add an `__init__.py` +# N802 - Function name `do_GET` should be lowercase +# N806 - Variable `POST_data` in function should be lowercase +# PTH111 - `os.path.expanduser()` should be replaced by `Path.expanduser()` +# PTH123 - `open()` should be replaced by `Path.open()` +# PLR0912 - Too many branches (13 > 12) +# PLR0913 - Too many arguments in function definition (6 > 5) +# PLR2004 - Magic value used in comparison, consider replacing `200` with a constant variable +# RUF012 - Mutable class attributes should be annotated with `typing.ClassVar` +# RUF013 - PEP 484 prohibits implicit `Optional` +# S101 - Use of `assert` detected +# S308 - Use of `mark_safe` may expose cross-site scripting vulnerabilities +# S603 - `subprocess` call: check for execution of untrusted input +# T201 - `print` found +# TRY003 - Avoid specifying long messages outside the exception class +# TRY300 - Consider moving this statement to an `else` block +# UP020 - Use builtin `open` + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +[format] +# Like Black, use double quotes for strings. +quote-style = "single" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = true + +# Like Black, automatically detect the appropriate line ending. +line-ending = "lf" + +# Enable auto-formatting of code examples in docstrings. Markdown, +# reStructuredText code/literal blocks and doctests are all supported. +# +# This is currently disabled by default, but it is planned for this +# to be opt-out in the future. +docstring-code-format = false + +# Set the line length limit used when formatting code snippets in +# docstrings. +# +# This only has an effect when the `docstring-code-format` setting is +# enabled. +docstring-code-line-length = "dynamic" + +[lint.flake8-quotes] +inline-quotes = "single" + +[lint.isort] +split-on-trailing-comma = false diff --git a/src/scorecounter/app.py b/src/scorecounter/app.py index cf4bc1d..26a0c74 100644 --- a/src/scorecounter/app.py +++ b/src/scorecounter/app.py @@ -1,7 +1,7 @@ """Simple score counter for two teams""" import toga -from toga.style.pack import COLUMN, ROW +from toga.constants import COLUMN, ROW class ScoreCounter(toga.App): @@ -9,65 +9,97 @@ class ScoreCounter(toga.App): def startup(self): """startup entry point""" - self.score_team1 = 0 - self.score_team2 = 0 + self._score_team1 = 0 + self._score_team2 = 0 - main_box = toga.Box(direction=COLUMN) + self.main_window = toga.MainWindow( + title=self.formal_name, on_resize=self.cb_main_window_resize + ) - self.score_label1 = toga.Label( - f'Team1: {self.score_team1}', margin=(0, 5), color='red' + self._score_label1 = toga.Label( + f'Team1: {self._score_team1}', + margin=(0, 5), + color='red', + font_weight='bold', + font_size=24, + ) + self._score_label2 = toga.Label( + f'Team2: {self._score_team2}', + margin=(0, 5), + color='blue', + font_weight='bold', + font_size=24, ) - self.score_label2 = toga.Label( - f'Team2: {self.score_team2}', margin=(0, 5), color='blue' + separator_label = toga.Label('', flex=1) + score_box = toga.Box( + direction=ROW, + margin=5, + children=[self._score_label1, separator_label, self._score_label2], ) - self.separator_label = toga.Label(' - ', margin=(0, 10)) - score_box = toga.Box(direction=ROW, margin=5) - score_box.add(self.score_label1) - score_box.add(self.separator_label) - score_box.add(self.score_label2) + # empty box for consuming vertical space + empty_box = toga.Box(flex=1) - button_clear = toga.Button( - 'Clear', on_press=self.cb_clear, margin=(20, 5, 5) + self._button_team1 = toga.Button( + 'Team 1 (+1)', + on_press=self.cb_score_team1, + background_color='red', + flex=1, + font_size=18, + color='white', + ) + self._button_team2 = toga.Button( + 'Team 2 (+1)', + on_press=self.cb_score_team2, + background_color='blue', + flex=1, + font_size=18, + color='white', + ) + button_box = toga.Box( + direction=COLUMN, + children=[self._button_team1, self._button_team2], + margin=(20, 5, 0), ) - button_team1 = toga.Button( - 'Team 1 (+1)', on_press=self.cb_score_team1, margin=(20, 5, 5) + + self.main_window.content = toga.Box( + direction=COLUMN, children=[score_box, empty_box, button_box] ) - button_team1.style.background_color = 'red' - button_team2 = toga.Button( - 'Team 2 (+1)', on_press=self.cb_score_team2, margin=5 + self._button_team1.style.height = int(self.main_window.size.height / 5) + self._button_team2.style.height = int(self.main_window.size.height / 5) + + command_clear = toga.Command( + self.cb_clear, text='Clear', group=toga.Group('Scoreboard') ) - button_team2.style.background_color = 'blue' - - main_box.add(score_box) - main_box.add(button_team1) - main_box.add(button_team2) - main_box.add(button_clear) - - self.main_window = toga.MainWindow(title=self.formal_name) - self.main_window.content = main_box + self.commands.add(command_clear) + self.main_window.show() def cb_clear(self, _widget): """Clear on press callback""" - self.score_team1 = 0 - self.score_team2 = 0 + self._score_team1 = 0 + self._score_team2 = 0 self.refresh() def cb_score_team1(self, _widget): """Team1 on press callback""" - self.score_team1 += 1 + self._score_team1 += 1 self.refresh() def cb_score_team2(self, _widget): """Team 2 on press callback""" - self.score_team2 += 1 + self._score_team2 += 1 self.refresh() + def cb_main_window_resize(self, widget) -> None: + """On main window resize callback""" + self._button_team1.style.height = int(widget.size.height / 5) + self._button_team2.style.height = int(widget.size.height / 5) + def refresh(self): """Refreshes the score labels""" - self.score_label1.text = f'Team1: {self.score_team1}' - self.score_label2.text = f'Team2: {self.score_team2}' + self._score_label1.text = f'Team1: {self._score_team1}' + self._score_label2.text = f'Team2: {self._score_team2}' def main(): -- cgit v1.3