Source code for nexusLIMS

# -*- coding: utf-8 -*-

#  NIST Public License - 2019
#
#  This software was developed by employees of the National Institute of
#  Standards and Technology (NIST), an agency of the Federal Government
#  and is being made available as a public service. Pursuant to title 17
#  United States Code Section 105, works of NIST employees are not subject
#  to copyright protection in the United States.  This software may be
#  subject to foreign copyright.  Permission in the United States and in
#  foreign countries, to the extent that NIST may hold copyright, to use,
#  copy, modify, create derivative works, and distribute this software and
#  its documentation without fee is hereby granted on a non-exclusive basis,
#  provided that this notice and disclaimer of warranty appears in all copies.
#
#  THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND,
#  EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED
#  TO, ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY
#  IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
#  AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION
#  WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE
#  ERROR FREE.  IN NO EVENT SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING,
#  BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES,
#  ARISING OUT OF, RESULTING FROM, OR IN ANY WAY CONNECTED WITH THIS SOFTWARE,
#  WHETHER OR NOT BASED UPON WARRANTY, CONTRACT, TORT, OR OTHERWISE, WHETHER
#  OR NOT INJURY WAS SUSTAINED BY PERSONS OR PROPERTY OR OTHERWISE, AND
#  WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT OF THE RESULTS OF,
#  OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
#
"""The NexusLIMS back-end software.

This module contains the software required to monitor a database for sessions
logged by users on instruments that are part of the NIST Electron Microscopy
Nexus Facility. Based off this information, records representing individual
experiments are automatically generated and uploaded to the front-end NexusLIMS
CDCS instance for users to browse, query, and edit.

Example
-------
In most cases, the only code that needs to be run directly is initiating the
record builder to look for new sessions, which can be done by running the
:py:mod:`~nexusLIMS.builder.record_builder` module directly:

.. code-block:: bash

    $ python -m nexusLIMS.builder.record_builder

Refer to :ref:`record-building` for more details.

**Configuration variables**

The following variables should be defined as environment variables in your
session, or in the ``.env`` file in the root of this package's repository (if
you are running using ``pipenv``).

.. _nexusLIMS-user:

`nexusLIMS_user`
    The username used to authenticate to calendar resources and CDCS

.. _nexusLIMS-pass:

`nexusLIMS_pass`
    The password used to authenticate to calendar resources and CDCS

.. _mmfnexus-path:

`mmfnexus_path`
    The path (should be already mounted) to the root folder containing data
    from the Electron Microscopy Nexus. This folder is accessible read-only,
    and it is where data is written to by instruments in the Electron
    Microscopy Nexus. The file paths for specific instruments (specified in
    the NexusLIMS database) are relative to this root.

.. _nexusLIMS-path:

`nexusLIMS_path`
    The root path used by NexusLIMS for various needs. This folder is used to
    store the NexusLIMS database, generated records, individual file metadata
    dumps and preview images, and anything else that is needed by the back-end
    system.

.. _nexusLIMS-db-path:

`nexusLIMS_db_path`
    The direct path to the NexusLIMS SQLite database file that contains
    information about the instruments in the Nexus Facility, as well as logs
    for the sessions created by users using the Session Logger Application.
"""
from pkg_resources import DistributionNotFound, get_distribution

try:
    # Change here if project is renamed and does not equal the package name
    dist_name = "nexusLIMS"
    __version__ = get_distribution(dist_name).version
except DistributionNotFound:
    __version__ = "unknown"
finally:
    del get_distribution, DistributionNotFound


import json
import logging
import os
import pathlib
import shutil
import sys


def _filter_hyperspy_messages(record):
    """Filter to be used with logging class to hide HyperSpy API import
    warnings within the NexusLIMS codebase"""
    # this only triggers if the hs.preferences.GUIs.warn_if_guis_are_missing
    # preference is set to True
    if record.msg.startswith('The ipywidgets GUI') or \
            record.msg.startswith('The traitsui GUI'):
        return False
    else:
        # unless we come across another HyperSpy error, this line won't be
        # reached, so exclude from coverage
        return True     # pragma: no cover


# connect the filter function to the HyperSpy logger
logging.getLogger('hyperspy.api').addFilter(_filter_hyperspy_messages)

# set log message format
logging.basicConfig(format='%(asctime)s %(name)s %(levelname)s: %(message)s')
logger = logging.getLogger(__name__)


[docs]def validate_config(config): keys_non_null = [ "mmfnexus_path", "nexusLIMS_path", "nexusLIMS_db_path", "cdcs_url", ] for k in keys_non_null: if not config.get(k): raise ValueError(f"Config is NOT valid: entry `{k}` is not present or Null.") return True
[docs]def get_config(): config_dir = os.path.join(pathlib.Path.home(), ".nexuslims") if not os.path.exists(config_dir): os.makedirs(config_dir) config_fn = os.path.join(config_dir, "config.json") if not os.path.isfile(config_fn): # default config default_fn = os.path.abspath(__file__) default_fn = default_fn.replace(os.path.basename(__file__), "config.json") shutil.copy(default_fn, config_fn) logger.warning(f"No `config.json` found in {config_dir}, a default copy is created.") logger.warning(json.dumps(json.loads(open(config_fn).read()))) try: config = json.loads(open(config_fn).read()) validate_config(config) except Exception as e: logger.exception(str(e)) sys.exit(0) return config