diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2f762555c5..025f9e4ccd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,9 +16,6 @@ "python.analysis.extraPaths": [ "/workspace" ], - "python.linting.mypyArgs": [ - "--cache-dir=.mypy_cache" - ], "python.analysis.typeCheckingMode": "basic", "python.analysis.diagnosticMode": "openFilesOnly", "python.analysis.autoSearchPaths": false, @@ -52,7 +49,7 @@ "**/dist/**": true, "**/pyrit/auxiliary_attacks/gcg/attack/**": true, "**/doc/**": true, - "**/.mypy_cache/**": true, + "**/.ty_cache/**": true, "**/frontend/node_modules/**": true, "**/frontend/dist/**": true, "**/dbdata/**": true diff --git a/.devcontainer/devcontainer_setup.sh b/.devcontainer/devcontainer_setup.sh index bb3512044f..f043dda6cb 100644 --- a/.devcontainer/devcontainer_setup.sh +++ b/.devcontainer/devcontainer_setup.sh @@ -1,31 +1,7 @@ #!/bin/bash set -e -MYPY_CACHE="/workspace/.mypy_cache" VIRTUAL_ENV="/opt/venv" -# Create the mypy cache directory if it doesn't exist -if [ ! -d "$MYPY_CACHE" ]; then - echo "Creating mypy cache directory..." - sudo mkdir -p $MYPY_CACHE - sudo chown vscode:vscode $MYPY_CACHE - sudo chmod 755 $MYPY_CACHE -else - # Check ownership - OWNER=$(stat -c '%U:%G' $MYPY_CACHE) - - if [ "$OWNER" != "vscode:vscode" ]; then - echo "Fixing mypy cache directory ownership..." - sudo chown -R vscode:vscode $MYPY_CACHE - fi - - # Check permissions - PERMS=$(stat -c '%a' $MYPY_CACHE) - - if [ "$PERMS" != "755" ]; then - echo "Fixing mypy cache directory permissions..." - sudo chmod -R 755 $MYPY_CACHE - fi -fi # cleanup old extensions sudo rm -rf /vscode/vscode-server/extensionsCache/github.copilot-* diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 7fc115bb25..17eb691333 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -13,7 +13,7 @@ services: - pip-cache:/home/vscode/.cache/pip:cached - uv-cache:/home/vscode/.cache/uv:cached - precommit-cache:/home/vscode/.cache/pre-commit:cached - - mypy-cache:/workspace/.mypy_cache:cached + - ty-cache:/workspace/.ty_cache:cached - pylance-cache:/home/vscode/.cache/pylance:cached - node-modules:/workspace/frontend/node_modules:cached - ~/.pyrit:/home/vscode/.pyrit:cached @@ -27,6 +27,6 @@ volumes: pip-cache: uv-cache: precommit-cache: - mypy-cache: + ty-cache: pylance-cache: node-modules: diff --git a/.dockerignore b/.dockerignore index d3fe487853..9e2100d2d5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -14,7 +14,7 @@ build/ **/*.py[cod] **/*$py.class **/.pytest_cache/ -**/.mypy_cache/ +**/.ty_cache/ # Environment files with secrets .env diff --git a/.gitignore b/.gitignore index f2e242c8b4..76e6c89da3 100644 --- a/.gitignore +++ b/.gitignore @@ -149,11 +149,6 @@ env-test # mkdocs documentation /site -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - # Pyre type checker .pyre/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 456eecafd5..8342a80b84 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -79,14 +79,11 @@ repos: additional_dependencies: ['requests'] exclude: (release_process.md|git.md|^doc/deployment/|tests|pyrit/prompt_converter/morse_converter.py|.github|pyrit/prompt_converter/emoji_converter.py|pyrit/score/markdown_injection.py|^pyrit/datasets/|^pyrit/auxiliary_attacks/gcg/) - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.15.0 + - repo: https://github.com/allganize/ty-pre-commit + rev: v0.0.32 hooks: - - id: mypy - name: mypy (strict) - files: &strict_modules ^pyrit/ + - id: ty-check + name: ty (type check) + files: ^pyrit/ exclude: ^pyrit/auxiliary_attacks/ - args: [--install-types, --non-interactive, --ignore-missing-imports, --sqlite-cache, --cache-dir=.mypy_cache, --strict] - entry: mypy - language: system - types: [ python ] + types: [python] diff --git a/Makefile b/Makefile index 8a0c1a4c93..f8b193bb76 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all pre-commit mypy unit-test unit-test-junit unit-test-cov-html unit-test-cov-xml diff-cover unit-test-diff-cover +.PHONY: all pre-commit ty unit-test unit-test-junit unit-test-cov-html unit-test-cov-xml diff-cover unit-test-diff-cover CMD:=uv run -m PYMODULE:=pyrit @@ -14,8 +14,8 @@ pre-commit: $(CMD) isort --multi-line 3 --recursive $(PYMODULE) $(TESTS) pre-commit run --all-files -mypy: - $(CMD) mypy $(PYMODULE) $(UNIT_TESTS) +ty: + $(CMD) ty check $(PYMODULE) $(UNIT_TESTS) # Build the full documentation site: # 1. Generate API reference JSON from Python source (griffe) diff --git a/doc/getting_started/install_local_dev.md b/doc/getting_started/install_local_dev.md index 9cbf51c2fb..fbf9526aaf 100644 --- a/doc/getting_started/install_local_dev.md +++ b/doc/getting_started/install_local_dev.md @@ -172,7 +172,7 @@ uv run ruff check --fix . #### Running Type Checker ```bash -uv run mypy pyrit/ +uv run ty check pyrit/ ``` #### Pre-commit Hooks @@ -188,7 +188,7 @@ If you prefer conda for environment management, you can use it to create a Pytho ### Prerequisites -1. **Conda or Miniconda**: Download from [https://docs.conda.io/en/latest/miniconda.html](https://docs.conda.io/en/latest/miniconda.html) +1. **Conda or Miniconda**: Download from [https://docs.anaconda.com/free/miniconda/](https://docs.anaconda.com/free/miniconda/) 2. **Git**: Clone the repository: ```bash diff --git a/pyproject.toml b/pyproject.toml index e0b7619961..660da58869 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ dev = [ "jupyter-book>=2.0.0", "jupytext>=1.17.1", "matplotlib>=3.10.0", - "mypy>=1.16.0", + "ty>=0.0.32", "mock-alchemy>=0.2.6", "pandas>=2.2.0", "pre-commit>=4.2.0", @@ -167,17 +167,33 @@ pythonpath = ["."] asyncio_default_fixture_loop_scope = "function" asyncio_mode = "auto" -[tool.mypy] -plugins = [] -ignore_missing_imports = true -strict = true -follow_imports = "silent" -disable_error_code = ["empty-body"] +[tool.ty] +[tool.ty.rules] +all = "error" +# Suppress errors for missing third-party stubs +unresolved-import = "ignore" +# Tolerate None attribute access +possibly-missing-attribute = "ignore" +# Allow existing type: ignore comments without matching errors +unused-ignore-comment = "warn" +unused-type-ignore-comment = "warn" +# Allow empty function bodies during development +empty-body = "ignore" + +[tool.ty.analysis] +respect-type-ignore-comments = true +# Treat colorama as Any — it has no type stubs and uses a dynamic pattern +# (class attrs are int, __init__ converts to str via setattr) that ty can't follow +replace-imports-with-any = ["colorama.**"] + +[tool.ty.src] exclude = ["doc/code/", "pyrit/auxiliary_attacks/"] -[[tool.mypy.overrides]] -module = "pyrit.prompt_target.hugging_face.*" -disallow_untyped_calls = false +# Relax type checking for HuggingFace module +[[tool.ty.overrides]] +include = ["pyrit/prompt_target/hugging_face/**"] +[tool.ty.overrides.rules] +invalid-argument-type = "warn" [tool.uv] constraint-dependencies = [ @@ -297,8 +313,10 @@ select = [ "UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up "W", # https://docs.astral.sh/ruff/rules/#pycodestyle-w "YTT", # https://docs.astral.sh/ruff/rules/#flake8-2020-ytt + "ANN", # https://docs.astral.sh/ruff/rules/#flake8-annotations-ann ] ignore = [ + "ANN401", # any-type (too strict — many legitimate uses of Any) "B903", # class-as-data-structure (test helper classes use @apply_defaults pattern) "D100", # Missing docstring in public module "D200", # One-line docstring should fit on one line @@ -331,12 +349,12 @@ notice-rgx = "Copyright \\(c\\) Microsoft Corporation\\.\\s*\\n.*Licensed under # Ignore copyright, import-location (E402), line length (E501), type-checking, and blanket type-ignore (PGH003) rules in doc/ directory # E402: notebooks have imports in code cells, not at top of file # E501: markdown comments in notebooks can exceed line length -# PGH003: blanket type: ignore in notebooks (not mypy-checked) +# PGH003: blanket type: ignore in notebooks (not type-checked) # A: notebook code commonly uses builtins like id, dir, display # ERA001: jupytext markdown cells look like commented-out code # LOG: notebooks use root logger for convenience # PLE1142: top-level await is valid in Jupyter notebooks -"doc/**" = ["CPY001", "TCH", "E402", "E501", "PGH003", "A", "ERA001", "LOG", "PLE1142"] +"doc/**" = ["ANN", "CPY001", "TCH", "E402", "E501", "PGH003", "A", "ERA001", "LOG", "PLE1142"] "pyrit/{auxiliary_attacks,ui}/**/*.py" = ["B905", "D101", "D102", "D103", "D104", "D105", "D106", "D107", "D401", "D404", "D417", "D418", "DOC102", "DOC201", "DOC202", "DOC402", "DOC501", "N", "PERF", "SIM101", "SIM108"] # Backend API routes raise HTTPException handled by FastAPI, not true exceptions "pyrit/backend/**/*.py" = ["DOC501", "B008"] @@ -346,7 +364,11 @@ notice-rgx = "Copyright \\(c\\) Microsoft Corporation\\.\\s*\\n.*Licensed under "pyrit/ui/**/*.py" = ["D", "DOC201", "DOC501"] "pyrit/__init__.py" = ["D104"] # Allow broad pytest.raises(Exception) in tests -"tests/**/*.py" = ["B017"] +"tests/**/*.py" = ["ANN", "B017"] +# Infrastructure/utility scripts — not part of the library API +"build_scripts/**/*.py" = ["ANN"] +"docker/**/*.py" = ["ANN"] +"frontend/dev.py" = ["ANN"] [tool.ruff.lint.pydocstyle] convention = "google" diff --git a/pyrightconfig.json b/pyrightconfig.json index 669d368a92..8aa821faed 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -9,7 +9,6 @@ "**/dist", ".venv", "pyrit.egg-info", - ".mypy_cache", ".pytest_cache" ], "reportMissingImports": true diff --git a/pyrit/analytics/conversation_analytics.py b/pyrit/analytics/conversation_analytics.py index 14c0cda697..3440ddce60 100644 --- a/pyrit/analytics/conversation_analytics.py +++ b/pyrit/analytics/conversation_analytics.py @@ -16,7 +16,7 @@ class ConversationAnalytics: based on conversation history or embedding similarity. """ - def __init__(self, *, memory_interface: MemoryInterface): + def __init__(self, *, memory_interface: MemoryInterface) -> None: """ Initialize the ConversationAnalytics with a memory interface for data access. @@ -86,7 +86,7 @@ def get_similar_chat_messages_by_embedding( return similar_messages -def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float: # type: ignore[type-arg, unused-ignore] +def cosine_similarity(a: np.ndarray, b: np.ndarray) -> float: """ Calculate the cosine similarity between two 1D vectors. diff --git a/pyrit/auth/azure_auth.py b/pyrit/auth/azure_auth.py index 2f26801f3e..31b267230c 100644 --- a/pyrit/auth/azure_auth.py +++ b/pyrit/auth/azure_auth.py @@ -158,7 +158,7 @@ async def async_token_provider() -> str: """ result = api_key() if inspect.isawaitable(result): - return await result + return await result # type: ignore[ty:invalid-return-type] return result return async_token_provider @@ -172,7 +172,7 @@ class AzureAuth(Authenticator): access_token: AccessToken _token_scope: str - def __init__(self, token_scope: str, tenant_id: str = ""): + def __init__(self, token_scope: str, tenant_id: str = "") -> None: """ Initialize Azure authentication. @@ -326,7 +326,7 @@ def get_azure_token_provider(scope: str) -> Callable[[], str]: raise -def get_azure_async_token_provider(scope: str): # type: ignore[no-untyped-def] +def get_azure_async_token_provider(scope: str) -> Callable[[], Awaitable[str]]: """ Get an asynchronous Azure token provider using AsyncDefaultAzureCredential. @@ -370,7 +370,7 @@ def get_default_azure_scope(endpoint: str) -> str: return "https://cognitiveservices.azure.com/.default" -def get_azure_openai_auth(endpoint: str): # type: ignore[no-untyped-def] +def get_azure_openai_auth(endpoint: str) -> Callable[[], Awaitable[str]]: """ Get an async Azure token provider for OpenAI endpoints. diff --git a/pyrit/auth/azure_storage_auth.py b/pyrit/auth/azure_storage_auth.py index 4c206f439b..1d3b0fa956 100644 --- a/pyrit/auth/azure_storage_auth.py +++ b/pyrit/auth/azure_storage_auth.py @@ -86,11 +86,11 @@ async def get_sas_token(container_url: str) -> str: account_name=storage_account_name, container_name=container_name, user_delegation_key=user_delegation_key, - permission=ContainerSasPermissions(read=True, write=True, create=True, list=True, delete=True), # type: ignore[no-untyped-call, unused-ignore] + permission=ContainerSasPermissions(read=True, write=True, create=True, list=True, delete=True), expiry=expiry_time, start=start_time, ) finally: await credential.close() - return sas_token # type: ignore[return-value, no-any-return, unused-ignore] + return sas_token diff --git a/pyrit/auth/copilot_authenticator.py b/pyrit/auth/copilot_authenticator.py index d0ccff4058..d79cc901bb 100644 --- a/pyrit/auth/copilot_authenticator.py +++ b/pyrit/auth/copilot_authenticator.py @@ -56,7 +56,7 @@ def __init__( token_capture_timeout_seconds: int = DEFAULT_TOKEN_CAPTURE_TIMEOUT, network_retries: int = DEFAULT_NETWORK_RETRIES, fallback_to_plaintext: bool = False, - ): + ) -> None: """ Initialize the CopilotAuthenticator. @@ -233,7 +233,7 @@ async def _get_cached_token_if_available_and_valid(self) -> Optional[dict[str, A minutes_left = (expiry_time - current_time).total_seconds() / 60 logger.info(f"Cached token is valid for another {minutes_left:.2f} minutes") - return token_data # type: ignore[no-any-return] + return token_data except Exception as e: error_name = type(e).__name__ @@ -474,8 +474,8 @@ async def response_handler(response: Any) -> None: finally: logger.info("Gracefully closing Playwright browser instance...") - if page: - await page.close() + if page: # type: ignore[ty:possibly-unresolved-reference] + await page.close() # type: ignore[ty:possibly-unresolved-reference] if context: await context.close() if browser: diff --git a/pyrit/backend/mappers/attack_mappers.py b/pyrit/backend/mappers/attack_mappers.py index 67b9e7931b..e9bc1e6b75 100644 --- a/pyrit/backend/mappers/attack_mappers.py +++ b/pyrit/backend/mappers/attack_mappers.py @@ -108,7 +108,7 @@ async def _get_sas_for_container_async(*, container_url: str) -> str: account_name=storage_account_name, container_name=container_name, user_delegation_key=delegation_key, - permission=ContainerSasPermissions(read=True), # type: ignore[no-untyped-call,unused-ignore] + permission=ContainerSasPermissions(read=True), expiry=expiry_time, start=start_time, ) diff --git a/pyrit/backend/middleware/error_handlers.py b/pyrit/backend/middleware/error_handlers.py index 743774c230..c263cdfc4d 100644 --- a/pyrit/backend/middleware/error_handlers.py +++ b/pyrit/backend/middleware/error_handlers.py @@ -38,7 +38,7 @@ async def validation_exception_handler( field=field_path, message=error["msg"], code=error["type"], - ) # type: ignore[call-arg] + ) ) problem = ProblemDetail( @@ -72,7 +72,7 @@ async def value_error_handler( status=status.HTTP_400_BAD_REQUEST, detail=str(exc), instance=str(request.url.path), - ) # type: ignore[call-arg] + ) return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, @@ -96,7 +96,7 @@ async def not_found_handler( status=status.HTTP_404_NOT_FOUND, detail=str(exc), instance=str(request.url.path), - ) # type: ignore[call-arg] + ) return JSONResponse( status_code=status.HTTP_404_NOT_FOUND, @@ -120,7 +120,7 @@ async def permission_error_handler( status=status.HTTP_403_FORBIDDEN, detail=str(exc), instance=str(request.url.path), - ) # type: ignore[call-arg] + ) return JSONResponse( status_code=status.HTTP_403_FORBIDDEN, @@ -144,7 +144,7 @@ async def not_implemented_handler( status=status.HTTP_501_NOT_IMPLEMENTED, detail=str(exc) or "This feature is not yet implemented", instance=str(request.url.path), - ) # type: ignore[call-arg] + ) return JSONResponse( status_code=status.HTTP_501_NOT_IMPLEMENTED, @@ -175,7 +175,7 @@ async def generic_exception_handler( status=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="An unexpected error occurred", instance=str(request.url.path), - ) # type: ignore[call-arg] + ) return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, diff --git a/pyrit/backend/services/converter_service.py b/pyrit/backend/services/converter_service.py index 592b21a147..b90887cb4d 100644 --- a/pyrit/backend/services/converter_service.py +++ b/pyrit/backend/services/converter_service.py @@ -119,7 +119,7 @@ def _parse_arg_descriptions(converter_class: type) -> dict[str, str]: Returns: dict[str, str]: Mapping of parameter names to their descriptions. """ - doc = (converter_class.__init__.__doc__ or converter_class.__doc__ or "").strip() # type: ignore[misc] + doc = (converter_class.__init__.__doc__ or converter_class.__doc__ or "").strip() match = re.search(r"Args:\s*\n(.*?)(?:\n\s*\n|\n\s*Returns:|\n\s*Raises:|\Z)", doc, re.DOTALL) if not match: return {} @@ -142,7 +142,7 @@ def _extract_parameters(converter_class: type) -> list[ConverterParameterSchema] list[ConverterParameterSchema]: List of parameter schemas. """ try: - sig = inspect.signature(converter_class.__init__) # type: ignore[misc] + sig = inspect.signature(converter_class.__init__) except (ValueError, TypeError): return [] @@ -186,7 +186,7 @@ def _extract_parameters(converter_class: type) -> list[ConverterParameterSchema] def _is_llm_based(converter_class: type) -> bool: """Return True if the converter requires an LLM target parameter.""" try: - sig = inspect.signature(converter_class.__init__) # type: ignore[misc] + sig = inspect.signature(converter_class.__init__) except (ValueError, TypeError): return False @@ -477,7 +477,7 @@ def _coerce_params(*, converter_class: type, params: dict[str, Any]) -> dict[str Params dict with values coerced to the expected types. """ try: - sig = inspect.signature(converter_class.__init__) # type: ignore[misc] + sig = inspect.signature(converter_class.__init__) except (ValueError, TypeError) as e: raise ValueError( f"Failed to inspect __init__ signature for converter '{converter_class.__name__}': {e}" @@ -531,7 +531,7 @@ async def _persist_data_uri_params_async( Params dict with data-URI values replaced by file paths. """ try: - sig = inspect.signature(converter_class.__init__) # type: ignore[misc] + sig = inspect.signature(converter_class.__init__) except (ValueError, TypeError): return params diff --git a/pyrit/cli/_cli_args.py b/pyrit/cli/_cli_args.py index 12f6257dbb..21d2944e33 100644 --- a/pyrit/cli/_cli_args.py +++ b/pyrit/cli/_cli_args.py @@ -163,7 +163,7 @@ def _argparse_validator(validator_func: Callable[..., Any]) -> Callable[[Any], A sig = inspect.signature(validator_func) params = list(sig.parameters.keys()) if not params: - raise ValueError(f"Validator function {validator_func.__name__} must have at least one parameter") + raise ValueError(f"Validator function {validator_func.__name__} must have at least one parameter") # type: ignore[ty:unresolved-attribute] first_param = params[0] def wrapper(value: Any) -> Any: diff --git a/pyrit/cli/frontend_core.py b/pyrit/cli/frontend_core.py index aed63cb96f..f25137d001 100644 --- a/pyrit/cli/frontend_core.py +++ b/pyrit/cli/frontend_core.py @@ -52,7 +52,7 @@ HAS_TERMCOLOR = False # Create a dummy termcolor module for fallback - class termcolor: # type: ignore[no-redef] # noqa: N801 + class termcolor: # noqa: N801 """Dummy termcolor fallback for colored printing if termcolor is not installed.""" @staticmethod @@ -91,7 +91,7 @@ def __init__( initializer_names: Optional[list[Any]] = None, env_files: Optional[list[Path]] = None, log_level: Optional[int] = None, - ): + ) -> None: """ Initialize PyRIT context. @@ -501,7 +501,7 @@ async def run_scenario_async( # Scenarios here are a concrete subclass # Runtime parameters are passed to initialize_async() - scenario = scenario_class() # type: ignore[call-arg] + scenario = scenario_class() # type: ignore[ty:missing-argument] await scenario.initialize_async(**init_kwargs) result = await scenario.run_async() diff --git a/pyrit/cli/pyrit_backend.py b/pyrit/cli/pyrit_backend.py index a01bec561c..f45cc0c448 100644 --- a/pyrit/cli/pyrit_backend.py +++ b/pyrit/cli/pyrit_backend.py @@ -227,8 +227,8 @@ def main(*, args: Optional[list[str]] = None) -> int: """ # Ensure emoji and other Unicode characters don't crash on Windows consoles # that use legacy encodings like cp1252. - sys.stdout.reconfigure(errors="replace") # type: ignore[union-attr] - sys.stderr.reconfigure(errors="replace") # type: ignore[union-attr] + sys.stdout.reconfigure(errors="replace") # type: ignore[ty:unresolved-attribute] + sys.stderr.reconfigure(errors="replace") # type: ignore[ty:unresolved-attribute] try: parsed_args = parse_args(args=args) diff --git a/pyrit/common/deprecation.py b/pyrit/common/deprecation.py index 89da08bdb9..8049ff0bb8 100644 --- a/pyrit/common/deprecation.py +++ b/pyrit/common/deprecation.py @@ -26,13 +26,13 @@ def print_deprecation_message( """ # Get the qualified name for old item if callable(old_item) or isinstance(old_item, type): - old_name = f"{old_item.__module__}.{old_item.__qualname__}" + old_name = f"{old_item.__module__}.{old_item.__qualname__}" # type: ignore[ty:unresolved-attribute] else: old_name = old_item # Get the qualified name for new item if callable(new_item) or isinstance(new_item, type): - new_name = f"{new_item.__module__}.{new_item.__qualname__}" + new_name = f"{new_item.__module__}.{new_item.__qualname__}" # type: ignore[ty:unresolved-attribute] else: new_name = new_item diff --git a/pyrit/common/display_response.py b/pyrit/common/display_response.py index 6a97af39cc..2010aa4532 100644 --- a/pyrit/common/display_response.py +++ b/pyrit/common/display_response.py @@ -51,6 +51,6 @@ async def display_image_response(response_piece: MessagePiece) -> None: image = Image.open(image_stream) # Jupyter built-in display function only works in notebooks. - display(image) # type: ignore[name-defined] # noqa: F821 + display(image) # type: ignore[ty:unresolved-reference] # noqa: F821 if response_piece.response_error == "blocked": logger.info("---\nContent blocked, cannot show a response.\n---") diff --git a/pyrit/common/notebook_utils.py b/pyrit/common/notebook_utils.py index 22b3a9b939..1ea49957c1 100644 --- a/pyrit/common/notebook_utils.py +++ b/pyrit/common/notebook_utils.py @@ -13,7 +13,7 @@ def is_in_ipython_session() -> bool: bool: True if the code is running in an IPython session, False otherwise. """ try: - __IPYTHON__ # type: ignore[name-defined] # noqa: B018 + __IPYTHON__ # type: ignore[ty:unresolved-reference] # noqa: B018 return True except NameError: return False diff --git a/pyrit/common/yaml_loadable.py b/pyrit/common/yaml_loadable.py index 6ee50b38e2..a7857b7ad7 100644 --- a/pyrit/common/yaml_loadable.py +++ b/pyrit/common/yaml_loadable.py @@ -44,5 +44,5 @@ def from_yaml_file(cls: type[T], file: Union[Path | str]) -> T: # If this class provides a from_dict factory, use it; # otherwise, just instantiate directly with **yaml_data if hasattr(cls, "from_dict") and callable(getattr(cls, "from_dict")): # noqa: B009 - return cls.from_dict(yaml_data) # type: ignore[attr-defined, no-any-return] + return cls.from_dict(yaml_data) # type: ignore[ty:call-non-callable] return cls(**yaml_data) diff --git a/pyrit/datasets/seed_datasets/local/local_dataset_loader.py b/pyrit/datasets/seed_datasets/local/local_dataset_loader.py index a78491509c..643fcd9786 100644 --- a/pyrit/datasets/seed_datasets/local/local_dataset_loader.py +++ b/pyrit/datasets/seed_datasets/local/local_dataset_loader.py @@ -28,7 +28,7 @@ class _LocalDatasetLoader(SeedDatasetProvider): should_register = False - def __init__(self, *, file_path: Path): + def __init__(self, *, file_path: Path) -> None: """ Initialize the local dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/aegis_ai_content_safety_dataset.py b/pyrit/datasets/seed_datasets/remote/aegis_ai_content_safety_dataset.py index 02140438c7..df4c412fff 100644 --- a/pyrit/datasets/seed_datasets/remote/aegis_ai_content_safety_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/aegis_ai_content_safety_dataset.py @@ -92,7 +92,7 @@ def __init__( ] ] ] = None, - ): + ) -> None: """ Initialize the NVIDIA Aegis AI Content Safety Dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/aya_redteaming_dataset.py b/pyrit/datasets/seed_datasets/remote/aya_redteaming_dataset.py index b670d71472..a513b8bb34 100644 --- a/pyrit/datasets/seed_datasets/remote/aya_redteaming_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/aya_redteaming_dataset.py @@ -61,7 +61,7 @@ def __init__( ] ] = None, harm_scope: Optional[Literal["global", "local"]] = None, - ): + ) -> None: """ Initialize the Aya Red-teaming dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/babelscape_alert_dataset.py b/pyrit/datasets/seed_datasets/remote/babelscape_alert_dataset.py index 376f099786..7ab6b2b01e 100644 --- a/pyrit/datasets/seed_datasets/remote/babelscape_alert_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/babelscape_alert_dataset.py @@ -28,7 +28,7 @@ def __init__( *, source: str = "Babelscape/ALERT", category: Optional[Literal["alert", "alert_adversarial"]] = "alert_adversarial", - ): + ) -> None: """ Initialize the Babelscape ALERT dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/beaver_tails_dataset.py b/pyrit/datasets/seed_datasets/remote/beaver_tails_dataset.py index 76c8dec70c..33b08af4e8 100644 --- a/pyrit/datasets/seed_datasets/remote/beaver_tails_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/beaver_tails_dataset.py @@ -36,7 +36,7 @@ def __init__( *, split: str = "330k_train", unsafe_only: bool = True, - ): + ) -> None: """ Initialize the BeaverTails dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/cbt_bench_dataset.py b/pyrit/datasets/seed_datasets/remote/cbt_bench_dataset.py index 9356072ef9..2d8cdc1f62 100644 --- a/pyrit/datasets/seed_datasets/remote/cbt_bench_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/cbt_bench_dataset.py @@ -34,7 +34,7 @@ def __init__( source: str = "Psychotherapy-LLM/CBT-Bench", config: str = "core_fine_seed", split: str = "train", - ): + ) -> None: """ Initialize the CBT-Bench dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/ccp_sensitive_prompts_dataset.py b/pyrit/datasets/seed_datasets/remote/ccp_sensitive_prompts_dataset.py index c272a549aa..72ad749bb9 100644 --- a/pyrit/datasets/seed_datasets/remote/ccp_sensitive_prompts_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/ccp_sensitive_prompts_dataset.py @@ -25,7 +25,7 @@ def __init__( self, *, source: str = "promptfoo/CCP-sensitive-prompts", - ): + ) -> None: """ Initialize the CCP-sensitive prompts dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/comic_jailbreak_dataset.py b/pyrit/datasets/seed_datasets/remote/comic_jailbreak_dataset.py index 0d8be4be11..296f287fb2 100644 --- a/pyrit/datasets/seed_datasets/remote/comic_jailbreak_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/comic_jailbreak_dataset.py @@ -105,7 +105,7 @@ def __init__( source_type: Literal["public_url", "file"] = "public_url", templates: list[str] | None = None, max_examples: int | None = None, - ): + ) -> None: """ Initialize the ComicJailbreak dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/darkbench_dataset.py b/pyrit/datasets/seed_datasets/remote/darkbench_dataset.py index 0dbcc47ef7..ebd447be24 100644 --- a/pyrit/datasets/seed_datasets/remote/darkbench_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/darkbench_dataset.py @@ -29,7 +29,7 @@ def __init__( dataset_name: str = "apart/darkbench", config: str = "default", split: str = "train", - ): + ) -> None: """ Initialize the DarkBench dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/equitymedqa_dataset.py b/pyrit/datasets/seed_datasets/remote/equitymedqa_dataset.py index 30dad61e8d..0bc3959fe4 100644 --- a/pyrit/datasets/seed_datasets/remote/equitymedqa_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/equitymedqa_dataset.py @@ -81,7 +81,7 @@ def __init__( *, source: str = "katielink/EquityMedQA", subset_name: Literal["all"] | str | Sequence[str] = "all", - ): + ) -> None: """ Initialize the EquityMedQA dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/forbidden_questions_dataset.py b/pyrit/datasets/seed_datasets/remote/forbidden_questions_dataset.py index 334b7b46a6..a7a1a9955a 100644 --- a/pyrit/datasets/seed_datasets/remote/forbidden_questions_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/forbidden_questions_dataset.py @@ -30,7 +30,7 @@ def __init__( *, source: str = "TrustAIRLab/forbidden_question_set", split: str = "default", - ): + ) -> None: """ Initialize the Forbidden Questions dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/harmbench_dataset.py b/pyrit/datasets/seed_datasets/remote/harmbench_dataset.py index a1e59f68e1..f0de4ccc97 100644 --- a/pyrit/datasets/seed_datasets/remote/harmbench_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/harmbench_dataset.py @@ -33,7 +33,7 @@ def __init__( "harmbench_behaviors_text_all.csv" ), source_type: Literal["public_url", "file"] = "public_url", - ): + ) -> None: """ Initialize the HarmBench dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/harmbench_multimodal_dataset.py b/pyrit/datasets/seed_datasets/remote/harmbench_multimodal_dataset.py index b9b1b26768..960bb90e97 100644 --- a/pyrit/datasets/seed_datasets/remote/harmbench_multimodal_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/harmbench_multimodal_dataset.py @@ -50,7 +50,7 @@ def __init__( ), source_type: Literal["public_url", "file"] = "public_url", categories: Optional[list[SemanticCategory]] = None, - ): + ) -> None: """ Initialize the HarmBench multimodal dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/harmful_qa_dataset.py b/pyrit/datasets/seed_datasets/remote/harmful_qa_dataset.py index 00f9c830dc..9f8171ad10 100644 --- a/pyrit/datasets/seed_datasets/remote/harmful_qa_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/harmful_qa_dataset.py @@ -32,7 +32,7 @@ def __init__( self, *, split: str = "train", - ): + ) -> None: """ Initialize the HarmfulQA dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/jbb_behaviors_dataset.py b/pyrit/datasets/seed_datasets/remote/jbb_behaviors_dataset.py index 79921c3cb4..4198a0cfd6 100644 --- a/pyrit/datasets/seed_datasets/remote/jbb_behaviors_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/jbb_behaviors_dataset.py @@ -29,7 +29,7 @@ def __init__( *, source: str = "JailbreakBench/JBB-Behaviors", split: str = "behaviors", - ): + ) -> None: """ Initialize the JBB-Behaviors dataset loader. @@ -107,7 +107,7 @@ async def fetch_dataset(self, *, cache: bool = True) -> SeedDataset: "jbb_category": category, "original_source": "JailbreakBench", }, - **common_metadata, # type: ignore[arg-type] + **common_metadata, # type: ignore[ty:invalid-argument-type] ) seed_prompts.append(seed_prompt) diff --git a/pyrit/datasets/seed_datasets/remote/librai_do_not_answer_dataset.py b/pyrit/datasets/seed_datasets/remote/librai_do_not_answer_dataset.py index 66689d5ed8..28cf707ed3 100644 --- a/pyrit/datasets/seed_datasets/remote/librai_do_not_answer_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/librai_do_not_answer_dataset.py @@ -26,7 +26,7 @@ def __init__( self, *, source: str = "LibrAI/do-not-answer", - ): + ) -> None: """ Initialize the LibrAI Do Not Answer dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/llm_latent_adversarial_training_dataset.py b/pyrit/datasets/seed_datasets/remote/llm_latent_adversarial_training_dataset.py index d3897a659f..e1cffbf7c5 100644 --- a/pyrit/datasets/seed_datasets/remote/llm_latent_adversarial_training_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/llm_latent_adversarial_training_dataset.py @@ -25,7 +25,7 @@ def __init__( self, *, source: str = "LLM-LAT/harmful-dataset", - ): + ) -> None: """ Initialize the LLM-LAT harmful dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/medsafetybench_dataset.py b/pyrit/datasets/seed_datasets/remote/medsafetybench_dataset.py index ab9a56414c..34ea7334f6 100644 --- a/pyrit/datasets/seed_datasets/remote/medsafetybench_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/medsafetybench_dataset.py @@ -27,7 +27,7 @@ def __init__( self, *, subset_name: Literal["train", "test", "generated", "all"] = "all", - ): + ) -> None: """ Initialize the MedSafetyBench dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/mlcommons_ailuminate_dataset.py b/pyrit/datasets/seed_datasets/remote/mlcommons_ailuminate_dataset.py index 95fce799b3..a78c7ef6d8 100644 --- a/pyrit/datasets/seed_datasets/remote/mlcommons_ailuminate_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/mlcommons_ailuminate_dataset.py @@ -49,7 +49,7 @@ def __init__( "airr_official_1.0_demo_en_us_prompt_set_release.csv" ), source_type: Literal["public_url", "file"] = "public_url", - ): + ) -> None: """ Initialize the AILuminate dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/multilingual_vulnerability_dataset.py b/pyrit/datasets/seed_datasets/remote/multilingual_vulnerability_dataset.py index 747f8e40f4..25a3986e41 100644 --- a/pyrit/datasets/seed_datasets/remote/multilingual_vulnerability_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/multilingual_vulnerability_dataset.py @@ -26,7 +26,7 @@ def __init__( self, *, source: str = "https://raw.githubusercontent.com/CarsonDon/Multilingual-Vuln-LLMs/main/prompts/allprompt.csv", - ): + ) -> None: """ Initialize the Multilingual Vulnerability dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/pku_safe_rlhf_dataset.py b/pyrit/datasets/seed_datasets/remote/pku_safe_rlhf_dataset.py index 9138766a25..79bb0bef48 100644 --- a/pyrit/datasets/seed_datasets/remote/pku_safe_rlhf_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/pku_safe_rlhf_dataset.py @@ -53,7 +53,7 @@ def __init__( ] ] ] = None, - ): + ) -> None: """ Initialize the PKU-SafeRLHF dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/red_team_social_bias_dataset.py b/pyrit/datasets/seed_datasets/remote/red_team_social_bias_dataset.py index 5bba24bfcf..55105e2c02 100644 --- a/pyrit/datasets/seed_datasets/remote/red_team_social_bias_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/red_team_social_bias_dataset.py @@ -28,7 +28,7 @@ def __init__( self, *, source: str = "svannie678/red_team_repo_social_bias_prompts", - ): + ) -> None: """ Initialize the Red Team Social Bias dataset loader. @@ -116,7 +116,7 @@ async def fetch_dataset(self, *, cache: bool = True) -> SeedDataset: data_type="text", prompt_group_id=group_id, sequence=i, - **prompt_metadata, # type: ignore[arg-type] + **prompt_metadata, # type: ignore[ty:invalid-argument-type] ) ) else: @@ -133,7 +133,7 @@ async def fetch_dataset(self, *, cache: bool = True) -> SeedDataset: SeedPrompt( value=escaped_cleaned_value, data_type="text", - **prompt_metadata, # type: ignore[arg-type] + **prompt_metadata, # type: ignore[ty:invalid-argument-type] ) ) diff --git a/pyrit/datasets/seed_datasets/remote/salad_bench_dataset.py b/pyrit/datasets/seed_datasets/remote/salad_bench_dataset.py index 50beb07496..67b90c5e4b 100644 --- a/pyrit/datasets/seed_datasets/remote/salad_bench_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/salad_bench_dataset.py @@ -37,7 +37,7 @@ def __init__( *, config: str = "prompts", split: str = "base", - ): + ) -> None: """ Initialize the SALAD-Bench dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/simple_safety_tests_dataset.py b/pyrit/datasets/seed_datasets/remote/simple_safety_tests_dataset.py index 299e9f1997..e25c8215dd 100644 --- a/pyrit/datasets/seed_datasets/remote/simple_safety_tests_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/simple_safety_tests_dataset.py @@ -32,7 +32,7 @@ def __init__( self, *, split: str = "test", - ): + ) -> None: """ Initialize the SimpleSafetyTests dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/sorry_bench_dataset.py b/pyrit/datasets/seed_datasets/remote/sorry_bench_dataset.py index 7c6b00839a..0167d9ca39 100644 --- a/pyrit/datasets/seed_datasets/remote/sorry_bench_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/sorry_bench_dataset.py @@ -101,7 +101,7 @@ def __init__( categories: Optional[list[str]] = None, prompt_style: Optional[str] = None, token: Optional[str] = None, - ): + ) -> None: """ Initialize the Sorry-Bench dataset loader. @@ -205,7 +205,7 @@ async def fetch_dataset(self, *, cache: bool = True) -> SeedDataset: "prompt_style": item_prompt_style, "question_id": question_id, }, - **common_metadata, # type: ignore[arg-type] + **common_metadata, # type: ignore[ty:invalid-argument-type] ) seed_prompts.append(seed_prompt) diff --git a/pyrit/datasets/seed_datasets/remote/sosbench_dataset.py b/pyrit/datasets/seed_datasets/remote/sosbench_dataset.py index ca4028ce8f..1474b53882 100644 --- a/pyrit/datasets/seed_datasets/remote/sosbench_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/sosbench_dataset.py @@ -26,7 +26,7 @@ def __init__( self, *, source: str = "SOSBench/SOSBench", - ): + ) -> None: """ Initialize the SOSBench dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/tdc23_redteaming_dataset.py b/pyrit/datasets/seed_datasets/remote/tdc23_redteaming_dataset.py index f4b972c9aa..c1ffd21b8f 100644 --- a/pyrit/datasets/seed_datasets/remote/tdc23_redteaming_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/tdc23_redteaming_dataset.py @@ -26,7 +26,7 @@ def __init__( self, *, source: str = "walledai/TDC23-RedTeaming", - ): + ) -> None: """ Initialize the TDC23-RedTeaming dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/toxic_chat_dataset.py b/pyrit/datasets/seed_datasets/remote/toxic_chat_dataset.py index 78259f8f3e..5e23332a1f 100644 --- a/pyrit/datasets/seed_datasets/remote/toxic_chat_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/toxic_chat_dataset.py @@ -39,7 +39,7 @@ def __init__( *, config: str = "toxicchat0124", split: str = "train", - ): + ) -> None: """ Initialize the ToxicChat dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/transphobia_awareness_dataset.py b/pyrit/datasets/seed_datasets/remote/transphobia_awareness_dataset.py index d4ee6da434..0be21d263f 100644 --- a/pyrit/datasets/seed_datasets/remote/transphobia_awareness_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/transphobia_awareness_dataset.py @@ -38,7 +38,7 @@ class _TransphobiaAwarenessDataset(_RemoteDatasetLoader): QUESTION_RESPONSE_PAIRS_URL = "https://zenodo.org/records/15482694/files/Question_Response_Pairs.xlsx?download=1" QUORA_QUESTION_LIST_URL = "https://zenodo.org/records/15482694/files/Quora%20Question%20List.xlsx?download=1" - def __init__(self, *, source: str = RATINGS_URL): + def __init__(self, *, source: str = RATINGS_URL) -> None: """ Initialize the Transphobia-Awareness dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/vlguard_dataset.py b/pyrit/datasets/seed_datasets/remote/vlguard_dataset.py index 8dc1f5303a..2d3518a33b 100644 --- a/pyrit/datasets/seed_datasets/remote/vlguard_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/vlguard_dataset.py @@ -157,7 +157,7 @@ async def fetch_dataset(self, *, cache: bool = True) -> SeedDataset: for example in metadata: image_filename = example.get("image") - is_safe = example.get("safe") + is_safe = example.get("safe", True) category = example.get("harmful_category", "") subcategory = example.get("harmful_subcategory", "") instr_resp_raw = example.get("instr-resp") diff --git a/pyrit/datasets/seed_datasets/remote/vlsu_multimodal_dataset.py b/pyrit/datasets/seed_datasets/remote/vlsu_multimodal_dataset.py index 7ad0a1b470..773248b1a4 100644 --- a/pyrit/datasets/seed_datasets/remote/vlsu_multimodal_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/vlsu_multimodal_dataset.py @@ -58,7 +58,7 @@ def __init__( categories: Optional[list[VLSUCategory]] = None, unsafe_grades: Optional[list[str]] = None, max_examples: Optional[int] = None, - ): + ) -> None: """ Initialize the ML-VLSU multimodal dataset loader. diff --git a/pyrit/datasets/seed_datasets/remote/xstest_dataset.py b/pyrit/datasets/seed_datasets/remote/xstest_dataset.py index eb155d6ae5..6c68248c4e 100644 --- a/pyrit/datasets/seed_datasets/remote/xstest_dataset.py +++ b/pyrit/datasets/seed_datasets/remote/xstest_dataset.py @@ -26,7 +26,7 @@ def __init__( *, source: str = "https://raw.githubusercontent.com/paul-rottger/exaggerated-safety/a3bb396/xstest_v2_prompts.csv", source_type: Literal["public_url", "file"] = "public_url", - ): + ) -> None: """ Initialize the XSTest dataset loader. diff --git a/pyrit/executor/attack/component/conversation_manager.py b/pyrit/executor/attack/component/conversation_manager.py index 1104676830..51802c2a9f 100644 --- a/pyrit/executor/attack/component/conversation_manager.py +++ b/pyrit/executor/attack/component/conversation_manager.py @@ -194,7 +194,7 @@ def __init__( *, attack_identifier: ComponentIdentifier, prompt_normalizer: Optional[PromptNormalizer] = None, - ): + ) -> None: """ Initialize the conversation manager. @@ -558,7 +558,7 @@ async def _process_prepended_for_chat_target_async( if is_multi_turn and final_prepended_message.api_role == "assistant": # Update executed_turns if hasattr(context, "executed_turns"): - context.executed_turns = state.turn_count + context.executed_turns = state.turn_count # type: ignore[ty:invalid-assignment] # Extract scores on final prepended assistant message if it exists and are relavent # Multi-part messages (e.g., text + image) may have scores on multiple pieces @@ -570,7 +570,7 @@ async def _process_prepended_for_chat_target_async( state.last_assistant_message_scores.append(score) # context.last_score gets the first matching score for single-score use cases. if hasattr(context, "last_score") and context.last_score is None: - context.last_score = score + context.last_score = score # type: ignore[ty:invalid-assignment] return state diff --git a/pyrit/executor/attack/core/attack_executor.py b/pyrit/executor/attack/core/attack_executor.py index 6bbf001611..c5e3816d65 100644 --- a/pyrit/executor/attack/core/attack_executor.py +++ b/pyrit/executor/attack/core/attack_executor.py @@ -119,7 +119,7 @@ class AttackExecutor: from seed groups. """ - def __init__(self, *, max_concurrency: int = 1): + def __init__(self, *, max_concurrency: int = 1) -> None: """ Initialize the attack executor with configurable concurrency control. diff --git a/pyrit/executor/attack/core/attack_parameters.py b/pyrit/executor/attack/core/attack_parameters.py index 53bd34f6f5..f1fca0f3e5 100644 --- a/pyrit/executor/attack/core/attack_parameters.py +++ b/pyrit/executor/attack/core/attack_parameters.py @@ -246,6 +246,6 @@ async def from_seed_group_async_wrapper( c, seed_group=seed_group, adversarial_chat=adversarial_chat, objective_scorer=objective_scorer, **ov ) - new_cls.from_seed_group_async = classmethod(from_seed_group_async_wrapper) # type: ignore[attr-defined] + new_cls.from_seed_group_async = classmethod(from_seed_group_async_wrapper) # type: ignore[ty:unresolved-attribute] - return new_cls + return new_cls # type: ignore[ty:invalid-return-type] diff --git a/pyrit/executor/attack/core/attack_strategy.py b/pyrit/executor/attack/core/attack_strategy.py index dac86d10aa..fe85d6ce51 100644 --- a/pyrit/executor/attack/core/attack_strategy.py +++ b/pyrit/executor/attack/core/attack_strategy.py @@ -122,7 +122,7 @@ class _DefaultAttackStrategyEventHandler(StrategyEventHandler[AttackStrategyCont Handles events during the execution of an attack strategy. """ - def __init__(self, logger: logging.Logger = logger): + def __init__(self, logger: logging.Logger = logger) -> None: """ Initialize the default event handler with a logger. @@ -238,9 +238,9 @@ def __init__( *, objective_target: PromptTarget, context_type: type[AttackStrategyContextT], - params_type: type[AttackParamsT] = AttackParameters, # type: ignore[assignment] + params_type: type[AttackParamsT] = AttackParameters, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] logger: logging.Logger = logger, - ): + ) -> None: """ Initialize the attack strategy with a specific context type and logger. diff --git a/pyrit/executor/attack/multi_turn/chunked_request.py b/pyrit/executor/attack/multi_turn/chunked_request.py index 1a70c89195..a375a0b9cf 100644 --- a/pyrit/executor/attack/multi_turn/chunked_request.py +++ b/pyrit/executor/attack/multi_turn/chunked_request.py @@ -86,7 +86,7 @@ class ChunkedRequestAttack(MultiTurnAttackStrategy[ChunkedRequestAttackContext, def __init__( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] chunk_size: int = 50, total_length: int = 200, chunk_type: str = "characters", diff --git a/pyrit/executor/attack/multi_turn/crescendo.py b/pyrit/executor/attack/multi_turn/crescendo.py index 9625a7c455..f0395209dd 100644 --- a/pyrit/executor/attack/multi_turn/crescendo.py +++ b/pyrit/executor/attack/multi_turn/crescendo.py @@ -121,7 +121,7 @@ class CrescendoAttack(MultiTurnAttackStrategy[CrescendoAttackContext, CrescendoA def __init__( self, *, - objective_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_adversarial_config: AttackAdversarialConfig, attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, diff --git a/pyrit/executor/attack/multi_turn/multi_prompt_sending.py b/pyrit/executor/attack/multi_turn/multi_prompt_sending.py index a9d4b75adc..c7a5d18280 100644 --- a/pyrit/executor/attack/multi_turn/multi_prompt_sending.py +++ b/pyrit/executor/attack/multi_turn/multi_prompt_sending.py @@ -127,7 +127,7 @@ class MultiPromptSendingAttack(MultiTurnAttackStrategy[MultiTurnAttackContext[An def __init__( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, prompt_normalizer: Optional[PromptNormalizer] = None, diff --git a/pyrit/executor/attack/multi_turn/multi_turn_attack_strategy.py b/pyrit/executor/attack/multi_turn/multi_turn_attack_strategy.py index 04c8084f7b..657800bd72 100644 --- a/pyrit/executor/attack/multi_turn/multi_turn_attack_strategy.py +++ b/pyrit/executor/attack/multi_turn/multi_turn_attack_strategy.py @@ -75,9 +75,9 @@ def __init__( *, objective_target: PromptTarget, context_type: type[MultiTurnAttackStrategyContextT], - params_type: type[AttackParamsT] = AttackParameters, # type: ignore[assignment] + params_type: type[AttackParamsT] = AttackParameters, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] logger: logging.Logger = logger, - ): + ) -> None: """ Implement the base class for multi-turn attack strategies. diff --git a/pyrit/executor/attack/multi_turn/red_teaming.py b/pyrit/executor/attack/multi_turn/red_teaming.py index 0dd784a0f0..7ef44b906c 100644 --- a/pyrit/executor/attack/multi_turn/red_teaming.py +++ b/pyrit/executor/attack/multi_turn/red_teaming.py @@ -89,14 +89,14 @@ class RedTeamingAttack(MultiTurnAttackStrategy[MultiTurnAttackContext[Any], Atta def __init__( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_adversarial_config: AttackAdversarialConfig, attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, prompt_normalizer: Optional[PromptNormalizer] = None, max_turns: int = 10, score_last_turn_only: bool = False, - ): + ) -> None: """ Initialize the red teaming attack strategy. diff --git a/pyrit/executor/attack/multi_turn/tree_of_attacks.py b/pyrit/executor/attack/multi_turn/tree_of_attacks.py index b0dfcc3ca1..462b6aa131 100644 --- a/pyrit/executor/attack/multi_turn/tree_of_attacks.py +++ b/pyrit/executor/attack/multi_turn/tree_of_attacks.py @@ -128,7 +128,7 @@ def threshold(self) -> float: Returns: float: The threshold value from the FloatScaleThresholdScorer. """ - return self.objective_scorer.threshold + return self.objective_scorer.threshold # type: ignore[ty:unresolved-attribute] @dataclass @@ -1254,7 +1254,7 @@ class TreeOfAttacksWithPruningAttack(AttackStrategy[TAPAttackContext, TAPAttackR def __init__( self, *, - objective_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_adversarial_config: AttackAdversarialConfig, attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, @@ -1266,7 +1266,7 @@ def __init__( desired_response_prefix: str = "Sure, here is", batch_size: int = 10, prepended_conversation_config: Optional[PrependedConversationConfig] = None, - ): + ) -> None: """ Initialize the Tree of Attacks with Pruning attack strategy. @@ -1862,7 +1862,7 @@ def _create_attack_node( adversarial_chat_seed_prompt=self._adversarial_chat_seed_prompt, adversarial_chat_system_seed_prompt=self._adversarial_chat_system_seed_prompt, adversarial_chat_prompt_template=self._adversarial_chat_prompt_template, - objective_scorer=self._objective_scorer, + objective_scorer=self._objective_scorer, # type: ignore[ty:invalid-argument-type] on_topic_scorer=self._create_on_topic_scorer(context.objective), request_converters=self._request_converters, response_converters=self._response_converters, diff --git a/pyrit/executor/attack/printer/console_printer.py b/pyrit/executor/attack/printer/console_printer.py index ff1cce42f9..9822198445 100644 --- a/pyrit/executor/attack/printer/console_printer.py +++ b/pyrit/executor/attack/printer/console_printer.py @@ -23,7 +23,7 @@ class ConsoleAttackResultPrinter(AttackResultPrinter): for consoles that don't support ANSI characters. """ - def __init__(self, *, width: int = 100, indent_size: int = 2, enable_colors: bool = True): + def __init__(self, *, width: int = 100, indent_size: int = 2, enable_colors: bool = True) -> None: """ Initialize the console printer. diff --git a/pyrit/executor/attack/printer/markdown_printer.py b/pyrit/executor/attack/printer/markdown_printer.py index 5946ce985c..402f9fd0c6 100644 --- a/pyrit/executor/attack/printer/markdown_printer.py +++ b/pyrit/executor/attack/printer/markdown_printer.py @@ -18,7 +18,7 @@ class MarkdownAttackResultPrinter(AttackResultPrinter): markdown formatting that should be properly rendered. """ - def __init__(self, *, display_inline: bool = True): + def __init__(self, *, display_inline: bool = True) -> None: """ Initialize the markdown printer. @@ -46,7 +46,7 @@ def _render_markdown(self, markdown_lines: list[str]) -> None: try: from IPython.display import Markdown, display - display(Markdown(full_markdown)) # type: ignore[no-untyped-call] + display(Markdown(full_markdown)) except (ImportError, NameError): # Fallback to print if IPython is not available print(full_markdown) diff --git a/pyrit/executor/attack/single_turn/context_compliance.py b/pyrit/executor/attack/single_turn/context_compliance.py index d03ab2a41f..4656ca49eb 100644 --- a/pyrit/executor/attack/single_turn/context_compliance.py +++ b/pyrit/executor/attack/single_turn/context_compliance.py @@ -57,7 +57,7 @@ class ContextComplianceAttack(PromptSendingAttack): def __init__( self, *, - objective_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_adversarial_config: AttackAdversarialConfig, attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, diff --git a/pyrit/executor/attack/single_turn/flip_attack.py b/pyrit/executor/attack/single_turn/flip_attack.py index 959f0da087..65be5ff552 100644 --- a/pyrit/executor/attack/single_turn/flip_attack.py +++ b/pyrit/executor/attack/single_turn/flip_attack.py @@ -40,7 +40,7 @@ class FlipAttack(PromptSendingAttack): def __init__( self, *, - objective_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, prompt_normalizer: Optional[PromptNormalizer] = None, diff --git a/pyrit/executor/attack/single_turn/many_shot_jailbreak.py b/pyrit/executor/attack/single_turn/many_shot_jailbreak.py index e1231d0396..303a0638d6 100644 --- a/pyrit/executor/attack/single_turn/many_shot_jailbreak.py +++ b/pyrit/executor/attack/single_turn/many_shot_jailbreak.py @@ -65,7 +65,7 @@ class ManyShotJailbreakAttack(PromptSendingAttack): def __init__( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, prompt_normalizer: Optional[PromptNormalizer] = None, diff --git a/pyrit/executor/attack/single_turn/prompt_sending.py b/pyrit/executor/attack/single_turn/prompt_sending.py index 07f1d670fa..9fbf8caf23 100644 --- a/pyrit/executor/attack/single_turn/prompt_sending.py +++ b/pyrit/executor/attack/single_turn/prompt_sending.py @@ -54,12 +54,12 @@ class PromptSendingAttack(SingleTurnAttackStrategy): def __init__( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, prompt_normalizer: Optional[PromptNormalizer] = None, max_attempts_on_failure: int = 0, - params_type: type[AttackParamsT] = AttackParameters, # type: ignore[assignment] + params_type: type[AttackParamsT] = AttackParameters, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] prepended_conversation_config: Optional[PrependedConversationConfig] = None, ) -> None: """ diff --git a/pyrit/executor/attack/single_turn/role_play.py b/pyrit/executor/attack/single_turn/role_play.py index e0d8a8d5f5..acc742bf78 100644 --- a/pyrit/executor/attack/single_turn/role_play.py +++ b/pyrit/executor/attack/single_turn/role_play.py @@ -65,7 +65,7 @@ class RolePlayAttack(PromptSendingAttack): def __init__( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_adversarial_config: AttackAdversarialConfig, role_play_definition_path: pathlib.Path, attack_converter_config: Optional[AttackConverterConfig] = None, diff --git a/pyrit/executor/attack/single_turn/single_turn_attack_strategy.py b/pyrit/executor/attack/single_turn/single_turn_attack_strategy.py index 508f83db1c..549e08222c 100644 --- a/pyrit/executor/attack/single_turn/single_turn_attack_strategy.py +++ b/pyrit/executor/attack/single_turn/single_turn_attack_strategy.py @@ -50,9 +50,9 @@ def __init__( *, objective_target: PromptTarget, context_type: type[SingleTurnAttackContext[Any]] = SingleTurnAttackContext, - params_type: type[AttackParamsT] = AttackParameters, # type: ignore[assignment] + params_type: type[AttackParamsT] = AttackParameters, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] logger: logging.Logger = logger, - ): + ) -> None: """ Define a base class for single-turn attack strategies. diff --git a/pyrit/executor/attack/single_turn/skeleton_key.py b/pyrit/executor/attack/single_turn/skeleton_key.py index 683614dce5..052606bfd3 100644 --- a/pyrit/executor/attack/single_turn/skeleton_key.py +++ b/pyrit/executor/attack/single_turn/skeleton_key.py @@ -53,7 +53,7 @@ class SkeletonKeyAttack(PromptSendingAttack): def __init__( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] attack_converter_config: Optional[AttackConverterConfig] = None, attack_scoring_config: Optional[AttackScoringConfig] = None, prompt_normalizer: Optional[PromptNormalizer] = None, diff --git a/pyrit/executor/benchmark/fairness_bias.py b/pyrit/executor/benchmark/fairness_bias.py index 05bb424c17..77b090f33f 100644 --- a/pyrit/executor/benchmark/fairness_bias.py +++ b/pyrit/executor/benchmark/fairness_bias.py @@ -94,7 +94,7 @@ def __init__( attack_scoring_config: Optional[AttackScoringConfig] = None, prompt_normalizer: Optional[PromptNormalizer] = None, max_attempts_on_failure: int = 0, - ): + ) -> None: """ Initialize the fairness bias benchmark strategy. diff --git a/pyrit/executor/benchmark/question_answering.py b/pyrit/executor/benchmark/question_answering.py index aedb6cf062..8f2307eba9 100644 --- a/pyrit/executor/benchmark/question_answering.py +++ b/pyrit/executor/benchmark/question_answering.py @@ -91,7 +91,7 @@ def __init__( question_asking_format_string: str = _DEFAULT_QUESTION_FORMAT, options_format_string: str = _DEFAULT_OPTIONS_FORMAT, max_attempts_on_failure: int = 0, - ): + ) -> None: """ Initialize the question answering benchmark strategy. diff --git a/pyrit/executor/core/strategy.py b/pyrit/executor/core/strategy.py index f2a04f2db0..833ea1e072 100644 --- a/pyrit/executor/core/strategy.py +++ b/pyrit/executor/core/strategy.py @@ -101,7 +101,7 @@ async def on_event(self, event_data: StrategyEventData[StrategyContextT, Strateg """ -class StrategyLogAdapter(logging.LoggerAdapter): # type: ignore[type-arg] +class StrategyLogAdapter(logging.LoggerAdapter): """ Custom logger adapter that adds strategy information to log messages. """ @@ -150,7 +150,7 @@ def __init__( context_type: type[StrategyContextT], event_handler: Optional[StrategyEventHandler[StrategyContextT, StrategyResultT]] = None, logger: logging.Logger = logger, - ): + ) -> None: """ Initialize the strategy with a context type and logger. diff --git a/pyrit/executor/promptgen/core/prompt_generator_strategy.py b/pyrit/executor/promptgen/core/prompt_generator_strategy.py index 29068611ba..6caafb437d 100644 --- a/pyrit/executor/promptgen/core/prompt_generator_strategy.py +++ b/pyrit/executor/promptgen/core/prompt_generator_strategy.py @@ -39,7 +39,7 @@ class _DefaultPromptGeneratorStrategyEventHandler( Handles events during the execution of a prompt generator strategy. """ - def __init__(self, logger: logging.Logger = logger): + def __init__(self, logger: logging.Logger = logger) -> None: """ Initialize the default event handler with a logger. @@ -74,7 +74,7 @@ def __init__( event_handler: Optional[ StrategyEventHandler[PromptGeneratorStrategyContextT, PromptGeneratorStrategyResultT] ] = None, - ): + ) -> None: """ Initialize the prompt generator strategy. diff --git a/pyrit/executor/promptgen/fuzzer/fuzzer.py b/pyrit/executor/promptgen/fuzzer/fuzzer.py index 1833bb0f9a..2ebc1e4cd2 100644 --- a/pyrit/executor/promptgen/fuzzer/fuzzer.py +++ b/pyrit/executor/promptgen/fuzzer/fuzzer.py @@ -50,7 +50,7 @@ def __init__( self, template: str, parent: Optional[_PromptNode] = None, - ): + ) -> None: """ Create the PromptNode instance. @@ -93,7 +93,7 @@ def __init__( reward_penalty: float, minimum_reward: float, non_leaf_node_probability: float, - ): + ) -> None: """ Initialize the MCTS explorer. @@ -295,7 +295,7 @@ class FuzzerResultPrinter: similar to the original FuzzerAttack result display. """ - def __init__(self, *, width: int = 100, indent_size: int = 2, enable_colors: bool = True): + def __init__(self, *, width: int = 100, indent_size: int = 2, enable_colors: bool = True) -> None: """ Initialize the fuzzer result printer. diff --git a/pyrit/executor/promptgen/fuzzer/fuzzer_converter_base.py b/pyrit/executor/promptgen/fuzzer/fuzzer_converter_base.py index 4db32e65e8..4bb108128c 100644 --- a/pyrit/executor/promptgen/fuzzer/fuzzer_converter_base.py +++ b/pyrit/executor/promptgen/fuzzer/fuzzer_converter_base.py @@ -40,9 +40,9 @@ class FuzzerConverter(PromptConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] prompt_template: SeedPrompt, - ): + ) -> None: """ Initialize the converter with the specified chat target and prompt template. diff --git a/pyrit/executor/promptgen/fuzzer/fuzzer_crossover_converter.py b/pyrit/executor/promptgen/fuzzer/fuzzer_crossover_converter.py index 2f2b44f4a7..6c1b5a0140 100644 --- a/pyrit/executor/promptgen/fuzzer/fuzzer_crossover_converter.py +++ b/pyrit/executor/promptgen/fuzzer/fuzzer_crossover_converter.py @@ -28,7 +28,7 @@ def __init__( converter_target: Optional[PromptChatTarget] = None, prompt_template: Optional[SeedPrompt] = None, prompt_templates: Optional[list[str]] = None, - ): + ) -> None: """ Initialize the converter with the specified chat target and prompt templates. diff --git a/pyrit/executor/promptgen/fuzzer/fuzzer_expand_converter.py b/pyrit/executor/promptgen/fuzzer/fuzzer_expand_converter.py index ddd8c60792..b82ebad0f9 100644 --- a/pyrit/executor/promptgen/fuzzer/fuzzer_expand_converter.py +++ b/pyrit/executor/promptgen/fuzzer/fuzzer_expand_converter.py @@ -26,7 +26,7 @@ def __init__( *, converter_target: Optional[PromptChatTarget] = None, prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """Initialize the expand converter with optional chat target and prompt template.""" prompt_template = ( prompt_template diff --git a/pyrit/executor/promptgen/fuzzer/fuzzer_rephrase_converter.py b/pyrit/executor/promptgen/fuzzer/fuzzer_rephrase_converter.py index 99a001b955..a0a2e2bd1a 100644 --- a/pyrit/executor/promptgen/fuzzer/fuzzer_rephrase_converter.py +++ b/pyrit/executor/promptgen/fuzzer/fuzzer_rephrase_converter.py @@ -21,7 +21,7 @@ class FuzzerRephraseConverter(FuzzerConverter): @apply_defaults def __init__( self, *, converter_target: Optional[PromptChatTarget] = None, prompt_template: Optional[SeedPrompt] = None - ): + ) -> None: """Initialize the rephrase converter with optional chat target and prompt template.""" prompt_template = ( prompt_template diff --git a/pyrit/executor/promptgen/fuzzer/fuzzer_shorten_converter.py b/pyrit/executor/promptgen/fuzzer/fuzzer_shorten_converter.py index a6ba025e1a..ca5c8dd8d8 100644 --- a/pyrit/executor/promptgen/fuzzer/fuzzer_shorten_converter.py +++ b/pyrit/executor/promptgen/fuzzer/fuzzer_shorten_converter.py @@ -21,7 +21,7 @@ class FuzzerShortenConverter(FuzzerConverter): @apply_defaults def __init__( self, *, converter_target: Optional[PromptChatTarget] = None, prompt_template: Optional[SeedPrompt] = None - ): + ) -> None: """Initialize the shorten converter with optional chat target and prompt template.""" prompt_template = ( prompt_template diff --git a/pyrit/executor/promptgen/fuzzer/fuzzer_similar_converter.py b/pyrit/executor/promptgen/fuzzer/fuzzer_similar_converter.py index cf891af371..0144cb09b3 100644 --- a/pyrit/executor/promptgen/fuzzer/fuzzer_similar_converter.py +++ b/pyrit/executor/promptgen/fuzzer/fuzzer_similar_converter.py @@ -21,7 +21,7 @@ class FuzzerSimilarConverter(FuzzerConverter): @apply_defaults def __init__( self, *, converter_target: Optional[PromptChatTarget] = None, prompt_template: Optional[SeedPrompt] = None - ): + ) -> None: """Initialize the similar converter with optional chat target and prompt template.""" prompt_template = ( prompt_template diff --git a/pyrit/executor/workflow/core/workflow_strategy.py b/pyrit/executor/workflow/core/workflow_strategy.py index 80dc3a298d..cee2abfbd6 100644 --- a/pyrit/executor/workflow/core/workflow_strategy.py +++ b/pyrit/executor/workflow/core/workflow_strategy.py @@ -38,7 +38,7 @@ class _DefaultWorkflowEventHandler(StrategyEventHandler[WorkflowContextT, Workfl Handles events during the execution of a workflow strategy. """ - def __init__(self, logger: logging.Logger = logger): + def __init__(self, logger: logging.Logger = logger) -> None: """ Initialize the default event handler with a logger. @@ -111,7 +111,7 @@ def __init__( context_type: type[WorkflowContextT], logger: logging.Logger = logger, event_handler: Optional[StrategyEventHandler[WorkflowContextT, WorkflowResultT]] = None, - ): + ) -> None: """ Initialize the workflow strategy with a specific context type and logger. diff --git a/pyrit/executor/workflow/xpia.py b/pyrit/executor/workflow/xpia.py index 1cb22a5773..cbac67479d 100644 --- a/pyrit/executor/workflow/xpia.py +++ b/pyrit/executor/workflow/xpia.py @@ -149,7 +149,7 @@ def __init__( converter_config: Optional[StrategyConverterConfig] = None, prompt_normalizer: Optional[PromptNormalizer] = None, logger: logging.Logger = logger, - ): + ) -> None: """ Initialize the XPIA workflow. diff --git a/pyrit/identifiers/component_identifier.py b/pyrit/identifiers/component_identifier.py index 6c43fb6cdb..ede18a14f1 100644 --- a/pyrit/identifiers/component_identifier.py +++ b/pyrit/identifiers/component_identifier.py @@ -267,7 +267,7 @@ def normalize(cls, value: Union[ComponentIdentifier, dict[str, Any]]) -> Compone new_item="ComponentIdentifier", removed_in="0.14.0", ) - return cls.from_dict(value) + return cls.from_dict(value) # type: ignore[ty:invalid-argument-type] raise TypeError(f"Expected ComponentIdentifier or dict, got {type(value).__name__}") def to_dict(self, *, max_value_length: Optional[int] = None) -> dict[str, Any]: @@ -437,9 +437,9 @@ def _collect_child_eval_hashes(self) -> set[str]: for child_val in self.children.values(): children_list = child_val if isinstance(child_val, list) else [child_val] for child in children_list: - if child.eval_hash: - hashes.add(child.eval_hash) - hashes.update(child._collect_child_eval_hashes()) + if child.eval_hash: # type: ignore[ty:unresolved-attribute] + hashes.add(child.eval_hash) # type: ignore[ty:unresolved-attribute] + hashes.update(child._collect_child_eval_hashes()) # type: ignore[ty:unresolved-attribute] return hashes @classmethod diff --git a/pyrit/memory/azure_sql_memory.py b/pyrit/memory/azure_sql_memory.py index 8353b120c4..94f6ce110d 100644 --- a/pyrit/memory/azure_sql_memory.py +++ b/pyrit/memory/azure_sql_memory.py @@ -69,7 +69,7 @@ def __init__( results_sas_token: Optional[str] = None, verbose: bool = False, skip_schema_migration: bool = False, - ): + ) -> None: """ Initialize an Azure SQL Memory backend. @@ -126,7 +126,7 @@ def _resolve_sas_token(env_var_name: str, passed_value: Optional[str] = None) -> Optional[str]: Resolved SAS token or None if not provided. """ try: - return default_values.get_required_value(env_var_name=env_var_name, passed_value=passed_value) # type: ignore[no-any-return] + return default_values.get_required_value(env_var_name=env_var_name, passed_value=passed_value) except ValueError: return None @@ -752,7 +752,7 @@ def _query_entries( return query.distinct().all() return query.all() except SQLAlchemyError as e: - logger.exception(f"Error fetching data from table {model_class.__tablename__}: {e}") # type: ignore[attr-defined] + logger.exception(f"Error fetching data from table {model_class.__tablename__}: {e}") # type: ignore[ty:unresolved-attribute] raise def _update_entries(self, *, entries: MutableSequence[Base], update_fields: dict[str, Any]) -> bool: @@ -780,7 +780,7 @@ def _update_entries(self, *, entries: MutableSequence[Base], update_fields: dict # attributes from the (potentially stale) detached object # and silently overwrite concurrent updates to columns # that are NOT in update_fields. - entry_in_session = session.get(type(entry), entry.id) # type: ignore[attr-defined] + entry_in_session = session.get(type(entry), entry.id) # type: ignore[ty:unresolved-attribute] if entry_in_session is None: entry_in_session = session.merge(entry) for field, value in update_fields.items(): diff --git a/pyrit/memory/memory_embedding.py b/pyrit/memory/memory_embedding.py index 6ff724db22..e2ddc26e77 100644 --- a/pyrit/memory/memory_embedding.py +++ b/pyrit/memory/memory_embedding.py @@ -16,7 +16,7 @@ class MemoryEmbedding: embedding_model (EmbeddingSupport): An instance of a class that supports embedding generation. """ - def __init__(self, *, embedding_model: Optional[EmbeddingSupport] = None): + def __init__(self, *, embedding_model: Optional[EmbeddingSupport] = None) -> None: """ Initialize the memory embedding helper with a backing embedding model. diff --git a/pyrit/memory/memory_interface.py b/pyrit/memory/memory_interface.py index 1fcda5ba7c..e3d93b9187 100644 --- a/pyrit/memory/memory_interface.py +++ b/pyrit/memory/memory_interface.py @@ -1347,7 +1347,7 @@ async def add_seeds_to_memory_async(self, *, seeds: Sequence[Seed], added_by: Op # Only SeedPrompt has set_encoding_metadata for audio/video/image files if hasattr(prompt, "set_encoding_metadata"): - prompt.set_encoding_metadata() + prompt.set_encoding_metadata() # type: ignore[ty:call-non-callable] # Handle serialization for image, audio & video SeedPrompts if prompt.data_type in ["image_path", "audio_path", "video_path"]: @@ -2018,7 +2018,7 @@ def update_scenario_run_state(self, *, scenario_result_id: str, scenario_run_sta scenario_result = scenario_results[0] # Update the scenario run state - scenario_result.scenario_run_state = scenario_run_state # type: ignore[assignment] + scenario_result.scenario_run_state = scenario_run_state # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] # Save updated result back to memory using update entry = ScenarioResultEntry(entry=scenario_result) diff --git a/pyrit/memory/memory_models.py b/pyrit/memory/memory_models.py index 5a11fa78c7..ee871d0e1e 100644 --- a/pyrit/memory/memory_models.py +++ b/pyrit/memory/memory_models.py @@ -221,7 +221,7 @@ class PromptMemoryEntry(Base): foreign_keys="ScoreEntry.prompt_request_response_id", ) - def __init__(self, *, entry: MessagePiece): + def __init__(self, *, entry: MessagePiece) -> None: """ Initialize a PromptMemoryEntry from a MessagePiece. @@ -252,14 +252,14 @@ def __init__(self, *, entry: MessagePiece): ) self.original_value = entry.original_value - self.original_value_data_type = entry.original_value_data_type # type: ignore[assignment] + self.original_value_data_type = entry.original_value_data_type # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] self.original_value_sha256 = entry.original_value_sha256 self.converted_value = entry.converted_value - self.converted_value_data_type = entry.converted_value_data_type # type: ignore[assignment] + self.converted_value_data_type = entry.converted_value_data_type # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] self.converted_value_sha256 = entry.converted_value_sha256 - self.response_error = entry.response_error # type: ignore[assignment] + self.response_error = entry.response_error # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] self.original_prompt_id = entry.original_prompt_id self.pyrit_version = pyrit.__version__ @@ -387,7 +387,7 @@ class ScoreEntry(Base): pyrit_version = mapped_column(String, nullable=True) prompt_request_piece: Mapped["PromptMemoryEntry"] = relationship("PromptMemoryEntry", back_populates="scores") - def __init__(self, *, entry: Score): + def __init__(self, *, entry: Score) -> None: """ Initialize a ScoreEntry from a Score object. @@ -400,7 +400,7 @@ def __init__(self, *, entry: Score): self.score_type = entry.score_type self.score_category = entry.score_category self.score_rationale = entry.score_rationale - self.score_metadata = entry.score_metadata # type: ignore[assignment] + self.score_metadata = entry.score_metadata # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] # Normalize to ComponentIdentifier (handles dict with deprecation warning) then convert to dict for JSON storage normalized_scorer = ComponentIdentifier.normalize(entry.scorer_class_identifier) # Ensure eval_hash is set before truncation so it survives the DB round-trip @@ -441,7 +441,7 @@ def get_score(self) -> Score: score_category=self.score_category, score_rationale=self.score_rationale, score_metadata=self.score_metadata, - scorer_class_identifier=scorer_identifier, # type: ignore[arg-type] + scorer_class_identifier=scorer_identifier, # type: ignore[ty:invalid-argument-type] message_piece_id=self.prompt_request_response_id, timestamp=_ensure_utc(self.timestamp), objective=self.objective, @@ -565,7 +565,7 @@ class SeedEntry(Base): role: Mapped[ChatMessageRole] = mapped_column(String, nullable=True) seed_type: Mapped[SeedType] = mapped_column(String, nullable=False, default="prompt") - def __init__(self, *, entry: Seed): + def __init__(self, *, entry: Seed) -> None: """ Initialize a SeedEntry from a Seed object. @@ -586,14 +586,14 @@ def __init__(self, *, entry: Seed): self.data_type = entry.data_type self.name = entry.name self.dataset_name = entry.dataset_name - self.harm_categories = entry.harm_categories # type: ignore[assignment] + self.harm_categories = entry.harm_categories # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] self.description = entry.description self.authors = list(entry.authors) if entry.authors else None self.groups = list(entry.groups) if entry.groups else None self.source = entry.source self.date_added = entry.date_added self.added_by = entry.added_by - self.prompt_metadata = entry.metadata # type: ignore[assignment] + self.prompt_metadata = entry.metadata # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] self.prompt_group_id = entry.prompt_group_id self.seed_type = seed_type @@ -601,11 +601,11 @@ def __init__(self, *, entry: Seed): if isinstance(entry, SeedPrompt): self.parameters = list(entry.parameters) if entry.parameters else None self.sequence = entry.sequence - self.role = entry.role # type: ignore[assignment] + self.role = entry.role # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] else: self.parameters = None self.sequence = None - self.role = None # type: ignore[assignment] + self.role = None # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] def get_seed(self) -> Seed: """ @@ -744,7 +744,7 @@ class AttackResultEntry(Base): foreign_keys=[last_score_id], ) - def __init__(self, *, entry: AttackResult): + def __init__(self, *, entry: AttackResult) -> None: """ Initialize an AttackResultEntry from an AttackResult object. @@ -955,7 +955,7 @@ class ScenarioResultEntry(Base): completion_time = mapped_column(DateTime, nullable=False) timestamp = mapped_column(DateTime, nullable=False) - def __init__(self, *, entry: ScenarioResult): + def __init__(self, *, entry: ScenarioResult) -> None: """ Initialize a ScenarioResultEntry from a ScenarioResult object. @@ -1046,7 +1046,7 @@ def get_scenario_result(self) -> ScenarioResult: scenario_identifier=scenario_identifier, objective_target_identifier=target_identifier, attack_results=attack_results, - objective_scorer_identifier=scorer_identifier, # type: ignore[arg-type] + objective_scorer_identifier=scorer_identifier, # type: ignore[ty:invalid-argument-type] scenario_run_state=self.scenario_run_state, labels=self.labels, number_tries=self.number_tries, diff --git a/pyrit/memory/sqlite_memory.py b/pyrit/memory/sqlite_memory.py index b910f68953..c6e2a2a5a9 100644 --- a/pyrit/memory/sqlite_memory.py +++ b/pyrit/memory/sqlite_memory.py @@ -61,7 +61,7 @@ def __init__( db_path: Optional[Union[Path, str]] = None, verbose: bool = False, skip_schema_migration: bool = False, - ): + ) -> None: """ Initialize the SQLiteMemory instance. @@ -342,7 +342,7 @@ def _query_entries( return query.distinct().all() return query.all() except SQLAlchemyError as e: - logger.exception(f"Error fetching data from table {model_class.__tablename__}: {e}") # type: ignore[attr-defined] + logger.exception(f"Error fetching data from table {model_class.__tablename__}: {e}") # type: ignore[ty:unresolved-attribute] raise def _insert_entry(self, entry: Base) -> None: @@ -405,7 +405,7 @@ def _update_entries(self, *, entries: MutableSequence[Base], update_fields: dict # attributes from the (potentially stale) detached object # and silently overwrite concurrent updates to columns # that are NOT in update_fields. - entry_in_session = session.get(type(entry), entry.id) # type: ignore[attr-defined] + entry_in_session = session.get(type(entry), entry.id) # type: ignore[ty:unresolved-attribute] if entry_in_session is None: entry_in_session = session.merge(entry) for field, value in update_fields.items(): @@ -569,7 +569,7 @@ def export_all_tables(self, *, export_type: str = "json") -> None: file_extension = f".{export_type}" file_path = DB_DATA_PATH / f"{table_name}{file_extension}" # Convert to list for exporter compatibility - self.exporter.export_data(list(data), file_path=file_path, export_type=export_type) # type: ignore[arg-type] + self.exporter.export_data(list(data), file_path=file_path, export_type=export_type) # type: ignore[ty:invalid-argument-type] def _get_attack_result_harm_category_condition(self, *, targeted_harm_categories: Sequence[str]) -> Any: """ diff --git a/pyrit/message_normalizer/tokenizer_template_normalizer.py b/pyrit/message_normalizer/tokenizer_template_normalizer.py index bd7e81b02f..dbdf135c5c 100644 --- a/pyrit/message_normalizer/tokenizer_template_normalizer.py +++ b/pyrit/message_normalizer/tokenizer_template_normalizer.py @@ -122,11 +122,11 @@ def _load_tokenizer(model_name: str, token: Optional[str]) -> "PreTrainedTokeniz Returns: The loaded tokenizer. """ - from transformers import AutoTokenizer + from transformers import AutoTokenizer # type: ignore[ty:possibly-missing-import] return cast( "PreTrainedTokenizerBase", - AutoTokenizer.from_pretrained(model_name, token=token or None), # type: ignore[no-untyped-call, unused-ignore] + AutoTokenizer.from_pretrained(model_name, token=token or None), ) @classmethod diff --git a/pyrit/models/attack_result.py b/pyrit/models/attack_result.py index a385ac36e7..f0e16d52fe 100644 --- a/pyrit/models/attack_result.py +++ b/pyrit/models/attack_result.py @@ -220,7 +220,7 @@ def _add_attack_identifier_compat(cls: type) -> type: The same class with a wrapped ``__init__``. """ - original_init = cls.__init__ # type: ignore[misc] + original_init = cls.__init__ @functools.wraps(original_init) def wrapped_init(self: Any, *args: Any, **kwargs: Any) -> None: @@ -241,7 +241,7 @@ def wrapped_init(self: Any, *args: Any, **kwargs: Any) -> None: ) original_init(self, *args, **kwargs) - cls.__init__ = wrapped_init # type: ignore[misc] + cls.__init__ = wrapped_init # type: ignore[ty:invalid-assignment] return cls diff --git a/pyrit/models/data_type_serializer.py b/pyrit/models/data_type_serializer.py index 86322e2300..578efca5cc 100644 --- a/pyrit/models/data_type_serializer.py +++ b/pyrit/models/data_type_serializer.py @@ -380,7 +380,7 @@ def _is_azure_storage_url(self, path: str) -> bool: class TextDataTypeSerializer(DataTypeSerializer): """Serializer for text and text-like prompt values that stay in-memory.""" - def __init__(self, *, prompt_text: str, data_type: PromptDataType = "text"): + def __init__(self, *, prompt_text: str, data_type: PromptDataType = "text") -> None: """ Initialize a text serializer. @@ -406,7 +406,7 @@ def data_on_disk(self) -> bool: class ErrorDataTypeSerializer(DataTypeSerializer): """Serializer for error payloads stored as in-memory text.""" - def __init__(self, *, prompt_text: str): + def __init__(self, *, prompt_text: str) -> None: """ Initialize an error serializer. @@ -431,7 +431,7 @@ def data_on_disk(self) -> bool: class URLDataTypeSerializer(DataTypeSerializer): """Serializer for URL values and URL-backed local file references.""" - def __init__(self, *, category: str, prompt_text: str, extension: Optional[str] = None): + def __init__(self, *, category: str, prompt_text: str, extension: Optional[str] = None) -> None: """ Initialize a URL serializer. @@ -461,7 +461,7 @@ def data_on_disk(self) -> bool: class ImagePathDataTypeSerializer(DataTypeSerializer): """Serializer for image path values stored on disk.""" - def __init__(self, *, category: str, prompt_text: Optional[str] = None, extension: Optional[str] = None): + def __init__(self, *, category: str, prompt_text: Optional[str] = None, extension: Optional[str] = None) -> None: """ Initialize an image-path serializer. @@ -498,7 +498,7 @@ def __init__( category: str, prompt_text: Optional[str] = None, extension: Optional[str] = None, - ): + ) -> None: """ Initialize an audio-path serializer. @@ -535,7 +535,7 @@ def __init__( category: str, prompt_text: Optional[str] = None, extension: Optional[str] = None, - ): + ) -> None: """ Initialize a video-path serializer. @@ -572,7 +572,7 @@ def __init__( category: str, prompt_text: Optional[str] = None, extension: Optional[str] = None, - ): + ) -> None: """ Initialize a generic binary-path serializer. diff --git a/pyrit/models/message_piece.py b/pyrit/models/message_piece.py index 52abdeb7d6..357fd7abef 100644 --- a/pyrit/models/message_piece.py +++ b/pyrit/models/message_piece.py @@ -55,7 +55,7 @@ def __init__( timestamp: Optional[datetime] = None, scores: Optional[list[Score]] = None, targeted_harm_categories: Optional[list[str]] = None, - ): + ) -> None: """ Initialize a MessagePiece. @@ -96,7 +96,7 @@ def __init__( """ self.id = id if id else uuid4() - if role not in ChatMessageRole.__args__: # type: ignore[attr-defined] + if role not in ChatMessageRole.__args__: raise ValueError(f"Role {role} is not a valid role.") self._role: ChatMessageRole = role @@ -319,7 +319,7 @@ def set_piece_not_in_database(self) -> None: This is needed when we're scoring prompts or other things that have not been sent by PyRIT """ - self.id = None # type: ignore[assignment] + self.id = None # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] def to_dict(self) -> dict[str, object]: """ diff --git a/pyrit/models/scenario_result.py b/pyrit/models/scenario_result.py index 4e137a7989..fb63490ee8 100644 --- a/pyrit/models/scenario_result.py +++ b/pyrit/models/scenario_result.py @@ -28,7 +28,7 @@ def __init__( scenario_version: int = 1, init_data: Optional[dict[str, Any]] = None, pyrit_version: Optional[str] = None, - ): + ) -> None: """ Initialize a ScenarioIdentifier. diff --git a/pyrit/models/score.py b/pyrit/models/score.py index 899557ed5c..58f50b8e92 100644 --- a/pyrit/models/score.py +++ b/pyrit/models/score.py @@ -65,7 +65,7 @@ def __init__( scorer_class_identifier: Union[ComponentIdentifier, dict[str, Any]], timestamp: Optional[datetime] = None, objective: Optional[str] = None, - ): + ) -> None: """ Initialize a score object. diff --git a/pyrit/models/seeds/seed_attack_group.py b/pyrit/models/seeds/seed_attack_group.py index 30b00e1100..9936f15683 100644 --- a/pyrit/models/seeds/seed_attack_group.py +++ b/pyrit/models/seeds/seed_attack_group.py @@ -36,7 +36,7 @@ def __init__( self, *, seeds: Sequence[Union[Seed, dict[str, Any]]], - ): + ) -> None: """ Initialize a SeedAttackGroup. diff --git a/pyrit/models/seeds/seed_attack_technique_group.py b/pyrit/models/seeds/seed_attack_technique_group.py index 39ae1a17e1..ee8eb0475d 100644 --- a/pyrit/models/seeds/seed_attack_technique_group.py +++ b/pyrit/models/seeds/seed_attack_technique_group.py @@ -38,7 +38,7 @@ def __init__( *, seeds: Sequence[Union[Seed, dict[str, Any]]], insertion_index: int | None = None, - ): + ) -> None: """ Initialize a SeedAttackTechniqueGroup. diff --git a/pyrit/models/seeds/seed_dataset.py b/pyrit/models/seeds/seed_dataset.py index 36749a382f..ac49ce9082 100644 --- a/pyrit/models/seeds/seed_dataset.py +++ b/pyrit/models/seeds/seed_dataset.py @@ -102,7 +102,7 @@ def __init__( added_by: Optional[str] = None, seed_type: Optional[SeedType] = None, is_jinja_template: bool = False, - ): + ) -> None: """ Initialize the dataset. Typically, you'll call from_dict or from_yaml_file so that top-level defaults @@ -151,7 +151,7 @@ def __init__( self.seeds = [] for p in input_seeds: if isinstance(p, dict): - p_seed_type = p.get("seed_type", seed_type) + p_seed_type = p.get("seed_type", seed_type) # type: ignore[ty:no-matching-overload] effective_type: SeedType = "prompt" if p_seed_type == "objective": @@ -165,44 +165,44 @@ def __init__( # Note: If Seed base class param names change, update here too. # SeedSimulatedConversation computes its own value, so we don't require it. base_params = { - "value_sha256": p.get("value_sha256"), + "value_sha256": p.get("value_sha256"), # type: ignore[ty:invalid-argument-type] "id": uuid.uuid4(), - "name": p.get("name") or self.name, - "dataset_name": p.get("dataset_name") or self.dataset_name or self.name, - "harm_categories": p.get("harm_categories", []), - "description": p.get("description") or self.description, - "authors": p.get("authors", []), - "groups": p.get("groups", []), - "source": p.get("source") or self.source, - "date_added": p.get("date_added"), - "added_by": p.get("added_by"), - "metadata": p.get("metadata", {}), - "prompt_group_id": p.get("prompt_group_id"), + "name": p.get("name") or self.name, # type: ignore[ty:invalid-argument-type] + "dataset_name": p.get("dataset_name") or self.dataset_name or self.name, # type: ignore[ty:invalid-argument-type] + "harm_categories": p.get("harm_categories", []), # type: ignore[ty:no-matching-overload] + "description": p.get("description") or self.description, # type: ignore[ty:invalid-argument-type] + "authors": p.get("authors", []), # type: ignore[ty:no-matching-overload] + "groups": p.get("groups", []), # type: ignore[ty:no-matching-overload] + "source": p.get("source") or self.source, # type: ignore[ty:invalid-argument-type] + "date_added": p.get("date_added"), # type: ignore[ty:invalid-argument-type] + "added_by": p.get("added_by"), # type: ignore[ty:invalid-argument-type] + "metadata": p.get("metadata", {}), # type: ignore[ty:no-matching-overload] + "prompt_group_id": p.get("prompt_group_id"), # type: ignore[ty:invalid-argument-type] "is_jinja_template": is_jinja_template, } if effective_type == "simulated_conversation": - _adv_path = p.get("adversarial_chat_system_prompt_path") - _sim_path = p.get("simulated_target_system_prompt_path") - _sc_kwargs: dict[str, Any] = {**base_params, "num_turns": p.get("num_turns", 3)} + _adv_path = p.get("adversarial_chat_system_prompt_path") # type: ignore[ty:invalid-argument-type] + _sim_path = p.get("simulated_target_system_prompt_path") # type: ignore[ty:invalid-argument-type] + _sc_kwargs: dict[str, Any] = {**base_params, "num_turns": p.get("num_turns", 3)} # type: ignore[ty:no-matching-overload] if _adv_path is not None: _sc_kwargs["adversarial_chat_system_prompt_path"] = str(_adv_path) if _sim_path is not None: _sc_kwargs["simulated_target_system_prompt_path"] = str(_sim_path) - self.seeds.append(SeedSimulatedConversation(**_sc_kwargs)) + self.seeds.append(SeedSimulatedConversation(**_sc_kwargs)) # type: ignore[ty:invalid-argument-type] elif effective_type == "objective": # SeedObjective inherits data_type="text" from base Seed property - base_params["value"] = p["value"] - self.seeds.append(SeedObjective(**base_params)) + base_params["value"] = p["value"] # type: ignore[ty:invalid-argument-type] + self.seeds.append(SeedObjective(**base_params)) # type: ignore[ty:invalid-argument-type] else: # prompt - base_params["value"] = p["value"] + base_params["value"] = p["value"] # type: ignore[ty:invalid-argument-type] self.seeds.append( SeedPrompt( - **base_params, - data_type=p.get("data_type") or self.data_type, - role=p.get("role", "user"), - sequence=p.get("sequence", 0), - parameters=p.get("parameters", {}), + **base_params, # type: ignore[ty:invalid-argument-type] + data_type=p.get("data_type") or self.data_type, # type: ignore[ty:invalid-argument-type] + role=p.get("role", "user"), # type: ignore[ty:no-matching-overload] + sequence=p.get("sequence", 0), # type: ignore[ty:no-matching-overload] + parameters=p.get("parameters", {}), # type: ignore[ty:no-matching-overload] ) ) elif isinstance(p, (SeedPrompt, SeedObjective, SeedSimulatedConversation)): diff --git a/pyrit/models/seeds/seed_group.py b/pyrit/models/seeds/seed_group.py index ebb81f29a8..6e76d0a171 100644 --- a/pyrit/models/seeds/seed_group.py +++ b/pyrit/models/seeds/seed_group.py @@ -49,7 +49,7 @@ def __init__( *, seeds: Sequence[Union[Seed, dict[str, Any]]], is_jinja_template: bool = False, - ): + ) -> None: """ Initialize a SeedGroup. diff --git a/pyrit/models/seeds/seed_prompt.py b/pyrit/models/seeds/seed_prompt.py index 7563936b6e..2610f70ec0 100644 --- a/pyrit/models/seeds/seed_prompt.py +++ b/pyrit/models/seeds/seed_prompt.py @@ -35,7 +35,7 @@ class SeedPrompt(Seed): # The type of data this prompt represents (e.g., text, image_path, audio_path, video_path) # This field shadows the base class property to allow per-prompt data types - data_type: Optional[PromptDataType] = None # type: ignore[assignment] + data_type: Optional[PromptDataType] = None # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] # Role of the prompt in a conversation (e.g., "user", "assistant") role: Optional[ChatMessageRole] = None diff --git a/pyrit/models/storage_io.py b/pyrit/models/storage_io.py index 05d4f8a5e8..08142e8571 100644 --- a/pyrit/models/storage_io.py +++ b/pyrit/models/storage_io.py @@ -218,7 +218,7 @@ async def _upload_blob_async(self, file_name: str, data: bytes, content_type: st Raises: RuntimeError: If the Azure container client is not initialized. """ - content_settings = ContentSettings(content_type=f"{content_type}") # type: ignore[no-untyped-call, unused-ignore] + content_settings = ContentSettings(content_type=f"{content_type}") logger.info(msg="\nUploading to Azure Storage as blob:\n\t" + file_name) try: @@ -322,13 +322,13 @@ async def read_file(self, path: Union[Path, str]) -> bytes: # Download the blob blob_stream = await blob_client.download_blob() - return bytes(await blob_stream.readall()) + return bytes(await blob_stream.readall()) # type: ignore[ty:invalid-argument-type] except Exception as exc: logger.exception(f"Failed to read file at {blob_name}: {exc}") raise finally: - await self._client_async.close() # type: ignore[no-untyped-call, unused-ignore] + await self._client_async.close() self._client_async = None async def write_file(self, path: Union[Path, str], data: bytes) -> None: @@ -351,7 +351,7 @@ async def write_file(self, path: Union[Path, str], data: bytes) -> None: logger.exception(f"Failed to write file at {blob_name}: {exc}") raise finally: - await self._client_async.close() # type: ignore[no-untyped-call, unused-ignore] + await self._client_async.close() self._client_async = None async def path_exists(self, path: Union[Path, str]) -> bool: @@ -374,7 +374,7 @@ async def path_exists(self, path: Union[Path, str]) -> bool: except ResourceNotFoundError: return False finally: - await self._client_async.close() # type: ignore[no-untyped-call, unused-ignore] + await self._client_async.close() self._client_async = None async def is_file(self, path: Union[Path, str]) -> bool: @@ -397,10 +397,10 @@ async def is_file(self, path: Union[Path, str]) -> bool: except ResourceNotFoundError: return False finally: - await self._client_async.close() # type: ignore[no-untyped-call, unused-ignore] + await self._client_async.close() self._client_async = None - async def create_directory_if_not_exists(self, directory_path: Union[Path, str]) -> None: + async def create_directory_if_not_exists(self, directory_path: Union[Path, str]) -> None: # type: ignore[ty:invalid-method-override] """ Log a no-op directory creation for Azure Blob Storage. diff --git a/pyrit/prompt_converter/add_image_text_converter.py b/pyrit/prompt_converter/add_image_text_converter.py index 82bc140f71..ac64bced12 100644 --- a/pyrit/prompt_converter/add_image_text_converter.py +++ b/pyrit/prompt_converter/add_image_text_converter.py @@ -44,12 +44,12 @@ def __init__( font_name: str = "helvetica.ttf", color: tuple[int, int, int] = (0, 0, 0), font_size: int | tuple[int, int] = 15, - x_pos: int = _UNSET, # type: ignore[assignment] - y_pos: int = _UNSET, # type: ignore[assignment] + x_pos: int = _UNSET, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] + y_pos: int = _UNSET, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] bounding_box: tuple[int, int, int, int] | None = None, rotation: float = 0.0, center_text: bool = False, - ): + ) -> None: """ Initialize the converter with the image file path and text properties. diff --git a/pyrit/prompt_converter/add_image_to_video_converter.py b/pyrit/prompt_converter/add_image_to_video_converter.py index 7b4b109b30..d13b333184 100644 --- a/pyrit/prompt_converter/add_image_to_video_converter.py +++ b/pyrit/prompt_converter/add_image_to_video_converter.py @@ -42,7 +42,7 @@ def __init__( output_path: Optional[str] = None, img_position: tuple[int, int] = (10, 10), img_resize_size: tuple[int, int] = (500, 500), - ): + ) -> None: """ Initialize the converter with the video path and image properties. @@ -133,7 +133,7 @@ async def _add_image_to_video(self, image_path: str, output_path: str) -> str: height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) file_extension = video_path.split(".")[-1].lower() if file_extension in video_encoding_map: - video_char_code = cv2.VideoWriter_fourcc(*video_encoding_map[file_extension]) # type: ignore[attr-defined, misc, unused-ignore] + video_char_code = cv2.VideoWriter_fourcc(*video_encoding_map[file_extension]) output_video = cv2.VideoWriter(output_path, video_char_code, fps, (width, height)) else: raise ValueError(f"Unsupported video format: {file_extension}") @@ -183,7 +183,7 @@ async def _add_image_to_video(self, image_path: str, output_path: str) -> str: with contextlib.suppress(cv2.error): cv2.destroyAllWindows() # Not available in headless OpenCV builds if azure_storage_flag: - os.remove(local_temp_path) + os.remove(local_temp_path) # type: ignore[ty:possibly-unresolved-reference] logger.info(f"Video saved as {output_path}") diff --git a/pyrit/prompt_converter/add_text_image_converter.py b/pyrit/prompt_converter/add_text_image_converter.py index 5a2e9f3a35..04cc069d68 100644 --- a/pyrit/prompt_converter/add_text_image_converter.py +++ b/pyrit/prompt_converter/add_text_image_converter.py @@ -39,7 +39,7 @@ def __init__( font_size: int = 15, x_pos: int = 10, y_pos: int = 10, - ): + ) -> None: """ Initialize the converter with the text and text properties. diff --git a/pyrit/prompt_converter/ansi_escape/ansi_attack_converter.py b/pyrit/prompt_converter/ansi_escape/ansi_attack_converter.py index bdd80dd6ca..aaee76c92f 100644 --- a/pyrit/prompt_converter/ansi_escape/ansi_attack_converter.py +++ b/pyrit/prompt_converter/ansi_escape/ansi_attack_converter.py @@ -39,7 +39,7 @@ def __init__( include_repeats: bool = True, include_unescape: bool = True, incorporate_user_prompt: bool = True, - ): + ) -> None: """ Initialize the converter with various options to control the scenarios generated. diff --git a/pyrit/prompt_converter/audio_white_noise_converter.py b/pyrit/prompt_converter/audio_white_noise_converter.py index a39d3e0c30..5be7c32c85 100644 --- a/pyrit/prompt_converter/audio_white_noise_converter.py +++ b/pyrit/prompt_converter/audio_white_noise_converter.py @@ -77,7 +77,7 @@ def _add_noise(self, data: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]: # Clip to valid range if np.issubdtype(data.dtype, np.integer): - noisy = np.clip(noisy, info.min, info.max) + noisy = np.clip(noisy, info.min, info.max) # type: ignore[ty:possibly-unresolved-reference] return np.asarray(noisy) diff --git a/pyrit/prompt_converter/azure_speech_audio_to_text_converter.py b/pyrit/prompt_converter/azure_speech_audio_to_text_converter.py index eb7e93adb6..a2506684ed 100644 --- a/pyrit/prompt_converter/azure_speech_audio_to_text_converter.py +++ b/pyrit/prompt_converter/azure_speech_audio_to_text_converter.py @@ -94,7 +94,7 @@ def __init__( self._azure_speech_resource_id: str | None = None if azure_speech_key is not None and callable(azure_speech_key): - self._token_provider = azure_speech_key + self._token_provider = azure_speech_key # type: ignore[ty:invalid-assignment] self._azure_speech_resource_id = default_values.get_required_value( env_var_name=self.AZURE_SPEECH_RESOURCE_ID_ENVIRONMENT_VARIABLE, passed_value=azure_speech_resource_id, diff --git a/pyrit/prompt_converter/azure_speech_text_to_audio_converter.py b/pyrit/prompt_converter/azure_speech_text_to_audio_converter.py index b64f437bd0..ad91964054 100644 --- a/pyrit/prompt_converter/azure_speech_text_to_audio_converter.py +++ b/pyrit/prompt_converter/azure_speech_text_to_audio_converter.py @@ -100,7 +100,7 @@ def __init__( self._azure_speech_resource_id: str | None = None if azure_speech_key is not None and callable(azure_speech_key): - self._token_provider = azure_speech_key + self._token_provider = azure_speech_key # type: ignore[ty:invalid-assignment] self._azure_speech_resource_id = default_values.get_required_value( env_var_name=self.AZURE_SPEECH_RESOURCE_ID_ENVIRONMENT_VARIABLE, passed_value=azure_speech_resource_id, diff --git a/pyrit/prompt_converter/binary_converter.py b/pyrit/prompt_converter/binary_converter.py index 12b139f22a..3394382560 100644 --- a/pyrit/prompt_converter/binary_converter.py +++ b/pyrit/prompt_converter/binary_converter.py @@ -30,7 +30,7 @@ def __init__( *, bits_per_char: BinaryConverter.BitsPerChar = BitsPerChar.BITS_16, word_selection_strategy: Optional[WordSelectionStrategy] = None, - ): + ) -> None: """ Initialize the converter with the specified bits per character and selection strategy. diff --git a/pyrit/prompt_converter/charswap_attack_converter.py b/pyrit/prompt_converter/charswap_attack_converter.py index 7f28c3d725..cc0f5f8cb2 100644 --- a/pyrit/prompt_converter/charswap_attack_converter.py +++ b/pyrit/prompt_converter/charswap_attack_converter.py @@ -23,7 +23,7 @@ def __init__( *, max_iterations: int = 10, word_selection_strategy: Optional[WordSelectionStrategy] = None, - ): + ) -> None: """ Initialize the converter with the specified parameters. diff --git a/pyrit/prompt_converter/codechameleon_converter.py b/pyrit/prompt_converter/codechameleon_converter.py index 43bb1e4ab8..2c4624d01d 100644 --- a/pyrit/prompt_converter/codechameleon_converter.py +++ b/pyrit/prompt_converter/codechameleon_converter.py @@ -79,7 +79,7 @@ def __init__( raise ValueError("Encryption and decryption functions not provided for custom encrypt_type.") self.encrypt_function = encrypt_function if isinstance(decrypt_function, list): - self.decrypt_function = self._stringify_decrypt(decrypt_function) + self.decrypt_function = self._stringify_decrypt(decrypt_function) # type: ignore[ty:invalid-argument-type] else: self.decrypt_function = self._stringify_decrypt([decrypt_function]) case "reverse": diff --git a/pyrit/prompt_converter/denylist_converter.py b/pyrit/prompt_converter/denylist_converter.py index 46f427caef..ff402ec3c0 100644 --- a/pyrit/prompt_converter/denylist_converter.py +++ b/pyrit/prompt_converter/denylist_converter.py @@ -26,10 +26,10 @@ class DenylistConverter(LLMGenericTextConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] system_prompt_template: Optional[SeedPrompt] = None, denylist: list[str] | None = None, - ): + ) -> None: """ Initialize the converter with a target, an optional system prompt template, and a denylist. diff --git a/pyrit/prompt_converter/diacritic_converter.py b/pyrit/prompt_converter/diacritic_converter.py index 918dfa723c..e85983bc3a 100644 --- a/pyrit/prompt_converter/diacritic_converter.py +++ b/pyrit/prompt_converter/diacritic_converter.py @@ -19,7 +19,7 @@ class DiacriticConverter(PromptConverter): SUPPORTED_INPUT_TYPES = ("text",) SUPPORTED_OUTPUT_TYPES = ("text",) - def __init__(self, target_chars: str = "aeiou", accent: str = "acute"): + def __init__(self, target_chars: str = "aeiou", accent: str = "acute") -> None: """ Initialize the converter with specified target characters and diacritic accent. diff --git a/pyrit/prompt_converter/image_compression_converter.py b/pyrit/prompt_converter/image_compression_converter.py index 7761dd0b40..fe40116371 100644 --- a/pyrit/prompt_converter/image_compression_converter.py +++ b/pyrit/prompt_converter/image_compression_converter.py @@ -60,7 +60,7 @@ def __init__( background_color: tuple[int, int, int] = (0, 0, 0), min_compression_threshold: int = 1024, fallback_to_original: bool = True, - ): + ) -> None: """ Initialize the converter with specified compression settings. diff --git a/pyrit/prompt_converter/leetspeak_converter.py b/pyrit/prompt_converter/leetspeak_converter.py index 0c6145a0f8..c233b745c3 100644 --- a/pyrit/prompt_converter/leetspeak_converter.py +++ b/pyrit/prompt_converter/leetspeak_converter.py @@ -20,7 +20,7 @@ def __init__( deterministic: bool = True, custom_substitutions: Optional[dict[str, list[str]]] = None, word_selection_strategy: Optional[WordSelectionStrategy] = None, - ): + ) -> None: """ Initialize the converter with optional deterministic mode and custom substitutions. diff --git a/pyrit/prompt_converter/llm_generic_text_converter.py b/pyrit/prompt_converter/llm_generic_text_converter.py index f56990247f..a0c582bcb1 100644 --- a/pyrit/prompt_converter/llm_generic_text_converter.py +++ b/pyrit/prompt_converter/llm_generic_text_converter.py @@ -32,7 +32,7 @@ class LLMGenericTextConverter(PromptConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] system_prompt_template: Optional[SeedPrompt] = None, user_prompt_template_with_objective: Optional[SeedPrompt] = None, **kwargs: Any, diff --git a/pyrit/prompt_converter/malicious_question_generator_converter.py b/pyrit/prompt_converter/malicious_question_generator_converter.py index 41a7848458..e283e25f1e 100644 --- a/pyrit/prompt_converter/malicious_question_generator_converter.py +++ b/pyrit/prompt_converter/malicious_question_generator_converter.py @@ -26,9 +26,9 @@ class MaliciousQuestionGeneratorConverter(LLMGenericTextConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """ Initialize the converter with a specific target and template. diff --git a/pyrit/prompt_converter/math_prompt_converter.py b/pyrit/prompt_converter/math_prompt_converter.py index fd6491bbc1..fe2afd512b 100644 --- a/pyrit/prompt_converter/math_prompt_converter.py +++ b/pyrit/prompt_converter/math_prompt_converter.py @@ -26,9 +26,9 @@ class MathPromptConverter(LLMGenericTextConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """ Initialize the converter with a specific target and template. diff --git a/pyrit/prompt_converter/negation_trap_converter.py b/pyrit/prompt_converter/negation_trap_converter.py index 1b03a38dfc..14d88d2730 100644 --- a/pyrit/prompt_converter/negation_trap_converter.py +++ b/pyrit/prompt_converter/negation_trap_converter.py @@ -36,7 +36,7 @@ def __init__( *, wrong_value: str = "incorrect_guess", trap_template: str | None = None, - ): + ) -> None: """ Initialize the Negation Trap Converter. diff --git a/pyrit/prompt_converter/noise_converter.py b/pyrit/prompt_converter/noise_converter.py index 0d7bdf302f..25464fea9b 100644 --- a/pyrit/prompt_converter/noise_converter.py +++ b/pyrit/prompt_converter/noise_converter.py @@ -27,11 +27,11 @@ class NoiseConverter(LLMGenericTextConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] noise: Optional[str] = None, number_errors: int = 5, prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """ Initialize the converter with the specified parameters. diff --git a/pyrit/prompt_converter/pdf_converter.py b/pyrit/prompt_converter/pdf_converter.py index 27a41932d1..2fa8a08e11 100644 --- a/pyrit/prompt_converter/pdf_converter.py +++ b/pyrit/prompt_converter/pdf_converter.py @@ -80,7 +80,7 @@ def __init__( # Keeping the user's path here self._existing_pdf_path: Optional[Path] = existing_pdf - # We store the file data in a separate BytesIO because of a mypy error + # We store the file data in a separate BytesIO for type checker compatibility self._existing_pdf_bytes: Optional[BytesIO] = None self._injection_items = injection_items or [] diff --git a/pyrit/prompt_converter/persuasion_converter.py b/pyrit/prompt_converter/persuasion_converter.py index 11b6bd66e6..f999194d65 100644 --- a/pyrit/prompt_converter/persuasion_converter.py +++ b/pyrit/prompt_converter/persuasion_converter.py @@ -52,9 +52,9 @@ class PersuasionConverter(PromptConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] persuasion_technique: str, - ): + ) -> None: """ Initialize the converter with the specified target and prompt template. diff --git a/pyrit/prompt_converter/qr_code_converter.py b/pyrit/prompt_converter/qr_code_converter.py index a4442fcdc1..4f934376b7 100644 --- a/pyrit/prompt_converter/qr_code_converter.py +++ b/pyrit/prompt_converter/qr_code_converter.py @@ -27,7 +27,7 @@ def __init__( finder_dark_color: Optional[tuple[int, int, int]] = None, finder_light_color: Optional[tuple[int, int, int]] = None, border_color: Optional[tuple[int, int, int]] = None, - ): + ) -> None: """ Initialize the converter with specified parameters for QR code generation. diff --git a/pyrit/prompt_converter/random_translation_converter.py b/pyrit/prompt_converter/random_translation_converter.py index 74953c2603..011a190964 100644 --- a/pyrit/prompt_converter/random_translation_converter.py +++ b/pyrit/prompt_converter/random_translation_converter.py @@ -35,11 +35,11 @@ class RandomTranslationConverter(LLMGenericTextConverter, WordLevelConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] system_prompt_template: Optional[SeedPrompt] = None, languages: Optional[list[str]] = None, word_selection_strategy: Optional[WordSelectionStrategy] = None, - ): + ) -> None: """ Initialize the converter with a target, an optional system prompt template, and language options. diff --git a/pyrit/prompt_converter/scientific_translation_converter.py b/pyrit/prompt_converter/scientific_translation_converter.py index 2a6c965996..d1c81ec1af 100644 --- a/pyrit/prompt_converter/scientific_translation_converter.py +++ b/pyrit/prompt_converter/scientific_translation_converter.py @@ -45,7 +45,7 @@ class ScientificTranslationConverter(LLMGenericTextConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] mode: str = "combined", prompt_template: Optional[SeedPrompt] = None, ) -> None: diff --git a/pyrit/prompt_converter/selective_text_converter.py b/pyrit/prompt_converter/selective_text_converter.py index 7346904a3c..c66bab1b50 100644 --- a/pyrit/prompt_converter/selective_text_converter.py +++ b/pyrit/prompt_converter/selective_text_converter.py @@ -196,7 +196,7 @@ async def _convert_word_level_async(self, *, prompt: str) -> ConverterResult: words = prompt.split(self._word_separator) # Get selected word indices - selected_indices = self._selection_strategy.select_words(words=words) # type: ignore[attr-defined] + selected_indices = self._selection_strategy.select_words(words=words) # type: ignore[ty:unresolved-attribute] # If no words selected, return original prompt if not selected_indices: diff --git a/pyrit/prompt_converter/suffix_append_converter.py b/pyrit/prompt_converter/suffix_append_converter.py index 616ed210be..d74ea27bd3 100644 --- a/pyrit/prompt_converter/suffix_append_converter.py +++ b/pyrit/prompt_converter/suffix_append_converter.py @@ -18,7 +18,7 @@ class SuffixAppendConverter(PromptConverter): SUPPORTED_INPUT_TYPES = ("text",) SUPPORTED_OUTPUT_TYPES = ("text",) - def __init__(self, *, suffix: str): + def __init__(self, *, suffix: str) -> None: """ Initialize the converter with the specified suffix. diff --git a/pyrit/prompt_converter/template_segment_converter.py b/pyrit/prompt_converter/template_segment_converter.py index 07ab83e164..23fdc05e76 100644 --- a/pyrit/prompt_converter/template_segment_converter.py +++ b/pyrit/prompt_converter/template_segment_converter.py @@ -30,7 +30,7 @@ def __init__( self, *, prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """ Initialize the converter with the specified target and prompt template. diff --git a/pyrit/prompt_converter/tense_converter.py b/pyrit/prompt_converter/tense_converter.py index 237a2934d5..246b6755f2 100644 --- a/pyrit/prompt_converter/tense_converter.py +++ b/pyrit/prompt_converter/tense_converter.py @@ -26,10 +26,10 @@ class TenseConverter(LLMGenericTextConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] tense: str, prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """ Initialize the converter with the target chat support, tense, and optional prompt template. diff --git a/pyrit/prompt_converter/text_jailbreak_converter.py b/pyrit/prompt_converter/text_jailbreak_converter.py index a95e032cc8..db180c3861 100644 --- a/pyrit/prompt_converter/text_jailbreak_converter.py +++ b/pyrit/prompt_converter/text_jailbreak_converter.py @@ -16,7 +16,7 @@ class TextJailbreakConverter(PromptConverter): SUPPORTED_INPUT_TYPES = ("text",) SUPPORTED_OUTPUT_TYPES = ("text",) - def __init__(self, *, jailbreak_template: TextJailBreak): + def __init__(self, *, jailbreak_template: TextJailBreak) -> None: """ Initialize the converter with the specified jailbreak template. diff --git a/pyrit/prompt_converter/token_smuggling/ascii_smuggler_converter.py b/pyrit/prompt_converter/token_smuggling/ascii_smuggler_converter.py index 1f373a22fb..8ec2e5a3a5 100644 --- a/pyrit/prompt_converter/token_smuggling/ascii_smuggler_converter.py +++ b/pyrit/prompt_converter/token_smuggling/ascii_smuggler_converter.py @@ -22,7 +22,7 @@ class AsciiSmugglerConverter(SmugglerConverter): [@embracethered2024unicode] """ - def __init__(self, action: Literal["encode", "decode"] = "encode", unicode_tags: bool = False): + def __init__(self, action: Literal["encode", "decode"] = "encode", unicode_tags: bool = False) -> None: """ Initialize the converter with options for encoding/decoding. diff --git a/pyrit/prompt_converter/token_smuggling/sneaky_bits_smuggler_converter.py b/pyrit/prompt_converter/token_smuggling/sneaky_bits_smuggler_converter.py index 78fa2836a6..cae77904f4 100644 --- a/pyrit/prompt_converter/token_smuggling/sneaky_bits_smuggler_converter.py +++ b/pyrit/prompt_converter/token_smuggling/sneaky_bits_smuggler_converter.py @@ -27,7 +27,7 @@ def __init__( action: Literal["encode", "decode"] = "encode", zero_char: Optional[str] = None, one_char: Optional[str] = None, - ): + ) -> None: """ Initialize the converter with options for encoding/decoding in Sneaky Bits mode. diff --git a/pyrit/prompt_converter/token_smuggling/variation_selector_smuggler_converter.py b/pyrit/prompt_converter/token_smuggling/variation_selector_smuggler_converter.py index 65cd67f086..9b375ca1f1 100644 --- a/pyrit/prompt_converter/token_smuggling/variation_selector_smuggler_converter.py +++ b/pyrit/prompt_converter/token_smuggling/variation_selector_smuggler_converter.py @@ -34,7 +34,7 @@ def __init__( action: Literal["encode", "decode"] = "encode", base_char_utf8: Optional[str] = None, embed_in_base: bool = True, - ): + ) -> None: """ Initialize the converter with options for encoding/decoding. diff --git a/pyrit/prompt_converter/tone_converter.py b/pyrit/prompt_converter/tone_converter.py index a7b8e5a9f1..b81a5a1268 100644 --- a/pyrit/prompt_converter/tone_converter.py +++ b/pyrit/prompt_converter/tone_converter.py @@ -26,10 +26,10 @@ class ToneConverter(LLMGenericTextConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] tone: str, prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """ Initialize the converter with the target chat support, tone, and optional prompt template. diff --git a/pyrit/prompt_converter/toxic_sentence_generator_converter.py b/pyrit/prompt_converter/toxic_sentence_generator_converter.py index d3390c6af7..1a2b56b36e 100644 --- a/pyrit/prompt_converter/toxic_sentence_generator_converter.py +++ b/pyrit/prompt_converter/toxic_sentence_generator_converter.py @@ -34,9 +34,9 @@ class ToxicSentenceGeneratorConverter(LLMGenericTextConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """ Initialize the converter with a specific target and template. diff --git a/pyrit/prompt_converter/translation_converter.py b/pyrit/prompt_converter/translation_converter.py index 911f72ab57..9b3b23db8c 100644 --- a/pyrit/prompt_converter/translation_converter.py +++ b/pyrit/prompt_converter/translation_converter.py @@ -41,7 +41,7 @@ class TranslationConverter(PromptConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] language: str, prompt_template: Optional[SeedPrompt] = None, max_retries: int = 3, diff --git a/pyrit/prompt_converter/transparency_attack_converter.py b/pyrit/prompt_converter/transparency_attack_converter.py index b98bf956e7..ddcf9bd4bb 100644 --- a/pyrit/prompt_converter/transparency_attack_converter.py +++ b/pyrit/prompt_converter/transparency_attack_converter.py @@ -30,7 +30,7 @@ class _AdamOptimizer: def __init__( self, *, learning_rate: float = 0.001, beta_1: float = 0.9, beta_2: float = 0.999, epsilon: float = 1e-8 - ): + ) -> None: """ Initialize the Adam optimizer with specified hyperparameters. @@ -44,11 +44,11 @@ def __init__( self.beta_1 = beta_1 self.beta_2 = beta_2 self.epsilon = epsilon - self.m: np.ndarray # type: ignore[type-arg, unused-ignore] # first moment vector - self.v: np.ndarray # type: ignore[type-arg, unused-ignore] # second moment vector + self.m: np.ndarray # first moment vector + self.v: np.ndarray # second moment vector self.t = 0 # initialize timestep - def update(self, *, params: np.ndarray, grads: np.ndarray) -> np.ndarray: # type: ignore[type-arg, unused-ignore] + def update(self, *, params: np.ndarray, grads: np.ndarray) -> np.ndarray: """ Perform a single update step using the Adam optimization algorithm. @@ -133,7 +133,7 @@ def __init__( learning_rate: float = 0.001, convergence_threshold: float = 1e-6, convergence_patience: int = 10, - ): + ) -> None: """ Initialize the converter with the path to a benign image and parameters for blending. @@ -200,7 +200,7 @@ def _build_identifier(self) -> ComponentIdentifier: } ) - def _load_and_preprocess_image(self, path: str) -> np.ndarray: # type: ignore[type-arg, unused-ignore] + def _load_and_preprocess_image(self, path: str) -> np.ndarray: """ Load image, convert to grayscale, resize, and normalize for optimization. @@ -221,7 +221,7 @@ def _load_and_preprocess_image(self, path: str) -> np.ndarray: # type: ignore[t except Exception as e: raise ValueError(f"Failed to load and preprocess image from {path}: {e}") from e - def _compute_mse_loss(self, blended_image: np.ndarray, target_tensor: np.ndarray) -> float: # type: ignore[type-arg, unused-ignore] + def _compute_mse_loss(self, blended_image: np.ndarray, target_tensor: np.ndarray) -> float: """ Compute Mean Squared Error (MSE) loss between blended and target images. @@ -234,7 +234,7 @@ def _compute_mse_loss(self, blended_image: np.ndarray, target_tensor: np.ndarray """ return float(np.mean(np.square(blended_image - target_tensor))) - def _create_blended_image(self, attack_image: np.ndarray, alpha: np.ndarray) -> np.ndarray: # type: ignore[type-arg, unused-ignore] + def _create_blended_image(self, attack_image: np.ndarray, alpha: np.ndarray) -> np.ndarray: """ Create a blended image using the attack image and alpha transparency. @@ -256,7 +256,7 @@ def _create_blended_image(self, attack_image: np.ndarray, alpha: np.ndarray) -> return la_image - async def _save_blended_image(self, attack_image: np.ndarray, alpha: np.ndarray) -> str: # type: ignore[type-arg, unused-ignore] + async def _save_blended_image(self, attack_image: np.ndarray, alpha: np.ndarray) -> str: """ Save the blended image with transparency as a PNG file. diff --git a/pyrit/prompt_converter/unicode_confusable_converter.py b/pyrit/prompt_converter/unicode_confusable_converter.py index c623cc25bb..2a180917df 100644 --- a/pyrit/prompt_converter/unicode_confusable_converter.py +++ b/pyrit/prompt_converter/unicode_confusable_converter.py @@ -30,7 +30,7 @@ def __init__( *, source_package: Literal["confusable_homoglyphs", "confusables"] = "confusable_homoglyphs", deterministic: bool = False, - ): + ) -> None: """ Initialize the converter with the specified source package for homoglyph generation. diff --git a/pyrit/prompt_converter/unicode_replacement_converter.py b/pyrit/prompt_converter/unicode_replacement_converter.py index 232905a143..4fd2b3d087 100644 --- a/pyrit/prompt_converter/unicode_replacement_converter.py +++ b/pyrit/prompt_converter/unicode_replacement_converter.py @@ -18,7 +18,7 @@ def __init__( *, encode_spaces: bool = False, word_selection_strategy: Optional[WordSelectionStrategy] = None, - ): + ) -> None: """ Initialize the converter with the specified selection strategy. diff --git a/pyrit/prompt_converter/variation_converter.py b/pyrit/prompt_converter/variation_converter.py index 328e463072..f19a3ea07b 100644 --- a/pyrit/prompt_converter/variation_converter.py +++ b/pyrit/prompt_converter/variation_converter.py @@ -40,9 +40,9 @@ class VariationConverter(PromptConverter): def __init__( self, *, - converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[assignment] + converter_target: PromptChatTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] prompt_template: Optional[SeedPrompt] = None, - ): + ) -> None: """ Initialize the converter with the specified target and prompt template. diff --git a/pyrit/prompt_converter/word_level_converter.py b/pyrit/prompt_converter/word_level_converter.py index 7753c49528..f8e381b522 100644 --- a/pyrit/prompt_converter/word_level_converter.py +++ b/pyrit/prompt_converter/word_level_converter.py @@ -33,7 +33,7 @@ def __init__( *, word_selection_strategy: Optional[WordSelectionStrategy] = None, word_split_separator: Optional[str] = " ", - ): + ) -> None: """ Initialize the converter with the specified selection strategy. diff --git a/pyrit/prompt_converter/zalgo_converter.py b/pyrit/prompt_converter/zalgo_converter.py index c24e7a5394..6f7c11e397 100644 --- a/pyrit/prompt_converter/zalgo_converter.py +++ b/pyrit/prompt_converter/zalgo_converter.py @@ -27,7 +27,7 @@ def __init__( intensity: int = 10, seed: Optional[int] = None, word_selection_strategy: Optional[WordSelectionStrategy] = None, - ): + ) -> None: """ Initialize the converter with the specified selection parameters. diff --git a/pyrit/prompt_normalizer/normalizer_request.py b/pyrit/prompt_normalizer/normalizer_request.py index 1cfaf97f37..c030ca5278 100644 --- a/pyrit/prompt_normalizer/normalizer_request.py +++ b/pyrit/prompt_normalizer/normalizer_request.py @@ -28,7 +28,7 @@ def __init__( request_converter_configurations: list[PromptConverterConfiguration] | None = None, response_converter_configurations: list[PromptConverterConfiguration] | None = None, conversation_id: Optional[str] = None, - ): + ) -> None: """ Initialize a normalizer request. diff --git a/pyrit/prompt_target/azure_blob_storage_target.py b/pyrit/prompt_target/azure_blob_storage_target.py index ae5a96140e..5bc74a89d2 100644 --- a/pyrit/prompt_target/azure_blob_storage_target.py +++ b/pyrit/prompt_target/azure_blob_storage_target.py @@ -155,7 +155,7 @@ async def _upload_blob_async(self, file_name: str, data: bytes, content_type: st Raises: RuntimeError: If blob storage client is not initialized. """ - content_settings = ContentSettings(content_type=f"{content_type}") # type: ignore[no-untyped-call, unused-ignore] + content_settings = ContentSettings(content_type=f"{content_type}") logger.info(msg="\nUploading to Azure Storage as blob:\n\t" + file_name) if not self._client_async: diff --git a/pyrit/prompt_target/hugging_face/hugging_face_chat_target.py b/pyrit/prompt_target/hugging_face/hugging_face_chat_target.py index c9a8e3c921..9c6b5ea8a1 100644 --- a/pyrit/prompt_target/hugging_face/hugging_face_chat_target.py +++ b/pyrit/prompt_target/hugging_face/hugging_face_chat_target.py @@ -8,8 +8,8 @@ from typing import Any, Optional, cast from transformers import ( - AutoModelForCausalLM, - AutoTokenizer, + AutoModelForCausalLM, # type: ignore[ty:possibly-missing-import] + AutoTokenizer, # type: ignore[ty:possibly-missing-import] BatchEncoding, PretrainedConfig, ) @@ -273,7 +273,7 @@ async def load_model_and_tokenizer(self) -> None: ) # Move the model to the correct device - self.model = self.model.to(self.device) # type: ignore[arg-type] + self.model = self.model.to(self.device) # type: ignore[ty:invalid-argument-type] # Debug prints to check types logger.info(f"Model loaded: {type(self.model)}") @@ -330,7 +330,7 @@ async def _send_prompt_to_target_async(self, *, normalized_conversation: list[Me try: # Ensure model is on the correct device (should already be the case from `load_model_and_tokenizer`) - self.model.to(self.device) # type: ignore[arg-type] + self.model.to(self.device) # type: ignore[ty:invalid-argument-type] # Record the length of the input tokens to later extract only the generated tokens input_length = input_ids.shape[-1] @@ -353,7 +353,7 @@ async def _send_prompt_to_target_async(self, *, normalized_conversation: list[Me # Decode the assistant's response from the generated token IDs assistant_response = cast( "str", - self.tokenizer.decode(generated_tokens, skip_special_tokens=self.skip_special_tokens), + self.tokenizer.decode(generated_tokens, skip_special_tokens=self.skip_special_tokens), # type: ignore[ty:unresolved-attribute] ).strip() if not assistant_response: diff --git a/pyrit/prompt_target/openai/openai_chat_target.py b/pyrit/prompt_target/openai/openai_chat_target.py index db059d6807..e61dcbb7ce 100644 --- a/pyrit/prompt_target/openai/openai_chat_target.py +++ b/pyrit/prompt_target/openai/openai_chat_target.py @@ -622,7 +622,7 @@ async def _build_chat_messages_for_multi_modal_async( elif message_piece.converted_value_data_type == "image_path": data_base64_encoded_url = await convert_local_image_to_data_url(message_piece.converted_value) image_url_entry = {"url": data_base64_encoded_url} - entry = {"type": "image_url", "image_url": image_url_entry} # type: ignore[dict-item] + entry = {"type": "image_url", "image_url": image_url_entry} content.append(entry) elif message_piece.converted_value_data_type == "audio_path": ext = DataTypeSerializer.get_extension(message_piece.converted_value) @@ -643,7 +643,7 @@ async def _build_chat_messages_for_multi_modal_async( base64_data = await audio_serializer.read_data_base64() audio_format = ext.lower().lstrip(".") input_audio_entry = {"data": base64_data, "format": audio_format} - entry = {"type": "input_audio", "input_audio": input_audio_entry} # type: ignore[dict-item] + entry = {"type": "input_audio", "input_audio": input_audio_entry} content.append(entry) else: raise ValueError( diff --git a/pyrit/prompt_target/openai/openai_completion_target.py b/pyrit/prompt_target/openai/openai_completion_target.py index 11b430d000..590d3b2915 100644 --- a/pyrit/prompt_target/openai/openai_completion_target.py +++ b/pyrit/prompt_target/openai/openai_completion_target.py @@ -155,7 +155,7 @@ async def _send_prompt_to_target_async(self, *, normalized_conversation: list[Me # Use unified error handler - automatically detects Completion and validates response = await self._handle_openai_request( - api_call=lambda: self._client.completions.create(**request_params), # type: ignore[call-overload] + api_call=lambda: self._client.completions.create(**request_params), # type: ignore[ty:no-matching-overload] request=message, ) return [response] diff --git a/pyrit/prompt_target/openai/openai_error_handling.py b/pyrit/prompt_target/openai/openai_error_handling.py index be1d9484c4..74e09b80c0 100644 --- a/pyrit/prompt_target/openai/openai_error_handling.py +++ b/pyrit/prompt_target/openai/openai_error_handling.py @@ -74,14 +74,14 @@ def _is_content_filter_error(data: Union[dict[str, object], str]) -> bool: if isinstance(data, dict): # Check for explicit content_filter or moderation_blocked codes error_obj = data.get("error") - code = error_obj.get("code") if isinstance(error_obj, dict) else None + code = error_obj.get("code") if isinstance(error_obj, dict) else None # type: ignore[ty:invalid-argument-type] if code in ["content_filter", "moderation_blocked"]: return True # OpenAI uses "invalid_prompt" for model-level safety blocks (e.g. CBRN topics). # Only treat it as a content filter when the message indicates a safety block, # not for other invalid_prompt reasons (e.g. malformed schemas). if code == "invalid_prompt": - message = error_obj.get("message", "") if isinstance(error_obj, dict) else "" + message = error_obj.get("message", "") if isinstance(error_obj, dict) else "" # type: ignore[ty:no-matching-overload] if "limited access" in str(message).lower() or "safety" in str(message).lower(): return True # Heuristic: Azure sometimes uses other codes with policy-related content diff --git a/pyrit/prompt_target/openai/openai_realtime_target.py b/pyrit/prompt_target/openai/openai_realtime_target.py index 17816a0113..6dd34c39b1 100644 --- a/pyrit/prompt_target/openai/openai_realtime_target.py +++ b/pyrit/prompt_target/openai/openai_realtime_target.py @@ -293,7 +293,7 @@ def _set_system_prompt_and_config_vars(self, system_prompt: str) -> dict[str, An } if self.voice: - session_config["audio"]["output"]["voice"] = self.voice # type: ignore[index] + session_config["audio"]["output"]["voice"] = self.voice # type: ignore[ty:invalid-assignment] return session_config diff --git a/pyrit/prompt_target/openai/openai_tts_target.py b/pyrit/prompt_target/openai/openai_tts_target.py index 046a2eaf9a..5d38cb7041 100644 --- a/pyrit/prompt_target/openai/openai_tts_target.py +++ b/pyrit/prompt_target/openai/openai_tts_target.py @@ -148,8 +148,8 @@ async def _send_prompt_to_target_async(self, *, normalized_conversation: list[Me model=str(body_parameters["model"]), voice=str(body_parameters["voice"]), input=str(body_parameters["input"]), - response_format=body_parameters.get("response_format"), # type: ignore[arg-type] - speed=body_parameters.get("speed"), # type: ignore[arg-type] + response_format=body_parameters.get("response_format"), # type: ignore[ty:invalid-argument-type] + speed=body_parameters.get("speed"), # type: ignore[ty:invalid-argument-type] ), request=message, ) diff --git a/pyrit/prompt_target/playwright_copilot_target.py b/pyrit/prompt_target/playwright_copilot_target.py index 21439db4d3..78e0af523f 100644 --- a/pyrit/prompt_target/playwright_copilot_target.py +++ b/pyrit/prompt_target/playwright_copilot_target.py @@ -525,7 +525,7 @@ async def _wait_for_images_to_stabilize( # Return latest new message groups (re-slice to exclude historical groups) all_groups = await self._page.query_selector_all(selectors.ai_messages_group_selector) - return all_groups[initial_group_count:] # type: ignore[no-any-return, unused-ignore] + return all_groups[initial_group_count:] async def _extract_images_from_iframes(self, ai_message_groups: list[Any]) -> list[Any]: """ diff --git a/pyrit/prompt_target/prompt_shield_target.py b/pyrit/prompt_target/prompt_shield_target.py index 234ff7bea6..2df1674744 100644 --- a/pyrit/prompt_target/prompt_shield_target.py +++ b/pyrit/prompt_target/prompt_shield_target.py @@ -247,7 +247,7 @@ def _add_auth_param_to_headers(self, headers: dict[str, str]) -> None: if self._api_key: # If callable, call it to get the token if callable(self._api_key): - token = self._api_key() + token = self._api_key() # type: ignore[ty:call-top-callable] headers["Authorization"] = f"Bearer {token}" else: # String API key diff --git a/pyrit/prompt_target/text_target.py b/pyrit/prompt_target/text_target.py index d6a4cb7835..7c9f9a6474 100644 --- a/pyrit/prompt_target/text_target.py +++ b/pyrit/prompt_target/text_target.py @@ -82,13 +82,13 @@ def import_scores_from_csv(self, csv_file_path: Path) -> list[MessagePiece]: labels = json.loads(labels_str) if labels_str else None message_piece = MessagePiece( - role=row["role"], # type: ignore[arg-type] + role=row["role"], # type: ignore[ty:invalid-argument-type] original_value=row["value"], - original_value_data_type=row.get("data_type", None), # type: ignore[arg-type] + original_value_data_type=row.get("data_type", None), # type: ignore[ty:invalid-argument-type] conversation_id=row.get("conversation_id", None), sequence=int(sequence_str) if sequence_str else 0, labels=labels, # deprecated - response_error=row.get("response_error", None), # type: ignore[arg-type] + response_error=row.get("response_error", None), # type: ignore[ty:invalid-argument-type] prompt_target_identifier=self.get_identifier(), ) message_pieces.append(message_piece) diff --git a/pyrit/registry/class_registries/base_class_registry.py b/pyrit/registry/class_registries/base_class_registry.py index 6b44c6e832..810b28a214 100644 --- a/pyrit/registry/class_registries/base_class_registry.py +++ b/pyrit/registry/class_registries/base_class_registry.py @@ -143,8 +143,8 @@ def get_registry_singleton(cls) -> Self: The singleton instance of this registry class. """ if cls not in cls._instances: - cls._instances[cls] = cls() # type: ignore[assignment] - return cls._instances[cls] # type: ignore[return-value] + cls._instances[cls] = cls() # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] + return cls._instances[cls] @classmethod def reset_instance(cls) -> None: diff --git a/pyrit/registry/class_registries/initializer_registry.py b/pyrit/registry/class_registries/initializer_registry.py index a8043ea9ae..029073260c 100644 --- a/pyrit/registry/class_registries/initializer_registry.py +++ b/pyrit/registry/class_registries/initializer_registry.py @@ -107,7 +107,7 @@ def _discover(self) -> None: else: for _file_stem, _file_path, initializer_class in discover_in_directory( directory=discovery_path, - base_class=PyRITInitializer, # type: ignore[type-abstract] + base_class=PyRITInitializer, recursive=True, ): self._register_initializer( @@ -143,7 +143,7 @@ def _process_file(self, *, file_path: Path, base_class: type) -> None: and not inspect.isabstract(attr) ): self._register_initializer( - initializer_class=attr, # type: ignore[arg-type] + initializer_class=attr, ) except Exception as e: diff --git a/pyrit/registry/class_registries/scenario_registry.py b/pyrit/registry/class_registries/scenario_registry.py index d34c077ee0..77009c5437 100644 --- a/pyrit/registry/class_registries/scenario_registry.py +++ b/pyrit/registry/class_registries/scenario_registry.py @@ -109,7 +109,7 @@ def _discover_builtin_scenarios(self) -> None: for registry_name, scenario_class in discover_in_package( package_path=package_path, package_name="pyrit.scenario.scenarios", - base_class=Scenario, # type: ignore[type-abstract] + base_class=Scenario, recursive=True, ): # Skip deprecated alias classes @@ -162,9 +162,7 @@ def discover_user_scenarios(self) -> None: from pyrit.scenario.core import Scenario try: - for _, scenario_class in discover_subclasses_in_loaded_modules( - base_class=Scenario # type: ignore[type-abstract] - ): + for _, scenario_class in discover_subclasses_in_loaded_modules(base_class=Scenario): # Check if this is a user-defined class (not from pyrit.scenario.scenarios) if not scenario_class.__module__.startswith("pyrit.scenario.scenarios"): # Convert class name to snake_case for scenario name diff --git a/pyrit/registry/object_registries/attack_technique_registry.py b/pyrit/registry/object_registries/attack_technique_registry.py index 389b096720..16a7efdc9f 100644 --- a/pyrit/registry/object_registries/attack_technique_registry.py +++ b/pyrit/registry/object_registries/attack_technique_registry.py @@ -263,16 +263,16 @@ def build_strategy_class_from_specs( members[spec.name] = (spec.name, spec_tags | matched_agg_tags) # Build the enum class dynamically - strategy_cls = ScenarioStrategy(class_name, members) # type: ignore[arg-type] + strategy_cls = ScenarioStrategy(class_name, members) # Override get_aggregate_tags on the generated class - @classmethod # type: ignore[misc] + @classmethod def _get_aggregate_tags(cls: type) -> set[str]: return set(all_aggregate_tag_names) - strategy_cls.get_aggregate_tags = _get_aggregate_tags # type: ignore[method-assign, assignment] + strategy_cls.get_aggregate_tags = _get_aggregate_tags # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] - return strategy_cls # type: ignore[return-value] + return strategy_cls # type: ignore[ty:invalid-return-type] @staticmethod def build_factory_from_spec(spec: AttackTechniqueSpec) -> AttackTechniqueFactory: @@ -319,7 +319,7 @@ def build_factory_from_spec(spec: AttackTechniqueSpec) -> AttackTechniqueFactory ) return AttackTechniqueFactory( - attack_class=spec.attack_class, + attack_class=spec.attack_class, # type: ignore[ty:invalid-argument-type] attack_kwargs=kwargs or None, ) @@ -331,7 +331,7 @@ def _accepts_adversarial(attack_class: type) -> bool: Returns: bool: Whether the parameter is present in the class constructor. """ - sig = inspect.signature(attack_class.__init__) # type: ignore[misc] + sig = inspect.signature(attack_class.__init__) return "attack_adversarial_config" in sig.parameters def register_from_specs( diff --git a/pyrit/registry/object_registries/base_instance_registry.py b/pyrit/registry/object_registries/base_instance_registry.py index 3d63ee5ed6..87cab41f04 100644 --- a/pyrit/registry/object_registries/base_instance_registry.py +++ b/pyrit/registry/object_registries/base_instance_registry.py @@ -88,7 +88,7 @@ def get_registry_singleton(cls) -> Self: """ if cls not in cls._instances: cls._instances[cls] = cls() - return cls._instances[cls] # type: ignore[return-value] + return cls._instances[cls] @classmethod def reset_instance(cls) -> None: diff --git a/pyrit/scenario/core/scenario.py b/pyrit/scenario/core/scenario.py index 283636f081..34c79257ba 100644 --- a/pyrit/scenario/core/scenario.py +++ b/pyrit/scenario/core/scenario.py @@ -269,7 +269,7 @@ def _prepare_strategies( async def initialize_async( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] scenario_strategies: Optional[Sequence[ScenarioStrategy]] = None, dataset_config: Optional[DatasetConfiguration] = None, max_concurrency: int = 10, diff --git a/pyrit/scenario/core/scenario_strategy.py b/pyrit/scenario/core/scenario_strategy.py index 0d399cd948..de557d724e 100644 --- a/pyrit/scenario/core/scenario_strategy.py +++ b/pyrit/scenario/core/scenario_strategy.py @@ -272,7 +272,7 @@ def resolve(cls: type[T], strategies: Sequence[Any] | None, *, default: T) -> li if not isinstance(item, cls): continue if item.value in aggregate_tags: - for s in cls.expand({item}): + for s in cls.expand({item}): # type: ignore[ty:invalid-argument-type] if s not in seen: seen.add(s) result.append(s) diff --git a/pyrit/scenario/core/scenario_techniques.py b/pyrit/scenario/core/scenario_techniques.py index 0349214db3..61e413be1a 100644 --- a/pyrit/scenario/core/scenario_techniques.py +++ b/pyrit/scenario/core/scenario_techniques.py @@ -108,7 +108,7 @@ def get_default_adversarial_target() -> PromptChatTarget: f"Registry entry 'adversarial_chat' must support multi-turn conversations, " f"but {type(target).__name__} does not." ) - return target # type: ignore[return-value] + return target return OpenAIChatTarget(temperature=1.2) @@ -155,11 +155,11 @@ def build_scenario_techniques() -> list[AttackTechniqueSpec]: result.append( dataclasses.replace( spec, - adversarial_chat=resolved, # type: ignore[arg-type] + adversarial_chat=resolved, adversarial_chat_key=None, ) ) - elif "attack_adversarial_config" in inspect.signature(spec.attack_class.__init__).parameters: # type: ignore[misc] + elif "attack_adversarial_config" in inspect.signature(spec.attack_class.__init__).parameters: if default_adversarial is None: default_adversarial = get_default_adversarial_target() result.append(dataclasses.replace(spec, adversarial_chat=default_adversarial)) diff --git a/pyrit/scenario/printer/console_printer.py b/pyrit/scenario/printer/console_printer.py index e886ae8448..0ec99e7b5b 100644 --- a/pyrit/scenario/printer/console_printer.py +++ b/pyrit/scenario/printer/console_printer.py @@ -28,7 +28,7 @@ def __init__( indent_size: int = 2, enable_colors: bool = True, scorer_printer: Optional[ScorerPrinter] = None, - ): + ) -> None: """ Initialize the console printer. diff --git a/pyrit/scenario/scenarios/airt/cyber.py b/pyrit/scenario/scenarios/airt/cyber.py index aad06d0adf..7f0250911a 100644 --- a/pyrit/scenario/scenarios/airt/cyber.py +++ b/pyrit/scenario/scenarios/airt/cyber.py @@ -54,7 +54,7 @@ def _build_cyber_strategy() -> type[ScenarioStrategy]: cyber_specs = [s for s in SCENARIO_TECHNIQUES if s.name in _CYBER_TECHNIQUE_NAMES] - return AttackTechniqueRegistry.build_strategy_class_from_specs( + return AttackTechniqueRegistry.build_strategy_class_from_specs( # type: ignore[ty:invalid-return-type] class_name="CyberStrategy", specs=cyber_specs, aggregate_tags={ diff --git a/pyrit/scenario/scenarios/airt/jailbreak.py b/pyrit/scenario/scenarios/airt/jailbreak.py index c09927def8..1870fdc0cf 100644 --- a/pyrit/scenario/scenarios/airt/jailbreak.py +++ b/pyrit/scenario/scenarios/airt/jailbreak.py @@ -3,7 +3,7 @@ import os from pathlib import Path -from typing import Optional, Union +from typing import Any, Optional, Union from pyrit.auth import get_azure_openai_auth from pyrit.common import apply_defaults @@ -268,7 +268,7 @@ async def _get_atomic_attack_from_strategy_async( ) attack: Optional[Union[ManyShotJailbreakAttack, PromptSendingAttack, RolePlayAttack, SkeletonKeyAttack]] = None - args = { + args: dict[str, Any] = { "objective_target": self._objective_target, "attack_scoring_config": AttackScoringConfig(objective_scorer=self._objective_scorer), "attack_converter_config": converter_config, diff --git a/pyrit/scenario/scenarios/airt/leakage.py b/pyrit/scenario/scenarios/airt/leakage.py index e892fe2152..801522d82e 100644 --- a/pyrit/scenario/scenarios/airt/leakage.py +++ b/pyrit/scenario/scenarios/airt/leakage.py @@ -282,11 +282,11 @@ async def _get_atomic_attack_from_strategy_async(self, strategy: str) -> AtomicA attack_strategy = await factory() - # The factory functions return specific AttackStrategy subclasses, but mypy infers ABC - # due to the heterogeneous dict values. The types are verified by unit tests. + # The factory functions return specific AttackStrategy subclasses, but the type checker + # infers ABC due to the heterogeneous dict values. The types are verified by unit tests. return AtomicAttack( atomic_attack_name=f"leakage_{strategy}", - attack_technique=AttackTechnique(attack=attack_strategy), # type: ignore[arg-type] + attack_technique=AttackTechnique(attack=attack_strategy), seed_groups=self._seed_groups, memory_labels=self._memory_labels, ) diff --git a/pyrit/scenario/scenarios/airt/psychosocial.py b/pyrit/scenario/scenarios/airt/psychosocial.py index b8963b9264..205bd615b2 100644 --- a/pyrit/scenario/scenarios/airt/psychosocial.py +++ b/pyrit/scenario/scenarios/airt/psychosocial.py @@ -207,7 +207,7 @@ def __init__( scenario_result_id: Optional[str] = None, subharm_configs: Optional[dict[str, SubharmConfig]] = None, max_turns: int = 5, - ): + ) -> None: """ Initialize the Psychosocial Harms Scenario. @@ -412,7 +412,7 @@ def _get_scorer(self, subharm: Optional[str] = None) -> FloatScaleThresholdScore ) # Wrap with conversation scorer to evaluate full conversation history - conversation_scorer: FloatScaleScorer = create_conversation_scorer(scorer=psych_scorer) # type: ignore[assignment] + conversation_scorer: FloatScaleScorer = create_conversation_scorer(scorer=psych_scorer) # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] # Wrap with threshold scorer # threshold=1.0 means only raw score 5 counts as attack success (extremely harmful) diff --git a/pyrit/scenario/scenarios/airt/rapid_response.py b/pyrit/scenario/scenarios/airt/rapid_response.py index 1c1ee01841..41d853f214 100644 --- a/pyrit/scenario/scenarios/airt/rapid_response.py +++ b/pyrit/scenario/scenarios/airt/rapid_response.py @@ -39,7 +39,7 @@ def _build_rapid_response_strategy() -> type[ScenarioStrategy]: from pyrit.registry.tag_query import TagQuery from pyrit.scenario.core.scenario_techniques import SCENARIO_TECHNIQUES - return AttackTechniqueRegistry.build_strategy_class_from_specs( + return AttackTechniqueRegistry.build_strategy_class_from_specs( # type: ignore[ty:invalid-return-type] class_name="RapidResponseStrategy", specs=TagQuery.all("core").filter(SCENARIO_TECHNIQUES), aggregate_tags={ diff --git a/pyrit/scenario/scenarios/foundry/red_team_agent.py b/pyrit/scenario/scenarios/foundry/red_team_agent.py index 8dc32e0f92..ac41e03e8a 100644 --- a/pyrit/scenario/scenarios/foundry/red_team_agent.py +++ b/pyrit/scenario/scenarios/foundry/red_team_agent.py @@ -115,11 +115,11 @@ def __post_init__(self) -> None: def name(self) -> str: """Return a human-readable name for this composite.""" if not self.converters: - return self.attack.value if self.attack else "baseline" + return self.attack.value if self.attack else "baseline" # type: ignore[ty:invalid-return-type] if self.attack is None and len(self.converters) == 1: return str(self.converters[0].value) attack_name = self.attack.value if self.attack else "baseline" - converter_names = ", ".join(c.value for c in self.converters) + converter_names = ", ".join(c.value for c in self.converters) # type: ignore[ty:no-matching-overload] return f"ComposedStrategy({attack_name}, {converter_names})" @@ -250,7 +250,7 @@ def __init__( attack_scoring_config: Optional[AttackScoringConfig] = None, include_baseline: bool = True, scenario_result_id: Optional[str] = None, - ): + ) -> None: """ Initialize a Foundry Scenario with the specified attack strategies. @@ -296,7 +296,7 @@ def __init__( async def initialize_async( self, *, - objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[assignment] + objective_target: PromptTarget = REQUIRED_VALUE, # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] scenario_strategies: Optional[ Sequence["FoundryStrategy | FoundryComposite | ScenarioCompositeStrategy"] ] = None, @@ -332,7 +332,7 @@ async def initialize_async( memory_labels=memory_labels, ) - def _prepare_strategies( # type: ignore[override] + def _prepare_strategies( # type: ignore[ty:invalid-method-override] self, strategies: "Optional[Sequence[FoundryStrategy | FoundryComposite | ScenarioCompositeStrategy]]", ) -> list[ScenarioStrategy]: @@ -581,7 +581,7 @@ def _get_attack( # Create the adversarial config from self._adversarial_target attack_adversarial_config = AttackAdversarialConfig(target=self._adversarial_chat) - kwargs["attack_adversarial_config"] = attack_adversarial_config # type: ignore[assignment] + kwargs["attack_adversarial_config"] = attack_adversarial_config # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] # Add attack-specific kwargs if provided if attack_kwargs: @@ -590,4 +590,4 @@ def _get_attack( # Type ignore is used because this is a factory method that works with compatible # attack types. The caller is responsible for ensuring the attack type accepts # these constructor parameters. - return attack_type(**kwargs) # type: ignore[arg-type] + return attack_type(**kwargs) # type: ignore[ty:invalid-argument-type] diff --git a/pyrit/scenario/scenarios/garak/encoding.py b/pyrit/scenario/scenarios/garak/encoding.py index ccf4550456..531b11062e 100644 --- a/pyrit/scenario/scenarios/garak/encoding.py +++ b/pyrit/scenario/scenarios/garak/encoding.py @@ -175,7 +175,7 @@ def __init__( encoding_templates: Optional[Sequence[str]] = None, include_baseline: bool = True, scenario_result_id: Optional[str] = None, - ): + ) -> None: """ Initialize the Encoding Scenario. diff --git a/pyrit/score/conversation_scorer.py b/pyrit/score/conversation_scorer.py index 7e5f03e2ab..c3bcbf4f87 100644 --- a/pyrit/score/conversation_scorer.py +++ b/pyrit/score/conversation_scorer.py @@ -183,7 +183,7 @@ def create_conversation_scorer( ) # Dynamically create a class that inherits from both ConversationScorer and the scorer's base class - class DynamicConversationScorer(ConversationScorer, scorer_base_class): # type: ignore[misc, valid-type] + class DynamicConversationScorer(ConversationScorer, scorer_base_class): # type: ignore[valid-type] # type: ignore[ty:unsupported-base] """Dynamic ConversationScorer that inherits from both ConversationScorer and the wrapped scorer's base class.""" def __init__(self) -> None: diff --git a/pyrit/score/float_scale/azure_content_filter_scorer.py b/pyrit/score/float_scale/azure_content_filter_scorer.py index 8a13f5ad5a..754a0269ce 100644 --- a/pyrit/score/float_scale/azure_content_filter_scorer.py +++ b/pyrit/score/float_scale/azure_content_filter_scorer.py @@ -148,8 +148,8 @@ def __init__( if self._endpoint is not None: if callable(self._api_key): # Token provider - create an AsyncTokenCredential wrapper - credential = AsyncTokenProviderCredential(self._api_key) - self._azure_cf_client = ContentSafetyClient(self._endpoint, credential=credential) + credential = AsyncTokenProviderCredential(self._api_key) # type: ignore[ty:invalid-argument-type] + self._azure_cf_client = ContentSafetyClient(self._endpoint, credential=credential) # type: ignore[ty:invalid-argument-type] else: # String API key if not isinstance(self._api_key, str): @@ -316,7 +316,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_metadata=metadata, score_rationale="", scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) all_scores.append(score_obj) @@ -336,7 +336,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_metadata=result.metadata, score_rationale=result.rationale, scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) for result in aggregated_results diff --git a/pyrit/score/float_scale/insecure_code_scorer.py b/pyrit/score/float_scale/insecure_code_scorer.py index 45c64dab00..e4764cb0b7 100644 --- a/pyrit/score/float_scale/insecure_code_scorer.py +++ b/pyrit/score/float_scale/insecure_code_scorer.py @@ -28,7 +28,7 @@ def __init__( chat_target: PromptChatTarget, system_prompt_path: Optional[Union[str, Path]] = None, validator: Optional[ScorerPromptValidator] = None, - ): + ) -> None: """ Initialize the Insecure Code Scorer. @@ -92,7 +92,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op system_prompt=self._system_prompt, message_value=message_piece.original_value, message_data_type=message_piece.converted_value_data_type, - scored_prompt_id=message_piece.id, + scored_prompt_id=message_piece.id, # type: ignore[ty:invalid-argument-type] category=self._harm_category, objective=objective, attack_identifier=message_piece.attack_identifier, diff --git a/pyrit/score/float_scale/plagiarism_scorer.py b/pyrit/score/float_scale/plagiarism_scorer.py index 5324be3bef..2e21d4cd48 100644 --- a/pyrit/score/float_scale/plagiarism_scorer.py +++ b/pyrit/score/float_scale/plagiarism_scorer.py @@ -186,7 +186,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_metadata=None, score_type="float_scale", score_rationale="Score is deterministic.", - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] scorer_class_identifier=self.get_identifier(), ) ] diff --git a/pyrit/score/float_scale/self_ask_general_float_scale_scorer.py b/pyrit/score/float_scale/self_ask_general_float_scale_scorer.py index ae9e0acc4b..3ac1c180d3 100644 --- a/pyrit/score/float_scale/self_ask_general_float_scale_scorer.py +++ b/pyrit/score/float_scale/self_ask_general_float_scale_scorer.py @@ -142,7 +142,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op system_prompt=system_prompt, message_value=user_prompt, message_data_type=message_piece.converted_value_data_type, - scored_prompt_id=message_piece.id, + scored_prompt_id=message_piece.id, # type: ignore[ty:invalid-argument-type] category=self._score_category, objective=objective, attack_identifier=message_piece.attack_identifier, diff --git a/pyrit/score/float_scale/self_ask_likert_scorer.py b/pyrit/score/float_scale/self_ask_likert_scorer.py index c6762089b6..03a79a6e46 100644 --- a/pyrit/score/float_scale/self_ask_likert_scorer.py +++ b/pyrit/score/float_scale/self_ask_likert_scorer.py @@ -156,12 +156,12 @@ class LikertScalePaths(enum.Enum): @property def path(self) -> Path: """Get the path to the Likert scale YAML file.""" - return self.value[0] # type: ignore[no-any-return] + return self.value[0] @property def evaluation_files(self) -> Optional[LikertScaleEvalFiles]: """Get the evaluation file configuration, or None if no evaluation dataset exists.""" - return self.value[1] # type: ignore[no-any-return] + return self.value[1] class SelfAskLikertScorer(FloatScaleScorer): @@ -454,7 +454,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op system_prompt=self._system_prompt, message_value=message_piece.converted_value, message_data_type=message_piece.converted_value_data_type, - scored_prompt_id=message_piece.id, + scored_prompt_id=message_piece.id, # type: ignore[ty:invalid-argument-type] category=self._score_category, attack_identifier=message_piece.attack_identifier, objective=objective, diff --git a/pyrit/score/float_scale/self_ask_scale_scorer.py b/pyrit/score/float_scale/self_ask_scale_scorer.py index 4bf0dc2dee..fcd0cb2cf0 100644 --- a/pyrit/score/float_scale/self_ask_scale_scorer.py +++ b/pyrit/score/float_scale/self_ask_scale_scorer.py @@ -121,7 +121,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op system_prompt=self._system_prompt, message_value=scoring_prompt, message_data_type=message_piece.converted_value_data_type, - scored_prompt_id=message_piece.id, + scored_prompt_id=message_piece.id, # type: ignore[ty:invalid-argument-type] category=self._category, objective=objective, attack_identifier=message_piece.attack_identifier, diff --git a/pyrit/score/float_scale/video_float_scale_scorer.py b/pyrit/score/float_scale/video_float_scale_scorer.py index 1097dd7476..d912701dc8 100644 --- a/pyrit/score/float_scale/video_float_scale_scorer.py +++ b/pyrit/score/float_scale/video_float_scale_scorer.py @@ -106,7 +106,7 @@ def _build_identifier(self) -> ComponentIdentifier: return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] "num_sampled_frames": self._video_helper.num_sampled_frames, "has_audio_scorer": self.audio_scorer is not None, "image_objective_template": self._video_helper.image_objective_template, diff --git a/pyrit/score/printer/console_scorer_printer.py b/pyrit/score/printer/console_scorer_printer.py index 0c5772f58a..27aec712ee 100644 --- a/pyrit/score/printer/console_scorer_printer.py +++ b/pyrit/score/printer/console_scorer_printer.py @@ -27,7 +27,7 @@ class ConsoleScorerPrinter(ScorerPrinter): _SCORER_DISPLAY_PARAMS = frozenset({"scorer_type", "score_aggregator"}) _TARGET_DISPLAY_PARAMS = frozenset({"model_name", "temperature"}) - def __init__(self, *, indent_size: int = 2, enable_colors: bool = True): + def __init__(self, *, indent_size: int = 2, enable_colors: bool = True) -> None: """ Initialize the console scorer printer. diff --git a/pyrit/score/scorer.py b/pyrit/score/scorer.py index 6e2a21999d..31665037f5 100644 --- a/pyrit/score/scorer.py +++ b/pyrit/score/scorer.py @@ -61,7 +61,7 @@ class Scorer(Identifiable, abc.ABC): _identifier: Optional[ComponentIdentifier] = None - def __init__(self, *, validator: ScorerPromptValidator): + def __init__(self, *, validator: ScorerPromptValidator) -> None: """ Initialize the Scorer. @@ -355,7 +355,7 @@ async def score_text_async(self, text: str, *, objective: Optional[str] = None) ] ) - request.message_pieces[0].id = None # type: ignore[assignment] + request.message_pieces[0].id = None # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] return await self.score_async(request, objective=objective) async def score_image_async(self, image_path: str, *, objective: Optional[str] = None) -> list[Score]: @@ -379,7 +379,7 @@ async def score_image_async(self, image_path: str, *, objective: Optional[str] = ] ) - request.message_pieces[0].id = None # type: ignore[assignment] + request.message_pieces[0].id = None # type: ignore[ty:invalid-assignment, ty:invalid-parameter-default] return await self.score_async(request, objective=objective) async def score_prompts_batch_async( @@ -622,7 +622,7 @@ async def _score_value_with_llm( elif isinstance(cat_val, list): if not all(isinstance(x, str) for x in cat_val): raise ValueError("'category' must be a string or a list of strings") - normalized_category = cat_val + normalized_category = cat_val # type: ignore[ty:invalid-assignment] else: # JSON must yield either a string or a list of strings raise ValueError("'category' must be a string or a list of strings") diff --git a/pyrit/score/scorer_evaluation/human_labeled_dataset.py b/pyrit/score/scorer_evaluation/human_labeled_dataset.py index 5ac40790a4..f0f0fdcd87 100644 --- a/pyrit/score/scorer_evaluation/human_labeled_dataset.py +++ b/pyrit/score/scorer_evaluation/human_labeled_dataset.py @@ -128,7 +128,7 @@ def __init__( version: str, harm_definition: Optional[str] = None, harm_definition_version: Optional[str] = None, - ): + ) -> None: """ Initialize the HumanLabeledDataset. diff --git a/pyrit/score/scorer_evaluation/krippendorff.py b/pyrit/score/scorer_evaluation/krippendorff.py index 4afe3dcdb6..9e5f363421 100644 --- a/pyrit/score/scorer_evaluation/krippendorff.py +++ b/pyrit/score/scorer_evaluation/krippendorff.py @@ -17,10 +17,10 @@ def _validate_and_prepare_data( - reliability_data: np.ndarray, # type: ignore[type-arg, unused-ignore] + reliability_data: np.ndarray, level_of_measurement: str, missing: float | None, -) -> tuple[np.ndarray, np.ndarray, np.ndarray]: # type: ignore[type-arg, unused-ignore] +) -> tuple[np.ndarray, np.ndarray, np.ndarray]: """ Validate inputs and prepare data for reliability calculation. @@ -60,10 +60,10 @@ def _validate_and_prepare_data( def _build_value_counts_matrix( - data: np.ndarray, # type: ignore[type-arg, unused-ignore] - valid_mask: np.ndarray, # type: ignore[type-arg, unused-ignore] - categories: np.ndarray, # type: ignore[type-arg, unused-ignore] -) -> np.ndarray: # type: ignore[type-arg, unused-ignore] + data: np.ndarray, + valid_mask: np.ndarray, + categories: np.ndarray, +) -> np.ndarray: """ Build matrix counting how many raters assigned each category to each item. @@ -92,8 +92,8 @@ def _build_value_counts_matrix( def _build_coincidence_matrix( - value_counts: np.ndarray, # type: ignore[type-arg, unused-ignore] -) -> np.ndarray: # type: ignore[type-arg, unused-ignore] + value_counts: np.ndarray, +) -> np.ndarray: """ Build coincidence matrix from value counts. @@ -129,8 +129,8 @@ def _build_coincidence_matrix( def _build_expected_matrix( - coincidence_matrix: np.ndarray, # type: ignore[type-arg, unused-ignore] -) -> tuple[np.ndarray, np.ndarray, float]: # type: ignore[type-arg, unused-ignore] + coincidence_matrix: np.ndarray, +) -> tuple[np.ndarray, np.ndarray, float]: """ Build expected coincidence matrix from observed coincidences. @@ -157,8 +157,8 @@ def _build_expected_matrix( def _build_ordinal_distance_matrix( num_categories: int, - n_v: np.ndarray, # type: ignore[type-arg, unused-ignore] -) -> np.ndarray: # type: ignore[type-arg, unused-ignore] + n_v: np.ndarray, +) -> np.ndarray: """ Build ordinal distance matrix using category marginals. @@ -213,7 +213,7 @@ def _compute_alpha_from_disagreements( def krippendorff_alpha( - reliability_data: np.ndarray, # type: ignore[type-arg, unused-ignore] # shape: (num_raters_or_trials, num_items); dtype float + reliability_data: np.ndarray, # shape: (num_raters_or_trials, num_items); dtype float level_of_measurement: str = "ordinal", missing: float | None = np.nan, ) -> float: diff --git a/pyrit/score/scorer_evaluation/scorer_evaluator.py b/pyrit/score/scorer_evaluation/scorer_evaluator.py index be931d0b01..ff16fcef09 100644 --- a/pyrit/score/scorer_evaluation/scorer_evaluator.py +++ b/pyrit/score/scorer_evaluation/scorer_evaluator.py @@ -82,7 +82,7 @@ class ScorerEvaluator(abc.ABC): # Subclasses must define the expected metrics type expected_metrics_type: MetricsType - def __init__(self, scorer: Scorer): + def __init__(self, scorer: Scorer) -> None: """ Initialize the ScorerEvaluator with a scorer. @@ -468,8 +468,8 @@ def _validate_and_extract_data( def _compute_metrics( self, *, - all_human_scores: np.ndarray, # type: ignore[type-arg, unused-ignore] - all_model_scores: np.ndarray, # type: ignore[type-arg, unused-ignore] + all_human_scores: np.ndarray, + all_model_scores: np.ndarray, num_scorer_trials: int, dataset_name: Optional[str] = None, dataset_version: Optional[str] = None, @@ -566,8 +566,8 @@ def _validate_and_extract_data( def _compute_metrics( self, *, - all_human_scores: np.ndarray, # type: ignore[type-arg, unused-ignore] - all_model_scores: np.ndarray, # type: ignore[type-arg, unused-ignore] + all_human_scores: np.ndarray, + all_model_scores: np.ndarray, num_scorer_trials: int, dataset_name: Optional[str] = None, dataset_version: Optional[str] = None, @@ -668,8 +668,8 @@ def _validate_and_extract_data( def _compute_metrics( self, *, - all_human_scores: np.ndarray, # type: ignore[type-arg, unused-ignore] - all_model_scores: np.ndarray, # type: ignore[type-arg, unused-ignore] + all_human_scores: np.ndarray, + all_model_scores: np.ndarray, num_scorer_trials: int, dataset_name: Optional[str] = None, dataset_version: Optional[str] = None, diff --git a/pyrit/score/scorer_evaluation/scorer_metrics.py b/pyrit/score/scorer_evaluation/scorer_metrics.py index 81f254d9b9..0dbccec577 100644 --- a/pyrit/score/scorer_evaluation/scorer_metrics.py +++ b/pyrit/score/scorer_evaluation/scorer_metrics.py @@ -43,7 +43,7 @@ class ScorerMetrics: num_scorer_trials: int = field(default=1, kw_only=True) dataset_name: Optional[str] = field(default=None, kw_only=True) dataset_version: Optional[str] = field(default=None, kw_only=True) - trial_scores: Optional[np.ndarray] = field(default=None, kw_only=True) # type: ignore[type-arg, unused-ignore] + trial_scores: Optional[np.ndarray] = field(default=None, kw_only=True) average_score_time_seconds: float = field(default=0.0, kw_only=True) def to_json(self) -> str: diff --git a/pyrit/score/true_false/decoding_scorer.py b/pyrit/score/true_false/decoding_scorer.py index 2a4e765f5e..060ef06a6e 100644 --- a/pyrit/score/true_false/decoding_scorer.py +++ b/pyrit/score/true_false/decoding_scorer.py @@ -61,7 +61,7 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] "text_matcher": self._text_matcher.__class__.__name__, }, ) @@ -111,7 +111,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_category=self._score_categories, score_rationale="", scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) ] diff --git a/pyrit/score/true_false/float_scale_threshold_scorer.py b/pyrit/score/true_false/float_scale_threshold_scorer.py index d77a7abcdf..5d35d52d0d 100644 --- a/pyrit/score/true_false/float_scale_threshold_scorer.py +++ b/pyrit/score/true_false/float_scale_threshold_scorer.py @@ -64,9 +64,9 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] "threshold": self._threshold, - "float_scale_aggregator": self._float_scale_aggregator.__name__, + "float_scale_aggregator": self._float_scale_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "sub_scorers": [self._scorer.get_identifier()], diff --git a/pyrit/score/true_false/gandalf_scorer.py b/pyrit/score/true_false/gandalf_scorer.py index 2aab7c264e..5ace770d42 100644 --- a/pyrit/score/true_false/gandalf_scorer.py +++ b/pyrit/score/true_false/gandalf_scorer.py @@ -64,7 +64,7 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "prompt_target": self._prompt_target.get_identifier(), @@ -170,7 +170,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_value_description=score_description, score_rationale="No password found in text.", score_metadata=None, - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] scorer_class_identifier=self.get_identifier(), objective=objective, ) @@ -195,7 +195,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_value="True", score_category=[self._defender], score_metadata=None, - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] scorer_class_identifier=self.get_identifier(), objective=objective, ) @@ -207,7 +207,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_value="False", score_category=[self._defender], score_metadata=None, - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] scorer_class_identifier=self.get_identifier(), objective=objective, ) diff --git a/pyrit/score/true_false/markdown_injection.py b/pyrit/score/true_false/markdown_injection.py index 27aecda5ee..583504a9cf 100644 --- a/pyrit/score/true_false/markdown_injection.py +++ b/pyrit/score/true_false/markdown_injection.py @@ -52,7 +52,7 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, ) @@ -84,7 +84,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_category=[self._category], score_rationale="", scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) ] diff --git a/pyrit/score/true_false/prompt_shield_scorer.py b/pyrit/score/true_false/prompt_shield_scorer.py index 5b3f067bb3..65234e5c66 100644 --- a/pyrit/score/true_false/prompt_shield_scorer.py +++ b/pyrit/score/true_false/prompt_shield_scorer.py @@ -58,7 +58,7 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "prompt_target": self._prompt_target.get_identifier(), @@ -100,10 +100,10 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_value=str(result), score_value_description="True if an attack or jailbreak has been detected, else False.", score_category=["attack_detection"], - score_metadata=meta, + score_metadata=meta, # type: ignore[ty:invalid-argument-type] score_rationale="", scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) diff --git a/pyrit/score/true_false/question_answer_scorer.py b/pyrit/score/true_false/question_answer_scorer.py index ea6b0b4e4c..f4e035e49f 100644 --- a/pyrit/score/true_false/question_answer_scorer.py +++ b/pyrit/score/true_false/question_answer_scorer.py @@ -62,7 +62,7 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] "correct_answer_matching_patterns": self._correct_answer_matching_patterns, }, ) @@ -106,7 +106,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op else "No matching text found in response" ), scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) ] diff --git a/pyrit/score/true_false/self_ask_category_scorer.py b/pyrit/score/true_false/self_ask_category_scorer.py index 7102ba3af6..03e54d7810 100644 --- a/pyrit/score/true_false/self_ask_category_scorer.py +++ b/pyrit/score/true_false/self_ask_category_scorer.py @@ -88,7 +88,7 @@ def _build_identifier(self) -> ComponentIdentifier: return self._create_identifier( params={ "system_prompt_template": self._system_prompt, - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "prompt_target": self._prompt_target.get_identifier(), diff --git a/pyrit/score/true_false/self_ask_general_true_false_scorer.py b/pyrit/score/true_false/self_ask_general_true_false_scorer.py index 44bb362748..23eb3d5aed 100644 --- a/pyrit/score/true_false/self_ask_general_true_false_scorer.py +++ b/pyrit/score/true_false/self_ask_general_true_false_scorer.py @@ -98,7 +98,7 @@ def _build_identifier(self) -> ComponentIdentifier: params={ "system_prompt_template": self._system_prompt_format_string, "user_prompt_template": self._prompt_format_string, - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "prompt_target": self._prompt_target.get_identifier(), diff --git a/pyrit/score/true_false/self_ask_refusal_scorer.py b/pyrit/score/true_false/self_ask_refusal_scorer.py index cf9b30f1d8..7ab4233879 100644 --- a/pyrit/score/true_false/self_ask_refusal_scorer.py +++ b/pyrit/score/true_false/self_ask_refusal_scorer.py @@ -125,7 +125,7 @@ def _build_identifier(self) -> ComponentIdentifier: params={ "system_prompt_template": self._system_prompt, "user_prompt_template": self._prompt_format_string, - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "prompt_target": self._prompt_target.get_identifier(), @@ -154,7 +154,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_category=self._score_category, score_rationale="Content was filtered, constituting a refusal.", scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) ] @@ -169,7 +169,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_category=self._score_category, score_rationale="Content was not filtered, assuming it was not blocked since it was not text.", scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) ] diff --git a/pyrit/score/true_false/self_ask_true_false_scorer.py b/pyrit/score/true_false/self_ask_true_false_scorer.py index d79060fcb4..47e38122f7 100644 --- a/pyrit/score/true_false/self_ask_true_false_scorer.py +++ b/pyrit/score/true_false/self_ask_true_false_scorer.py @@ -44,7 +44,14 @@ class TrueFalseQuestion: This is sent to an LLM and can be used as an alternative to a yaml file from TrueFalseQuestionPaths. """ - def __init__(self, *, true_description: str, false_description: str = "", category: str = "", metadata: str = ""): + def __init__( + self, + *, + true_description: str, + false_description: str = "", + category: str = "", + metadata: str = "", + ) -> None: """ Initialize a TrueFalseQuestion instance. @@ -170,7 +177,7 @@ def _build_identifier(self) -> ComponentIdentifier: params={ "system_prompt_template": self._system_prompt, "user_prompt_template": "objective: {objective}\nresponse: {response}", - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "prompt_target": self._prompt_target.get_identifier(), diff --git a/pyrit/score/true_false/substring_scorer.py b/pyrit/score/true_false/substring_scorer.py index 38ab69a30a..97ba4835d8 100644 --- a/pyrit/score/true_false/substring_scorer.py +++ b/pyrit/score/true_false/substring_scorer.py @@ -60,7 +60,7 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] "substring": self._substring, "text_matcher": self._text_matcher.__class__.__name__, }, @@ -90,7 +90,7 @@ async def _score_piece_async(self, message_piece: MessagePiece, *, objective: Op score_category=self._score_categories, score_rationale="", scorer_class_identifier=self.get_identifier(), - message_piece_id=message_piece.id, + message_piece_id=message_piece.id, # type: ignore[ty:invalid-argument-type] objective=objective, ) ] diff --git a/pyrit/score/true_false/true_false_composite_scorer.py b/pyrit/score/true_false/true_false_composite_scorer.py index 45d0dc4cdb..d40d3874b3 100644 --- a/pyrit/score/true_false/true_false_composite_scorer.py +++ b/pyrit/score/true_false/true_false_composite_scorer.py @@ -62,7 +62,7 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "sub_scorers": [s.get_identifier() for s in self._scorers], diff --git a/pyrit/score/true_false/true_false_inverter_scorer.py b/pyrit/score/true_false/true_false_inverter_scorer.py index 3fd97cf9cd..5b3a1404cd 100644 --- a/pyrit/score/true_false/true_false_inverter_scorer.py +++ b/pyrit/score/true_false/true_false_inverter_scorer.py @@ -40,7 +40,7 @@ def _build_identifier(self) -> ComponentIdentifier: """ return self._create_identifier( params={ - "score_aggregator": self._score_aggregator.__name__, + "score_aggregator": self._score_aggregator.__name__, # type: ignore[ty:unresolved-attribute] }, children={ "sub_scorers": [self._scorer.get_identifier()], diff --git a/pyrit/score/true_false/true_false_score_aggregator.py b/pyrit/score/true_false/true_false_score_aggregator.py index b0b1df7eea..4a04313599 100644 --- a/pyrit/score/true_false/true_false_score_aggregator.py +++ b/pyrit/score/true_false/true_false_score_aggregator.py @@ -116,7 +116,7 @@ def _create_binary_aggregator( """ return _create_aggregator( name, - result_func=lambda bs, _op=op: functools.reduce(_op, bs), # type: ignore[misc] + result_func=lambda bs, _op=op: functools.reduce(_op, bs), true_msg=true_msg, false_msg=false_msg, ) diff --git a/pyrit/setup/initialization.py b/pyrit/setup/initialization.py index f826661573..6e3f89b861 100644 --- a/pyrit/setup/initialization.py +++ b/pyrit/setup/initialization.py @@ -274,13 +274,13 @@ async def initialize_pyrit_async( if memory_db_type == IN_MEMORY: logger.info("Using in-memory SQLite database.") - memory = SQLiteMemory(db_path=":memory:", **memory_instance_kwargs) + memory = SQLiteMemory(db_path=":memory:", **memory_instance_kwargs) # type: ignore[ty:invalid-assignment] elif memory_db_type == SQLITE: logger.info("Using persistent SQLite database.") - memory = SQLiteMemory(**memory_instance_kwargs) + memory = SQLiteMemory(**memory_instance_kwargs) # type: ignore[ty:invalid-assignment] elif memory_db_type == AZURE_SQL: logger.info("Using AzureSQL database.") - memory = AzureSQLMemory(**memory_instance_kwargs) + memory = AzureSQLMemory(**memory_instance_kwargs) # type: ignore[ty:invalid-assignment] else: raise ValueError( f"Memory database type '{memory_db_type}' is not a supported type {get_args(MemoryDatabaseType)}" diff --git a/pyrit/setup/initializers/airt.py b/pyrit/setup/initializers/airt.py index 8fc62ea5e0..8a5247d527 100644 --- a/pyrit/setup/initializers/airt.py +++ b/pyrit/setup/initializers/airt.py @@ -145,20 +145,24 @@ async def initialize_async(self) -> None: # 1. Setup converter target self._setup_converter_target( - endpoint=converter_endpoint, api_key=converter_api_key, model_name=converter_model_name or "" + endpoint=converter_endpoint, + api_key=converter_api_key, # type: ignore[ty:invalid-argument-type] + model_name=converter_model_name or "", ) # 2. Setup scorers self._setup_scorers( endpoint=scorer_endpoint, - api_key=scorer_api_key, + api_key=scorer_api_key, # type: ignore[ty:invalid-argument-type] content_safety_api_key=content_safety_api_key, model_name=scorer_model_name or "", ) # 3. Setup adversarial targets self._setup_adversarial_targets( - endpoint=converter_endpoint, api_key=converter_api_key, model_name=converter_model_name or "" + endpoint=converter_endpoint, + api_key=converter_api_key, # type: ignore[ty:invalid-argument-type] + model_name=converter_model_name or "", ) def _setup_converter_target(self, *, endpoint: str, api_key: str, model_name: str) -> None: diff --git a/pyrit/setup/initializers/components/scorers.py b/pyrit/setup/initializers/components/scorers.py index a246990863..b9ba987c78 100644 --- a/pyrit/setup/initializers/components/scorers.py +++ b/pyrit/setup/initializers/components/scorers.py @@ -387,7 +387,7 @@ def _register_likert_scorers(self) -> None: scorer_name = f"likert_{scale.name.lower().removesuffix('_scale')}_gpt4o" self._try_register( name=scorer_name, - factory=lambda s=scale: SelfAskLikertScorer( # type: ignore[misc] + factory=lambda s=scale: SelfAskLikertScorer( chat_target=self._require_dependency(gpt4o, name=GPT4O_TARGET), likert_scale=s, ), @@ -491,13 +491,10 @@ def _register_compound_objective_scorers(self) -> None: name=ACS_WITH_REFUSAL, factory=lambda: TrueFalseCompositeScorer( aggregator=TrueFalseScoreAggregator.AND, - scorers=cast( - "list[TrueFalseScorer]", - [ - self._require_dependency(acs, name="acs_threshold"), - TrueFalseInverterScorer(scorer=self._require_dependency(refusal, name="refusal")), - ], - ), + scorers=[ + self._require_dependency(acs, name="acs_threshold"), + TrueFalseInverterScorer(scorer=self._require_dependency(refusal, name="refusal")), + ], ), required_targets=[acs, refusal], tags=composite_tag, @@ -506,13 +503,10 @@ def _register_compound_objective_scorers(self) -> None: name=SCALE_AND_REFUSAL, factory=lambda: TrueFalseCompositeScorer( aggregator=TrueFalseScoreAggregator.AND, - scorers=cast( - "list[TrueFalseScorer]", - [ - self._require_dependency(scale, name="scale"), - TrueFalseInverterScorer(scorer=self._require_dependency(refusal, name="refusal")), - ], - ), + scorers=[ + self._require_dependency(scale, name="scale"), + TrueFalseInverterScorer(scorer=self._require_dependency(refusal, name="refusal")), + ], ), required_targets=[scale, refusal], tags=composite_tag, @@ -608,7 +602,7 @@ def _get_chat_target(self, target_name: str) -> "PromptChatTarget | None": PromptChatTarget | None: The chat target instance if found, otherwise None. """ target_registry = TargetRegistry.get_registry_singleton() - return target_registry.get_instance_by_name(target_name) # type: ignore[return-value] + return target_registry.get_instance_by_name(target_name) def _require_dependency(self, value: RequiredDependencyT | None, *, name: str) -> RequiredDependencyT: """ diff --git a/pyrit/setup/initializers/pyrit_initializer.py b/pyrit/setup/initializers/pyrit_initializer.py index 863954566d..bda2460c0f 100644 --- a/pyrit/setup/initializers/pyrit_initializer.py +++ b/pyrit/setup/initializers/pyrit_initializer.py @@ -355,7 +355,7 @@ async def get_info_async(cls) -> dict[str, Any]: # Add supported parameters if any are declared if instance.supported_parameters: - base_info["supported_parameters"] = [ + base_info["supported_parameters"] = [ # type: ignore[ty:invalid-assignment] { "name": p.name, "description": p.description, @@ -367,7 +367,7 @@ async def get_info_async(cls) -> dict[str, Any]: # Add required environment variables if any are defined if instance.required_env_vars: - base_info["required_env_vars"] = instance.required_env_vars + base_info["required_env_vars"] = instance.required_env_vars # type: ignore[ty:invalid-assignment] # Add dynamic default values information try: diff --git a/pyrit/setup/initializers/simple.py b/pyrit/setup/initializers/simple.py index b50b5f8710..f49b4e79f2 100644 --- a/pyrit/setup/initializers/simple.py +++ b/pyrit/setup/initializers/simple.py @@ -9,6 +9,7 @@ """ import os +from collections.abc import Awaitable, Callable from pyrit.common.apply_defaults import set_default_value, set_global_variable from pyrit.executor.attack import ( @@ -83,7 +84,7 @@ def required_env_vars(self) -> list[str]: "OPENAI_CHAT_MODEL", ] - def _get_api_key(self): # type: ignore[no-untyped-def] + def _get_api_key(self) -> str | Callable[[], Awaitable[str]]: """ Get the API key or Entra auth token provider. @@ -122,16 +123,16 @@ async def initialize_async(self) -> None: 3. Adversarial target configurations 4. Default values for attack types """ - api_key = self._get_api_key() # type: ignore[no-untyped-call] + api_key = self._get_api_key() # 1. Setup converter target - self._setup_converter_target(api_key=api_key) + self._setup_converter_target(api_key=api_key) # type: ignore[ty:invalid-argument-type] # 2. Setup scorers - self._setup_scorers(api_key=api_key) + self._setup_scorers(api_key=api_key) # type: ignore[ty:invalid-argument-type] # 3. Setup adversarial targets - self._setup_adversarial_targets(api_key=api_key) + self._setup_adversarial_targets(api_key=api_key) # type: ignore[ty:invalid-argument-type] def _setup_converter_target(self, *, api_key: str) -> None: """Set up the default converter target configuration.""" diff --git a/tests/unit/cli/test_cli_args.py b/tests/unit/cli/test_cli_args.py new file mode 100644 index 0000000000..c8e2cab090 --- /dev/null +++ b/tests/unit/cli/test_cli_args.py @@ -0,0 +1,25 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. + +import pytest + +from pyrit.cli._cli_args import _argparse_validator + + +def test_argparse_validator_no_params_raises(): + """Validator with zero parameters should raise ValueError.""" + no_param_func = eval("lambda: None") + with pytest.raises(ValueError, match="must have at least one parameter"): + _argparse_validator(no_param_func) + + +def test_argparse_validator_wraps_keyword_only(): + """Validator with keyword-only param should work via positional call.""" + + def validate_name(*, name: str) -> str: + if not name: + raise ValueError("name is required") + return name.upper() + + wrapped = _argparse_validator(validate_name) + assert wrapped("hello") == "HELLO" diff --git a/tests/unit/prompt_target/target/test_prompt_shield_target.py b/tests/unit/prompt_target/target/test_prompt_shield_target.py index 4443080f62..118fd7769f 100644 --- a/tests/unit/prompt_target/target/test_prompt_shield_target.py +++ b/tests/unit/prompt_target/target/test_prompt_shield_target.py @@ -112,6 +112,26 @@ def test_token_provider_authentication(): assert callable(target._api_key) +def test_add_auth_header_with_callable_api_key(): + """Test that _add_auth_param_to_headers calls the token provider and sets Bearer token.""" + token_provider = MagicMock(return_value="test_token") + target = PromptShieldTarget(endpoint="https://test.endpoint.com", api_key=token_provider) + + headers: dict[str, str] = {} + target._add_auth_param_to_headers(headers) + token_provider.assert_called_once() + assert headers["Authorization"] == "Bearer test_token" + + +def test_add_auth_header_with_string_api_key(): + """Test that _add_auth_param_to_headers sets Ocp-Apim-Subscription-Key for string keys.""" + target = PromptShieldTarget(endpoint="https://test.endpoint.com", api_key="my_key") + + headers: dict[str, str] = {} + target._add_auth_param_to_headers(headers) + assert headers["Ocp-Apim-Subscription-Key"] == "my_key" + + def test_init_raises_when_endpoint_none(): """Guard at line 98: endpoint_value is None raises ValueError.""" with patch("pyrit.prompt_target.prompt_shield_target.default_values") as mock_dv: diff --git a/uv.lock b/uv.lock index 3fc940caf9..fb9b64e9f7 100644 --- a/uv.lock +++ b/uv.lock @@ -3046,79 +3046,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, ] -[[package]] -name = "librt" -version = "0.7.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/29/47f29026ca17f35cf299290292d5f8331f5077364974b7675a353179afa2/librt-0.7.7.tar.gz", hash = "sha256:81d957b069fed1890953c3b9c3895c7689960f233eea9a1d9607f71ce7f00b2c", size = 145910, upload-time = "2026-01-01T23:52:22.87Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/84/2cfb1f3b9b60bab52e16a220c931223fc8e963d0d7bb9132bef012aafc3f/librt-0.7.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4836c5645f40fbdc275e5670819bde5ab5f2e882290d304e3c6ddab1576a6d0", size = 54709, upload-time = "2026-01-01T23:50:48.326Z" }, - { url = "https://files.pythonhosted.org/packages/19/a1/3127b277e9d3784a8040a54e8396d9ae5c64d6684dc6db4b4089b0eedcfb/librt-0.7.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae8aec43117a645a31e5f60e9e3a0797492e747823b9bda6972d521b436b4e8", size = 56658, upload-time = "2026-01-01T23:50:49.74Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e9/b91b093a5c42eb218120445f3fef82e0b977fa2225f4d6fc133d25cdf86a/librt-0.7.7-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:aea05f701ccd2a76b34f0daf47ca5068176ff553510b614770c90d76ac88df06", size = 161026, upload-time = "2026-01-01T23:50:50.853Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/1ded77d5976a79d7057af4a010d577ce4f473ff280984e68f4974a3281e5/librt-0.7.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b16ccaeff0ed4355dfb76fe1ea7a5d6d03b5ad27f295f77ee0557bc20a72495", size = 169529, upload-time = "2026-01-01T23:50:52.24Z" }, - { url = "https://files.pythonhosted.org/packages/da/6e/6ca5bdaa701e15f05000ac1a4c5d1475c422d3484bd3d1ca9e8c2f5be167/librt-0.7.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c48c7e150c095d5e3cea7452347ba26094be905d6099d24f9319a8b475fcd3e0", size = 183271, upload-time = "2026-01-01T23:50:55.287Z" }, - { url = "https://files.pythonhosted.org/packages/e7/2d/55c0e38073997b4bbb5ddff25b6d1bbba8c2f76f50afe5bb9c844b702f34/librt-0.7.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4dcee2f921a8632636d1c37f1bbdb8841d15666d119aa61e5399c5268e7ce02e", size = 179039, upload-time = "2026-01-01T23:50:56.807Z" }, - { url = "https://files.pythonhosted.org/packages/33/4e/3662a41ae8bb81b226f3968426293517b271d34d4e9fd4b59fc511f1ae40/librt-0.7.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14ef0f4ac3728ffd85bfc58e2f2f48fb4ef4fa871876f13a73a7381d10a9f77c", size = 173505, upload-time = "2026-01-01T23:50:58.291Z" }, - { url = "https://files.pythonhosted.org/packages/f8/5d/cf768deb8bdcbac5f8c21fcb32dd483d038d88c529fd351bbe50590b945d/librt-0.7.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e4ab69fa37f8090f2d971a5d2bc606c7401170dbdae083c393d6cbf439cb45b8", size = 193570, upload-time = "2026-01-01T23:50:59.546Z" }, - { url = "https://files.pythonhosted.org/packages/a1/ea/ee70effd13f1d651976d83a2812391f6203971740705e3c0900db75d4bce/librt-0.7.7-cp310-cp310-win32.whl", hash = "sha256:4bf3cc46d553693382d2abf5f5bd493d71bb0f50a7c0beab18aa13a5545c8900", size = 42600, upload-time = "2026-01-01T23:51:00.694Z" }, - { url = "https://files.pythonhosted.org/packages/f0/eb/dc098730f281cba76c279b71783f5de2edcba3b880c1ab84a093ef826062/librt-0.7.7-cp310-cp310-win_amd64.whl", hash = "sha256:f0c8fe5aeadd8a0e5b0598f8a6ee3533135ca50fd3f20f130f9d72baf5c6ac58", size = 48977, upload-time = "2026-01-01T23:51:01.726Z" }, - { url = "https://files.pythonhosted.org/packages/f0/56/30b5c342518005546df78841cb0820ae85a17e7d07d521c10ef367306d0d/librt-0.7.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a487b71fbf8a9edb72a8c7a456dda0184642d99cd007bc819c0b7ab93676a8ee", size = 54709, upload-time = "2026-01-01T23:51:02.774Z" }, - { url = "https://files.pythonhosted.org/packages/72/78/9f120e3920b22504d4f3835e28b55acc2cc47c9586d2e1b6ba04c3c1bf01/librt-0.7.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f4d4efb218264ecf0f8516196c9e2d1a0679d9fb3bb15df1155a35220062eba8", size = 56663, upload-time = "2026-01-01T23:51:03.838Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ea/7d7a1ee7dfc1151836028eba25629afcf45b56bbc721293e41aa2e9b8934/librt-0.7.7-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b8bb331aad734b059c4b450cd0a225652f16889e286b2345af5e2c3c625c3d85", size = 161705, upload-time = "2026-01-01T23:51:04.917Z" }, - { url = "https://files.pythonhosted.org/packages/45/a5/952bc840ac8917fbcefd6bc5f51ad02b89721729814f3e2bfcc1337a76d6/librt-0.7.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:467dbd7443bda08338fc8ad701ed38cef48194017554f4c798b0a237904b3f99", size = 171029, upload-time = "2026-01-01T23:51:06.09Z" }, - { url = "https://files.pythonhosted.org/packages/fa/bf/c017ff7da82dc9192cf40d5e802a48a25d00e7639b6465cfdcee5893a22c/librt-0.7.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50d1d1ee813d2d1a3baf2873634ba506b263032418d16287c92ec1cc9c1a00cb", size = 184704, upload-time = "2026-01-01T23:51:07.549Z" }, - { url = "https://files.pythonhosted.org/packages/77/ec/72f3dd39d2cdfd6402ab10836dc9cbf854d145226062a185b419c4f1624a/librt-0.7.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7e5070cf3ec92d98f57574da0224f8c73faf1ddd6d8afa0b8c9f6e86997bc74", size = 180719, upload-time = "2026-01-01T23:51:09.062Z" }, - { url = "https://files.pythonhosted.org/packages/78/86/06e7a1a81b246f3313bf515dd9613a1c81583e6fd7843a9f4d625c4e926d/librt-0.7.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bdb9f3d865b2dafe7f9ad7f30ef563c80d0ddd2fdc8cc9b8e4f242f475e34d75", size = 174537, upload-time = "2026-01-01T23:51:10.611Z" }, - { url = "https://files.pythonhosted.org/packages/83/08/f9fb2edc9c7a76e95b2924ce81d545673f5b034e8c5dd92159d1c7dae0c6/librt-0.7.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8185c8497d45164e256376f9da5aed2bb26ff636c798c9dabe313b90e9f25b28", size = 195238, upload-time = "2026-01-01T23:51:11.762Z" }, - { url = "https://files.pythonhosted.org/packages/ba/56/ea2d2489d3ea1f47b301120e03a099e22de7b32c93df9a211e6ff4f9bf38/librt-0.7.7-cp311-cp311-win32.whl", hash = "sha256:44d63ce643f34a903f09ff7ca355aae019a3730c7afd6a3c037d569beeb5d151", size = 42939, upload-time = "2026-01-01T23:51:13.192Z" }, - { url = "https://files.pythonhosted.org/packages/58/7b/c288f417e42ba2a037f1c0753219e277b33090ed4f72f292fb6fe175db4c/librt-0.7.7-cp311-cp311-win_amd64.whl", hash = "sha256:7d13cc340b3b82134f8038a2bfe7137093693dcad8ba5773da18f95ad6b77a8a", size = 49240, upload-time = "2026-01-01T23:51:14.264Z" }, - { url = "https://files.pythonhosted.org/packages/7c/24/738eb33a6c1516fdb2dfd2a35db6e5300f7616679b573585be0409bc6890/librt-0.7.7-cp311-cp311-win_arm64.whl", hash = "sha256:983de36b5a83fe9222f4f7dcd071f9b1ac6f3f17c0af0238dadfb8229588f890", size = 42613, upload-time = "2026-01-01T23:51:15.268Z" }, - { url = "https://files.pythonhosted.org/packages/56/72/1cd9d752070011641e8aee046c851912d5f196ecd726fffa7aed2070f3e0/librt-0.7.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2a85a1fc4ed11ea0eb0a632459ce004a2d14afc085a50ae3463cd3dfe1ce43fc", size = 55687, upload-time = "2026-01-01T23:51:16.291Z" }, - { url = "https://files.pythonhosted.org/packages/50/aa/d5a1d4221c4fe7e76ae1459d24d6037783cb83c7645164c07d7daf1576ec/librt-0.7.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c87654e29a35938baead1c4559858f346f4a2a7588574a14d784f300ffba0efd", size = 57136, upload-time = "2026-01-01T23:51:17.363Z" }, - { url = "https://files.pythonhosted.org/packages/23/6f/0c86b5cb5e7ef63208c8cc22534df10ecc5278efc0d47fb8815577f3ca2f/librt-0.7.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c9faaebb1c6212c20afd8043cd6ed9de0a47d77f91a6b5b48f4e46ed470703fe", size = 165320, upload-time = "2026-01-01T23:51:18.455Z" }, - { url = "https://files.pythonhosted.org/packages/16/37/df4652690c29f645ffe405b58285a4109e9fe855c5bb56e817e3e75840b3/librt-0.7.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1908c3e5a5ef86b23391448b47759298f87f997c3bd153a770828f58c2bb4630", size = 174216, upload-time = "2026-01-01T23:51:19.599Z" }, - { url = "https://files.pythonhosted.org/packages/9a/d6/d3afe071910a43133ec9c0f3e4ce99ee6df0d4e44e4bddf4b9e1c6ed41cc/librt-0.7.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dbc4900e95a98fc0729523be9d93a8fedebb026f32ed9ffc08acd82e3e181503", size = 189005, upload-time = "2026-01-01T23:51:21.052Z" }, - { url = "https://files.pythonhosted.org/packages/d5/18/74060a870fe2d9fd9f47824eba6717ce7ce03124a0d1e85498e0e7efc1b2/librt-0.7.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7ea4e1fbd253e5c68ea0fe63d08577f9d288a73f17d82f652ebc61fa48d878d", size = 183961, upload-time = "2026-01-01T23:51:22.493Z" }, - { url = "https://files.pythonhosted.org/packages/7c/5e/918a86c66304af66a3c1d46d54df1b2d0b8894babc42a14fb6f25511497f/librt-0.7.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ef7699b7a5a244b1119f85c5bbc13f152cd38240cbb2baa19b769433bae98e50", size = 177610, upload-time = "2026-01-01T23:51:23.874Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d7/b5e58dc2d570f162e99201b8c0151acf40a03a39c32ab824dd4febf12736/librt-0.7.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:955c62571de0b181d9e9e0a0303c8bc90d47670a5eff54cf71bf5da61d1899cf", size = 199272, upload-time = "2026-01-01T23:51:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/18/87/8202c9bd0968bdddc188ec3811985f47f58ed161b3749299f2c0dd0f63fb/librt-0.7.7-cp312-cp312-win32.whl", hash = "sha256:1bcd79be209313b270b0e1a51c67ae1af28adad0e0c7e84c3ad4b5cb57aaa75b", size = 43189, upload-time = "2026-01-01T23:51:26.799Z" }, - { url = "https://files.pythonhosted.org/packages/61/8d/80244b267b585e7aa79ffdac19f66c4861effc3a24598e77909ecdd0850e/librt-0.7.7-cp312-cp312-win_amd64.whl", hash = "sha256:4353ee891a1834567e0302d4bd5e60f531912179578c36f3d0430f8c5e16b456", size = 49462, upload-time = "2026-01-01T23:51:27.813Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1f/75db802d6a4992d95e8a889682601af9b49d5a13bbfa246d414eede1b56c/librt-0.7.7-cp312-cp312-win_arm64.whl", hash = "sha256:a76f1d679beccccdf8c1958e732a1dfcd6e749f8821ee59d7bec009ac308c029", size = 42828, upload-time = "2026-01-01T23:51:28.804Z" }, - { url = "https://files.pythonhosted.org/packages/8d/5e/d979ccb0a81407ec47c14ea68fb217ff4315521730033e1dd9faa4f3e2c1/librt-0.7.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f4a0b0a3c86ba9193a8e23bb18f100d647bf192390ae195d84dfa0a10fb6244", size = 55746, upload-time = "2026-01-01T23:51:29.828Z" }, - { url = "https://files.pythonhosted.org/packages/f5/2c/3b65861fb32f802c3783d6ac66fc5589564d07452a47a8cf9980d531cad3/librt-0.7.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5335890fea9f9e6c4fdf8683061b9ccdcbe47c6dc03ab8e9b68c10acf78be78d", size = 57174, upload-time = "2026-01-01T23:51:31.226Z" }, - { url = "https://files.pythonhosted.org/packages/50/df/030b50614b29e443607220097ebaf438531ea218c7a9a3e21ea862a919cd/librt-0.7.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b4346b1225be26def3ccc6c965751c74868f0578cbcba293c8ae9168483d811", size = 165834, upload-time = "2026-01-01T23:51:32.278Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e1/bd8d1eacacb24be26a47f157719553bbd1b3fe812c30dddf121c0436fd0b/librt-0.7.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a10b8eebdaca6e9fdbaf88b5aefc0e324b763a5f40b1266532590d5afb268a4c", size = 174819, upload-time = "2026-01-01T23:51:33.461Z" }, - { url = "https://files.pythonhosted.org/packages/46/7d/91d6c3372acf54a019c1ad8da4c9ecf4fc27d039708880bf95f48dbe426a/librt-0.7.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:067be973d90d9e319e6eb4ee2a9b9307f0ecd648b8a9002fa237289a4a07a9e7", size = 189607, upload-time = "2026-01-01T23:51:34.604Z" }, - { url = "https://files.pythonhosted.org/packages/fa/ac/44604d6d3886f791fbd1c6ae12d5a782a8f4aca927484731979f5e92c200/librt-0.7.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:23d2299ed007812cccc1ecef018db7d922733382561230de1f3954db28433977", size = 184586, upload-time = "2026-01-01T23:51:35.845Z" }, - { url = "https://files.pythonhosted.org/packages/5c/26/d8a6e4c17117b7f9b83301319d9a9de862ae56b133efb4bad8b3aa0808c9/librt-0.7.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6b6f8ea465524aa4c7420c7cc4ca7d46fe00981de8debc67b1cc2e9957bb5b9d", size = 178251, upload-time = "2026-01-01T23:51:37.018Z" }, - { url = "https://files.pythonhosted.org/packages/99/ab/98d857e254376f8e2f668e807daccc1f445e4b4fc2f6f9c1cc08866b0227/librt-0.7.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8df32a99cc46eb0ee90afd9ada113ae2cafe7e8d673686cf03ec53e49635439", size = 199853, upload-time = "2026-01-01T23:51:38.195Z" }, - { url = "https://files.pythonhosted.org/packages/7c/55/4523210d6ae5134a5da959900be43ad8bab2e4206687b6620befddb5b5fd/librt-0.7.7-cp313-cp313-win32.whl", hash = "sha256:86f86b3b785487c7760247bcdac0b11aa8bf13245a13ed05206286135877564b", size = 43247, upload-time = "2026-01-01T23:51:39.629Z" }, - { url = "https://files.pythonhosted.org/packages/25/40/3ec0fed5e8e9297b1cf1a3836fb589d3de55f9930e3aba988d379e8ef67c/librt-0.7.7-cp313-cp313-win_amd64.whl", hash = "sha256:4862cb2c702b1f905c0503b72d9d4daf65a7fdf5a9e84560e563471e57a56949", size = 49419, upload-time = "2026-01-01T23:51:40.674Z" }, - { url = "https://files.pythonhosted.org/packages/1c/7a/aab5f0fb122822e2acbc776addf8b9abfb4944a9056c00c393e46e543177/librt-0.7.7-cp313-cp313-win_arm64.whl", hash = "sha256:0996c83b1cb43c00e8c87835a284f9057bc647abd42b5871e5f941d30010c832", size = 42828, upload-time = "2026-01-01T23:51:41.731Z" }, - { url = "https://files.pythonhosted.org/packages/69/9c/228a5c1224bd23809a635490a162e9cbdc68d99f0eeb4a696f07886b8206/librt-0.7.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:23daa1ab0512bafdd677eb1bfc9611d8ffbe2e328895671e64cb34166bc1b8c8", size = 55188, upload-time = "2026-01-01T23:51:43.14Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c2/0e7c6067e2b32a156308205e5728f4ed6478c501947e9142f525afbc6bd2/librt-0.7.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:558a9e5a6f3cc1e20b3168fb1dc802d0d8fa40731f6e9932dcc52bbcfbd37111", size = 56895, upload-time = "2026-01-01T23:51:44.534Z" }, - { url = "https://files.pythonhosted.org/packages/0e/77/de50ff70c80855eb79d1d74035ef06f664dd073fb7fb9d9fb4429651b8eb/librt-0.7.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2567cb48dc03e5b246927ab35cbb343376e24501260a9b5e30b8e255dca0d1d2", size = 163724, upload-time = "2026-01-01T23:51:45.571Z" }, - { url = "https://files.pythonhosted.org/packages/6e/19/f8e4bf537899bdef9e0bb9f0e4b18912c2d0f858ad02091b6019864c9a6d/librt-0.7.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6066c638cdf85ff92fc6f932d2d73c93a0e03492cdfa8778e6d58c489a3d7259", size = 172470, upload-time = "2026-01-01T23:51:46.823Z" }, - { url = "https://files.pythonhosted.org/packages/42/4c/dcc575b69d99076768e8dd6141d9aecd4234cba7f0e09217937f52edb6ed/librt-0.7.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a609849aca463074c17de9cda173c276eb8fee9e441053529e7b9e249dc8b8ee", size = 186806, upload-time = "2026-01-01T23:51:48.009Z" }, - { url = "https://files.pythonhosted.org/packages/fe/f8/4094a2b7816c88de81239a83ede6e87f1138477d7ee956c30f136009eb29/librt-0.7.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:add4e0a000858fe9bb39ed55f31085506a5c38363e6eb4a1e5943a10c2bfc3d1", size = 181809, upload-time = "2026-01-01T23:51:49.35Z" }, - { url = "https://files.pythonhosted.org/packages/1b/ac/821b7c0ab1b5a6cd9aee7ace8309c91545a2607185101827f79122219a7e/librt-0.7.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a3bfe73a32bd0bdb9a87d586b05a23c0a1729205d79df66dee65bb2e40d671ba", size = 175597, upload-time = "2026-01-01T23:51:50.636Z" }, - { url = "https://files.pythonhosted.org/packages/71/f9/27f6bfbcc764805864c04211c6ed636fe1d58f57a7b68d1f4ae5ed74e0e0/librt-0.7.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0ecce0544d3db91a40f8b57ae26928c02130a997b540f908cefd4d279d6c5848", size = 196506, upload-time = "2026-01-01T23:51:52.535Z" }, - { url = "https://files.pythonhosted.org/packages/46/ba/c9b9c6fc931dd7ea856c573174ccaf48714905b1a7499904db2552e3bbaf/librt-0.7.7-cp314-cp314-win32.whl", hash = "sha256:8f7a74cf3a80f0c3b0ec75b0c650b2f0a894a2cec57ef75f6f72c1e82cdac61d", size = 39747, upload-time = "2026-01-01T23:51:53.683Z" }, - { url = "https://files.pythonhosted.org/packages/c5/69/cd1269337c4cde3ee70176ee611ab0058aa42fc8ce5c9dce55f48facfcd8/librt-0.7.7-cp314-cp314-win_amd64.whl", hash = "sha256:3d1fe2e8df3268dd6734dba33ededae72ad5c3a859b9577bc00b715759c5aaab", size = 45971, upload-time = "2026-01-01T23:51:54.697Z" }, - { url = "https://files.pythonhosted.org/packages/79/fd/e0844794423f5583108c5991313c15e2b400995f44f6ec6871f8aaf8243c/librt-0.7.7-cp314-cp314-win_arm64.whl", hash = "sha256:2987cf827011907d3dfd109f1be0d61e173d68b1270107bb0e89f2fca7f2ed6b", size = 39075, upload-time = "2026-01-01T23:51:55.726Z" }, - { url = "https://files.pythonhosted.org/packages/42/02/211fd8f7c381e7b2a11d0fdfcd410f409e89967be2e705983f7c6342209a/librt-0.7.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8e92c8de62b40bfce91d5e12c6e8b15434da268979b1af1a6589463549d491e6", size = 57368, upload-time = "2026-01-01T23:51:56.706Z" }, - { url = "https://files.pythonhosted.org/packages/4c/b6/aca257affae73ece26041ae76032153266d110453173f67d7603058e708c/librt-0.7.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f683dcd49e2494a7535e30f779aa1ad6e3732a019d80abe1309ea91ccd3230e3", size = 59238, upload-time = "2026-01-01T23:51:58.066Z" }, - { url = "https://files.pythonhosted.org/packages/96/47/7383a507d8e0c11c78ca34c9d36eab9000db5989d446a2f05dc40e76c64f/librt-0.7.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b15e5d17812d4d629ff576699954f74e2cc24a02a4fc401882dd94f81daba45", size = 183870, upload-time = "2026-01-01T23:51:59.204Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b8/50f3d8eec8efdaf79443963624175c92cec0ba84827a66b7fcfa78598e51/librt-0.7.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c084841b879c4d9b9fa34e5d5263994f21aea7fd9c6add29194dbb41a6210536", size = 194608, upload-time = "2026-01-01T23:52:00.419Z" }, - { url = "https://files.pythonhosted.org/packages/23/d9/1b6520793aadb59d891e3b98ee057a75de7f737e4a8b4b37fdbecb10d60f/librt-0.7.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c8fb9966f84737115513fecbaf257f9553d067a7dd45a69c2c7e5339e6a8dc", size = 206776, upload-time = "2026-01-01T23:52:01.705Z" }, - { url = "https://files.pythonhosted.org/packages/ff/db/331edc3bba929d2756fa335bfcf736f36eff4efcb4f2600b545a35c2ae58/librt-0.7.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9b5fb1ecb2c35362eab2dbd354fd1efa5a8440d3e73a68be11921042a0edc0ff", size = 203206, upload-time = "2026-01-01T23:52:03.315Z" }, - { url = "https://files.pythonhosted.org/packages/b2/e1/6af79ec77204e85f6f2294fc171a30a91bb0e35d78493532ed680f5d98be/librt-0.7.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:d1454899909d63cc9199a89fcc4f81bdd9004aef577d4ffc022e600c412d57f3", size = 196697, upload-time = "2026-01-01T23:52:04.857Z" }, - { url = "https://files.pythonhosted.org/packages/f3/46/de55ecce4b2796d6d243295c221082ca3a944dc2fb3a52dcc8660ce7727d/librt-0.7.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7ef28f2e7a016b29792fe0a2dd04dec75725b32a1264e390c366103f834a9c3a", size = 217193, upload-time = "2026-01-01T23:52:06.159Z" }, - { url = "https://files.pythonhosted.org/packages/41/61/33063e271949787a2f8dd33c5260357e3d512a114fc82ca7890b65a76e2d/librt-0.7.7-cp314-cp314t-win32.whl", hash = "sha256:5e419e0db70991b6ba037b70c1d5bbe92b20ddf82f31ad01d77a347ed9781398", size = 40277, upload-time = "2026-01-01T23:52:07.625Z" }, - { url = "https://files.pythonhosted.org/packages/06/21/1abd972349f83a696ea73159ac964e63e2d14086fdd9bc7ca878c25fced4/librt-0.7.7-cp314-cp314t-win_amd64.whl", hash = "sha256:d6b7d93657332c817b8d674ef6bf1ab7796b4f7ce05e420fd45bd258a72ac804", size = 46765, upload-time = "2026-01-01T23:52:08.647Z" }, - { url = "https://files.pythonhosted.org/packages/51/0e/b756c7708143a63fca65a51ca07990fa647db2cc8fcd65177b9e96680255/librt-0.7.7-cp314-cp314t-win_arm64.whl", hash = "sha256:142c2cd91794b79fd0ce113bd658993b7ede0fe93057668c2f98a45ca00b7e91", size = 39724, upload-time = "2026-01-01T23:52:09.745Z" }, -] - [[package]] name = "lxml" version = "6.0.2" @@ -3869,61 +3796,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/66/4fce8755f25d77324401886c00017c556be7ca3039575b94037aff905385/murmurhash-1.0.15-cp314-cp314t-win_arm64.whl", hash = "sha256:c22e56c6a0b70598a66e456de5272f76088bc623688da84ef403148a6d41851d", size = 26219, upload-time = "2025-11-14T09:51:03.563Z" }, ] -[[package]] -name = "mypy" -version = "1.19.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, - { name = "mypy-extensions" }, - { name = "pathspec" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/63/e499890d8e39b1ff2df4c0c6ce5d371b6844ee22b8250687a99fd2f657a8/mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec", size = 13101333, upload-time = "2025-12-15T05:03:03.28Z" }, - { url = "https://files.pythonhosted.org/packages/72/4b/095626fc136fba96effc4fd4a82b41d688ab92124f8c4f7564bffe5cf1b0/mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b", size = 12164102, upload-time = "2025-12-15T05:02:33.611Z" }, - { url = "https://files.pythonhosted.org/packages/0c/5b/952928dd081bf88a83a5ccd49aaecfcd18fd0d2710c7ff07b8fb6f7032b9/mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6", size = 12765799, upload-time = "2025-12-15T05:03:28.44Z" }, - { url = "https://files.pythonhosted.org/packages/2a/0d/93c2e4a287f74ef11a66fb6d49c7a9f05e47b0a4399040e6719b57f500d2/mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74", size = 13522149, upload-time = "2025-12-15T05:02:36.011Z" }, - { url = "https://files.pythonhosted.org/packages/7b/0e/33a294b56aaad2b338d203e3a1d8b453637ac36cb278b45005e0901cf148/mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1", size = 13810105, upload-time = "2025-12-15T05:02:40.327Z" }, - { url = "https://files.pythonhosted.org/packages/0e/fd/3e82603a0cb66b67c5e7abababce6bf1a929ddf67bf445e652684af5c5a0/mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac", size = 10057200, upload-time = "2025-12-15T05:02:51.012Z" }, - { url = "https://files.pythonhosted.org/packages/ef/47/6b3ebabd5474d9cdc170d1342fbf9dddc1b0ec13ec90bf9004ee6f391c31/mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288", size = 13028539, upload-time = "2025-12-15T05:03:44.129Z" }, - { url = "https://files.pythonhosted.org/packages/5c/a6/ac7c7a88a3c9c54334f53a941b765e6ec6c4ebd65d3fe8cdcfbe0d0fd7db/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab", size = 12083163, upload-time = "2025-12-15T05:03:37.679Z" }, - { url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" }, - { url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" }, - { url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" }, - { url = "https://files.pythonhosted.org/packages/fd/a3/47cbd4e85bec4335a9cd80cf67dbc02be21b5d4c9c23ad6b95d6c5196bac/mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042", size = 10055772, upload-time = "2025-12-15T05:03:26.179Z" }, - { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" }, - { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" }, - { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, - { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" }, - { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" }, - { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" }, - { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" }, - { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" }, - { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" }, - { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" }, - { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" }, - { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" }, - { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, - { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, - { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, - { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, -] - -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - [[package]] name = "nbclient" version = "0.10.4" @@ -4762,15 +4634,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] -[[package]] -name = "pathspec" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c2/97/39352be14d20d377a387828daf9d3f765fad1ff29bd49913d5bbf4cefe61/pathspec-1.0.0.tar.gz", hash = "sha256:9ada63a23541746b0cf7d5672a39ea77eac31dd23a80470be90df83537512131", size = 129410, upload-time = "2026-01-06T03:21:22.892Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/bb/39e6768529454cc2b57e1e2fa0a0a18ff64397a16303270e215a3e03285f/pathspec-1.0.0-py3-none-any.whl", hash = "sha256:1373719036e64a2b9de3b8ddd9e30afb082a915619f07265ed76d9ae507800ae", size = 54316, upload-time = "2026-01-06T03:21:21.74Z" }, -] - [[package]] name = "pexpect" version = "4.9.0" @@ -5693,7 +5556,6 @@ dev = [ { name = "jupytext" }, { name = "matplotlib" }, { name = "mock-alchemy" }, - { name = "mypy" }, { name = "pandas" }, { name = "pre-commit" }, { name = "pytest" }, @@ -5703,6 +5565,7 @@ dev = [ { name = "pytest-xdist" }, { name = "respx" }, { name = "ruff" }, + { name = "ty" }, { name = "types-aiofiles" }, { name = "types-cachetools" }, { name = "types-decorator" }, @@ -5789,7 +5652,6 @@ requires-dist = [ { name = "mlflow", marker = "extra == 'all'", specifier = ">=3.11.1" }, { name = "mlflow", marker = "extra == 'gcg'", specifier = ">=3.11.1" }, { name = "mock-alchemy", marker = "extra == 'dev'", specifier = ">=0.2.6" }, - { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.16.0" }, { name = "numpy", marker = "python_full_version < '3.14'", specifier = ">=1.26.0" }, { name = "numpy", marker = "python_full_version >= '3.14'", specifier = ">=2.3.0" }, { name = "ollama", marker = "extra == 'all'", specifier = ">=0.5.1" }, @@ -5832,6 +5694,7 @@ requires-dist = [ { name = "tqdm", specifier = ">=4.67.1" }, { name = "transformers", specifier = ">=4.55.0" }, { name = "treelib", specifier = ">=1.7.1" }, + { name = "ty", marker = "extra == 'dev'", specifier = ">=0.0.32" }, { name = "types-aiofiles", marker = "extra == 'dev'", specifier = ">=24.1.0" }, { name = "types-cachetools", marker = "extra == 'dev'", specifier = ">=5.5.0" }, { name = "types-decorator", marker = "extra == 'dev'", specifier = ">=5.1.0" }, @@ -7611,6 +7474,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/b5/b0d3d8b901b6a04ca38df5e24c27e53afb15b93624d7fd7d658c7cd9352a/triton-3.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bac7f7d959ad0f48c0e97d6643a1cc0fd5786fe61cb1f83b537c6b2d54776478", size = 170582192, upload-time = "2025-11-11T17:41:23.963Z" }, ] +[[package]] +name = "ty" +version = "0.0.32" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/7e/2aa791c9ae7b8cd5024cd4122e92267f664ca954cea3def3211919fa3c1f/ty-0.0.32.tar.gz", hash = "sha256:8743174c5f920f6700a4a0c9de140109189192ba16226884cd50095b43b8a45c", size = 5522294, upload-time = "2026-04-20T19:29:01.626Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/eb/1075dc6a49d7acbe2584ae4d5b410c41b1f177a5adcc567e09eca4c69000/ty-0.0.32-py3-none-linux_armv6l.whl", hash = "sha256:dacbc2f6cd698d488ae7436838ff929570455bf94bfa4d9fe57a630c552aff83", size = 10902959, upload-time = "2026-04-20T19:28:31.907Z" }, + { url = "https://files.pythonhosted.org/packages/33/d2/c35fc8bc66e98d1ee9b0f8ed319bf743e450e1f1e997574b178fab75670f/ty-0.0.32-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914bbc4f605ce2a9e2a78982e28fae1d3359a169d141f9dc3b4c7749cd5eca81", size = 10726172, upload-time = "2026-04-20T19:28:44.765Z" }, + { url = "https://files.pythonhosted.org/packages/96/32/c827da3ca480456fb02d8cea68a2609273b6c220fea0be9a4c8d8470b86e/ty-0.0.32-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4787ac9fe1f86b1f3133f5c6732adbe2df5668b50c679ac6e2d98cd284da812f", size = 10163701, upload-time = "2026-04-20T19:28:27.005Z" }, + { url = "https://files.pythonhosted.org/packages/ba/9e/2734478fbdb90c160cb2813a3916a16a2af5c1e231f87d635f6131d781fb/ty-0.0.32-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ea0a728af99fe40dd744cba6441a2404f80b7f4bde17aa6da393810af5ea57", size = 10656220, upload-time = "2026-04-20T19:29:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/44/9f/0007da2d35e424debe7e9f86ffbc1ab7f60983cfbc5f0411324ab2de5292/ty-0.0.32-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2850561f9b018ae33d7e5bbfa0ac414d3c518513edcffe43877dc9801446b9c5", size = 10696086, upload-time = "2026-04-20T19:28:46.829Z" }, + { url = "https://files.pythonhosted.org/packages/3b/5e/ce5fd4ec803222ae3e69a76d2a2db2eed55e19f5b131702b9789ef45f93d/ty-0.0.32-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5fa2fb3c614349ee211d36476b49d88c5ef79a687cdb91b2872ad023b94d2f8", size = 11184800, upload-time = "2026-04-20T19:28:42.57Z" }, + { url = "https://files.pythonhosted.org/packages/6c/46/ebcf67a5999421331214aac51a7464db42de2be15bbe929c612a3ed0b039/ty-0.0.32-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b89969307ab2417d41c9be8059dd79feea577234e1e10d35132f5495e0d42c6", size = 11718718, upload-time = "2026-04-20T19:28:36.433Z" }, + { url = "https://files.pythonhosted.org/packages/18/2c/2141c86ed0ce0962b45cefb658a95e734f59759d47f20afdcd9c732910a1/ty-0.0.32-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b59868ede9b1d69a088f0d695df52a0061f95fa7baa1d5e0dc6fc9cf06e1334", size = 11346369, upload-time = "2026-04-20T19:28:48.967Z" }, + { url = "https://files.pythonhosted.org/packages/7a/da/ed6f772339cf29bd9a46def9d6db5084689eb574ee4d150ff704224c1ed8/ty-0.0.32-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8300caf35345498e9b9b03e550bba03cee8f5f5f8ab4c83c3b1ff1b7403b7d3a", size = 11280714, upload-time = "2026-04-20T19:28:51.516Z" }, + { url = "https://files.pythonhosted.org/packages/da/9b/c6813987edf4816a40e0c8e408b555f97d3f267c7b3a1688c8bbdf65609c/ty-0.0.32-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:583c7094f4574b02f724db924f98b804d1387a0bd9405ecb5e078cc0f47fbcfb", size = 10638806, upload-time = "2026-04-20T19:28:29.651Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d4/0cefcbd2ad0f3d51762ccf58e652ec7da146eb6ae34f87228f6254bbb8be/ty-0.0.32-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e44ebe1bb4143a5628bc4db67ac0dfebe14594af671e4ee66f6f2e983da56501", size = 10726106, upload-time = "2026-04-20T19:29:06.3Z" }, + { url = "https://files.pythonhosted.org/packages/32/ad/2c8a97f91f06311f4367400f7d13534bbda2522c73c99a3e4c0757dff9b8/ty-0.0.32-py3-none-musllinux_1_2_i686.whl", hash = "sha256:06f17ada3e069cba6148342ef88e9929156beca8473e8d4f101b68f66c75643e", size = 10872951, upload-time = "2026-04-20T19:28:34.077Z" }, + { url = "https://files.pythonhosted.org/packages/ba/68/42293f9248106dd51875120971a5cc6ea315c2c4dcfb8e59aa063aa0af26/ty-0.0.32-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e96e60fa556cec04f15d7ea62d2ceee5982bd389233e961ab9fd42304e278175", size = 11363334, upload-time = "2026-04-20T19:28:54.036Z" }, + { url = "https://files.pythonhosted.org/packages/df/92/be9abf4d3e589ad5023e2ea965b93e204ec856420d46adf73c5c36c04678/ty-0.0.32-py3-none-win32.whl", hash = "sha256:2ff2ebb4986b24aebcf1444db7db5ca41b36086040e95eea9f8fb851c11e805c", size = 10260689, upload-time = "2026-04-20T19:28:56.541Z" }, + { url = "https://files.pythonhosted.org/packages/14/61/dc86acea899349d2579cb8419aecedd83dc504d7d6a10df65eef546c8300/ty-0.0.32-py3-none-win_amd64.whl", hash = "sha256:ba7284a4a954b598c1b31500352b3ec1f89bff533825592b5958848226fdc7ee", size = 11255371, upload-time = "2026-04-20T19:28:39.917Z" }, + { url = "https://files.pythonhosted.org/packages/43/01/beffec56d71ca25b343ede63adb076456b5b3e211f1c066452a44cd120b3/ty-0.0.32-py3-none-win_arm64.whl", hash = "sha256:7e10aadbdbda989a7d567ee6a37f8b98d4d542e31e3b190a2879fd581f75d658", size = 10658087, upload-time = "2026-04-20T19:28:59.286Z" }, +] + [[package]] name = "typer" version = "0.24.2"