Example #1
0
def check_save_version(expected=None,
                       filename=None,
                       die=False,
                       verbose=True,
                       **kwargs):
    '''
    A convenience function that bundles check_version with git_info and saves
    automatically to disk from the calling file. The idea is to put this at the
    top of an analysis script, and commit the resulting file, to keep track of
    which version of Covasim was used.

    Args:
        expected (str): expected version information
        filename (str): file to save to; if None, guess based on current file name
        kwargs (dict): passed to git_info(), and thence to sc.savejson()

    **Examples**::

        cv.check_save_version()
        cv.check_save_version('1.3.2', filename='script.gitinfo', comments='This is the main analysis script')
        cv.check_save_version('1.7.2', folder='gitinfo', comments={'SynthPops':sc.gitinfo(sp.__file__)})
    '''

    # First, check the version if supplied
    if expected:
        check_version(expected, die=die, verbose=verbose)

    # Now, check and save the git info
    if filename is None:
        filename = sc.getcaller(tostring=False)['filename']
    git_info(filename=filename, frame=3, **kwargs)

    return
def git_info(filename=None, check=False, comments=None, old_info=None, die=False, indent=2, verbose=True, frame=2, **kwargs):
    '''
    Get current git information and optionally write it to disk. Simplest usage
    is cv.git_info(__file__)

    Args:
        filename  (str): name of the file to write to or read from
        check    (bool): whether or not to compare two git versions
        comments (dict): additional comments to include in the file
        old_info (dict): dictionary of information to check against
        die      (bool): whether or not to raise an exception if the check fails
        indent    (int): how many indents to use when writing the file to disk
        verbose  (bool): detail to print
        frame     (int): how many frames back to look for caller info
        kwargs   (dict): passed to sc.loadjson() (if check=True) or sc.savejson() (if check=False)

    **Examples**::

        cv.git_info() # Return information
        cv.git_info(__file__) # Writes to disk
        cv.git_info('covasim_version.gitinfo') # Writes to disk
        cv.git_info('covasim_version.gitinfo', check=True) # Checks that current version matches saved file
    '''

    # Handle the case where __file__ is supplied as the argument
    if isinstance(filename, str) and filename.endswith('.py'):
        filename = filename.replace('.py', '.gitinfo')

    # Get git info
    calling_file = sc.makefilepath(sc.getcaller(frame=frame, tostring=False)['filename'])
    cv_info = {'version':cvv.__version__}
    cv_info.update(sc.gitinfo(__file__, verbose=False))
    caller_info = sc.gitinfo(calling_file, verbose=False)
    caller_info['filename'] = calling_file
    info = {'covasim':cv_info, 'called_by':caller_info}
    if comments:
        info['comments'] = comments

    # Just get information and optionally write to disk
    if not check:
        if filename is not None:
            output = sc.savejson(filename, info, indent=indent, **kwargs)
        else:
            output = info
        return output

    # Check if versions match, and optionally raise an error
    else:
        if filename is not None:
            old_info = sc.loadjson(filename, **kwargs)
        string = ''
        old_cv_info = old_info['covasim'] if 'covasim' in old_info else old_info
        if cv_info != old_cv_info: # pragma: no cover
            string = f'Git information differs: {cv_info} vs. {old_cv_info}'
            if die:
                raise ValueError(string)
            elif verbose:
                print(string)
        return
Example #3
0
def savefig(filename=None, comments=None, **kwargs):
    '''
    Wrapper for Matplotlib's savefig() function which automatically stores Covasim
    metadata in the figure. By default, saves (git) information from both the Covasim
    version and the calling function. Additional comments can be added to the saved
    file as well. These can be retrieved via cv.get_png_metadata(). Metadata can
    also be stored for SVG and PDF formats, but cannot be automatically retrieved.

    Args:
        filename (str): name of the file to save to (default, timestamp)
        comments (str): additional metadata to save to the figure
        kwargs (dict): passed to savefig()

    **Example**::

        cv.Sim().run(do_plot=True)
        filename = cv.savefig()
    '''

    # Handle inputs
    dpi = kwargs.pop('dpi', 150)
    metadata = kwargs.pop('metadata', {})

    if filename is None:  # pragma: no cover
        now = sc.getdate(dateformat='%Y-%b-%d_%H.%M.%S')
        filename = f'covasim_{now}.png'

    metadata = {}
    metadata['Covasim version'] = cvv.__version__
    gitinfo = git_info()
    for key, value in gitinfo['covasim'].items():
        metadata[f'Covasim {key}'] = value
    for key, value in gitinfo['called_by'].items():
        metadata[f'Covasim caller {key}'] = value
    metadata['Covasim current time'] = sc.getdate()
    metadata['Covasim calling file'] = sc.getcaller()
    if comments:
        metadata['Covasim comments'] = comments

    # Handle different formats
    lcfn = filename.lower()  # Lowercase filename
    if lcfn.endswith('pdf') or lcfn.endswith('svg'):
        metadata = {
            'Keywords': str(metadata)
        }  # PDF and SVG doesn't support storing a dict

    # Save the figure
    pl.savefig(filename, dpi=dpi, metadata=metadata, **kwargs)
    return filename
def savefig(filename=None, comments=None, fig=None, **kwargs):
    '''
    Wrapper for Matplotlib's ``pl.savefig()`` function which automatically stores
    Covasim metadata in the figure.

    By default, saves (git) information from both the Covasim version and the calling
    function. Additional comments can be added to the saved file as well. These can
    be retrieved via ``cv.get_png_metadata()`` (or ``sc.loadmetadata``). Metadata can
    also be stored for PDF, but cannot be automatically retrieved.

    Args:
        filename (str/list): name of the file to save to (default, timestamp); can also be a list of names
        comments (str/dict): additional metadata to save to the figure
        fig      (fig/list): figure to save (by default, current one); can also be a list of figures
        kwargs   (dict):     passed to ``fig.savefig()``

    **Example**::

        cv.Sim().run().plot()
        cv.savefig()
    '''

    # Handle inputs
    dpi = kwargs.pop('dpi', 150)
    metadata = kwargs.pop('metadata', {})

    if fig is None:
        fig = pl.gcf()
    figlist = sc.tolist(fig)

    if filename is None: # pragma: no cover
        now = sc.getdate(dateformat='%Y-%b-%d_%H.%M.%S')
        filename = f'covasim_{now}.png'
    filenamelist = sc.tolist(filename)

    if len(figlist) != len(filenamelist):
        errormsg = f'You have supplied {len(figlist)} figures and {len(filenamelist)} filenames: these must be the same length'
        raise ValueError(errormsg)

    metadata = {}
    metadata['Covasim version'] = cvv.__version__
    gitinfo = git_info()
    for key,value in gitinfo['covasim'].items():
        metadata[f'Covasim {key}'] = value
    for key,value in gitinfo['called_by'].items():
        metadata[f'Covasim caller {key}'] = value
    metadata['Covasim current time'] = sc.getdate()
    metadata['Covasim calling file'] = sc.getcaller()
    if comments:
        metadata['Covasim comments'] = comments

    # Loop over the figures (usually just one)
    for thisfig, thisfilename in zip(figlist, filenamelist):

        # Handle different formats
        lcfn = thisfilename.lower() # Lowercase filename
        if lcfn.endswith('pdf') or lcfn.endswith('svg'):
            metadata = {'Keywords':str(metadata)} # PDF and SVG doesn't support storing a dict

        # Save the figure
        thisfig.savefig(thisfilename, dpi=dpi, metadata=metadata, **kwargs)

    return filename