Source code for mmf.utils.run
r"""Running Programs
This module is intended to be used to manage important runs that generate data
for a paper, etc.
For interactive use, start python as follows::
python -im mmf.utils.run
If you need to run a script, then use this module as the startup file with one
of the following commands::
PYTHONSTARTUP=path_to_mmf/mmf/utils/run.py python file.py
PYTHONSTARTUP=path_to_mmf/mmf/utils/run.py python -c "import blah;..."
To find the full path for the previous commands, run::
python -c"import sys;sys._pymmf_no_init=True;import mmf;print mmf.run_cmd()"
This can be aliased for easy use.
Purpose
-------
The aim of this module is reproducibility:
1) This module assumes that the application be run in an appropriately named
directory: no special sub-directory will be created (other than those
associated with :class:`mmf.archive.DataSet` instances).
2) The command must be run in a mercurial repository with no outstanding
commits. The current revision number and checksum is used for output. These
checks can be temporarily disabled by setting the environmental variable
`STRICT=false`, but this should be avoided except during testing as it breaks
the reproducibility.
3) All input and output is recorded.
4) ``pip`` is used to record the versions of libraries installed when the
program is run.
"""
import os.path
import subprocess
import sys
[docs]def run_cmd():
r"""Return the run command for running python with this module as the
startup file."""
return 'PYTHONSTARTUP="' + os.path.realpath(__file__) + '" python'
[docs]def get_hg_checksum(strict=True):
r"""Return a string of the form `<rev>_<checksum>` where `<rev>` is the
local revision number and `<checksum>` is the checksum of the current
revision. (Note: `<rev>` is not unique and may vary from repository to
repository, but provides a simple chronological ordering for runs that is
not intuitively deducible from the `<checksum>`.)
Parameters
----------
strict : bool
If `True`, then this will raise a :exc:`ValueError` exception if the
there are uncommited changes.
"""
try:
subprocess.check_output(["hg","--version"]).strip()
except:
print("ERROR: Could not execute Mercurial (hg)!")
raise
try:
hg_checksum = subprocess.check_output(["hg","-q","id"]).strip()
except:
print("ERROR: Could not get version! (Is there are repository here?)")
raise
try:
hg_local_revision = subprocess.check_output(["hg","id","-n"]).strip()
except:
print("ERROR: Could not get local revision!")
raise
if len(hg_checksum) not in [12, 13]:
raise ValueError(
'Please run from within the mercurial repo. "hg -1 id" gave:\n' +
hg_checksum)
if (strict and hg_checksum.endswith('+')):
raise ValueError(
'Repository has uncommited changes! ' +
'Commit ("hg com") before running.')
hg_checksum = "%s_%s" % (hg_local_revision, hg_checksum)
return hg_checksum
[docs]def get_pip_requirements():
r"""Return the ``pip`` requirements file as a string."""
if "__main__" == __name__:
strict = (os.environ.get('STRICT', "True").lower() != "false")
hg_checksum = get_hg_checksum(strict)
print hg_checksum