Last active
February 21, 2023 13:29
-
-
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
This file contains 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
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') |
This file contains 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
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