Repository: pytest-dev/pytest
Pull request: Fixed invalid regex handling in filterwarnings
<!--
Thanks for submitting a PR, your contribution is really appreciated!

Here is a quick checklist that should be present in PRs.

- [ ] Include documentation when adding new features.
- [ ] Include new tests or update existing tests when applicable.
- [X] Allow maintainers to push and squash when merging my commits. Please uncheck this if you prefer to squash the commits yourself.

If this change fixes an issue, please:

- [ ] Add text like ``closes #XYZW`` to the PR description and/or commits (where ``XYZW`` is the issue number). See the [github docs](https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) for more information.

Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:

- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/main/changelog/README.rst) for details.

  Write sentences in the **past or present tense**, examples:

  * *Improved verbose diff output with sequences.*
  * *Terminal summary statistics now use multiple colors.*

  Also make sure to end the sentence with a `.`.

- [ ] Add yourself to `AUTHORS` in alphabetical order.
-->

closes #13119

- Updated the `parse_warning_filter` method to handle invalid regex pattern provided to message/module args.
- Added a test case in testing/test_warnings.py to validate the new behavior.
- Created a changelog fragment to document this improvement.


Problem statement:
config option filterwarnings ignore::DeprecationWarning:* crashes with regex exception: PatternError
Since Python3.13 upgrade there are many deprecation warnings from packages. These are not my concern, I'm sure the maintainers will sort things out by the time they need to. If they don't it won't be a warning and I'll see the error.

Found a number of forum posts on how to suppress  DeprecationWarning using different methods, none of which worked in current version of pytest.

This syntax in pytest.ini seemed like a fairly succinct way to suppress all DeprecationWarning messages, but it didn't. 
Forgot about the change that did nothing at the time.
After Python3.13 upgrade pytest crashed every time.

 Eventually found it was this filterwarnings line:
```
[pytest]
minversion = 6.0
addopts = -ra -q
asyncio_mode = auto
asyncio_default_fixture_loop_scope = function
testpaths =
    tests
filterwarnings = ignore::DeprecationWarning:*
```
It might be that this is invalid syntax edge case, in which case the line can be ignored with an appropriate (non-fatal) error message.
What would be terrific is if it actually did suppress all DeprecationWarning messages, as the syntax suggests.

Crash is easily reproduced:
```
pytest tests
/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/josepy/util.py:26: DeprecationWarning: CSR support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
  def __init__(self, wrapped: Union[crypto.X509, crypto.X509Req]) -> None:
/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/acme/crypto_util.py:280: DeprecationWarning: CSR support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
  def _pyopenssl_cert_or_req_all_names(loaded_cert_or_req: Union[crypto.X509, crypto.X509Req]
/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/acme/crypto_util.py:291: DeprecationWarning: CSR support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
  def _pyopenssl_cert_or_req_san(cert_or_req: Union[crypto.X509, crypto.X509Req]) -> List[str]:
/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/acme/crypto_util.py:318: DeprecationWarning: CSR support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
  def _pyopenssl_cert_or_req_san_ip(cert_or_req: Union[crypto.X509, crypto.X509Req]) -> List[str]:
/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/acme/crypto_util.py:338: DeprecationWarning: CSR support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
  def _pyopenssl_extract_san_list_raw(cert_or_req: Union[crypto.X509, crypto.X509Req]) -> List[str]:
/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/acme/crypto_util.py:372: DeprecationWarning: X509Extension support in pyOpenSSL is deprecated. You should use the APIs in cryptography.
  extensions: Optional[List[crypto.X509Extension]] = None,
/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/homeassistant/components/http/__init__.py:310: DeprecationWarning: Inheritance class HomeAssistantApplication from web.Application is discouraged
  class HomeAssistantApplication(web.Application):
Traceback (most recent call last):
  File "/home/homeassistant/sonnenbackup/.venv/bin/pytest", line 8, in <module>
    sys.exit(console_main())
             ~~~~~~~~~~~~^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 201, in console_main
    code = main()
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 156, in main
    config = _prepareconfig(args, plugins)
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 341, in _prepareconfig
    config = pluginmanager.hook.pytest_cmdline_parse(
        pluginmanager=pluginmanager, args=args
    )
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_hooks.py", line 513, in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_manager.py", line 120, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_callers.py", line 139, in _multicall
    raise exception.with_traceback(exception.__traceback__)
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_callers.py", line 122, in _multicall
    teardown.throw(exception)  # type: ignore[union-attr]
    ~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/helpconfig.py", line 105, in pytest_cmdline_parse
    config = yield
             ^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_callers.py", line 103, in _multicall
    res = hook_impl.function(*args)
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1140, in pytest_cmdline_parse
    self.parse(args)
    ~~~~~~~~~~^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1494, in parse
    self._preparse(args, addopts=addopts)
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1398, in _preparse
    self.hook.pytest_load_initial_conftests(
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        early_config=self, args=args, parser=self._parser
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_hooks.py", line 513, in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_manager.py", line 120, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_callers.py", line 139, in _multicall
    raise exception.with_traceback(exception.__traceback__)
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/pluggy/_callers.py", line 98, in _multicall
    next(function_gen)  # first yield
    ~~~~^^^^^^^^^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/warnings.py", line 148, in pytest_load_initial_conftests
    with catch_warnings_for_item(
         ~~~~~~~~~~~~~~~~~~~~~~~^
        config=early_config, ihook=early_config.hook, when="config", item=None
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ):
    ^
  File "/usr/local/lib/python3.13/contextlib.py", line 141, in __enter__
    return next(self.gen)
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/warnings.py", line 54, in catch_warnings_for_item
    apply_warning_filters(config_filters, cmdline_filters)
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/homeassistant/sonnenbackup/.venv/lib/python3.13/site-packages/_pytest/config/__init__.py", line 1970, in apply_warning_filters
    warnings.filterwarnings(*parse_warning_filter(arg, escape=False))
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/warnings.py", line 164, in filterwarnings
    module = re.compile(module)
  File "/usr/local/lib/python3.13/re/__init__.py", line 289, in compile
    return _compile(pattern, flags)
  File "/usr/local/lib/python3.13/re/__init__.py", line 350, in _compile
    p = _compiler.compile(pattern, flags)
  File "/usr/local/lib/python3.13/re/_compiler.py", line 743, in compile
    p = _parser.parse(p, flags)
  File "/usr/local/lib/python3.13/re/_parser.py", line 980, in parse
    p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
  File "/usr/local/lib/python3.13/re/_parser.py", line 459, in _parse_sub
    itemsappend(_parse(source, state, verbose, nested + 1,
                ~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                       not nested and not items))
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/re/_parser.py", line 686, in _parse
    raise source.error("nothing to repeat",
                       source.tell() - here + len(this))
re.PatternError: nothing to repeat at position 0
```

Packages installed:
```
Package                                 Version
--------------------------------------- -----------
acme                                    3.0.1
aiodns                                  3.2.0
aiohappyeyeballs                        2.4.4
aiohasupervisor                         0.2.2b5
aiohttp                                 3.11.11
aiohttp-cors                            0.7.0
aiohttp-fast-zlib                       0.2.0
aiooui                                  0.1.7
aiosignal                               1.3.2
aiozoneinfo                             0.2.1
annotated-types                         0.7.0
anyio                                   4.8.0
astral                                  2.2
async_interrupt                         1.2.0
async-timeout                           5.0.1
asyncio                                 3.4.3
asyncmock                               0.4.2
atomicwrites-homeassistant              1.4.1
attrs                                   24.2.0
audioop-lts                             0.2.1
awesomeversion                          24.6.0
bcrypt                                  4.2.0
bleak                                   0.22.3
bleak-retry-connector                   3.6.0
bluetooth-adapters                      0.20.2
bluetooth-auto-recovery                 1.4.2
bluetooth-data-tools                    1.20.0
boolean.py                              4.0
boto3                                   1.35.94
botocore                                1.35.94
btsocket                                0.3.0
certifi                                 2024.12.14
cffi                                    1.17.1
charset-normalizer                      3.4.1
ciso8601                                2.3.2
coverage                                7.6.8
cronsim                                 2.6
cryptography                            44.0.0
dbus-fast                               2.28.0
envs                                    1.4
execnet                                 2.1.1
fnv-hash-fast                           1.0.2
fnvhash                                 0.1.0
freezegun                               1.5.1
frozenlist                              1.5.0
h11                                     0.14.0
habluetooth                             3.7.0
hass-nabucasa                           0.87.0
home-assistant-bluetooth                1.13.0
homeassistant                           2025.1.0
httpcore                                1.0.7
httpx                                   0.27.2
idna                                    3.10
ifaddr                                  0.2.0
iniconfig                               2.0.0
isal                                    1.7.1
Jinja2                                  3.1.5
jmespath                                1.0.1
josepy                                  1.14.0
license-expression                      30.4.0
load-dotenv                             0.1.0
lru-dict                                1.3.0
MarkupSafe                              3.0.2
mashumaro                               3.15
mock                                    5.1.0
mock-open                               1.4.0
multidict                               6.1.0
numpy                                   2.2.0
orjson                                  3.10.12
packaging                               24.2
paho-mqtt                               1.6.1
pillow                                  11.0.0
pip                                     24.3.1
pipdeptree                              2.23.4
pluggy                                  1.5.0
propcache                               0.2.1
psutil                                  6.1.1
psutil-home-assistant                   0.0.1
pycares                                 4.5.0
pycognito                               2024.5.1
pycparser                               2.22
pydantic                                2.10.4
pydantic_core                           2.27.2
PyJWT                                   2.10.1
pylint-per-file-ignores                 1.3.2
pyOpenSSL                               24.3.0
pyRFC3339                               2.0.1
PyRIC                                   0.1.6.3
pytest                                  8.3.4
pytest-aiohttp                          1.0.5
pytest-asyncio                          0.25.2
pytest-cov                              6.0.0
pytest_freezer                          0.4.8
pytest-github-actions-annotate-failures 0.2.0
pytest-homeassistant-custom-component   0.13.201
pytest-mock                             3.14.0
pytest-picked                           0.5.0
pytest-socket                           0.7.0
pytest-sugar                            1.0.0
pytest-timeout                          2.3.1
pytest-unordered                        0.6.1
pytest-xdist                            3.6.1
python-dateutil                         2.9.0.post0
python-dotenv                           1.0.1
python-slugify                          8.0.4
pytz                                    2024.2
PyYAML                                  6.0.2
requests                                2.32.3
requests-mock                           1.12.1
responses                               0.25.3
respx                                   0.21.1
s3transfer                              0.10.4
securetar                               2024.11.0
setuptools                              75.7.0
six                                     1.17.0
sniffio                                 1.3.1
snitun                                  0.39.1
sonnen_api_v2                           0.5.13
SQLAlchemy                              2.0.36
standard-aifc                           3.13.0
standard-chunk                          3.13.0
standard-telnetlib                      3.13.0
syrupy                                  4.8.0
termcolor                               2.5.0
text-unidecode                          1.3
tqdm                                    4.66.5
typing_extensions                       4.12.2
tzdata                                  2024.2
uart-devices                            0.1.0
ulid-transform                          1.0.2
urllib3                                 1.26.20
urllib3-mock                            0.3.3
usb-devices                             0.4.5
uv                                      0.5.8
voluptuous                              0.15.2
voluptuous-openapi                      0.0.5
voluptuous-serialize                    2.6.0
webrtc-models                           0.3.0
yarl                                    1.18.3

```


OS:  Ubuntu 24.04.1 LTS (GNU/Linux 5.15.167.4-microsoft-standard-WSL2 x86_64)

Python 3.13.0

Hints from issue discussion:
You're asking for modules matching the regex `r"*"` this regex is invalid because of the reasons in the traceback.

You should simply omit the module to match any:
```ini
filterwarnings = ignore::DeprecationWarning
```

The invalid pattern is clearly an user error and shouldn't just magically work, but I agree that the error message could be more readable.

#12526 did something similar for `pytest.raises` for some inspiration. @virendrapatil24 do you maybe want to pick this one up too?
yeah @The-Compiler, I know what to do here. Will pick this up.

Commit message: [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Patch to review:
diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py
index 0161f5952b8..fd14dc17e39 100644
--- a/src/_pytest/config/__init__.py
+++ b/src/_pytest/config/__init__.py
@@ -1953,6 +1953,11 @@ def parse_warning_filter(
             ) from None
     else:
         lineno = 0
+    try:
+        re.compile(message)
+        re.compile(module)
+    except re.error as e:
+        raise UsageError(error_template.format(error=f"invalid regex: {e}"))
     return action, message, category, module, lineno
 
 
diff --git a/testing/test_warnings.py b/testing/test_warnings.py
index d4d0e0b7f93..c8a4d386437 100644
--- a/testing/test_warnings.py
+++ b/testing/test_warnings.py
@@ -511,6 +511,22 @@ def test_hidden_by_system(self, pytester: Pytester, monkeypatch) -> None:
         result = pytester.runpytest_subprocess()
         assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
 
+    def test_invalid_regex_in_filterwarning(self, pytester: Pytester) -> None:
+        self.create_file(pytester)
+        pytester.makeini(
+            """
+                [pytest]
+                filterwarnings =
+                    ignore::DeprecationWarning:*
+        """
+        )
+        result = pytester.runpytest_subprocess()
+        result.stderr.fnmatch_lines(
+            [
+                "*invalid regex: nothing to repeat at position 0*",
+            ]
+        )
+
 
 @pytest.mark.skip("not relevant until pytest 9.0")
 @pytest.mark.parametrize("change_default", [None, "ini", "cmdline"])


Code review comments:
diff_hunk: @@ -1953,6 +1953,11 @@ def parse_warning_filter(
             ) from None
     else:
         lineno = 0
+    try:
+        re.compile(message)
+        re.compile(module)
+    except re.error as e:
+        raise UsageError(error_template.format(error=f"invalid regex: {e}"))
path: src/_pytest/config/__init__.py
text: @user1:
```suggestion
        raise UsageError(error_template.format(error=f"Invalid regex {e.pattern!r}: {e}"))
```

Maybe, so it's clearer for more complex definitions which one of the two is the culprit?

@author:
sure will update the same, thanks!