Blackened tests and docs
This commit is contained in:
parent
5966ce29be
commit
d9cb00568a
7 changed files with 160 additions and 178 deletions
|
|
@ -17,32 +17,34 @@ import sys
|
||||||
|
|
||||||
# Load module from relative imports
|
# Load module from relative imports
|
||||||
|
|
||||||
module_path = os.path.abspath('../..')
|
module_path = os.path.abspath("../..")
|
||||||
sys.path.insert(0, module_path)
|
sys.path.insert(0, module_path)
|
||||||
|
|
||||||
# Handle mock imports for non-platform-agnostic modules
|
# Handle mock imports for non-platform-agnostic modules
|
||||||
|
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
|
||||||
class Mock(MagicMock):
|
class Mock(MagicMock):
|
||||||
@classmethod
|
@classmethod
|
||||||
def __getattr__(cls, name):
|
def __getattr__(cls, name):
|
||||||
return MagicMock()
|
return MagicMock()
|
||||||
|
|
||||||
mock_imports = ['picamera', 'picamera.array', 'picamera.mmalobj']
|
|
||||||
|
mock_imports = ["picamera", "picamera.array", "picamera.mmalobj"]
|
||||||
|
|
||||||
sys.modules.update((mod_name, Mock()) for mod_name in mock_imports)
|
sys.modules.update((mod_name, Mock()) for mod_name in mock_imports)
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = 'OpenFlexure Microscope Software'
|
project = "OpenFlexure Microscope Software"
|
||||||
copyright = '2018, Bath Open Instrumentation Group'
|
copyright = "2018, Bath Open Instrumentation Group"
|
||||||
author = 'Bath Open Instrumentation Group'
|
author = "Bath Open Instrumentation Group"
|
||||||
|
|
||||||
# The short X.Y version
|
# The short X.Y version
|
||||||
version = ''
|
version = ""
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
release = ''
|
release = ""
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
@ -55,32 +57,32 @@ release = ''
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
"sphinx.ext.autodoc",
|
||||||
'sphinx.ext.napoleon',
|
"sphinx.ext.napoleon",
|
||||||
'sphinx.ext.intersphinx',
|
"sphinx.ext.intersphinx",
|
||||||
'sphinx.ext.todo',
|
"sphinx.ext.todo",
|
||||||
'sphinx.ext.viewcode',
|
"sphinx.ext.viewcode",
|
||||||
'sphinx.ext.githubpages',
|
"sphinx.ext.githubpages",
|
||||||
'sphinx.ext.ifconfig',
|
"sphinx.ext.ifconfig",
|
||||||
'sphinxcontrib.httpdomain',
|
"sphinxcontrib.httpdomain",
|
||||||
'sphinxcontrib.autohttp.flask',
|
"sphinxcontrib.autohttp.flask",
|
||||||
'sphinxcontrib.autohttp.flaskqref'
|
"sphinxcontrib.autohttp.flaskqref",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Override ordering
|
# Override ordering
|
||||||
autodoc_member_order = 'bysource'
|
autodoc_member_order = "bysource"
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix(es) of source filenames.
|
# The suffix(es) of source filenames.
|
||||||
# You can specify multiple suffix as a list of string:
|
# You can specify multiple suffix as a list of string:
|
||||||
#
|
#
|
||||||
# source_suffix = ['.rst', '.md']
|
# source_suffix = ['.rst', '.md']
|
||||||
source_suffix = '.rst'
|
source_suffix = ".rst"
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = "index"
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
@ -114,7 +116,7 @@ html_theme = "sphinx_rtd_theme"
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# 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,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ['_static']
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
# Custom sidebar templates, must be a dictionary that maps document names
|
# Custom sidebar templates, must be a dictionary that maps document names
|
||||||
# to template names.
|
# to template names.
|
||||||
|
|
@ -130,7 +132,7 @@ html_static_path = ['_static']
|
||||||
# -- Options for HTMLHelp output ---------------------------------------------
|
# -- Options for HTMLHelp output ---------------------------------------------
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'OpenFlexureMicroscopeSoftwaredoc'
|
htmlhelp_basename = "OpenFlexureMicroscopeSoftwaredoc"
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output ------------------------------------------------
|
# -- Options for LaTeX output ------------------------------------------------
|
||||||
|
|
@ -139,15 +141,12 @@ latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#
|
#
|
||||||
# 'papersize': 'letterpaper',
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
#
|
#
|
||||||
# 'pointsize': '10pt',
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
#
|
#
|
||||||
# 'preamble': '',
|
# 'preamble': '',
|
||||||
|
|
||||||
# Latex figure (float) alignment
|
# Latex figure (float) alignment
|
||||||
#
|
#
|
||||||
# 'figure_align': 'htbp',
|
# 'figure_align': 'htbp',
|
||||||
|
|
@ -157,8 +156,13 @@ latex_elements = {
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
(master_doc, 'OpenFlexureMicroscopeSoftware.tex', 'OpenFlexure Microscope Software Documentation',
|
(
|
||||||
'Bath Open Instrumentation Group', 'manual'),
|
master_doc,
|
||||||
|
"OpenFlexureMicroscopeSoftware.tex",
|
||||||
|
"OpenFlexure Microscope Software Documentation",
|
||||||
|
"Bath Open Instrumentation Group",
|
||||||
|
"manual",
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -167,8 +171,13 @@ latex_documents = [
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [
|
||||||
(master_doc, 'openflexuremicroscopesoftware', 'OpenFlexure Microscope Software Documentation',
|
(
|
||||||
[author], 1)
|
master_doc,
|
||||||
|
"openflexuremicroscopesoftware",
|
||||||
|
"OpenFlexure Microscope Software Documentation",
|
||||||
|
[author],
|
||||||
|
1,
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -178,9 +187,15 @@ man_pages = [
|
||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
(master_doc, 'OpenFlexureMicroscopeSoftware', 'OpenFlexure Microscope Software Documentation',
|
(
|
||||||
author, 'OpenFlexureMicroscopeSoftware', 'One line description of project.',
|
master_doc,
|
||||||
'Miscellaneous'),
|
"OpenFlexureMicroscopeSoftware",
|
||||||
|
"OpenFlexure Microscope Software Documentation",
|
||||||
|
author,
|
||||||
|
"OpenFlexureMicroscopeSoftware",
|
||||||
|
"One line description of project.",
|
||||||
|
"Miscellaneous",
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -199,7 +214,7 @@ epub_title = project
|
||||||
# epub_uid = ''
|
# epub_uid = ''
|
||||||
|
|
||||||
# A list of files that should not be packed into the epub file.
|
# A list of files that should not be packed into the epub file.
|
||||||
epub_exclude_files = ['search.html']
|
epub_exclude_files = ["search.html"]
|
||||||
|
|
||||||
|
|
||||||
# -- Extension configuration -------------------------------------------------
|
# -- Extension configuration -------------------------------------------------
|
||||||
|
|
@ -208,11 +223,11 @@ epub_exclude_files = ['search.html']
|
||||||
|
|
||||||
# Example configuration for intersphinx: refer to the Python standard library.
|
# Example configuration for intersphinx: refer to the Python standard library.
|
||||||
intersphinx_mapping = {
|
intersphinx_mapping = {
|
||||||
'openflexure_stage': ('https://openflexure-stage.readthedocs.io/en/latest/', None),
|
"openflexure_stage": ("https://openflexure-stage.readthedocs.io/en/latest/", None),
|
||||||
'picamera': ('https://picamera.readthedocs.io/en/release-1.13/', None)
|
"picamera": ("https://picamera.readthedocs.io/en/release-1.13/", None),
|
||||||
}
|
}
|
||||||
|
|
||||||
# -- Options for todo extension ----------------------------------------------
|
# -- Options for todo extension ----------------------------------------------
|
||||||
|
|
||||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
todo_include_todos = True
|
todo_include_todos = True
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ FORM_PATH = os.path.join(HERE, "forms.json")
|
||||||
|
|
||||||
### MICROSCOPE PLUGIN ###
|
### MICROSCOPE PLUGIN ###
|
||||||
|
|
||||||
|
|
||||||
class MyPluginClass(MicroscopePlugin):
|
class MyPluginClass(MicroscopePlugin):
|
||||||
"""
|
"""
|
||||||
A set of default plugins
|
A set of default plugins
|
||||||
|
|
@ -20,13 +21,13 @@ class MyPluginClass(MicroscopePlugin):
|
||||||
|
|
||||||
global FORM_PATH
|
global FORM_PATH
|
||||||
|
|
||||||
with open(FORM_PATH, 'r') as sc:
|
with open(FORM_PATH, "r") as sc:
|
||||||
api_form = json.load(sc)
|
api_form = json.load(sc)
|
||||||
|
|
||||||
api_views = {
|
api_views = {
|
||||||
'/identify': IdentifyAPI,
|
"/identify": IdentifyAPI,
|
||||||
'/hello': HelloWorldAPI,
|
"/hello": HelloWorldAPI,
|
||||||
'/timelapse': TimelapseAPI,
|
"/timelapse": TimelapseAPI,
|
||||||
}
|
}
|
||||||
|
|
||||||
def identify(self):
|
def identify(self):
|
||||||
|
|
@ -34,8 +35,9 @@ class MyPluginClass(MicroscopePlugin):
|
||||||
Demonstrate access to Microscope.camera, and Microscope.stage
|
Demonstrate access to Microscope.camera, and Microscope.stage
|
||||||
"""
|
"""
|
||||||
|
|
||||||
response = "My parent camera is {}, and my parent stage is {}.".format(self.microscope.camera,
|
response = "My parent camera is {}, and my parent stage is {}.".format(
|
||||||
self.microscope.stage)
|
self.microscope.camera, self.microscope.stage
|
||||||
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def hello_world(self):
|
def hello_world(self):
|
||||||
|
|
@ -58,33 +60,33 @@ class MyPluginClass(MicroscopePlugin):
|
||||||
|
|
||||||
# Create a data stream to capture to
|
# Create a data stream to capture to
|
||||||
capture_data = self.microscope.camera.new_image(
|
capture_data = self.microscope.camera.new_image(
|
||||||
write_to_file=True,
|
write_to_file=True, temporary=False
|
||||||
temporary=False)
|
)
|
||||||
|
|
||||||
# Capture a still image from the Pi camera, into the data stream
|
# Capture a still image from the Pi camera, into the data stream
|
||||||
self.microscope.camera.capture(
|
self.microscope.camera.capture(capture_data, use_video_port=True)
|
||||||
capture_data,
|
|
||||||
use_video_port=True)
|
|
||||||
|
|
||||||
# Append the capture data to our list
|
# Append the capture data to our list
|
||||||
capture_array.append(capture_data)
|
capture_array.append(capture_data)
|
||||||
|
|
||||||
# Wait for 1 minute
|
# Wait for 1 minute
|
||||||
time.sleep(60)
|
time.sleep(60)
|
||||||
|
|
||||||
|
|
||||||
### API VIEWS ###
|
### API VIEWS ###
|
||||||
|
|
||||||
|
|
||||||
class IdentifyAPI(MicroscopeViewPlugin):
|
class IdentifyAPI(MicroscopeViewPlugin):
|
||||||
"""
|
"""
|
||||||
A simple example API plugin, attached through the main microscope plugin.
|
A simple example API plugin, attached through the main microscope plugin.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
"""
|
"""
|
||||||
Method to call when an HTTP GET request is made.
|
Method to call when an HTTP GET request is made.
|
||||||
"""
|
"""
|
||||||
# Call a method from our plugin, using the MicroscopeViewPlugin.plugin shortcut
|
# Call a method from our plugin, using the MicroscopeViewPlugin.plugin shortcut
|
||||||
data = self.plugin.identify()
|
data = self.plugin.identify()
|
||||||
return Response(escape(data))
|
return Response(escape(data))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -99,13 +101,11 @@ class HelloWorldAPI(MicroscopeViewPlugin):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# If the microscope does not already contain our plugin_string attribute
|
# If the microscope does not already contain our plugin_string attribute
|
||||||
if not hasattr(self.microscope, 'plugin_string'):
|
if not hasattr(self.microscope, "plugin_string"):
|
||||||
# Make a string, using the MicroscopeViewPlugin.plugin shortcut
|
# Make a string, using the MicroscopeViewPlugin.plugin shortcut
|
||||||
self.microscope.plugin_string = self.plugin.hello_world()
|
self.microscope.plugin_string = self.plugin.hello_world()
|
||||||
|
|
||||||
json_response = jsonify({
|
json_response = jsonify({"plugin_string": self.microscope.plugin_string})
|
||||||
'plugin_string': self.microscope.plugin_string
|
|
||||||
})
|
|
||||||
|
|
||||||
return Response(json_response)
|
return Response(json_response)
|
||||||
|
|
||||||
|
|
@ -118,18 +118,17 @@ class HelloWorldAPI(MicroscopeViewPlugin):
|
||||||
payload = JsonResponse(request)
|
payload = JsonResponse(request)
|
||||||
|
|
||||||
# Extract a value from the JSON key 'plugin_string', and convert to a string. If no value is given, default to empty.
|
# Extract a value from the JSON key 'plugin_string', and convert to a string. If no value is given, default to empty.
|
||||||
new_plugin_string = payload.param('plugin_string', default='', convert=str)
|
new_plugin_string = payload.param("plugin_string", default="", convert=str)
|
||||||
|
|
||||||
if new_plugin_string: # If not None or empty
|
if new_plugin_string: # If not None or empty
|
||||||
# Set microscope attribute to the specified string
|
# Set microscope attribute to the specified string
|
||||||
self.microscope.plugin_string = new_plugin_string
|
self.microscope.plugin_string = new_plugin_string
|
||||||
|
|
||||||
json_response = jsonify({
|
json_response = jsonify({"plugin_string": self.microscope.plugin_string})
|
||||||
'plugin_string': self.microscope.plugin_string
|
|
||||||
})
|
|
||||||
|
|
||||||
return Response(json_response)
|
return Response(json_response)
|
||||||
|
|
||||||
|
|
||||||
class TimelapseAPI(MicroscopeViewPlugin):
|
class TimelapseAPI(MicroscopeViewPlugin):
|
||||||
def post(self):
|
def post(self):
|
||||||
|
|
||||||
|
|
@ -137,10 +136,12 @@ class TimelapseAPI(MicroscopeViewPlugin):
|
||||||
payload = JsonResponse(request)
|
payload = JsonResponse(request)
|
||||||
|
|
||||||
# Extract the "n_images" parameter if it was passed. Otherwise, default to 10.
|
# Extract the "n_images" parameter if it was passed. Otherwise, default to 10.
|
||||||
n_images = payload.param('n_images', default=10, convert=int)
|
n_images = payload.param("n_images", default=10, convert=int)
|
||||||
|
|
||||||
# Attach the long-running method as a microscope task
|
# Attach the long-running method as a microscope task
|
||||||
self.timelapse_task = self.microscope.task.start(self.plugin.timelapse, n_images)
|
self.timelapse_task = self.microscope.task.start(
|
||||||
|
self.plugin.timelapse, n_images
|
||||||
|
)
|
||||||
|
|
||||||
# Return the state of the task (will show ID, start time, and status before the task has finished)
|
# Return the state of the task (will show ID, start time, and status before the task has finished)
|
||||||
return jsonify(self.timelapse_task.state), 202
|
return jsonify(self.timelapse_task.state), 202
|
||||||
|
|
|
||||||
|
|
@ -30,63 +30,61 @@ class APIconnection:
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
def set_overlay(self, message="", size=50):
|
def set_overlay(self, message="", size=50):
|
||||||
json = {
|
json = {"text": message, "size": size}
|
||||||
"text": message,
|
return self.post("/camera/overlay", json=json)
|
||||||
"size": size
|
|
||||||
}
|
|
||||||
return self.post('/camera/overlay', json=json)
|
|
||||||
|
|
||||||
def get_overlay(self):
|
def get_overlay(self):
|
||||||
return self.get('/camera/overlay')
|
return self.get("/camera/overlay")
|
||||||
|
|
||||||
def get_config(self):
|
def get_config(self):
|
||||||
return self.get('/config')
|
return self.get("/config")
|
||||||
|
|
||||||
def set_config(self, config_dict):
|
def set_config(self, config_dict):
|
||||||
return self.post('/config', json=config_dict)
|
return self.post("/config", json=config_dict)
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
return self.get('/state')
|
return self.get("/state")
|
||||||
|
|
||||||
def start_preview(self):
|
def start_preview(self):
|
||||||
return self.post('/camera/preview/start')
|
return self.post("/camera/preview/start")
|
||||||
|
|
||||||
def stop_preview(self):
|
def stop_preview(self):
|
||||||
return self.post('/camera/preview/stop')
|
return self.post("/camera/preview/stop")
|
||||||
|
|
||||||
def move_by(self, x=0, y=0, z=0):
|
def move_by(self, x=0, y=0, z=0):
|
||||||
json = {
|
json = {"x": x, "y": y, "z": z}
|
||||||
"x": x,
|
return self.post("/stage/position", json=json)
|
||||||
"y": y,
|
|
||||||
"z": z
|
|
||||||
}
|
|
||||||
return self.post('/stage/position', json=json)
|
|
||||||
|
|
||||||
def new_capture(self, use_video_port=True, keep_on_disk=False, resize=None):
|
def new_capture(self, use_video_port=True, keep_on_disk=False, resize=None):
|
||||||
json = {
|
json = {"keep_on_disk": keep_on_disk, "use_video_port": use_video_port}
|
||||||
"keep_on_disk": keep_on_disk,
|
|
||||||
"use_video_port": use_video_port
|
|
||||||
}
|
|
||||||
|
|
||||||
if resize:
|
if resize:
|
||||||
json['size'] = {'width': resize[0], 'height': resize[1]}
|
json["size"] = {"width": resize[0], "height": resize[1]}
|
||||||
|
|
||||||
return self.post('/camera/capture', json=json)
|
return self.post("/camera/capture", json=json)
|
||||||
|
|
||||||
def get_capture(self, capture_id):
|
def get_capture(self, capture_id):
|
||||||
uri_route = '/camera/capture/{}/download'.format(capture_id)
|
uri_route = "/camera/capture/{}/download".format(capture_id)
|
||||||
r = self.get(uri_route, json=False)
|
r = self.get(uri_route, json=False)
|
||||||
img = Image.open(BytesIO(r.content))
|
img = Image.open(BytesIO(r.content))
|
||||||
array = np.asarray(img, dtype=np.int32)
|
array = np.asarray(img, dtype=np.int32)
|
||||||
return array
|
return array
|
||||||
|
|
||||||
def del_capture(self, capture_id):
|
def del_capture(self, capture_id):
|
||||||
uri_route = '/camera/capture/{}'.format(capture_id)
|
uri_route = "/camera/capture/{}".format(capture_id)
|
||||||
return self.delete(uri_route)
|
return self.delete(uri_route)
|
||||||
|
|
||||||
def capture(self, use_video_port=True, keep_on_disk=False, delete_after_use=True, resize=None):
|
def capture(
|
||||||
p = self.new_capture(use_video_port=use_video_port, keep_on_disk=keep_on_disk, resize=resize)
|
self,
|
||||||
capture_id = p['metadata']['id']
|
use_video_port=True,
|
||||||
|
keep_on_disk=False,
|
||||||
|
delete_after_use=True,
|
||||||
|
resize=None,
|
||||||
|
):
|
||||||
|
p = self.new_capture(
|
||||||
|
use_video_port=use_video_port, keep_on_disk=keep_on_disk, resize=resize
|
||||||
|
)
|
||||||
|
capture_id = p["metadata"]["id"]
|
||||||
img_array = self.get_capture(capture_id)
|
img_array = self.get_capture(capture_id)
|
||||||
|
|
||||||
if delete_after_use:
|
if delete_after_use:
|
||||||
|
|
@ -95,10 +93,8 @@ class APIconnection:
|
||||||
return img_array
|
return img_array
|
||||||
|
|
||||||
def set_zoom(self, zoom_value=1.0):
|
def set_zoom(self, zoom_value=1.0):
|
||||||
json = {
|
json = {"zoom_value": zoom_value}
|
||||||
"zoom_value": zoom_value,
|
return self.post("/camera/zoom", json=json)
|
||||||
}
|
|
||||||
return self.post('/camera/zoom', json=json)
|
|
||||||
|
|
||||||
def get_zoom(self):
|
def get_zoom(self):
|
||||||
return self.get('/camera/zoom')
|
return self.get("/camera/zoom")
|
||||||
|
|
|
||||||
|
|
@ -6,27 +6,23 @@ import unittest
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
class TestCapture(unittest.TestCase):
|
class TestCapture(unittest.TestCase):
|
||||||
|
|
||||||
def test_capture_config(self):
|
def test_capture_config(self):
|
||||||
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
||||||
config = connection.get_config()
|
config = connection.get_config()
|
||||||
|
|
||||||
expected_keys = [
|
expected_keys = ["image_resolution", "stream_resolution", "numpy_resolution"]
|
||||||
'image_resolution',
|
|
||||||
'stream_resolution',
|
|
||||||
'numpy_resolution',
|
|
||||||
]
|
|
||||||
|
|
||||||
for key in expected_keys:
|
for key in expected_keys:
|
||||||
self.assertTrue(key in config)
|
self.assertTrue(key in config)
|
||||||
|
|
||||||
def test_capture_videoport(self):
|
def test_capture_videoport(self):
|
||||||
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
||||||
resolution = connection.get_config()['stream_resolution']
|
resolution = connection.get_config()["stream_resolution"]
|
||||||
|
|
||||||
for resize in [None, (640, 480)]:
|
for resize in [None, (640, 480)]:
|
||||||
|
|
||||||
|
|
@ -34,16 +30,17 @@ class TestCapture(unittest.TestCase):
|
||||||
resolution = resize
|
resolution = resize
|
||||||
|
|
||||||
capture_array = connection.capture(
|
capture_array = connection.capture(
|
||||||
use_video_port=True,
|
use_video_port=True,
|
||||||
keep_on_disk=False,
|
keep_on_disk=False,
|
||||||
delete_after_use=True,
|
delete_after_use=True,
|
||||||
resize=resize)
|
resize=resize,
|
||||||
|
)
|
||||||
|
|
||||||
self.assertTrue(capture_array.shape == (resolution[1], resolution[0], 3))
|
self.assertTrue(capture_array.shape == (resolution[1], resolution[0], 3))
|
||||||
|
|
||||||
def test_capture_full(self):
|
def test_capture_full(self):
|
||||||
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
||||||
resolution = connection.get_config()['image_resolution']
|
resolution = connection.get_config()["image_resolution"]
|
||||||
|
|
||||||
for resize in [None, (640, 480)]:
|
for resize in [None, (640, 480)]:
|
||||||
|
|
||||||
|
|
@ -51,23 +48,21 @@ class TestCapture(unittest.TestCase):
|
||||||
resolution = resize
|
resolution = resize
|
||||||
|
|
||||||
capture_array = connection.capture(
|
capture_array = connection.capture(
|
||||||
use_video_port=False,
|
use_video_port=False,
|
||||||
keep_on_disk=False,
|
keep_on_disk=False,
|
||||||
delete_after_use=True,
|
delete_after_use=True,
|
||||||
resize=resize)
|
resize=resize,
|
||||||
|
)
|
||||||
|
|
||||||
self.assertTrue(capture_array.shape == (resolution[1], resolution[0], 3))
|
self.assertTrue(capture_array.shape == (resolution[1], resolution[0], 3))
|
||||||
|
|
||||||
|
|
||||||
class TestStage(unittest.TestCase):
|
class TestStage(unittest.TestCase):
|
||||||
|
|
||||||
def test_stage_config(self):
|
def test_stage_config(self):
|
||||||
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
||||||
config = connection.get_config()
|
config = connection.get_config()
|
||||||
|
|
||||||
expected_keys = [
|
expected_keys = ["backlash"]
|
||||||
'backlash',
|
|
||||||
]
|
|
||||||
|
|
||||||
for key in expected_keys:
|
for key in expected_keys:
|
||||||
self.assertTrue(key in config)
|
self.assertTrue(key in config)
|
||||||
|
|
@ -76,14 +71,12 @@ class TestStage(unittest.TestCase):
|
||||||
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
||||||
state = connection.get_state()
|
state = connection.get_state()
|
||||||
|
|
||||||
self.assertTrue('stage' in state)
|
self.assertTrue("stage" in state)
|
||||||
|
|
||||||
expected_keys = [
|
expected_keys = ["position"]
|
||||||
'position',
|
|
||||||
]
|
|
||||||
|
|
||||||
for key in expected_keys:
|
for key in expected_keys:
|
||||||
self.assertTrue(key in state['stage'])
|
self.assertTrue(key in state["stage"])
|
||||||
|
|
||||||
def test_stage_movement(self):
|
def test_stage_movement(self):
|
||||||
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
connection = APIconnection(host="localhost", port=5000, api_ver="v1")
|
||||||
|
|
@ -91,16 +84,16 @@ class TestStage(unittest.TestCase):
|
||||||
move_distance = 500
|
move_distance = 500
|
||||||
for axis in range(3):
|
for axis in range(3):
|
||||||
for direction in [1, -1]:
|
for direction in [1, -1]:
|
||||||
pos_i_dict = connection.get_state()['stage']['position']
|
pos_i_dict = connection.get_state()["stage"]["position"]
|
||||||
pos_i = [pos_i_dict['x'], pos_i_dict['y'], pos_i_dict['z']]
|
pos_i = [pos_i_dict["x"], pos_i_dict["y"], pos_i_dict["z"]]
|
||||||
|
|
||||||
move = [0, 0, 0]
|
move = [0, 0, 0]
|
||||||
move[axis] = move_distance*direction
|
move[axis] = move_distance * direction
|
||||||
|
|
||||||
connection.move_by(*move)
|
connection.move_by(*move)
|
||||||
|
|
||||||
pos_f_dict = connection.get_state()['stage']['position']
|
pos_f_dict = connection.get_state()["stage"]["position"]
|
||||||
pos_f = [pos_f_dict['x'], pos_f_dict['y'], pos_f_dict['z']]
|
pos_f = [pos_f_dict["x"], pos_f_dict["y"], pos_f_dict["z"]]
|
||||||
|
|
||||||
diff = np.subtract(pos_f, pos_i)
|
diff = np.subtract(pos_f, pos_i)
|
||||||
logging.debug("{} > {}".format(pos_i, pos_f))
|
logging.debug("{} > {}".format(pos_i, pos_f))
|
||||||
|
|
@ -108,7 +101,7 @@ class TestStage(unittest.TestCase):
|
||||||
self.assertTrue(np.array_equal(diff, move))
|
self.assertTrue(np.array_equal(diff, move))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
|
|
||||||
suites = [
|
suites = [
|
||||||
unittest.TestLoader().loadTestsFromTestCase(TestCapture),
|
unittest.TestLoader().loadTestsFromTestCase(TestCapture),
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@ import unittest
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
class TestCaptureMethods(unittest.TestCase):
|
class TestCaptureMethods(unittest.TestCase):
|
||||||
|
|
||||||
def test_still_capture(self):
|
def test_still_capture(self):
|
||||||
"""Tests capturing still images to a BytesIO stream."""
|
"""Tests capturing still images to a BytesIO stream."""
|
||||||
global camera
|
global camera
|
||||||
|
|
@ -30,11 +30,7 @@ class TestCaptureMethods(unittest.TestCase):
|
||||||
# Capture to a context (auto-deletes files when done)
|
# Capture to a context (auto-deletes files when done)
|
||||||
with camera.new_image(write_to_file=False) as output:
|
with camera.new_image(write_to_file=False) as output:
|
||||||
|
|
||||||
camera.capture(
|
camera.capture(output, use_video_port=use_video_port, resize=resize)
|
||||||
output,
|
|
||||||
use_video_port=use_video_port,
|
|
||||||
resize=resize
|
|
||||||
)
|
|
||||||
|
|
||||||
# Ensure file deletion fails and returns False
|
# Ensure file deletion fails and returns False
|
||||||
self.assertFalse(output.delete_file())
|
self.assertFalse(output.delete_file())
|
||||||
|
|
@ -43,14 +39,8 @@ class TestCaptureMethods(unittest.TestCase):
|
||||||
|
|
||||||
# BEFORE DELETE: Ensure StreamObject 'stream' has
|
# BEFORE DELETE: Ensure StreamObject 'stream' has
|
||||||
# a valid BytesIO object and byte string
|
# a valid BytesIO object and byte string
|
||||||
self.assertTrue(isinstance(
|
self.assertTrue(isinstance(output.data, io.IOBase))
|
||||||
output.data,
|
self.assertTrue(isinstance(output.binary, (bytes, bytearray)))
|
||||||
io.IOBase
|
|
||||||
))
|
|
||||||
self.assertTrue(isinstance(
|
|
||||||
output.binary,
|
|
||||||
(bytes, bytearray)
|
|
||||||
))
|
|
||||||
|
|
||||||
# Save capture to file
|
# Save capture to file
|
||||||
output.save_file()
|
output.save_file()
|
||||||
|
|
@ -65,10 +55,7 @@ class TestCaptureMethods(unittest.TestCase):
|
||||||
# AFTER DELETE: Ensure StreamObject 'stream' has
|
# AFTER DELETE: Ensure StreamObject 'stream' has
|
||||||
# a valid BytesIO object and byte string
|
# a valid BytesIO object and byte string
|
||||||
self.assertTrue(isinstance(output.data, io.IOBase))
|
self.assertTrue(isinstance(output.data, io.IOBase))
|
||||||
self.assertTrue(isinstance(
|
self.assertTrue(isinstance(output.binary, (bytes, bytearray)))
|
||||||
output.binary,
|
|
||||||
(bytes, bytearray)
|
|
||||||
))
|
|
||||||
|
|
||||||
# Create a PIL image from stream
|
# Create a PIL image from stream
|
||||||
image = Image.open(output.data)
|
image = Image.open(output.data)
|
||||||
|
|
@ -102,7 +89,8 @@ class TestCaptureMethods(unittest.TestCase):
|
||||||
output = camera.capture(
|
output = camera.capture(
|
||||||
camera.new_image(write_to_file=True),
|
camera.new_image(write_to_file=True),
|
||||||
use_video_port=use_video_port,
|
use_video_port=use_video_port,
|
||||||
resize=resize)
|
resize=resize,
|
||||||
|
)
|
||||||
|
|
||||||
# Check file got saved
|
# Check file got saved
|
||||||
self.assertTrue(os.path.isfile(output.file))
|
self.assertTrue(os.path.isfile(output.file))
|
||||||
|
|
@ -122,7 +110,6 @@ class TestCaptureMethods(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class TestUnencodedMethods(unittest.TestCase):
|
class TestUnencodedMethods(unittest.TestCase):
|
||||||
|
|
||||||
def test_yuv_array(self):
|
def test_yuv_array(self):
|
||||||
"""Tests capturing unencoded YUV data to a Numpy array."""
|
"""Tests capturing unencoded YUV data to a Numpy array."""
|
||||||
global camera
|
global camera
|
||||||
|
|
@ -136,9 +123,7 @@ class TestUnencodedMethods(unittest.TestCase):
|
||||||
camera.wait_for_camera()
|
camera.wait_for_camera()
|
||||||
|
|
||||||
# Capture RGB array
|
# Capture RGB array
|
||||||
yuv = camera.yuv(
|
yuv = camera.yuv(use_video_port=use_video_port, resize=resize)
|
||||||
use_video_port=use_video_port,
|
|
||||||
resize=resize)
|
|
||||||
|
|
||||||
# Ensure capture output is a valid numpy array
|
# Ensure capture output is a valid numpy array
|
||||||
self.assertTrue(isinstance(yuv, np.ndarray))
|
self.assertTrue(isinstance(yuv, np.ndarray))
|
||||||
|
|
@ -168,9 +153,7 @@ class TestUnencodedMethods(unittest.TestCase):
|
||||||
camera.wait_for_camera()
|
camera.wait_for_camera()
|
||||||
|
|
||||||
# Capture RGB array
|
# Capture RGB array
|
||||||
rgb = camera.array(
|
rgb = camera.array(use_video_port=use_video_port, resize=resize)
|
||||||
use_video_port=use_video_port,
|
|
||||||
resize=resize)
|
|
||||||
|
|
||||||
# Ensure capture output is a valid numpy array
|
# Ensure capture output is a valid numpy array
|
||||||
self.assertTrue(isinstance(rgb, np.ndarray))
|
self.assertTrue(isinstance(rgb, np.ndarray))
|
||||||
|
|
@ -189,7 +172,6 @@ class TestUnencodedMethods(unittest.TestCase):
|
||||||
|
|
||||||
|
|
||||||
class TestRecordMethods(unittest.TestCase):
|
class TestRecordMethods(unittest.TestCase):
|
||||||
|
|
||||||
def test_video_record(self):
|
def test_video_record(self):
|
||||||
"""Tests recording videos to BytesIO stream, and to file on disk."""
|
"""Tests recording videos to BytesIO stream, and to file on disk."""
|
||||||
global camera
|
global camera
|
||||||
|
|
@ -201,9 +183,7 @@ class TestRecordMethods(unittest.TestCase):
|
||||||
# Wait for camera
|
# Wait for camera
|
||||||
camera.wait_for_camera()
|
camera.wait_for_camera()
|
||||||
|
|
||||||
with camera.new_video(
|
with camera.new_video(write_to_file=write_to_file) as output:
|
||||||
write_to_file=write_to_file
|
|
||||||
) as output:
|
|
||||||
|
|
||||||
# Start recording
|
# Start recording
|
||||||
camera.start_recording(output)
|
camera.start_recording(output)
|
||||||
|
|
@ -278,7 +258,7 @@ class TestThreadStarting(unittest.TestCase):
|
||||||
self.assertIsInstance(camera.stream, io.IOBase)
|
self.assertIsInstance(camera.stream, io.IOBase)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
with PiCameraStreamer() as camera:
|
with PiCameraStreamer() as camera:
|
||||||
|
|
||||||
suites = [
|
suites = [
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,17 @@ import atexit
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import logging, sys
|
import logging, sys
|
||||||
|
|
||||||
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
class TestPluginMethods(unittest.TestCase):
|
class TestPluginMethods(unittest.TestCase):
|
||||||
|
|
||||||
def test_plugin_load(self):
|
def test_plugin_load(self):
|
||||||
plugin_arr = microscope.plugin.plugins
|
plugin_arr = microscope.plugin.plugins
|
||||||
|
|
||||||
plugin_names = [plugin[0] for plugin in plugin_arr]
|
plugin_names = [plugin[0] for plugin in plugin_arr]
|
||||||
|
|
||||||
self.assertTrue('testing' in plugin_names)
|
self.assertTrue("testing" in plugin_names)
|
||||||
|
|
||||||
def test_camera_access(self):
|
def test_camera_access(self):
|
||||||
identify = microscope.plugin.testing.identify()
|
identify = microscope.plugin.testing.identify()
|
||||||
|
|
@ -29,18 +29,16 @@ class TestPluginMethods(unittest.TestCase):
|
||||||
self.assertTrue(identify[1] is microscope.stage)
|
self.assertTrue(identify[1] is microscope.stage)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
|
|
||||||
with Microscope() as microscope:
|
with Microscope() as microscope:
|
||||||
|
|
||||||
microscope.attach(PiCameraStreamer(), OpenFlexureStage())
|
microscope.attach(PiCameraStreamer(), OpenFlexureStage())
|
||||||
|
|
||||||
microscope.plugin.attach("openflexure_microscope.plugins.testing:Plugin")
|
microscope.plugin.attach("openflexure_microscope.plugins.testing:Plugin")
|
||||||
|
|
||||||
suites = [
|
suites = [unittest.TestLoader().loadTestsFromTestCase(TestPluginMethods)]
|
||||||
unittest.TestLoader().loadTestsFromTestCase(TestPluginMethods),
|
|
||||||
]
|
|
||||||
|
|
||||||
alltests = unittest.TestSuite(suites)
|
alltests = unittest.TestSuite(suites)
|
||||||
|
|
||||||
result = unittest.TextTestRunner(verbosity=2).run(alltests)
|
result = unittest.TextTestRunner(verbosity=2).run(alltests)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ logging.basicConfig(stream=sys.stderr, level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
class TestMicroscope(unittest.TestCase):
|
class TestMicroscope(unittest.TestCase):
|
||||||
|
|
||||||
def test_movement(self):
|
def test_movement(self):
|
||||||
move_distance = 500
|
move_distance = 500
|
||||||
for axis in range(3):
|
for axis in range(3):
|
||||||
|
|
@ -20,9 +19,11 @@ class TestMicroscope(unittest.TestCase):
|
||||||
pos_i = stage.position
|
pos_i = stage.position
|
||||||
logging.debug(pos_i)
|
logging.debug(pos_i)
|
||||||
|
|
||||||
logging.info("Moving axis {} by {}".format(axis, move_distance*direction))
|
logging.info(
|
||||||
|
"Moving axis {} by {}".format(axis, move_distance * direction)
|
||||||
|
)
|
||||||
move = [0, 0, 0]
|
move = [0, 0, 0]
|
||||||
move[axis] = move_distance*direction
|
move[axis] = move_distance * direction
|
||||||
|
|
||||||
stage.move_rel(move)
|
stage.move_rel(move)
|
||||||
|
|
||||||
|
|
@ -33,12 +34,10 @@ class TestMicroscope(unittest.TestCase):
|
||||||
self.assertTrue(np.array_equal(diff, move))
|
self.assertTrue(np.array_equal(diff, move))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
with OpenFlexureStage("/dev/ttyUSB0") as stage:
|
with OpenFlexureStage("/dev/ttyUSB0") as stage:
|
||||||
|
|
||||||
suites = [
|
suites = [unittest.TestLoader().loadTestsFromTestCase(TestMicroscope)]
|
||||||
unittest.TestLoader().loadTestsFromTestCase(TestMicroscope),
|
|
||||||
]
|
|
||||||
|
|
||||||
alltests = unittest.TestSuite(suites)
|
alltests = unittest.TestSuite(suites)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue