From 6ea046be64bcd615aa1097cd7637a7ae0291794e Mon Sep 17 00:00:00 2001 From: philipstarkey Date: Thu, 25 Jun 2020 19:48:25 +1000 Subject: [PATCH] Squashed commit of the following: commit 348bbeb349d2cf758dcdf668c26efc6321a00e00 Author: Phil Starkey Date: Thu Jun 25 19:47:34 2020 +1000 Update dependencies in setup.cfg Bumped labscript_devices and labscript_utils versions to `>=3.0.0` commit 24b3728b600cf19da1af25ad1c705625d1fb805b Merge: f3a5f41 0a3df34 Author: Phil Starkey Date: Thu Jun 25 12:55:47 2020 +1000 Merge pull request #77 from chrisjbillington/anywhere-unit-conversions Allow BLACS to use conversion classes defined outside labscript_utils commit 0a3df34faf2b2fa10afc7ebf46cc5e08a1db10e2 Author: chrisjbillington Date: Wed Jun 24 22:50:15 2020 -0400 Fix error message formatting args being the wrong way around commit 9ed289038be83f8891897ff46e70c008aca6a047 Author: chrisjbillington Date: Wed Jun 24 19:26:10 2020 -0400 Allow BLACS to use conversion classes defined outside labscript_utils Labscript has long-since saved unit conversions with their full import path instead of just a class name, and `labscript_utils.unitconversisons` has provided a function `get_unit_conversion_class()` to look them up. Here we just use that function to look up unit calibration classes. `get_unit_conversion_class()` falls back to the old behaviour of importing all unit conversion modules in `labscript_utils.unitconversisons` and looking for the given class if it encounters an unqualified class name. commit f3a5f4113f3d1726093043abd16f90a56496b3d6 Merge: 88eb635 cb41ec0 Author: Chris Billington Date: Wed Jun 24 20:47:58 2020 -0400 Merge pull request #78 from philipstarkey/fix-h5py-file-mode Addresses labscript-suite/labscript-utils#47 commit cb41ec06676290fa597875cefd0cfb586198c496 Author: philipstarkey Date: Thu Jun 25 10:32:57 2020 +1000 Addresses labscript-suite/labscript-utils#47 commit 88eb635d5aff9e369c6a45f5014ab308de03bb97 Merge: 968afbc 6439a26 Author: Russell Anderson <5637107+rpanderson@users.noreply.github.com> Date: Mon Jun 22 18:07:29 2020 +1000 Merge pull request #76 from philipstarkey/master fix docs conf bugs identified in labscript-suite/labscript-utils#57 commit 6439a26b8118ed489fdceac5e15c013f30cdb317 Author: philipstarkey Date: Sat Jun 20 18:32:02 2020 +1000 fix docs conf bugs identified in labscript-suite/labscript-utils#57 commit 968afbcfd8e682f82b159b8393706e60971a3f58 Merge: 51a47c1 de2d967 Author: Phil Starkey Date: Fri Jun 19 19:00:41 2020 +1000 Merge pull request #75 from philipstarkey/master Empty sphinx project following our template commit de2d967e47066f60689cdfcce077f3dd0d81e7eb Author: philipstarkey Date: Fri Jun 19 17:18:04 2020 +1000 Empty sphinx project following our template commit 51a47c12ab69d0e11a7e482aa2d18d4e6a4da052 Author: Russell Anderson <5637107+rpanderson@users.noreply.github.com> Date: Wed Jun 17 10:24:16 2020 +1000 Abbreviate installation instructions in README.md commit fe40066e01826460538b72aecae36cf1df55fc96 Author: Russell Anderson <5637107+rpanderson@users.noreply.github.com> Date: Tue Jun 16 22:19:12 2020 +1000 Populated README.md with styling, iconogrpahy, prose, and badges commit 06e430b92ff007cbad7dafc9d50c20aaf282bef0 Merge: e739553 1d1e9c4 Author: Russell Anderson <5637107+rpanderson@users.noreply.github.com> Date: Tue Jun 16 12:07:07 2020 +1000 Merge pull request #73 from rpanderson/master experiment_name changed to apparatus_name commit 1d1e9c48840dddea2004da65648c49b8ddc5c011 Author: Russell Anderson <5637107+rpanderson@users.noreply.github.com> Date: Wed Jun 10 22:50:36 2020 +1000 experiment_name changed to apparatus_name Per labscript-suite/labscript-utils#53 Co-authored-by: chrisjbillington Co-authored-by: Russell Anderson <5637107+rpanderson@users.noreply.github.com> --- .gitignore | 167 +++++++++++++++- README.md | 24 ++- blacs/experiment_queue.py | 2 +- blacs/output_classes.py | 27 ++- blacs/plugins/cycle_time/__init__.py | 2 +- docs/Makefile | 20 ++ docs/make.bat | 35 ++++ docs/source/_static/custom.css | 63 ++++++ docs/source/_templates/components.rst | 47 +++++ docs/source/conf.py | 225 +++++++++++++++++++++ docs/source/img/blacs.ico | Bin 0 -> 104672 bytes docs/source/img/blacs_32nx32n.svg | 178 +++++++++++++++++ docs/source/img/blacs_64x64.svg | 39 ++++ docs/source/img/labscript_32nx32n.svg | 186 +++++++++++++++++ docs/source/img/lyse_32nx32n.svg | 256 ++++++++++++++++++++++++ docs/source/img/runmanager_32nx32n.svg | 267 +++++++++++++++++++++++++ docs/source/img/runviewer_32nx32n.svg | 223 +++++++++++++++++++++ docs/source/index.rst | 32 +++ readthedocs.yaml | 27 +++ setup.cfg | 10 +- 20 files changed, 1802 insertions(+), 28 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/source/_static/custom.css create mode 100644 docs/source/_templates/components.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/img/blacs.ico create mode 100644 docs/source/img/blacs_32nx32n.svg create mode 100644 docs/source/img/blacs_64x64.svg create mode 100644 docs/source/img/labscript_32nx32n.svg create mode 100644 docs/source/img/lyse_32nx32n.svg create mode 100644 docs/source/img/runmanager_32nx32n.svg create mode 100644 docs/source/img/runviewer_32nx32n.svg create mode 100644 docs/source/index.rst create mode 100644 readthedocs.yaml diff --git a/.gitignore b/.gitignore index 7bb5b41f..70c27dc9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,161 @@ -*.pyc +# This gitignore file consists of 2 parts: +# * The standard Python .gitignore rules from GitHub +# * custom ignore rules for the labscript suite. +# +# These should be kept separate so that the generic rules can be updated with a +# copy/paste without having to worry about whether we are removing custom rules + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: *.log -*.orig -*.aux -*.toc -dist/* -*.egg-info -*.eggs \ No newline at end of file +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# +# Custom labscript suite .gitignore rules start below +# + +# Editors +.vscode/ + +# conda build results +conda_build/ +conda_packages/ + +# Sphinx documentation +docs/html/ +docs/source/_build/ +docs/source/components.rst \ No newline at end of file diff --git a/README.md b/README.md index c43561bd..f1c533f7 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,21 @@ -# BLACS +the labscript suite – blacs -Part of the labscript suite, provides an interface to hardware used to control a buffered experiment. It manages a queue of shots to be run as well as providing manual control over devices between shots. +# the _labscript suite_ » blacs -( -[view on Bitbucket](https://bitbucket.org/labscript_suite/blacs) -) +### Graphical interface to scientific instruments and experiment supervision - * For install instructions, see the [labscript suite install guide](https://bitbucket.org/labscript_suite/install-guide) +[![Actions Status](https://github.com/labscript-suite/blacs/workflows/Build%20and%20Release/badge.svg?branch=maintenance%2F3.0.x)](https://github.com/labscript-suite/blacs/actions) +[![License](https://img.shields.io/pypi/l/blacs.svg)](https://github.com/labscript-suite/blacs/raw/master/LICENSE.txt) +[![Python Version](https://img.shields.io/pypi/pyversions/blacs.svg)](https://python.org) +[![PyPI](https://img.shields.io/pypi/v/blacs.svg)](https://pypi.org/project/blacs) +[![Conda Version](https://img.shields.io/conda/v/labscript-suite/lyse)](https://anaconda.org/labscript-suite/blacs) +[![Google Group](https://img.shields.io/badge/Google%20Group-labscriptsuite-blue.svg)](https://groups.google.com/forum/#!forum/labscriptsuite) + + + +**blacs** supervises the execution of experiments controlled by the [*labscript suite*](https://github.com/labscript-suite/labscript-suite). It manages experiment queuing and hardware-timed execution, and provides manual control over devices between experiment shots. + + +## Installation + +blacs is distributed as a Python package on [PyPI](https://pypi.org/user/labscript-suite) and [Anaconda Cloud](https://anaconda.org/labscript-suite), and should be installed with other components of the _labscript suite_. Please see the [installation guide](https://docs.labscriptsuite.org/en/latest/installation) for details. diff --git a/blacs/experiment_queue.py b/blacs/experiment_queue.py index f1eeec9d..1844cf11 100644 --- a/blacs/experiment_queue.py +++ b/blacs/experiment_queue.py @@ -382,7 +382,7 @@ def process_request(self,h5_filepath): result,error = inmain(self.BLACS.connection_table.compare_to,new_conn) if result: # Has this run file been run already? - with h5py.File(h5_filepath) as h5_file: + with h5py.File(h5_filepath, 'r') as h5_file: if 'data' in h5_file['/']: rerun = True else: diff --git a/blacs/output_classes.py b/blacs/output_classes.py index 52814165..155880d0 100644 --- a/blacs/output_classes.py +++ b/blacs/output_classes.py @@ -23,10 +23,7 @@ from labscript_utils.qtwidgets.digitaloutput import DigitalOutput, InvertedDigitalOutput from labscript_utils.qtwidgets.ddsoutput import DDSOutput from labscript_utils.qtwidgets.imageoutput import ImageOutput -try: - from labscript_utils.unitconversions import * -except Exception: - print('failed to import unit conversion classes') +from labscript_utils.unitconversions import get_unit_conversion_class class AO(object): @@ -54,22 +51,30 @@ def __init__(self, hardware_name, connection_name, device_name, program_function # Initialise Calibrations self._comboboxmodel.appendRow(QStandardItem(self._base_unit)) if calib_class is not None: - if calib_class not in globals() or not isinstance(calib_params,dict) or globals()[calib_class].base_unit != default_units: + try: + cls = get_unit_conversion_class(calib_class) + # ImportError if module doesn't exist. Attribute error if it does but the + # class name does not exist within it. KeyError if the unit conversion class + # is an old-style unqualified class name expected to be in the globals() + # dict of the unitconversions module, but does not exist. + except (ImportError, AttributeError, KeyError): + cls = None + if cls is None or not isinstance(calib_params, dict) or cls.base_unit != default_units: # log an error: reason = '' - if calib_class not in globals(): - reason = 'The unit conversion class was not imported. Is it in the correct folder? Is it imported when you call "from unitconversions import *" from a python terminal?' - elif not isinstance(calib_params,dict): + if calib_class is None: + reason = f'The unit conversion class {calib_class} could not be imported. Ensure it is available on the computer running BLACS.' + elif not isinstance(calib_params, dict): reason = 'The parameters for the unit conversion class are not a dictionary. Check your connection table code for errors and recompile it' - elif globals()[calib_class].base_unit != default_units: - reason = 'The base unit of your unit conversion class does not match this hardware channel. The hardware channel has base units %s while your unit conversion class uses %s'%(globals()[calib_class].base_unit,default_units) + elif cls.base_unit != default_units: + reason = f'The base unit of your unit conversion class does not match this hardware channel. The hardware channel has base units {default_units} while your unit conversion class uses {cls.base_unit}' self._logger.error('The unit conversion class (%s) could not be loaded. Reason: %s'%(calib_class,reason)) # Use default units self._calibration = None else: try: # initialise calibration class - self._calibration = globals()[calib_class](calib_params) + self._calibration = cls(calib_params) self._logger.debug('unit conversion class instantiated') for unit in self._calibration.derived_units: try: diff --git a/blacs/plugins/cycle_time/__init__.py b/blacs/plugins/cycle_time/__init__.py index d9f3aa47..80905464 100644 --- a/blacs/plugins/cycle_time/__init__.py +++ b/blacs/plugins/cycle_time/__init__.py @@ -68,7 +68,7 @@ def pre_transition_to_buffered(self, h5_filepath): self.target_cycle_time = self.next_target_cycle_time self.delay_after_programming = self.next_delay_after_programming - with h5py.File(h5_filepath) as f: + with h5py.File(h5_filepath, 'r') as f: try: group = f['shot_properties'] except KeyError: diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..9534b018 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css new file mode 100644 index 00000000..d766bfa0 --- /dev/null +++ b/docs/source/_static/custom.css @@ -0,0 +1,63 @@ +/* Add space between collapsible details HTML tags */ +details { + margin-bottom: 1em; +} + +/* Darker pygment highlighing of console input/output */ +.highlight .go { + color: #404040; +} + +/* White captions in sidebar */ +.wy-nav-side p.caption { + color: #f5f5f5; +} + +/* labscript blue, alpha = 83% */ +.wy-side-nav-search { + background: #2946bbd3; +} + +.wy-nav-top { + background: #2946bbd3; +} + +/* labscript green, alpha = 75% */ +.rst-content .note .admonition-title { + background: #00804fbf; +} + +/* labscript green, alpha = 25% */ +.rst-content .note { + background: #00804f3f; +} + +/* labscript red, alpha = 75% */ +.rst-content .warning .admonition-title { + background: #bc294cbf +} + +/* labscript red, alpha = 25% */ +.rst-content .warning { + background: #bc294c3b; +} + +/* Elevation +* +* Style box-shadows using Material Design's idea of elevation. These particular numbers are taken from here: +* +* https://github.com/material-components/material-components-web +* https://material-components-web.appspot.com/elevation.html +*/ + +.rst-content img.screenshot { + border: none; + /* MD Elevation 8 */ + box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), + 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12); + margin-bottom: 24px; +} + +img.labscript-suite-icon { + min-width: 32px; +} \ No newline at end of file diff --git a/docs/source/_templates/components.rst b/docs/source/_templates/components.rst new file mode 100644 index 00000000..f9669391 --- /dev/null +++ b/docs/source/_templates/components.rst @@ -0,0 +1,47 @@ +{% if current_project != 'the labscript suite' %} +.. toctree:: + :maxdepth: 2 + :hidden: + + the labscript suite <{{intersphinx_mapping['labscript-suite'][0]}}> + +{% endif %} +*labscript suite* components +============================ + +The *labscript suite* is modular by design, and is comprised of: + +.. list-table:: Python libraries + :widths: 10 90 + :header-rows: 0 + + {% for prog, item in programs.items() if item.type == 'lib' %} + * - .. image:: {{img_path}}/{{item.icon}} + :target: {{intersphinx_mapping['%s' | format(prog)][0]}} + :class: labscript-suite-icon + - |{{prog}}|_ --- {{item.desc}} + {% endfor %} + +.. list-table:: Graphical applications + :widths: 10 90 + :header-rows: 0 + + {% for prog, item in programs.items() if item.type == 'gui' %} + * - .. image:: {{img_path}}/{{item.icon}} + :target: {{intersphinx_mapping['%s' | format(prog)][0]}} + :class: labscript-suite-icon + - |{{prog}}|_ --- {{item.desc}} + {% endfor %} + +.. toctree:: + :maxdepth: 2 + :hidden: + + {% for prog in programs|sort if prog != current_project %} + {{prog}} <{{intersphinx_mapping['%s' | format(prog)][0]}}> + {% endfor %} + +{% for prog in programs %} +.. |{{prog}}| replace:: **{{prog}}** +.. _{{prog}}: {{intersphinx_mapping['%s' | format(prog)][0]}} +{% endfor %} \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..1bbadc91 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,225 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +from pathlib import Path +from m2r import MdInclude +from recommonmark.transform import AutoStructify +from jinja2 import FileSystemLoader, Environment + +# -- Project information (unique to each project) ------------------------------------- + +project = "blacs" +copyright = "2020, labscript suite" +author = "labscript suite contributors" + +# The full version, including alpha/beta/rc tags +from blacs import __version__ as version # noqa: E402 + +release = version + +# HTML icons +img_path = 'img' +html_logo = img_path + "/blacs_64x64.svg" +html_favicon = img_path + "/blacs.ico" + +# -- General configuration (should be identical across all projects) ------------------ + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosectionlabel", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "sphinx_rtd_theme", + "recommonmark", +] + +autodoc_typehints = 'description' + +# Prefix each autosectionlabel with the name of the document it is in and a colon +autosectionlabel_prefix_document = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# The suffix(es) of source filenames. +source_suffix = ['.rst', '.md'] + +# The master toctree document. +master_doc = 'index' + +# intersphinx allows us to link directly to other repos sphinxdocs. +# https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html +intersphinx_mapping = { + 'python': ('https://docs.python.org/3/', None), + 'numpy': ('https://numpy.org/doc/stable/', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), + 'qtutils': ('https://qtutils.readthedocs.io/en/stable/', None), + 'pyqtgraph': ( + 'https://pyqtgraph.readthedocs.io/en/latest/', + None, + ), # change to stable once v0.11 is published + 'matplotlib': ('https://matplotlib.org/', None), + 'h5py': ('http://docs.h5py.org/en/stable/', None), + 'pydaqmx': ('https://pythonhosted.org/PyDAQmx/', None), + 'qt': ( + '', + 'pyqt5-modified-objects.inv', + ) # from https://github.com/MSLNZ/msl-qt/blob/master/docs/create_pyqt_objects.py + # under MIT License + # TODO + # desktop-app + # spinapi/pynivision/etc +} + +# list of all labscript suite components that have docs +labscript_suite_programs = { + 'labscript': { + 'desc': 'Expressive composition of hardware-timed experiments', + 'icon': 'labscript_32nx32n.svg', + 'type': 'lib', + }, + 'labscript-devices': { + 'desc': 'Plugin architecture for controlling experiment hardware', + 'icon': 'labscript_32nx32n.svg', + 'type': 'lib', + }, + 'labscript-utils': { + 'desc': 'Shared modules used by the *labscript suite*', + 'icon': 'labscript_32nx32n.svg', + 'type': 'lib', + }, + 'runmanager': { + 'desc': 'Graphical and remote interface to parameterized experiments', + 'icon': 'runmanager_32nx32n.svg', + 'type': 'gui', + }, + 'blacs': { + 'desc': 'Graphical interface to scientific instruments and experiment supervision', + 'icon': 'blacs_32nx32n.svg', + 'type': 'gui', + }, + 'lyse': { + 'desc': 'Online analysis of live experiment data', + 'icon': 'lyse_32nx32n.svg', + 'type': 'gui', + }, + 'runviewer': { + 'desc': 'Visualize hardware-timed experiment instructions', + 'icon': 'runviewer_32nx32n.svg', + 'type': 'gui', + }, +} + +# whether to use stable or latest version +labscript_suite_doc_version = os.environ.get('READTHEDOCS_VERSION', 'latest') +if '.' in labscript_suite_doc_version: + labscript_suite_doc_version = 'stable' +elif labscript_suite_doc_version not in ['stable', 'latest']: + labscript_suite_doc_version = 'latest' + +# add intersphinx references for each component +for ls_prog in labscript_suite_programs: + intersphinx_mapping[ls_prog] = ( + 'https://docs.labscriptsuite.org/projects/{}/en/{}/'.format( + ls_prog, labscript_suite_doc_version + ), + None, + ) + +# add intersphinx reference for the metapackage +if project != "the labscript suite": + intersphinx_mapping['labscript-suite'] = ( + 'https://docs.labscriptsuite.org/en/{}/'.format(labscript_suite_doc_version), + None, + ) + +# Make `some code` equivalent to :code:`some code` +default_role = 'code' + +# hide todo notes if on readthedocs and not building the latest +if os.environ.get('READTHEDOCS') and ( + os.environ.get('READTHEDOCS_VERSION') != 'latest' + or ( + os.environ.get('READTHEDOCS_PROJECT') == project + or os.environ.get('READTHEDOCS_PROJECT') == 'labscriptsuite' + ) +): + todo_include_todos = False +else: + todo_include_todos = True + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "sphinx_rtd_theme" +html_title = "labscript suite | {project}".format( + project=project + if project != "labscript-suite" + else "experiment control and automation" +) +html_short_title = "labscript suite" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Customize the html_theme +html_theme_options = {'navigation_depth': 3} + +# Use m2r only for mdinclude and recommonmark for everything else +# https://github.com/readthedocs/recommonmark/issues/191#issuecomment-622369992 +def setup(app): + config = { + # 'url_resolver': lambda url: github_doc_root + url, + 'auto_toc_tree_section': 'Contents', + 'enable_eval_rst': True, + } + app.add_config_value('recommonmark_config', config, True) + app.add_transform(AutoStructify) + + # from m2r to make `mdinclude` work + app.add_config_value('no_underscore_emphasis', False, 'env') + app.add_config_value('m2r_parse_relative_links', False, 'env') + app.add_config_value('m2r_anonymous_references', False, 'env') + app.add_config_value('m2r_disable_inline_math', False, 'env') + app.add_directive('mdinclude', MdInclude) + app.add_css_file('custom.css') + + # generate the components.rst file dynamically so it points to stable/latest + # of subprojects correctly + loader = FileSystemLoader(Path(__file__).resolve().parent / templates_path[0]) + env = Environment(loader=loader) + template = env.get_template('components.rst') + with open(Path(__file__).resolve().parent / 'components.rst', 'w') as f: + f.write( + template.render( + intersphinx_mapping=intersphinx_mapping, + programs=labscript_suite_programs, + current_project=project, + img_path=img_path + ) + ) diff --git a/docs/source/img/blacs.ico b/docs/source/img/blacs.ico new file mode 100644 index 0000000000000000000000000000000000000000..6f626d9df956e30a5a8d13a02114a8b17bc45892 GIT binary patch literal 104672 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 + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/docs/source/img/blacs_64x64.svg b/docs/source/img/blacs_64x64.svg new file mode 100644 index 00000000..f139a01d --- /dev/null +++ b/docs/source/img/blacs_64x64.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/docs/source/img/labscript_32nx32n.svg b/docs/source/img/labscript_32nx32n.svg new file mode 100644 index 00000000..97272afa --- /dev/null +++ b/docs/source/img/labscript_32nx32n.svg @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/docs/source/img/lyse_32nx32n.svg b/docs/source/img/lyse_32nx32n.svg new file mode 100644 index 00000000..1ddcdccd --- /dev/null +++ b/docs/source/img/lyse_32nx32n.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/img/runmanager_32nx32n.svg b/docs/source/img/runmanager_32nx32n.svg new file mode 100644 index 00000000..d9df689a --- /dev/null +++ b/docs/source/img/runmanager_32nx32n.svg @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/img/runviewer_32nx32n.svg b/docs/source/img/runviewer_32nx32n.svg new file mode 100644 index 00000000..ee5aa68f --- /dev/null +++ b/docs/source/img/runviewer_32nx32n.svg @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..2993f86d --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,32 @@ +.. blacs documentation master file, created by + sphinx-quickstart on Thu Jun 18 17:05:42 2020. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +blacs +===== + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: DOCUMENTATION + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: FURTHER DOCUMENTATION + + components + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: LINKS + + Home Page + Source Code + PyPI + Anaconda Cloud + BitBucket Archive + +.. todolist:: diff --git a/readthedocs.yaml b/readthedocs.yaml new file mode 100644 index 00000000..35084d6e --- /dev/null +++ b/readthedocs.yaml @@ -0,0 +1,27 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation in the docs/ directory with Sphinx +sphinx: + builder: dirhtml + configuration: docs/source/conf.py + fail_on_warning: false + +# Optionally build your docs in additional formats such as PDF +formats: + - pdf + - epub + +# Optionally set the version of Python and requirements required to build your docs +python: + version: 3.7 + install: + - method: pip + path: . + extra_requirements: + - docs + system_packages: true + \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 93e41b8f..815d189f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,8 +26,8 @@ packages = find: python_requires = >=3.6 install_requires = importlib_metadata - labscript_devices>=2.0 - labscript_utils>=2.15.0 + labscript_devices>=3.0.0 + labscript_utils>=3.0.0 qtutils>=2.3.2 zprocess>=2.14.1 @@ -39,3 +39,9 @@ gui_scripts = [options.extras_require] pyqt = PyQt5 +docs = + PyQt5 + Sphinx==3.0.1 + sphinx-rtd-theme==0.4.3 + recommonmark==0.6.0 + m2r==0.2.1