Commit d9cb0056 authored by Joel Collins's avatar Joel Collins
Browse files

Blackened tests and docs

parent 5966ce29
Loading
Loading
Loading
Loading
+53 −38
Original line number Diff line number Diff line
@@ -17,32 +17,34 @@ import sys

# Load module from relative imports

module_path = os.path.abspath('../..')
module_path = os.path.abspath("../..")
sys.path.insert(0, module_path)

# Handle mock imports for non-platform-agnostic modules

from unittest.mock import MagicMock


class Mock(MagicMock):
    @classmethod
    def __getattr__(cls, name):
        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)

# -- Project information -----------------------------------------------------

project = 'OpenFlexure Microscope Software'
copyright = '2018, Bath Open Instrumentation Group'
author = 'Bath Open Instrumentation Group'
project = "OpenFlexure Microscope Software"
copyright = "2018, Bath Open Instrumentation Group"
author = "Bath Open Instrumentation Group"

# The short X.Y version
version = ''
version = ""
# The full version, including alpha/beta/rc tags
release = ''
release = ""


# -- General configuration ---------------------------------------------------
@@ -55,32 +57,32 @@ release = ''
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.napoleon',
    'sphinx.ext.intersphinx',
    'sphinx.ext.todo',
    'sphinx.ext.viewcode',
    'sphinx.ext.githubpages',
    'sphinx.ext.ifconfig',
    'sphinxcontrib.httpdomain',
    'sphinxcontrib.autohttp.flask',
    'sphinxcontrib.autohttp.flaskqref'
    "sphinx.ext.autodoc",
    "sphinx.ext.napoleon",
    "sphinx.ext.intersphinx",
    "sphinx.ext.todo",
    "sphinx.ext.viewcode",
    "sphinx.ext.githubpages",
    "sphinx.ext.ifconfig",
    "sphinxcontrib.httpdomain",
    "sphinxcontrib.autohttp.flask",
    "sphinxcontrib.autohttp.flaskqref",
]

# Override ordering
autodoc_member_order = 'bysource'
autodoc_member_order = "bysource"

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
source_suffix = ".rst"

# The master toctree document.
master_doc = 'index'
master_doc = "index"

# The language for content autogenerated by Sphinx. Refer to documentation
# 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,
# 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']
html_static_path = ["_static"]

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
@@ -130,7 +132,7 @@ html_static_path = ['_static']
# -- Options for HTMLHelp output ---------------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = 'OpenFlexureMicroscopeSoftwaredoc'
htmlhelp_basename = "OpenFlexureMicroscopeSoftwaredoc"


# -- Options for LaTeX output ------------------------------------------------
@@ -139,15 +141,12 @@ latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',

    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',

    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
@@ -157,8 +156,13 @@ latex_elements = {
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
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
# (source start file, name, description, authors, manual section).
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,
#  dir menu entry, description, category)
texinfo_documents = [
    (master_doc, 'OpenFlexureMicroscopeSoftware', 'OpenFlexure Microscope Software Documentation',
     author, 'OpenFlexureMicroscopeSoftware', 'One line description of project.',
     'Miscellaneous'),
    (
        master_doc,
        "OpenFlexureMicroscopeSoftware",
        "OpenFlexure Microscope Software Documentation",
        author,
        "OpenFlexureMicroscopeSoftware",
        "One line description of project.",
        "Miscellaneous",
    )
]


@@ -199,7 +214,7 @@ epub_title = project
# epub_uid = ''

# 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 -------------------------------------------------
@@ -208,8 +223,8 @@ epub_exclude_files = ['search.html']

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
    'openflexure_stage': ('https://openflexure-stage.readthedocs.io/en/latest/', None),
    'picamera': ('https://picamera.readthedocs.io/en/release-1.13/', None)
    "openflexure_stage": ("https://openflexure-stage.readthedocs.io/en/latest/", None),
    "picamera": ("https://picamera.readthedocs.io/en/release-1.13/", None),
}

# -- Options for todo extension ----------------------------------------------
+27 −26
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ FORM_PATH = os.path.join(HERE, "forms.json")

### MICROSCOPE PLUGIN ###


class MyPluginClass(MicroscopePlugin):
    """
    A set of default plugins
@@ -20,13 +21,13 @@ class MyPluginClass(MicroscopePlugin):

    global FORM_PATH

    with open(FORM_PATH, 'r') as sc:
    with open(FORM_PATH, "r") as sc:
        api_form = json.load(sc)

    api_views = {
        '/identify': IdentifyAPI,
        '/hello': HelloWorldAPI,
        '/timelapse': TimelapseAPI,
        "/identify": IdentifyAPI,
        "/hello": HelloWorldAPI,
        "/timelapse": TimelapseAPI,
    }

    def identify(self):
@@ -34,8 +35,9 @@ class MyPluginClass(MicroscopePlugin):
        Demonstrate access to Microscope.camera, and Microscope.stage
        """

        response = "My parent camera is {}, and my parent stage is {}.".format(self.microscope.camera, 
                                                                                self.microscope.stage)
        response = "My parent camera is {}, and my parent stage is {}.".format(
            self.microscope.camera, self.microscope.stage
        )
        return response

    def hello_world(self):
@@ -58,13 +60,11 @@ class MyPluginClass(MicroscopePlugin):

                # Create a data stream to capture to
                capture_data = self.microscope.camera.new_image(
                    write_to_file=True,
                    temporary=False)
                    write_to_file=True, temporary=False
                )

                # Capture a still image from the Pi camera, into the data stream
                self.microscope.camera.capture(
                    capture_data,
                    use_video_port=True)
                self.microscope.camera.capture(capture_data, use_video_port=True)

                # Append the capture data to our list
                capture_array.append(capture_data)
@@ -75,10 +75,12 @@ class MyPluginClass(MicroscopePlugin):

### API VIEWS ###


class IdentifyAPI(MicroscopeViewPlugin):
    """
    A simple example API plugin, attached through the main microscope plugin.
    """

    def get(self):
        """
        Method to call when an HTTP GET request is made.
@@ -99,13 +101,11 @@ class HelloWorldAPI(MicroscopeViewPlugin):
        """

        # 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
            self.microscope.plugin_string = self.plugin.hello_world()

        json_response = jsonify({
            'plugin_string': self.microscope.plugin_string
        })
        json_response = jsonify({"plugin_string": self.microscope.plugin_string})

        return Response(json_response)

@@ -118,18 +118,17 @@ class HelloWorldAPI(MicroscopeViewPlugin):
        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.
        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
            # Set microscope attribute to the specified string
            self.microscope.plugin_string = new_plugin_string

        json_response = jsonify({
            'plugin_string': self.microscope.plugin_string
        })
        json_response = jsonify({"plugin_string": self.microscope.plugin_string})

        return Response(json_response)


class TimelapseAPI(MicroscopeViewPlugin):
    def post(self):

@@ -137,10 +136,12 @@ class TimelapseAPI(MicroscopeViewPlugin):
        payload = JsonResponse(request)

        # 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
        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 jsonify(self.timelapse_task.state), 202
+29 −33
Original line number Diff line number Diff line
@@ -30,63 +30,61 @@ class APIconnection:
        return r.json()

    def set_overlay(self, message="", size=50):
        json = {
            "text": message,
            "size": size
        }
        return self.post('/camera/overlay', json=json)
        json = {"text": message, "size": size}
        return self.post("/camera/overlay", json=json)

    def get_overlay(self):
        return self.get('/camera/overlay')
        return self.get("/camera/overlay")

    def get_config(self):
        return self.get('/config')
        return self.get("/config")

    def set_config(self, config_dict):
        return self.post('/config', json=config_dict)
        return self.post("/config", json=config_dict)

    def get_state(self):
        return self.get('/state')
        return self.get("/state")

    def start_preview(self):
        return self.post('/camera/preview/start')
        return self.post("/camera/preview/start")

    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):
        json = {
            "x": x,
            "y": y,
            "z": z
        }
        return self.post('/stage/position', json=json)
        json = {"x": x, "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):
        json = {
            "keep_on_disk": keep_on_disk,
            "use_video_port": use_video_port
        }
        json = {"keep_on_disk": keep_on_disk, "use_video_port": use_video_port}

        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):
        uri_route = '/camera/capture/{}/download'.format(capture_id)
        uri_route = "/camera/capture/{}/download".format(capture_id)
        r = self.get(uri_route, json=False)
        img = Image.open(BytesIO(r.content))
        array = np.asarray(img, dtype=np.int32)
        return array

    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)

    def capture(self, 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']
    def capture(
        self,
        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)

        if delete_after_use:
@@ -95,10 +93,8 @@ class APIconnection:
        return img_array

    def set_zoom(self, zoom_value=1.0):
        json = {
            "zoom_value": zoom_value,
        }
        return self.post('/camera/zoom', json=json)
        json = {"zoom_value": zoom_value}
        return self.post("/camera/zoom", json=json)

    def get_zoom(self):
        return self.get('/camera/zoom')
        return self.get("/camera/zoom")
+25 −32
Original line number Diff line number Diff line
@@ -6,27 +6,23 @@ import unittest

import logging
import sys

logging.basicConfig(stream=sys.stderr, level=logging.INFO)


class TestCapture(unittest.TestCase):

    def test_capture_config(self):
        connection = APIconnection(host="localhost", port=5000, api_ver="v1")
        config = connection.get_config()

        expected_keys = [
            'image_resolution',
            'stream_resolution',
            'numpy_resolution',
        ]
        expected_keys = ["image_resolution", "stream_resolution", "numpy_resolution"]

        for key in expected_keys:
            self.assertTrue(key in config)

    def test_capture_videoport(self):
        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)]:

@@ -37,13 +33,14 @@ class TestCapture(unittest.TestCase):
                use_video_port=True,
                keep_on_disk=False,
                delete_after_use=True,
                resize=resize)
                resize=resize,
            )

            self.assertTrue(capture_array.shape == (resolution[1], resolution[0], 3))

    def test_capture_full(self):
        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)]:

@@ -54,20 +51,18 @@ class TestCapture(unittest.TestCase):
                use_video_port=False,
                keep_on_disk=False,
                delete_after_use=True,
                resize=resize)
                resize=resize,
            )

            self.assertTrue(capture_array.shape == (resolution[1], resolution[0], 3))


class TestStage(unittest.TestCase):

    def test_stage_config(self):
        connection = APIconnection(host="localhost", port=5000, api_ver="v1")
        config = connection.get_config()

        expected_keys = [
            'backlash',
        ]
        expected_keys = ["backlash"]

        for key in expected_keys:
            self.assertTrue(key in config)
@@ -76,14 +71,12 @@ class TestStage(unittest.TestCase):
        connection = APIconnection(host="localhost", port=5000, api_ver="v1")
        state = connection.get_state()

        self.assertTrue('stage' in state)
        self.assertTrue("stage" in state)

        expected_keys = [
            'position',
        ]
        expected_keys = ["position"]

        for key in expected_keys:
            self.assertTrue(key in state['stage'])
            self.assertTrue(key in state["stage"])

    def test_stage_movement(self):
        connection = APIconnection(host="localhost", port=5000, api_ver="v1")
@@ -91,16 +84,16 @@ class TestStage(unittest.TestCase):
        move_distance = 500
        for axis in range(3):
            for direction in [1, -1]:
                pos_i_dict = connection.get_state()['stage']['position']
                pos_i = [pos_i_dict['x'], pos_i_dict['y'], pos_i_dict['z']]
                pos_i_dict = connection.get_state()["stage"]["position"]
                pos_i = [pos_i_dict["x"], pos_i_dict["y"], pos_i_dict["z"]]

                move = [0, 0, 0]
                move[axis] = move_distance * direction

                connection.move_by(*move)

                pos_f_dict = connection.get_state()['stage']['position']
                pos_f = [pos_f_dict['x'], pos_f_dict['y'], pos_f_dict['z']]
                pos_f_dict = connection.get_state()["stage"]["position"]
                pos_f = [pos_f_dict["x"], pos_f_dict["y"], pos_f_dict["z"]]

                diff = np.subtract(pos_f, pos_i)
                logging.debug("{} > {}".format(pos_i, pos_f))
@@ -108,7 +101,7 @@ class TestStage(unittest.TestCase):
                self.assertTrue(np.array_equal(diff, move))


if __name__ == '__main__':
if __name__ == "__main__":

    suites = [
        unittest.TestLoader().loadTestsFromTestCase(TestCapture),
+11 −31
Original line number Diff line number Diff line
@@ -12,11 +12,11 @@ import unittest

import logging
import sys

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)


class TestCaptureMethods(unittest.TestCase):

    def test_still_capture(self):
        """Tests capturing still images to a BytesIO stream."""
        global camera
@@ -30,11 +30,7 @@ class TestCaptureMethods(unittest.TestCase):
                # Capture to a context (auto-deletes files when done)
                with camera.new_image(write_to_file=False) as output:

                    camera.capture(
                        output, 
                        use_video_port=use_video_port, 
                        resize=resize
                    ) 
                    camera.capture(output, use_video_port=use_video_port, resize=resize)

                    # Ensure file deletion fails and returns False
                    self.assertFalse(output.delete_file())
@@ -43,14 +39,8 @@ class TestCaptureMethods(unittest.TestCase):

                    # BEFORE DELETE: Ensure StreamObject 'stream' has
                    # a valid BytesIO object and byte string
                    self.assertTrue(isinstance(
                        output.data,
                        io.IOBase
                        ))
                    self.assertTrue(isinstance(
                        output.binary,
                        (bytes, bytearray)
                        ))
                    self.assertTrue(isinstance(output.data, io.IOBase))
                    self.assertTrue(isinstance(output.binary, (bytes, bytearray)))

                    # Save capture to file
                    output.save_file()
@@ -65,10 +55,7 @@ class TestCaptureMethods(unittest.TestCase):
                    # AFTER DELETE: Ensure StreamObject 'stream' has
                    # a valid BytesIO object and byte string
                    self.assertTrue(isinstance(output.data, io.IOBase))
                    self.assertTrue(isinstance(
                        output.binary,
                        (bytes, bytearray)
                        ))
                    self.assertTrue(isinstance(output.binary, (bytes, bytearray)))

                    # Create a PIL image from stream
                    image = Image.open(output.data)
@@ -102,7 +89,8 @@ class TestCaptureMethods(unittest.TestCase):
                output = camera.capture(
                    camera.new_image(write_to_file=True),
                    use_video_port=use_video_port,
                    resize=resize)
                    resize=resize,
                )

                # Check file got saved
                self.assertTrue(os.path.isfile(output.file))
@@ -122,7 +110,6 @@ class TestCaptureMethods(unittest.TestCase):


class TestUnencodedMethods(unittest.TestCase):

    def test_yuv_array(self):
        """Tests capturing unencoded YUV data to a Numpy array."""
        global camera
@@ -136,9 +123,7 @@ class TestUnencodedMethods(unittest.TestCase):
                camera.wait_for_camera()

                # Capture RGB array
                yuv = camera.yuv(
                    use_video_port=use_video_port,
                    resize=resize)
                yuv = camera.yuv(use_video_port=use_video_port, resize=resize)

                # Ensure capture output is a valid numpy array
                self.assertTrue(isinstance(yuv, np.ndarray))
@@ -168,9 +153,7 @@ class TestUnencodedMethods(unittest.TestCase):
                camera.wait_for_camera()

                # Capture RGB array
                rgb = camera.array(
                    use_video_port=use_video_port,
                    resize=resize)
                rgb = camera.array(use_video_port=use_video_port, resize=resize)

                # Ensure capture output is a valid numpy array
                self.assertTrue(isinstance(rgb, np.ndarray))
@@ -189,7 +172,6 @@ class TestUnencodedMethods(unittest.TestCase):


class TestRecordMethods(unittest.TestCase):

    def test_video_record(self):
        """Tests recording videos to BytesIO stream, and to file on disk."""
        global camera
@@ -201,9 +183,7 @@ class TestRecordMethods(unittest.TestCase):
            # Wait for camera
            camera.wait_for_camera()

            with camera.new_video(
                write_to_file=write_to_file
            ) as output:
            with camera.new_video(write_to_file=write_to_file) as output:

                # Start recording
                camera.start_recording(output)
@@ -278,7 +258,7 @@ class TestThreadStarting(unittest.TestCase):
        self.assertIsInstance(camera.stream, io.IOBase)


if __name__ == '__main__':
if __name__ == "__main__":
    with PiCameraStreamer() as camera:

        suites = [
Loading