Skip to content

Instantly share code, notes, and snippets.

@Jerakin
Created March 18, 2026 14:10
Show Gist options
  • Select an option

  • Save Jerakin/9eaa9f415015216e9f6042f3f7c211e9 to your computer and use it in GitHub Desktop.

Select an option

Save Jerakin/9eaa9f415015216e9f6042f3f7c211e9 to your computer and use it in GitHub Desktop.
Deprecate method into a propery
"""Deprecation Property.
Using the decorated function as a property `A().value` works as intended,
while calling it `A().value()` will show the warning with the provided message.
```python
class Test:
@deprecation_property
def b(self):
return "b"
```
"""
from __future__ import annotations
import warnings
from typing import Any, TypeVar
T = TypeVar("T")
class deprecation_property(property): # noqa: N801
"""Property decorator warns if the user is calling the decorated as a method."""
def __get__(self, obj: T, obj_type: type[T] | None = None) -> Any: # noqa: ANN401
value: Any = super().__get__(obj, obj_type)
_property = self
class _Proxy(type(value)):
def __call__(self) -> Any: # noqa: ANN401
name = _property.fget.__name__ if _property.fget else "unknown property" # ty:ignore[unresolved-attribute]
warnings.warn(
f"Calling '{name}' as method is deprecated."
" Use it as a property instead.",
DeprecationWarning,
stacklevel=2,
)
return value
try:
return _Proxy(value)
except TypeError:
return _Proxy(*value)
"""Deprecation Property.
Alternative version that supports a custom message.
Using the decorated function as a property `A().value` works as intended,
while calling it `A().value()` will show the warning with the provided message.
```python
class Test:
@deprecation_property
def b(self):
return "b"
```
"""
from __future__ import annotations
import warnings
from typing import Any, TypeVar
T = TypeVar("T")
def deprecation_property(
message: str, warning_type: type[Warning] = DeprecationWarning
) -> type[property]:
class _Property(property):
def __get__(self, obj: T, obj_type: type[T] | None = None) -> Any: # noqa: ANN401
value: Any = super().__get__(obj, obj_type)
class _Proxy(type(value)):
def __call__(self) -> Any: # noqa: ANN401
warnings.warn(message, warning_type, stacklevel=2)
return value
try:
return _Proxy(value)
except TypeError:
return _Proxy(*value)
return _Property
class Test:
def __init__(self) -> None:
self.value = "b"
@deprecation_property
def b(self) -> str:
return self.value
@b.setter
def b(self, v: str) -> None:
self.value = v
def test_deprecated_property_works_as_property():
t = Test()
p = t.b
assert t.b == "b"
def test_deprecated_property_works_as_method():
t = Test()
assert t.b() == "b"
def test_deprecated_property_calls_warning():
t = Test()
with pytest.deprecated_call():
t.b()
def test_deprecated_property_still_setter():
t = Test()
assert t.b == "b"
t.b = "c"
assert t.b == "c"
class Test:
def __init__(self) -> None:
self.value = "b"
@deprecation_property("`.b()` is deprecated use `.b` instead")
def b(self) -> str:
return self.value
@b.setter
def b(self, v: str) -> None:
self.value = v
def test_deprecated_property_works_as_property():
t = Test()
p = t.b
assert t.b == "b"
def test_deprecated_property_works_as_method():
t = Test()
assert t.b() == "b"
def test_deprecated_property_calls_warning():
t = Test()
with pytest.deprecated_call():
t.b()
def test_deprecated_property_still_setter():
t = Test()
assert t.b == "b"
t.b = "c"
assert t.b == "c"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment