From a645c9382fd8d1f3d672c7c1550cf10fe2dadffb Mon Sep 17 00:00:00 2001 From: hularuns <159131400+hularuns@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:13:32 +0000 Subject: [PATCH 1/8] warn_deprecated now respect if a user wants to `ignore` deprecation warnings - checks by checking module name and action --- disnake/utils.py | 27 ++++++++++++++++++++------- tests/test_utils.py | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/disnake/utils.py b/disnake/utils.py index 2cb4ba5674..ba0f2fee92 100644 --- a/disnake/utils.py +++ b/disnake/utils.py @@ -301,13 +301,26 @@ def warn_deprecated( stacklevel = 1 # reset stacklevel, assume we just want the first frame outside library code old_filters = warnings.filters[:] - try: - warnings.simplefilter("always", DeprecationWarning) - warnings.warn(*args, stacklevel=stacklevel + 1, category=DeprecationWarning, **kwargs) - finally: - assert isinstance(warnings.filters, list) - warnings.filters[:] = old_filters - + send_warning = True + if len(old_filters) > 0: + for action, _, category, module, _ in old_filters: + if ( + (category is DeprecationWarning) + and ("disnake" in str(module)) + and (action == "ignore") + ): + send_warning = False + break # break out after first disnake rule, it's good enough. + + if send_warning: + # this still allows force bypassing of filters if the default DeprecationWarning ignore is set. + try: + warnings.simplefilter(action="always", category=DeprecationWarning) + warnings.warn(*args, stacklevel=stacklevel + 1, category=DeprecationWarning, **kwargs) + finally: + # NOTE: Is this assertion even necessary? warnings.filters is always at minimum an empty list? + assert isinstance(warnings.filters, list) + warnings.filters[:] = old_filters def oauth_url( client_id: Union[int, str], diff --git a/tests/test_utils.py b/tests/test_utils.py index 84fe54400c..86683b35ba 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -127,6 +127,46 @@ def func(n: int) -> None: assert result[0].filename == mock.__file__ +@pytest.mark.parametrize( + "msg", + ["This is a deprecated function"], +) +def test_deprecated_warn(msg: str) -> None: + # Just test if works + # first clear existing filters - these will be restored at the end as this is probably messing with the global warning filters + filters = warnings.filters[:] + + warnings.resetwarnings() + with warnings.catch_warnings(record=True) as result: + warnings.filterwarnings("always", category=DeprecationWarning, module=r"disnake\..*") # this also works with just a plain str + utils.warn_deprecated(msg) + + assert len(result) == 1 + assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] + assert result[0].category is DeprecationWarning + + # Reset With empty filters - expected behaviour is that a warning is forced because it's empty + warnings.resetwarnings() + assert len(warnings.filters) == 0 # should be empty + with warnings.catch_warnings(record=True) as result: + utils.warn_deprecated(msg) + + assert len(result) == 1 + assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] + assert result[0].category is DeprecationWarning + + # Reset With empty filters - expected behaviour is that there is no warning because it's ignored + warnings.resetwarnings() + assert len(warnings.filters) == 0 # should be empty + with warnings.catch_warnings(record=True) as result: + warnings.filterwarnings("ignore", category=DeprecationWarning, module=r"disnake\..*") + utils.warn_deprecated(msg) + + assert len(result) == 0 + + + warnings.filters[:] = filters # pyright: ignore[reportIndexIssue] + @pytest.mark.parametrize( ("params", "expected"), [ @@ -1024,4 +1064,4 @@ def decorated(self) -> None: ... ], ) def test_signature_has_self_param(function, expected) -> None: - assert utils.signature_has_self_param(function) == expected + assert utils.signature_has_self_param(function) == expected \ No newline at end of file From cf77a2d39d3d41f6669a6c4584e57d6d953780ce Mon Sep 17 00:00:00 2001 From: hularuns <159131400+hularuns@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:16:11 +0000 Subject: [PATCH 2/8] linting --- disnake/utils.py | 4 +++- tests/test_utils.py | 22 ++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/disnake/utils.py b/disnake/utils.py index ba0f2fee92..c64f7ae390 100644 --- a/disnake/utils.py +++ b/disnake/utils.py @@ -301,6 +301,7 @@ def warn_deprecated( stacklevel = 1 # reset stacklevel, assume we just want the first frame outside library code old_filters = warnings.filters[:] + warnings.filterwarnings(action="default", category=DeprecationWarning, module="cumbum") send_warning = True if len(old_filters) > 0: for action, _, category, module, _ in old_filters: @@ -319,9 +320,10 @@ def warn_deprecated( warnings.warn(*args, stacklevel=stacklevel + 1, category=DeprecationWarning, **kwargs) finally: # NOTE: Is this assertion even necessary? warnings.filters is always at minimum an empty list? - assert isinstance(warnings.filters, list) + assert isinstance(warnings.filters, list) warnings.filters[:] = old_filters + def oauth_url( client_id: Union[int, str], *, diff --git a/tests/test_utils.py b/tests/test_utils.py index 86683b35ba..01af3029f3 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -132,41 +132,43 @@ def func(n: int) -> None: ["This is a deprecated function"], ) def test_deprecated_warn(msg: str) -> None: - # Just test if works + # Just test if works # first clear existing filters - these will be restored at the end as this is probably messing with the global warning filters filters = warnings.filters[:] - + warnings.resetwarnings() with warnings.catch_warnings(record=True) as result: - warnings.filterwarnings("always", category=DeprecationWarning, module=r"disnake\..*") # this also works with just a plain str + warnings.filterwarnings( + "always", category=DeprecationWarning, module=r"disnake\..*" + ) # this also works with just a plain str utils.warn_deprecated(msg) assert len(result) == 1 assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] assert result[0].category is DeprecationWarning - + # Reset With empty filters - expected behaviour is that a warning is forced because it's empty warnings.resetwarnings() - assert len(warnings.filters) == 0 # should be empty + assert len(warnings.filters) == 0 # should be empty with warnings.catch_warnings(record=True) as result: utils.warn_deprecated(msg) assert len(result) == 1 assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] assert result[0].category is DeprecationWarning - + # Reset With empty filters - expected behaviour is that there is no warning because it's ignored warnings.resetwarnings() - assert len(warnings.filters) == 0 # should be empty + assert len(warnings.filters) == 0 # should be empty with warnings.catch_warnings(record=True) as result: warnings.filterwarnings("ignore", category=DeprecationWarning, module=r"disnake\..*") utils.warn_deprecated(msg) assert len(result) == 0 + warnings.filters[:] = filters # pyright: ignore[reportIndexIssue] + - warnings.filters[:] = filters # pyright: ignore[reportIndexIssue] - @pytest.mark.parametrize( ("params", "expected"), [ @@ -1064,4 +1066,4 @@ def decorated(self) -> None: ... ], ) def test_signature_has_self_param(function, expected) -> None: - assert utils.signature_has_self_param(function) == expected \ No newline at end of file + assert utils.signature_has_self_param(function) == expected From d9bcc218118a4e64445b84bee1a052db5c41da29 Mon Sep 17 00:00:00 2001 From: hularuns <159131400+hularuns@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:25:48 +0000 Subject: [PATCH 3/8] changelog added --- changelog/1476.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/1476.bugfix.rst diff --git a/changelog/1476.bugfix.rst b/changelog/1476.bugfix.rst new file mode 100644 index 0000000000..9173768db5 --- /dev/null +++ b/changelog/1476.bugfix.rst @@ -0,0 +1 @@ +warn_deprecated now respected warning.filter ignores if at least "disnake" is passed to module argument. From 1b411529a64724bfcd3e3747075f4eb39b786538 Mon Sep 17 00:00:00 2001 From: hularuns <159131400+hularuns@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:14:22 +0000 Subject: [PATCH 4/8] removed rogue line from when devving --- disnake/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/disnake/utils.py b/disnake/utils.py index c64f7ae390..d781fb3ab1 100644 --- a/disnake/utils.py +++ b/disnake/utils.py @@ -301,7 +301,6 @@ def warn_deprecated( stacklevel = 1 # reset stacklevel, assume we just want the first frame outside library code old_filters = warnings.filters[:] - warnings.filterwarnings(action="default", category=DeprecationWarning, module="cumbum") send_warning = True if len(old_filters) > 0: for action, _, category, module, _ in old_filters: From e936d99201737119e6cd60c8c5a3ad84a54873d5 Mon Sep 17 00:00:00 2001 From: Sam <159131400+hularuns@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:15:40 +0000 Subject: [PATCH 5/8] Update changelog/1476.bugfix.rst Co-authored-by: Eneg <42005170+Enegg@users.noreply.github.com> Signed-off-by: Sam <159131400+hularuns@users.noreply.github.com> --- changelog/1476.bugfix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/1476.bugfix.rst b/changelog/1476.bugfix.rst index 9173768db5..9652655425 100644 --- a/changelog/1476.bugfix.rst +++ b/changelog/1476.bugfix.rst @@ -1 +1 @@ -warn_deprecated now respected warning.filter ignores if at least "disnake" is passed to module argument. +Fix ``utils.warn_deprecated`` to respect :mod:`warnings` filters defined by user. From f67ee9af4adf11c6271652a3b0a495a3b7630796 Mon Sep 17 00:00:00 2001 From: Sam <159131400+hularuns@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:18:40 +0000 Subject: [PATCH 6/8] Update disnake/utils.py Co-authored-by: Eneg <42005170+Enegg@users.noreply.github.com> Signed-off-by: Sam <159131400+hularuns@users.noreply.github.com> --- disnake/utils.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/disnake/utils.py b/disnake/utils.py index d781fb3ab1..64fbb7a47f 100644 --- a/disnake/utils.py +++ b/disnake/utils.py @@ -312,15 +312,16 @@ def warn_deprecated( send_warning = False break # break out after first disnake rule, it's good enough. - if send_warning: - # this still allows force bypassing of filters if the default DeprecationWarning ignore is set. - try: - warnings.simplefilter(action="always", category=DeprecationWarning) - warnings.warn(*args, stacklevel=stacklevel + 1, category=DeprecationWarning, **kwargs) - finally: - # NOTE: Is this assertion even necessary? warnings.filters is always at minimum an empty list? - assert isinstance(warnings.filters, list) - warnings.filters[:] = old_filters + # allow force bypassing of filters if the default DeprecationWarning ignore is set. + if not send_warning: + return + + try: + warnings.simplefilter(action="always", category=DeprecationWarning) + warnings.warn(*args, stacklevel=stacklevel + 1, category=DeprecationWarning, **kwargs) + finally: + assert isinstance(warnings.filters, list) + warnings.filters[:] = old_filters def oauth_url( From c415bd1dc153d215da247c14745a979ebcb1e434 Mon Sep 17 00:00:00 2001 From: hularuns <159131400+hularuns@users.noreply.github.com> Date: Sat, 15 Nov 2025 11:27:37 +0000 Subject: [PATCH 7/8] Early return if a disnake ignore rule is found in warn_deprecated. - updated tests to be more explanatory if they fail assertions --- disnake/utils.py | 12 +++--------- tests/test_utils.py | 14 +++++++------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/disnake/utils.py b/disnake/utils.py index 64fbb7a47f..af94d68f27 100644 --- a/disnake/utils.py +++ b/disnake/utils.py @@ -301,21 +301,15 @@ def warn_deprecated( stacklevel = 1 # reset stacklevel, assume we just want the first frame outside library code old_filters = warnings.filters[:] - send_warning = True - if len(old_filters) > 0: + if len(old_filters) >= 0: for action, _, category, module, _ in old_filters: if ( (category is DeprecationWarning) and ("disnake" in str(module)) and (action == "ignore") ): - send_warning = False - break # break out after first disnake rule, it's good enough. - - # allow force bypassing of filters if the default DeprecationWarning ignore is set. - if not send_warning: - return - + return # if a disnake ignore rule is found, we skip warning + # we allow force bypassing of filters if the default/global DeprecationWarning ignore is set. try: warnings.simplefilter(action="always", category=DeprecationWarning) warnings.warn(*args, stacklevel=stacklevel + 1, category=DeprecationWarning, **kwargs) diff --git a/tests/test_utils.py b/tests/test_utils.py index 01af3029f3..3c75889ba3 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -143,28 +143,28 @@ def test_deprecated_warn(msg: str) -> None: ) # this also works with just a plain str utils.warn_deprecated(msg) - assert len(result) == 1 - assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] + assert len(result) == 1, "Expected one warning to be raised." assert result[0].category is DeprecationWarning + assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] # Reset With empty filters - expected behaviour is that a warning is forced because it's empty warnings.resetwarnings() - assert len(warnings.filters) == 0 # should be empty with warnings.catch_warnings(record=True) as result: utils.warn_deprecated(msg) - assert len(result) == 1 - assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] + assert len(result) == 1, "Expected one warning to be raised." assert result[0].category is DeprecationWarning + assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] # Reset With empty filters - expected behaviour is that there is no warning because it's ignored warnings.resetwarnings() - assert len(warnings.filters) == 0 # should be empty with warnings.catch_warnings(record=True) as result: warnings.filterwarnings("ignore", category=DeprecationWarning, module=r"disnake\..*") utils.warn_deprecated(msg) - assert len(result) == 0 + assert len(result) == 0, ( + "Expected no warnings to be raised when declaring disnake to be ignored." + ) warnings.filters[:] = filters # pyright: ignore[reportIndexIssue] From 0ff68b39b7c4bc9a638f152fb04a51a1b3fca98c Mon Sep 17 00:00:00 2001 From: hularuns <159131400+hularuns@users.noreply.github.com> Date: Sat, 15 Nov 2025 11:30:34 +0000 Subject: [PATCH 8/8] Prettied up comments - also removed the cheeky change of old_filters >= and replaced with > --- disnake/utils.py | 6 +++--- tests/test_utils.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/disnake/utils.py b/disnake/utils.py index af94d68f27..77907212df 100644 --- a/disnake/utils.py +++ b/disnake/utils.py @@ -301,15 +301,15 @@ def warn_deprecated( stacklevel = 1 # reset stacklevel, assume we just want the first frame outside library code old_filters = warnings.filters[:] - if len(old_filters) >= 0: + if len(old_filters) > 0: for action, _, category, module, _ in old_filters: if ( (category is DeprecationWarning) and ("disnake" in str(module)) and (action == "ignore") ): - return # if a disnake ignore rule is found, we skip warning - # we allow force bypassing of filters if the default/global DeprecationWarning ignore is set. + return # If a disnake ignore rule is found, we skip warning. + # We allow force bypassing of filters if the default/global DeprecationWarning ignore is set. try: warnings.simplefilter(action="always", category=DeprecationWarning) warnings.warn(*args, stacklevel=stacklevel + 1, category=DeprecationWarning, **kwargs) diff --git a/tests/test_utils.py b/tests/test_utils.py index 3c75889ba3..b57999bdfc 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -138,16 +138,15 @@ def test_deprecated_warn(msg: str) -> None: warnings.resetwarnings() with warnings.catch_warnings(record=True) as result: - warnings.filterwarnings( - "always", category=DeprecationWarning, module=r"disnake\..*" - ) # this also works with just a plain str + warnings.filterwarnings("always", category=DeprecationWarning, module=r"disnake\..*") utils.warn_deprecated(msg) assert len(result) == 1, "Expected one warning to be raised." assert result[0].category is DeprecationWarning assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] - # Reset With empty filters - expected behaviour is that a warning is forced because it's empty + # Reset With empty filters. + # Expected behaviour is that a warning is forced because it's empty. warnings.resetwarnings() with warnings.catch_warnings(record=True) as result: utils.warn_deprecated(msg) @@ -156,7 +155,8 @@ def test_deprecated_warn(msg: str) -> None: assert result[0].category is DeprecationWarning assert result[0].message.args[0] == msg # pyright: ignore[reportAttributeAccessIssue] - # Reset With empty filters - expected behaviour is that there is no warning because it's ignored + # Reset With empty filters and add disnake ignore rule. + # Expected behaviour is that there is no warning because it's ignored. warnings.resetwarnings() with warnings.catch_warnings(record=True) as result: warnings.filterwarnings("ignore", category=DeprecationWarning, module=r"disnake\..*")