Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into explicit-config-opt…
Browse files Browse the repository at this point in the history
…ions
  • Loading branch information
drogenlied committed May 3, 2017
2 parents d98188b + 9cea38b commit d371811
Show file tree
Hide file tree
Showing 54 changed files with 1,321 additions and 576 deletions.
36 changes: 36 additions & 0 deletions .appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

#branches:
# only:
# - master

environment:
global:
PYTHON: "C:\\miniconda"
PYTHON_ARCH: "64" # needs to be set for CMD_IN_ENV to succeed. If a mix
# of 32 bit and 64 bit builds are needed, move this
# to the matrix section.

platform:
-x64

install:
- "powershell %APPVEYOR_BUILD_FOLDER%\\tools\\setup_conda_windows.ps1"
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- 'conda env remove --yes --name qudi || exit 0'
- "conda env create -f %APPVEYOR_BUILD_FOLDER%\\tools\\conda-env-win8-qt5.yml"
- "activate qudi"
- "python %APPVEYOR_BUILD_FOLDER%\\tools\\qudikernel.py install"

# Not a .NET project, we build in the install step instead
build: false

test_script:
- sh "%APPVEYOR_BUILD_FOLDER%\\tools\\test.sh"

artifacts:
- path: qudi.log
name: Qudi log file

- path: notebooks
name: test notebooks
type: zip
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Originally built around a confocal fluorescence microscope experiments, it has g

## Citation
If you are publishing scientific results, mentioning Qudi in your methods decscription is the least you can do as good scientific practice.
A paper about Qudi has been accepted for publication in [SoftwareX](https://www.journals.elsevier.com/softwarex/). Until it is officailly published, you should cite the preprint [arXiv:1611.09146](https://arxiv.org/abs/1611.09146) \[quant-ph\] for this purpose.
You should cite our paper [Qudi: A modular python suite for experiment control and data processing](http://doi.org/10.1016/j.softx.2017.02.001) for this purpose.

## Documentation
User and code documentation about Qudi is located at http://ulm-iqo.github.io/qudi-generated-docs/html-docs/ .
Expand Down
59 changes: 0 additions & 59 deletions appveyor.yml

This file was deleted.

1 change: 1 addition & 0 deletions config/example/default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ logic:
sequencegeneratorlogic:
module.Class: 'sequence_generator_logic.SequenceGeneratorLogic'
#overhead_bytes: 4294967296 Not properly implemented yet
#additional_methods_dir: 'C:\\Custom_dir\\Methods' optional

pulseextractionlogic:
module.Class: 'pulse_extraction_logic.PulseExtractionLogic'
Expand Down
10 changes: 9 additions & 1 deletion core/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@
# define a global variable for the manager
man = None

# Until here every module is in the python standard library.
# Check vital packages for qudi, otherwise qudi will not even start.
from core.util.helpers import import_check
err_code = import_check()

if err_code != 0:
sys.exit(err_code)


# install logging facility for Qt errors
import qtpy
Expand Down Expand Up @@ -180,7 +188,7 @@ def setupParentPoller(self, manager):
self.poller.start()
else:
logger.warning('Qudi running unsupervised, restart wiill not work.')


def quitProxy(self, obj):
""" Helper function to emit doQuit signal
Expand Down
62 changes: 55 additions & 7 deletions core/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,10 @@ def readConfig(self, configFile):
logger.info("Starting Manager configuration from {0}".format(
configFile))
cfg = config.load(configFile)
self.configFile = configFile
# Read modules, devices, and stylesheet out of config
self.configure(cfg)

self.configFile = configFile
print("\n============= Manager configuration complete =================\n")
logger.info('Manager configuration complete.')

Expand Down Expand Up @@ -326,7 +326,55 @@ def configure(self, cfg):
# global config
elif key == 'global' and cfg['global'] is not None:
for m in cfg['global']:
if m == 'startup':
if (m == 'extensions'):
# deal with str, list and unknown types
if (isinstance(cfg['global'][m], str)):
dirnames = [cfg['global'][m]]
elif (isinstance(cfg['global'][m], list)):
dirnames = cfg['global'][m]
else:
logger.warning('Global ''path'' '
'configuration is neither str '
' nor list. Ignoring.')
continue
# add specified directories
for ii in range(len(dirnames)):
path = ''
# absolute or relative path? Existing?
if (os.path.isabs(dirnames[ii]) and
os.path.isdir(dirnames[ii])):
path = dirnames[ii]
else:
# relative path?
path = os.path.abspath(
'{0}/{1}'.format(
os.path.dirname(self.configFile),
dirnames[ii]))
if (not os.path.isdir(path)):
path = ''
if (path == ''):
logger.warning(
'Error while adding qudi '
'extension: Directory \'{0}\' '
'does not exist.'
''.format(
cfg['global'][m][ii]))
continue
# check for __init__.py files within extension
# and issue warning if existing
for paths, dirs, files in os.walk(path):
if ('__init__.py' in files):
logger.warning(
'Warning: Extension {0} contains '
'__init__.py. Expect unexpected '
'behaviour. Hope you know what '
'you are doing.'.format(path))
break
# add directory to search path
logger.debug('Adding extension path: {0}'
''.format(path))
sys.path.insert(1+ii, path)
elif m == 'startup':
self.tree['global']['startup'] = cfg[
'global']['startup']
elif m == 'stylesheet' and self.hasGui:
Expand Down Expand Up @@ -607,9 +655,9 @@ def connectModule(self, base, mkey):
destmod = connections[c]
destbase = ''
# check if module exists at all
if (not destmod in self.tree['loaded']['gui'] and
not destmod in self.tree['loaded']['hardware'] and
not destmod in self.tree['loaded']['logic']):
if (destmod not in self.tree['loaded']['gui'] and
destmod not in self.tree['loaded']['hardware'] and
destmod not in self.tree['loaded']['logic']):
logger.error('Cannot connect {0}.{1}.{2} to module {3}. '
'Module does not exist.'.format(
base, mkey, c, destmod))
Expand Down Expand Up @@ -1038,7 +1086,7 @@ def startModule(self, base, key):

for mkey in sorteddeps:
for mbase in ('hardware', 'logic', 'gui'):
if mkey in self.tree['defined'][mbase] and not mkey in self.tree['loaded'][mbase]:
if mkey in self.tree['defined'][mbase] and mkey not in self.tree['loaded'][mbase]:
success = self.loadConfigureModule(mbase, mkey)
if success < 0:
logger.warning('Stopping module loading after loading failure.')
Expand Down Expand Up @@ -1109,7 +1157,7 @@ def restartModuleRecursive(self, base, key):

for mkey in reversed(unloaded_mods):
mbase = self.findBase(mkey)
if mkey in self.tree['defined'][mbase] and not mkey in self.tree['loaded'][mbase]:
if mkey in self.tree['defined'][mbase] and mkey not in self.tree['loaded'][mbase]:
success = self.loadConfigureModule(mbase, mkey)
if success < 0:
logger.warning('Stopping loading module {0}.{1} after '
Expand Down
49 changes: 49 additions & 0 deletions core/util/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
except ImportError:
pass

import importlib
import logging
logger = logging.getLogger(__name__)

# Optional function for exiting immediately (with some manual teardown)


Expand Down Expand Up @@ -77,3 +81,48 @@ def exit(exitcode=0):
os.closerange(3, 4096)

os._exit(exitcode)



def import_check():
""" Checks whether all the necessary modules are present upon start of qudi.
@return: int, error code either 0 or 4.
Check also whether some recommended packages exists. Return err_code=0 if
all vital packages are installed and err_code=4 if vital packages are
missing. Make a warning about missing packages.
"""
err_code = 0

# encode like: (python-package-name, repository-name)
vital_pkg = [('ruamel.yaml','ruamel.yaml'), ('rpyc','rpyc'), ('fysom','fysom')]
opt_pkg = [('pyqtgraph','pyqtgraph'), ('git','gitpython')]

for pkg_name, repo_name in vital_pkg:
try:
importlib.import_module(pkg_name)
except ImportError:
logger.error('No Package "{0}" installed! Perform e.g.\n\n'
' pip install {1}\n\n'
'in the console to install the missing package.'.format(pkg_name, repo_name))
err_code = err_code | 4

try:
from qtpy.QtCore import Qt
except ImportError:
logger.error('No Qt bindungs detected! Perform e.g.\n\n'
' pip install PyQt5\n\n'
'in the console to install the missing package.')
err_code = err_code | 4

for pkg_name, repo_name in opt_pkg:
try:
importlib.import_module(pkg_name)
except ImportError:
logger.warning('No Package "{0}" installed! It is recommended to '
'have this package installed. Perform e.g.\n\n'
' pip install {1}\n\n'
'in the console to install the missing package.'.format(pkg_name, repo_name))

return err_code
57 changes: 57 additions & 0 deletions documentation/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,62 @@
# Changelog {#changelog}

## Release 0.8

Released on 2 Mar 2017.
Available at https://github.com/Ulm-IQO/qudi/releases/tag/v0.8

Caution: fits need to be configured in the respective settings dialog and
may not include printed results or may be just broken.
If you find a defective fit, consider fixing it and submitting a pull request.

Changes/New features:

* The Qudi paper was published: http://doi.org/10.1016/j.softx.2017.02.001
* Move everything to Qt5 only (no more Qt4 support) and pyqtgraph 0.10.0
* Re-usable/configurable fit GUI components
* Scienific notation input for PID GUI
* Support for [Extensions](@ref extensions) (out-of-tree modules)
* Removed the fysom event parameter (usually called e) from on_activae and on_deactivate functions
* Swabian Instruments TimeTagger / PulseStreamer hardware modules
* Much faster savelogic
* Remove 'Out' connectors, connection is now by module name only
* Pulse analysis supports multiple methods
* Predefined pulse sequences can now be imported from a custom path
(in addition to /logic/predefined_methods)
* Module loading and unloading now definitely happens in the correct order
* Locked modules are only deactivated after prompting the user

Config changes:
* New optional parameter "additional_methods_dir" for SequenceGeneratorLogic
* No more 'Out' connectors:

Old style, produces lots of warnings:

logic:
counter:
module.Class: 'counter_logic.CounterLogic'
connect:
counter1: 'mynicard.counter'
savelogic: 'savelogic.savelogic'
save:
module.Class: 'save_logic.SaveLogic'
win_data_directory: 'C:/Data'
unix_data_directory: 'Data/'

New style:

logic:
counter:
module.Class: 'counter_logic.CounterLogic'
connect:
counter1: 'mynicard'
savelogic: 'save'
save:
module.Class: 'save_logic.SaveLogic'
win_data_directory: 'C:/Data'
unix_data_directory: 'Data/'


## Release 0.7

Released on 01 Feb 2017.
Expand Down
Loading

0 comments on commit d371811

Please sign in to comment.