warp-lang 1.9.0__py3-none-win_amd64.whl → 1.10.0rc2__py3-none-win_amd64.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 warp-lang might be problematic. Click here for more details.

Files changed (350) hide show
  1. warp/__init__.py +301 -287
  2. warp/__init__.pyi +2220 -313
  3. warp/_src/__init__.py +14 -0
  4. warp/_src/autograd.py +1075 -0
  5. warp/_src/build.py +618 -0
  6. warp/_src/build_dll.py +640 -0
  7. warp/{builtins.py → _src/builtins.py} +1497 -226
  8. warp/_src/codegen.py +4359 -0
  9. warp/{config.py → _src/config.py} +178 -169
  10. warp/_src/constants.py +57 -0
  11. warp/_src/context.py +8294 -0
  12. warp/_src/dlpack.py +462 -0
  13. warp/_src/fabric.py +355 -0
  14. warp/_src/fem/__init__.py +14 -0
  15. warp/_src/fem/adaptivity.py +508 -0
  16. warp/_src/fem/cache.py +687 -0
  17. warp/_src/fem/dirichlet.py +188 -0
  18. warp/{fem → _src/fem}/domain.py +40 -30
  19. warp/_src/fem/field/__init__.py +131 -0
  20. warp/_src/fem/field/field.py +701 -0
  21. warp/{fem → _src/fem}/field/nodal_field.py +30 -15
  22. warp/{fem → _src/fem}/field/restriction.py +1 -1
  23. warp/{fem → _src/fem}/field/virtual.py +53 -27
  24. warp/_src/fem/geometry/__init__.py +32 -0
  25. warp/{fem → _src/fem}/geometry/adaptive_nanogrid.py +77 -163
  26. warp/_src/fem/geometry/closest_point.py +97 -0
  27. warp/{fem → _src/fem}/geometry/deformed_geometry.py +14 -22
  28. warp/{fem → _src/fem}/geometry/element.py +32 -10
  29. warp/{fem → _src/fem}/geometry/geometry.py +48 -20
  30. warp/{fem → _src/fem}/geometry/grid_2d.py +12 -23
  31. warp/{fem → _src/fem}/geometry/grid_3d.py +12 -23
  32. warp/{fem → _src/fem}/geometry/hexmesh.py +40 -63
  33. warp/{fem → _src/fem}/geometry/nanogrid.py +255 -248
  34. warp/{fem → _src/fem}/geometry/partition.py +121 -63
  35. warp/{fem → _src/fem}/geometry/quadmesh.py +26 -45
  36. warp/{fem → _src/fem}/geometry/tetmesh.py +40 -63
  37. warp/{fem → _src/fem}/geometry/trimesh.py +26 -45
  38. warp/{fem → _src/fem}/integrate.py +164 -158
  39. warp/_src/fem/linalg.py +383 -0
  40. warp/_src/fem/operator.py +396 -0
  41. warp/_src/fem/polynomial.py +229 -0
  42. warp/{fem → _src/fem}/quadrature/pic_quadrature.py +15 -20
  43. warp/{fem → _src/fem}/quadrature/quadrature.py +95 -47
  44. warp/_src/fem/space/__init__.py +248 -0
  45. warp/{fem → _src/fem}/space/basis_function_space.py +20 -11
  46. warp/_src/fem/space/basis_space.py +679 -0
  47. warp/{fem → _src/fem}/space/dof_mapper.py +3 -3
  48. warp/{fem → _src/fem}/space/function_space.py +14 -13
  49. warp/{fem → _src/fem}/space/grid_2d_function_space.py +4 -7
  50. warp/{fem → _src/fem}/space/grid_3d_function_space.py +4 -4
  51. warp/{fem → _src/fem}/space/hexmesh_function_space.py +4 -10
  52. warp/{fem → _src/fem}/space/nanogrid_function_space.py +3 -9
  53. warp/{fem → _src/fem}/space/partition.py +117 -60
  54. warp/{fem → _src/fem}/space/quadmesh_function_space.py +4 -10
  55. warp/{fem → _src/fem}/space/restriction.py +66 -33
  56. warp/_src/fem/space/shape/__init__.py +152 -0
  57. warp/{fem → _src/fem}/space/shape/cube_shape_function.py +9 -9
  58. warp/{fem → _src/fem}/space/shape/shape_function.py +8 -9
  59. warp/{fem → _src/fem}/space/shape/square_shape_function.py +6 -6
  60. warp/{fem → _src/fem}/space/shape/tet_shape_function.py +3 -3
  61. warp/{fem → _src/fem}/space/shape/triangle_shape_function.py +3 -3
  62. warp/{fem → _src/fem}/space/tetmesh_function_space.py +3 -9
  63. warp/_src/fem/space/topology.py +459 -0
  64. warp/{fem → _src/fem}/space/trimesh_function_space.py +3 -9
  65. warp/_src/fem/types.py +112 -0
  66. warp/_src/fem/utils.py +486 -0
  67. warp/_src/jax.py +186 -0
  68. warp/_src/jax_experimental/__init__.py +14 -0
  69. warp/_src/jax_experimental/custom_call.py +387 -0
  70. warp/_src/jax_experimental/ffi.py +1284 -0
  71. warp/_src/jax_experimental/xla_ffi.py +656 -0
  72. warp/_src/marching_cubes.py +708 -0
  73. warp/_src/math.py +414 -0
  74. warp/_src/optim/__init__.py +14 -0
  75. warp/_src/optim/adam.py +163 -0
  76. warp/_src/optim/linear.py +1606 -0
  77. warp/_src/optim/sgd.py +112 -0
  78. warp/_src/paddle.py +406 -0
  79. warp/_src/render/__init__.py +14 -0
  80. warp/_src/render/imgui_manager.py +289 -0
  81. warp/_src/render/render_opengl.py +3636 -0
  82. warp/_src/render/render_usd.py +937 -0
  83. warp/_src/render/utils.py +160 -0
  84. warp/_src/sparse.py +2716 -0
  85. warp/_src/tape.py +1206 -0
  86. warp/{thirdparty → _src/thirdparty}/unittest_parallel.py +9 -2
  87. warp/_src/torch.py +391 -0
  88. warp/_src/types.py +5870 -0
  89. warp/_src/utils.py +1693 -0
  90. warp/autograd.py +12 -1054
  91. warp/bin/warp-clang.dll +0 -0
  92. warp/bin/warp.dll +0 -0
  93. warp/build.py +8 -588
  94. warp/build_dll.py +6 -471
  95. warp/codegen.py +6 -4246
  96. warp/constants.py +6 -39
  97. warp/context.py +12 -7851
  98. warp/dlpack.py +6 -444
  99. warp/examples/distributed/example_jacobi_mpi.py +4 -5
  100. warp/examples/fem/example_adaptive_grid.py +1 -1
  101. warp/examples/fem/example_apic_fluid.py +1 -1
  102. warp/examples/fem/example_burgers.py +8 -8
  103. warp/examples/fem/example_diffusion.py +1 -1
  104. warp/examples/fem/example_distortion_energy.py +1 -1
  105. warp/examples/fem/example_mixed_elasticity.py +2 -2
  106. warp/examples/fem/example_navier_stokes.py +1 -1
  107. warp/examples/fem/example_nonconforming_contact.py +7 -7
  108. warp/examples/fem/example_stokes.py +1 -1
  109. warp/examples/fem/example_stokes_transfer.py +1 -1
  110. warp/examples/fem/utils.py +2 -2
  111. warp/examples/interop/example_jax_callable.py +1 -1
  112. warp/examples/interop/example_jax_ffi_callback.py +1 -1
  113. warp/examples/interop/example_jax_kernel.py +3 -2
  114. warp/examples/tile/example_tile_mcgp.py +191 -0
  115. warp/fabric.py +6 -337
  116. warp/fem/__init__.py +159 -97
  117. warp/fem/adaptivity.py +7 -489
  118. warp/fem/cache.py +9 -648
  119. warp/fem/dirichlet.py +6 -184
  120. warp/fem/field/__init__.py +8 -109
  121. warp/fem/field/field.py +7 -652
  122. warp/fem/geometry/__init__.py +7 -18
  123. warp/fem/geometry/closest_point.py +11 -77
  124. warp/fem/linalg.py +18 -366
  125. warp/fem/operator.py +11 -369
  126. warp/fem/polynomial.py +9 -209
  127. warp/fem/space/__init__.py +5 -211
  128. warp/fem/space/basis_space.py +6 -662
  129. warp/fem/space/shape/__init__.py +41 -118
  130. warp/fem/space/topology.py +6 -437
  131. warp/fem/types.py +6 -81
  132. warp/fem/utils.py +11 -444
  133. warp/jax.py +8 -165
  134. warp/jax_experimental/__init__.py +14 -1
  135. warp/jax_experimental/custom_call.py +8 -342
  136. warp/jax_experimental/ffi.py +17 -853
  137. warp/jax_experimental/xla_ffi.py +5 -596
  138. warp/marching_cubes.py +5 -689
  139. warp/math.py +16 -393
  140. warp/native/array.h +385 -37
  141. warp/native/builtin.h +316 -39
  142. warp/native/bvh.cpp +43 -9
  143. warp/native/bvh.cu +62 -27
  144. warp/native/bvh.h +310 -309
  145. warp/native/clang/clang.cpp +102 -97
  146. warp/native/coloring.cpp +0 -1
  147. warp/native/crt.h +208 -0
  148. warp/native/exports.h +156 -0
  149. warp/native/hashgrid.cu +2 -0
  150. warp/native/intersect.h +24 -1
  151. warp/native/intersect_tri.h +44 -35
  152. warp/native/mat.h +1456 -276
  153. warp/native/mesh.cpp +4 -4
  154. warp/native/mesh.cu +4 -2
  155. warp/native/mesh.h +176 -61
  156. warp/native/quat.h +0 -52
  157. warp/native/scan.cu +2 -0
  158. warp/native/sort.cu +22 -13
  159. warp/native/sort.h +2 -0
  160. warp/native/sparse.cu +7 -3
  161. warp/native/spatial.h +12 -0
  162. warp/native/tile.h +837 -70
  163. warp/native/tile_radix_sort.h +1 -1
  164. warp/native/tile_reduce.h +394 -46
  165. warp/native/tile_scan.h +4 -4
  166. warp/native/vec.h +469 -53
  167. warp/native/version.h +23 -0
  168. warp/native/volume.cpp +1 -1
  169. warp/native/volume.cu +1 -0
  170. warp/native/volume.h +1 -1
  171. warp/native/volume_builder.cu +2 -0
  172. warp/native/warp.cpp +60 -32
  173. warp/native/warp.cu +313 -201
  174. warp/native/warp.h +14 -11
  175. warp/optim/__init__.py +6 -3
  176. warp/optim/adam.py +6 -145
  177. warp/optim/linear.py +14 -1585
  178. warp/optim/sgd.py +6 -94
  179. warp/paddle.py +6 -388
  180. warp/render/__init__.py +8 -4
  181. warp/render/imgui_manager.py +7 -267
  182. warp/render/render_opengl.py +6 -3616
  183. warp/render/render_usd.py +6 -918
  184. warp/render/utils.py +6 -142
  185. warp/sparse.py +37 -2563
  186. warp/tape.py +6 -1188
  187. warp/tests/__main__.py +1 -1
  188. warp/tests/cuda/test_async.py +4 -4
  189. warp/tests/cuda/test_conditional_captures.py +1 -1
  190. warp/tests/cuda/test_multigpu.py +1 -1
  191. warp/tests/cuda/test_streams.py +58 -1
  192. warp/tests/geometry/test_bvh.py +157 -22
  193. warp/tests/geometry/test_hash_grid.py +38 -0
  194. warp/tests/geometry/test_marching_cubes.py +0 -1
  195. warp/tests/geometry/test_mesh.py +5 -3
  196. warp/tests/geometry/test_mesh_query_aabb.py +5 -12
  197. warp/tests/geometry/test_mesh_query_point.py +5 -2
  198. warp/tests/geometry/test_mesh_query_ray.py +15 -3
  199. warp/tests/geometry/test_volume_write.py +5 -5
  200. warp/tests/interop/test_dlpack.py +14 -14
  201. warp/tests/interop/test_jax.py +1382 -79
  202. warp/tests/interop/test_paddle.py +1 -1
  203. warp/tests/test_adam.py +0 -1
  204. warp/tests/test_arithmetic.py +9 -9
  205. warp/tests/test_array.py +529 -100
  206. warp/tests/test_array_reduce.py +3 -3
  207. warp/tests/test_atomic.py +12 -8
  208. warp/tests/test_atomic_bitwise.py +209 -0
  209. warp/tests/test_atomic_cas.py +4 -4
  210. warp/tests/test_bool.py +2 -2
  211. warp/tests/test_builtins_resolution.py +5 -571
  212. warp/tests/test_codegen.py +34 -15
  213. warp/tests/test_conditional.py +1 -1
  214. warp/tests/test_context.py +6 -6
  215. warp/tests/test_copy.py +242 -161
  216. warp/tests/test_ctypes.py +3 -3
  217. warp/tests/test_devices.py +24 -2
  218. warp/tests/test_examples.py +16 -84
  219. warp/tests/test_fabricarray.py +35 -35
  220. warp/tests/test_fast_math.py +0 -2
  221. warp/tests/test_fem.py +60 -14
  222. warp/tests/test_fixedarray.py +3 -3
  223. warp/tests/test_func.py +8 -5
  224. warp/tests/test_generics.py +1 -1
  225. warp/tests/test_indexedarray.py +24 -24
  226. warp/tests/test_intersect.py +39 -9
  227. warp/tests/test_large.py +1 -1
  228. warp/tests/test_lerp.py +3 -1
  229. warp/tests/test_linear_solvers.py +1 -1
  230. warp/tests/test_map.py +49 -4
  231. warp/tests/test_mat.py +52 -62
  232. warp/tests/test_mat_constructors.py +4 -5
  233. warp/tests/test_mat_lite.py +1 -1
  234. warp/tests/test_mat_scalar_ops.py +121 -121
  235. warp/tests/test_math.py +34 -0
  236. warp/tests/test_module_aot.py +4 -4
  237. warp/tests/test_modules_lite.py +28 -2
  238. warp/tests/test_print.py +11 -11
  239. warp/tests/test_quat.py +93 -58
  240. warp/tests/test_runlength_encode.py +1 -1
  241. warp/tests/test_scalar_ops.py +38 -10
  242. warp/tests/test_smoothstep.py +1 -1
  243. warp/tests/test_sparse.py +126 -15
  244. warp/tests/test_spatial.py +105 -87
  245. warp/tests/test_special_values.py +6 -6
  246. warp/tests/test_static.py +7 -7
  247. warp/tests/test_struct.py +13 -2
  248. warp/tests/test_triangle_closest_point.py +48 -1
  249. warp/tests/test_tuple.py +96 -0
  250. warp/tests/test_types.py +82 -9
  251. warp/tests/test_utils.py +52 -52
  252. warp/tests/test_vec.py +29 -29
  253. warp/tests/test_vec_constructors.py +5 -5
  254. warp/tests/test_vec_scalar_ops.py +97 -97
  255. warp/tests/test_version.py +75 -0
  256. warp/tests/tile/test_tile.py +239 -0
  257. warp/tests/tile/test_tile_atomic_bitwise.py +403 -0
  258. warp/tests/tile/test_tile_cholesky.py +7 -4
  259. warp/tests/tile/test_tile_load.py +26 -2
  260. warp/tests/tile/test_tile_mathdx.py +3 -3
  261. warp/tests/tile/test_tile_matmul.py +1 -1
  262. warp/tests/tile/test_tile_mlp.py +2 -4
  263. warp/tests/tile/test_tile_reduce.py +214 -13
  264. warp/tests/unittest_suites.py +6 -14
  265. warp/tests/unittest_utils.py +10 -9
  266. warp/tests/walkthrough_debug.py +3 -1
  267. warp/torch.py +6 -373
  268. warp/types.py +29 -5750
  269. warp/utils.py +10 -1659
  270. {warp_lang-1.9.0.dist-info → warp_lang-1.10.0rc2.dist-info}/METADATA +47 -103
  271. warp_lang-1.10.0rc2.dist-info/RECORD +468 -0
  272. warp_lang-1.10.0rc2.dist-info/licenses/licenses/Gaia-LICENSE.txt +6 -0
  273. warp_lang-1.10.0rc2.dist-info/licenses/licenses/appdirs-LICENSE.txt +22 -0
  274. warp_lang-1.10.0rc2.dist-info/licenses/licenses/asset_pixel_jpg-LICENSE.txt +3 -0
  275. warp_lang-1.10.0rc2.dist-info/licenses/licenses/cuda-LICENSE.txt +1582 -0
  276. warp_lang-1.10.0rc2.dist-info/licenses/licenses/dlpack-LICENSE.txt +201 -0
  277. warp_lang-1.10.0rc2.dist-info/licenses/licenses/fp16-LICENSE.txt +28 -0
  278. warp_lang-1.10.0rc2.dist-info/licenses/licenses/libmathdx-LICENSE.txt +220 -0
  279. warp_lang-1.10.0rc2.dist-info/licenses/licenses/llvm-LICENSE.txt +279 -0
  280. warp_lang-1.10.0rc2.dist-info/licenses/licenses/moller-LICENSE.txt +16 -0
  281. warp_lang-1.10.0rc2.dist-info/licenses/licenses/nanovdb-LICENSE.txt +2 -0
  282. warp_lang-1.10.0rc2.dist-info/licenses/licenses/nvrtc-LICENSE.txt +1592 -0
  283. warp_lang-1.10.0rc2.dist-info/licenses/licenses/svd-LICENSE.txt +23 -0
  284. warp_lang-1.10.0rc2.dist-info/licenses/licenses/unittest_parallel-LICENSE.txt +21 -0
  285. warp_lang-1.10.0rc2.dist-info/licenses/licenses/usd-LICENSE.txt +213 -0
  286. warp_lang-1.10.0rc2.dist-info/licenses/licenses/windingnumber-LICENSE.txt +21 -0
  287. warp/examples/assets/cartpole.urdf +0 -110
  288. warp/examples/assets/crazyflie.usd +0 -0
  289. warp/examples/assets/nv_ant.xml +0 -92
  290. warp/examples/assets/nv_humanoid.xml +0 -183
  291. warp/examples/assets/quadruped.urdf +0 -268
  292. warp/examples/optim/example_bounce.py +0 -266
  293. warp/examples/optim/example_cloth_throw.py +0 -228
  294. warp/examples/optim/example_drone.py +0 -870
  295. warp/examples/optim/example_inverse_kinematics.py +0 -182
  296. warp/examples/optim/example_inverse_kinematics_torch.py +0 -191
  297. warp/examples/optim/example_softbody_properties.py +0 -400
  298. warp/examples/optim/example_spring_cage.py +0 -245
  299. warp/examples/optim/example_trajectory.py +0 -227
  300. warp/examples/sim/example_cartpole.py +0 -143
  301. warp/examples/sim/example_cloth.py +0 -225
  302. warp/examples/sim/example_cloth_self_contact.py +0 -316
  303. warp/examples/sim/example_granular.py +0 -130
  304. warp/examples/sim/example_granular_collision_sdf.py +0 -202
  305. warp/examples/sim/example_jacobian_ik.py +0 -244
  306. warp/examples/sim/example_particle_chain.py +0 -124
  307. warp/examples/sim/example_quadruped.py +0 -203
  308. warp/examples/sim/example_rigid_chain.py +0 -203
  309. warp/examples/sim/example_rigid_contact.py +0 -195
  310. warp/examples/sim/example_rigid_force.py +0 -133
  311. warp/examples/sim/example_rigid_gyroscopic.py +0 -115
  312. warp/examples/sim/example_rigid_soft_contact.py +0 -140
  313. warp/examples/sim/example_soft_body.py +0 -196
  314. warp/examples/tile/example_tile_walker.py +0 -327
  315. warp/sim/__init__.py +0 -74
  316. warp/sim/articulation.py +0 -793
  317. warp/sim/collide.py +0 -2570
  318. warp/sim/graph_coloring.py +0 -307
  319. warp/sim/import_mjcf.py +0 -791
  320. warp/sim/import_snu.py +0 -227
  321. warp/sim/import_urdf.py +0 -579
  322. warp/sim/import_usd.py +0 -898
  323. warp/sim/inertia.py +0 -357
  324. warp/sim/integrator.py +0 -245
  325. warp/sim/integrator_euler.py +0 -2000
  326. warp/sim/integrator_featherstone.py +0 -2101
  327. warp/sim/integrator_vbd.py +0 -2487
  328. warp/sim/integrator_xpbd.py +0 -3295
  329. warp/sim/model.py +0 -4821
  330. warp/sim/particles.py +0 -121
  331. warp/sim/render.py +0 -431
  332. warp/sim/utils.py +0 -431
  333. warp/tests/sim/disabled_kinematics.py +0 -244
  334. warp/tests/sim/test_cloth.py +0 -863
  335. warp/tests/sim/test_collision.py +0 -743
  336. warp/tests/sim/test_coloring.py +0 -347
  337. warp/tests/sim/test_inertia.py +0 -161
  338. warp/tests/sim/test_model.py +0 -226
  339. warp/tests/sim/test_sim_grad.py +0 -287
  340. warp/tests/sim/test_sim_grad_bounce_linear.py +0 -212
  341. warp/tests/sim/test_sim_kinematics.py +0 -98
  342. warp/thirdparty/__init__.py +0 -0
  343. warp_lang-1.9.0.dist-info/RECORD +0 -456
  344. /warp/{fem → _src/fem}/quadrature/__init__.py +0 -0
  345. /warp/{tests/sim → _src/thirdparty}/__init__.py +0 -0
  346. /warp/{thirdparty → _src/thirdparty}/appdirs.py +0 -0
  347. /warp/{thirdparty → _src/thirdparty}/dlpack.py +0 -0
  348. {warp_lang-1.9.0.dist-info → warp_lang-1.10.0rc2.dist-info}/WHEEL +0 -0
  349. {warp_lang-1.9.0.dist-info → warp_lang-1.10.0rc2.dist-info}/licenses/LICENSE.md +0 -0
  350. {warp_lang-1.9.0.dist-info → warp_lang-1.10.0rc2.dist-info}/top_level.txt +0 -0
warp/tests/test_tuple.py CHANGED
@@ -13,6 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ import sys
16
17
  import unittest
17
18
  from typing import Any, Tuple
18
19
 
@@ -208,6 +209,92 @@ def test_loop_variadic_ellipsis():
208
209
  wp.expect_eq(res, 22)
209
210
 
210
211
 
212
+ # Test for Python 3.10 tuple type compatibility issue
213
+ # Only define these functions on Python 3.9+ where lowercase tuple is supported
214
+ if sys.version_info >= (3, 9):
215
+
216
+ @wp.func
217
+ def complex_tuple_function(scale: float, offset: wp.vec3) -> tuple[float, wp.vec3f, wp.vec3f]:
218
+ """
219
+ Function that returns a complex tuple with mixed types.
220
+ This specifically tests the tuple[float, wp.vec3f, wp.vec3f] case
221
+ that was problematic on Python 3.10.
222
+ """
223
+ # Create some computed values
224
+ scaled_value = scale * 2.5
225
+ position = wp.vec3f(offset.x + 1.0, offset.y + 2.0, offset.z + 3.0)
226
+ velocity = wp.vec3f(scale * 0.1, scale * 0.2, scale * 0.3)
227
+
228
+ return (scaled_value, position, velocity)
229
+
230
+ @wp.func
231
+ def mixed_types_tuple_function() -> tuple[wp.vec3f, wp.vec3f, float, wp.mat33f]:
232
+ """
233
+ Function returning mixed types in a tuple.
234
+ Tests tuple[vec3f, vec3f, float, mat33f] type annotation.
235
+ """
236
+ return (
237
+ wp.vec3f(1.0, 2.0, 3.0),
238
+ wp.vec3f(4.0, 5.0, 6.0),
239
+ 42.0,
240
+ wp.mat33f(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
241
+ )
242
+
243
+ @wp.func
244
+ def homogeneous_tuple_function() -> tuple[wp.vec3f, wp.vec3f, wp.vec3f]:
245
+ """
246
+ Function returning fixed-size homogeneous tuple.
247
+ Tests tuple[wp.vec3f, wp.vec3f, wp.vec3f] type annotation.
248
+ """
249
+ return (wp.vec3f(1.0, 2.0, 3.0), wp.vec3f(4.0, 5.0, 6.0), wp.vec3f(7.0, 8.0, 9.0))
250
+
251
+ @wp.kernel
252
+ def test_complex_tuple_functions():
253
+ """
254
+ Kernel that tests complex tuple return types that were problematic on Python 3.10.
255
+ """
256
+ # Test the main problematic case: tuple[float, wp.vec3f, wp.vec3f]
257
+ result1 = complex_tuple_function(4.0, wp.vec3(10.0, 20.0, 30.0))
258
+
259
+ # Unpack and verify
260
+ scale_result, pos_result, vel_result = result1
261
+ wp.expect_near(scale_result, 10.0) # 4.0 * 2.5
262
+ wp.expect_eq(pos_result, wp.vec3f(11.0, 22.0, 33.0))
263
+ wp.expect_eq(vel_result, wp.vec3f(0.4, 0.8, 1.2))
264
+
265
+ # Test access by index
266
+ wp.expect_near(result1[0], 10.0)
267
+ wp.expect_eq(result1[1], wp.vec3f(11.0, 22.0, 33.0))
268
+ wp.expect_eq(result1[2], wp.vec3f(0.4, 0.8, 1.2))
269
+
270
+ # Test more complex tuple: tuple[vec3f, vec3f, float, mat33f]
271
+ mixed_result = mixed_types_tuple_function()
272
+ result_pos, result_vel, result_energy, result_transform = mixed_result
273
+
274
+ # Verify known values
275
+ wp.expect_eq(result_pos, wp.vec3f(1.0, 2.0, 3.0))
276
+ wp.expect_eq(result_vel, wp.vec3f(4.0, 5.0, 6.0))
277
+ wp.expect_eq(result_energy, 42.0)
278
+
279
+ # Verify transform matrix is identity
280
+ wp.expect_eq(result_transform[0, 0], 1.0)
281
+ wp.expect_eq(result_transform[1, 1], 1.0)
282
+ wp.expect_eq(result_transform[2, 2], 1.0)
283
+
284
+ # Test fixed-size homogeneous tuple: tuple[wp.vec3f, wp.vec3f, wp.vec3f]
285
+ homo_result = homogeneous_tuple_function()
286
+ wp.expect_eq(len(homo_result), 3)
287
+ wp.expect_eq(homo_result[0], wp.vec3f(1.0, 2.0, 3.0))
288
+ wp.expect_eq(homo_result[1], wp.vec3f(4.0, 5.0, 6.0))
289
+ wp.expect_eq(homo_result[2], wp.vec3f(7.0, 8.0, 9.0))
290
+
291
+ # Test unpacking
292
+ vec1, vec2, vec3 = homo_result
293
+ wp.expect_eq(vec1, wp.vec3f(1.0, 2.0, 3.0))
294
+ wp.expect_eq(vec2, wp.vec3f(4.0, 5.0, 6.0))
295
+ wp.expect_eq(vec3, wp.vec3f(7.0, 8.0, 9.0))
296
+
297
+
211
298
  devices = get_test_devices()
212
299
 
213
300
 
@@ -258,6 +345,15 @@ add_kernel_test(
258
345
  dim=1,
259
346
  devices=devices,
260
347
  )
348
+ # Only register the test for lowercase tuple syntax on Python 3.9+
349
+ if sys.version_info >= (3, 9):
350
+ add_kernel_test(
351
+ TestTuple,
352
+ name="test_complex_tuple_functions",
353
+ kernel=test_complex_tuple_functions,
354
+ dim=1,
355
+ devices=devices,
356
+ )
261
357
 
262
358
 
263
359
  if __name__ == "__main__":
warp/tests/test_types.py CHANGED
@@ -13,6 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ import sys
16
17
  import unittest
17
18
 
18
19
  from warp.tests.unittest_utils import *
@@ -79,13 +80,13 @@ def test_floats(test, device, dtype):
79
80
  def test_vector(test, device, dtype):
80
81
  def make_scalar(x):
81
82
  # Cast to the correct integer type to simulate wrapping.
82
- if dtype in wp.types.int_types:
83
+ if dtype in wp._src.types.int_types:
83
84
  return dtype._type_(x).value
84
85
 
85
86
  return x
86
87
 
87
88
  def make_vec(*args):
88
- if dtype in wp.types.int_types:
89
+ if dtype in wp._src.types.int_types:
89
90
  # Cast to the correct integer type to simulate wrapping.
90
91
  return tuple(dtype._type_(x).value for x in args)
91
92
 
@@ -143,6 +144,12 @@ def test_vector(test, device, dtype):
143
144
  test.assertTrue(v != vec3_cls(1, 2, 3))
144
145
  test.assertEqual(str(v), "[{}]".format(", ".join(str(x) for x in v)))
145
146
 
147
+ # Copy constructor.
148
+ v_copy = vec3_cls(v)
149
+ v_copy[0] = 123
150
+ test.assertSequenceEqual(v, make_vec(2, 4, 6))
151
+ test.assertSequenceEqual(v_copy, make_vec(123, 4, 6))
152
+
146
153
  # Check added purely for coverage reasons but is this really a desired
147
154
  # behaviour? Not allowing to define new attributes using systems like
148
155
  # `__slots__` could help improving memory usage.
@@ -281,24 +288,24 @@ class TestTypes(unittest.TestCase):
281
288
  v2[:1] = (v2,)
282
289
 
283
290
  def test_matrix(self):
284
- for dtype in (*wp.types.float_types, float):
291
+ for dtype in (*wp._src.types.float_types, float):
285
292
 
286
293
  def make_scalar(x, dtype=dtype):
287
294
  # Cast to the correct integer type to simulate wrapping.
288
- if dtype in wp.types.int_types:
295
+ if dtype in wp._src.types.int_types:
289
296
  return dtype._type_(x).value
290
297
 
291
298
  return x
292
299
 
293
300
  def make_vec(*args, dtype=dtype):
294
- if dtype in wp.types.int_types:
301
+ if dtype in wp._src.types.int_types:
295
302
  # Cast to the correct integer type to simulate wrapping.
296
303
  return tuple(dtype._type_(x).value for x in args)
297
304
 
298
305
  return args
299
306
 
300
307
  def make_mat(*args, dtype=dtype):
301
- if dtype in wp.types.int_types:
308
+ if dtype in wp._src.types.int_types:
302
309
  # Cast to the correct integer type to simulate wrapping.
303
310
  return tuple(tuple(dtype._type_(x).value for x in row) for row in args)
304
311
 
@@ -419,6 +426,12 @@ class TestTypes(unittest.TestCase):
419
426
  "[{}]".format(",\n ".join("[{}]".format(", ".join(str(y) for y in m[x])) for x in range(m._shape_[0]))),
420
427
  )
421
428
 
429
+ # Copy constructor.
430
+ m_copy = mat22_cls(m)
431
+ m_copy[0, 0] = 123
432
+ self.assertSequenceEqual(m, make_mat((2, 4), (6, 8)))
433
+ self.assertSequenceEqual(m_copy, make_mat((123, 4), (6, 8)))
434
+
422
435
  # Check added purely for coverage reasons but is this really a desired
423
436
  # behaviour? Not allowing to define new attributes using systems like
424
437
  # `__slots__` could help improving memory usage.
@@ -527,14 +540,74 @@ class TestTypes(unittest.TestCase):
527
540
  test_conversions(wp.uint64, np.uint64)
528
541
  test_conversions(wp.bool, np.bool_)
529
542
 
543
+ # Only define this test method on Python 3.9+ where lowercase tuple is supported
544
+ if sys.version_info >= (3, 9):
545
+
546
+ def test_tuple_type_code_generation(self):
547
+ """Test that tuple type annotations generate correct type codes, especially on Python 3.10."""
548
+ import sys
549
+ import types
550
+ from typing import get_origin
551
+
552
+ # Test basic tuple types
553
+ tuple_float_float = tuple[float, float]
554
+ result = wp._src.types.get_type_code(tuple_float_float)
555
+ self.assertEqual(result, "tpl2f4f4", "tuple[float, float] should generate 'tpl2f4f4'")
556
+
557
+ # Test tuple with Warp vector types - the problematic case from Python 3.10
558
+ tuple_mixed = tuple[float, wp.vec3f, wp.vec3f]
559
+ result = wp._src.types.get_type_code(tuple_mixed)
560
+ self.assertEqual(result, "tpl3f4v3f4v3f4", "tuple[float, vec3f, vec3f] should generate 'tpl3f4v3f4v3f4'")
561
+
562
+ # Test homogeneous tuple with ellipsis
563
+ tuple_homogeneous = tuple[wp.vec3f, ...]
564
+ result = wp._src.types.get_type_code(tuple_homogeneous)
565
+ self.assertEqual(result, "tpl2v3f4?", "tuple[vec3f, ...] should generate 'tpl2v3f4?'")
566
+
567
+ # Test single element tuple
568
+ tuple_single = tuple[wp.int32]
569
+ result = wp._src.types.get_type_code(tuple_single)
570
+ self.assertEqual(result, "tpl1i4", "tuple[int32] should generate 'tpl1i4'")
571
+
572
+ # Test tuple with multiple Warp types
573
+ tuple_multi_warp = tuple[wp.vec3f, wp.mat33f, wp.quatf]
574
+ result = wp._src.types.get_type_code(tuple_multi_warp)
575
+ self.assertEqual(
576
+ result, "tpl3v3f4m33f4qf4", "tuple[vec3f, mat33f, quatf] should generate 'tpl3v3f4m33f4qf4'"
577
+ )
530
578
 
531
- for dtype in wp.types.int_types:
579
+ # Verify the fix works on Python 3.9-3.10 specifically
580
+ if sys.version_info < (3, 11) and hasattr(types, "GenericAlias"):
581
+ # On Python 3.9-3.10, tuple[...] creates types.GenericAlias
582
+ self.assertIsInstance(
583
+ tuple_mixed, types.GenericAlias, "On Python 3.9-3.10, tuple[...] should create types.GenericAlias"
584
+ )
585
+ self.assertIs(tuple_mixed.__origin__, tuple, "GenericAlias origin should be tuple")
586
+
587
+ # Verify our fix catches this case
588
+ self.assertEqual(get_origin(tuple_mixed), tuple, "get_origin should return tuple")
589
+ elif sys.version_info >= (3, 11):
590
+ # On Python 3.11+, the existing code path should handle it
591
+ self.assertEqual(get_origin(tuple_mixed), tuple, "get_origin should return tuple on Python 3.11+")
592
+
593
+ # Test that the fix doesn't break existing functionality
594
+ # Test with built-in Python types
595
+ tuple_builtin = tuple[int, str, bool]
596
+ try:
597
+ # This might fail because str and bool aren't Warp types, but it shouldn't crash
598
+ wp._src.types.get_type_code(tuple_builtin)
599
+ except TypeError as e:
600
+ # Expected to fail for non-Warp types, but should be a clean TypeError
601
+ self.assertIn("Unrecognized type", str(e))
602
+
603
+
604
+ for dtype in wp._src.types.int_types:
532
605
  add_function_test(TestTypes, f"test_integers_{dtype.__name__}", test_integers, devices=devices, dtype=dtype)
533
606
 
534
- for dtype in wp.types.float_types:
607
+ for dtype in wp._src.types.float_types:
535
608
  add_function_test(TestTypes, f"test_floats_{dtype.__name__}", test_floats, devices=devices, dtype=dtype)
536
609
 
537
- for dtype in (*wp.types.scalar_types, int, float):
610
+ for dtype in (*wp._src.types.scalar_types, int, float):
538
611
  add_function_test(TestTypes, f"test_vector_{dtype.__name__}", test_vector, devices=devices, dtype=dtype)
539
612
 
540
613
  if __name__ == "__main__":
warp/tests/test_utils.py CHANGED
@@ -18,8 +18,8 @@ import inspect
18
18
  import io
19
19
  import unittest
20
20
 
21
+ from warp._src.types import type_scalar_type
21
22
  from warp.tests.unittest_utils import *
22
- from warp.types import type_scalar_type
23
23
 
24
24
 
25
25
  def test_array_scan(test, device):
@@ -37,8 +37,8 @@ def test_array_scan(test, device):
37
37
  result_inc = wp.zeros_like(values)
38
38
  result_exc = wp.zeros_like(values)
39
39
 
40
- wp.utils.array_scan(values, result_inc, True)
41
- wp.utils.array_scan(values, result_exc, False)
40
+ wp._src.utils.array_scan(values, result_inc, True)
41
+ wp._src.utils.array_scan(values, result_exc, False)
42
42
 
43
43
  tolerance = 0 if dtype == int else 1e-3
44
44
 
@@ -54,7 +54,7 @@ def test_array_scan(test, device):
54
54
  def test_array_scan_empty(test, device):
55
55
  values = wp.array((), dtype=int, device=device)
56
56
  result = wp.array((), dtype=int, device=device)
57
- wp.utils.array_scan(values, result)
57
+ wp._src.utils.array_scan(values, result)
58
58
 
59
59
 
60
60
  def test_array_scan_error_sizes_mismatch(test, device):
@@ -64,7 +64,7 @@ def test_array_scan_error_sizes_mismatch(test, device):
64
64
  RuntimeError,
65
65
  r"In and out array storage sizes do not match \(123 vs 234\)$",
66
66
  ):
67
- wp.utils.array_scan(values, result, True)
67
+ wp._src.utils.array_scan(values, result, True)
68
68
 
69
69
 
70
70
  def test_array_scan_error_dtypes_mismatch(test, device):
@@ -74,7 +74,7 @@ def test_array_scan_error_dtypes_mismatch(test, device):
74
74
  RuntimeError,
75
75
  r"In and out array data types do not match \(int32 vs float32\)$",
76
76
  ):
77
- wp.utils.array_scan(values, result, True)
77
+ wp._src.utils.array_scan(values, result, True)
78
78
 
79
79
 
80
80
  def test_array_scan_error_unsupported_dtype(test, device):
@@ -84,7 +84,7 @@ def test_array_scan_error_unsupported_dtype(test, device):
84
84
  RuntimeError,
85
85
  r"Unsupported data type: vec3f$",
86
86
  ):
87
- wp.utils.array_scan(values, result, True)
87
+ wp._src.utils.array_scan(values, result, True)
88
88
 
89
89
 
90
90
  def test_radix_sort_pairs(test, device):
@@ -93,7 +93,7 @@ def test_radix_sort_pairs(test, device):
93
93
  for keyType in keyTypes:
94
94
  keys = wp.array((7, 2, 8, 4, 1, 6, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0), dtype=keyType, device=device)
95
95
  values = wp.array((1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0), dtype=int, device=device)
96
- wp.utils.radix_sort_pairs(keys, values, 8)
96
+ wp._src.utils.radix_sort_pairs(keys, values, 8)
97
97
  assert_np_equal(keys.numpy()[:8], np.array((1, 2, 3, 4, 5, 6, 7, 8)))
98
98
  assert_np_equal(values.numpy()[:8], np.array((5, 2, 8, 4, 7, 6, 1, 3)))
99
99
 
@@ -104,7 +104,7 @@ def test_segmented_sort_pairs(test, device):
104
104
  for keyType in keyTypes:
105
105
  keys = wp.array((7, 2, 8, 4, 1, 6, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0), dtype=keyType, device=device)
106
106
  values = wp.array((1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0), dtype=int, device=device)
107
- wp.utils.segmented_sort_pairs(
107
+ wp._src.utils.segmented_sort_pairs(
108
108
  keys,
109
109
  values,
110
110
  8,
@@ -121,7 +121,7 @@ def test_radix_sort_pairs_empty(test, device):
121
121
  for keyType in keyTypes:
122
122
  keys = wp.array((), dtype=keyType, device=device)
123
123
  values = wp.array((), dtype=int, device=device)
124
- wp.utils.radix_sort_pairs(keys, values, 0)
124
+ wp._src.utils.radix_sort_pairs(keys, values, 0)
125
125
 
126
126
 
127
127
  def test_segmented_sort_pairs_empty(test, device):
@@ -130,7 +130,7 @@ def test_segmented_sort_pairs_empty(test, device):
130
130
  for keyType in keyTypes:
131
131
  keys = wp.array((), dtype=keyType, device=device)
132
132
  values = wp.array((), dtype=int, device=device)
133
- wp.utils.segmented_sort_pairs(
133
+ wp._src.utils.segmented_sort_pairs(
134
134
  keys, values, 0, wp.array((), dtype=int, device=device), wp.array((), dtype=int, device=device)
135
135
  )
136
136
 
@@ -145,7 +145,7 @@ def test_radix_sort_pairs_error_insufficient_storage(test, device):
145
145
  RuntimeError,
146
146
  r"Keys and values array storage must be large enough to contain 2\*count elements$",
147
147
  ):
148
- wp.utils.radix_sort_pairs(keys, values, 3)
148
+ wp._src.utils.radix_sort_pairs(keys, values, 3)
149
149
 
150
150
 
151
151
  def test_segmented_sort_pairs_error_insufficient_storage(test, device):
@@ -158,7 +158,7 @@ def test_segmented_sort_pairs_error_insufficient_storage(test, device):
158
158
  RuntimeError,
159
159
  r"Array storage must be large enough to contain 2\*count elements$",
160
160
  ):
161
- wp.utils.segmented_sort_pairs(
161
+ wp._src.utils.segmented_sort_pairs(
162
162
  keys,
163
163
  values,
164
164
  3,
@@ -177,7 +177,7 @@ def test_radix_sort_pairs_error_unsupported_dtype(test, device):
177
177
  RuntimeError,
178
178
  rf"Unsupported keys and values data types: {keyType.__name__}, float32$",
179
179
  ):
180
- wp.utils.radix_sort_pairs(keys, values, 1)
180
+ wp._src.utils.radix_sort_pairs(keys, values, 1)
181
181
 
182
182
 
183
183
  def test_segmented_sort_pairs_error_unsupported_dtype(test, device):
@@ -190,7 +190,7 @@ def test_segmented_sort_pairs_error_unsupported_dtype(test, device):
190
190
  RuntimeError,
191
191
  rf"Unsupported data type: {keyType.__name__}$",
192
192
  ):
193
- wp.utils.segmented_sort_pairs(
193
+ wp._src.utils.segmented_sort_pairs(
194
194
  keys,
195
195
  values,
196
196
  1,
@@ -203,11 +203,11 @@ def test_array_sum(test, device):
203
203
  for dtype in (wp.float32, wp.float64):
204
204
  with test.subTest(dtype=dtype):
205
205
  values = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
206
- test.assertEqual(wp.utils.array_sum(values), 6.0)
206
+ test.assertEqual(wp._src.utils.array_sum(values), 6.0)
207
207
 
208
208
  values = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
209
209
  result = wp.empty(shape=(1,), dtype=dtype, device=device)
210
- wp.utils.array_sum(values, out=result)
210
+ wp._src.utils.array_sum(values, out=result)
211
211
  test.assertEqual(result.numpy()[0], 6.0)
212
212
 
213
213
 
@@ -218,7 +218,7 @@ def test_array_sum_error_out_dtype_mismatch(test, device):
218
218
  RuntimeError,
219
219
  r"out array should have type float32$",
220
220
  ):
221
- wp.utils.array_sum(values, out=result)
221
+ wp._src.utils.array_sum(values, out=result)
222
222
 
223
223
 
224
224
  def test_array_sum_error_out_shape_mismatch(test, device):
@@ -228,7 +228,7 @@ def test_array_sum_error_out_shape_mismatch(test, device):
228
228
  RuntimeError,
229
229
  r"out array should have shape \(1,\)$",
230
230
  ):
231
- wp.utils.array_sum(values, out=result)
231
+ wp._src.utils.array_sum(values, out=result)
232
232
 
233
233
 
234
234
  def test_array_sum_error_unsupported_dtype(test, device):
@@ -237,25 +237,25 @@ def test_array_sum_error_unsupported_dtype(test, device):
237
237
  RuntimeError,
238
238
  r"Unsupported data type: int32$",
239
239
  ):
240
- wp.utils.array_sum(values)
240
+ wp._src.utils.array_sum(values)
241
241
 
242
242
 
243
243
  def test_array_inner(test, device):
244
244
  for dtype in (wp.float32, wp.float64, wp.vec3):
245
245
  a = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
246
246
  b = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
247
- test.assertEqual(wp.utils.array_inner(a, b), 14.0)
247
+ test.assertEqual(wp._src.utils.array_inner(a, b), 14.0)
248
248
 
249
249
  a = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
250
250
  b = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
251
251
  result = wp.empty(shape=(1,), dtype=type_scalar_type(dtype), device=device)
252
- wp.utils.array_inner(a, b, out=result)
252
+ wp._src.utils.array_inner(a, b, out=result)
253
253
  test.assertEqual(result.numpy()[0], 14.0)
254
254
 
255
255
  # test with different instances of same type
256
256
  a = wp.array((1.0, 2.0, 3.0), dtype=wp.vec3, device=device)
257
257
  b = wp.array((1.0, 2.0, 3.0), dtype=wp.vec(3, float), device=device)
258
- test.assertEqual(wp.utils.array_inner(a, b), 14.0)
258
+ test.assertEqual(wp._src.utils.array_inner(a, b), 14.0)
259
259
 
260
260
 
261
261
  def test_array_inner_error_sizes_mismatch(test, device):
@@ -265,7 +265,7 @@ def test_array_inner_error_sizes_mismatch(test, device):
265
265
  RuntimeError,
266
266
  r"A and b array storage sizes do not match \(2 vs 3\)$",
267
267
  ):
268
- wp.utils.array_inner(a, b)
268
+ wp._src.utils.array_inner(a, b)
269
269
 
270
270
 
271
271
  def test_array_inner_error_dtypes_mismatch(test, device):
@@ -275,7 +275,7 @@ def test_array_inner_error_dtypes_mismatch(test, device):
275
275
  RuntimeError,
276
276
  r"A and b array data types do not match \(float32 vs float64\)$",
277
277
  ):
278
- wp.utils.array_inner(a, b)
278
+ wp._src.utils.array_inner(a, b)
279
279
 
280
280
 
281
281
  def test_array_inner_error_out_dtype_mismatch(test, device):
@@ -286,7 +286,7 @@ def test_array_inner_error_out_dtype_mismatch(test, device):
286
286
  RuntimeError,
287
287
  r"out array should have type float32$",
288
288
  ):
289
- wp.utils.array_inner(a, b, result)
289
+ wp._src.utils.array_inner(a, b, result)
290
290
 
291
291
 
292
292
  def test_array_inner_error_out_shape_mismatch(test, device):
@@ -297,7 +297,7 @@ def test_array_inner_error_out_shape_mismatch(test, device):
297
297
  RuntimeError,
298
298
  r"out array should have shape \(1,\)$",
299
299
  ):
300
- wp.utils.array_inner(a, b, result)
300
+ wp._src.utils.array_inner(a, b, result)
301
301
 
302
302
 
303
303
  def test_array_inner_error_unsupported_dtype(test, device):
@@ -307,34 +307,34 @@ def test_array_inner_error_unsupported_dtype(test, device):
307
307
  RuntimeError,
308
308
  r"Unsupported data type: int32$",
309
309
  ):
310
- wp.utils.array_inner(a, b)
310
+ wp._src.utils.array_inner(a, b)
311
311
 
312
312
 
313
313
  def test_array_cast(test, device):
314
314
  values = wp.array((1, 2, 3), dtype=int, device=device)
315
315
  result = wp.empty(3, dtype=float, device=device)
316
- wp.utils.array_cast(values, result)
316
+ wp._src.utils.array_cast(values, result)
317
317
  test.assertEqual(result.dtype, wp.float32)
318
318
  test.assertEqual(result.shape, (3,))
319
319
  assert_np_equal(result.numpy(), np.array((1.0, 2.0, 3.0), dtype=float))
320
320
 
321
321
  values = wp.array((1, 2, 3, 4), dtype=int, device=device)
322
322
  result = wp.empty((2, 2), dtype=float, device=device)
323
- wp.utils.array_cast(values, result)
323
+ wp._src.utils.array_cast(values, result)
324
324
  test.assertEqual(result.dtype, wp.float32)
325
325
  test.assertEqual(result.shape, (2, 2))
326
326
  assert_np_equal(result.numpy(), np.array(((1.0, 2.0), (3.0, 4.0)), dtype=float))
327
327
 
328
328
  values = wp.array(((1, 2), (3, 4)), dtype=wp.vec2, device=device)
329
329
  result = wp.zeros(2, dtype=float, device=device)
330
- wp.utils.array_cast(values, result, count=1)
330
+ wp._src.utils.array_cast(values, result, count=1)
331
331
  test.assertEqual(result.dtype, wp.float32)
332
332
  test.assertEqual(result.shape, (2,))
333
333
  assert_np_equal(result.numpy(), np.array((1.0, 2.0), dtype=float))
334
334
 
335
335
  values = wp.array(((1, 2), (3, 4)), dtype=int, device=device)
336
336
  result = wp.zeros((2, 2), dtype=int, device=device)
337
- wp.utils.array_cast(values, result)
337
+ wp._src.utils.array_cast(values, result)
338
338
  test.assertEqual(result.dtype, wp.int32)
339
339
  test.assertEqual(result.shape, (2, 2))
340
340
  assert_np_equal(result.numpy(), np.array(((1, 2), (3, 4)), dtype=int))
@@ -347,7 +347,7 @@ def test_array_cast_error_unsupported_partial_cast(test, device):
347
347
  RuntimeError,
348
348
  r"Partial cast is not supported for arrays with more than one dimension$",
349
349
  ):
350
- wp.utils.array_cast(values, result, count=1)
350
+ wp._src.utils.array_cast(values, result, count=1)
351
351
 
352
352
 
353
353
  devices = get_test_devices()
@@ -357,8 +357,8 @@ class TestUtils(unittest.TestCase):
357
357
  def test_warn(self):
358
358
  # Multiple warnings get printed out each time.
359
359
  with contextlib.redirect_stdout(io.StringIO()) as f:
360
- wp.utils.warn("hello, world!")
361
- wp.utils.warn("hello, world!")
360
+ wp._src.utils.warn("hello, world!")
361
+ wp._src.utils.warn("hello, world!")
362
362
 
363
363
  expected = "Warp UserWarning: hello, world!\nWarp UserWarning: hello, world!\n"
364
364
 
@@ -370,14 +370,14 @@ class TestUtils(unittest.TestCase):
370
370
  wp.config.verbose_warnings = True
371
371
  with contextlib.redirect_stdout(io.StringIO()) as f:
372
372
  frame_info = inspect.getframeinfo(inspect.currentframe())
373
- wp.utils.warn("hello, world!")
374
- wp.utils.warn("hello, world!")
373
+ wp._src.utils.warn("hello, world!")
374
+ wp._src.utils.warn("hello, world!")
375
375
 
376
376
  expected = (
377
377
  f"Warp UserWarning: hello, world! ({frame_info.filename}:{frame_info.lineno + 1})\n"
378
- ' wp.utils.warn("hello, world!")\n'
378
+ ' wp._src.utils.warn("hello, world!")\n'
379
379
  f"Warp UserWarning: hello, world! ({frame_info.filename}:{frame_info.lineno + 2})\n"
380
- ' wp.utils.warn("hello, world!")\n'
380
+ ' wp._src.utils.warn("hello, world!")\n'
381
381
  )
382
382
 
383
383
  self.assertEqual(f.getvalue(), expected)
@@ -388,8 +388,8 @@ class TestUtils(unittest.TestCase):
388
388
 
389
389
  # Multiple similar deprecation warnings get printed out only once.
390
390
  with contextlib.redirect_stdout(io.StringIO()) as f:
391
- wp.utils.warn("hello, world!", category=DeprecationWarning)
392
- wp.utils.warn("hello, world!", category=DeprecationWarning)
391
+ wp._src.utils.warn("hello, world!", category=DeprecationWarning)
392
+ wp._src.utils.warn("hello, world!", category=DeprecationWarning)
393
393
 
394
394
  expected = "Warp DeprecationWarning: hello, world!\n"
395
395
 
@@ -397,8 +397,8 @@ class TestUtils(unittest.TestCase):
397
397
 
398
398
  # Multiple different deprecation warnings get printed out each time.
399
399
  with contextlib.redirect_stdout(io.StringIO()) as f:
400
- wp.utils.warn("foo", category=DeprecationWarning)
401
- wp.utils.warn("bar", category=DeprecationWarning)
400
+ wp._src.utils.warn("foo", category=DeprecationWarning)
401
+ wp._src.utils.warn("bar", category=DeprecationWarning)
402
402
 
403
403
  expected = "Warp DeprecationWarning: foo\nWarp DeprecationWarning: bar\n"
404
404
 
@@ -407,7 +407,7 @@ class TestUtils(unittest.TestCase):
407
407
  def test_transform_expand(self):
408
408
  t = (1.0, 2.0, 3.0, 4.0, 3.0, 2.0, 1.0)
409
409
  self.assertEqual(
410
- wp.utils.transform_expand(t),
410
+ wp._src.utils.transform_expand(t),
411
411
  wp.transformf(p=(1.0, 2.0, 3.0), q=(4.0, 3.0, 2.0, 1.0)),
412
412
  )
413
413
 
@@ -419,7 +419,7 @@ class TestUtils(unittest.TestCase):
419
419
  RuntimeError,
420
420
  r"In and out array storage devices do not match \(cpu vs cuda:0\)$",
421
421
  ):
422
- wp.utils.array_scan(values, result, True)
422
+ wp._src.utils.array_scan(values, result, True)
423
423
 
424
424
  @unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
425
425
  def test_radix_sort_pairs_error_devices_mismatch(self):
@@ -429,7 +429,7 @@ class TestUtils(unittest.TestCase):
429
429
  RuntimeError,
430
430
  r"Keys and values array storage devices do not match \(cpu vs cuda:0\)$",
431
431
  ):
432
- wp.utils.radix_sort_pairs(keys, values, 1)
432
+ wp._src.utils.radix_sort_pairs(keys, values, 1)
433
433
 
434
434
  @unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
435
435
  def test_array_inner_error_out_device_mismatch(self):
@@ -440,7 +440,7 @@ class TestUtils(unittest.TestCase):
440
440
  RuntimeError,
441
441
  r"out storage device should match values array$",
442
442
  ):
443
- wp.utils.array_inner(a, b, result)
443
+ wp._src.utils.array_inner(a, b, result)
444
444
 
445
445
  @unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
446
446
  def test_array_sum_error_out_device_mismatch(self):
@@ -450,7 +450,7 @@ class TestUtils(unittest.TestCase):
450
450
  RuntimeError,
451
451
  r"out storage device should match values array$",
452
452
  ):
453
- wp.utils.array_sum(values, out=result)
453
+ wp._src.utils.array_sum(values, out=result)
454
454
 
455
455
  @unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
456
456
  def test_array_inner_error_devices_mismatch(self):
@@ -460,7 +460,7 @@ class TestUtils(unittest.TestCase):
460
460
  RuntimeError,
461
461
  r"A and b array storage devices do not match \(cpu vs cuda:0\)$",
462
462
  ):
463
- wp.utils.array_inner(a, b)
463
+ wp._src.utils.array_inner(a, b)
464
464
 
465
465
  @unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
466
466
  def test_array_cast_error_devices_mismatch(self):
@@ -470,14 +470,14 @@ class TestUtils(unittest.TestCase):
470
470
  RuntimeError,
471
471
  r"Array storage devices do not match \(cpu vs cuda:0\)$",
472
472
  ):
473
- wp.utils.array_cast(values, result)
473
+ wp._src.utils.array_cast(values, result)
474
474
 
475
475
  def test_mesh_adjacency(self):
476
476
  triangles = (
477
477
  (0, 3, 1),
478
478
  (0, 2, 3),
479
479
  )
480
- adj = wp.utils.MeshAdjacency(triangles, len(triangles))
480
+ adj = wp._src.utils.MeshAdjacency(triangles, len(triangles))
481
481
  expected_edges = {
482
482
  (0, 3): (0, 3, 1, 2, 0, 1),
483
483
  (1, 3): (3, 1, 0, -1, 0, -1),
@@ -496,7 +496,7 @@ class TestUtils(unittest.TestCase):
496
496
  )
497
497
 
498
498
  with contextlib.redirect_stdout(io.StringIO()) as f:
499
- wp.utils.MeshAdjacency(triangles, len(triangles))
499
+ wp._src.utils.MeshAdjacency(triangles, len(triangles))
500
500
 
501
501
  self.assertEqual(f.getvalue(), "Detected non-manifold edge\n")
502
502