sqlite-utils provides a decorator for registering custom Python functions that looks like this:
from sqlite_utils import Database
db = Database(memory=True)
@db.register_function
def reverse_string(s):
return "".join(reversed(list(s)))
I wanted to add an optional deterministic=True parameter to the decorator.
Problem: the decorator currently does not take any arguments. But I wanted this to work as well:
@db.register_function(deterministic=True)
def reverse_string(s):
return "".join(reversed(list(s)))
I don't want to break backwards compatibility with existing code.
First lesson: any time you are designing a decorator that might accept arguments in the future, design it to work like this!
@db.register_function()
def reverse_string(s):
return "".join(reversed(list(s)))
Since I hadn't done that, I needed an alternative pattern that could differentiate between the two ways in which the decorator might be called. I ended up going with this:
def register_function(self, fn=None, deterministic=None):
def register(fn):
name = fn.__name__
arity = len(inspect.signature(fn).parameters)
kwargs = {}
if deterministic and sys.version_info >= (3, 8):
kwargs["deterministic"] = True
self.conn.create_function(name, arity, fn, **kwargs)
return fn
if fn is None:
return register
else:
register(fn)
Created 2020-10-28T14:54:48-07:00, updated 2020-12-29T13:55:23-08:00 · History · Edit