Skip to content

Commit 2d369d2

Browse files
committed
adds docs fixes , compatibility fixes , lint , ci , precommit improvements
1 parent 6c5ffbf commit 2d369d2

315 files changed

Lines changed: 4632 additions & 2401 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
[![codecov](https://codecov.io/gh/ccBittorrent/ccbt/branch/main/graph/badge.svg)](https://codecov.io/gh/ccBittorrent/ccbt)
44
[![🥷 Bandit](https://img.shields.io/badge/🥷-security-yellow.svg)](https://ccbittorrent.readthedocs.io/en/reports/bandit/)
5-
[![🐍 Python](https://img.shields.io/badge/python-3.8%2B-blue.svg)](../pyproject.toml)
5+
[![🐍python 🟰](https://github.com/ccBitTorrent/ccbt/actions/workflows/test.yml/badge.svg)](https://github.com/ccBitTorrent/ccbt/actions/workflows/test.yml)
6+
[![🐧Linux](https://github.com/ccBitTorrent/ccbt/actions/workflows/test.yml/badge.svg)](https://github.com/ccBitTorrent/ccbt/actions/workflows/test.yml)
7+
[![🪟Windows](https://github.com/ccBitTorrent/ccbt/actions/workflows/test.yml/badge.svg)](https://github.com/ccBitTorrent/ccbt/actions/workflows/test.yml)
8+
69
[![📜License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://ccbittorrent.readthedocs.io/en/license/)
710
[![🤝Contributing](https://img.shields.io/badge/🤝-open-brightgreen?logo=pre-commit&logoColor=white)](https://ccbittorrent.readthedocs.io/en/contributing/)
811
[![🎁UV](https://img.shields.io/badge/🎁-uv-orange.svg)](https://ccbittorrent.readthedocs.io/en/getting-started/)

.github/workflows/build-documentation.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,19 @@ jobs:
140140
141141
- name: Build documentation
142142
run: |
143+
# Ensure coverage directory exists right before build (in case it was cleaned)
144+
mkdir -p site/reports/htmlcov
145+
if [ ! -f site/reports/htmlcov/index.html ]; then
146+
echo '<html><body><h1>Coverage Report</h1><p>Coverage report not available. Run tests to generate coverage data.</p></body></html>' > site/reports/htmlcov/index.html
147+
fi
148+
143149
# Use the patched build script which includes all necessary patches:
144150
# - i18n plugin fixes (alternates attribute, Locale validation for 'arc')
145151
# - git-revision-date-localized plugin fix for 'arc' locale
152+
# - Autorefs plugin patch to suppress multiple primary URLs warnings
153+
# - Coverage plugin patch to suppress missing directory warnings
146154
# - All patches are applied before mkdocs is imported
147155
# Set MKDOCS_STRICT=true to enable strict mode in CI
148-
# Reports are ensured to exist in previous step to avoid warnings
149156
MKDOCS_STRICT=true uv run python dev/build_docs_patched_clean.py
150157
151158
- name: Upload documentation artifact

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ jobs:
3838
- name: Run Ruff formatting check
3939
run: |
4040
uv run ruff --config dev/ruff.toml format --check ccbt/
41+
42+
- name: Run compatibility linter
43+
run: |
44+
uv run python dev/compatibility_linter.py ccbt/
4145
4246
type-check:
4347
name: type-check

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ MagicMock
1212
.coverage_html
1313
.cursor
1414
scripts
15-
compatibility_tests/
15+
compatibility_tests/
16+
lint_outputs/
1617

1718
# Byte-compiled / optimized / DLL files
1819
__pycache__/

ccbt/cli/advanced_commands.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import tempfile
1212
import time
1313
from pathlib import Path
14-
from typing import Any
14+
from typing import Any, Optional
1515

1616
import click
1717
from rich.console import Console
@@ -36,7 +36,7 @@ class OptimizationPreset:
3636
def _apply_optimizations(
3737
preset: str = OptimizationPreset.BALANCED,
3838
save_to_file: bool = False,
39-
config_file: str | None = None,
39+
config_file: Optional[str] = None,
4040
) -> dict[str, Any]:
4141
"""Apply performance optimizations based on system capabilities.
4242
@@ -248,7 +248,7 @@ def performance(
248248
optimize: bool,
249249
preset: str,
250250
save: bool,
251-
config_file: str | None,
251+
config_file: Optional[str],
252252
benchmark: bool,
253253
profile: bool,
254254
) -> None:

ccbt/cli/checkpoints.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import asyncio
1010
import time
1111
from pathlib import Path
12-
from typing import TYPE_CHECKING
12+
from typing import TYPE_CHECKING, Optional
1313

1414
from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
1515
from rich.table import Table
@@ -236,7 +236,7 @@ def backup_checkpoint(
236236
def restore_checkpoint(
237237
config_manager: ConfigManager,
238238
backup_file: str,
239-
info_hash: str | None,
239+
info_hash: Optional[str],
240240
console: Console,
241241
) -> None:
242242
"""Restore a checkpoint from a backup file."""

ccbt/cli/config_commands.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import logging
1616
import os
1717
from pathlib import Path
18+
from typing import Optional, Union
1819

1920
import click
2021
import toml
@@ -26,7 +27,7 @@
2627
logger = logging.getLogger(__name__)
2728

2829

29-
def _find_project_root(start_path: Path | None = None) -> Path | None:
30+
def _find_project_root(start_path: Optional[Path] = None) -> Optional[Path]:
3031
"""Find the project root directory by looking for pyproject.toml or .git.
3132
3233
Walks up the directory tree from start_path (or current directory) until
@@ -56,7 +57,7 @@ def _find_project_root(start_path: Path | None = None) -> Path | None:
5657

5758

5859
def _should_skip_project_local_write(
59-
config_file: Path | None, explicit_config_file: str | Path | None
60+
config_file: Optional[Path], explicit_config_file: Optional[Union[str, Path]]
6061
) -> bool:
6162
"""Check if we should skip writing to project-local ccbt.toml during tests.
6263
@@ -130,9 +131,9 @@ def config():
130131
@click.option("--config", "config_file", type=click.Path(exists=True), default=None)
131132
def show_config(
132133
format_: str,
133-
section: str | None,
134-
key: str | None,
135-
config_file: str | None,
134+
section: Optional[str],
135+
key: Optional[str],
136+
config_file: Optional[str],
136137
):
137138
"""Show current configuration in the desired format."""
138139
cm = ConfigManager(config_file)
@@ -174,7 +175,7 @@ def show_config(
174175
@config.command("get")
175176
@click.argument("key")
176177
@click.option("--config", "config_file", type=click.Path(exists=True), default=None)
177-
def get_value(key: str, config_file: str | None):
178+
def get_value(key: str, config_file: Optional[str]):
178179
"""Get a specific configuration value by dotted path."""
179180
cm = ConfigManager(config_file)
180181
data = cm.config.model_dump(mode="json")
@@ -223,9 +224,9 @@ def set_value(
223224
value: str,
224225
global_flag: bool,
225226
local_flag: bool,
226-
config_file: str | None,
227-
restart_daemon_flag: bool | None,
228-
no_restart_daemon_flag: bool | None,
227+
config_file: Optional[str],
228+
restart_daemon_flag: Optional[bool],
229+
no_restart_daemon_flag: Optional[bool],
229230
):
230231
"""Set a configuration value and persist to TOML file.
231232
@@ -325,12 +326,12 @@ def parse_value(raw: str):
325326
help=_("Skip daemon restart even if needed"),
326327
)
327328
def reset_config(
328-
section: str | None,
329-
key: str | None,
329+
section: Optional[str],
330+
key: Optional[str],
330331
confirm: bool,
331-
config_file: str | None,
332-
restart_daemon_flag: bool | None,
333-
no_restart_daemon_flag: bool | None,
332+
config_file: Optional[str],
333+
restart_daemon_flag: Optional[bool],
334+
no_restart_daemon_flag: Optional[bool],
334335
):
335336
"""Reset configuration to defaults (optionally for a section/key)."""
336337
if not confirm:
@@ -399,7 +400,7 @@ def reset_config(
399400

400401
@config.command("validate")
401402
@click.option("--config", "config_file", type=click.Path(exists=True), default=None)
402-
def validate_config_cmd(config_file: str | None):
403+
def validate_config_cmd(config_file: Optional[str]):
403404
"""Validate configuration file and print result."""
404405
try:
405406
ConfigManager(config_file)
@@ -414,10 +415,10 @@ def validate_config_cmd(config_file: str | None):
414415
@click.option("--backup", is_flag=True, help=_("Create backup before migration"))
415416
@click.option("--config", "config_file", type=click.Path(exists=True), default=None)
416417
def migrate_config_cmd(
417-
from_version: str | None, # noqa: ARG001
418-
to_version: str | None, # noqa: ARG001
418+
from_version: Optional[str], # noqa: ARG001
419+
to_version: Optional[str], # noqa: ARG001
419420
backup: bool,
420-
config_file: str | None,
421+
config_file: Optional[str],
421422
):
422423
"""Migrate configuration between versions (no-op placeholder)."""
423424
# For now, this is a placeholder that just validates and echoes

ccbt/cli/config_commands_extended.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import logging
5050
import os
5151
from pathlib import Path
52+
from typing import Optional
5253

5354
import click
5455
import toml
@@ -130,7 +131,7 @@ def config_extended():
130131
help="Specific model to generate schema for (e.g., Config, NetworkConfig)",
131132
)
132133
@click.option("--output", "-o", type=click.Path(), help="Output file path")
133-
def schema_cmd(format_: str, model: str | None, output: str | None):
134+
def schema_cmd(format_: str, model: Optional[str], output: Optional[str]):
134135
"""Generate JSON schema for configuration models."""
135136
try:
136137
if model:
@@ -209,10 +210,10 @@ def schema_cmd(format_: str, model: str | None, output: str | None):
209210
def template_cmd(
210211
template_name: str,
211212
apply: bool,
212-
output: str | None,
213-
config_file: str | None,
214-
restart_daemon_flag: bool | None,
215-
no_restart_daemon_flag: bool | None,
213+
output: Optional[str],
214+
config_file: Optional[str],
215+
restart_daemon_flag: Optional[bool],
216+
no_restart_daemon_flag: Optional[bool],
216217
):
217218
"""Manage configuration templates."""
218219
try:
@@ -333,10 +334,10 @@ def template_cmd(
333334
def profile_cmd(
334335
profile_name: str,
335336
apply: bool,
336-
output: str | None,
337-
config_file: str | None,
338-
restart_daemon_flag: bool | None,
339-
no_restart_daemon_flag: bool | None,
337+
output: Optional[str],
338+
config_file: Optional[str],
339+
restart_daemon_flag: Optional[bool],
340+
no_restart_daemon_flag: Optional[bool],
340341
):
341342
"""Manage configuration profiles."""
342343
try:
@@ -448,7 +449,7 @@ def profile_cmd(
448449
help="Compress backup",
449450
)
450451
@click.option("--config", "config_file", type=click.Path(exists=True), default=None)
451-
def backup_cmd(description: str, compress: bool, config_file: str | None):
452+
def backup_cmd(description: str, compress: bool, config_file: Optional[str]):
452453
"""Create configuration backup."""
453454
try:
454455
cm = ConfigManager(config_file)
@@ -488,7 +489,7 @@ def backup_cmd(description: str, compress: bool, config_file: str | None):
488489
help="Skip confirmation prompt",
489490
)
490491
@click.option("--config", "config_file", type=click.Path(), default=None)
491-
def restore_cmd(backup_file: str, confirm: bool, config_file: str | None):
492+
def restore_cmd(backup_file: str, confirm: bool, config_file: Optional[str]):
492493
"""Restore configuration from backup."""
493494
try:
494495
if not confirm:
@@ -578,7 +579,7 @@ def list_backups_cmd(format_: str):
578579
type=click.Path(),
579580
help="Output file path",
580581
)
581-
def diff_cmd(config1: str, config2: str, format_: str, output: str | None):
582+
def diff_cmd(config1: str, config2: str, format_: str, output: Optional[str]):
582583
"""Compare two configuration files."""
583584
try:
584585
# ConfigDiff instance is not required; use classmethod compare_files
@@ -696,10 +697,10 @@ def capabilities_summary_cmd():
696697
)
697698
def auto_tune_cmd(
698699
apply: bool,
699-
output: str | None,
700-
config_file: str | None,
701-
restart_daemon_flag: bool | None,
702-
no_restart_daemon_flag: bool | None,
700+
output: Optional[str],
701+
config_file: Optional[str],
702+
restart_daemon_flag: Optional[bool],
703+
no_restart_daemon_flag: Optional[bool],
703704
):
704705
"""Auto-tune configuration based on system capabilities."""
705706
try:
@@ -792,7 +793,7 @@ def auto_tune_cmd(
792793
help="Output file path",
793794
)
794795
@click.option("--config", "config_file", type=click.Path(exists=True), default=None)
795-
def export_cmd(format_: str, output: str, config_file: str | None):
796+
def export_cmd(format_: str, output: str, config_file: Optional[str]):
796797
"""Export configuration to file."""
797798
try:
798799
cm = ConfigManager(config_file)
@@ -857,11 +858,11 @@ def export_cmd(format_: str, output: str, config_file: str | None):
857858
)
858859
def import_cmd(
859860
import_file: str,
860-
format_: str | None,
861-
output: str | None,
862-
config_file: str | None,
863-
restart_daemon_flag: bool | None,
864-
no_restart_daemon_flag: bool | None,
861+
format_: Optional[str],
862+
output: Optional[str],
863+
config_file: Optional[str],
864+
restart_daemon_flag: Optional[bool],
865+
no_restart_daemon_flag: Optional[bool],
865866
):
866867
"""Import configuration from file."""
867868
try:
@@ -967,7 +968,7 @@ def import_cmd(
967968
is_flag=True,
968969
help="Show detailed validation results",
969970
)
970-
def validate_cmd(config_file: str | None, detailed: bool):
971+
def validate_cmd(config_file: Optional[str], detailed: bool):
971972
"""Validate configuration file."""
972973
try:
973974
cm = ConfigManager(config_file)

ccbt/cli/config_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from __future__ import annotations
88

9-
from typing import TYPE_CHECKING
9+
from typing import TYPE_CHECKING, Optional
1010

1111
from rich.console import Console
1212
from rich.prompt import Confirm
@@ -249,7 +249,7 @@ async def _restart_daemon_async(force: bool = False) -> bool:
249249
def restart_daemon_if_needed(
250250
_config_manager: ConfigManager,
251251
requires_restart: bool,
252-
auto_restart: bool | None = None,
252+
auto_restart: Optional[bool] = None,
253253
force: bool = False,
254254
) -> bool:
255255
"""Restart daemon if needed and running.

ccbt/cli/create_torrent.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import logging
99
from pathlib import Path
10+
from typing import Optional
1011

1112
import click
1213
from rich.console import Console
@@ -89,15 +90,15 @@
8990
def create_torrent(
9091
_ctx: click.Context,
9192
source: Path,
92-
output: Path | None,
93+
output: Optional[Path],
9394
format_v2: bool,
9495
format_hybrid: bool,
9596
format_v1: bool,
9697
tracker: tuple[str, ...],
9798
web_seed: tuple[str, ...],
98-
comment: str | None,
99+
comment: Optional[str],
99100
created_by: str,
100-
piece_length: int | None,
101+
piece_length: Optional[int],
101102
private: bool,
102103
_verbose: int = 0, # ARG001: Unused parameter (Click count=True)
103104
) -> None:

0 commit comments

Comments
 (0)