vispy 0.15.0__cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.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 (521) 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 +1003 -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 +1213 -0
  45. vispy/color/tests/__init__.py +0 -0
  46. vispy/color/tests/test_color.py +378 -0
  47. vispy/conftest.py +12 -0
  48. vispy/ext/__init__.py +0 -0
  49. vispy/ext/cocoapy.py +1522 -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 +162 -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 +700 -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 +594 -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 +568 -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 +1824 -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 +1046 -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 +105 -0
  274. vispy/scene/cameras/base_camera.py +551 -0
  275. vispy/scene/cameras/fly.py +474 -0
  276. vispy/scene/cameras/magnify.py +163 -0
  277. vispy/scene/cameras/panzoom.py +311 -0
  278. vispy/scene/cameras/perspective.py +338 -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 +183 -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 +448 -0
  306. vispy/testing/_testing.py +416 -0
  307. vispy/testing/image_tester.py +494 -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 +32 -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 +21 -0
  377. vispy/visuals/__init__.py +50 -0
  378. vispy/visuals/_scalable_textures.py +487 -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 +162 -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 +801 -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 +161 -0
  430. vispy/visuals/gridmesh.py +98 -0
  431. vispy/visuals/histogram.py +58 -0
  432. vispy/visuals/image.py +701 -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 +819 -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_gridlines.py +30 -0
  477. vispy/visuals/tests/test_histogram.py +24 -0
  478. vispy/visuals/tests/test_image.py +392 -0
  479. vispy/visuals/tests/test_image_complex.py +36 -0
  480. vispy/visuals/tests/test_infinite_line.py +53 -0
  481. vispy/visuals/tests/test_instanced_mesh.py +50 -0
  482. vispy/visuals/tests/test_isosurface.py +22 -0
  483. vispy/visuals/tests/test_linear_region.py +152 -0
  484. vispy/visuals/tests/test_markers.py +54 -0
  485. vispy/visuals/tests/test_mesh.py +261 -0
  486. vispy/visuals/tests/test_mesh_normals.py +218 -0
  487. vispy/visuals/tests/test_polygon.py +112 -0
  488. vispy/visuals/tests/test_rectangle.py +163 -0
  489. vispy/visuals/tests/test_regular_polygon.py +111 -0
  490. vispy/visuals/tests/test_scalable_textures.py +196 -0
  491. vispy/visuals/tests/test_sdf.py +73 -0
  492. vispy/visuals/tests/test_spectrogram.py +42 -0
  493. vispy/visuals/tests/test_surface_plot.py +57 -0
  494. vispy/visuals/tests/test_text.py +95 -0
  495. vispy/visuals/tests/test_volume.py +542 -0
  496. vispy/visuals/tests/test_windbarb.py +33 -0
  497. vispy/visuals/text/__init__.py +7 -0
  498. vispy/visuals/text/_sdf_cpu.cpython-313-aarch64-linux-gnu.so +0 -0
  499. vispy/visuals/text/_sdf_cpu.pyx +112 -0
  500. vispy/visuals/text/_sdf_gpu.py +316 -0
  501. vispy/visuals/text/text.py +675 -0
  502. vispy/visuals/transforms/__init__.py +34 -0
  503. vispy/visuals/transforms/_util.py +191 -0
  504. vispy/visuals/transforms/base_transform.py +233 -0
  505. vispy/visuals/transforms/chain.py +300 -0
  506. vispy/visuals/transforms/interactive.py +98 -0
  507. vispy/visuals/transforms/linear.py +564 -0
  508. vispy/visuals/transforms/nonlinear.py +398 -0
  509. vispy/visuals/transforms/tests/__init__.py +0 -0
  510. vispy/visuals/transforms/tests/test_transforms.py +243 -0
  511. vispy/visuals/transforms/transform_system.py +339 -0
  512. vispy/visuals/tube.py +173 -0
  513. vispy/visuals/visual.py +923 -0
  514. vispy/visuals/volume.py +1366 -0
  515. vispy/visuals/windbarb.py +291 -0
  516. vispy/visuals/xyz_axis.py +34 -0
  517. vispy-0.15.0.dist-info/METADATA +243 -0
  518. vispy-0.15.0.dist-info/RECORD +521 -0
  519. vispy-0.15.0.dist-info/WHEEL +6 -0
  520. vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
  521. vispy-0.15.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,494 @@
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
+ # TODO: check for more properties of image
161
+ def assert_image_reasonable(image):
162
+ """Check that an image is reasonable.
163
+
164
+ The given image is checked to not be completely black or white.
165
+
166
+ Parameters:
167
+ -----------
168
+ image : (h, w, 4) ndarray or 'screenshot'
169
+ The test result to check
170
+ """
171
+ if isinstance(image, str) and image == "screenshot":
172
+ image = _screenshot(alpha=True)
173
+
174
+ # check dimensions
175
+ assert image.ndim == 3
176
+ assert image.shape[2] == 4
177
+
178
+ # check white or black
179
+ assert image[...,:3].max() > 0
180
+ assert image[...,:3].min() < 255
181
+
182
+ def assert_image_match(im1, im2, min_corr=0.9, px_threshold=50.,
183
+ px_count=None, max_px_diff=None, avg_px_diff=None,
184
+ img_diff=None):
185
+ """Check that two images match.
186
+
187
+ Images that differ in shape or dtype will fail unconditionally.
188
+ Further tests for similarity depend on the arguments supplied.
189
+
190
+ Parameters
191
+ ----------
192
+ im1 : (h, w, 4) ndarray
193
+ Test output image
194
+ im2 : (h, w, 4) ndarray
195
+ Test standard image
196
+ min_corr : float or None
197
+ Minimum allowed correlation coefficient between corresponding image
198
+ values (see numpy.corrcoef)
199
+ px_threshold : float
200
+ Minimum value difference at which two pixels are considered different
201
+ px_count : int or None
202
+ Maximum number of pixels that may differ
203
+ max_px_diff : float or None
204
+ Maximum allowed difference between pixels
205
+ avg_px_diff : float or None
206
+ Average allowed difference between pixels
207
+ img_diff : float or None
208
+ Maximum allowed summed difference between images
209
+
210
+ """
211
+ assert im1.ndim == 3
212
+ assert im1.shape[2] == 4
213
+ assert im1.dtype == im2.dtype
214
+
215
+ diff = im1.astype(float) - im2.astype(float)
216
+ if img_diff is not None:
217
+ assert np.abs(diff).sum() <= img_diff
218
+
219
+ pxdiff = diff.max(axis=2) # largest value difference per pixel
220
+ mask = np.abs(pxdiff) >= px_threshold
221
+ if px_count is not None:
222
+ assert mask.sum() <= px_count
223
+
224
+ masked_diff = diff[mask]
225
+ if max_px_diff is not None and masked_diff.size > 0:
226
+ assert masked_diff.max() <= max_px_diff
227
+ if avg_px_diff is not None and masked_diff.size > 0:
228
+ assert masked_diff.mean() <= avg_px_diff
229
+
230
+ if min_corr is not None:
231
+ with np.errstate(invalid='ignore'):
232
+ corr = np.corrcoef(im1.ravel(), im2.ravel())[0, 1]
233
+ assert corr >= min_corr
234
+
235
+
236
+ def _save_failed_test(data, expect, filename):
237
+ from ..io import _make_png
238
+ commit, error = run_subprocess(['git', 'rev-parse', 'HEAD'])
239
+ name = filename.split('/')
240
+ name.insert(-1, commit.strip())
241
+ filename = '/'.join(name)
242
+ host = 'data.vispy.org'
243
+
244
+ # concatenate data, expect, and diff into a single image
245
+ ds = data.shape
246
+ es = expect.shape
247
+
248
+ shape = (max(ds[0], es[0]) + 4, ds[1] + es[1] + 8 + max(ds[1], es[1]), 4)
249
+ img = np.empty(shape, dtype=np.ubyte)
250
+ img[..., :3] = 100
251
+ img[..., 3] = 255
252
+
253
+ img[2:2+ds[0], 2:2+ds[1], :ds[2]] = data
254
+ img[2:2+es[0], ds[1]+4:ds[1]+4+es[1], :es[2]] = expect
255
+
256
+ diff = make_diff_image(data, expect)
257
+ img[2:2+diff.shape[0], -diff.shape[1]-2:-2] = diff
258
+
259
+ png = _make_png(img)
260
+ conn = HTTPConnection(host)
261
+ req = urlencode({'name': filename,
262
+ 'data': base64.b64encode(png)})
263
+ conn.request('POST', '/upload.py', req)
264
+ response = conn.getresponse().read()
265
+ conn.close()
266
+ print("\nImage comparison failed. Test result: %s %s Expected result: "
267
+ "%s %s" % (data.shape, data.dtype, expect.shape, expect.dtype))
268
+ print("Uploaded to: \nhttp://%s/data/%s" % (host, filename))
269
+ if not response.startswith(b'OK'):
270
+ print("WARNING: Error uploading data to %s" % host)
271
+ print(response)
272
+
273
+
274
+ def make_diff_image(im1, im2):
275
+ """Return image array showing the differences between im1 and im2.
276
+
277
+ Handles images of different shape. Alpha channels are not compared.
278
+ """
279
+ ds = im1.shape
280
+ es = im2.shape
281
+
282
+ diff = np.empty((max(ds[0], es[0]), max(ds[1], es[1]), 4), dtype=int)
283
+ diff[..., :3] = 128
284
+ diff[..., 3] = 255
285
+ diff[:ds[0], :ds[1], :min(ds[2], 3)] += im1[..., :3]
286
+ diff[:es[0], :es[1], :min(es[2], 3)] -= im2[..., :3]
287
+ diff = np.clip(diff, 0, 255).astype(np.ubyte)
288
+ return diff
289
+
290
+
291
+ def downsample(data, n, axis=0):
292
+ """Downsample by averaging points together across axis.
293
+ If multiple axes are specified, runs once per axis.
294
+ """
295
+ if hasattr(axis, '__len__'):
296
+ if not hasattr(n, '__len__'):
297
+ n = [n]*len(axis)
298
+ for i in range(len(axis)):
299
+ data = downsample(data, n[i], axis[i])
300
+ return data
301
+
302
+ if n <= 1:
303
+ return data
304
+ nPts = int(data.shape[axis] / n)
305
+ s = list(data.shape)
306
+ s[axis] = nPts
307
+ s.insert(axis+1, n)
308
+ sl = [slice(None)] * data.ndim
309
+ sl[axis] = slice(0, nPts*n)
310
+ d1 = data[tuple(sl)]
311
+ d1.shape = tuple(s)
312
+ d2 = d1.mean(axis+1)
313
+
314
+ return d2
315
+
316
+
317
+ class ImageTester(scene.SceneCanvas):
318
+ """Graphical interface for auditing image comparison tests."""
319
+
320
+ def __init__(self):
321
+ self.grid = None
322
+ self.views = None
323
+ self.console = None
324
+ self.last_key = None
325
+
326
+ scene.SceneCanvas.__init__(self, size=(1000, 800))
327
+
328
+ self.bgcolor = (0.1, 0.1, 0.1, 1)
329
+ self.grid = self.central_widget.add_grid()
330
+ border = (0.3, 0.3, 0.3, 1)
331
+ self.views = (self.grid.add_view(row=0, col=0, border_color=border),
332
+ self.grid.add_view(row=0, col=1, border_color=border),
333
+ self.grid.add_view(row=0, col=2, border_color=border))
334
+ label_text = ['test output', 'standard', 'diff']
335
+ for i, v in enumerate(self.views):
336
+ v.camera = 'panzoom'
337
+ v.camera.aspect = 1
338
+ v.camera.flip = (False, True)
339
+ # unfreeze it to set the image and label on the view
340
+ # this is slightly hacky, but it is simpler than
341
+ # creating another class/storing as a dict or a tuple
342
+ v.unfreeze()
343
+ v.image = scene.Image(parent=v.scene)
344
+ v.label = scene.Text(label_text[i], parent=v, color='yellow',
345
+ anchor_x='left', anchor_y='top')
346
+ v.freeze()
347
+
348
+ self.views[1].camera.link(self.views[0].camera)
349
+ self.views[2].camera.link(self.views[0].camera)
350
+ self.console = scene.Console(text_color='white', border_color=border)
351
+ self.grid.add_widget(self.console, row=1, col=0, col_span=3)
352
+
353
+ def test(self, im1, im2, message):
354
+ self.show()
355
+ self.console.write('------------------')
356
+ self.console.write(message)
357
+ if im2 is None:
358
+ self.console.write('Image1: %s %s Image2: [no standard]' %
359
+ (im1.shape, im1.dtype))
360
+ im2 = np.zeros((1, 1, 3), dtype=np.ubyte)
361
+ else:
362
+ self.console.write('Image1: %s %s Image2: %s %s' %
363
+ (im1.shape, im1.dtype, im2.shape, im2.dtype))
364
+ self.console.write('(P)ass or (F)ail this test?')
365
+ self.views[0].image.set_data(im1)
366
+ self.views[1].image.set_data(im2)
367
+ diff = make_diff_image(im1, im2)
368
+
369
+ self.views[2].image.set_data(diff)
370
+ self.views[0].camera.set_range()
371
+
372
+ while True:
373
+ self.app.process_events()
374
+ if self.last_key is None:
375
+ pass
376
+ elif self.last_key.lower() == 'p':
377
+ self.console.write('PASS')
378
+ break
379
+ elif self.last_key.lower() in ('f', 'esc'):
380
+ self.console.write('FAIL')
381
+ raise Exception("User rejected test result.")
382
+ time.sleep(0.03)
383
+
384
+ for v in self.views:
385
+ v.image.set_data(np.zeros((1, 1, 3), dtype=np.ubyte))
386
+
387
+ def on_key_press(self, event):
388
+ self.last_key = event.key.name
389
+
390
+
391
+ def get_test_data_repo():
392
+ """Return the path to a git repository with the required commit checked
393
+ out.
394
+
395
+ If the repository does not exist, then it is cloned from
396
+ https://github.com/vispy/test-data. If the repository already exists
397
+ then the required commit is checked out.
398
+ """
399
+ # This tag marks the test-data commit that this version of vispy should
400
+ # be tested against. When adding or changing test images, create
401
+ # and push a new tag and update this variable.
402
+ test_data_tag = 'test-data-10'
403
+
404
+ data_path = config['test_data_path']
405
+ git_path = 'http://github.com/vispy/test-data'
406
+ gitbase = git_cmd_base(data_path)
407
+
408
+ if os.path.isdir(data_path):
409
+ # Already have a test-data repository to work with.
410
+
411
+ # Get the commit ID of test_data_tag. Do a fetch if necessary.
412
+ try:
413
+ tag_commit = git_commit_id(data_path, test_data_tag)
414
+ except NameError:
415
+ cmd = gitbase + ['fetch', '--tags', 'origin']
416
+ print(' '.join(cmd))
417
+ check_call(cmd)
418
+ try:
419
+ tag_commit = git_commit_id(data_path, test_data_tag)
420
+ except NameError:
421
+ raise Exception("Could not find tag '%s' in test-data repo at"
422
+ " %s" % (test_data_tag, data_path))
423
+ except Exception:
424
+ if not os.path.exists(os.path.join(data_path, '.git')):
425
+ raise Exception("Directory '%s' does not appear to be a git "
426
+ "repository. Please remove this directory." %
427
+ data_path)
428
+ else:
429
+ raise
430
+
431
+ # If HEAD is not the correct commit, then do a checkout
432
+ if git_commit_id(data_path, 'HEAD') != tag_commit:
433
+ print("Checking out test-data tag '%s'" % test_data_tag)
434
+ check_call(gitbase + ['checkout', test_data_tag])
435
+
436
+ else:
437
+ print("Attempting to create git clone of test data repo in %s.." %
438
+ data_path)
439
+
440
+ parent_path = os.path.split(data_path)[0]
441
+ if not os.path.isdir(parent_path):
442
+ os.makedirs(parent_path)
443
+
444
+ if IS_CI:
445
+ # Create a shallow clone of the test-data repository (to avoid
446
+ # downloading more data than is necessary)
447
+ os.makedirs(data_path)
448
+ cmds = [
449
+ gitbase + ['init'],
450
+ gitbase + ['remote', 'add', 'origin', git_path],
451
+ gitbase + ['fetch', '--tags', 'origin', test_data_tag,
452
+ '--depth=1'],
453
+ gitbase + ['checkout', '-b', 'main', 'FETCH_HEAD'],
454
+ ]
455
+ else:
456
+ # Create a full clone
457
+ cmds = [['git', 'clone', git_path, data_path]]
458
+
459
+ for cmd in cmds:
460
+ print(' '.join(cmd))
461
+ rval = check_call(cmd)
462
+ if rval == 0:
463
+ continue
464
+ raise RuntimeError("Test data path '%s' does not exist and could "
465
+ "not be created with git. Either create a git "
466
+ "clone of %s or set the test_data_path "
467
+ "variable to an existing clone." %
468
+ (data_path, git_path))
469
+
470
+ return data_path
471
+
472
+
473
+ def git_cmd_base(path):
474
+ return ['git', '--git-dir=%s/.git' % path, '--work-tree=%s' % path]
475
+
476
+
477
+ def git_status(path):
478
+ """Return a string listing all changes to the working tree in a git
479
+ repository.
480
+ """
481
+ cmd = git_cmd_base(path) + ['status', '--porcelain']
482
+ return run_subprocess(cmd, stderr=None, universal_newlines=True)[0]
483
+
484
+
485
+ def git_commit_id(path, ref):
486
+ """Return the commit id of *ref* in the git repository at *path*."""
487
+ cmd = git_cmd_base(path) + ['show', ref]
488
+ try:
489
+ output = run_subprocess(cmd, stderr=None, universal_newlines=True)[0]
490
+ except CalledProcessError:
491
+ raise NameError("Unknown git reference '%s'" % ref)
492
+ commit = output.split('\n')[0]
493
+ assert commit[:7] == 'commit '
494
+ 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,32 @@
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
18
+
19
+ from typing import Optional
20
+
21
+ import numpy as np
22
+
23
+ # `copy` keyword semantics changed in NumPy 2.0
24
+ # this maintains compatibility with older versions
25
+ # if/when NumPy 2.0 becomes the minimum version, we can remove this
26
+ # we don't worry about early dev versions of NumPy 2.0 (that may or may not have the kwarg) here
27
+ # see:
28
+ # https://numpy.org/devdocs/numpy_2_0_migration_guide.html#adapting-to-changes-in-the-copy-keyword
29
+ # https://github.com/scipy/scipy/pull/20172
30
+ np_copy_if_needed: Optional[bool] = None
31
+ if np.lib.NumpyVersion(np.__version__) < "1.28.0":
32
+ np_copy_if_needed = False
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