Skip to content

Standalone script (install doit on the fly)

Oliver Schneider edited this page Jun 7, 2019 · 1 revision

NB: standalone does not refer to a script without dependencies in this context. Instead it refers to the fact that you can run this script without having to rely on executing it implicitly it via the doit command.

Suppose you want to make use of doit, but you would also like for the users of your script to be able to start said script the conventional way instead of invoking doit which in turn will look for a dodo.py file in the current folder (unless an alternative file is given with the -f command line switch).

Taking the task_hello() function from the introduction and the instructions from here we can extend the dodo.py (or whatever you want to call the script now that it's standalone) as follows in order for it to install the doit package on-the-fly:

#!/usr/bin/python3
import sys

def import_or_install(modname, pip_name=None):
    """Import or install a package and allow the PIP package name to be
       different from the module we attempt to import.
    """
    if modname in sys.modules:
        return sys.modules[modname]
    from importlib import import_module
    mod = None
    try:
        mod = import_module(modname)
    except ImportError:
        print("Attempting to install %s on the fly." % (pip_name or modname), file=sys.stderr)
        cmdline = ["install", "--upgrade", "--user"]
        try:
            from pip._internal import main as pipmain
            cmdline.append(pip_name or modname)
            pipmain(cmdline)
            mod = import_module(modname)
        except ImportError as exc:
            print("Could not install %s on the fly." % (pip_name or modname), file=sys.stderr)
            raise exc from None
    if mod is not None:
        globals()[modname] = mod
    return mod

def task_hello():
    """hello"""

    def python_hello(targets):
        with open(targets[0], "a") as output:
            output.write("Python says Hello World!!!\n")

    return {
        "actions": [python_hello],
        "targets": ["hello.txt"],
        }

if __name__ == "__main__":
    import_or_install("doit")
    doit.run(globals())

... which is pretty standalone. It doesn't require user-intervention to install dependencies nor does it require the invocation via doit.

Clone this wiki locally