From 279dd30a2f57bc2158f16983a5a0e757e3ff660f Mon Sep 17 00:00:00 2001 From: "Haoyu (Daniel)" Date: Sat, 18 May 2024 17:39:35 +0800 Subject: [PATCH 1/5] fix comment case --- monty/dev.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monty/dev.py b/monty/dev.py index 10a16677..629b05d2 100644 --- a/monty/dev.py +++ b/monty/dev.py @@ -64,9 +64,9 @@ def _is_in_owner_repo() -> bool: owner_repo = ( result.stdout.decode("utf-8") .strip() - .lstrip("https://github.com/") # https clone - .lstrip("git@github.com:") # ssh clone - .rstrip(".git") # ssh clone + .lstrip("https://github.com/") # HTTPS clone + .lstrip("git@github.com:") # SSH clone + .rstrip(".git") # SSH clone ) return owner_repo == os.getenv("GITHUB_REPOSITORY") From a044476198f4945360caf4b4d258cb373908617c Mon Sep 17 00:00:00 2001 From: "Haoyu (Daniel)" Date: Wed, 22 May 2024 10:23:32 +0800 Subject: [PATCH 2/5] improve format of deprecation msg --- monty/dev.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/monty/dev.py b/monty/dev.py index 629b05d2..0abc4019 100644 --- a/monty/dev.py +++ b/monty/dev.py @@ -103,7 +103,11 @@ def craft_message( r = replacement.__func__ else: r = replacement - msg += f"; use {r.__name__} in {r.__module__} instead." + + if deadline is None: + msg += f"; use {r.__name__} in {r.__module__} instead." + else: + msg += f"Use {r.__name__} in {r.__module__} instead." if message: msg += "\n" + message From c5dec2ec8475a577071bdca4d510a965d5f3f61a Mon Sep 17 00:00:00 2001 From: "Haoyu (Daniel)" Date: Wed, 22 May 2024 10:54:51 +0800 Subject: [PATCH 3/5] allow decorator class --- monty/dev.py | 24 ++++++++++++++++++++++-- tests/test_dev.py | 17 +++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/monty/dev.py b/monty/dev.py index 0abc4019..f53b57ac 100644 --- a/monty/dev.py +++ b/monty/dev.py @@ -6,6 +6,7 @@ from __future__ import annotations import functools +import inspect import logging import os import subprocess @@ -113,7 +114,7 @@ def craft_message( msg += "\n" + message return msg - def deprecated_decorator(old: Callable) -> Callable: + def deprecated_function_decorator(old: Callable) -> Callable: def wrapped(*args, **kwargs): msg = craft_message(old, replacement, message, _deadline) warnings.warn(msg, category=category, stacklevel=2) @@ -121,13 +122,32 @@ def wrapped(*args, **kwargs): return wrapped + def deprecated_class_decorator(cls: Type) -> Type: + original_init = cls.__init__ + + def new_init(self, *args, **kwargs): + msg = craft_message(cls, replacement, message, _deadline) + warnings.warn(msg, category=category, stacklevel=2) + original_init(self, *args, **kwargs) + + cls.__init__ = new_init + return cls + # Convert deadline to datetime type _deadline = datetime(*deadline) if deadline is not None else None # Raise CI warning after removal deadline raise_deadline_warning() - return deprecated_decorator + def decorator(target: Callable) -> Callable: + if inspect.isfunction(target): + return deprecated_function_decorator(target) + elif inspect.isclass(target): + return deprecated_class_decorator(target) + else: + raise TypeError("The @deprecated decorator can only be applied to classes or functions") + + return decorator class requires: diff --git a/tests/test_dev.py b/tests/test_dev.py index dee1a94b..9ff5f418 100644 --- a/tests/test_dev.py +++ b/tests/test_dev.py @@ -92,6 +92,23 @@ def classmethod_b(cls): with pytest.warns(DeprecationWarning): assert TestClass_deprecationwarning().classmethod_b() == "b" + def test_deprecated_class(self): + class TestClassNew: + """A dummy class for tests.""" + + def method_a(self): + pass + + @deprecated(replacement=TestClassNew) + class TestClassOld: + """A dummy class for tests.""" + + def method_b(self): + pass + + with pytest.warns(FutureWarning, match="TestClassOld is deprecated"): + TestClassOld() + def test_deprecated_deadline(self, monkeypatch): with pytest.raises(DeprecationWarning): with patch("subprocess.run") as mock_run: From eaa6c901543cb860bb5314f690065884f2d0c4be Mon Sep 17 00:00:00 2001 From: "Haoyu (Daniel)" Date: Wed, 22 May 2024 10:56:13 +0800 Subject: [PATCH 4/5] ruff fixes --- monty/dev.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/monty/dev.py b/monty/dev.py index f53b57ac..ccbb4b74 100644 --- a/monty/dev.py +++ b/monty/dev.py @@ -145,7 +145,9 @@ def decorator(target: Callable) -> Callable: elif inspect.isclass(target): return deprecated_class_decorator(target) else: - raise TypeError("The @deprecated decorator can only be applied to classes or functions") + raise TypeError( + "The @deprecated decorator can only be applied to classes or functions" + ) return decorator From 37fdad7096e51066fc112dd1239f543879178556 Mon Sep 17 00:00:00 2001 From: Haoyu Yang Date: Wed, 22 May 2024 13:30:09 +0800 Subject: [PATCH 5/5] reduce repetition --- monty/dev.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/monty/dev.py b/monty/dev.py index ccbb4b74..2e9de435 100644 --- a/monty/dev.py +++ b/monty/dev.py @@ -106,9 +106,10 @@ def craft_message( r = replacement if deadline is None: - msg += f"; use {r.__name__} in {r.__module__} instead." + msg += "; use " # for better formatting else: - msg += f"Use {r.__name__} in {r.__module__} instead." + msg += "Use " + msg += f"{r.__name__} in {r.__module__} instead." if message: msg += "\n" + message