Package: relmod
relmod- auto-reloading module development libraryPlace your Python code in a directory and start using it immediately.Import file names as auto-deep-reloading modules.Import directories as auto-reloading namespaces.Rununittestcases easily.Running the following:import relmod

with open('./myfunc.py', 'w') as f:    # create a file with a function
    f.write("""
def add(x, y):
    return x + y
""")

myfunc = relmod.at('./myfunc.py')      # load file as a module

print(myfunc.add(3, 4))                # call the function

import unittest
class TestMyFunc(unittest.TestCase):   # create a test
    def test_add(self):
        self.assertEqual(
            myfunc.add(3, 4), 7)

relmod.runtest(TestMyFunc)             # run the testproduces this output:7
test_add (__main__.TestMyFunc) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.003s

OKMotivationTherelmodlibrary allows for placing helper modules and functions
in a directory and making them quickly available, with reloading if needed.
This helps with converting existing notebook cells into re-usable
library code.Tests for these library functions can be developed easily along the way.When you're finished, you no longer needrelmod. You have a readily usable
Python library. Packaging is up to you.ExamplesUse the current working directory as a namespace module:lib = relmod.at('.')Entering folders that are not valid Python identifiers is supported:py = lib['./Documents and Settings'].sub.foldersRelative directories can be given:parent = lib['../']  # go up a directory, using []ImportingImport an object from a module into the global namespace:relmod.imp('./myfunc.py', 'add')Rename references in the import usingasrelmod.imp('./myfunc.py', 'add as add2')
print(add2(3, 4))Names can be comma-separated, e.g.'add, sub, mult, div'.Import a filename as another name:relmod.imp('./myfunc.py as mfunc')
mfunc.add(1, 2)Note:Non-module objects imported usingrelmod.impare not automatically
reloaded if changes occur to the file. You will need to reimport them.Cell ModeThe.installfunction will use the current working directory
if__file__is not defined. This is useful in a cell-mode
environment.here = relmod.install(globals())Using.installallows for relative imports within__main__:from . import myfunc
print(myfunc.add(3, 4))Use the parent directory of__file__as a namespace:here = relmod.up(__file__)Top-level ModulesYou can register a directory or file as a top-level module and then import it.relmod.toplevel('myfunc', './myfunc.py')
import myfunc
myfunc.add(3, 4)TestingRun a single test case method:relmod.runtest(TestMyFunc, 'test_add')Find and run allunittest.TestCaseclasses in a module:relmod.testmod(mod)Only run a single class in a test file and exit:@relmod.testonly()
class Test(unittest.TestCase):
    ...

    @relmod.testfocus  # optionally focus only on this test
    def test_thing(self):
        ...How it worksThe.imp,.at,.up,.use, and.installfunctions returnFakeModuleTypeobjects wrapped in aModuleProxyobject that trigger reloading when
accessing its attributes, if needed. Namespace and__init__.pyfake
modules perform auto-reloading on attribute access as well.The files and directories accessed viarelmodare not found insys.modules. These "fake modules" are handled separately and
behave as regular Python modules, with enhancements. Relative
imports within a fake module perform dependency tracking,
allowing for lazy deep-reloading of modules.The auto-reloading of a module's sourcewill not hot-patchexisting
objects like the%autoreloadmagic from IPython. Hot-patching makes
certain assumptions about your code, and if violated, will introduce
subtle bugs.Relative Path ResolutionTherelmod.atandrelmod.upfunctions useos.getcwd()when resolving
relative paths.Therelmod.useandrelmod.impfunctions use__file__from the calling
frame's globals dictionary, and usesos.getcwd()as a fallback if__file__is not defined.It is recommended to use.useand.impin library scripts where relative
paths must resolve relative to the script's file path rather than the current
working directory.Here is a comparison of different ways to resolve the path".":lib = relmod.at('.')     # resolved using os.getcwd()

lib = relmod.use('.')    # resolved using __file__

relmod.imp('. as lib')   # resolved using __file__,
                         # injects `lib` into caller's global namespaceOther UtilitiesThere are other utilities inrelmodthat are useful for quick development.APIDescriptionrelmod.execfile()Executes a file's contents in a provided namespacerelmod.autoAuto-imports toplevel modules on attribute accessrelmod.sitePredefined site module names, seefakesite.pyInstallpip3 install relmodZenBeautiful is better than ugly.relmodis a useful alternative toimportlib.reloadandsys.pathhacking.Explicit is better than implicit.If you want a file, request it.Namespaces are one honking great idea -- let's do more of those!relmodturns the filesystem into a namespaceThere should be one-- and preferably only one --obvious way to do it.relmodis the way ;-)