vispy 0.14.0__cp311-cp311-macosx_11_0_arm64.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.

Files changed (519) hide show
  1. vispy/__init__.py +33 -0
  2. vispy/app/__init__.py +15 -0
  3. vispy/app/_default_app.py +76 -0
  4. vispy/app/_detect_eventloop.py +148 -0
  5. vispy/app/application.py +263 -0
  6. vispy/app/backends/__init__.py +52 -0
  7. vispy/app/backends/_egl.py +264 -0
  8. vispy/app/backends/_glfw.py +513 -0
  9. vispy/app/backends/_jupyter_rfb.py +278 -0
  10. vispy/app/backends/_offscreen_util.py +121 -0
  11. vispy/app/backends/_osmesa.py +235 -0
  12. vispy/app/backends/_pyglet.py +451 -0
  13. vispy/app/backends/_pyqt4.py +36 -0
  14. vispy/app/backends/_pyqt5.py +36 -0
  15. vispy/app/backends/_pyqt6.py +40 -0
  16. vispy/app/backends/_pyside.py +37 -0
  17. vispy/app/backends/_pyside2.py +52 -0
  18. vispy/app/backends/_pyside6.py +53 -0
  19. vispy/app/backends/_qt.py +968 -0
  20. vispy/app/backends/_sdl2.py +444 -0
  21. vispy/app/backends/_template.py +244 -0
  22. vispy/app/backends/_test.py +8 -0
  23. vispy/app/backends/_tk.py +800 -0
  24. vispy/app/backends/_wx.py +476 -0
  25. vispy/app/backends/tests/__init__.py +0 -0
  26. vispy/app/backends/tests/test_offscreen_util.py +52 -0
  27. vispy/app/backends/tests/test_rfb.py +77 -0
  28. vispy/app/base.py +294 -0
  29. vispy/app/canvas.py +828 -0
  30. vispy/app/qt.py +92 -0
  31. vispy/app/tests/__init__.py +0 -0
  32. vispy/app/tests/qt-designer.ui +58 -0
  33. vispy/app/tests/test_app.py +442 -0
  34. vispy/app/tests/test_backends.py +164 -0
  35. vispy/app/tests/test_canvas.py +122 -0
  36. vispy/app/tests/test_context.py +92 -0
  37. vispy/app/tests/test_qt.py +47 -0
  38. vispy/app/tests/test_simultaneous.py +134 -0
  39. vispy/app/timer.py +174 -0
  40. vispy/color/__init__.py +17 -0
  41. vispy/color/_color_dict.py +193 -0
  42. vispy/color/color_array.py +447 -0
  43. vispy/color/color_space.py +181 -0
  44. vispy/color/colormap.py +1134 -0
  45. vispy/color/tests/__init__.py +0 -0
  46. vispy/color/tests/test_color.py +352 -0
  47. vispy/conftest.py +12 -0
  48. vispy/ext/__init__.py +0 -0
  49. vispy/ext/cocoapy.py +1542 -0
  50. vispy/ext/cubehelix.py +138 -0
  51. vispy/ext/egl.py +375 -0
  52. vispy/ext/fontconfig.py +118 -0
  53. vispy/ext/gdi32plus.py +206 -0
  54. vispy/ext/osmesa.py +105 -0
  55. vispy/geometry/__init__.py +23 -0
  56. vispy/geometry/_triangulation_debugger.py +171 -0
  57. vispy/geometry/calculations.py +134 -0
  58. vispy/geometry/curves.py +399 -0
  59. vispy/geometry/generation.py +643 -0
  60. vispy/geometry/isocurve.py +175 -0
  61. vispy/geometry/isosurface.py +465 -0
  62. vispy/geometry/meshdata.py +698 -0
  63. vispy/geometry/normals.py +78 -0
  64. vispy/geometry/parametric.py +56 -0
  65. vispy/geometry/polygon.py +137 -0
  66. vispy/geometry/rect.py +210 -0
  67. vispy/geometry/tests/__init__.py +0 -0
  68. vispy/geometry/tests/test_calculations.py +23 -0
  69. vispy/geometry/tests/test_generation.py +56 -0
  70. vispy/geometry/tests/test_meshdata.py +106 -0
  71. vispy/geometry/tests/test_triangulation.py +506 -0
  72. vispy/geometry/torusknot.py +142 -0
  73. vispy/geometry/triangulation.py +876 -0
  74. vispy/gloo/__init__.py +56 -0
  75. vispy/gloo/buffer.py +505 -0
  76. vispy/gloo/context.py +272 -0
  77. vispy/gloo/framebuffer.py +257 -0
  78. vispy/gloo/gl/__init__.py +234 -0
  79. vispy/gloo/gl/_constants.py +332 -0
  80. vispy/gloo/gl/_es2.py +986 -0
  81. vispy/gloo/gl/_gl2.py +1365 -0
  82. vispy/gloo/gl/_proxy.py +499 -0
  83. vispy/gloo/gl/_pyopengl2.py +362 -0
  84. vispy/gloo/gl/dummy.py +24 -0
  85. vispy/gloo/gl/es2.py +62 -0
  86. vispy/gloo/gl/gl2.py +98 -0
  87. vispy/gloo/gl/glplus.py +168 -0
  88. vispy/gloo/gl/pyopengl2.py +97 -0
  89. vispy/gloo/gl/tests/__init__.py +0 -0
  90. vispy/gloo/gl/tests/test_basics.py +282 -0
  91. vispy/gloo/gl/tests/test_functionality.py +566 -0
  92. vispy/gloo/gl/tests/test_names.py +246 -0
  93. vispy/gloo/gl/tests/test_use.py +71 -0
  94. vispy/gloo/glir.py +1816 -0
  95. vispy/gloo/globject.py +101 -0
  96. vispy/gloo/preprocessor.py +67 -0
  97. vispy/gloo/program.py +543 -0
  98. vispy/gloo/tests/__init__.py +0 -0
  99. vispy/gloo/tests/test_buffer.py +558 -0
  100. vispy/gloo/tests/test_context.py +119 -0
  101. vispy/gloo/tests/test_framebuffer.py +195 -0
  102. vispy/gloo/tests/test_glir.py +307 -0
  103. vispy/gloo/tests/test_globject.py +35 -0
  104. vispy/gloo/tests/test_program.py +302 -0
  105. vispy/gloo/tests/test_texture.py +732 -0
  106. vispy/gloo/tests/test_use_gloo.py +187 -0
  107. vispy/gloo/tests/test_util.py +60 -0
  108. vispy/gloo/tests/test_wrappers.py +261 -0
  109. vispy/gloo/texture.py +1045 -0
  110. vispy/gloo/util.py +129 -0
  111. vispy/gloo/wrappers.py +762 -0
  112. vispy/glsl/__init__.py +42 -0
  113. vispy/glsl/antialias/antialias.glsl +7 -0
  114. vispy/glsl/antialias/cap-butt.glsl +31 -0
  115. vispy/glsl/antialias/cap-round.glsl +29 -0
  116. vispy/glsl/antialias/cap-square.glsl +30 -0
  117. vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
  118. vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
  119. vispy/glsl/antialias/cap.glsl +67 -0
  120. vispy/glsl/antialias/caps.glsl +67 -0
  121. vispy/glsl/antialias/filled.glsl +50 -0
  122. vispy/glsl/antialias/outline.glsl +40 -0
  123. vispy/glsl/antialias/stroke.glsl +43 -0
  124. vispy/glsl/arrowheads/angle.glsl +99 -0
  125. vispy/glsl/arrowheads/arrowheads.frag +60 -0
  126. vispy/glsl/arrowheads/arrowheads.glsl +12 -0
  127. vispy/glsl/arrowheads/arrowheads.vert +83 -0
  128. vispy/glsl/arrowheads/curved.glsl +48 -0
  129. vispy/glsl/arrowheads/inhibitor.glsl +26 -0
  130. vispy/glsl/arrowheads/stealth.glsl +46 -0
  131. vispy/glsl/arrowheads/triangle.glsl +97 -0
  132. vispy/glsl/arrowheads/util.glsl +13 -0
  133. vispy/glsl/arrows/angle-30.glsl +12 -0
  134. vispy/glsl/arrows/angle-60.glsl +12 -0
  135. vispy/glsl/arrows/angle-90.glsl +12 -0
  136. vispy/glsl/arrows/arrow.frag +39 -0
  137. vispy/glsl/arrows/arrow.vert +49 -0
  138. vispy/glsl/arrows/arrows.glsl +17 -0
  139. vispy/glsl/arrows/common.glsl +187 -0
  140. vispy/glsl/arrows/curved.glsl +63 -0
  141. vispy/glsl/arrows/stealth.glsl +50 -0
  142. vispy/glsl/arrows/triangle-30.glsl +12 -0
  143. vispy/glsl/arrows/triangle-60.glsl +12 -0
  144. vispy/glsl/arrows/triangle-90.glsl +12 -0
  145. vispy/glsl/arrows/util.glsl +98 -0
  146. vispy/glsl/build_spatial_filters.py +660 -0
  147. vispy/glsl/collections/agg-fast-path.frag +20 -0
  148. vispy/glsl/collections/agg-fast-path.vert +78 -0
  149. vispy/glsl/collections/agg-glyph.frag +60 -0
  150. vispy/glsl/collections/agg-glyph.vert +33 -0
  151. vispy/glsl/collections/agg-marker.frag +35 -0
  152. vispy/glsl/collections/agg-marker.vert +48 -0
  153. vispy/glsl/collections/agg-path.frag +55 -0
  154. vispy/glsl/collections/agg-path.vert +166 -0
  155. vispy/glsl/collections/agg-point.frag +21 -0
  156. vispy/glsl/collections/agg-point.vert +35 -0
  157. vispy/glsl/collections/agg-segment.frag +32 -0
  158. vispy/glsl/collections/agg-segment.vert +75 -0
  159. vispy/glsl/collections/marker.frag +38 -0
  160. vispy/glsl/collections/marker.vert +48 -0
  161. vispy/glsl/collections/raw-path.frag +15 -0
  162. vispy/glsl/collections/raw-path.vert +24 -0
  163. vispy/glsl/collections/raw-point.frag +14 -0
  164. vispy/glsl/collections/raw-point.vert +31 -0
  165. vispy/glsl/collections/raw-segment.frag +18 -0
  166. vispy/glsl/collections/raw-segment.vert +26 -0
  167. vispy/glsl/collections/raw-triangle.frag +13 -0
  168. vispy/glsl/collections/raw-triangle.vert +26 -0
  169. vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
  170. vispy/glsl/collections/sdf-glyph.frag +80 -0
  171. vispy/glsl/collections/sdf-glyph.vert +59 -0
  172. vispy/glsl/collections/tick-labels.vert +71 -0
  173. vispy/glsl/colormaps/autumn.glsl +20 -0
  174. vispy/glsl/colormaps/blues.glsl +20 -0
  175. vispy/glsl/colormaps/color-space.glsl +17 -0
  176. vispy/glsl/colormaps/colormaps.glsl +24 -0
  177. vispy/glsl/colormaps/cool.glsl +20 -0
  178. vispy/glsl/colormaps/fire.glsl +21 -0
  179. vispy/glsl/colormaps/gray.glsl +20 -0
  180. vispy/glsl/colormaps/greens.glsl +20 -0
  181. vispy/glsl/colormaps/hot.glsl +22 -0
  182. vispy/glsl/colormaps/ice.glsl +20 -0
  183. vispy/glsl/colormaps/icefire.glsl +23 -0
  184. vispy/glsl/colormaps/parse.py +40 -0
  185. vispy/glsl/colormaps/reds.glsl +20 -0
  186. vispy/glsl/colormaps/spring.glsl +20 -0
  187. vispy/glsl/colormaps/summer.glsl +20 -0
  188. vispy/glsl/colormaps/user.glsl +22 -0
  189. vispy/glsl/colormaps/util.glsl +41 -0
  190. vispy/glsl/colormaps/wheel.glsl +21 -0
  191. vispy/glsl/colormaps/winter.glsl +20 -0
  192. vispy/glsl/lines/agg.frag +320 -0
  193. vispy/glsl/lines/agg.vert +241 -0
  194. vispy/glsl/markers/arrow.glsl +12 -0
  195. vispy/glsl/markers/asterisk.glsl +16 -0
  196. vispy/glsl/markers/chevron.glsl +14 -0
  197. vispy/glsl/markers/clover.glsl +20 -0
  198. vispy/glsl/markers/club.glsl +31 -0
  199. vispy/glsl/markers/cross.glsl +17 -0
  200. vispy/glsl/markers/diamond.glsl +12 -0
  201. vispy/glsl/markers/disc.glsl +9 -0
  202. vispy/glsl/markers/ellipse.glsl +67 -0
  203. vispy/glsl/markers/hbar.glsl +9 -0
  204. vispy/glsl/markers/heart.glsl +15 -0
  205. vispy/glsl/markers/infinity.glsl +15 -0
  206. vispy/glsl/markers/marker-sdf.frag +74 -0
  207. vispy/glsl/markers/marker-sdf.vert +41 -0
  208. vispy/glsl/markers/marker.frag +36 -0
  209. vispy/glsl/markers/marker.vert +46 -0
  210. vispy/glsl/markers/markers.glsl +24 -0
  211. vispy/glsl/markers/pin.glsl +18 -0
  212. vispy/glsl/markers/ring.glsl +11 -0
  213. vispy/glsl/markers/spade.glsl +28 -0
  214. vispy/glsl/markers/square.glsl +10 -0
  215. vispy/glsl/markers/tag.glsl +11 -0
  216. vispy/glsl/markers/triangle.glsl +14 -0
  217. vispy/glsl/markers/vbar.glsl +9 -0
  218. vispy/glsl/math/circle-through-2-points.glsl +30 -0
  219. vispy/glsl/math/constants.glsl +48 -0
  220. vispy/glsl/math/double.glsl +114 -0
  221. vispy/glsl/math/functions.glsl +20 -0
  222. vispy/glsl/math/point-to-line-distance.glsl +31 -0
  223. vispy/glsl/math/point-to-line-projection.glsl +29 -0
  224. vispy/glsl/math/signed-line-distance.glsl +27 -0
  225. vispy/glsl/math/signed-segment-distance.glsl +30 -0
  226. vispy/glsl/misc/regular-grid.frag +244 -0
  227. vispy/glsl/misc/spatial-filters.frag +1407 -0
  228. vispy/glsl/misc/viewport-NDC.glsl +20 -0
  229. vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
  230. vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
  231. vispy/glsl/transforms/hammer.glsl +44 -0
  232. vispy/glsl/transforms/identity.glsl +6 -0
  233. vispy/glsl/transforms/identity_forward.glsl +23 -0
  234. vispy/glsl/transforms/identity_inverse.glsl +23 -0
  235. vispy/glsl/transforms/linear-scale.glsl +127 -0
  236. vispy/glsl/transforms/log-scale.glsl +126 -0
  237. vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
  238. vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
  239. vispy/glsl/transforms/panzoom.glsl +10 -0
  240. vispy/glsl/transforms/polar.glsl +41 -0
  241. vispy/glsl/transforms/position.glsl +44 -0
  242. vispy/glsl/transforms/power-scale.glsl +139 -0
  243. vispy/glsl/transforms/projection.glsl +7 -0
  244. vispy/glsl/transforms/pvm.glsl +13 -0
  245. vispy/glsl/transforms/rotate.glsl +45 -0
  246. vispy/glsl/transforms/trackball.glsl +15 -0
  247. vispy/glsl/transforms/translate.glsl +35 -0
  248. vispy/glsl/transforms/transverse_mercator.glsl +38 -0
  249. vispy/glsl/transforms/viewport-clipping.glsl +14 -0
  250. vispy/glsl/transforms/viewport-transform.glsl +16 -0
  251. vispy/glsl/transforms/viewport.glsl +50 -0
  252. vispy/glsl/transforms/x.glsl +24 -0
  253. vispy/glsl/transforms/y.glsl +19 -0
  254. vispy/glsl/transforms/z.glsl +14 -0
  255. vispy/io/__init__.py +20 -0
  256. vispy/io/_data/spatial-filters.npy +0 -0
  257. vispy/io/datasets.py +94 -0
  258. vispy/io/image.py +231 -0
  259. vispy/io/mesh.py +122 -0
  260. vispy/io/stl.py +167 -0
  261. vispy/io/tests/__init__.py +0 -0
  262. vispy/io/tests/test_image.py +47 -0
  263. vispy/io/tests/test_io.py +121 -0
  264. vispy/io/wavefront.py +350 -0
  265. vispy/plot/__init__.py +36 -0
  266. vispy/plot/fig.py +58 -0
  267. vispy/plot/plotwidget.py +522 -0
  268. vispy/plot/tests/__init__.py +0 -0
  269. vispy/plot/tests/test_plot.py +46 -0
  270. vispy/scene/__init__.py +43 -0
  271. vispy/scene/cameras/__init__.py +27 -0
  272. vispy/scene/cameras/_base.py +38 -0
  273. vispy/scene/cameras/arcball.py +106 -0
  274. vispy/scene/cameras/base_camera.py +538 -0
  275. vispy/scene/cameras/fly.py +474 -0
  276. vispy/scene/cameras/magnify.py +163 -0
  277. vispy/scene/cameras/panzoom.py +308 -0
  278. vispy/scene/cameras/perspective.py +333 -0
  279. vispy/scene/cameras/tests/__init__.py +0 -0
  280. vispy/scene/cameras/tests/test_cameras.py +27 -0
  281. vispy/scene/cameras/tests/test_link.py +53 -0
  282. vispy/scene/cameras/tests/test_perspective.py +122 -0
  283. vispy/scene/cameras/turntable.py +173 -0
  284. vispy/scene/canvas.py +639 -0
  285. vispy/scene/events.py +85 -0
  286. vispy/scene/node.py +644 -0
  287. vispy/scene/subscene.py +20 -0
  288. vispy/scene/tests/__init__.py +0 -0
  289. vispy/scene/tests/test_canvas.py +119 -0
  290. vispy/scene/tests/test_node.py +142 -0
  291. vispy/scene/tests/test_visuals.py +141 -0
  292. vispy/scene/visuals.py +276 -0
  293. vispy/scene/widgets/__init__.py +18 -0
  294. vispy/scene/widgets/anchor.py +25 -0
  295. vispy/scene/widgets/axis.py +88 -0
  296. vispy/scene/widgets/colorbar.py +176 -0
  297. vispy/scene/widgets/console.py +351 -0
  298. vispy/scene/widgets/grid.py +509 -0
  299. vispy/scene/widgets/label.py +50 -0
  300. vispy/scene/widgets/tests/__init__.py +0 -0
  301. vispy/scene/widgets/tests/test_colorbar.py +47 -0
  302. vispy/scene/widgets/viewbox.py +199 -0
  303. vispy/scene/widgets/widget.py +478 -0
  304. vispy/testing/__init__.py +51 -0
  305. vispy/testing/_runners.py +446 -0
  306. vispy/testing/_testing.py +416 -0
  307. vispy/testing/image_tester.py +473 -0
  308. vispy/testing/rendered_array_tester.py +85 -0
  309. vispy/testing/tests/__init__.py +0 -0
  310. vispy/testing/tests/test_testing.py +20 -0
  311. vispy/util/__init__.py +17 -0
  312. vispy/util/bunch.py +15 -0
  313. vispy/util/check_environment.py +57 -0
  314. vispy/util/config.py +490 -0
  315. vispy/util/dpi/__init__.py +19 -0
  316. vispy/util/dpi/_linux.py +69 -0
  317. vispy/util/dpi/_quartz.py +26 -0
  318. vispy/util/dpi/_win32.py +34 -0
  319. vispy/util/dpi/tests/__init__.py +0 -0
  320. vispy/util/dpi/tests/test_dpi.py +16 -0
  321. vispy/util/eq.py +41 -0
  322. vispy/util/event.py +774 -0
  323. vispy/util/fetching.py +276 -0
  324. vispy/util/filter.py +44 -0
  325. vispy/util/fonts/__init__.py +14 -0
  326. vispy/util/fonts/_freetype.py +73 -0
  327. vispy/util/fonts/_quartz.py +192 -0
  328. vispy/util/fonts/_triage.py +36 -0
  329. vispy/util/fonts/_vispy_fonts.py +20 -0
  330. vispy/util/fonts/_win32.py +105 -0
  331. vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
  332. vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
  333. vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
  334. vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
  335. vispy/util/fonts/tests/__init__.py +0 -0
  336. vispy/util/fonts/tests/test_font.py +45 -0
  337. vispy/util/fourier.py +69 -0
  338. vispy/util/frozen.py +25 -0
  339. vispy/util/gallery_scraper.py +268 -0
  340. vispy/util/keys.py +91 -0
  341. vispy/util/logs.py +358 -0
  342. vispy/util/osmesa_gl.py +17 -0
  343. vispy/util/profiler.py +135 -0
  344. vispy/util/ptime.py +16 -0
  345. vispy/util/quaternion.py +229 -0
  346. vispy/util/svg/__init__.py +18 -0
  347. vispy/util/svg/base.py +20 -0
  348. vispy/util/svg/color.py +219 -0
  349. vispy/util/svg/element.py +51 -0
  350. vispy/util/svg/geometry.py +478 -0
  351. vispy/util/svg/group.py +66 -0
  352. vispy/util/svg/length.py +81 -0
  353. vispy/util/svg/number.py +25 -0
  354. vispy/util/svg/path.py +332 -0
  355. vispy/util/svg/shapes.py +57 -0
  356. vispy/util/svg/style.py +59 -0
  357. vispy/util/svg/svg.py +40 -0
  358. vispy/util/svg/transform.py +223 -0
  359. vispy/util/svg/transformable.py +28 -0
  360. vispy/util/svg/viewport.py +73 -0
  361. vispy/util/tests/__init__.py +0 -0
  362. vispy/util/tests/test_config.py +58 -0
  363. vispy/util/tests/test_docstring_parameters.py +123 -0
  364. vispy/util/tests/test_emitter_group.py +262 -0
  365. vispy/util/tests/test_event_emitter.py +743 -0
  366. vispy/util/tests/test_fourier.py +35 -0
  367. vispy/util/tests/test_gallery_scraper.py +112 -0
  368. vispy/util/tests/test_import.py +127 -0
  369. vispy/util/tests/test_key.py +22 -0
  370. vispy/util/tests/test_logging.py +45 -0
  371. vispy/util/tests/test_run.py +14 -0
  372. vispy/util/tests/test_transforms.py +42 -0
  373. vispy/util/tests/test_vispy.py +48 -0
  374. vispy/util/transforms.py +201 -0
  375. vispy/util/wrappers.py +155 -0
  376. vispy/version.py +4 -0
  377. vispy/visuals/__init__.py +50 -0
  378. vispy/visuals/_scalable_textures.py +485 -0
  379. vispy/visuals/axis.py +678 -0
  380. vispy/visuals/border.py +208 -0
  381. vispy/visuals/box.py +79 -0
  382. vispy/visuals/collections/__init__.py +30 -0
  383. vispy/visuals/collections/agg_fast_path_collection.py +219 -0
  384. vispy/visuals/collections/agg_path_collection.py +197 -0
  385. vispy/visuals/collections/agg_point_collection.py +52 -0
  386. vispy/visuals/collections/agg_segment_collection.py +142 -0
  387. vispy/visuals/collections/array_list.py +401 -0
  388. vispy/visuals/collections/base_collection.py +482 -0
  389. vispy/visuals/collections/collection.py +253 -0
  390. vispy/visuals/collections/path_collection.py +23 -0
  391. vispy/visuals/collections/point_collection.py +19 -0
  392. vispy/visuals/collections/polygon_collection.py +25 -0
  393. vispy/visuals/collections/raw_path_collection.py +119 -0
  394. vispy/visuals/collections/raw_point_collection.py +113 -0
  395. vispy/visuals/collections/raw_polygon_collection.py +77 -0
  396. vispy/visuals/collections/raw_segment_collection.py +112 -0
  397. vispy/visuals/collections/raw_triangle_collection.py +78 -0
  398. vispy/visuals/collections/segment_collection.py +19 -0
  399. vispy/visuals/collections/triangle_collection.py +16 -0
  400. vispy/visuals/collections/util.py +168 -0
  401. vispy/visuals/colorbar.py +699 -0
  402. vispy/visuals/cube.py +41 -0
  403. vispy/visuals/ellipse.py +163 -0
  404. vispy/visuals/filters/__init__.py +10 -0
  405. vispy/visuals/filters/base_filter.py +242 -0
  406. vispy/visuals/filters/clipper.py +60 -0
  407. vispy/visuals/filters/clipping_planes.py +122 -0
  408. vispy/visuals/filters/color.py +181 -0
  409. vispy/visuals/filters/markers.py +28 -0
  410. vispy/visuals/filters/mesh.py +796 -0
  411. vispy/visuals/filters/picking.py +60 -0
  412. vispy/visuals/filters/tests/__init__.py +3 -0
  413. vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
  414. vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
  415. vispy/visuals/glsl/__init__.py +1 -0
  416. vispy/visuals/glsl/antialiasing.py +133 -0
  417. vispy/visuals/glsl/color.py +63 -0
  418. vispy/visuals/graphs/__init__.py +1 -0
  419. vispy/visuals/graphs/graph.py +240 -0
  420. vispy/visuals/graphs/layouts/__init__.py +55 -0
  421. vispy/visuals/graphs/layouts/circular.py +49 -0
  422. vispy/visuals/graphs/layouts/force_directed.py +211 -0
  423. vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
  424. vispy/visuals/graphs/layouts/random.py +52 -0
  425. vispy/visuals/graphs/tests/__init__.py +1 -0
  426. vispy/visuals/graphs/tests/test_layouts.py +139 -0
  427. vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
  428. vispy/visuals/graphs/util.py +120 -0
  429. vispy/visuals/gridlines.py +105 -0
  430. vispy/visuals/gridmesh.py +98 -0
  431. vispy/visuals/histogram.py +58 -0
  432. vispy/visuals/image.py +688 -0
  433. vispy/visuals/image_complex.py +130 -0
  434. vispy/visuals/infinite_line.py +199 -0
  435. vispy/visuals/instanced_mesh.py +152 -0
  436. vispy/visuals/isocurve.py +213 -0
  437. vispy/visuals/isoline.py +241 -0
  438. vispy/visuals/isosurface.py +113 -0
  439. vispy/visuals/line/__init__.py +6 -0
  440. vispy/visuals/line/arrow.py +289 -0
  441. vispy/visuals/line/dash_atlas.py +90 -0
  442. vispy/visuals/line/line.py +545 -0
  443. vispy/visuals/line_plot.py +135 -0
  444. vispy/visuals/linear_region.py +199 -0
  445. vispy/visuals/markers.py +810 -0
  446. vispy/visuals/mesh.py +373 -0
  447. vispy/visuals/mesh_normals.py +159 -0
  448. vispy/visuals/plane.py +54 -0
  449. vispy/visuals/polygon.py +145 -0
  450. vispy/visuals/rectangle.py +196 -0
  451. vispy/visuals/regular_polygon.py +56 -0
  452. vispy/visuals/scrolling_lines.py +197 -0
  453. vispy/visuals/shaders/__init__.py +17 -0
  454. vispy/visuals/shaders/compiler.py +206 -0
  455. vispy/visuals/shaders/expression.py +99 -0
  456. vispy/visuals/shaders/function.py +788 -0
  457. vispy/visuals/shaders/multiprogram.py +145 -0
  458. vispy/visuals/shaders/parsing.py +140 -0
  459. vispy/visuals/shaders/program.py +161 -0
  460. vispy/visuals/shaders/shader_object.py +162 -0
  461. vispy/visuals/shaders/tests/__init__.py +0 -0
  462. vispy/visuals/shaders/tests/test_function.py +486 -0
  463. vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
  464. vispy/visuals/shaders/tests/test_parsing.py +57 -0
  465. vispy/visuals/shaders/variable.py +272 -0
  466. vispy/visuals/spectrogram.py +169 -0
  467. vispy/visuals/sphere.py +80 -0
  468. vispy/visuals/surface_plot.py +192 -0
  469. vispy/visuals/tests/__init__.py +0 -0
  470. vispy/visuals/tests/test_arrows.py +109 -0
  471. vispy/visuals/tests/test_axis.py +120 -0
  472. vispy/visuals/tests/test_collections.py +15 -0
  473. vispy/visuals/tests/test_colorbar.py +179 -0
  474. vispy/visuals/tests/test_colormap.py +97 -0
  475. vispy/visuals/tests/test_ellipse.py +122 -0
  476. vispy/visuals/tests/test_histogram.py +24 -0
  477. vispy/visuals/tests/test_image.py +390 -0
  478. vispy/visuals/tests/test_image_complex.py +36 -0
  479. vispy/visuals/tests/test_infinite_line.py +53 -0
  480. vispy/visuals/tests/test_instanced_mesh.py +50 -0
  481. vispy/visuals/tests/test_isosurface.py +22 -0
  482. vispy/visuals/tests/test_linear_region.py +152 -0
  483. vispy/visuals/tests/test_markers.py +54 -0
  484. vispy/visuals/tests/test_mesh.py +261 -0
  485. vispy/visuals/tests/test_mesh_normals.py +218 -0
  486. vispy/visuals/tests/test_polygon.py +112 -0
  487. vispy/visuals/tests/test_rectangle.py +163 -0
  488. vispy/visuals/tests/test_regular_polygon.py +111 -0
  489. vispy/visuals/tests/test_scalable_textures.py +180 -0
  490. vispy/visuals/tests/test_sdf.py +73 -0
  491. vispy/visuals/tests/test_spectrogram.py +42 -0
  492. vispy/visuals/tests/test_text.py +95 -0
  493. vispy/visuals/tests/test_volume.py +542 -0
  494. vispy/visuals/tests/test_windbarb.py +33 -0
  495. vispy/visuals/text/__init__.py +7 -0
  496. vispy/visuals/text/_sdf_cpu.cpython-311-darwin.so +0 -0
  497. vispy/visuals/text/_sdf_cpu.pyx +110 -0
  498. vispy/visuals/text/_sdf_gpu.py +316 -0
  499. vispy/visuals/text/text.py +675 -0
  500. vispy/visuals/transforms/__init__.py +34 -0
  501. vispy/visuals/transforms/_util.py +191 -0
  502. vispy/visuals/transforms/base_transform.py +233 -0
  503. vispy/visuals/transforms/chain.py +300 -0
  504. vispy/visuals/transforms/interactive.py +98 -0
  505. vispy/visuals/transforms/linear.py +564 -0
  506. vispy/visuals/transforms/nonlinear.py +398 -0
  507. vispy/visuals/transforms/tests/__init__.py +0 -0
  508. vispy/visuals/transforms/tests/test_transforms.py +243 -0
  509. vispy/visuals/transforms/transform_system.py +339 -0
  510. vispy/visuals/tube.py +173 -0
  511. vispy/visuals/visual.py +923 -0
  512. vispy/visuals/volume.py +1335 -0
  513. vispy/visuals/windbarb.py +291 -0
  514. vispy/visuals/xyz_axis.py +34 -0
  515. vispy-0.14.0.dist-info/LICENSE.txt +36 -0
  516. vispy-0.14.0.dist-info/METADATA +218 -0
  517. vispy-0.14.0.dist-info/RECORD +519 -0
  518. vispy-0.14.0.dist-info/WHEEL +5 -0
  519. vispy-0.14.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,473 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -----------------------------------------------------------------------------
3
+ # Copyright (c) Vispy Development Team. All Rights Reserved.
4
+ # Distributed under the (new) BSD License. See LICENSE.txt for more info.
5
+ # -----------------------------------------------------------------------------
6
+ """Test utilities for comparing rendered results with expected image files.
7
+
8
+ Procedure for unit-testing with images:
9
+
10
+ 1. Run unit tests at least once; this initializes a git clone of
11
+ vispy/test-data in config['test_data_path']. This path is
12
+ `~/.vispy/test-data` unless the config variable has been modified.
13
+ The config file is located at `vispy/vispy/util/config.py`
14
+
15
+ 2. Run individual test scripts with the --vispy-audit flag:
16
+
17
+ $ python vispy/visuals/tests/test_ellipse.py --vispy-audit
18
+
19
+ Any failing tests will
20
+ display the test results, standard image, and the differences between the
21
+ two. If the test result is bad, then press (f)ail. If the test result is
22
+ good, then press (p)ass and the new image will be saved to the test-data
23
+ directory.
24
+
25
+ 3. After adding or changing test images, create a new commit:
26
+
27
+ $ cd ~/.vispy/test-data
28
+ $ git add ...
29
+ $ git commit -a
30
+
31
+ 4. Look up the most recent tag name from the `test_data_tag` variable in
32
+ get_test_data_repo() below. Increment the tag name by 1 in the function
33
+ and create a new tag in the test-data repository:
34
+
35
+ $ git tag test-data-NNN
36
+ $ git push --tags origin main
37
+
38
+ This tag is used to ensure that each vispy commit is linked to a specific
39
+ commit in the test-data repository. This makes it possible to push new
40
+ commits to the test-data repository without interfering with existing
41
+ tests, and also allows unit tests to continue working on older vispy
42
+ versions.
43
+
44
+ Finally, update the tag name in ``get_test_data_repo`` to the new name.
45
+
46
+ """
47
+
48
+ import time
49
+ import os
50
+ import sys
51
+ import inspect
52
+ import base64
53
+ from subprocess import check_call, CalledProcessError
54
+ import numpy as np
55
+
56
+ from http.client import HTTPConnection
57
+ from urllib.parse import urlencode
58
+
59
+ from .. import scene, config
60
+ from ..io import read_png, write_png
61
+ from ..gloo.util import _screenshot
62
+ from ..util import run_subprocess
63
+ from . import IS_CI
64
+
65
+
66
+ tester = None
67
+
68
+
69
+ def _get_tester():
70
+ global tester
71
+ if tester is None:
72
+ tester = ImageTester()
73
+ return tester
74
+
75
+
76
+ def assert_image_approved(image, standard_file, message=None, **kwargs):
77
+ """Check that an image test result matches a pre-approved standard.
78
+
79
+ If the result does not match, then the user can optionally invoke a GUI
80
+ to compare the images and decide whether to fail the test or save the new
81
+ image as the standard.
82
+
83
+ This function will automatically clone the test-data repository into
84
+ ~/.vispy/test-data. However, it is up to the user to ensure this repository
85
+ is kept up to date and to commit/push new images after they are saved.
86
+
87
+ Run the test with python <test-path> --vispy-audit-tests to bring up
88
+ the auditing GUI.
89
+
90
+ Parameters
91
+ ----------
92
+ image : (h, w, 4) ndarray or 'screenshot'
93
+ The test result to check
94
+ standard_file : str
95
+ The name of the approved test image to check against. This file name
96
+ is relative to the root of the vispy test-data repository and will
97
+ be automatically fetched.
98
+ message : str
99
+ A string description of the image. It is recommended to describe
100
+ specific features that an auditor should look for when deciding whether
101
+ to fail a test.
102
+
103
+ Extra keyword arguments are used to set the thresholds for automatic image
104
+ comparison (see ``assert_image_match()``).
105
+ """
106
+ if isinstance(image, str) and image == "screenshot":
107
+ image = _screenshot(alpha=True)
108
+ if message is None:
109
+ code = inspect.currentframe().f_back.f_code
110
+ message = "%s::%s" % (code.co_filename, code.co_name)
111
+
112
+ # Make sure we have a test data repo available, possibly invoking git
113
+ data_path = get_test_data_repo()
114
+
115
+ # Read the standard image if it exists
116
+ std_file = os.path.join(data_path, standard_file)
117
+ if not os.path.isfile(std_file):
118
+ std_image = None
119
+ else:
120
+ std_image = read_png(std_file)
121
+
122
+ # If the test image does not match, then we go to audit if requested.
123
+ try:
124
+ if image.shape != std_image.shape:
125
+ # Allow im1 to be an integer multiple larger than im2 to account
126
+ # for high-resolution displays
127
+ ims1 = np.array(image.shape).astype(float)
128
+ ims2 = np.array(std_image.shape).astype(float)
129
+ sr = ims1 / ims2
130
+ if (sr[0] != sr[1] or not np.allclose(sr, np.round(sr)) or
131
+ sr[0] < 1):
132
+ raise TypeError("Test result shape %s is not an integer factor"
133
+ " larger than standard image shape %s." %
134
+ (ims1, ims2))
135
+ sr = np.round(sr).astype(int)
136
+ image = downsample(image, sr[0], axis=(0, 1)).astype(image.dtype)
137
+
138
+ assert_image_match(image, std_image, **kwargs)
139
+ except Exception:
140
+ if standard_file in git_status(data_path):
141
+ print("\n\nWARNING: unit test failed against modified standard "
142
+ "image %s.\nTo revert this file, run `cd %s; git checkout "
143
+ "%s`\n" % (std_file, data_path, standard_file))
144
+ if config['audit_tests']:
145
+ sys.excepthook(*sys.exc_info())
146
+ _get_tester().test(image, std_image, message)
147
+ std_path = os.path.dirname(std_file)
148
+ print('Saving new standard image to "%s"' % std_file)
149
+ if not os.path.isdir(std_path):
150
+ os.makedirs(std_path)
151
+ write_png(std_file, image)
152
+ else:
153
+ if std_image is None:
154
+ raise Exception("Test standard %s does not exist." % std_file)
155
+ else:
156
+ if IS_CI:
157
+ _save_failed_test(image, std_image, standard_file)
158
+ raise
159
+
160
+
161
+ def assert_image_match(im1, im2, min_corr=0.9, px_threshold=50.,
162
+ px_count=None, max_px_diff=None, avg_px_diff=None,
163
+ img_diff=None):
164
+ """Check that two images match.
165
+
166
+ Images that differ in shape or dtype will fail unconditionally.
167
+ Further tests for similarity depend on the arguments supplied.
168
+
169
+ Parameters
170
+ ----------
171
+ im1 : (h, w, 4) ndarray
172
+ Test output image
173
+ im2 : (h, w, 4) ndarray
174
+ Test standard image
175
+ min_corr : float or None
176
+ Minimum allowed correlation coefficient between corresponding image
177
+ values (see numpy.corrcoef)
178
+ px_threshold : float
179
+ Minimum value difference at which two pixels are considered different
180
+ px_count : int or None
181
+ Maximum number of pixels that may differ
182
+ max_px_diff : float or None
183
+ Maximum allowed difference between pixels
184
+ avg_px_diff : float or None
185
+ Average allowed difference between pixels
186
+ img_diff : float or None
187
+ Maximum allowed summed difference between images
188
+
189
+ """
190
+ assert im1.ndim == 3
191
+ assert im1.shape[2] == 4
192
+ assert im1.dtype == im2.dtype
193
+
194
+ diff = im1.astype(float) - im2.astype(float)
195
+ if img_diff is not None:
196
+ assert np.abs(diff).sum() <= img_diff
197
+
198
+ pxdiff = diff.max(axis=2) # largest value difference per pixel
199
+ mask = np.abs(pxdiff) >= px_threshold
200
+ if px_count is not None:
201
+ assert mask.sum() <= px_count
202
+
203
+ masked_diff = diff[mask]
204
+ if max_px_diff is not None and masked_diff.size > 0:
205
+ assert masked_diff.max() <= max_px_diff
206
+ if avg_px_diff is not None and masked_diff.size > 0:
207
+ assert masked_diff.mean() <= avg_px_diff
208
+
209
+ if min_corr is not None:
210
+ with np.errstate(invalid='ignore'):
211
+ corr = np.corrcoef(im1.ravel(), im2.ravel())[0, 1]
212
+ assert corr >= min_corr
213
+
214
+
215
+ def _save_failed_test(data, expect, filename):
216
+ from ..io import _make_png
217
+ commit, error = run_subprocess(['git', 'rev-parse', 'HEAD'])
218
+ name = filename.split('/')
219
+ name.insert(-1, commit.strip())
220
+ filename = '/'.join(name)
221
+ host = 'data.vispy.org'
222
+
223
+ # concatenate data, expect, and diff into a single image
224
+ ds = data.shape
225
+ es = expect.shape
226
+
227
+ shape = (max(ds[0], es[0]) + 4, ds[1] + es[1] + 8 + max(ds[1], es[1]), 4)
228
+ img = np.empty(shape, dtype=np.ubyte)
229
+ img[..., :3] = 100
230
+ img[..., 3] = 255
231
+
232
+ img[2:2+ds[0], 2:2+ds[1], :ds[2]] = data
233
+ img[2:2+es[0], ds[1]+4:ds[1]+4+es[1], :es[2]] = expect
234
+
235
+ diff = make_diff_image(data, expect)
236
+ img[2:2+diff.shape[0], -diff.shape[1]-2:-2] = diff
237
+
238
+ png = _make_png(img)
239
+ conn = HTTPConnection(host)
240
+ req = urlencode({'name': filename,
241
+ 'data': base64.b64encode(png)})
242
+ conn.request('POST', '/upload.py', req)
243
+ response = conn.getresponse().read()
244
+ conn.close()
245
+ print("\nImage comparison failed. Test result: %s %s Expected result: "
246
+ "%s %s" % (data.shape, data.dtype, expect.shape, expect.dtype))
247
+ print("Uploaded to: \nhttp://%s/data/%s" % (host, filename))
248
+ if not response.startswith(b'OK'):
249
+ print("WARNING: Error uploading data to %s" % host)
250
+ print(response)
251
+
252
+
253
+ def make_diff_image(im1, im2):
254
+ """Return image array showing the differences between im1 and im2.
255
+
256
+ Handles images of different shape. Alpha channels are not compared.
257
+ """
258
+ ds = im1.shape
259
+ es = im2.shape
260
+
261
+ diff = np.empty((max(ds[0], es[0]), max(ds[1], es[1]), 4), dtype=int)
262
+ diff[..., :3] = 128
263
+ diff[..., 3] = 255
264
+ diff[:ds[0], :ds[1], :min(ds[2], 3)] += im1[..., :3]
265
+ diff[:es[0], :es[1], :min(es[2], 3)] -= im2[..., :3]
266
+ diff = np.clip(diff, 0, 255).astype(np.ubyte)
267
+ return diff
268
+
269
+
270
+ def downsample(data, n, axis=0):
271
+ """Downsample by averaging points together across axis.
272
+ If multiple axes are specified, runs once per axis.
273
+ """
274
+ if hasattr(axis, '__len__'):
275
+ if not hasattr(n, '__len__'):
276
+ n = [n]*len(axis)
277
+ for i in range(len(axis)):
278
+ data = downsample(data, n[i], axis[i])
279
+ return data
280
+
281
+ if n <= 1:
282
+ return data
283
+ nPts = int(data.shape[axis] / n)
284
+ s = list(data.shape)
285
+ s[axis] = nPts
286
+ s.insert(axis+1, n)
287
+ sl = [slice(None)] * data.ndim
288
+ sl[axis] = slice(0, nPts*n)
289
+ d1 = data[tuple(sl)]
290
+ d1.shape = tuple(s)
291
+ d2 = d1.mean(axis+1)
292
+
293
+ return d2
294
+
295
+
296
+ class ImageTester(scene.SceneCanvas):
297
+ """Graphical interface for auditing image comparison tests."""
298
+
299
+ def __init__(self):
300
+ self.grid = None
301
+ self.views = None
302
+ self.console = None
303
+ self.last_key = None
304
+
305
+ scene.SceneCanvas.__init__(self, size=(1000, 800))
306
+
307
+ self.bgcolor = (0.1, 0.1, 0.1, 1)
308
+ self.grid = self.central_widget.add_grid()
309
+ border = (0.3, 0.3, 0.3, 1)
310
+ self.views = (self.grid.add_view(row=0, col=0, border_color=border),
311
+ self.grid.add_view(row=0, col=1, border_color=border),
312
+ self.grid.add_view(row=0, col=2, border_color=border))
313
+ label_text = ['test output', 'standard', 'diff']
314
+ for i, v in enumerate(self.views):
315
+ v.camera = 'panzoom'
316
+ v.camera.aspect = 1
317
+ v.camera.flip = (False, True)
318
+ # unfreeze it to set the image and label on the view
319
+ # this is slightly hacky, but it is simpler than
320
+ # creating another class/storing as a dict or a tuple
321
+ v.unfreeze()
322
+ v.image = scene.Image(parent=v.scene)
323
+ v.label = scene.Text(label_text[i], parent=v, color='yellow',
324
+ anchor_x='left', anchor_y='top')
325
+ v.freeze()
326
+
327
+ self.views[1].camera.link(self.views[0].camera)
328
+ self.views[2].camera.link(self.views[0].camera)
329
+ self.console = scene.Console(text_color='white', border_color=border)
330
+ self.grid.add_widget(self.console, row=1, col=0, col_span=3)
331
+
332
+ def test(self, im1, im2, message):
333
+ self.show()
334
+ self.console.write('------------------')
335
+ self.console.write(message)
336
+ if im2 is None:
337
+ self.console.write('Image1: %s %s Image2: [no standard]' %
338
+ (im1.shape, im1.dtype))
339
+ im2 = np.zeros((1, 1, 3), dtype=np.ubyte)
340
+ else:
341
+ self.console.write('Image1: %s %s Image2: %s %s' %
342
+ (im1.shape, im1.dtype, im2.shape, im2.dtype))
343
+ self.console.write('(P)ass or (F)ail this test?')
344
+ self.views[0].image.set_data(im1)
345
+ self.views[1].image.set_data(im2)
346
+ diff = make_diff_image(im1, im2)
347
+
348
+ self.views[2].image.set_data(diff)
349
+ self.views[0].camera.set_range()
350
+
351
+ while True:
352
+ self.app.process_events()
353
+ if self.last_key is None:
354
+ pass
355
+ elif self.last_key.lower() == 'p':
356
+ self.console.write('PASS')
357
+ break
358
+ elif self.last_key.lower() in ('f', 'esc'):
359
+ self.console.write('FAIL')
360
+ raise Exception("User rejected test result.")
361
+ time.sleep(0.03)
362
+
363
+ for v in self.views:
364
+ v.image.set_data(np.zeros((1, 1, 3), dtype=np.ubyte))
365
+
366
+ def on_key_press(self, event):
367
+ self.last_key = event.key.name
368
+
369
+
370
+ def get_test_data_repo():
371
+ """Return the path to a git repository with the required commit checked
372
+ out.
373
+
374
+ If the repository does not exist, then it is cloned from
375
+ https://github.com/vispy/test-data. If the repository already exists
376
+ then the required commit is checked out.
377
+ """
378
+ # This tag marks the test-data commit that this version of vispy should
379
+ # be tested against. When adding or changing test images, create
380
+ # and push a new tag and update this variable.
381
+ test_data_tag = 'test-data-10'
382
+
383
+ data_path = config['test_data_path']
384
+ git_path = 'http://github.com/vispy/test-data'
385
+ gitbase = git_cmd_base(data_path)
386
+
387
+ if os.path.isdir(data_path):
388
+ # Already have a test-data repository to work with.
389
+
390
+ # Get the commit ID of test_data_tag. Do a fetch if necessary.
391
+ try:
392
+ tag_commit = git_commit_id(data_path, test_data_tag)
393
+ except NameError:
394
+ cmd = gitbase + ['fetch', '--tags', 'origin']
395
+ print(' '.join(cmd))
396
+ check_call(cmd)
397
+ try:
398
+ tag_commit = git_commit_id(data_path, test_data_tag)
399
+ except NameError:
400
+ raise Exception("Could not find tag '%s' in test-data repo at"
401
+ " %s" % (test_data_tag, data_path))
402
+ except Exception:
403
+ if not os.path.exists(os.path.join(data_path, '.git')):
404
+ raise Exception("Directory '%s' does not appear to be a git "
405
+ "repository. Please remove this directory." %
406
+ data_path)
407
+ else:
408
+ raise
409
+
410
+ # If HEAD is not the correct commit, then do a checkout
411
+ if git_commit_id(data_path, 'HEAD') != tag_commit:
412
+ print("Checking out test-data tag '%s'" % test_data_tag)
413
+ check_call(gitbase + ['checkout', test_data_tag])
414
+
415
+ else:
416
+ print("Attempting to create git clone of test data repo in %s.." %
417
+ data_path)
418
+
419
+ parent_path = os.path.split(data_path)[0]
420
+ if not os.path.isdir(parent_path):
421
+ os.makedirs(parent_path)
422
+
423
+ if IS_CI:
424
+ # Create a shallow clone of the test-data repository (to avoid
425
+ # downloading more data than is necessary)
426
+ os.makedirs(data_path)
427
+ cmds = [
428
+ gitbase + ['init'],
429
+ gitbase + ['remote', 'add', 'origin', git_path],
430
+ gitbase + ['fetch', '--tags', 'origin', test_data_tag,
431
+ '--depth=1'],
432
+ gitbase + ['checkout', '-b', 'main', 'FETCH_HEAD'],
433
+ ]
434
+ else:
435
+ # Create a full clone
436
+ cmds = [['git', 'clone', git_path, data_path]]
437
+
438
+ for cmd in cmds:
439
+ print(' '.join(cmd))
440
+ rval = check_call(cmd)
441
+ if rval == 0:
442
+ continue
443
+ raise RuntimeError("Test data path '%s' does not exist and could "
444
+ "not be created with git. Either create a git "
445
+ "clone of %s or set the test_data_path "
446
+ "variable to an existing clone." %
447
+ (data_path, git_path))
448
+
449
+ return data_path
450
+
451
+
452
+ def git_cmd_base(path):
453
+ return ['git', '--git-dir=%s/.git' % path, '--work-tree=%s' % path]
454
+
455
+
456
+ def git_status(path):
457
+ """Return a string listing all changes to the working tree in a git
458
+ repository.
459
+ """
460
+ cmd = git_cmd_base(path) + ['status', '--porcelain']
461
+ return run_subprocess(cmd, stderr=None, universal_newlines=True)[0]
462
+
463
+
464
+ def git_commit_id(path, ref):
465
+ """Return the commit id of *ref* in the git repository at *path*."""
466
+ cmd = git_cmd_base(path) + ['show', ref]
467
+ try:
468
+ output = run_subprocess(cmd, stderr=None, universal_newlines=True)[0]
469
+ except CalledProcessError:
470
+ raise NameError("Unknown git reference '%s'" % ref)
471
+ commit = output.split('\n')[0]
472
+ assert commit[:7] == 'commit '
473
+ return commit[7:]
@@ -0,0 +1,85 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -----------------------------------------------------------------------------
3
+ # Copyright (c) Vispy Development Team. All Rights Reserved.
4
+ # Distributed under the (new) BSD License. See LICENSE.txt for more info.
5
+ # -----------------------------------------------------------------------------
6
+ """Test utilities for comparing rendered arrays with expected array results."""
7
+
8
+ from typing import Optional, Any
9
+ import numpy as np
10
+ import pytest
11
+
12
+ try:
13
+ from numpy.typing import ArrayLike, DtypeLike
14
+ except ImportError:
15
+ ArrayLike = np.ndarray
16
+ DtypeLike = Any
17
+
18
+
19
+ def compare_render(
20
+ orig_data: ArrayLike,
21
+ rendered_data: ArrayLike,
22
+ previous_render: Optional[ArrayLike] = None,
23
+ atol: Optional[float] = 1.0
24
+ ):
25
+ """Compare an expected original array with the rendered result.
26
+
27
+ Parameters
28
+ ----------
29
+ orig_data
30
+ Expected output result array. This will be converted to an RGBA array
31
+ to be compared against the rendered data.
32
+ rendered_data
33
+ Actual rendered result as an RGBA 8-bit unsigned array.
34
+ previous_render
35
+ Previous instance of a render that the current render should not be
36
+ equal to.
37
+ atol
38
+ Absolute tolerance to be passed to
39
+ :func:`numpy.testing.assert_allclose`.
40
+
41
+ """
42
+ predicted = make_rgba(orig_data)
43
+ np.testing.assert_allclose(rendered_data.astype(float), predicted.astype(float), atol=atol)
44
+ if previous_render is not None:
45
+ # assert not allclose
46
+ pytest.raises(AssertionError, np.testing.assert_allclose,
47
+ rendered_data, previous_render, atol=10)
48
+
49
+
50
+ def max_for_dtype(input_dtype: DtypeLike):
51
+ """Get maximum value an image array should have for a specific dtype.
52
+
53
+ This is max int for each integer type or 1.0 for floating point types.
54
+
55
+ """
56
+ if np.issubdtype(input_dtype, np.integer):
57
+ max_val = np.iinfo(input_dtype).max
58
+ else:
59
+ max_val = 1.0
60
+ return max_val
61
+
62
+
63
+ def make_rgba(data_in: ArrayLike) -> ArrayLike:
64
+ """Convert any array to an RGBA array.
65
+
66
+ RGBA arrays have 3 dimensions where the last represents the channels. If
67
+ an Alpha channel needs to be added it will be made completely opaque.
68
+
69
+ Returns
70
+ -------
71
+ 3D RGBA unsigned 8-bit array
72
+
73
+ """
74
+ max_val = max_for_dtype(data_in.dtype)
75
+ if data_in.ndim == 3 and data_in.shape[-1] == 1:
76
+ data_in = data_in.squeeze()
77
+
78
+ if data_in.ndim == 2:
79
+ out = np.stack([data_in] * 4, axis=2)
80
+ out[:, :, 3] = max_val
81
+ elif data_in.shape[-1] == 3:
82
+ out = np.concatenate((data_in, np.ones((*data_in.shape[:2], 1)) * max_val), axis=2)
83
+ else:
84
+ out = data_in
85
+ return np.round((out.astype(np.float32) * 255 / max_val)).astype(np.uint8)
File without changes
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -----------------------------------------------------------------------------
3
+ # Copyright (c) Vispy Development Team. All Rights Reserved.
4
+ # Distributed under the (new) BSD License. See LICENSE.txt for more info.
5
+ # -----------------------------------------------------------------------------
6
+ from vispy.testing import (assert_in, assert_not_in, assert_is,
7
+ run_tests_if_main, assert_raises)
8
+
9
+
10
+ def test_testing():
11
+ """Test testing ports"""
12
+ assert_raises(AssertionError, assert_in, 'foo', 'bar')
13
+ assert_in('foo', 'foobar')
14
+ assert_raises(AssertionError, assert_not_in, 'foo', 'foobar')
15
+ assert_not_in('foo', 'bar')
16
+ assert_raises(AssertionError, assert_is, None, 0)
17
+ assert_is(None, None)
18
+
19
+
20
+ run_tests_if_main()
vispy/util/__init__.py ADDED
@@ -0,0 +1,17 @@
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
+
5
+ """Utilities for Vispy. A collection of modules that are used in
6
+ one or more Vispy sub-packages.
7
+ """
8
+
9
+ from .logs import logger, set_log_level, use_log_level # noqa
10
+ from .config import (config, sys_info, save_config, get_config_keys, # noqa
11
+ set_data_dir, _TempDir, _get_args) # noqa
12
+ from .fetching import load_data_file # noqa
13
+ from .frozen import Frozen # noqa
14
+ from . import fonts # noqa
15
+ from . import transforms # noqa
16
+ from .wrappers import use, run_subprocess # noqa
17
+ from .bunch import SimpleBunch # noqa
vispy/util/bunch.py ADDED
@@ -0,0 +1,15 @@
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
+
5
+
6
+ # Class adapted from mne-python
7
+
8
+ class SimpleBunch(dict):
9
+ """Container object for datasets: dictionnary-like object that
10
+ exposes its keys as attributes.
11
+ """
12
+
13
+ def __init__(self, **kwargs):
14
+ dict.__init__(self, kwargs)
15
+ self.__dict__ = self
@@ -0,0 +1,57 @@
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 os
5
+ from packaging.version import Version
6
+
7
+ from vispy.util import use_log_level
8
+
9
+
10
+ def has_matplotlib(version='1.2'):
11
+ """Determine if mpl is a usable version"""
12
+ try:
13
+ import matplotlib
14
+ except Exception:
15
+ has_mpl = False
16
+ else:
17
+ if Version(matplotlib.__version__) >= Version(version):
18
+ has_mpl = True
19
+ else:
20
+ has_mpl = False
21
+ return has_mpl
22
+
23
+
24
+ def has_skimage(version='0.11'):
25
+ """Determine if scikit-image is a usable version"""
26
+ try:
27
+ import skimage
28
+ except ImportError:
29
+ return False
30
+ sk_version = Version(skimage.__version__)
31
+ return sk_version >= Version(version)
32
+
33
+
34
+ def has_backend(backend, has=(), capable=(), out=()):
35
+ from ..app.backends import BACKENDMAP
36
+ using = os.getenv('_VISPY_TESTING_APP', None)
37
+ if using is not None and using != backend:
38
+ # e.g., we are on a 'pyglet' run but the test requires PyQt4
39
+ ret = (False,) if len(out) > 0 else False
40
+ for o in out:
41
+ ret += (None,)
42
+ return ret
43
+
44
+ # let's follow the standard code path
45
+ module_name = BACKENDMAP[backend.lower()][1]
46
+ with use_log_level('warning', print_msg=False):
47
+ mod = __import__('app.backends.%s' % module_name, globals(), level=2)
48
+ mod = getattr(mod.backends, module_name)
49
+ good = mod.testable
50
+ for h in has:
51
+ good = (good and getattr(mod, 'has_%s' % h))
52
+ for cap in capable:
53
+ good = (good and mod.capability[cap])
54
+ ret = (good,) if len(out) > 0 else good
55
+ for o in out:
56
+ ret += (getattr(mod, o),)
57
+ return ret