Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 28 additions & 0 deletions .github/instructions/style-guide.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,33 @@ def calculate_score(
"""
```

### Code references in docstrings

The PyRIT docs build uses **MyST** (Markdown-flavoured), not reStructuredText.
Do **not** use reST cross-reference roles in docstrings or module comments —
they render as raw text under MyST and are inconsistent with the rest of the
codebase, which uses plain double-backtick code spans for symbol names.

```python
# WRONG — reST roles render as literal `:class:\`SeedPrompt\`` under MyST
"""Returns a :class:`SeedPrompt` instance."""
"""Delegate to :func:`download_files_async` (deprecated alias)."""
"""See :meth:`PromptTarget.apply_capabilities` for details."""

# CORRECT — plain double-backtick code span (matches existing convention)
"""Returns a ``SeedPrompt`` instance."""
"""Delegate to ``download_files_async`` (deprecated alias)."""
"""See ``PromptTarget.apply_capabilities`` for details."""
```

Roles to avoid include `:class:`, `:func:`, `:meth:`, `:mod:`, `:attr:`,
`:data:`, `:exc:`, `:obj:`, `:ref:`, and any `:py:*:` variants
(e.g. `:py:class:`, `:py:func:`).

If you genuinely need a Sphinx cross-reference (rare in PyRIT — most
docstrings just name the symbol in backticks), use the MyST role syntax
`` {class}`Name` `` instead. The default, though, is plain double-backticks.

### Class-Level Constants
- Define constants as class attributes, not module-level
- Use UPPER_CASE naming for constants
Expand Down Expand Up @@ -454,6 +481,7 @@ Before committing code, ensure:
- [ ] All functions have complete type annotations
- [ ] Functions with >1 parameter use keyword-only arguments
- [ ] Docstrings include parameter types
- [ ] Docstrings use plain double-backtick code spans for symbol references (no reST roles)
- [ ] Enums are used instead of Literals
- [ ] Functions are focused and under 20 lines
- [ ] Error messages are helpful and specific
Expand Down
4 changes: 2 additions & 2 deletions pyrit/auth/azure_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,10 +443,10 @@ async def get_speech_config_async(
"""
Get the speech config, resolving a callable token provider if one is provided.

This is the async counterpart to :func:`get_speech_config`. When a callable
This is the async counterpart to ``get_speech_config``. When a callable
``token_provider`` is supplied, it is invoked (and awaited if async) to obtain
a token, which is then used with the ``aad#{resource_id}#{token}`` auth format.
Otherwise, it delegates to the synchronous :func:`get_speech_config`.
Otherwise, it delegates to the synchronous ``get_speech_config``.

Args:
token_provider (Callable | None): An optional sync or async callable that returns a token string.
Expand Down
2 changes: 1 addition & 1 deletion pyrit/common/data_url_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ async def convert_local_image_to_data_url_async(image_path: str) -> str:

async def convert_local_image_to_data_url(image_path: str) -> str:
"""
Delegate to :func:`convert_local_image_to_data_url_async` (deprecated alias).
Delegate to ``convert_local_image_to_data_url_async`` (deprecated alias).
Returns:
str: A string containing the MIME type and the base64-encoded data of the image, formatted as a data URL.
Expand Down
2 changes: 1 addition & 1 deletion pyrit/common/display_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async def display_image_response_async(response_piece: MessagePiece) -> None:


async def display_image_response(response_piece: MessagePiece) -> None:
"""Delegate to :func:`display_image_response_async` (deprecated alias)."""
"""Delegate to ``display_image_response_async`` (deprecated alias)."""
print_deprecation_message(
old_item="pyrit.common.display_response.display_image_response",
new_item="pyrit.common.display_response.display_image_response_async",
Expand Down
8 changes: 4 additions & 4 deletions pyrit/common/download_hf_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ async def download_with_limit_async(url: str) -> None:


async def download_specific_files(model_id: str, file_patterns: list[str] | None, token: str, cache_dir: Path) -> None:
"""Delegate to :func:`download_specific_files_async` (deprecated alias)."""
"""Delegate to ``download_specific_files_async`` (deprecated alias)."""
print_deprecation_message(
old_item="pyrit.common.download_hf_model.download_specific_files",
new_item="pyrit.common.download_hf_model.download_specific_files_async",
Expand All @@ -140,7 +140,7 @@ async def download_specific_files(model_id: str, file_patterns: list[str] | None

async def download_chunk(url: str, headers: dict[str, str], start: int, end: int, client: httpx.AsyncClient) -> bytes:
"""
Delegate to :func:`download_chunk_async` (deprecated alias).
Delegate to ``download_chunk_async`` (deprecated alias).

Returns:
The content of the downloaded chunk.
Expand All @@ -154,7 +154,7 @@ async def download_chunk(url: str, headers: dict[str, str], start: int, end: int


async def download_file(url: str, token: str, download_dir: Path, num_splits: int) -> None:
"""Delegate to :func:`download_file_async` (deprecated alias)."""
"""Delegate to ``download_file_async`` (deprecated alias)."""
print_deprecation_message(
old_item="pyrit.common.download_hf_model.download_file",
new_item="pyrit.common.download_hf_model.download_file_async",
Expand All @@ -166,7 +166,7 @@ async def download_file(url: str, token: str, download_dir: Path, num_splits: in
async def download_files(
urls: list[str], token: str, download_dir: Path, num_splits: int = 3, parallel_downloads: int = 4
) -> None:
"""Delegate to :func:`download_files_async` (deprecated alias)."""
"""Delegate to ``download_files_async`` (deprecated alias)."""
print_deprecation_message(
old_item="pyrit.common.download_hf_model.download_files",
new_item="pyrit.common.download_hf_model.download_files_async",
Expand Down
2 changes: 1 addition & 1 deletion pyrit/prompt_converter/add_text_image_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class AddTextImageConverter(_BaseImageTextConverter):
"""
Adds a string to an image and wraps the text into multiple lines if necessary.

This class is similar to :class:`AddImageTextConverter` except
This class is similar to ``AddImageTextConverter`` except
we pass in text as an argument to the constructor as opposed to an image file path.
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def recognize_audio(self, audio_bytes: bytes) -> str:
Recognize audio file and return transcribed text.

.. deprecated::
Use :meth:`convert_async` instead, which resolves token providers correctly.
Use ``convert_async`` instead, which resolves token providers correctly.
This method does not support callable token providers.

Args:
Expand Down
38 changes: 19 additions & 19 deletions pyrit/prompt_target/common/discover_target_capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

This module exposes two complementary probes:

* :func:`_discover_capability_flags_async` discovers the boolean capability flags
defined on :class:`TargetCapabilities` (e.g. ``supports_system_prompt``,
* ``_discover_capability_flags_async`` discovers the boolean capability flags
defined on ``TargetCapabilities`` (e.g. ``supports_system_prompt``,
``supports_multi_message_pieces``). For each capability that has a probe
defined, a minimal request is sent to the target. If the request succeeds,
the capability is included in the returned set. Capabilities without a
registered probe fall back to the target's declared native support from
``target.capabilities``.
* :func:`_discover_input_modalities_async` discovers which input modality
* ``_discover_input_modalities_async`` discovers which input modality
combinations a target actually supports by sending a minimal test request
for each combination declared in ``TargetCapabilities.input_modalities``.

Expand Down Expand Up @@ -120,7 +120,7 @@ def _permissive_configuration(
Temporarily replace ``target``'s configuration with one that declares every
boolean capability as natively supported.

This bypasses :meth:`PromptTarget._validate_request`, which would otherwise
This bypasses ``PromptTarget._validate_request``, which would otherwise
short-circuit probes for capabilities the target declares as unsupported
before any API call is made. The original configuration is restored on exit.

Expand Down Expand Up @@ -182,9 +182,9 @@ def _probe_metadata(extra: dict[str, str | int] | None = None) -> dict[str, str

def _user_text_piece(*, value: str, conversation_id: str) -> MessagePiece:
"""
Build a single user-role text :class:`MessagePiece` for use in a probe.
Build a single user-role text ``MessagePiece`` for use in a probe.

The piece's ``prompt_metadata`` is tagged with :data:`PROBE_METADATA_KEY`
The piece's ``prompt_metadata`` is tagged with ``PROBE_METADATA_KEY``
so that consumers aggregating memory can filter out probe-written rows.

Args:
Expand Down Expand Up @@ -229,7 +229,7 @@ async def _send_and_check_async(
retries (int): Number of additional attempts after the first failure.
Only transient errors are retried; non-retryable errors and
non-error responses are final. Retry attempts use exponential
backoff starting at :data:`DEFAULT_PROBE_RETRY_BACKOFF_SECONDS`.
backoff starting at ``DEFAULT_PROBE_RETRY_BACKOFF_SECONDS``.
Defaults to 1.
label (str): Short label used in log messages. Defaults to
``"Capability probe"``.
Expand Down Expand Up @@ -291,8 +291,8 @@ async def _probe_system_prompt_async(target: PromptTarget, timeout_s: float, ret
"""
Probe whether ``target`` accepts a system prompt followed by a user message.

Writes a system-role :class:`MessagePiece` directly to ``target._memory``
rather than calling :meth:`pyrit.prompt_target.PromptChatTarget.set_system_prompt`
Writes a system-role ``MessagePiece`` directly to ``target._memory``
rather than calling ``pyrit.prompt_target.PromptChatTarget.set_system_prompt``
(which is only defined on ``PromptChatTarget`` subclasses anyway).
``set_system_prompt`` can be overridden by subclasses (e.g. mocks) to do
nothing or to perform extra work, which would mask whether the underlying
Expand Down Expand Up @@ -526,10 +526,10 @@ async def _discover_capability_flags_async(
Args:
target (PromptTarget): The target to probe.
capabilities (Iterable[CapabilityName] | None): Capabilities to check.
Defaults to every member of :class:`CapabilityName`.
Defaults to every member of ``CapabilityName``.
per_probe_timeout_s (float): Per-attempt timeout (seconds) applied to
each probe request. Defaults to
:data:`DEFAULT_PROBE_TIMEOUT_SECONDS`.
``DEFAULT_PROBE_TIMEOUT_SECONDS``.
retries (int): Number of additional attempts after the first failure
for each probe. Only exceptions/timeouts are retried; an explicit
error response is final. Set to ``0`` to disable retries.
Expand Down Expand Up @@ -593,7 +593,7 @@ async def _discover_capability_flags_async(

# Default mapping of non-text modalities to packaged probe assets. Callers can
# override via the ``test_assets`` parameter of
# :func:`_discover_input_modalities_async`. Modalities whose assets do not exist
# ``_discover_input_modalities_async``. Modalities whose assets do not exist
# on disk are skipped (logged and excluded from the result).
DEFAULT_TEST_ASSETS: dict[PromptDataType, str] = {
"audio_path": str(_TARGET_CAPABILITIES_DATASET_PATH / "probe_audio.wav"),
Expand Down Expand Up @@ -622,11 +622,11 @@ async def _discover_input_modalities_async(
declared in ``target.capabilities.input_modalities``.
test_assets (dict[PromptDataType, str] | None): Mapping from
non-text modality to a file path used as the probe payload.
Defaults to :data:`DEFAULT_TEST_ASSETS`. Combinations whose
Defaults to ``DEFAULT_TEST_ASSETS``. Combinations whose
non-text assets are missing on disk are skipped.
per_probe_timeout_s (float): Per-attempt timeout (seconds) applied to
each probe request. Defaults to
:data:`DEFAULT_PROBE_TIMEOUT_SECONDS`.
``DEFAULT_PROBE_TIMEOUT_SECONDS``.
retries (int): Number of additional attempts after the first failure
for each probe. Only exceptions/timeouts are retried; an explicit
error response is final. Set to ``0`` to disable retries.
Expand Down Expand Up @@ -685,7 +685,7 @@ async def discover_target_capabilities_async(
"""
Probe both the boolean capability flags and the input modality combinations
that ``target`` accepts, and return a merged best-effort
:class:`TargetCapabilities`.
``TargetCapabilities``.

Boolean capabilities with a registered probe are checked with live
requests; capabilities without a probe fall back to the target's
Expand All @@ -704,17 +704,17 @@ async def discover_target_capabilities_async(
the target's declared support.
test_assets (dict[PromptDataType, str] | None): Mapping from non-text
modality to a file path used as the probe payload. Defaults to
:data:`DEFAULT_TEST_ASSETS`. Combinations whose non-text assets
``DEFAULT_TEST_ASSETS``. Combinations whose non-text assets
are missing on disk are skipped.
capabilities (Iterable[CapabilityName] | None): Capabilities to probe.
Defaults to every member of :class:`CapabilityName`. Capabilities
Defaults to every member of ``CapabilityName``. Capabilities
not listed here fall back to the target's declared support.
retries (int): Number of additional attempts after the first failure
for each probe. Only exceptions/timeouts are retried; an explicit
error response is final. Set to ``0`` to disable retries.
Defaults to 1.
apply (bool): If True, install the discovered capabilities on ``target``
via :meth:`PromptTarget.apply_capabilities` before returning.
via ``PromptTarget.apply_capabilities`` before returning.
Probe results are an upper bound (the request was accepted, not
necessarily honored), so leave this False when you want to inspect
or diff the result before committing to it. Defaults to False.
Expand Down Expand Up @@ -790,7 +790,7 @@ def _create_test_message(
test_assets: dict[PromptDataType, str],
) -> Message:
"""
Build a minimal :class:`Message` that exercises ``modalities``.
Build a minimal ``Message`` that exercises ``modalities``.

Args:
modalities (frozenset[PromptDataType]): The modalities to include.
Expand Down
8 changes: 4 additions & 4 deletions pyrit/prompt_target/common/prompt_chat_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class PromptChatTarget(PromptTarget):
"""
.. deprecated:: 0.14.0
``PromptChatTarget`` is deprecated and will be removed in v0.16.0. Use
:class:`PromptTarget` directly with a ``TargetConfiguration`` declaring
``PromptTarget`` directly with a ``TargetConfiguration`` declaring
``supports_multi_turn=True`` and ``supports_editable_history=True``.

Backwards-compatible alias for :class:`PromptTarget`. All chat-target functionality
(``set_system_prompt``, ``is_response_format_json``) lives on :class:`PromptTarget`.
Subclassing or instantiating this class emits a :class:`DeprecationWarning`.
Backwards-compatible alias for ``PromptTarget``. All chat-target functionality
(``set_system_prompt``, ``is_response_format_json``) lives on ``PromptTarget``.
Subclassing or instantiating this class emits a ``DeprecationWarning``.
"""

_DEFAULT_CONFIGURATION: TargetConfiguration = TargetConfiguration(
Expand Down
10 changes: 5 additions & 5 deletions pyrit/prompt_target/common/prompt_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ async def send_prompt_async(self, *, message: Message) -> list[Message]:
1. Validates the message, fetches the conversation from memory, appends ``message``, and runs
the normalization pipeline (system‑squash, history‑squash, etc.).
2. Validates the normalized conversation against the target's capabilities.
3. Delegates to :meth:`_send_prompt_to_target_async` with the normalized
3. Delegates to ``_send_prompt_to_target_async`` with the normalized
conversation.

Subclasses MUST NOT override this method. Override
:meth:`_send_prompt_to_target_async` instead.
``_send_prompt_to_target_async`` instead.

Args:
message (Message): The message to send.
Expand All @@ -121,7 +121,7 @@ async def _send_prompt_to_target_async(self, *, normalized_conversation: list[Me
"""
Target-specific send logic.

Called by :meth:`send_prompt_async` after validation and normalization.
Called by ``send_prompt_async`` after validation and normalization.

Args:
normalized_conversation (list[Message]): The full conversation
Expand Down Expand Up @@ -263,7 +263,7 @@ def set_system_prompt(

If the target does not natively support system prompts, whether this
call is ultimately honored depends on the target's
:class:`CapabilityHandlingPolicy`:
``CapabilityHandlingPolicy``:

* ``ADAPT`` — the normalization pipeline (e.g. system squash) will
fold the system message into user content on the wire.
Expand Down Expand Up @@ -388,7 +388,7 @@ def apply_capabilities(self, *, capabilities: TargetCapabilities) -> None:

Policy is preserved because it expresses user intent (ADAPT vs RAISE),
independent of what the probe found. To change policy or normalizer
overrides, build a new :class:`TargetConfiguration` and pass it via
overrides, build a new ``TargetConfiguration`` and pass it via
``custom_configuration`` at construction time instead.

Note:
Expand Down
8 changes: 4 additions & 4 deletions pyrit/prompt_target/common/target_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ async def normalize_async(self, *, messages: list[Message]) -> list[Message]:
def as_identifier_params(self) -> dict[str, Any]:
"""
Return a deterministic, serializable representation of this configuration
suitable for inclusion in a :class:`ComponentIdentifier`.
suitable for inclusion in a ``ComponentIdentifier``.

The returned dict preserves the structure of :class:`TargetConfiguration`
The returned dict preserves the structure of ``TargetConfiguration``
— capabilities, policy, and pipeline are kept as nested sub-dicts rather
than flattened into the caller — so the identifier reflects the shape of
the object it describes.
Expand Down Expand Up @@ -174,8 +174,8 @@ def as_identifier_params(self) -> dict[str, Any]:
@staticmethod
def _capabilities_to_identifier_params(capabilities: TargetCapabilities) -> dict[str, Any]:
"""
Project a :class:`TargetCapabilities` instance into a deterministic dict
suitable for inclusion in a :class:`ComponentIdentifier`.
Project a ``TargetCapabilities`` instance into a deterministic dict
suitable for inclusion in a ``ComponentIdentifier``.

Fields are discovered dynamically via ``dataclasses.fields`` so new
capability fields are picked up automatically. Set-valued fields (e.g.,
Expand Down
6 changes: 3 additions & 3 deletions pyrit/prompt_target/common/target_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ class TargetRequirements:
requires from a target.

The single source of truth for capability names is the
:class:`CapabilityName` enum; this class is simply a typed wrapper
``CapabilityName`` enum; this class is simply a typed wrapper
around the set of capabilities a consumer needs.

Two tiers of requirement are supported:

* ``required`` \u2014 satisfied either by native support on the target or
by an ``ADAPT`` entry in the target's
:class:`CapabilityHandlingPolicy`. Use this when the consumer only
``CapabilityHandlingPolicy``. Use this when the consumer only
needs the behavior to appear on the wire.
* ``native_required`` \u2014 must be natively supported. Adaptation is
rejected. Use this when adaptation would silently change the
Expand All @@ -38,7 +38,7 @@ class TargetRequirements:
Modality requirements are also supported:

* ``required_input_modalities`` — each entry is a frozenset of
:class:`PromptDataType` values the consumer needs the target to
``PromptDataType`` values the consumer needs the target to
accept. At least one of the target's input modality combos must be
a superset of each required combo.
* ``required_output_modalities`` — same semantics for outputs.
Expand Down
Loading
Loading