vispy 0.15.0__cp312-cp312-macosx_10_13_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of vispy might be problematic. Click here for more details.
- vispy/__init__.py +33 -0
- vispy/app/__init__.py +15 -0
- vispy/app/_default_app.py +76 -0
- vispy/app/_detect_eventloop.py +148 -0
- vispy/app/application.py +263 -0
- vispy/app/backends/__init__.py +52 -0
- vispy/app/backends/_egl.py +264 -0
- vispy/app/backends/_glfw.py +513 -0
- vispy/app/backends/_jupyter_rfb.py +278 -0
- vispy/app/backends/_offscreen_util.py +121 -0
- vispy/app/backends/_osmesa.py +235 -0
- vispy/app/backends/_pyglet.py +451 -0
- vispy/app/backends/_pyqt4.py +36 -0
- vispy/app/backends/_pyqt5.py +36 -0
- vispy/app/backends/_pyqt6.py +40 -0
- vispy/app/backends/_pyside.py +37 -0
- vispy/app/backends/_pyside2.py +52 -0
- vispy/app/backends/_pyside6.py +53 -0
- vispy/app/backends/_qt.py +1003 -0
- vispy/app/backends/_sdl2.py +444 -0
- vispy/app/backends/_template.py +244 -0
- vispy/app/backends/_test.py +8 -0
- vispy/app/backends/_tk.py +800 -0
- vispy/app/backends/_wx.py +476 -0
- vispy/app/backends/tests/__init__.py +0 -0
- vispy/app/backends/tests/test_offscreen_util.py +52 -0
- vispy/app/backends/tests/test_rfb.py +77 -0
- vispy/app/base.py +294 -0
- vispy/app/canvas.py +828 -0
- vispy/app/qt.py +92 -0
- vispy/app/tests/__init__.py +0 -0
- vispy/app/tests/qt-designer.ui +58 -0
- vispy/app/tests/test_app.py +442 -0
- vispy/app/tests/test_backends.py +164 -0
- vispy/app/tests/test_canvas.py +122 -0
- vispy/app/tests/test_context.py +92 -0
- vispy/app/tests/test_qt.py +47 -0
- vispy/app/tests/test_simultaneous.py +134 -0
- vispy/app/timer.py +174 -0
- vispy/color/__init__.py +17 -0
- vispy/color/_color_dict.py +193 -0
- vispy/color/color_array.py +447 -0
- vispy/color/color_space.py +181 -0
- vispy/color/colormap.py +1213 -0
- vispy/color/tests/__init__.py +0 -0
- vispy/color/tests/test_color.py +378 -0
- vispy/conftest.py +12 -0
- vispy/ext/__init__.py +0 -0
- vispy/ext/cocoapy.py +1522 -0
- vispy/ext/cubehelix.py +138 -0
- vispy/ext/egl.py +375 -0
- vispy/ext/fontconfig.py +118 -0
- vispy/ext/gdi32plus.py +206 -0
- vispy/ext/osmesa.py +105 -0
- vispy/geometry/__init__.py +23 -0
- vispy/geometry/_triangulation_debugger.py +171 -0
- vispy/geometry/calculations.py +162 -0
- vispy/geometry/curves.py +399 -0
- vispy/geometry/generation.py +643 -0
- vispy/geometry/isocurve.py +175 -0
- vispy/geometry/isosurface.py +465 -0
- vispy/geometry/meshdata.py +700 -0
- vispy/geometry/normals.py +78 -0
- vispy/geometry/parametric.py +56 -0
- vispy/geometry/polygon.py +137 -0
- vispy/geometry/rect.py +210 -0
- vispy/geometry/tests/__init__.py +0 -0
- vispy/geometry/tests/test_calculations.py +23 -0
- vispy/geometry/tests/test_generation.py +56 -0
- vispy/geometry/tests/test_meshdata.py +106 -0
- vispy/geometry/tests/test_triangulation.py +594 -0
- vispy/geometry/torusknot.py +142 -0
- vispy/geometry/triangulation.py +876 -0
- vispy/gloo/__init__.py +56 -0
- vispy/gloo/buffer.py +505 -0
- vispy/gloo/context.py +272 -0
- vispy/gloo/framebuffer.py +257 -0
- vispy/gloo/gl/__init__.py +234 -0
- vispy/gloo/gl/_constants.py +332 -0
- vispy/gloo/gl/_es2.py +986 -0
- vispy/gloo/gl/_gl2.py +1365 -0
- vispy/gloo/gl/_proxy.py +499 -0
- vispy/gloo/gl/_pyopengl2.py +362 -0
- vispy/gloo/gl/dummy.py +24 -0
- vispy/gloo/gl/es2.py +62 -0
- vispy/gloo/gl/gl2.py +98 -0
- vispy/gloo/gl/glplus.py +168 -0
- vispy/gloo/gl/pyopengl2.py +97 -0
- vispy/gloo/gl/tests/__init__.py +0 -0
- vispy/gloo/gl/tests/test_basics.py +282 -0
- vispy/gloo/gl/tests/test_functionality.py +568 -0
- vispy/gloo/gl/tests/test_names.py +246 -0
- vispy/gloo/gl/tests/test_use.py +71 -0
- vispy/gloo/glir.py +1824 -0
- vispy/gloo/globject.py +101 -0
- vispy/gloo/preprocessor.py +67 -0
- vispy/gloo/program.py +543 -0
- vispy/gloo/tests/__init__.py +0 -0
- vispy/gloo/tests/test_buffer.py +558 -0
- vispy/gloo/tests/test_context.py +119 -0
- vispy/gloo/tests/test_framebuffer.py +195 -0
- vispy/gloo/tests/test_glir.py +307 -0
- vispy/gloo/tests/test_globject.py +35 -0
- vispy/gloo/tests/test_program.py +302 -0
- vispy/gloo/tests/test_texture.py +732 -0
- vispy/gloo/tests/test_use_gloo.py +187 -0
- vispy/gloo/tests/test_util.py +60 -0
- vispy/gloo/tests/test_wrappers.py +261 -0
- vispy/gloo/texture.py +1046 -0
- vispy/gloo/util.py +129 -0
- vispy/gloo/wrappers.py +762 -0
- vispy/glsl/__init__.py +42 -0
- vispy/glsl/antialias/antialias.glsl +7 -0
- vispy/glsl/antialias/cap-butt.glsl +31 -0
- vispy/glsl/antialias/cap-round.glsl +29 -0
- vispy/glsl/antialias/cap-square.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
- vispy/glsl/antialias/cap.glsl +67 -0
- vispy/glsl/antialias/caps.glsl +67 -0
- vispy/glsl/antialias/filled.glsl +50 -0
- vispy/glsl/antialias/outline.glsl +40 -0
- vispy/glsl/antialias/stroke.glsl +43 -0
- vispy/glsl/arrowheads/angle.glsl +99 -0
- vispy/glsl/arrowheads/arrowheads.frag +60 -0
- vispy/glsl/arrowheads/arrowheads.glsl +12 -0
- vispy/glsl/arrowheads/arrowheads.vert +83 -0
- vispy/glsl/arrowheads/curved.glsl +48 -0
- vispy/glsl/arrowheads/inhibitor.glsl +26 -0
- vispy/glsl/arrowheads/stealth.glsl +46 -0
- vispy/glsl/arrowheads/triangle.glsl +97 -0
- vispy/glsl/arrowheads/util.glsl +13 -0
- vispy/glsl/arrows/angle-30.glsl +12 -0
- vispy/glsl/arrows/angle-60.glsl +12 -0
- vispy/glsl/arrows/angle-90.glsl +12 -0
- vispy/glsl/arrows/arrow.frag +39 -0
- vispy/glsl/arrows/arrow.vert +49 -0
- vispy/glsl/arrows/arrows.glsl +17 -0
- vispy/glsl/arrows/common.glsl +187 -0
- vispy/glsl/arrows/curved.glsl +63 -0
- vispy/glsl/arrows/stealth.glsl +50 -0
- vispy/glsl/arrows/triangle-30.glsl +12 -0
- vispy/glsl/arrows/triangle-60.glsl +12 -0
- vispy/glsl/arrows/triangle-90.glsl +12 -0
- vispy/glsl/arrows/util.glsl +98 -0
- vispy/glsl/build_spatial_filters.py +660 -0
- vispy/glsl/collections/agg-fast-path.frag +20 -0
- vispy/glsl/collections/agg-fast-path.vert +78 -0
- vispy/glsl/collections/agg-glyph.frag +60 -0
- vispy/glsl/collections/agg-glyph.vert +33 -0
- vispy/glsl/collections/agg-marker.frag +35 -0
- vispy/glsl/collections/agg-marker.vert +48 -0
- vispy/glsl/collections/agg-path.frag +55 -0
- vispy/glsl/collections/agg-path.vert +166 -0
- vispy/glsl/collections/agg-point.frag +21 -0
- vispy/glsl/collections/agg-point.vert +35 -0
- vispy/glsl/collections/agg-segment.frag +32 -0
- vispy/glsl/collections/agg-segment.vert +75 -0
- vispy/glsl/collections/marker.frag +38 -0
- vispy/glsl/collections/marker.vert +48 -0
- vispy/glsl/collections/raw-path.frag +15 -0
- vispy/glsl/collections/raw-path.vert +24 -0
- vispy/glsl/collections/raw-point.frag +14 -0
- vispy/glsl/collections/raw-point.vert +31 -0
- vispy/glsl/collections/raw-segment.frag +18 -0
- vispy/glsl/collections/raw-segment.vert +26 -0
- vispy/glsl/collections/raw-triangle.frag +13 -0
- vispy/glsl/collections/raw-triangle.vert +26 -0
- vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
- vispy/glsl/collections/sdf-glyph.frag +80 -0
- vispy/glsl/collections/sdf-glyph.vert +59 -0
- vispy/glsl/collections/tick-labels.vert +71 -0
- vispy/glsl/colormaps/autumn.glsl +20 -0
- vispy/glsl/colormaps/blues.glsl +20 -0
- vispy/glsl/colormaps/color-space.glsl +17 -0
- vispy/glsl/colormaps/colormaps.glsl +24 -0
- vispy/glsl/colormaps/cool.glsl +20 -0
- vispy/glsl/colormaps/fire.glsl +21 -0
- vispy/glsl/colormaps/gray.glsl +20 -0
- vispy/glsl/colormaps/greens.glsl +20 -0
- vispy/glsl/colormaps/hot.glsl +22 -0
- vispy/glsl/colormaps/ice.glsl +20 -0
- vispy/glsl/colormaps/icefire.glsl +23 -0
- vispy/glsl/colormaps/parse.py +40 -0
- vispy/glsl/colormaps/reds.glsl +20 -0
- vispy/glsl/colormaps/spring.glsl +20 -0
- vispy/glsl/colormaps/summer.glsl +20 -0
- vispy/glsl/colormaps/user.glsl +22 -0
- vispy/glsl/colormaps/util.glsl +41 -0
- vispy/glsl/colormaps/wheel.glsl +21 -0
- vispy/glsl/colormaps/winter.glsl +20 -0
- vispy/glsl/lines/agg.frag +320 -0
- vispy/glsl/lines/agg.vert +241 -0
- vispy/glsl/markers/arrow.glsl +12 -0
- vispy/glsl/markers/asterisk.glsl +16 -0
- vispy/glsl/markers/chevron.glsl +14 -0
- vispy/glsl/markers/clover.glsl +20 -0
- vispy/glsl/markers/club.glsl +31 -0
- vispy/glsl/markers/cross.glsl +17 -0
- vispy/glsl/markers/diamond.glsl +12 -0
- vispy/glsl/markers/disc.glsl +9 -0
- vispy/glsl/markers/ellipse.glsl +67 -0
- vispy/glsl/markers/hbar.glsl +9 -0
- vispy/glsl/markers/heart.glsl +15 -0
- vispy/glsl/markers/infinity.glsl +15 -0
- vispy/glsl/markers/marker-sdf.frag +74 -0
- vispy/glsl/markers/marker-sdf.vert +41 -0
- vispy/glsl/markers/marker.frag +36 -0
- vispy/glsl/markers/marker.vert +46 -0
- vispy/glsl/markers/markers.glsl +24 -0
- vispy/glsl/markers/pin.glsl +18 -0
- vispy/glsl/markers/ring.glsl +11 -0
- vispy/glsl/markers/spade.glsl +28 -0
- vispy/glsl/markers/square.glsl +10 -0
- vispy/glsl/markers/tag.glsl +11 -0
- vispy/glsl/markers/triangle.glsl +14 -0
- vispy/glsl/markers/vbar.glsl +9 -0
- vispy/glsl/math/circle-through-2-points.glsl +30 -0
- vispy/glsl/math/constants.glsl +48 -0
- vispy/glsl/math/double.glsl +114 -0
- vispy/glsl/math/functions.glsl +20 -0
- vispy/glsl/math/point-to-line-distance.glsl +31 -0
- vispy/glsl/math/point-to-line-projection.glsl +29 -0
- vispy/glsl/math/signed-line-distance.glsl +27 -0
- vispy/glsl/math/signed-segment-distance.glsl +30 -0
- vispy/glsl/misc/regular-grid.frag +244 -0
- vispy/glsl/misc/spatial-filters.frag +1407 -0
- vispy/glsl/misc/viewport-NDC.glsl +20 -0
- vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
- vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
- vispy/glsl/transforms/hammer.glsl +44 -0
- vispy/glsl/transforms/identity.glsl +6 -0
- vispy/glsl/transforms/identity_forward.glsl +23 -0
- vispy/glsl/transforms/identity_inverse.glsl +23 -0
- vispy/glsl/transforms/linear-scale.glsl +127 -0
- vispy/glsl/transforms/log-scale.glsl +126 -0
- vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
- vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
- vispy/glsl/transforms/panzoom.glsl +10 -0
- vispy/glsl/transforms/polar.glsl +41 -0
- vispy/glsl/transforms/position.glsl +44 -0
- vispy/glsl/transforms/power-scale.glsl +139 -0
- vispy/glsl/transforms/projection.glsl +7 -0
- vispy/glsl/transforms/pvm.glsl +13 -0
- vispy/glsl/transforms/rotate.glsl +45 -0
- vispy/glsl/transforms/trackball.glsl +15 -0
- vispy/glsl/transforms/translate.glsl +35 -0
- vispy/glsl/transforms/transverse_mercator.glsl +38 -0
- vispy/glsl/transforms/viewport-clipping.glsl +14 -0
- vispy/glsl/transforms/viewport-transform.glsl +16 -0
- vispy/glsl/transforms/viewport.glsl +50 -0
- vispy/glsl/transforms/x.glsl +24 -0
- vispy/glsl/transforms/y.glsl +19 -0
- vispy/glsl/transforms/z.glsl +14 -0
- vispy/io/__init__.py +20 -0
- vispy/io/_data/spatial-filters.npy +0 -0
- vispy/io/datasets.py +94 -0
- vispy/io/image.py +231 -0
- vispy/io/mesh.py +122 -0
- vispy/io/stl.py +167 -0
- vispy/io/tests/__init__.py +0 -0
- vispy/io/tests/test_image.py +47 -0
- vispy/io/tests/test_io.py +121 -0
- vispy/io/wavefront.py +350 -0
- vispy/plot/__init__.py +36 -0
- vispy/plot/fig.py +58 -0
- vispy/plot/plotwidget.py +522 -0
- vispy/plot/tests/__init__.py +0 -0
- vispy/plot/tests/test_plot.py +46 -0
- vispy/scene/__init__.py +43 -0
- vispy/scene/cameras/__init__.py +27 -0
- vispy/scene/cameras/_base.py +38 -0
- vispy/scene/cameras/arcball.py +105 -0
- vispy/scene/cameras/base_camera.py +551 -0
- vispy/scene/cameras/fly.py +474 -0
- vispy/scene/cameras/magnify.py +163 -0
- vispy/scene/cameras/panzoom.py +311 -0
- vispy/scene/cameras/perspective.py +338 -0
- vispy/scene/cameras/tests/__init__.py +0 -0
- vispy/scene/cameras/tests/test_cameras.py +27 -0
- vispy/scene/cameras/tests/test_link.py +53 -0
- vispy/scene/cameras/tests/test_perspective.py +122 -0
- vispy/scene/cameras/turntable.py +183 -0
- vispy/scene/canvas.py +639 -0
- vispy/scene/events.py +85 -0
- vispy/scene/node.py +644 -0
- vispy/scene/subscene.py +20 -0
- vispy/scene/tests/__init__.py +0 -0
- vispy/scene/tests/test_canvas.py +119 -0
- vispy/scene/tests/test_node.py +142 -0
- vispy/scene/tests/test_visuals.py +141 -0
- vispy/scene/visuals.py +276 -0
- vispy/scene/widgets/__init__.py +18 -0
- vispy/scene/widgets/anchor.py +25 -0
- vispy/scene/widgets/axis.py +88 -0
- vispy/scene/widgets/colorbar.py +176 -0
- vispy/scene/widgets/console.py +351 -0
- vispy/scene/widgets/grid.py +509 -0
- vispy/scene/widgets/label.py +50 -0
- vispy/scene/widgets/tests/__init__.py +0 -0
- vispy/scene/widgets/tests/test_colorbar.py +47 -0
- vispy/scene/widgets/viewbox.py +199 -0
- vispy/scene/widgets/widget.py +478 -0
- vispy/testing/__init__.py +51 -0
- vispy/testing/_runners.py +448 -0
- vispy/testing/_testing.py +416 -0
- vispy/testing/image_tester.py +494 -0
- vispy/testing/rendered_array_tester.py +85 -0
- vispy/testing/tests/__init__.py +0 -0
- vispy/testing/tests/test_testing.py +20 -0
- vispy/util/__init__.py +32 -0
- vispy/util/bunch.py +15 -0
- vispy/util/check_environment.py +57 -0
- vispy/util/config.py +490 -0
- vispy/util/dpi/__init__.py +19 -0
- vispy/util/dpi/_linux.py +69 -0
- vispy/util/dpi/_quartz.py +26 -0
- vispy/util/dpi/_win32.py +34 -0
- vispy/util/dpi/tests/__init__.py +0 -0
- vispy/util/dpi/tests/test_dpi.py +16 -0
- vispy/util/eq.py +41 -0
- vispy/util/event.py +774 -0
- vispy/util/fetching.py +276 -0
- vispy/util/filter.py +44 -0
- vispy/util/fonts/__init__.py +14 -0
- vispy/util/fonts/_freetype.py +73 -0
- vispy/util/fonts/_quartz.py +192 -0
- vispy/util/fonts/_triage.py +36 -0
- vispy/util/fonts/_vispy_fonts.py +20 -0
- vispy/util/fonts/_win32.py +105 -0
- vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
- vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
- vispy/util/fonts/tests/__init__.py +0 -0
- vispy/util/fonts/tests/test_font.py +45 -0
- vispy/util/fourier.py +69 -0
- vispy/util/frozen.py +25 -0
- vispy/util/gallery_scraper.py +268 -0
- vispy/util/keys.py +91 -0
- vispy/util/logs.py +358 -0
- vispy/util/osmesa_gl.py +17 -0
- vispy/util/profiler.py +135 -0
- vispy/util/ptime.py +16 -0
- vispy/util/quaternion.py +229 -0
- vispy/util/svg/__init__.py +18 -0
- vispy/util/svg/base.py +20 -0
- vispy/util/svg/color.py +219 -0
- vispy/util/svg/element.py +51 -0
- vispy/util/svg/geometry.py +478 -0
- vispy/util/svg/group.py +66 -0
- vispy/util/svg/length.py +81 -0
- vispy/util/svg/number.py +25 -0
- vispy/util/svg/path.py +332 -0
- vispy/util/svg/shapes.py +57 -0
- vispy/util/svg/style.py +59 -0
- vispy/util/svg/svg.py +40 -0
- vispy/util/svg/transform.py +223 -0
- vispy/util/svg/transformable.py +28 -0
- vispy/util/svg/viewport.py +73 -0
- vispy/util/tests/__init__.py +0 -0
- vispy/util/tests/test_config.py +58 -0
- vispy/util/tests/test_docstring_parameters.py +123 -0
- vispy/util/tests/test_emitter_group.py +262 -0
- vispy/util/tests/test_event_emitter.py +743 -0
- vispy/util/tests/test_fourier.py +35 -0
- vispy/util/tests/test_gallery_scraper.py +112 -0
- vispy/util/tests/test_import.py +127 -0
- vispy/util/tests/test_key.py +22 -0
- vispy/util/tests/test_logging.py +45 -0
- vispy/util/tests/test_run.py +14 -0
- vispy/util/tests/test_transforms.py +42 -0
- vispy/util/tests/test_vispy.py +48 -0
- vispy/util/transforms.py +201 -0
- vispy/util/wrappers.py +155 -0
- vispy/version.py +21 -0
- vispy/visuals/__init__.py +50 -0
- vispy/visuals/_scalable_textures.py +487 -0
- vispy/visuals/axis.py +678 -0
- vispy/visuals/border.py +208 -0
- vispy/visuals/box.py +79 -0
- vispy/visuals/collections/__init__.py +30 -0
- vispy/visuals/collections/agg_fast_path_collection.py +219 -0
- vispy/visuals/collections/agg_path_collection.py +197 -0
- vispy/visuals/collections/agg_point_collection.py +52 -0
- vispy/visuals/collections/agg_segment_collection.py +142 -0
- vispy/visuals/collections/array_list.py +401 -0
- vispy/visuals/collections/base_collection.py +482 -0
- vispy/visuals/collections/collection.py +253 -0
- vispy/visuals/collections/path_collection.py +23 -0
- vispy/visuals/collections/point_collection.py +19 -0
- vispy/visuals/collections/polygon_collection.py +25 -0
- vispy/visuals/collections/raw_path_collection.py +119 -0
- vispy/visuals/collections/raw_point_collection.py +113 -0
- vispy/visuals/collections/raw_polygon_collection.py +77 -0
- vispy/visuals/collections/raw_segment_collection.py +112 -0
- vispy/visuals/collections/raw_triangle_collection.py +78 -0
- vispy/visuals/collections/segment_collection.py +19 -0
- vispy/visuals/collections/triangle_collection.py +16 -0
- vispy/visuals/collections/util.py +168 -0
- vispy/visuals/colorbar.py +699 -0
- vispy/visuals/cube.py +41 -0
- vispy/visuals/ellipse.py +162 -0
- vispy/visuals/filters/__init__.py +10 -0
- vispy/visuals/filters/base_filter.py +242 -0
- vispy/visuals/filters/clipper.py +60 -0
- vispy/visuals/filters/clipping_planes.py +122 -0
- vispy/visuals/filters/color.py +181 -0
- vispy/visuals/filters/markers.py +28 -0
- vispy/visuals/filters/mesh.py +801 -0
- vispy/visuals/filters/picking.py +60 -0
- vispy/visuals/filters/tests/__init__.py +3 -0
- vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
- vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
- vispy/visuals/glsl/__init__.py +1 -0
- vispy/visuals/glsl/antialiasing.py +133 -0
- vispy/visuals/glsl/color.py +63 -0
- vispy/visuals/graphs/__init__.py +1 -0
- vispy/visuals/graphs/graph.py +240 -0
- vispy/visuals/graphs/layouts/__init__.py +55 -0
- vispy/visuals/graphs/layouts/circular.py +49 -0
- vispy/visuals/graphs/layouts/force_directed.py +211 -0
- vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
- vispy/visuals/graphs/layouts/random.py +52 -0
- vispy/visuals/graphs/tests/__init__.py +1 -0
- vispy/visuals/graphs/tests/test_layouts.py +139 -0
- vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
- vispy/visuals/graphs/util.py +120 -0
- vispy/visuals/gridlines.py +161 -0
- vispy/visuals/gridmesh.py +98 -0
- vispy/visuals/histogram.py +58 -0
- vispy/visuals/image.py +701 -0
- vispy/visuals/image_complex.py +130 -0
- vispy/visuals/infinite_line.py +199 -0
- vispy/visuals/instanced_mesh.py +152 -0
- vispy/visuals/isocurve.py +213 -0
- vispy/visuals/isoline.py +241 -0
- vispy/visuals/isosurface.py +113 -0
- vispy/visuals/line/__init__.py +6 -0
- vispy/visuals/line/arrow.py +289 -0
- vispy/visuals/line/dash_atlas.py +90 -0
- vispy/visuals/line/line.py +545 -0
- vispy/visuals/line_plot.py +135 -0
- vispy/visuals/linear_region.py +199 -0
- vispy/visuals/markers.py +819 -0
- vispy/visuals/mesh.py +373 -0
- vispy/visuals/mesh_normals.py +159 -0
- vispy/visuals/plane.py +54 -0
- vispy/visuals/polygon.py +145 -0
- vispy/visuals/rectangle.py +196 -0
- vispy/visuals/regular_polygon.py +56 -0
- vispy/visuals/scrolling_lines.py +197 -0
- vispy/visuals/shaders/__init__.py +17 -0
- vispy/visuals/shaders/compiler.py +206 -0
- vispy/visuals/shaders/expression.py +99 -0
- vispy/visuals/shaders/function.py +788 -0
- vispy/visuals/shaders/multiprogram.py +145 -0
- vispy/visuals/shaders/parsing.py +140 -0
- vispy/visuals/shaders/program.py +161 -0
- vispy/visuals/shaders/shader_object.py +162 -0
- vispy/visuals/shaders/tests/__init__.py +0 -0
- vispy/visuals/shaders/tests/test_function.py +486 -0
- vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
- vispy/visuals/shaders/tests/test_parsing.py +57 -0
- vispy/visuals/shaders/variable.py +272 -0
- vispy/visuals/spectrogram.py +169 -0
- vispy/visuals/sphere.py +80 -0
- vispy/visuals/surface_plot.py +192 -0
- vispy/visuals/tests/__init__.py +0 -0
- vispy/visuals/tests/test_arrows.py +109 -0
- vispy/visuals/tests/test_axis.py +120 -0
- vispy/visuals/tests/test_collections.py +15 -0
- vispy/visuals/tests/test_colorbar.py +179 -0
- vispy/visuals/tests/test_colormap.py +97 -0
- vispy/visuals/tests/test_ellipse.py +122 -0
- vispy/visuals/tests/test_gridlines.py +30 -0
- vispy/visuals/tests/test_histogram.py +24 -0
- vispy/visuals/tests/test_image.py +392 -0
- vispy/visuals/tests/test_image_complex.py +36 -0
- vispy/visuals/tests/test_infinite_line.py +53 -0
- vispy/visuals/tests/test_instanced_mesh.py +50 -0
- vispy/visuals/tests/test_isosurface.py +22 -0
- vispy/visuals/tests/test_linear_region.py +152 -0
- vispy/visuals/tests/test_markers.py +54 -0
- vispy/visuals/tests/test_mesh.py +261 -0
- vispy/visuals/tests/test_mesh_normals.py +218 -0
- vispy/visuals/tests/test_polygon.py +112 -0
- vispy/visuals/tests/test_rectangle.py +163 -0
- vispy/visuals/tests/test_regular_polygon.py +111 -0
- vispy/visuals/tests/test_scalable_textures.py +196 -0
- vispy/visuals/tests/test_sdf.py +73 -0
- vispy/visuals/tests/test_spectrogram.py +42 -0
- vispy/visuals/tests/test_surface_plot.py +57 -0
- vispy/visuals/tests/test_text.py +95 -0
- vispy/visuals/tests/test_volume.py +542 -0
- vispy/visuals/tests/test_windbarb.py +33 -0
- vispy/visuals/text/__init__.py +7 -0
- vispy/visuals/text/_sdf_cpu.cpython-312-darwin.so +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +112 -0
- vispy/visuals/text/_sdf_gpu.py +316 -0
- vispy/visuals/text/text.py +675 -0
- vispy/visuals/transforms/__init__.py +34 -0
- vispy/visuals/transforms/_util.py +191 -0
- vispy/visuals/transforms/base_transform.py +233 -0
- vispy/visuals/transforms/chain.py +300 -0
- vispy/visuals/transforms/interactive.py +98 -0
- vispy/visuals/transforms/linear.py +564 -0
- vispy/visuals/transforms/nonlinear.py +398 -0
- vispy/visuals/transforms/tests/__init__.py +0 -0
- vispy/visuals/transforms/tests/test_transforms.py +243 -0
- vispy/visuals/transforms/transform_system.py +339 -0
- vispy/visuals/tube.py +173 -0
- vispy/visuals/visual.py +923 -0
- vispy/visuals/volume.py +1366 -0
- vispy/visuals/windbarb.py +291 -0
- vispy/visuals/xyz_axis.py +34 -0
- vispy-0.15.0.dist-info/METADATA +243 -0
- vispy-0.15.0.dist-info/RECORD +521 -0
- vispy-0.15.0.dist-info/WHEEL +6 -0
- vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
- vispy-0.15.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
3
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
4
|
+
import unittest
|
|
5
|
+
import copy
|
|
6
|
+
import functools
|
|
7
|
+
|
|
8
|
+
from vispy.util.event import Event, EventEmitter
|
|
9
|
+
from vispy.testing import run_tests_if_main, assert_raises, assert_equal
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BasicEvent(Event):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TypedEvent(Event):
|
|
17
|
+
|
|
18
|
+
def __init__(self, **kwargs):
|
|
19
|
+
kwargs['type'] = 'typed_event'
|
|
20
|
+
Event.__init__(self, **kwargs)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TestEmitters(unittest.TestCase):
|
|
24
|
+
|
|
25
|
+
def test_emitter(self):
|
|
26
|
+
"""Emitter constructed with no arguments"""
|
|
27
|
+
em = EventEmitter()
|
|
28
|
+
|
|
29
|
+
# type must be specified when emitting since Event requires type
|
|
30
|
+
# argument and the emitter was constructed without it.
|
|
31
|
+
try:
|
|
32
|
+
em()
|
|
33
|
+
assert False, "Emitting event with no type should have failed."
|
|
34
|
+
except TypeError:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
# See that emitted event has all of the properties we expect
|
|
38
|
+
ev = self.try_emitter(em, type='test_event')
|
|
39
|
+
self.assert_result(
|
|
40
|
+
event=ev,
|
|
41
|
+
event_class=Event,
|
|
42
|
+
source=None,
|
|
43
|
+
type='test_event',
|
|
44
|
+
sources=[None])
|
|
45
|
+
|
|
46
|
+
def test_emitter_source(self):
|
|
47
|
+
"""Emitter constructed with source argument"""
|
|
48
|
+
em = EventEmitter(source=self)
|
|
49
|
+
ev = self.try_emitter(em, type='test_event')
|
|
50
|
+
self.assert_result(
|
|
51
|
+
event=ev,
|
|
52
|
+
event_class=Event,
|
|
53
|
+
source=self,
|
|
54
|
+
type='test_event',
|
|
55
|
+
sources=[self])
|
|
56
|
+
|
|
57
|
+
# overriding source should fail:
|
|
58
|
+
try:
|
|
59
|
+
ev = em(type='test_event', source=None)
|
|
60
|
+
assert False, "Should not be able to specify source when emitting"
|
|
61
|
+
except AttributeError:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
def test_emitter_type(self):
|
|
65
|
+
"""Emitter constructed with type argument"""
|
|
66
|
+
em = EventEmitter(type='asdf')
|
|
67
|
+
ev = self.try_emitter(em)
|
|
68
|
+
self.assert_result(
|
|
69
|
+
event=ev,
|
|
70
|
+
event_class=Event,
|
|
71
|
+
source=None,
|
|
72
|
+
type='asdf',
|
|
73
|
+
sources=[None])
|
|
74
|
+
|
|
75
|
+
# overriding type is ok:
|
|
76
|
+
ev = self.try_emitter(em, type='qwer')
|
|
77
|
+
self.assert_result(
|
|
78
|
+
event=ev,
|
|
79
|
+
event_class=Event,
|
|
80
|
+
source=None,
|
|
81
|
+
type='qwer',
|
|
82
|
+
sources=[None])
|
|
83
|
+
|
|
84
|
+
def test_emitter_type_event_class(self):
|
|
85
|
+
"""Emitter constructed with event_class argument"""
|
|
86
|
+
em = EventEmitter(event_class=BasicEvent)
|
|
87
|
+
ev = self.try_emitter(em, type='test_event')
|
|
88
|
+
self.assert_result(
|
|
89
|
+
event=ev,
|
|
90
|
+
event_class=BasicEvent,
|
|
91
|
+
source=None,
|
|
92
|
+
type='test_event',
|
|
93
|
+
sources=[None])
|
|
94
|
+
|
|
95
|
+
# specifying non-event class should fail (eventually):
|
|
96
|
+
class X:
|
|
97
|
+
|
|
98
|
+
def __init__(self, *args, **kwargs):
|
|
99
|
+
self.blocked = False
|
|
100
|
+
|
|
101
|
+
def _push_source(self, s):
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
def _pop_source(self):
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
em = EventEmitter(event_class=X)
|
|
109
|
+
ev = self.try_emitter(em, type='test_event')
|
|
110
|
+
self.assert_result() # checks event type
|
|
111
|
+
assert False, \
|
|
112
|
+
"Should not be able to construct emitter with non-Event class"
|
|
113
|
+
except Exception:
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
def test_event_kwargs(self):
|
|
117
|
+
"""Extra Event kwargs"""
|
|
118
|
+
em = EventEmitter(type='test_event')
|
|
119
|
+
em.default_args['key1'] = 'test1'
|
|
120
|
+
em.connect(self.record_event)
|
|
121
|
+
self.result = None
|
|
122
|
+
em(key2='test2')
|
|
123
|
+
self.assert_result(key1='test1', key2='test2')
|
|
124
|
+
|
|
125
|
+
def test_prebuilt_event(self):
|
|
126
|
+
"""Emit pre-built event"""
|
|
127
|
+
em = EventEmitter(type='test_event')
|
|
128
|
+
em.default_args['key1'] = 'test1'
|
|
129
|
+
em.connect(self.record_event)
|
|
130
|
+
|
|
131
|
+
self.result = None
|
|
132
|
+
ev = Event(type='my_type')
|
|
133
|
+
em(ev)
|
|
134
|
+
self.assert_result(event=ev, type='my_type')
|
|
135
|
+
assert not hasattr(self.result[0], 'key1')
|
|
136
|
+
|
|
137
|
+
def test_emitter_subclass(self):
|
|
138
|
+
"""The EventEmitter subclassing"""
|
|
139
|
+
class MyEmitter(EventEmitter):
|
|
140
|
+
|
|
141
|
+
def _prepare_event(self, *args, **kwargs):
|
|
142
|
+
ev = super(MyEmitter, self)._prepare_event(*args, **kwargs)
|
|
143
|
+
ev.test_tag = 1
|
|
144
|
+
return ev
|
|
145
|
+
em = MyEmitter(type='test_event')
|
|
146
|
+
em.connect(self.record_event)
|
|
147
|
+
self.result = None
|
|
148
|
+
em()
|
|
149
|
+
self.assert_result(test_tag=1)
|
|
150
|
+
|
|
151
|
+
def test_typed_event(self):
|
|
152
|
+
"""Emit Event class with pre-specified type"""
|
|
153
|
+
em = EventEmitter(event_class=TypedEvent)
|
|
154
|
+
ev = self.try_emitter(em) # no need to specify type here
|
|
155
|
+
self.assert_result(
|
|
156
|
+
event=ev,
|
|
157
|
+
event_class=TypedEvent,
|
|
158
|
+
source=None,
|
|
159
|
+
type='typed_event',
|
|
160
|
+
sources=[None])
|
|
161
|
+
|
|
162
|
+
def test_disconnect(self):
|
|
163
|
+
"""Emitter disconnection"""
|
|
164
|
+
em = EventEmitter(type='test_event')
|
|
165
|
+
|
|
166
|
+
def cb1(ev):
|
|
167
|
+
self.result = 1
|
|
168
|
+
|
|
169
|
+
def cb2(ev):
|
|
170
|
+
self.result = 2
|
|
171
|
+
|
|
172
|
+
em.connect((self, 'record_event'))
|
|
173
|
+
em.connect(cb1)
|
|
174
|
+
em.connect(cb2)
|
|
175
|
+
self.result = None
|
|
176
|
+
em.disconnect(cb2)
|
|
177
|
+
em.disconnect(cb2) # should pass silently
|
|
178
|
+
ev = em()
|
|
179
|
+
self.assert_result(event=ev)
|
|
180
|
+
|
|
181
|
+
self.result = None
|
|
182
|
+
em.disconnect((self, 'record_event'))
|
|
183
|
+
ev = em()
|
|
184
|
+
assert self.result == 1
|
|
185
|
+
|
|
186
|
+
self.result = None
|
|
187
|
+
em.connect(cb1)
|
|
188
|
+
em.connect(cb2)
|
|
189
|
+
em.connect((self, 'record_event'))
|
|
190
|
+
em.disconnect()
|
|
191
|
+
em()
|
|
192
|
+
assert self.result is None
|
|
193
|
+
|
|
194
|
+
def test_reconnect(self):
|
|
195
|
+
"""Ignore callback reconnect"""
|
|
196
|
+
em = EventEmitter(type='test_event')
|
|
197
|
+
|
|
198
|
+
def cb(ev):
|
|
199
|
+
self.result += 1
|
|
200
|
+
|
|
201
|
+
em.connect(cb)
|
|
202
|
+
em.connect(cb) # second connection should do nothing.
|
|
203
|
+
self.result = 0
|
|
204
|
+
em()
|
|
205
|
+
assert self.result == 1
|
|
206
|
+
|
|
207
|
+
def test_decorator_connection(self):
|
|
208
|
+
"""Connection by decorator"""
|
|
209
|
+
em = EventEmitter(type='test_event')
|
|
210
|
+
|
|
211
|
+
@em.connect
|
|
212
|
+
def cb(ev):
|
|
213
|
+
self.result = 1
|
|
214
|
+
|
|
215
|
+
self.result = None
|
|
216
|
+
em()
|
|
217
|
+
assert self.result == 1
|
|
218
|
+
|
|
219
|
+
def test_chained_emitters(self):
|
|
220
|
+
"""Chained emitters"""
|
|
221
|
+
em1 = EventEmitter(source=None, type='test_event1')
|
|
222
|
+
em2 = EventEmitter(source=self, type='test_event2')
|
|
223
|
+
em1.connect(em2)
|
|
224
|
+
em1.connect(self.record_event)
|
|
225
|
+
self.result = None
|
|
226
|
+
ev = em1()
|
|
227
|
+
self.assert_result(
|
|
228
|
+
event=ev,
|
|
229
|
+
event_class=Event,
|
|
230
|
+
source=None,
|
|
231
|
+
type='test_event1',
|
|
232
|
+
sources=[None])
|
|
233
|
+
|
|
234
|
+
# sources look different from second emitter, but type is the same.
|
|
235
|
+
em1.disconnect(self.record_event)
|
|
236
|
+
em2.connect(self.record_event)
|
|
237
|
+
self.result = None
|
|
238
|
+
ev = em1()
|
|
239
|
+
self.assert_result(
|
|
240
|
+
event=ev,
|
|
241
|
+
event_class=Event,
|
|
242
|
+
source=self,
|
|
243
|
+
type='test_event1',
|
|
244
|
+
sources=[
|
|
245
|
+
None,
|
|
246
|
+
self])
|
|
247
|
+
|
|
248
|
+
def test_emitter_error_handling(self):
|
|
249
|
+
"""Emitter error handling"""
|
|
250
|
+
em = EventEmitter(type='test_event')
|
|
251
|
+
em.print_callback_errors = 'never'
|
|
252
|
+
|
|
253
|
+
def cb(ev):
|
|
254
|
+
raise Exception('test')
|
|
255
|
+
|
|
256
|
+
# first callback fails; second callback still runs.
|
|
257
|
+
em.connect(self.record_event)
|
|
258
|
+
em.connect(cb)
|
|
259
|
+
self.result = None
|
|
260
|
+
ev = em()
|
|
261
|
+
self.assert_result(event=ev)
|
|
262
|
+
|
|
263
|
+
# this time we should get an exception
|
|
264
|
+
self.result = None
|
|
265
|
+
em.ignore_callback_errors = False
|
|
266
|
+
try:
|
|
267
|
+
em()
|
|
268
|
+
assert False, "Emission should have raised exception"
|
|
269
|
+
except Exception as err:
|
|
270
|
+
if str(err) != 'test':
|
|
271
|
+
raise
|
|
272
|
+
|
|
273
|
+
def test_emission_order(self):
|
|
274
|
+
"""Event emission order"""
|
|
275
|
+
em = EventEmitter(type='test_event')
|
|
276
|
+
|
|
277
|
+
def cb1(ev):
|
|
278
|
+
self.result = 1
|
|
279
|
+
|
|
280
|
+
def cb2(ev):
|
|
281
|
+
self.result = 2
|
|
282
|
+
|
|
283
|
+
em.connect(cb1)
|
|
284
|
+
em.connect(cb2)
|
|
285
|
+
self.result = None
|
|
286
|
+
em()
|
|
287
|
+
assert self.result == 1, "Events emitted in wrong order"
|
|
288
|
+
|
|
289
|
+
em.disconnect()
|
|
290
|
+
em.connect(cb2)
|
|
291
|
+
em.connect(cb1)
|
|
292
|
+
self.result = None
|
|
293
|
+
em()
|
|
294
|
+
assert self.result == 2, "Events emitted in wrong order"
|
|
295
|
+
|
|
296
|
+
def test_multiple_callbacks(self):
|
|
297
|
+
"""Multiple emitter callbacks"""
|
|
298
|
+
em = EventEmitter(type='test_event')
|
|
299
|
+
em.connect(functools.partial(self.record_event, key=1))
|
|
300
|
+
em.connect(functools.partial(self.record_event, key=2))
|
|
301
|
+
em.connect(functools.partial(self.record_event, key=3))
|
|
302
|
+
ev = em()
|
|
303
|
+
self.assert_result(key=1, event=ev, sources=[None])
|
|
304
|
+
self.assert_result(key=2, event=ev, sources=[None])
|
|
305
|
+
self.assert_result(key=3, event=ev, sources=[None])
|
|
306
|
+
|
|
307
|
+
def test_symbolic_callback(self):
|
|
308
|
+
"""Symbolic callbacks"""
|
|
309
|
+
em = EventEmitter(type='test_event')
|
|
310
|
+
em.connect((self, 'record_event'))
|
|
311
|
+
ev = em()
|
|
312
|
+
self.assert_result(event=ev)
|
|
313
|
+
|
|
314
|
+
# now check overriding the connected method
|
|
315
|
+
def cb(ev):
|
|
316
|
+
self.result = 1
|
|
317
|
+
|
|
318
|
+
self.result = None
|
|
319
|
+
orig_method = self.record_event
|
|
320
|
+
try:
|
|
321
|
+
self.record_event = cb
|
|
322
|
+
em()
|
|
323
|
+
assert self.result == 1
|
|
324
|
+
finally:
|
|
325
|
+
self.record_event = orig_method
|
|
326
|
+
|
|
327
|
+
def test_source_stack_integrity(self):
|
|
328
|
+
"""Emitter checks source stack"""
|
|
329
|
+
em = EventEmitter(type='test_event')
|
|
330
|
+
|
|
331
|
+
def cb(ev):
|
|
332
|
+
ev._sources.append('x')
|
|
333
|
+
em.connect(cb)
|
|
334
|
+
|
|
335
|
+
try:
|
|
336
|
+
em()
|
|
337
|
+
except RuntimeError as err:
|
|
338
|
+
if str(err) != 'Event source-stack mismatch.':
|
|
339
|
+
raise
|
|
340
|
+
|
|
341
|
+
em.disconnect()
|
|
342
|
+
|
|
343
|
+
def cb(ev):
|
|
344
|
+
ev._sources = []
|
|
345
|
+
em.connect(cb)
|
|
346
|
+
|
|
347
|
+
try:
|
|
348
|
+
em()
|
|
349
|
+
except IndexError:
|
|
350
|
+
pass
|
|
351
|
+
|
|
352
|
+
def test_emitter_loop(self):
|
|
353
|
+
"""Catch emitter loops"""
|
|
354
|
+
em1 = EventEmitter(type='test_event1')
|
|
355
|
+
em2 = EventEmitter(type='test_event2')
|
|
356
|
+
em1.ignore_callback_errors = False
|
|
357
|
+
em2.ignore_callback_errors = False
|
|
358
|
+
|
|
359
|
+
# cross-connect emitters; when we emit, an exception should be raised
|
|
360
|
+
# indicating an event loop.
|
|
361
|
+
em1.connect(em2)
|
|
362
|
+
em2.connect(em1)
|
|
363
|
+
try:
|
|
364
|
+
em1()
|
|
365
|
+
except RuntimeError as err:
|
|
366
|
+
if str(err) != 'EventEmitter loop detected!':
|
|
367
|
+
raise err
|
|
368
|
+
|
|
369
|
+
def test_emitter_block(self):
|
|
370
|
+
"""EventEmitter.blocker"""
|
|
371
|
+
em = EventEmitter(type='test_event')
|
|
372
|
+
em.connect(self.record_event)
|
|
373
|
+
self.result = None
|
|
374
|
+
|
|
375
|
+
with em.blocker():
|
|
376
|
+
em()
|
|
377
|
+
assert self.result is None
|
|
378
|
+
|
|
379
|
+
ev = em()
|
|
380
|
+
self.assert_result(event=ev)
|
|
381
|
+
|
|
382
|
+
def test_event_handling(self):
|
|
383
|
+
"""Event.handled"""
|
|
384
|
+
em = EventEmitter(type='test_event')
|
|
385
|
+
|
|
386
|
+
def cb1(ev):
|
|
387
|
+
ev.handled = True
|
|
388
|
+
|
|
389
|
+
def cb2(ev):
|
|
390
|
+
assert ev.handled
|
|
391
|
+
self.result = 1
|
|
392
|
+
em.connect(cb2)
|
|
393
|
+
em.connect(cb1)
|
|
394
|
+
self.result = None
|
|
395
|
+
em()
|
|
396
|
+
assert self.result == 1
|
|
397
|
+
|
|
398
|
+
def test_event_block(self):
|
|
399
|
+
"""Event.blocked"""
|
|
400
|
+
em = EventEmitter(type='test_event')
|
|
401
|
+
|
|
402
|
+
def cb1(ev):
|
|
403
|
+
ev.handled = True
|
|
404
|
+
self.result = 1
|
|
405
|
+
|
|
406
|
+
def cb2(ev):
|
|
407
|
+
ev.blocked = True
|
|
408
|
+
self.result = 2
|
|
409
|
+
|
|
410
|
+
em.connect(self.record_event)
|
|
411
|
+
em.connect(cb1)
|
|
412
|
+
self.result = None
|
|
413
|
+
em()
|
|
414
|
+
self.assert_result()
|
|
415
|
+
|
|
416
|
+
em.connect(cb2)
|
|
417
|
+
self.result = None
|
|
418
|
+
em()
|
|
419
|
+
assert self.result == 2
|
|
420
|
+
|
|
421
|
+
def try_emitter(self, em, **kwargs):
|
|
422
|
+
em.connect(self.record_event)
|
|
423
|
+
self.result = None
|
|
424
|
+
return em(**kwargs)
|
|
425
|
+
|
|
426
|
+
def record_event(self, ev, key=None):
|
|
427
|
+
# get a copy of all event attributes because these may change
|
|
428
|
+
# as the event is passed around; we want to know exactly what the event
|
|
429
|
+
# looked like when it reached this callback.
|
|
430
|
+
names = [name for name in dir(ev) if name[0] != '_']
|
|
431
|
+
attrs = {}
|
|
432
|
+
for name in names:
|
|
433
|
+
val = getattr(ev, name)
|
|
434
|
+
if name == 'source':
|
|
435
|
+
attrs[name] = val
|
|
436
|
+
elif name == 'sources':
|
|
437
|
+
attrs[name] = val[:]
|
|
438
|
+
else:
|
|
439
|
+
try:
|
|
440
|
+
attrs[name] = copy.deepcopy(val)
|
|
441
|
+
except Exception:
|
|
442
|
+
try:
|
|
443
|
+
attrs[name] = copy.copy(val)
|
|
444
|
+
except Exception:
|
|
445
|
+
attrs[name] = val
|
|
446
|
+
if key is None:
|
|
447
|
+
self.result = ev, attrs
|
|
448
|
+
else:
|
|
449
|
+
if not hasattr(self, 'result') or self.result is None:
|
|
450
|
+
self.result = {}
|
|
451
|
+
self.result[key] = ev, attrs
|
|
452
|
+
|
|
453
|
+
def assert_result(self, key=None, **kwargs):
|
|
454
|
+
assert (hasattr(self, 'result') and self.result is not None), \
|
|
455
|
+
"No event recorded"
|
|
456
|
+
|
|
457
|
+
if key is None:
|
|
458
|
+
event, event_attrs = self.result
|
|
459
|
+
else:
|
|
460
|
+
event, event_attrs = self.result[key]
|
|
461
|
+
|
|
462
|
+
assert isinstance(event, Event), "Emitted object is not Event instance"
|
|
463
|
+
|
|
464
|
+
for name, val in kwargs.items():
|
|
465
|
+
if name == 'event':
|
|
466
|
+
assert event is val, "Event objects do not match"
|
|
467
|
+
|
|
468
|
+
elif name == 'event_class':
|
|
469
|
+
assert isinstance(event, val), \
|
|
470
|
+
"Emitted object is not instance of %s" % val.__name__
|
|
471
|
+
|
|
472
|
+
else:
|
|
473
|
+
attr = event_attrs[name]
|
|
474
|
+
assert (attr == val), "Event.%s != %s (%s)" % (
|
|
475
|
+
name, str(val), str(attr))
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def test_event_connect_order():
|
|
479
|
+
"""Test event connection order"""
|
|
480
|
+
def a():
|
|
481
|
+
return
|
|
482
|
+
|
|
483
|
+
def b():
|
|
484
|
+
return
|
|
485
|
+
|
|
486
|
+
def c():
|
|
487
|
+
return
|
|
488
|
+
|
|
489
|
+
def d():
|
|
490
|
+
return
|
|
491
|
+
|
|
492
|
+
def e():
|
|
493
|
+
return
|
|
494
|
+
|
|
495
|
+
def f():
|
|
496
|
+
return
|
|
497
|
+
|
|
498
|
+
em = EventEmitter(type='test_event')
|
|
499
|
+
assert_raises(ValueError, em.connect, c, before=['c', 'foo'])
|
|
500
|
+
assert_raises(ValueError, em.connect, c, position='foo')
|
|
501
|
+
assert_raises(TypeError, em.connect, c, ref=dict())
|
|
502
|
+
em.connect(c, ref=True)
|
|
503
|
+
assert_equal((c,), tuple(em.callbacks))
|
|
504
|
+
em.connect(c)
|
|
505
|
+
assert_equal((c,), tuple(em.callbacks))
|
|
506
|
+
em.connect(d, ref=True, position='last')
|
|
507
|
+
assert_equal((c, d), tuple(em.callbacks))
|
|
508
|
+
em.connect(b, ref=True) # position='first'
|
|
509
|
+
assert_equal((b, c, d), tuple(em.callbacks))
|
|
510
|
+
assert_raises(RuntimeError, em.connect, a, before='c', after='d') # can't
|
|
511
|
+
em.connect(a, ref=True, before=['c', 'd']) # first possible pos == 0
|
|
512
|
+
assert_equal((a, b, c, d), tuple(em.callbacks))
|
|
513
|
+
em.connect(f, ref=True, after=['c', 'd'])
|
|
514
|
+
assert_equal((a, b, c, d, f), tuple(em.callbacks))
|
|
515
|
+
em.connect(e, ref=True, after='d', before='f')
|
|
516
|
+
assert_equal(('a', 'b', 'c', 'd', 'e', 'f'), tuple(em.callback_refs))
|
|
517
|
+
em.disconnect(e)
|
|
518
|
+
em.connect(e, ref=True, after='a', before='f', position='last')
|
|
519
|
+
assert_equal(('a', 'b', 'c', 'd', 'e', 'f'), tuple(em.callback_refs))
|
|
520
|
+
em.disconnect(e)
|
|
521
|
+
em.connect(e, ref='e', after='d', before='f', position='last')
|
|
522
|
+
assert_equal(('a', 'b', 'c', 'd', 'e', 'f'), tuple(em.callback_refs))
|
|
523
|
+
em.disconnect(e)
|
|
524
|
+
em.connect(e, after='d', before='f', position='first') # no name
|
|
525
|
+
assert_equal(('a', 'b', 'c', 'd', None, 'f'), tuple(em.callback_refs))
|
|
526
|
+
em.disconnect(e)
|
|
527
|
+
assert_raises(ValueError, em.connect, e, ref='d') # duplicate name
|
|
528
|
+
em.connect(e, ref=True, after=[], before='f', position='last')
|
|
529
|
+
assert_equal(('a', 'b', 'c', 'd', 'e', 'f'), tuple(em.callback_refs))
|
|
530
|
+
assert_equal((a, b, c, d, e, f), tuple(em.callbacks))
|
|
531
|
+
|
|
532
|
+
old_e = e
|
|
533
|
+
|
|
534
|
+
def e():
|
|
535
|
+
return
|
|
536
|
+
|
|
537
|
+
assert_raises(ValueError, em.connect, e, ref=True) # duplicate name
|
|
538
|
+
em.connect(e)
|
|
539
|
+
assert_equal((None, 'a', 'b', 'c', 'd', 'e', 'f'),
|
|
540
|
+
tuple(em.callback_refs))
|
|
541
|
+
assert_equal((e, a, b, c, d, old_e, f), tuple(em.callbacks))
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def test_emitter_block():
|
|
545
|
+
state = [False, False]
|
|
546
|
+
|
|
547
|
+
def a(ev):
|
|
548
|
+
state[0] = True
|
|
549
|
+
|
|
550
|
+
def b(ev):
|
|
551
|
+
state[1] = True
|
|
552
|
+
|
|
553
|
+
e = EventEmitter(source=None, type='event')
|
|
554
|
+
e.connect(a)
|
|
555
|
+
e.connect(b)
|
|
556
|
+
|
|
557
|
+
def assert_state(a, b):
|
|
558
|
+
assert state == [a, b]
|
|
559
|
+
state[0] = False
|
|
560
|
+
state[1] = False
|
|
561
|
+
|
|
562
|
+
e()
|
|
563
|
+
assert_state(True, True)
|
|
564
|
+
|
|
565
|
+
# test global blocking
|
|
566
|
+
e.block()
|
|
567
|
+
e()
|
|
568
|
+
assert_state(False, False)
|
|
569
|
+
e.block()
|
|
570
|
+
e()
|
|
571
|
+
assert_state(False, False)
|
|
572
|
+
|
|
573
|
+
# test global unlock, multiple depth
|
|
574
|
+
e.unblock()
|
|
575
|
+
e()
|
|
576
|
+
assert_state(False, False)
|
|
577
|
+
e.unblock()
|
|
578
|
+
e()
|
|
579
|
+
assert_state(True, True)
|
|
580
|
+
|
|
581
|
+
# test unblock failure
|
|
582
|
+
try:
|
|
583
|
+
e.unblock()
|
|
584
|
+
raise Exception("Expected RuntimeError")
|
|
585
|
+
except RuntimeError:
|
|
586
|
+
pass
|
|
587
|
+
|
|
588
|
+
# test single block
|
|
589
|
+
e.block(a)
|
|
590
|
+
e()
|
|
591
|
+
assert_state(False, True)
|
|
592
|
+
|
|
593
|
+
e.block(b)
|
|
594
|
+
e()
|
|
595
|
+
assert_state(False, False)
|
|
596
|
+
|
|
597
|
+
e.block(b)
|
|
598
|
+
e()
|
|
599
|
+
assert_state(False, False)
|
|
600
|
+
|
|
601
|
+
# test single unblock
|
|
602
|
+
e.unblock(a)
|
|
603
|
+
e()
|
|
604
|
+
assert_state(True, False)
|
|
605
|
+
|
|
606
|
+
e.unblock(b)
|
|
607
|
+
e()
|
|
608
|
+
assert_state(True, False)
|
|
609
|
+
|
|
610
|
+
e.unblock(b)
|
|
611
|
+
e()
|
|
612
|
+
assert_state(True, True)
|
|
613
|
+
|
|
614
|
+
# Test single unblock failure
|
|
615
|
+
try:
|
|
616
|
+
e.unblock(a)
|
|
617
|
+
raise Exception("Expected RuntimeError")
|
|
618
|
+
except RuntimeError:
|
|
619
|
+
pass
|
|
620
|
+
|
|
621
|
+
# test global blocker
|
|
622
|
+
with e.blocker():
|
|
623
|
+
e()
|
|
624
|
+
assert_state(False, False)
|
|
625
|
+
|
|
626
|
+
# test nested blocker
|
|
627
|
+
with e.blocker():
|
|
628
|
+
e()
|
|
629
|
+
assert_state(False, False)
|
|
630
|
+
|
|
631
|
+
e()
|
|
632
|
+
assert_state(False, False)
|
|
633
|
+
|
|
634
|
+
e()
|
|
635
|
+
assert_state(True, True)
|
|
636
|
+
|
|
637
|
+
# test single blocker
|
|
638
|
+
with e.blocker(a):
|
|
639
|
+
e()
|
|
640
|
+
assert_state(False, True)
|
|
641
|
+
|
|
642
|
+
# test nested gloabel blocker
|
|
643
|
+
with e.blocker():
|
|
644
|
+
e()
|
|
645
|
+
assert_state(False, False)
|
|
646
|
+
|
|
647
|
+
e()
|
|
648
|
+
assert_state(False, True)
|
|
649
|
+
|
|
650
|
+
# test nested single blocker
|
|
651
|
+
with e.blocker(a):
|
|
652
|
+
e()
|
|
653
|
+
assert_state(False, True)
|
|
654
|
+
|
|
655
|
+
with e.blocker(b):
|
|
656
|
+
e()
|
|
657
|
+
assert_state(False, False)
|
|
658
|
+
|
|
659
|
+
e()
|
|
660
|
+
assert_state(False, True)
|
|
661
|
+
|
|
662
|
+
e()
|
|
663
|
+
assert_state(True, True)
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def test_emitter_reentrance_allowed_when_blocked1():
|
|
667
|
+
# Minimal re-entrance example
|
|
668
|
+
|
|
669
|
+
e = EventEmitter(source=None, type='test')
|
|
670
|
+
count = 0
|
|
671
|
+
|
|
672
|
+
@e.connect
|
|
673
|
+
def foo(x):
|
|
674
|
+
nonlocal count
|
|
675
|
+
count += 1
|
|
676
|
+
with e.blocker():
|
|
677
|
+
e()
|
|
678
|
+
|
|
679
|
+
e()
|
|
680
|
+
assert count == 1
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
def test_emitter_reentrance_allowed_when_blocked2():
|
|
684
|
+
# More realistic re-entrance example
|
|
685
|
+
# The real world case for this might be a longer chain of events
|
|
686
|
+
# where event1's callback knows that what it's doing will trigger
|
|
687
|
+
# the same event so it blocks it:
|
|
688
|
+
# event1 -> foo -> event2 -> bar -> event1 -> (ignored bc blocked).
|
|
689
|
+
|
|
690
|
+
e1 = EventEmitter(source=None, type='test1')
|
|
691
|
+
e2 = EventEmitter(source=None, type='test2')
|
|
692
|
+
count = 0
|
|
693
|
+
|
|
694
|
+
@e1.connect
|
|
695
|
+
def foo(x):
|
|
696
|
+
nonlocal count
|
|
697
|
+
count += 1
|
|
698
|
+
with e1.blocker():
|
|
699
|
+
e2()
|
|
700
|
+
|
|
701
|
+
@e2.connect
|
|
702
|
+
def bar(x):
|
|
703
|
+
nonlocal count
|
|
704
|
+
count += 10
|
|
705
|
+
e1()
|
|
706
|
+
|
|
707
|
+
e1()
|
|
708
|
+
assert count == 11
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
def test_emitter_reentrance_allowed_when_blocked3():
|
|
712
|
+
# Like the previous, but blocking callbacks instead of the event itself.
|
|
713
|
+
# Allows more fine-grained control. To some extent anyway - all callbacks
|
|
714
|
+
# of the event must be blocked to prevent raising the emitter loop error.
|
|
715
|
+
|
|
716
|
+
e1 = EventEmitter(source=None, type='test1')
|
|
717
|
+
e2 = EventEmitter(source=None, type='test2')
|
|
718
|
+
count = 0
|
|
719
|
+
|
|
720
|
+
@e1.connect
|
|
721
|
+
def foo(x):
|
|
722
|
+
nonlocal count
|
|
723
|
+
count += 1
|
|
724
|
+
with e1.blocker(foo):
|
|
725
|
+
e2()
|
|
726
|
+
|
|
727
|
+
@e2.connect
|
|
728
|
+
def bar(x):
|
|
729
|
+
nonlocal count
|
|
730
|
+
count += 10
|
|
731
|
+
e1()
|
|
732
|
+
|
|
733
|
+
@e2.connect
|
|
734
|
+
def eggs(x):
|
|
735
|
+
nonlocal count
|
|
736
|
+
count += 100
|
|
737
|
+
e1()
|
|
738
|
+
|
|
739
|
+
e1()
|
|
740
|
+
assert count == 111
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
run_tests_if_main()
|