Skip to content

Instantly share code, notes, and snippets.

@typemytype
Created January 23, 2017 20:58
Show Gist options
  • Select an option

  • Save typemytype/0554f1e313d7d94455e09a347e26892e to your computer and use it in GitHub Desktop.

Select an option

Save typemytype/0554f1e313d7d94455e09a347e26892e to your computer and use it in GitHub Desktop.
class Implementation(object):
"""
Implementation object collection all methods for a given implementation
"""
def __init__(self):
self.funcMap = {}
self._currentInstance = None
def __get__(self, instance, instanceCls):
# set the current instance
self._currentInstance = instance
# return self, this mains the object will __getattr__ calls for methods
return self
def __getattr__(self, attr):
# get a method
# if the curren instance does not have the attr
# raise an not implemented error
if not hasattr(self._currentInstance, attr):
raise NotImplementedError("'%s' not implemented" % attr)
def attrWrapper(*args, **kwargs):
# loop over all parent classes
for cls in self._currentInstance.__class__.__mro__:
# check if the cls has that attr
if hasattr(cls, attr):
# get the function
func = getattr(cls, attr)
# check if the function is wrapped
if hasattr(func, "wrappedFunc"):
# check the wrapped function is in the function map
# it can happen multiple implementation have wrapped functions
# with the same attr name
if func.wrappedFunc == self.funcMap[attr]:
# call the function with the current instance
result = func.wrappedFunc(self._currentInstance, *args, **kwargs)
# reset the currentInstance
self._currentInstance = None
# return the result
return result
# decorate by returning an attrWrapper
return attrWrapper
def implement(self, func):
# `implement` decorates the function
# accisible through an implementation
# if this is called without an implementation
# it will search in the parent classes for the same
# function by name, if not available it will raise
# a NotImplementedError
# get the name of the decorated func
name = func.__name__
# map the func
self.funcMap[name] = func
# the decorator wrapper
def wrapper(instance, *args, **kwargs):
found = False
# loop over all parent classes
for cls in instance.__class__.__mro__:
# check if func name is available
if hasattr(cls, name):
# get the func
func = getattr(cls, name)
# check if the function is not a wrapped func
if not hasattr(func, "wrappedFunc"):
# set found flag to true
found = True
break
# if not found raise NotImplementedError
if found is False:
raise NotImplementedError("'%s' not implemented" % name)
# call that found function
return func(instance, *args, **kwargs)
# tag the wrapped decorator with the wrapped func
wrapper.wrappedFunc = func
# decorate by returning an wrapper
return wrapper
####
class BaseContour(object):
def aMethod(self, point):
return "BaseContour aMethod", point
class BetaContour(BaseContour):
beta = Implementation()
@beta.implement
def aMethod(self, point):
return "BetaContour aMethod", point
@beta.implement
def moreMethods(self, foo):
return "BetaContour moreMethods", foo
class Contour(BetaContour):
roboFont = Implementation()
@roboFont.implement
def aMethod(self, point, test):
return "Contour aMethod", point, test
@BetaContour.beta.implement
def testing(self, someThing):
return "Contour testing", someThing
c = Contour()
print c.aMethod((10, 10))
print c.beta.aMethod((20, 20)), "-"
print c.roboFont.aMethod((30, 30), False)
print c.roboFont.aMethod("ll", "kk")
print c.beta.moreMethods("bar")
# print c.roboFont.aMethoddfsdf("ll", "kk") # raise error
print c.beta.testing("hello")
# print c.testing("hello") # raise error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment