Skip to content

Commit a609688

Browse files
Merged in user_devices (pull request #81)
User devices
2 parents 1d7abf5 + 6ae5cfe commit a609688

File tree

1 file changed

+61
-24
lines changed

1 file changed

+61
-24
lines changed

__init__.py

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import warnings
1919
import traceback
2020
import inspect
21+
from labscript_utils import labscript_suite_install_dir, dedent
22+
from labscript_utils.labconfig import LabConfig
2123

2224
__version__ = '2.5.0'
2325

@@ -27,9 +29,6 @@
2729
check_version('zprocess', '2.2.7', '3')
2830
check_version('numpy', '1.15.1', '2')
2931

30-
from labscript_utils import labscript_suite_install_dir, dedent
31-
32-
LABSCRIPT_DEVICES_DIR = os.path.join(labscript_suite_install_dir, 'labscript_devices')
3332

3433
"""This file contains the machinery for registering and looking up what BLACS tab and
3534
runviewer parser classes belong to a particular labscript device. "labscript device"
@@ -46,18 +45,22 @@
4645
splitting it across multiple files.
4746
4847
The "new" method is more flexible. It allows BLACS tabs and runviewer parsers to be
49-
defined in any importable file within a subfolder of labscript_devices. Classes using
50-
this method can be in files with any name, and do not need class decorators. Instead,
51-
the classes should be registered by creating a file called 'register_classes.py', which
52-
when imported, makes calls to labscript_devices.register_classes() to register
53-
which BLACS tab and runviewer parser class belong to each device. Tab and parser classes
54-
must be passed to register_classes() as fully qualified names, i.e.
55-
"labscript_devices.submodule.ClassName", not by passing in the classes themselves. This
56-
ensures imports can be deferred until the classes are actually needed. When BLACS and
57-
runviewer look up classes with get_BLACS_tab() and get_runviewer_parser(),
58-
populate_registry() will be called in order to find all files called
59-
'register_classes.py' within subfolders (at any depth) of labscript_devices, and they
60-
will be imported to run their code and hence register their classes.
48+
defined in any importable file within a subfolder of labscript_devices. Additionally,
49+
the 'user_devices' configuration setting in labconfig can be used to specify a
50+
comma-delimited list of names of importable packages containing additional labscript
51+
devices.
52+
53+
Classes using the new method can be in files with any name, and do not need class
54+
decorators. Instead, the classes should be registered by creating a file called
55+
'register_classes.py', which when imported, makes calls to
56+
labscript_devices.register_classes() to register which BLACS tab and runviewer parser
57+
class belong to each device. Tab and parser classes must be passed to register_classes()
58+
as fully qualified names, i.e. "labscript_devices.submodule.ClassName", not by passing
59+
in the classes themselves. This ensures imports can be deferred until the classes are
60+
actually needed. When BLACS and runviewer look up classes with get_BLACS_tab() and
61+
get_runviewer_parser(), populate_registry() will be called in order to find all files
62+
called 'register_classes.py' within subfolders (at any depth) of labscript_devices, and
63+
they will be imported to run their code and hence register their classes.
6164
6265
The "new" method does not impose any restrictions on code organisation within subfolders
6366
of labscript_devices, and so is preferable as it allows auxiliary utilities or resource
@@ -69,6 +72,39 @@
6972
"""
7073

7174

75+
def _get_import_paths(import_names):
76+
"""For the given list of packages, return all folders containing their submodules.
77+
If the packages do not exist, ignore them."""
78+
paths = []
79+
for name in import_names:
80+
if PY2:
81+
try:
82+
_, location, _ = imp.find_module(name)
83+
except ImportError:
84+
continue
85+
paths.append(os.path.dirname(location))
86+
else:
87+
spec = importlib.util.find_spec(name)
88+
if spec is not None and spec.submodule_search_locations is not None:
89+
paths.extend(spec.submodule_search_locations)
90+
return paths
91+
92+
93+
def _get_device_dirs():
94+
"""Return the directory of labscript_devices, and the folders containing
95+
submodules of any packages listed in the user_devices labconfig setting"""
96+
try:
97+
user_devices = LabConfig().get('DEFAULT', 'user_devices')
98+
except (LabConfig.NoOptionError, LabConfig.NoSectionError):
99+
user_devices = 'user_devices'
100+
# Split on commas, remove whitespace:
101+
user_devices = [s.strip() for s in user_devices.split(',')]
102+
return _get_import_paths(['labscript_devices'] + user_devices)
103+
104+
105+
LABSCRIPT_DEVICES_DIRS = _get_device_dirs()
106+
107+
72108
class ClassRegister(object):
73109
"""A register for looking up classes by module name. Provides a
74110
decorator and a method for looking up classes decorated with it,
@@ -241,15 +277,16 @@ def populate_registry():
241277
# But they cannot all have the same name, so we import them as
242278
# labscript_devices._register_classes_script_<num> with increasing number.
243279
module_num = 0
244-
for folder, _, filenames in os.walk(LABSCRIPT_DEVICES_DIR):
245-
if 'register_classes.py' in filenames:
246-
# The module name is the path to the file, relative to the labscript suite
247-
# install directory:
248-
# Open the file using the import machinery, and import it as module_name.
249-
fp, pathname, desc = imp.find_module('register_classes', [folder])
250-
module_name = 'labscript_devices._register_classes_script_%d' % module_num
251-
_ = imp.load_module(module_name, fp, pathname, desc)
252-
module_num += 1
280+
for devices_dir in LABSCRIPT_DEVICES_DIRS:
281+
for folder, _, filenames in os.walk(devices_dir):
282+
if 'register_classes.py' in filenames:
283+
# The module name is the path to the file, relative to the labscript suite
284+
# install directory:
285+
# Open the file using the import machinery, and import it as module_name.
286+
fp, pathname, desc = imp.find_module('register_classes', [folder])
287+
module_name = 'labscript_devices._register_classes_%d' % module_num
288+
_ = imp.load_module(module_name, fp, pathname, desc)
289+
module_num += 1
253290

254291

255292
if __name__ == '__main__':

0 commit comments

Comments
 (0)