Repository: huggingface/transformers
Pull request: fix(modeling_attn_mask_utils): remove FutureWarning from logger.warning_once()

# What does this PR do?

This PR fixes a `TypeError: not all arguments converted during string formatting` caused by incorrectly passing `FutureWarning` as a second argument to `logger.warning_once()` in this file, introduced in https://github.com/huggingface/transformers/pull/42848. Because Python's logging module expects string formatting arguments (like `%s`) rather than warning categories, passing `FutureWarning` without a placeholder triggered a crash when the warning evaluated.

~I prioritized the use of `logger.warning_once()` instead of `warnings.warn(msg, FutureWarning)` to align with the logging patterns in similar transformers `modeling_` utils files.~ -> This was later changed to prefer `warnings` for sake of preserving the `FutureWarning`: https://github.com/huggingface/transformers/pull/44307#discussion_r2861121388

I didn't test this locally, but here's a small snippet for reproduction:
```
>>> import logging
>>> DEPRECATION_MESSAGE = "test"
>>> logging.warning(DEPRECATION_MESSAGE)
WARNING:root:test
>>> logging.warning(DEPRECATION_MESSAGE,FutureWarning)
--- Logging error ---
Traceback (most recent call last):
  File "/Users/steven.palma/miniforge3/lib/python3.12/logging/__init__.py", line 1160, in emit
    msg = self.format(record)
          ^^^^^^^^^^^^^^^^^^^
  File "/Users/steven.palma/miniforge3/lib/python3.12/logging/__init__.py", line 999, in format
    return fmt.format(record)
           ^^^^^^^^^^^^^^^^^^
  File "/Users/steven.palma/miniforge3/lib/python3.12/logging/__init__.py", line 703, in format
    record.message = record.getMessage()
                     ^^^^^^^^^^^^^^^^^^^
  File "/Users/steven.palma/miniforge3/lib/python3.12/logging/__init__.py", line 392, in getMessage
    msg = msg % self.args
          ~~~~^~~~~~~~~~~
TypeError: not all arguments converted during string formatting
Call stack:
  File "<stdin>", line 1, in <module>
Message: 'test'
Arguments: (<class 'FutureWarning'>,)
>>>
```

Here's an example of this happening in downstream libraries: https://github.com/huggingface/lerobot/actions/runs/22455225460/job/65035766998

## Before submitting
- [ ] This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
- [ ] Did you read the [contributor guideline](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md#create-a-pull-request),
      Pull Request section?
- [ ] Was this discussed/approved via a Github issue or the [forum](https://discuss.huggingface.co/)? Please add a link
      to it if that's the case.
- [ ] Did you make sure to update the documentation with your changes? Here are the
      [documentation guidelines](https://github.com/huggingface/transformers/tree/main/docs), and
      [here are tips on formatting docstrings](https://github.com/huggingface/transformers/tree/main/docs#writing-source-documentation).
- [ ] Did you write any new necessary tests?


## Who can review?

* Anyone in the community is free to review the PR once the tests have passed.
* @vasqu @ArthurZucker 


Changed files:
filename: src/transformers/modeling_attn_mask_utils.py
patch: @@ -17,18 +17,15 @@
 and will be removed in the future.
 """
 
+import warnings
 from dataclasses import dataclass
 from typing import Union
 
 import torch
 
-from .utils import logging
 from .utils.import_utils import is_torchdynamo_compiling, is_tracing
 
 
-logger = logging.get_logger(__name__)
-
-
 DEPRECATION_MESSAGE = (
     "The attention mask API under `transformers.modeling_attn_mask_utils` (`AttentionMaskConverter`) "
     "is deprecated and will be removed in Transformers v5.10. Please use the new API in `transformers.masking_utils`."
@@ -71,7 +68,7 @@ class AttentionMaskConverter:
     sliding_window: int
 
     def __init__(self, is_causal: bool, sliding_window: int | None = None):
-        logger.warning_once(DEPRECATION_MESSAGE, FutureWarning)
+        warnings.warn(DEPRECATION_MESSAGE, FutureWarning)
 
         self.is_causal = is_causal
         self.sliding_window = sliding_window
@@ -172,7 +169,7 @@ def _make_causal_mask(
         """
         Make causal mask used for bi-directional self-attention.
         """
-        logger.warning_once(DEPRECATION_MESSAGE, FutureWarning)
+        warnings.warn(DEPRECATION_MESSAGE, FutureWarning)
 
         bsz, tgt_len = input_ids_shape
         mask = torch.full((tgt_len, tgt_len), torch.finfo(dtype).min, device=device)
@@ -202,7 +199,7 @@ def _expand_mask(mask: torch.Tensor, dtype: torch.dtype, tgt_len: int | None = N
         """
         Expands attention_mask from `[bsz, seq_len]` to `[bsz, 1, tgt_seq_len, src_seq_len]`.
         """
-        logger.warning_once(DEPRECATION_MESSAGE, FutureWarning)
+        warnings.warn(DEPRECATION_MESSAGE, FutureWarning)
 
         bsz, src_len = mask.size()
         tgt_len = tgt_len if tgt_len is not None else src_len
@@ -254,7 +251,7 @@ def _unmask_unattended(
            [0, 1, 1]]]]
         ```
         """
-        logger.warning_once(DEPRECATION_MESSAGE, FutureWarning)
+        warnings.warn(DEPRECATION_MESSAGE, FutureWarning)
 
         # fmt: on
         if expanded_mask.dtype == torch.bool:
@@ -281,7 +278,7 @@ def _ignore_causal_mask_sdpa(
         allowing to dispatch to the flash attention kernel (that can otherwise not be used if a custom `attn_mask` is
         passed).
         """
-        logger.warning_once(DEPRECATION_MESSAGE, FutureWarning)
+        warnings.warn(DEPRECATION_MESSAGE, FutureWarning)
 
         _, query_length = inputs_embeds.shape[0], inputs_embeds.shape[1]
         key_value_length = query_length + past_key_values_length
@@ -464,7 +461,7 @@ def _prepare_4d_attention_mask_for_sdpa(mask: torch.Tensor, dtype: torch.dtype,
         tgt_len (`int`):
             The target length or query length the created mask shall have.
     """
-    logger.warning_once(DEPRECATION_MESSAGE, FutureWarning)
+    warnings.warn(DEPRECATION_MESSAGE, FutureWarning)
 
     _, key_value_length = mask.shape
     tgt_len = tgt_len if tgt_len is not None else key_value_length