Exemple #1
0
def write_custom_annotation(h5file,
                            annotation_name,
                            annotation_value,
                            annotations_sub_group=None):
    """
    Write a custom annotation to an HDF5 database.

    The annotation is written to the `h5file` under the `annotation_name` such
    that it holds the `annotation_value`.

    Parameters
    ----------
    h5file : tables.file.File
        The handle to the HDF5 database to which the annotation is written.
    annotation_name : str
        The name of the annotation to write.
    annotation_value : a JSON serialisable object
        The annotation value to write.
    annotations_sub_group : str
        The group node under "/annotations" to which the custom annotation is
        written (the default is None which implies that the custom annotation
        is written directly under "/annotations").

    Notes
    -----
    The `annotation_value` must be a JSON seriablisable object.

    Examples
    --------
    Write a custom annotation to an HDF5 database.

    >>> import magni
    >>> from magni.reproducibility.io import write_custom_annotation
    >>> annotation_name = 'custom_annotation'
    >>> annotation_value = 'the value'
    >>> with magni.utils.multiprocessing.File('db.hdf5', mode='a') as h5file:
    ...    write_custom_annotation(h5file, annotation_name, annotation_value)
    ...    annotations = magni.reproducibility.io.read_annotations(h5file)
    >>> str(annotations['custom_annotation'])
    'the value'

    """
    @_decorate_validation
    def validate_input():
        _generic('h5file', tables.file.File)
        _generic('annotation_name', 'string')
        _generic('annotations_sub_group', 'string', ignore_none=True)

    validate_input()

    if annotations_sub_group is not None:
        annotations_group = '/'.join(['/annotations', annotations_sub_group])
    else:
        annotations_group = '/annotations'

    try:
        ann_val = json.dumps(annotation_value)
    except TypeError:
        raise TypeError('The annotation value does not have a valid JSON ' +
                        'representation. It may not be used as an annotation.')

    try:
        h5file.create_array(annotations_group,
                            annotation_name,
                            obj=ann_val.encode(),
                            createparents=True)
        h5file.flush()
    except tables.NodeError:
        raise tables.NodeError(
            'The annotation "{!r}" already exists '.format(annotation_name) +
            'in the database. Remove the old annotation before placing a ' +
            'new one.')
Exemple #2
0
def annotate_database(h5file):
    """
    Annotate an HDF5 database with information about Magni and the platform.

    The annotation consists of a group in the root of the `h5file` having nodes
    that each provide information about Magni or the platform on which this
    function is run.

    Parameters
    ----------
    h5file : tables.file.File
        The handle to the HDF5 database that should be annotated.

    See Also
    --------
    magni.reproducibility._annotation.get_conda_info : Conda annotation
    magni.reproducibility._annotation.get_git_revision : Git annotation
    magni.reproducibility._annotation.get_platform_info : Platform annotation
    magni.reproducibility._annotation.get_datetime : Date and time annotation
    magni.reproducibility._annotation.get_magni_config : Magni config
        annotation
    magni.reproducibility._annotation.get_magni_info : Magni info annotation

    Notes
    -----
    The annotations of the database includes the following:

    * conda_info - Information about Continuum Anacononda install
    * git_revision - Git revision and tag of Magni
    * platform_info - Information about the current platform (system)
    * datetime - The current date and time
    * magni_config - Infomation about the current configuration of Magni
    * magni_info - Information from `help(magni)`

    Examples
    --------
    Annotate the database named 'db.hdf5':

    >>> import magni
    >>> from magni.reproducibility.io import annotate_database
    >>> with magni.utils.multiprocessing.File('db.hdf5', mode='a') as h5file:
    ...     annotate_database(h5file)

    """
    @_decorate_validation
    def validate_input():
        _generic('h5file', tables.file.File)

    validate_input()

    annotations = {
        'conda_info': json.dumps(_annotation.get_conda_info()),
        'git_revision': json.dumps(_annotation.get_git_revision()),
        'platform_info': json.dumps(_annotation.get_platform_info()),
        'datetime': json.dumps(_annotation.get_datetime()),
        'magni_config': json.dumps(_annotation.get_magni_config()),
        'magni_info': json.dumps(_annotation.get_magni_info())
    }

    try:
        annotations_group = h5file.create_group('/', 'annotations')
        for annotation in annotations:
            h5file.create_array(annotations_group,
                                annotation,
                                obj=annotations[annotation].encode())
        h5file.flush()
    except tables.NodeError:
        raise tables.NodeError('The database has already been annotated. ' +
                               'Remove the existing annotation prior to ' +
                               '(re)annotating the database.')
Exemple #3
0
def chase_database(h5file):
    """
    Chase an HDF5 database to track information about stack and source code.

    The chase consist of a group in the root of the `h5file` having nodes that
    each profide information about the program execution that led to this chase
    of the database.

    Parameters
    ----------
    h5file : tables.file.File
        The handle to the HDF5 database that should be chased.

    See Also
    --------
    magni.reproducibility._chase.get_main_file_name : Name of main file
    magni.reproducibility._chase.get_main_file_source : Main file source code
    magni.reproducibility._chase.get_main_source : Source code around main
    magni.reproducibility._chase.get_stack_trace : Complete stack trace

    Notes
    -----
    The chase include the following information:

    * main_file_name - Name of the main file/script that called this function
    * main_file_source - Full source code of the main file/script
    * main_source - Extract of main file source code that called this function
    * stack_trace - Complete stack trace up until the call to this function

    Examples
    --------
    Chase the database named 'db.hdf5':

    >>> import magni
    >>> from magni.reproducibility.io import chase_database
    >>> with magni.utils.multiprocessing.File('db.hdf5', mode='a') as h5file:
    ...     chase_database(h5file)

    """
    @_decorate_validation
    def validate_input():
        _generic('h5file', tables.file.File)

    validate_input()

    chases = {
        'main_file_name': json.dumps(_chase.get_main_file_name()),
        'main_file_source': json.dumps(_chase.get_main_file_source()),
        'main_source': json.dumps(_chase.get_main_source()),
        'stack_trace': json.dumps(_chase.get_stack_trace())
    }

    try:
        chase_group = h5file.create_group('/', 'chases')
        for chase in chases:
            h5file.create_array(chase_group, chase, obj=chases[chase].encode())
        h5file.flush()

    except tables.NodeError:
        raise tables.NodeError('The database has already been chased. ' +
                               'Remove the existing chase prior to ' +
                               '(re)chasing the database.')