Skip to content

Instantly share code, notes, and snippets.

@linw1995
Last active March 10, 2021 07:59
Show Gist options
  • Select an option

  • Save linw1995/e160910d2d30e0498309f6a7ecc80c72 to your computer and use it in GitHub Desktop.

Select an option

Save linw1995/e160910d2d30e0498309f6a7ecc80c72 to your computer and use it in GitHub Desktop.
MustSetProperty -- descriptor that raises exception if its value is None.
from typing import Any, Generic, Optional, TypeVar, Union, overload
T = TypeVar("T")
class UnsetError(Exception):
pass
class MustSetProperty(Generic[T]):
def __set_name__(self, owner: Any, name: str):
"""
Customized names -- Descriptor HowTo Guide
https://docs.python.org/3/howto/descriptor.html#customized-names
"""
self.public_name = name
self.private_name = f"__must_set_{name}"
@overload
def __get__(self, obj: None, objtype: Any) -> "MustSetProperty[T]":
pass
@overload
def __get__(self, obj: Any, objtype: Any) -> T:
pass
def __get__(self, obj: Any, objtype: Any) -> Union["MustSetProperty[T]", T]:
if obj is None:
return self
if (value := getattr(obj, self.private_name, None)) is None:
raise UnsetError(f"{self.public_name} is missing")
return value
def __set__(self, obj: Any, value: Optional[T]):
setattr(obj, self.private_name, value)
class Bar:
name = MustSetProperty[str]()
assert isinstance(Bar.name, MustSetProperty)
bar = Bar()
try:
bar.name # raise UnsetError
except UnsetError:
print("accesing error")
bar.name = "bar"
print(bar.name) # accesing OK
bar.name = None # set None
try:
bar.name # raise UnsetError
except UnsetError:
print("accesing error")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment