Skip to content

Instantly share code, notes, and snippets.

@o11c
Last active August 26, 2015 03:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save o11c/ce0c2ff74b87ea71ad46 to your computer and use it in GitHub Desktop.
Save o11c/ce0c2ff74b87ea71ad46 to your computer and use it in GitHub Desktop.
import util
from collections import namedtuple
Foo = namedtuple('Foo', 'x y')
@util.member(Foo)
def frob(self):
return self.x + self.y
util.cleanup()
#!/usr/bin/env python3
import foo
assert not hasattr(foo, 'frob')
assert foo.Foo(1, 2).frob() == 3
#!/usr/bin/env python3
import traceback
import util
class Foo:
def oops(self):
raise ValueError
class Bar:
pass
@util.member(Bar)
def oops(self):
raise ValueError
util.cleanup()
def tb_has_qualname(cls):
try:
cls().oops()
except ValueError as e:
fun_name = traceback.extract_tb(e.__traceback__)[-1][2]
unqual = fun_name == 'oops'
assert unqual or fun_name.endswith('.oops')
return not unqual
assert False, 'unreachable'
def test():
foo_q = tb_has_qualname(Foo)
print('Foo qualname?', foo_q)
bar_q = tb_has_qualname(Bar)
print('Bar qualname?', bar_q)
assert foo_q == bar_q
if __name__ == '__main__':
test()
import sys
# It is not possible to delete something from the calling globals before
# it exists. Remember, the decorator (necessarily) operates on the
# function *before* its own result is assigned to the namespace.
DELETEME = object()
def member(cls):
def decorator(fun):
name = fun.__name__
fun.__qualname__ = '%s.%s' % (cls.__qualname__, name)
setattr(cls, name, fun)
return DELETEME
return decorator
def filtered_dir(obj):
return [x for x in dir(obj) if x != '__%s__' % x.strip('_')]
def print_info(name, obj):
print('%s: ' % name, obj)
print('type(%s): ' % name, type(obj))
print('filtered_dir(%s):' % name, filtered_dir(obj))
if hasattr(obj, '__dict__'):
print('vars(%s): ' % name, vars(obj))
print()
def cleanup(exclude={'DELETEME'}):
# Basically the same logic as collections.namedtuple uses
# to set the returned class's __module__
try:
mod_globals = sys._getframe(1).f_globals
except (AttributeError, ValueError):
print('Unable to get caller\'s globals for cleanup')
return
keys_to_delete = {k for k, v in mod_globals.items() if v is DELETEME}
for k in keys_to_delete - exclude:
del mod_globals[k]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment