Skip to content

Commit 6d72af4

Browse files
committed
Fix several lint issues and improve CI workflow
1 parent 2829500 commit 6d72af4

6 files changed

Lines changed: 38 additions & 29 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ jobs:
2424
- name: Install dependencies
2525
run: pip install -e ".[dev]"
2626

27+
- name: Lint
28+
run: ruff check src/ tests/
29+
2730
- name: Run tests
2831
run: pytest
2932

src/tca/__init__.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
"""Terminal Colors Architecture (TCA) theme support for Python."""
22

3-
from importlib.metadata import version, PackageNotFoundError
3+
from importlib.metadata import PackageNotFoundError, version
44

5-
from .theme import (
6-
Theme,
7-
Meta,
8-
ANSI,
9-
Semantic,
10-
UI,
11-
Base16,
12-
ColorRamp,
13-
)
145
from .loader import (
6+
find_theme,
157
get_data_dir,
168
get_themes_dir,
179
list_theme_files,
1810
list_theme_names,
19-
find_theme,
2011
load_theme,
2112
load_theme_file,
2213
load_theme_from_path,
2314
load_themes_from_dir,
2415
)
16+
from .theme import (
17+
ANSI,
18+
UI,
19+
Base16,
20+
ColorRamp,
21+
Meta,
22+
Semantic,
23+
Theme,
24+
)
2525

2626
try:
2727
__version__ = version("tca-python")

src/tca/loader.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import warnings
44
from pathlib import Path
5+
56
import platformdirs
67

78
from .theme import Theme

src/tca/textual.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import annotations
44

55
from dataclasses import dataclass
6-
from typing import TYPE_CHECKING
6+
from typing import TYPE_CHECKING, Any
77

88
from .theme import Theme
99

@@ -17,7 +17,7 @@ def _color(hex_str: str) -> Color:
1717
return _Color.parse(hex_str)
1818

1919

20-
def _color_system(**kwargs) -> ColorSystem:
20+
def _color_system(**kwargs: Any) -> ColorSystem:
2121
from textual.design import ColorSystem as _ColorSystem
2222
return _ColorSystem(**kwargs)
2323

@@ -31,7 +31,7 @@ class TextualTheme(Theme):
3131
"""
3232

3333
@classmethod
34-
def from_theme(cls, theme: Theme) -> "TextualTheme":
34+
def from_theme(cls, theme: Theme) -> TextualTheme:
3535
"""Create a TextualTheme from a Theme object."""
3636
from dataclasses import fields as _fields
3737
return cls(**{f.name: getattr(theme, f.name) for f in _fields(Theme)})
@@ -65,7 +65,7 @@ def ui_color(self, name: str) -> Color:
6565
"""Get UI color by name as Textual Color."""
6666
return _color(getattr(self.ui, name))
6767

68-
def get_palette_ramp(self, name: str) -> dict[int, Color]:
68+
def get_palette_ramp(self, name: str) -> dict[int, Color]: # type: ignore[override]
6969
"""Get palette ramp as a dict of index to Textual Color."""
7070
ramp = super().get_palette_ramp(name)
7171
return {tone: _color(color) for tone, color in ramp.items()}

src/tca/theme.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,28 @@
33
from __future__ import annotations
44

55
import sys
6+
from collections.abc import Iterator
67
from dataclasses import dataclass, fields
7-
from typing import Any
8+
from typing import Any, TypeVar
89

910
if sys.version_info >= (3, 11):
1011
import tomllib
1112
else:
12-
import tomli as tomllib # type: ignore[no-redef]
13+
import tomli as tomllib
1314

1415

1516
# ---------------------------------------------------------------------------
1617
# Shared mixin for _Raw* data classes
1718
# ---------------------------------------------------------------------------
1819

20+
_T = TypeVar("_T", bound="_FromDictMixin")
21+
22+
1923
class _FromDictMixin:
2024
"""Mixin providing a generic from_dict classmethod for dataclasses."""
2125

2226
@classmethod
23-
def from_dict(cls, d: dict[str, Any]):
27+
def from_dict(cls: type[_T], d: dict[str, Any]) -> _T:
2428
known = {f.name for f in fields(cls)} # type: ignore[arg-type]
2529
return cls(**{k: v for k, v in d.items() if k in known})
2630

@@ -90,7 +94,7 @@ class _RawUI:
9094
selection_fg: str | None = None
9195

9296
@classmethod
93-
def from_dict(cls, d: dict[str, Any]) -> "_RawUI":
97+
def from_dict(cls, d: dict[str, Any]) -> _RawUI:
9498
"""Build from a nested dict as produced by TOML [ui.bg], [ui.fg], etc."""
9599
field_names = {f.name for f in fields(cls)}
96100
flat: dict[str, str] = {}
@@ -126,7 +130,7 @@ class _RawBase16:
126130
base0f: str | None = None
127131

128132
@classmethod
129-
def from_dict(cls, d: dict[str, Any]) -> "_RawBase16":
133+
def from_dict(cls, d: dict[str, Any]) -> _RawBase16:
130134
field_names = {f.name for f in fields(cls)}
131135
# Normalise keys to lowercase (spec examples show base0A etc.)
132136
normalised = {k.lower(): v for k, v in d.items()}
@@ -153,7 +157,7 @@ def __len__(self) -> int:
153157
def __getitem__(self, index: int) -> str:
154158
return self.colors[index]
155159

156-
def __iter__(self):
160+
def __iter__(self) -> Iterator[str]:
157161
return iter(self.colors)
158162

159163

@@ -262,7 +266,7 @@ class Theme:
262266
base16: Base16
263267

264268
@classmethod
265-
def _from_raw(cls, raw: "_RawTheme") -> "Theme":
269+
def _from_raw(cls, raw: _RawTheme) -> Theme:
266270
meta = raw.resolve_meta()
267271
palette = raw.resolve_palette()
268272
ansi = raw.resolve_ansi()
@@ -284,12 +288,12 @@ def get_palette_ramp(self, name: str) -> dict[int, str]:
284288
return {i: color for i, color in enumerate(ramp.colors)}
285289

286290
@classmethod
287-
def from_toml(cls, data_str: str) -> "Theme":
291+
def from_toml(cls, data_str: str) -> Theme:
288292
raw = _RawTheme.from_toml(data_str)
289293
return cls._from_raw(raw)
290294

291295
@classmethod
292-
def from_dict(cls, data: dict[str, Any]) -> "Theme":
296+
def from_dict(cls, data: dict[str, Any]) -> Theme:
293297
raw = _RawTheme.from_dict(data)
294298
return cls._from_raw(raw)
295299

@@ -505,14 +509,14 @@ def _is_dark(self) -> bool:
505509
# ------------------------------------------------------------------
506510

507511
@classmethod
508-
def from_toml(cls, data_str: str) -> "_RawTheme":
512+
def from_toml(cls, data_str: str) -> _RawTheme:
509513
data = tomllib.loads(data_str)
510514
if not data:
511515
raise ValueError("Empty theme file")
512516
return cls.from_dict(data)
513517

514518
@classmethod
515-
def from_dict(cls, data: dict[str, Any]) -> "_RawTheme":
519+
def from_dict(cls, data: dict[str, Any]) -> _RawTheme:
516520
# --- [theme] section (required) ---
517521
theme_dict = data.get("theme", {})
518522
theme_meta = _RawThemeMeta.from_dict(theme_dict)

tests/test_theme.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""Tests for TCA theme loading and resolution."""
22

3+
from pathlib import Path
4+
35
import pytest
6+
47
from tca import load_theme, load_theme_from_path, load_themes_from_dir
58
from tca.theme import Theme
6-
from pathlib import Path
7-
89

910
DRACULA_PATH = Path(__file__).parent / "dracula.toml"
1011
THEMES_DIR = Path(__file__).parent
@@ -68,7 +69,7 @@ def test_ansi_normal_colors():
6869

6970

7071
def test_ansi_bright_colors():
71-
"""Bright ANSI colours (brightBlack in YAML → bright_black in Python) are resolved."""
72+
"""Bright ANSI colours (e.g. bright_black) are populated and valid."""
7273
theme = load_theme(DRACULA_PATH)
7374
assert theme.ansi.bright_black is not None
7475
assert theme.ansi.bright_black.startswith("#")

0 commit comments

Comments
 (0)