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.')
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.')
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.')