Skip to content

chore: add ruff linting rules and fix violations#109

Merged
twangodev merged 5 commits intomainfrom
fix/formatting
Feb 13, 2026
Merged

chore: add ruff linting rules and fix violations#109
twangodev merged 5 commits intomainfrom
fix/formatting

Conversation

@twangodev
Copy link
Collaborator

@twangodev twangodev commented Feb 13, 2026

Summary by CodeRabbit

  • New Features

    • Added APICreditEntity to the public API exports.
  • Chores

    • Configured Ruff linting in project configuration.
    • Modernized type annotations to Python 3.9+ built-ins and tightened public model hints.
    • Consolidated and normalized imports across the codebase; simplified iteration/style patterns.
    • Updated example TTS script and getting-started notebook representation.
  • Tests

    • Reworked and reorganized unit/integration tests for consistency and clearer fixtures.

Copilot AI review requested due to automatic review settings February 13, 2026 19:05
@coderabbitai
Copy link

coderabbitai bot commented Feb 13, 2026

📝 Walkthrough

Walkthrough

Wide-scope typing and import modernizations across the codebase: replace typing generics with built-in generics, move iterator types to collections.abc, add from __future__ import annotations, switch several relative imports to absolute fishaudio paths, add Ruff config, and minor example/notebook and test formatting edits.

Changes

Cohort / File(s) Summary
Type Annotation Modernization
src/fishaudio/types/asr.py, src/fishaudio/types/shared.py, src/fishaudio/types/tts.py, src/fishaudio/types/voices.py
Replaced List[T]/Dict annotations with built-in list[T]/dict[...]; removed unused List/Dict imports; adjusted default annotations where applicable.
Resource Type & Iteration Updates
src/fishaudio/resources/tts.py, src/fishaudio/resources/voices.py, src/fishaudio/resources/realtime.py
Updated method signatures to use built-in generics (list[...], dict[...]); moved iterator/generator type imports to collections.abc; small control-flow tweak in realtime error-check branch.
Core Type & Signature Adjustments
src/fishaudio/core/client_wrapper.py, src/fishaudio/core/request_options.py, src/fishaudio/core/websocket_options.py, src/fishaudio/core/iterators.py
Switched Dictdict and Listlist in signatures; updated several method annotations to use built-in generics; iterator types now from collections.abc.
Absolute Import Path Changes
src/fishaudio/resources/account.py, src/fishaudio/resources/asr.py, src/fishaudio/utils/play.py, src/fishaudio/utils/stream.py
Replaced relative imports (..core, ..types, ..exceptions) with absolute fishaudio.* imports; no runtime behavior changes.
SDK and IO Adjustments
src/fish_audio_sdk/apis.py, src/fish_audio_sdk/io.py, src/fish_audio_sdk/schemas.py, src/fish_audio_sdk/websocket.py, src/fish_audio_sdk/__init__.py
Added from __future__ import annotations; introduced TYPE_CHECKING guards; reorganized imports; exported APICreditEntity in SDK __init__; minor import reorderings only.
Examples & Notebook
examples/getting-started/01_simple_tts.py, examples/getting_started.ipynb
Replaced os.path.getsize() with Path(...).stat().st_size and switched ospathlib.Path; notebook cell sources refactored into line arrays (no functional change).
Configuration
pyproject.toml
Added Ruff lint configuration blocks ([tool.ruff.lint], flake8-type-checking, pyupgrade settings) and retained existing uv sources.
Scripts
scripts/copy_docs.py
Added from __future__ import annotations to enable postponed evaluation of annotations; no logic change.
Utilities: I/O & Save
src/fishaudio/utils/save.py, src/fishaudio/utils/stream.py, src/fishaudio/utils/play.py
Switched file I/O to Path(...).open(...) in save; moved iterator imports to collections.abc; updated exception import paths to absolute where applicable.
Tests & Test Fixtures
tests/unit/..., tests/integration/...
Majority are import reorderings, minor refactors: replaced some explicit loops with yield from, moved pytest imports, converted mock_open usage to real tmp_path I/O, and adjusted a few test expectations to match import/API re-exports.
Public API Export Adjustment
src/fish_audio_sdk/__init__.py
Added APICreditEntity to exported symbols (__all__) and re-exported from .schemas.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through code in a flurry of hops,
Lists turned to builtins with tiny soft plops.
Imports aligned, annotations in tow,
Ruff gave a nod, and the notebooks did glow.
A carrot for tests — all tidy, all clean!

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the PR: adding Ruff linting rules and fixing violations throughout the codebase.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/formatting

No actionable comments were generated in the recent review. 🎉


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 90.38462% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/fishaudio/core/client_wrapper.py 37.50% 5 Missing ⚠️
Files with missing lines Coverage Δ
src/fishaudio/client.py 91.42% <ø> (ø)
src/fishaudio/core/iterators.py 100.00% <100.00%> (ø)
src/fishaudio/core/request_options.py 91.66% <100.00%> (ø)
src/fishaudio/core/websocket_options.py 100.00% <100.00%> (ø)
src/fishaudio/resources/account.py 92.59% <100.00%> (ø)
src/fishaudio/resources/asr.py 50.00% <100.00%> (ø)
src/fishaudio/resources/realtime.py 100.00% <100.00%> (ø)
src/fishaudio/resources/tts.py 94.78% <100.00%> (ø)
src/fishaudio/resources/voices.py 58.92% <100.00%> (+0.74%) ⬆️
src/fishaudio/types/asr.py 100.00% <100.00%> (ø)
... and 7 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a Ruff lint configuration and applies a broad set of style/type-hint cleanups across the SDK, tests, and examples to satisfy the new lint rules.

Changes:

  • Add Ruff lint rule configuration to pyproject.toml.
  • Refactor imports and type annotations (e.g., typing.Listlist, typing.Iteratorcollections.abc.Iterator, absolute imports).
  • Update a few tests/examples to comply with pathlib and simplification rules (e.g., tmp_path usage, yield from, Path(...).stat()).

Reviewed changes

Copilot reviewed 39 out of 39 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/unit/test_voices.py Import ordering/type import sorting cleanup.
tests/unit/test_utils.py Switch save() tests to use tmp_path + real filesystem reads; import cleanup.
tests/unit/test_types.py Reordered imported types to satisfy import-sorting.
tests/unit/test_tts_realtime.py Import ordering cleanup.
tests/unit/test_tts.py Import ordering cleanup.
tests/unit/test_realtime.py Import ordering + small simplification in a mock (else removal).
tests/unit/test_core.py Import ordering + combine nested context managers.
tests/unit/test_client.py Import ordering cleanup.
tests/unit/test_account.py Import ordering cleanup.
tests/unit/conftest.py Import ordering cleanup.
tests/integration/test_tts_websocket_integration.py Import ordering + yield from simplification.
tests/integration/test_account_integration.py Import ordering cleanup.
tests/integration/conftest.py Simplify bytes vs chunk-join assignment.
src/fishaudio/utils/stream.py Use collections.abc.Iterator and absolute import for exceptions.
src/fishaudio/utils/save.py Use pathlib.Path.open() (PTH) and modern typing imports.
src/fishaudio/utils/play.py Use collections.abc.Iterable and absolute import for exceptions.
src/fishaudio/types/voices.py Replace typing.List with builtin list generics.
src/fishaudio/types/tts.py Replace typing.List with builtin list generics.
src/fishaudio/types/shared.py Replace typing.List with builtin list generics.
src/fishaudio/types/asr.py Replace typing.List with builtin list generics.
src/fishaudio/resources/voices.py Type hint updates + absolute imports; introduces builtins.list[...] annotations.
src/fishaudio/resources/tts.py Typing/import refactor (collections.abc, absolute imports), minor generator simplification.
src/fishaudio/resources/realtime.py Use builtin dict[...] typing + absolute import for exceptions; minor control-flow simplification.
src/fishaudio/resources/asr.py Absolute import cleanup.
src/fishaudio/resources/account.py Absolute import cleanup.
src/fishaudio/core/websocket_options.py Dictdict typing update.
src/fishaudio/core/request_options.py Dictdict typing update.
src/fishaudio/core/iterators.py Use collections.abc iterator types.
src/fishaudio/core/client_wrapper.py Dictdict typing update + import normalization.
src/fishaudio/client.py Import ordering cleanup.
src/fish_audio_sdk/websocket.py Import ordering + collections.abc iterator types.
src/fish_audio_sdk/schemas.py Add future annotations + move some imports under TYPE_CHECKING.
src/fish_audio_sdk/io.py Add future annotations + typing/import refactor + small return simplifications.
src/fish_audio_sdk/apis.py Add future annotations + move Generator to TYPE_CHECKING.
src/fish_audio_sdk/init.py Reorder exports/imports.
scripts/copy_docs.py Add future annotations import.
pyproject.toml Add Ruff lint configuration and pyupgrade settings.
examples/getting_started.ipynb Reformat cell source to multi-line list form.
examples/getting-started/01_simple_tts.py Replace os.path.getsize with Path(...).stat() for PTH compliance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +7
import builtins
from typing import Optional, Union

from ..core import OMIT, AsyncClientWrapper, ClientWrapper, RequestOptions
from ..types import PaginatedResponse, Visibility, Voice
from fishaudio.core import OMIT, AsyncClientWrapper, ClientWrapper, RequestOptions
from fishaudio.types import PaginatedResponse, Visibility, Voice
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importing builtins just to write builtins.list[...] in type annotations is unnecessary and inconsistent with the rest of this file (which already uses list[str]). Prefer list[...] directly and drop the builtins import unless there’s a specific shadowing concern to document.

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/fish_audio_sdk/schemas.py`:
- Around line 1-9: The module currently imports datetime and decimal only under
TYPE_CHECKING which leaves those names absent at runtime and breaks Pydantic
model resolution (with from __future__ import annotations present); move the
imports for datetime and decimal out of the TYPE_CHECKING guard so they are
available at runtime (ensure module-level imports of datetime and decimal are
present) so classes like ModelEntity and APICreditEntity can resolve
datetime.datetime and decimal.Decimal when Pydantic evaluates annotations.

In `@tests/unit/test_core.py`:
- Around line 104-108: The test uses a parenthesized multi-context with
(patch.dict(...), pytest.raises(...)) which is only valid in Python 3.10+;
update the test to use nested with statements so it remains Python 3.9
compatible: open a with patch.dict("os.environ", {}, clear=True): block and
inside it open a with pytest.raises(ValueError, match="API key must be
provided"): block, then call ClientWrapper() within the inner block.
🧹 Nitpick comments (8)
src/fishaudio/utils/save.py (1)

5-5: Consider using UnionX | Y syntax with from __future__ import annotations.

The broader PR adds from __future__ import annotations across the codebase. This file could follow suit, allowing bytes | Iterable[bytes] instead of Union[bytes, Iterable[bytes]] and dropping the Union import.

♻️ Proposed refactor
+from __future__ import annotations
+
 from collections.abc import Iterable
 from pathlib import Path
-from typing import Union
 
 
-def save(audio: Union[bytes, Iterable[bytes]], filename: str) -> None:
+def save(audio: bytes | Iterable[bytes], filename: str) -> None:
src/fishaudio/utils/play.py (2)

5-8: Import modernization looks good, but Union is still used.

The PR modernizes typing imports across the codebase (including from __future__ import annotations in other files). Consider adding from __future__ import annotations here too and replacing Union[bytes, Iterable[bytes]] on line 21 with bytes | Iterable[bytes], which would also let you drop the Union import on line 6.

♻️ Suggested diff
+from __future__ import annotations
+
 """Audio playback utility."""
 
 import io
 import subprocess
 from collections.abc import Iterable
-from typing import Union
 
 from fishaudio.exceptions import DependencyError

And on line 21:

-    audio: Union[bytes, Iterable[bytes]],
+    audio: bytes | Iterable[bytes],

11-17: _is_installed is duplicated in stream.py.

Both play.py and stream.py define an identical _is_installed helper. Consider extracting it to a shared location (e.g., fishaudio/utils/__init__.py or a small _common.py module) to reduce duplication.

src/fishaudio/utils/stream.py (1)

66-72: Pre-existing: repeated bytes concatenation is O(n²).

audio_buffer += chunk copies the entire buffer on each iteration. For large audio streams this can be slow. A bytearray or list of chunks joined at the end would be more efficient. Not introduced by this PR, so just a heads-up.

♻️ Suggested improvement
-    audio_buffer = b""
+    chunks: list[bytes] = []
     try:
         for chunk in audio_stream:
             if chunk and mpv_process.stdin:
                 mpv_process.stdin.write(chunk)
                 mpv_process.stdin.flush()
-                audio_buffer += chunk
+                chunks.append(chunk)
     finally:
         # Cleanup
         if mpv_process.stdin:
             mpv_process.stdin.close()
         mpv_process.wait()
 
-    return audio_buffer
+    return b"".join(chunks)
src/fishaudio/resources/tts.py (1)

11-32: Inconsistent import style: absolute imports for cross-package, relative for same-package.

Lines 11–17 use absolute imports (from fishaudio.core ..., from fishaudio.types ...), but line 32 still uses a relative import (from .realtime ...). This is a common and defensible pattern (absolute for cross-package, relative for intra-package), but if the intent of this PR is to standardize on absolute imports, consider making it consistent.

Optional: switch to absolute import
-from .realtime import aiter_websocket_audio, iter_websocket_audio
+from fishaudio.resources.realtime import aiter_websocket_audio, iter_websocket_audio
tests/unit/test_tts.py (1)

403-421: Pre-existing: list() wrapping convert() return value is misleading.

tts_client.convert(...) returns bytes. Wrapping it in list() produces a list of integers (byte values), which is likely unintentional. The test still passes because it only inspects the mock's call_args, but the list() call is confusing. Not introduced by this PR, so no action needed now.

Optional cleanup
-        list(
-            tts_client.convert(text="Hello", format="wav", speed=1.3, latency="normal")
-        )
+        tts_client.convert(text="Hello", format="wav", speed=1.3, latency="normal")
src/fishaudio/core/request_options.py (1)

3-25: Ensure Python 3.9+ is the minimum supported version.

dict[str, str] as a runtime type annotation (without from __future__ import annotations) requires Python 3.9+. This is consistent with the broader modernization in this PR, but worth confirming. Also, consider adding from __future__ import annotations here for consistency with other files in the PR (e.g., src/fish_audio_sdk/apis.py), which would also allow replacing Optional[...] with ... | None.

src/fishaudio/core/client_wrapper.py (1)

63-76: Runtime dict[str, str] without from __future__ import annotations.

Same note as request_options.pydict[str, str] and dict[str, Any] as runtime annotations require Python 3.9+. Consider adding from __future__ import annotations for consistency with src/fish_audio_sdk/apis.py, or confirm the project targets 3.9+.

@twangodev twangodev merged commit a4a7a24 into main Feb 13, 2026
26 checks passed
@twangodev twangodev deleted the fix/formatting branch February 13, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant