diff --git a/README.md b/README.md index d01c372..b542a10 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Run a model in a few lines. Python API: ```python -from moderators.auto_model import AutoModerator +from moderators import AutoModerator # Load from the Hugging Face Hub (e.g., NSFW image classifier) moderator = AutoModerator.from_pretrained("viddexa/nsfw-mini") @@ -101,7 +101,7 @@ JSON shape (CLI output): Tip (Python): ```python from dataclasses import asdict -from moderators.auto_model import AutoModerator +from moderators import AutoModerator moderator = AutoModerator.from_pretrained("viddexa/nsfw-mini") result = moderator("/path/to/image.jpg") diff --git a/examples/README.md b/examples/README.md index 831430d..894a754 100644 --- a/examples/README.md +++ b/examples/README.md @@ -18,10 +18,10 @@ uv add moderators ## Quickstart (Image, Python) ```python -from moderators.auto_model import AutoModerator +from moderators import AutoModerator # NSFW image classification model from the Hub -moderator = AutoModerator.from_pretrained("viddexa/nsfw-mini") +moderator = AutoModerator.from_pretrained("viddexa/nsfw-detector-mini") # Run on a local image path result = moderator("/path/to/image.jpg") @@ -30,7 +30,7 @@ print(result) ## Quickstart (Image, CLI) ```bash -moderators viddexa/nsfw-mini /path/to/image.jpg +moderators viddexa/nsfw-detector-mini /path/to/image.jpg ``` Tip: Add `--local-files-only` to force offline usage if the files are already cached. @@ -40,10 +40,10 @@ Process a directory of images and print the top result per file. ```python from pathlib import Path -from moderators.auto_model import AutoModerator +from moderators import AutoModerator images_dir = Path("/path/to/images") -model = AutoModerator.from_pretrained("viddexa/nsfw-mini") +model = AutoModerator.from_pretrained("viddexa/nsfw-detector-mini") for img_path in images_dir.glob("**/*"): if img_path.suffix.lower() in {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".gif", ".avif"}: @@ -56,7 +56,7 @@ You can also load a text classifier. Python: ```python -from moderators.auto_model import AutoModerator +from moderators import AutoModerator text_model = AutoModerator.from_pretrained("distilbert/distilbert-base-uncased-finetuned-sst-2-english") print(text_model("I love this!")) @@ -78,13 +78,13 @@ python examples/benchmarks.py [--warmup N] [--repeats N] Examples: ```bash # Default backend (auto-detected) -python examples/benchmarks.py viddexa/nsfw-mini /path/to/image.jpg --warmup 3 --repeats 20 +python examples/benchmarks.py viddexa/nsfw-detector-mini /path/to/image.jpg --warmup 3 --repeats 20 ``` Expected output (sample): ``` -Model: viddexa/nsfw-mini +Model: viddexa/nsfw-detector-mini Backend: auto Runs: 20, avg: 12.34 ms, p50: 11.80 ms, p90: 14.10 ms ``` diff --git a/examples/benchmarks.py b/examples/benchmarks.py index 67c289b..525fae9 100644 --- a/examples/benchmarks.py +++ b/examples/benchmarks.py @@ -4,7 +4,7 @@ import statistics import time -from moderators.auto_model import AutoModerator +from moderators import AutoModerator def summarize(times: list[float]) -> dict[str, float]: diff --git a/pyproject.toml b/pyproject.toml index 50b09fd..3fb9076 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,10 +43,10 @@ packages = ["src/moderators"] [tool.ruff] line-length = 120 -target-version = "py310" +target-version = "py39" [tool.ruff.lint] -extend-select = ["I", "D", "UP"] +extend-select = ["F", "I", "D", "UP", "RUF", "FA"] ignore = [ "D100", # Missing docstring in public module "D104", # Missing docstring in public package @@ -58,6 +58,9 @@ ignore = [ "D406", # Section name should end with a newline "D407", # Missing dashed underline after section "D413", # Missing blank line after last section + "RUF001", # Ambiguous Unicode characters in strings + "RUF002", # Ambiguous Unicode characters in docstrings + "RUF012", # Mutable default values in class attributes ] [tool.ruff.lint.per-file-ignores] diff --git a/src/moderators/__init__.py b/src/moderators/__init__.py index 3dc1f76..57e4d35 100644 --- a/src/moderators/__init__.py +++ b/src/moderators/__init__.py @@ -1 +1,5 @@ -__version__ = "0.1.0" +__version__ = "0.1.1" + +from .auto_model import AutoModerator + +__all__ = ["AutoModerator"] diff --git a/src/moderators/cli.py b/src/moderators/cli.py index 3fbb040..80ef629 100644 --- a/src/moderators/cli.py +++ b/src/moderators/cli.py @@ -3,7 +3,7 @@ import json from dataclasses import asdict, is_dataclass -from moderators.auto_model import AutoModerator +from moderators import AutoModerator def _to_jsonable(obj): diff --git a/src/moderators/utils/__init__.py b/src/moderators/utils/__init__.py index 6d548d1..ba1886a 100644 --- a/src/moderators/utils/__init__.py +++ b/src/moderators/utils/__init__.py @@ -4,8 +4,8 @@ __all__ = [ "auto_install", - "ensure_transformers", "ensure_dl_framework", "ensure_pillow_for_task", + "ensure_transformers", "preprocess_image_input", ] diff --git a/src/moderators/utils/deps.py b/src/moderators/utils/deps.py index ac3faf0..c392459 100644 --- a/src/moderators/utils/deps.py +++ b/src/moderators/utils/deps.py @@ -29,7 +29,7 @@ def auto_install(packages: list[str]) -> bool: def ensure_transformers(install_fn: Callable[[list[str]], bool]): """Ensure 'transformers' is importable; optionally auto-install and retry.""" try: - import transformers as _transformers # noqa: F401 + import transformers as _transformers return _transformers except Exception: @@ -48,7 +48,7 @@ def ensure_dl_framework(install_fn: Callable[[list[str]], bool]) -> str: Tries to auto-install torch first. """ try: - import torch # noqa: F401 + import torch return "pt" except Exception: @@ -81,7 +81,7 @@ def ensure_pillow_for_task(task: str, install_fn: Callable[[list[str]], bool]) - if "image" not in str(task).lower(): return try: - import PIL # noqa: F401 + import PIL except Exception: if not install_fn(["Pillow"]): raise ImportError("This image task requires Pillow. Install with: uv pip install Pillow") diff --git a/src/moderators/utils/image.py b/src/moderators/utils/image.py index fc35536..8e30fba 100644 --- a/src/moderators/utils/image.py +++ b/src/moderators/utils/image.py @@ -44,8 +44,8 @@ def _process(obj: Any): w, h = img.size if w < min_side or h < min_side: scale = max(min_side / w, min_side / h) - new_w = int(round(w * scale)) - new_h = int(round(h * scale)) + new_w = round(w * scale) + new_h = round(h * scale) resample = getattr(getattr(Image, "Resampling", Image), "BILINEAR") img = img.resize((new_w, new_h), resample) except Exception: diff --git a/tests/test_auto_model.py b/tests/test_auto_model.py index d7e152e..e0984f6 100644 --- a/tests/test_auto_model.py +++ b/tests/test_auto_model.py @@ -4,7 +4,7 @@ import pytest -from moderators.auto_model import AutoModerator +from moderators import AutoModerator from moderators.integrations.base import PredictionResult from moderators.integrations.transformers_moderator import TransformersModerator diff --git a/tests/test_push_to_hub.py b/tests/test_push_to_hub.py index 685a898..7f45eb6 100644 --- a/tests/test_push_to_hub.py +++ b/tests/test_push_to_hub.py @@ -1,7 +1,7 @@ import json from pathlib import Path -from moderators.auto_model import AutoModerator +from moderators import AutoModerator class _FakeTempDir: @@ -14,7 +14,7 @@ def __enter__(self): return self.name def __exit__(self, exc_type, exc, tb): - # Klasörü bilerek silmiyoruz; test sonrasında pytest tmp cleanup zaten yapar. + # Intentionally not deleting folder; pytest tmp cleanup handles it after tests. return False @@ -25,7 +25,7 @@ def write_config(tmp_path: Path, data: dict) -> Path: def test_push_to_hub_offline(tmp_path, monkeypatch, fake_transformers): - # Ağ ve ağır bağımlılıkları devre dışı bırak + # Disable network and heavy dependencies monkeypatch.setenv("MODERATORS_DISABLE_AUTO_INSTALL", "1") monkeypatch.setattr( "moderators.integrations.transformers_moderator.ensure_dl_framework", @@ -56,35 +56,35 @@ def upload_folder(self, repo_id, repo_type, folder_path, commit_message=None, to } return {"ok": True} - # Doğru namespace: hub_mixin içindeki HfApi sembolünü patch'le + # Correct namespace: patch the HfApi symbol in hub_mixin monkeypatch.setattr( "huggingface_hub.hub_mixin.HfApi", lambda *a, **k: FakeApi(), raising=True, ) - # Geçici klasörün silinmesini engelle: SoftTemporaryDirectory'yi patch'le + # Prevent deletion of temp folder: patch SoftTemporaryDirectory monkeypatch.setattr( "huggingface_hub.hub_mixin.SoftTemporaryDirectory", lambda *a, **k: _FakeTempDir(prefix="moderators_push_"), raising=True, ) - # Yerel bir TransformersModerator konfigürasyonu ile yükle + # Load with a local TransformersModerator configuration model_dir = write_config(tmp_path, {"architecture": "TransformersModerator", "task": "text-classification"}) mod = AutoModerator.from_pretrained(str(model_dir)) - # push_to_hub çağrısı (ağ yok, FakeApi çalışacak) + # push_to_hub call (no network, FakeApi will run) repo_id = "user/repo-for-tests" mod.push_to_hub(repo_id, commit_message="test commit", token="fake-token") - # upload_folder çağrıldı mı? + # Was upload_folder called? assert "upload_folder" in calls up = calls["upload_folder"] folder_path = Path(up["folder_path"]) assert folder_path.exists() - # Kaydedilen config.json doğrula + # Verify saved config.json cfg = json.loads((folder_path / "config.json").read_text(encoding="utf-8")) assert cfg.get("architecture") == "TransformersModerator" assert cfg.get("task") == "text-classification"