Forked from mahmoudimus/python-monkey-patch-built-ins.py
Last active
October 28, 2020 12:16
-
-
Save carymrobbins/7920536 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# found this from Armin R. on Twitter, what a beautiful gem ;) | |
import ctypes | |
from types import DictProxyType, MethodType | |
def main(): | |
import datetime | |
class _(monkey(int)): | |
# Create properties for timedelta constructors (seconds, minutes, etc.). | |
def __metaclass__(name, bases, attrs): | |
ks = ['seconds', 'minutes', 'hours', 'days'] | |
for k in ks: | |
p = property(lambda self, k=k: datetime.timedelta(**{k: self})) | |
# Create a property for self.second and self.seconds. | |
attrs[k[:-1]] = attrs[k] = p | |
return type(name, bases, attrs) | |
class _(monkey(datetime.timedelta)): | |
@property | |
def ago(self): | |
return datetime.datetime.now() - self | |
@property | |
def from_now(self): | |
return datetime.datetime.now() + self | |
print '3 days ago:', (3).days.from_now | |
print '2 hours ago:', (2).hours.ago | |
print '1 minute ago:', (1).minute.ago | |
# figure out side of _Py_ssize_t | |
if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'): | |
_Py_ssize_t = ctypes.c_int64 | |
else: | |
_Py_ssize_t = ctypes.c_int | |
# regular python | |
class _PyObject(ctypes.Structure): | |
pass | |
_PyObject._fields_ = [ | |
('ob_refcnt', _Py_ssize_t), | |
('ob_type', ctypes.POINTER(_PyObject)) | |
] | |
# python with trace | |
if object.__basicsize__ != ctypes.sizeof(_PyObject): | |
class _PyObject(ctypes.Structure): | |
pass | |
_PyObject._fields_ = [ | |
('_ob_next', ctypes.POINTER(_PyObject)), | |
('_ob_prev', ctypes.POINTER(_PyObject)), | |
('ob_refcnt', _Py_ssize_t), | |
('ob_type', ctypes.POINTER(_PyObject)) | |
] | |
class _DictProxy(_PyObject): | |
_fields_ = [('dict', ctypes.POINTER(_PyObject))] | |
def reveal_dict(proxy): | |
if not isinstance(proxy, DictProxyType): | |
raise TypeError('dictproxy expected') | |
dp = _DictProxy.from_address(id(proxy)) | |
ns = {} | |
ctypes.pythonapi.PyDict_SetItem(ctypes.py_object(ns), | |
ctypes.py_object(None), | |
dp.dict) | |
return ns[None] | |
def get_class_dict(cls): | |
d = getattr(cls, '__dict__', None) | |
if d is None: | |
raise TypeError('given class does not have a dictionary') | |
if isinstance(d, DictProxyType): | |
return reveal_dict(d) | |
return d | |
def monkey(cls): | |
""" | |
>>> import datetime | |
>>> class _(monkey(int)): | |
... @property | |
... def days(self): | |
... return datetime.timedelta(days=self) | |
>>> class _(monkey(datetime.timedelta)): | |
... @property | |
... def ago(self): | |
... return datetime.datetime.now() - self | |
>>> (3).days.ago | |
datetime.datetime(2013, 12, 10, 16, 32, 55, 204075) | |
""" | |
class_dict = get_class_dict(cls) | |
class Meta(type): | |
def __new__(mcs, name, bases, attrs): | |
for k, v in attrs.iteritems(): | |
class_dict[k] = v | |
return super(Meta, mcs).__new__(mcs, name, bases, attrs) | |
class Klass(object): | |
__metaclass__ = Meta | |
return Klass | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment