User Notes

This page has various different notes for using PyExpLabSys.

Setting up logging of your program

To set up logging of a program, it is possible to simply follow the standard library documentation. However, since many of the programs that uses PyExpLabSys are programs that runs for extended periods without monitoring, a more specific logging setup may be required. E.g. one that makes use of email handlers, so be notified by email in case of errors or warnings.

For that purpose, PyExpLabSys has the get_logger() function in the utilities module that is a convinience function to set up a logger with one or more of the commonly used log handlers i.e. a terminal handler, a rotating file handler and email handlers. This may be used to things up and running in a hurry.

from PyExpLabSys.common import utilities

utilities.MAIL_HOST = 'my.mail.host'
utilities.WARNING_EMAIL = 'email-address-to-use-in-case-of-warnings@log.com'
utilities.ERROR_EMAIL = 'email-address-to-use-in-case-of-error@log.com'

# Returns a logger with terminal and emails handlers per default
LOG = utilities.get_logger('my_program_name')

# A rotating file handler can be added:
LOG = utilities.get_logger('my_program_name', file_log=True)

Activating PyExpLabSys library logging in you program

PyExpLabSys contains quite a few loggers and exposes a few convinience functions in the utilities module for listing and activating them. To get a list of loggers that are relevant for the modules that you have imported, you can use either the get_library_logger_names() function, which will return you a list or the print_library_logger_names() function, which prints them out:

from PyExpLabSys.common import sockets
from PyExpLabSys.common.utilities import print_library_logger_names

print_library_logger_names()

produces the following output:

Current PyExpLabSys loggers
===========================
 * PyExpLabSys.common.sockets.PullUDPHandler
 * PyExpLabSys.common.sockets.DataPushSocket
 * PyExpLabSys.common.sockets.PushUDPHandler
 * PyExpLabSys.settings
 * PyExpLabSys.common.sockets.DateDataPullSocket
 * PyExpLabSys.common.sockets.CallBackThread
 * PyExpLabSys.common
 * PyExpLabSys.common.sockets.CommonDataPullSocket
 * PyExpLabSys.common.sockets
 * PyExpLabSys.common.sockets.DataPullSocket
 * PyExpLabSys
 * PyExpLabSys.common.sockets.LiveSocket

To activate a logger use the full path of the logger e.g. PyExpLabSys.common.sockets.DataPullSocket and remembers that the loggers are configured as a tree, so activating PyExpLabSys.common.sockets will activate all the loggers in that module and activating PyExpLabSys will activate all PyExpLabSys library loggers.

There are now two ways to activate a logger. One is to configure one from scratch, using the path of the logger and the same options as in get_logger():

from PyExpLabSys.common import sockets
from PyExpLabSys.common.utilities import activate_library_logging

activate_library_logging(
    'PyExpLabSys.common.sockets.DateDataPullSocket',
    level='debug',
    file_log=True,
    file_name='socket_log.txt',
)

This would output all log message at debug level to a file called socket_log.txt.

The other way to activate a library logger is to ask it to enherit all the handlers and levels from an existing logger. This will send all the library log messages to the same destination:

from PyExpLabSys.common.utilities import get_logger, activate_library_logging
from PyExpLabSys.common import sockets

LOG = get_logger('my_program_name')
LOG.info('My program started')

# Configure a library logger to use the same handlers

activate_library_logging(
    'PyExpLabSys.common.sockets.DateDataPullSocket',
    logger_to_inherit_from=LOG,
)

It is still possible, when inheriting from an existing logger, to set a custom level for the library logger, using the level argument as in the example above.

Using PyExpLabSys drivers outside of PyExpLabSys

All I wanted was a banana, but what I got was a gorilla holding a banana

The quote above, is often used to refer to the fact that it can be difficult to use a component from a “framework” separate from the framework.

PyExpLabSys is not a framework as such, but there are some common elements that are used across different in principle independent modules. Specifically, most of the drivers in PyExpLabSys will work just fine outside of PyExpLabSys, with a few very minor modifications, by just copying the file to where the driver is to be used. Most of the drivers make use of just one other PyExpLabSys module that tie it to the package, the supported_versions module. The only thing that this module does, is to mark the specific driver as working with Python 2, Python 3 or both, and make a check at run-time of the Python version and possibly output a warning. It can therefore trivially be removed. To do this, look to lines of code somewhat like this:

from PyExpLabSys.common.supported_versions import python2_and_3
python2_and_3(__file__)

and comment them out. The specific function that is imported and called, will vary depending on which versions is supported, but that should be fairly simple to figure out.