# -*- coding: utf-8 -*-
"""
Created on Tue Aug 23 11:03:57 2016
@author: Sam Schott (ss2151@cam.ac.uk)
(c) Sam Schott; This work is licensed under a Creative Commons
Attribution-NonCommercial-NoDerivs 2.0 UK: England & Wales License.
"""
import sys
import os
import logging
import time
import subprocess
import traceback
try:
from IPython import get_ipython
IP = get_ipython()
except ImportError:
IP = None
try:
res = subprocess.check_output(["Xepr", "--apipath"])
except (FileNotFoundError, subprocess.CalledProcessError):
BRUKER_XEPR_API_PATH = ""
else:
BRUKER_XEPR_API_PATH = res.decode()
ENVIRON_XEPR_API_PATH = os.environ.get("XEPR_API_PATH", "")
os.environ["SPY_UMR_ENABLED"] = "False"
logger = logging.getLogger(__name__)
# ======================================================================================
# Create splash screen
# ======================================================================================
[docs]def show_splash_screen():
"""
Shows the CustomXepr splash screen.
:returns: :class:`PyQt5.QtWidgets.QSplashScreen`.
"""
from PyQt5 import QtWidgets
from customxepr.gui import SplashScreen
splash = SplashScreen()
splash.show()
splash.raise_()
QtWidgets.QApplication.processEvents()
splash.showMessage("Initializing...")
return splash
# ======================================================================================
# Connect to instruments: Bruker Xepr, Keithley and MercuryiTC.
# ======================================================================================
[docs]def connect_to_instruments():
"""
Tries to connect to Keithley, Mercury and Xepr. Uses the visa
addresses saved in the respective configuration files.
:returns: Tuple containing instrument instances.
:rtype: tuple
"""
from keithley2600 import Keithley2600
from keithleygui.config.main import CONF as KCONF
from mercuryitc import MercuryITC
from mercurygui.config.main import CONF as MCONF
keithley_address = KCONF.get("Connection", "VISA_ADDRESS")
keithley_visa_lib = KCONF.get("Connection", "VISA_LIBRARY")
mercury_address = MCONF.get("Connection", "VISA_ADDRESS")
mercury_visa_lib = MCONF.get("Connection", "VISA_LIBRARY")
try:
# Search for the XeprAPI in the following locations, use the first match:
# 1) path from environment variable, if given
# 2) installed python package
# 3) pre-installed version with Xepr
sys.path.insert(0, ENVIRON_XEPR_API_PATH)
sys.path.insert(-1, BRUKER_XEPR_API_PATH)
from XeprAPI import Xepr
xepr = Xepr()
except ImportError:
logger.info("XeprAPI could not be located.")
xepr = None
except IOError:
logger.info("No running Xepr instance could be found.")
xepr = None
mercury = MercuryITC(
mercury_address, mercury_visa_lib, open_timeout=1, timeout=5000
)
keithley = Keithley2600(
keithley_address, keithley_visa_lib, open_timeout=1, timeout=5000
)
return xepr, mercury, keithley
# ======================================================================================
# Start CustomXepr and user interfaces
# ======================================================================================
[docs]def start_gui(customXepr, mercury, keithley):
"""
Starts GUIs for Keithley, Mercury and CustomXepr.
:returns: Tuple containing GUI instances.
:rtype: tuple
"""
from keithleygui.main import KeithleyGuiApp
from mercurygui.main import MercuryMonitorApp
from customxepr.gui import CustomXeprGuiApp
mercury_gui = MercuryMonitorApp(mercury)
keithley_gui = KeithleyGuiApp(keithley)
customXepr_gui = CustomXeprGuiApp(customXepr)
mercury_gui.QUIT_ON_CLOSE = False
keithley_gui.QUIT_ON_CLOSE = False
customXepr_gui.QUIT_ON_CLOSE = False
customXepr_gui.show()
mercury_gui.show()
keithley_gui.show()
return customXepr_gui, mercury_gui, keithley_gui
def _exit_hook(instruments, guis=None):
if guis:
for ui in guis:
try:
ui.exit_() # this will disconnect automatically
except Exception:
traceback.print_exc()
for inst in instruments:
try:
inst.disconnect() # disconnect instruments manually
except Exception:
traceback.print_exc()
[docs]def run_cli():
"""
This is the main interactive shell entry point. Calling ``run_cli`` will connect to
all instruments and return instantiated control classes.
:returns: Tuple containing instrument instances.
:rtype: tuple
"""
from customxepr.main import CustomXepr
xepr, mercury, keithley = connect_to_instruments()
customXepr = CustomXepr(xepr, mercury, keithley)
return customXepr, xepr, mercury, keithley
[docs]def run_gui():
"""
Runs the CustomXepr GUI -- this is the main entry point. Calling ``run_gui`` will
first create a Qt application, then aim to connect to Xepr, a Keithley2600
instrument and a MercuryiTC temperature controller and finally create user
interfaces to control all three instruments.
"""
from customxepr import __version__, __author__
from customxepr.main import CustomXepr
from customxepr.gui.error_dialog import patch_excepthook
year = str(time.localtime().tm_year)
banner = (
"Welcome to CustomXepr {0}. You can access connected instruments through "
'"customXepr" or directly as "xepr", "keithley" and "mercury".\n\n'
'Use "%run -i path/to/file.py" to run a python script such '
"as a measurement routine. An introduction to CustomXepr is "
"available at \x1b[1;34mhttps://customxepr.readthedocs.io\x1b[0m.\n\n"
"(c) 2016-{1}, {2}.".format(__version__, year, __author__)
)
ui = ()
# start qt app
from PyQt5 import QtCore, QtWidgets
app = QtWidgets.QApplication(["CustomXepr"])
app.setApplicationName("CustomXepr")
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps)
splash = show_splash_screen() # create splash screen for messages
splash.showMessage("Connecting to instruments...")
xepr, mercury, keithley = connect_to_instruments()
customXepr = CustomXepr(xepr, mercury, keithley)
splash.showMessage("Loading user interface...")
ui = start_gui(customXepr, mercury, keithley)
# start ipython kernel and jupyter console
splash.showMessage("Loading console...")
from qtconsole.inprocess import QtInProcessKernelManager
from customxepr.gui.jupyter_widget import CustomRichJupyterWidget
def exit_customxepr():
_exit_hook(instruments=(mercury, keithley), guis=ui)
app.quit()
kernel_manager = QtInProcessKernelManager()
kernel_manager.start_kernel(show_banner=False)
kernel = kernel_manager.kernel
kernel.shell.banner1 = ""
kernel_manager.kernel.shell.ask_exit = lambda: print(
"Please close this window to exit."
)
kernel.gui = "qt"
kernel_client = kernel_manager.client()
kernel_client.start_channels()
font_size = int(QtWidgets.QTextEdit().font().pointSize())
ipython_widget = CustomRichJupyterWidget(
banner=banner,
font_size=font_size,
gui_completion="droplist",
on_close=exit_customxepr,
)
ipython_widget.kernel_manager = kernel_manager
ipython_widget.kernel_client = kernel_client
ipython_widget.show()
var_dict = {
"customXepr": customXepr,
"xepr": xepr,
"mercury": mercury,
"keithley": keithley,
"ui": ui,
"kernel_manager": kernel_manager,
}
kernel.shell.push(var_dict)
patch_excepthook() # display errors from Qt event loop to user
splash.close() # remove splash screen
# clear all root loggers
logging.getLogger().handlers.clear()
# start event loop
sys.exit(app.exec_())
[docs]def run_ip():
"""
Runs the CustomXepr GUI from IPython.
"""
global customXepr, xepr, mercury, keithley, ui, app
from customxepr import __version__, __author__
from customxepr.main import CustomXepr
year = str(time.localtime().tm_year)
banner = (
"Welcome to CustomXepr {0}. You can access connected instruments through "
'"customXepr" or directly as "xepr", "keithley" and "mercury".\n\n'
'Use "%run -i path/to/file.py" to run a python script such '
"as a measurement routine. An introduction to CustomXepr is "
"available at \x1b[1;34mhttps://customxepr.readthedocs.io\x1b[0m.\n\n"
"(c) 2016-{1}, {2}.".format(__version__, year, __author__)
)
# start qt app
from PyQt5 import QtCore, QtWidgets
IP.enable_gui("qt")
IP.run_line_magic("load_ext", "autoreload")
IP.run_line_magic("autoreload", "0")
app = QtWidgets.QApplication(["CustomXepr"])
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps)
try:
import matplotlib
matplotlib.use("Qt5Agg")
except ImportError:
pass
splash = show_splash_screen() # create splash screen for messages
splash.showMessage("Connecting to instruments...")
xepr, mercury, keithley = connect_to_instruments()
customXepr = CustomXepr(xepr, mercury, keithley)
splash.showMessage("Loading user interface...")
ui = start_gui(customXepr, mercury, keithley)
splash.close() # remove splash screen
IP.run_line_magic("clear", "")
print(banner)
if __name__ == "__main__":
if IP:
run_ip()
else:
run_gui()