Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ec4a611
[deps]: replace `mypy` w ith`ty`;
maifeeulasad Jan 17, 2026
a5edbf0
[lock]: regenerated lock file for uv;
maifeeulasad Jan 17, 2026
c284c5b
[cleanup]: remove mypy pre commit hook;
maifeeulasad Jan 17, 2026
60f6639
[maint]: add ty cache in dockerignore instead of mypy;
maifeeulasad Jan 17, 2026
4cf17ef
[maint]: add ty cache in dev container instead of mypy;
maifeeulasad Jan 17, 2026
f92b16e
[maint]: add ty cache in container volume instead of mypy;
maifeeulasad Jan 17, 2026
790a5fa
[doc]: update command for `ty` type checker;
maifeeulasad Jan 17, 2026
ab255f4
[feat]: ty make command replacing mypy;
maifeeulasad Jan 17, 2026
3ba4c50
[config]: `ty` config over `mypy`;
maifeeulasad Jan 17, 2026
91c8a37
[config]: cleanup false `ty` config;
maifeeulasad Jan 17, 2026
fad4f45
Merge origin/main into migration-mypy-to-ty
romanlutz Apr 24, 2026
48baf5d
Tighten ty config, add Ruff ANN rules, fix annotations
romanlutz Apr 27, 2026
9cb177c
Merge origin/main into migration-mypy-to-ty
romanlutz Apr 27, 2026
73b53d7
Migrate type: ignore comments from mypy to ty format
romanlutz Apr 27, 2026
0e5bed5
Merge remote-tracking branch 'origin/main' into migration-mypy-to-ty
romanlutz Apr 28, 2026
df9b079
Clean up unused type: ignore suppression comments
romanlutz Apr 28, 2026
bde463d
Fix 4 type: ignore comments with wrong ty codes
romanlutz Apr 28, 2026
2a56021
Add assert message_piece.id is not None to fix UUID type errors in sc…
romanlutz Apr 28, 2026
918997d
Add ty pre-commit hook, fix remaining ty errors
romanlutz Apr 28, 2026
e249e61
Merge branch 'main' into migration-mypy-to-ty-maifee
romanlutz Apr 28, 2026
5da054e
Suppress ty error on new cyber scenario factory (same pattern as rapi…
romanlutz Apr 28, 2026
663a09a
Fix ruff formatting and misplaced type: ignore comments in airt.py
romanlutz Apr 28, 2026
a2ac1e9
Fix unit test failures: replace asserts with type: ignore in scorers
romanlutz Apr 28, 2026
a609926
Fix pre-commit failures: update miniconda URL and exclude infra scrip…
romanlutz Apr 29, 2026
a38c6c5
Revert type: ignore changes in auxiliary_attacks/gcg/ (excluded from …
romanlutz Apr 29, 2026
d5ada68
Add tests for uncovered lines to meet diff-coverage threshold
romanlutz Apr 29, 2026
a530487
Remove all mypy references from the repository
romanlutz Apr 29, 2026
c115210
Merge branch 'main' into migration-mypy-to-ty-maifee
romanlutz Apr 29, 2026
668e3bb
Merge remote-tracking branch 'origin/main' into migration-mypy-to-ty
romanlutz Apr 30, 2026
4eb45ef
Merge remote-tracking branch 'maifeeulasad/migration-mypy-to-ty-maife…
romanlutz Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
24 changes: 0 additions & 24 deletions .devcontainer/devcontainer_setup.sh
Original file line number Diff line number Diff line change
@@ -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-*
Expand Down
4 changes: 2 additions & 2 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -27,6 +27,6 @@ volumes:
pip-cache:
uv-cache:
precommit-cache:
mypy-cache:
ty-cache:
pylance-cache:
node-modules:
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ build/
**/*.py[cod]
**/*$py.class
**/.pytest_cache/
**/.mypy_cache/
**/.ty_cache/

# Environment files with secrets
.env
Expand Down
5 changes: 0 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,6 @@ env-test
# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

Expand Down
15 changes: 6 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions doc/getting_started/install_local_dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
48 changes: 35 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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 = [
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"]
Expand All @@ -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"
1 change: 0 additions & 1 deletion pyrightconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"**/dist",
".venv",
"pyrit.egg-info",
".mypy_cache",
".pytest_cache"
],
"reportMissingImports": true
Expand Down
4 changes: 2 additions & 2 deletions pyrit/analytics/conversation_analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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.

Expand Down
8 changes: 4 additions & 4 deletions pyrit/auth/azure_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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.

Expand Down
4 changes: 2 additions & 2 deletions pyrit/auth/azure_storage_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 4 additions & 4 deletions pyrit/auth/copilot_authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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__
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion pyrit/backend/mappers/attack_mappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand Down
Loading
Loading