From 09db2856ccdd218346b98304c61fc3b8c2a208ba Mon Sep 17 00:00:00 2001 From: simleek Date: Sun, 10 Nov 2019 10:18:32 -0700 Subject: [PATCH] Updated docs to satisfy tox --- displayarray/__main__.py | 2 + displayarray/{uid.py => _uid.py} | 2 + displayarray/{util.py => _util.py} | 2 + displayarray/callbacks.py | 4 +- displayarray/effects/__init__.py | 1 + displayarray/effects/crop.py | 25 +++++- displayarray/effects/lens.py | 90 ++++++++++++++++++-- displayarray/effects/select_channels.py | 22 ++++- displayarray/frame/frame_publishing.py | 7 +- displayarray/frame/frame_updater.py | 10 ++- displayarray/frame/get_frame_ids.py | 2 + displayarray/frame/np_to_opencv.py | 3 + displayarray/frame/subscriber_dictionary.py | 2 + displayarray/input.py | 31 +++++-- displayarray/window/subscriber_windows.py | 8 +- displayarray/window/window_commands.py | 2 + docs/.doctrees/environment.pickle | Bin 77094 -> 77094 bytes tox.ini | 3 + 18 files changed, 191 insertions(+), 25 deletions(-) rename displayarray/{uid.py => _uid.py} (93%) rename displayarray/{util.py => _util.py} (90%) diff --git a/displayarray/__main__.py b/displayarray/__main__.py index 4292906..9938d50 100644 --- a/displayarray/__main__.py +++ b/displayarray/__main__.py @@ -1,5 +1,6 @@ """ DisplayArray. + Display NumPy arrays. Usage: @@ -25,6 +26,7 @@ import asyncio def main(argv=None): + """Process command line arguments.""" arguments = docopt(__doc__, argv=argv) if arguments["--version"]: from displayarray import __version__ diff --git a/displayarray/uid.py b/displayarray/_uid.py similarity index 93% rename from displayarray/uid.py rename to displayarray/_uid.py index f64b6df..742503c 100644 --- a/displayarray/uid.py +++ b/displayarray/_uid.py @@ -1,3 +1,5 @@ +"""Generate unique IDs for videos.""" + from collections.abc import Hashable diff --git a/displayarray/util.py b/displayarray/_util.py similarity index 90% rename from displayarray/util.py rename to displayarray/_util.py index cb4eff6..27e37ed 100644 --- a/displayarray/util.py +++ b/displayarray/_util.py @@ -1,3 +1,5 @@ +"""Functions needed to deal with OpenCV.""" + import weakref diff --git a/displayarray/callbacks.py b/displayarray/callbacks.py index de728ca..0e2586c 100644 --- a/displayarray/callbacks.py +++ b/displayarray/callbacks.py @@ -1,3 +1,5 @@ +"""Standard callbacks to use on incoming frames.""" + from displayarray.window import window_commands import numpy as np @@ -35,7 +37,7 @@ class function_display_callback(object): # NOSONAR """ def __init__(self, display_function, finish_function=None): - + """Run display_function on frames.""" self.looping = True self.first_call = True diff --git a/displayarray/effects/__init__.py b/displayarray/effects/__init__.py index e69de29..2885141 100644 --- a/displayarray/effects/__init__.py +++ b/displayarray/effects/__init__.py @@ -0,0 +1 @@ +"""Effects to run on numpy arrays to make data clearer.""" diff --git a/displayarray/effects/crop.py b/displayarray/effects/crop.py index d861075..ae18e32 100644 --- a/displayarray/effects/crop.py +++ b/displayarray/effects/crop.py @@ -1,11 +1,26 @@ +"""Crop any n-dimensional array.""" + import numpy as np -from ..input import mouse_loop +from displayarray.input import mouse_loop class Crop(object): - """A callback class that will return the input array cropped to the output size. N-dimensional.""" + """ + A callback class that will return the input array cropped to the output size. N-dimensional. + + >>> crop_it = Crop((2,2,2)) + >>> arr = np.ones((4,4,4)) + >>> crop_it(arr) + array([[[1., 1.], + [1., 1.]], + + [[1., 1.], + [1., 1.]]]) + + """ def __init__(self, output_size=(64, 64, 3), center=None): + """Create the cropper.""" self._output_size = None self._center = None self.odd_center = None @@ -17,20 +32,24 @@ class Crop(object): @property def output_size(self): + """Get the output size after cropping.""" return self._output_size @output_size.setter def output_size(self, set): + """Set what the output size will be after cropping.""" self._output_size = set if self._output_size is not None: self._output_size = np.asarray(set) @property def center(self): + """Get center crop position on the input.""" return self._center @center.setter def center(self, set): + """Set center crop position on the input.""" self._center = set if self._center is not None: self._center = np.asarray(set) @@ -87,7 +106,7 @@ class Crop(object): return out_array.astype(arr.dtype) def enable_mouse_control(self): - """Move the mouse to move where the crop is from on the original image""" + """Move the mouse to move where the crop is from on the original image.""" @mouse_loop def m_loop(me): diff --git a/displayarray/effects/lens.py b/displayarray/effects/lens.py index 1038c81..5dc8278 100644 --- a/displayarray/effects/lens.py +++ b/displayarray/effects/lens.py @@ -1,9 +1,11 @@ +"""Create lens effects. Currently only 2D+color arrays are supported.""" + import numpy as np -from ..input import mouse_loop +from displayarray.input import mouse_loop import cv2 -class ControllableLens(object): +class _ControllableLens(object): def __init__(self, use_bleed=False, zoom=1, center=None): self.center = center self.zoom = zoom @@ -22,10 +24,66 @@ class ControllableLens(object): ) / 2 -class Barrel(ControllableLens): - def __init__( - self, use_bleed=False, barrel_power=1, pincushion_power=1, zoom=1, center=None - ): +class Barrel(_ControllableLens): + """ + Create a barrel distortion. + + >>> distort_it = Barrel(zoom=1, barrel_power=1.5) + >>> x = np.linspace(0, 1, 4) + >>> y = np.linspace(0, 1, 4) + >>> c = np.linspace(0, 1, 2) + >>> arrx, arry, arrc = np.meshgrid(x,y,c) + >>> arrx + array([[[0. , 0. ], + [0.33333333, 0.33333333], + [0.66666667, 0.66666667], + [1. , 1. ]], + + [[0. , 0. ], + [0.33333333, 0.33333333], + [0.66666667, 0.66666667], + [1. , 1. ]], + + [[0. , 0. ], + [0.33333333, 0.33333333], + [0.66666667, 0.66666667], + [1. , 1. ]], + + [[0. , 0. ], + [0.33333333, 0.33333333], + [0.66666667, 0.66666667], + [1. , 1. ]]]) + + >>> distort_it(arrx) + array([[[0.33333333, 0.33333333], + [0.33333333, 0.33333333], + [0.66666667, 0.66666667], + [0.66666667, 0.66666667]], + + [[0.33333333, 0.33333333], + [0.33333333, 0.33333333], + [0.66666667, 0.66666667], + [0.66666667, 0.66666667]], + + [[0.33333333, 0.33333333], + [0.33333333, 0.33333333], + [0.66666667, 0.66666667], + [0.66666667, 0.66666667]], + + [[0.33333333, 0.33333333], + [0.33333333, 0.33333333], + [0.66666667, 0.66666667], + [0.66666667, 0.66666667]]]) + + :param zoom: How far to zoom into the array + :param barrel_power: How much to distort. + 1 = no distortion. >1 increases size of center. 0>> from examples.videos import test_video @@ -179,6 +183,7 @@ async def read_updates_zero_mq( blocking: bool = False, end_callback: Callable[[Any], bool] = lambda x: False, ): + """Read updated frames from ZeroMQ.""" import zmq ctx = zmq.Context() @@ -216,6 +221,7 @@ async def read_updates_ros( poll_rate_hz=None, end_callback: Callable[[Any], bool] = lambda x: False, ): + """Read updated frames from ROS.""" import rospy from rospy.numpy_msg import numpy_msg from rospy.client import _WFM diff --git a/displayarray/frame/get_frame_ids.py b/displayarray/frame/get_frame_ids.py index ac95b18..284aa7f 100644 --- a/displayarray/frame/get_frame_ids.py +++ b/displayarray/frame/get_frame_ids.py @@ -1,3 +1,5 @@ +"""Get camera IDs.""" + import cv2 from typing import List diff --git a/displayarray/frame/np_to_opencv.py b/displayarray/frame/np_to_opencv.py index 3366aed..a9a482c 100644 --- a/displayarray/frame/np_to_opencv.py +++ b/displayarray/frame/np_to_opencv.py @@ -1,3 +1,5 @@ +"""Allow OpenCV to handle numpy arrays as input.""" + import numpy as np import cv2 @@ -6,6 +8,7 @@ class NpCam(object): """Add OpenCV camera controls to a numpy array.""" def __init__(self, img): + """Create a fake camera for OpenCV based on the initial array.""" assert isinstance(img, np.ndarray) self.__img = img self.__is_opened = True diff --git a/displayarray/frame/subscriber_dictionary.py b/displayarray/frame/subscriber_dictionary.py index 174bb3a..1955579 100644 --- a/displayarray/frame/subscriber_dictionary.py +++ b/displayarray/frame/subscriber_dictionary.py @@ -9,6 +9,7 @@ class CamHandler(object): """A camera handler instance that will send commands to and receive data from a camera.""" def __init__(self, name, sub): + """Create the cam handler.""" self.name = name self.cmd = None self.sub: VariableSub = sub @@ -20,6 +21,7 @@ class Cam(object): """A camera publisher instance that will send frames, status, and commands out.""" def __init__(self, name): + """Create the cam.""" self.name = name self.cmd = None self.frame_pub = VariablePub() diff --git a/displayarray/input.py b/displayarray/input.py index c287bec..ea814cb 100644 --- a/displayarray/input.py +++ b/displayarray/input.py @@ -1,3 +1,5 @@ +"""Decorators for creating input loops that OpenCV handles.""" + from displayarray.window import window_commands import threading import time @@ -9,6 +11,7 @@ class MouseEvent(object): """Holds all the OpenCV mouse event information.""" def __init__(self, event, x, y, flags, param): + """Create an OpenCV mouse event.""" self.event = event self.x = x self.y = y @@ -62,10 +65,19 @@ class _mouse_loop_thread(object): # NOSONAR class mouse_loop(object): # NOSONAR - """Run a function on mouse information that is received by the window, continuously in a new thread.""" + """ + Run a function on mouse information that is received by the window, continuously in a new thread. - def __init__(self, f, run_when_no_events=False): - self.t = threading.Thread(target=_mouse_loop_thread(f, run_when_no_events)) + >>> @mouse_loop + ... def fun(mouse_event): + ... print("x:{}, y:{}".format(mouse_event.x, mouse_event.y)) + """ + + def __init__(self, f): + """Start a new mouse thread for the decorated function.""" + self.t = threading.Thread( + target=_mouse_loop_thread(f, run_when_no_events=False) + ) self.t.start() def __call__(self, *args, **kwargs): @@ -111,10 +123,17 @@ class _key_loop_thread(object): # NOSONAR class key_loop(object): # NOSONAR - """Run a function on mouse information that is received by the window, continuously in a new thread.""" + """ + Run a function on mouse information that is received by the window, continuously in a new thread. - def __init__(self, f: Callable[[str], None], run_when_no_events=False): - self.t = threading.Thread(target=_key_loop_thread(f, run_when_no_events)) + >>> @key_loop + ... def fun(key): + ... print("key pressed:{}".format(key)) + """ + + def __init__(self, f: Callable[[str], None]): + """Start a new key thread for the decorated function.""" + self.t = threading.Thread(target=_key_loop_thread(f, run_when_no_events=False)) self.t.start() def __call__(self, *args, **kwargs): diff --git a/displayarray/window/subscriber_windows.py b/displayarray/window/subscriber_windows.py index 97c9b4c..d7b6f7a 100644 --- a/displayarray/window/subscriber_windows.py +++ b/displayarray/window/subscriber_windows.py @@ -1,3 +1,5 @@ +"""OpenCV windows that will display the arrays.""" + import warnings from threading import Thread from typing import List, Union, Callable, Any, Dict, Iterable, Optional @@ -7,13 +9,13 @@ import numpy as np from localpubsub import NoData from displayarray.callbacks import global_cv_display_callback -from displayarray.uid import uid_for_source +from displayarray._uid import uid_for_source from displayarray.frame import subscriber_dictionary from displayarray.frame.frame_updater import FrameCallable from displayarray.frame.frame_updater import FrameUpdater from displayarray.input import MouseEvent from displayarray.window import window_commands -from displayarray.util import WeakMethod +from displayarray._util import WeakMethod from displayarray.effects.select_channels import SelectChannels @@ -29,6 +31,7 @@ class SubscriberWindows(object): video_sources: Iterable[Union[str, int]] = (0,), callbacks: Optional[List[Callable[[np.ndarray], Any]]] = None, ): + """Create the array displaying window.""" self.source_names: List[Union[str, int]] = [] self.close_threads: Optional[List[Thread]] = [] self.frames: List[np.ndarray] = [] @@ -52,6 +55,7 @@ class SubscriberWindows(object): return not self.exited def block(self): + """Update the window continuously while blocking the outer program.""" self.loop() for ct in self.close_threads: ct.join() diff --git a/displayarray/window/window_commands.py b/displayarray/window/window_commands.py index f2015d1..f30a59c 100644 --- a/displayarray/window/window_commands.py +++ b/displayarray/window/window_commands.py @@ -1,3 +1,5 @@ +"""Commands to control the array displaying windows.""" + from localpubsub import VariablePub, VariableSub key_pub = VariablePub() diff --git a/docs/.doctrees/environment.pickle b/docs/.doctrees/environment.pickle index 98a174723c1980eea50b59c363d00b0f51510d39..69f0ee333a07c3ed58f4b0ed9cec505d27389872 100644 GIT binary patch delta 1936 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 diff --git a/tox.ini b/tox.ini index 2eb68c2..bf25cbd 100644 --- a/tox.ini +++ b/tox.ini @@ -39,6 +39,9 @@ whitelist_externals = poetry description = enforce code style commands = poetry run black displayarray --check +[pydocstyle] +ignore = D105, D212, D203, D202 + [testenv:pydocstyle] whitelist_externals = poetry description = enforce documentation style