Blackened tests and docs

This commit is contained in:
Joel Collins 2019-09-15 14:21:24 +01:00
parent 5966ce29be
commit d9cb00568a
7 changed files with 160 additions and 178 deletions

View file

@ -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

View file

@ -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

View file

@ -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")

View file

@ -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),

View file

@ -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 = [

View file

@ -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)

View file

@ -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)