I imagine that the hook code would be something like this: INJECTED_WARNING = """ #------------------------------------------------------------------------------ # The following is the import code for the settings directory injected by Juju #------------------------------------------------------------------------------ """ PKG = '_juju_extensions_settings' PKG_DIR = os.path.join(os.path.dirname(path_to_rb_settings_py), PKG) def open_settings(extname): filename = os.path.join(PKG_DIR, extname + '_settings.py') try: return open(filename, 'r+') except IOError: if os.path.exists(filename): raise if not os.path.exists(PKG_DIR): os.mkdir(PKG_DIR) with open(path_to_rb_settings_py, 'a') as settings_py: settings_py.write(INJECTED_WARNING) settings_py.write("from {} import *".format(PKG)) extfile = open(filename, 'w+') with open(os.path.join(PKG_DIR, '__init__.py'), 'a') as initfile: initfile.write('from .{} import *\n'.format(extname)) return extfile def set_settings(extname, settings): # inspired by what the django charm does. lines = [] for name, value in settings.items(): line = '{} = {!r}\n'.format(name, value) try: ast.literal_eval(line) except SyntaxError: hookenv.log('bad setting: {!r}'.format(line)) return # fail? lines.append(line) with open_settings(extname) as extfile: extfile.writelines(lines) extfile.truncate() # Force RB to reload settings.py.i touch(path_to_rb_settings_py) def clear_settings(extname=None): if extname is not None: filename = os.path.join(PKG_DIR, extname + '_settings.py') if os.path.exists(filename): os.remove(filename) extline = 'from .{} import *\n'.format(extname) with open(os.path.join(PKG_DIR, '__init__.py'), 'r+') as initfile: last = 0 for line in initfile: if line == extline: break last += len(line) lines = [] for line in initfile: lines.append(line) initfile.seek(last) initfile.writelines(lines) initfile.truncate() else: if os.path.exists(PKG_DIR): os.rmdir(PKG_DIR) # remove import from path_to_rb_settings_py? def related_name(): """Return the name of the extension in the current relation.""" # We just use the service name. unit = hookenv.related_units()[0] service = unit.partition('/')[0] return service def _handle_relation_settings(): requested = hookenv.relation_get('settings') if not requested: # no settings to add return name = related_name() settings = hookenv.relation_get('_all_settings') or {} settings.update(requested) try: set_settings(name, settings) except Exception as e: hookenv.log("could not update reviewboard settings: {}".format(e)) # hooks @hooks.hook('reviewboard-extensions-relation-joined') def reviewboard_extensions_relation_joined(): # Force reviewboard to reload, thus recognizing the new extension. touch(path_to_rb_settings_py) @hooks.hook('reviewboard-extensions-relation-changed') def reviewboard_extensions_relation_changed(): _handle_relation_settings() @hooks.hook('reviewboard-extensions-relation-departed') def reviewboard_extensions_relation_departed(): clear_settings(related_name()) @hooks.hook('reviewboard-extensions-relation-broken') def reviewboard_extensions_relation_broken(): clear_settings(related_name()) @hooks.hook('stop') def stop(): ... clear_settings()