Skip to content

Instantly share code, notes, and snippets.

@L3viathan
Created August 18, 2018 15:57
Show Gist options
  • Save L3viathan/0a70241d8ab4ca20c8a87c99d7a9875b to your computer and use it in GitHub Desktop.
Save L3viathan/0a70241d8ab4ca20c8a87c99d7a9875b to your computer and use it in GitHub Desktop.
Abusing Type Annotations (inspired by zmitchell)
# inspiration: https://tinkering.xyz/abusing-type-annotations/
from __future__ import annotations
from typeanno import restrict
@restrict
class Test:
x: 0 < x < 10
def __init__(self, x):
self.x = x
if __name__ == '__main__':
t = Test(7)
print(t.x, "is 7")
t.x = 3
print(t.x, "is 3")
try:
t.x = 12
print("This won't be printed")
except ValueError:
print("Couldn't set property")
import inspect
import ast
def make_restriction(ann, name):
return eval(
compile(
ast.Expression(
body=ast.Lambda(
args=ast.arguments(
args=[ast.arg(
arg=name,
lineno=1,
col_offset=0,
)],
kwonlyargs=[],
kw_defaults=[],
defaults=[],
),
body=ann,
lineno=1,
col_offset=0,
),
),
filename="<ast>",
mode="eval",
),
)
def restrict(cls):
src = inspect.getsource(cls)
mod = ast.parse(src)
for statement in mod.body[0].body:
if isinstance(statement, ast.AnnAssign):
name = statement.target.id
restriction = make_restriction(
statement.annotation,
name,
)
def getter(self):
return getattr(self, f"_{name}")
def setter(self, value):
if restriction(value):
setattr(self, f"_{name}", value)
else:
raise ValueError(
"Value {value!r} didn't pass check",
)
setattr(cls, name, property(fget=getter, fset=setter))
return cls
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment