Skip to content

Instantly share code, notes, and snippets.

@berdario
Last active February 21, 2023 13:29
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 berdario/f91fb8f212420cd00f75 to your computer and use it in GitHub Desktop.
Save berdario/f91fb8f212420cd00f75 to your computer and use it in GitHub Desktop.
A simple python hook system that doesn't mutate global variables and tries to be as side-effect free as possible
from __future__ import print_function
import sys
from collections import namedtuple
from imp import load_module, find_module
from pathlib import Path
Hooks = namedtuple('Hooks', 'preactivate postactivate get_env_details postrmvirtualenv')
_HOOKS = Hooks._fields
def hook(f):
fname = f.__name__
if fname not in _HOOKS:
msg = '{0} is not a valid hook. Possible hooks are: {1}'.format(fname, _HOOKS)
raise ImportError(msg)
return f
paths = ['.', 'inner']
def select_hooks(module):
for _hook in _HOOKS:
loaded_hook = getattr(module, _hook, None)
if loaded_hook:
yield _hook, loaded_hook
def load_hooks(paths):
for path in paths:
if Path(path).exists():
try:
module = load_module('<TEMP>', *find_module('hooks', [path]))
for hooktuple in select_hooks(module):
yield hooktuple # this would be a 'yield from' in Python3 only
del module
except ImportError as err:
print(err, file=sys.stderr)
def discover_hooks(paths):
hooks = {h:[] for h in _HOOKS}
for hookname, hook in load_hooks(paths):
hooks[hookname].append(hook)
return Hooks(**hooks)
if __name__ == '__main__':
hooks = discover_hooks(paths)
for h in hooks.preactivate:
h('fakeenv')
for h in hooks.get_env_details:
h('fakeenv')
from _utils import hook
@hook
def preactivate(env): # This will fail due to the extra "e"
print('preactivating', env, '!')
# This would fail due to the extra "e"
# @hook
# def preeactivate(env):
# print('preactivating', env, '!')
# The hook decorator is completely optional
def get_env_details(env):
print("here I'd need to supply you some details about", env)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment