warp-lang 1.0.0b5__py3-none-manylinux2014_x86_64.whl → 1.0.0b6__py3-none-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. docs/conf.py +3 -4
  2. examples/env/env_ant.py +1 -1
  3. examples/env/env_cartpole.py +1 -1
  4. examples/env/env_humanoid.py +1 -1
  5. examples/example_dem.py +28 -26
  6. examples/example_diffray.py +37 -30
  7. examples/example_fluid.py +7 -3
  8. examples/example_jacobian_ik.py +1 -1
  9. examples/example_mesh_intersect.py +10 -7
  10. examples/example_nvdb.py +3 -3
  11. examples/example_render_opengl.py +19 -10
  12. examples/example_sim_cartpole.py +9 -5
  13. examples/example_sim_cloth.py +29 -25
  14. examples/example_sim_fk_grad.py +2 -2
  15. examples/example_sim_fk_grad_torch.py +3 -3
  16. examples/example_sim_grad_bounce.py +11 -8
  17. examples/example_sim_grad_cloth.py +12 -9
  18. examples/example_sim_granular.py +2 -2
  19. examples/example_sim_granular_collision_sdf.py +13 -13
  20. examples/example_sim_neo_hookean.py +3 -3
  21. examples/example_sim_particle_chain.py +2 -2
  22. examples/example_sim_quadruped.py +8 -5
  23. examples/example_sim_rigid_chain.py +8 -5
  24. examples/example_sim_rigid_contact.py +13 -10
  25. examples/example_sim_rigid_fem.py +2 -2
  26. examples/example_sim_rigid_gyroscopic.py +2 -2
  27. examples/example_sim_rigid_kinematics.py +1 -1
  28. examples/example_sim_trajopt.py +3 -2
  29. examples/fem/example_apic_fluid.py +5 -7
  30. examples/fem/example_diffusion_mgpu.py +18 -16
  31. warp/__init__.py +3 -2
  32. warp/bin/warp.so +0 -0
  33. warp/build_dll.py +29 -9
  34. warp/builtins.py +206 -7
  35. warp/codegen.py +58 -38
  36. warp/config.py +3 -1
  37. warp/context.py +234 -128
  38. warp/fem/__init__.py +2 -2
  39. warp/fem/cache.py +2 -1
  40. warp/fem/field/nodal_field.py +18 -17
  41. warp/fem/geometry/hexmesh.py +11 -6
  42. warp/fem/geometry/quadmesh_2d.py +16 -12
  43. warp/fem/geometry/tetmesh.py +19 -8
  44. warp/fem/geometry/trimesh_2d.py +18 -7
  45. warp/fem/integrate.py +341 -196
  46. warp/fem/quadrature/__init__.py +1 -1
  47. warp/fem/quadrature/pic_quadrature.py +138 -53
  48. warp/fem/quadrature/quadrature.py +81 -9
  49. warp/fem/space/__init__.py +1 -1
  50. warp/fem/space/basis_space.py +169 -51
  51. warp/fem/space/grid_2d_function_space.py +2 -2
  52. warp/fem/space/grid_3d_function_space.py +2 -2
  53. warp/fem/space/hexmesh_function_space.py +2 -2
  54. warp/fem/space/partition.py +9 -6
  55. warp/fem/space/quadmesh_2d_function_space.py +2 -2
  56. warp/fem/space/shape/cube_shape_function.py +27 -15
  57. warp/fem/space/shape/square_shape_function.py +29 -18
  58. warp/fem/space/tetmesh_function_space.py +2 -2
  59. warp/fem/space/topology.py +10 -0
  60. warp/fem/space/trimesh_2d_function_space.py +2 -2
  61. warp/fem/utils.py +10 -5
  62. warp/native/array.h +49 -8
  63. warp/native/builtin.h +31 -14
  64. warp/native/cuda_util.cpp +8 -3
  65. warp/native/cuda_util.h +1 -0
  66. warp/native/exports.h +1177 -1108
  67. warp/native/intersect.h +4 -4
  68. warp/native/intersect_adj.h +8 -8
  69. warp/native/mat.h +65 -6
  70. warp/native/mesh.h +126 -5
  71. warp/native/quat.h +28 -4
  72. warp/native/vec.h +76 -14
  73. warp/native/warp.cu +1 -6
  74. warp/render/render_opengl.py +261 -109
  75. warp/sim/import_mjcf.py +13 -7
  76. warp/sim/import_urdf.py +14 -14
  77. warp/sim/inertia.py +17 -18
  78. warp/sim/model.py +67 -67
  79. warp/sim/render.py +1 -1
  80. warp/sparse.py +6 -6
  81. warp/stubs.py +19 -81
  82. warp/tape.py +1 -1
  83. warp/tests/__main__.py +3 -6
  84. warp/tests/{test_class_kernel.py → aux_test_class_kernel.py} +9 -1
  85. warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -0
  86. warp/tests/{test_dependent.py → aux_test_dependent.py} +2 -2
  87. warp/tests/{test_reference.py → aux_test_reference.py} +1 -1
  88. warp/tests/aux_test_unresolved_func.py +14 -0
  89. warp/tests/aux_test_unresolved_symbol.py +14 -0
  90. warp/tests/{test_kinematics.py → disabled_kinematics.py} +10 -12
  91. warp/tests/run_coverage_serial.py +31 -0
  92. warp/tests/test_adam.py +102 -106
  93. warp/tests/test_arithmetic.py +39 -40
  94. warp/tests/test_array.py +46 -48
  95. warp/tests/test_array_reduce.py +25 -19
  96. warp/tests/test_atomic.py +62 -26
  97. warp/tests/test_bool.py +16 -11
  98. warp/tests/test_builtins_resolution.py +1292 -0
  99. warp/tests/test_bvh.py +9 -12
  100. warp/tests/test_closest_point_edge_edge.py +53 -57
  101. warp/tests/test_codegen.py +164 -134
  102. warp/tests/test_compile_consts.py +13 -19
  103. warp/tests/test_conditional.py +30 -32
  104. warp/tests/test_copy.py +9 -12
  105. warp/tests/test_ctypes.py +90 -98
  106. warp/tests/test_dense.py +20 -14
  107. warp/tests/test_devices.py +34 -35
  108. warp/tests/test_dlpack.py +74 -75
  109. warp/tests/test_examples.py +215 -97
  110. warp/tests/test_fabricarray.py +15 -21
  111. warp/tests/test_fast_math.py +14 -11
  112. warp/tests/test_fem.py +280 -97
  113. warp/tests/test_fp16.py +19 -15
  114. warp/tests/test_func.py +177 -194
  115. warp/tests/test_generics.py +71 -77
  116. warp/tests/test_grad.py +83 -32
  117. warp/tests/test_grad_customs.py +7 -9
  118. warp/tests/test_hash_grid.py +6 -10
  119. warp/tests/test_import.py +9 -23
  120. warp/tests/test_indexedarray.py +19 -21
  121. warp/tests/test_intersect.py +15 -9
  122. warp/tests/test_large.py +17 -19
  123. warp/tests/test_launch.py +14 -17
  124. warp/tests/test_lerp.py +63 -63
  125. warp/tests/test_lvalue.py +84 -35
  126. warp/tests/test_marching_cubes.py +9 -13
  127. warp/tests/test_mat.py +388 -3004
  128. warp/tests/test_mat_lite.py +9 -12
  129. warp/tests/test_mat_scalar_ops.py +2889 -0
  130. warp/tests/test_math.py +10 -11
  131. warp/tests/test_matmul.py +104 -100
  132. warp/tests/test_matmul_lite.py +72 -98
  133. warp/tests/test_mesh.py +35 -32
  134. warp/tests/test_mesh_query_aabb.py +18 -25
  135. warp/tests/test_mesh_query_point.py +39 -23
  136. warp/tests/test_mesh_query_ray.py +9 -21
  137. warp/tests/test_mlp.py +8 -9
  138. warp/tests/test_model.py +89 -93
  139. warp/tests/test_modules_lite.py +15 -25
  140. warp/tests/test_multigpu.py +87 -114
  141. warp/tests/test_noise.py +10 -12
  142. warp/tests/test_operators.py +14 -21
  143. warp/tests/test_options.py +10 -11
  144. warp/tests/test_pinned.py +16 -18
  145. warp/tests/test_print.py +16 -20
  146. warp/tests/test_quat.py +121 -88
  147. warp/tests/test_rand.py +12 -13
  148. warp/tests/test_reload.py +27 -32
  149. warp/tests/test_rounding.py +7 -10
  150. warp/tests/test_runlength_encode.py +105 -106
  151. warp/tests/test_smoothstep.py +8 -9
  152. warp/tests/test_snippet.py +13 -22
  153. warp/tests/test_sparse.py +30 -29
  154. warp/tests/test_spatial.py +179 -174
  155. warp/tests/test_streams.py +100 -107
  156. warp/tests/test_struct.py +98 -67
  157. warp/tests/test_tape.py +11 -17
  158. warp/tests/test_torch.py +89 -86
  159. warp/tests/test_transient_module.py +9 -12
  160. warp/tests/test_types.py +328 -50
  161. warp/tests/test_utils.py +217 -218
  162. warp/tests/test_vec.py +133 -2133
  163. warp/tests/test_vec_lite.py +8 -11
  164. warp/tests/test_vec_scalar_ops.py +2099 -0
  165. warp/tests/test_volume.py +391 -382
  166. warp/tests/test_volume_write.py +122 -135
  167. warp/tests/unittest_serial.py +35 -0
  168. warp/tests/unittest_suites.py +291 -0
  169. warp/tests/{test_base.py → unittest_utils.py} +138 -25
  170. warp/tests/{test_misc.py → unused_test_misc.py} +13 -5
  171. warp/tests/{test_debug.py → walkthough_debug.py} +2 -15
  172. warp/thirdparty/unittest_parallel.py +257 -54
  173. warp/types.py +119 -98
  174. warp/utils.py +14 -0
  175. {warp_lang-1.0.0b5.dist-info → warp_lang-1.0.0b6.dist-info}/METADATA +2 -1
  176. {warp_lang-1.0.0b5.dist-info → warp_lang-1.0.0b6.dist-info}/RECORD +182 -178
  177. {warp_lang-1.0.0b5.dist-info → warp_lang-1.0.0b6.dist-info}/WHEEL +1 -1
  178. warp/tests/test_all.py +0 -239
  179. warp/tests/test_conditional_unequal_types_kernels.py +0 -14
  180. warp/tests/test_coverage.py +0 -38
  181. warp/tests/test_unresolved_func.py +0 -7
  182. warp/tests/test_unresolved_symbol.py +0 -7
  183. /warp/tests/{test_compile_consts_dummy.py → aux_test_compile_consts_dummy.py} +0 -0
  184. /warp/tests/{test_reference_reference.py → aux_test_reference_reference.py} +0 -0
  185. /warp/tests/{test_square.py → aux_test_square.py} +0 -0
  186. {warp_lang-1.0.0b5.dist-info → warp_lang-1.0.0b6.dist-info}/LICENSE.md +0 -0
  187. {warp_lang-1.0.0b5.dist-info → warp_lang-1.0.0b6.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,22 @@
1
1
  # Licensed under the MIT License
2
2
  # https://github.com/craigahobbs/unittest-parallel/blob/main/LICENSE
3
3
 
4
+ # SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5
+ # SPDX-License-Identifier: LicenseRef-NvidiaProprietary
6
+ #
7
+ # NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
8
+ # property and proprietary rights in and to this material, related
9
+ # documentation and any modifications thereto. Any use, reproduction,
10
+ # disclosure or distribution of this material and related documentation
11
+ # without an express license agreement from NVIDIA CORPORATION or
12
+ # its affiliates is strictly prohibited.
13
+
4
14
  """
5
15
  unittest-parallel command-line script main module
6
16
  """
7
17
 
8
18
  import argparse
19
+ import concurrent.futures # NVIDIA Modification
9
20
  import multiprocessing
10
21
  import os
11
22
  import sys
@@ -15,7 +26,20 @@ import unittest
15
26
  from contextlib import contextmanager
16
27
  from io import StringIO
17
28
 
18
- import coverage
29
+ import warp.tests.unittest_suites # NVIDIA Modification
30
+
31
+ try:
32
+ import coverage
33
+
34
+ COVERAGE_AVAILABLE = True # NVIDIA Modification
35
+ except ImportError:
36
+ COVERAGE_AVAILABLE = False # NVIDIA Modification
37
+
38
+
39
+ # The following variables are NVIDIA Modifications
40
+ RUNNING_IN_TEAMCITY = os.environ.get("TEAMCITY_VERSION") is not None
41
+ TEST_SUITE_NAME = "WarpTests"
42
+ START_DIRECTORY = os.path.dirname(__file__) # The directory to start test discovery
19
43
 
20
44
 
21
45
  def main(argv=None):
@@ -25,8 +49,8 @@ def main(argv=None):
25
49
 
26
50
  # Command line arguments
27
51
  parser = argparse.ArgumentParser(prog="unittest-parallel")
28
- parser.add_argument("-v", "--verbose", action="store_const", const=2, default=1, help="Verbose output")
29
- parser.add_argument("-q", "--quiet", dest="verbose", action="store_const", const=0, default=1, help="Quiet output")
52
+ # parser.add_argument("-v", "--verbose", action="store_const", const=2, default=1, help="Verbose output")
53
+ parser.add_argument("-q", "--quiet", dest="verbose", action="store_const", const=0, default=2, help="Quiet output")
30
54
  parser.add_argument("-f", "--failfast", action="store_true", default=False, help="Stop on first fail or error")
31
55
  parser.add_argument(
32
56
  "-b", "--buffer", action="store_true", default=False, help="Buffer stdout and stderr during tests"
@@ -38,9 +62,6 @@ def main(argv=None):
38
62
  type=_convert_select_pattern,
39
63
  help="Only run tests which match the given substring",
40
64
  )
41
- parser.add_argument(
42
- "-s", "--start-directory", metavar="START", default=".", help="Directory to start discovery ('.' default)"
43
- )
44
65
  parser.add_argument(
45
66
  "-p", "--pattern", metavar="PATTERN", default="test*.py", help="Pattern to match tests ('test*.py' default)"
46
67
  )
@@ -59,11 +80,19 @@ def main(argv=None):
59
80
  default=0,
60
81
  help="The number of test processes (default is 0, all cores)",
61
82
  )
83
+ group_parallel.add_argument(
84
+ "-m",
85
+ "--maxjobs",
86
+ metavar="MAXCOUNT",
87
+ type=int,
88
+ default=8,
89
+ help="The maximum number of test processes (default is 8)",
90
+ ) # NVIDIA Modification
62
91
  group_parallel.add_argument(
63
92
  "--level",
64
93
  choices=["module", "class", "test"],
65
- default="module",
66
- help="Set the test parallelism level (default is 'module')",
94
+ default="class",
95
+ help="Set the test parallelism level (default is 'class')",
67
96
  )
68
97
  group_parallel.add_argument(
69
98
  "--disable-process-pooling",
@@ -71,40 +100,45 @@ def main(argv=None):
71
100
  default=False,
72
101
  help="Do not reuse processes used to run test suites",
73
102
  )
103
+ group_parallel.add_argument(
104
+ "--disable-concurrent-futures",
105
+ action="store_true",
106
+ default=False,
107
+ help="Use multiprocessing instead of concurrent.futures.",
108
+ ) # NVIDIA Modification
109
+ group_parallel.add_argument(
110
+ "--serial-fallback",
111
+ action="store_true",
112
+ default=False,
113
+ help="Run in a single-process (no spawning) mode without multiprocessing or concurrent.futures.",
114
+ ) # NVIDIA Modification
74
115
  group_coverage = parser.add_argument_group("coverage options")
75
116
  group_coverage.add_argument("--coverage", action="store_true", help="Run tests with coverage")
76
117
  group_coverage.add_argument("--coverage-branch", action="store_true", help="Run tests with branch coverage")
77
- group_coverage.add_argument("--coverage-rcfile", metavar="RCFILE", help="Specify coverage configuration file")
78
- group_coverage.add_argument(
79
- "--coverage-include",
80
- metavar="PAT",
81
- action="append",
82
- help="Include only files matching one of these patterns. Accepts shell-style (quoted) wildcards.",
83
- )
84
- group_coverage.add_argument(
85
- "--coverage-omit",
86
- metavar="PAT",
87
- action="append",
88
- help="Omit files matching one of these patterns. Accepts shell-style (quoted) wildcards.",
89
- )
90
118
  group_coverage.add_argument(
91
- "--coverage-source",
92
- metavar="SRC",
93
- action="append",
94
- help="A list of packages or directories of code to be measured",
119
+ "--coverage-html",
120
+ metavar="DIR",
121
+ help="Generate coverage HTML report",
122
+ default=os.path.join(START_DIRECTORY, "..", "..", "htmlcov"),
95
123
  )
96
- group_coverage.add_argument("--coverage-html", metavar="DIR", help="Generate coverage HTML report")
97
124
  group_coverage.add_argument("--coverage-xml", metavar="FILE", help="Generate coverage XML report")
98
125
  group_coverage.add_argument(
99
126
  "--coverage-fail-under", metavar="MIN", type=float, help="Fail if coverage percentage under min"
100
127
  )
101
128
  args = parser.parse_args(args=argv)
129
+
102
130
  if args.coverage_branch:
103
131
  args.coverage = args.coverage_branch
104
132
 
133
+ if args.coverage and not COVERAGE_AVAILABLE:
134
+ parser.exit(
135
+ status=2, message="--coverage was used, but coverage was not found. Is it installed?\n"
136
+ ) # NVIDIA Modification
137
+
105
138
  process_count = max(0, args.jobs)
106
139
  if process_count == 0:
107
140
  process_count = multiprocessing.cpu_count()
141
+ process_count = min(process_count, args.maxjobs) # NVIDIA Modification
108
142
 
109
143
  # Create the temporary directory (for coverage files)
110
144
  with tempfile.TemporaryDirectory() as temp_dir:
@@ -113,9 +147,10 @@ def main(argv=None):
113
147
  test_loader = unittest.TestLoader()
114
148
  if args.testNamePatterns:
115
149
  test_loader.testNamePatterns = args.testNamePatterns
116
- discover_suite = test_loader.discover(
117
- args.start_directory, pattern=args.pattern, top_level_dir=args.top_level_directory
118
- )
150
+ discover_suite = warp.tests.unittest_suites.auto_discover_suite(
151
+ test_loader, args.pattern
152
+ ) # NVIDIA Modification
153
+ # discover_suite = warp.tests.unittest_suites.explicit_suite()
119
154
 
120
155
  # Get the parallelizable test suites
121
156
  if args.level == "test":
@@ -128,26 +163,69 @@ def main(argv=None):
128
163
  # Don't use more processes than test suites
129
164
  process_count = max(1, min(len(test_suites), process_count))
130
165
 
131
- # Report test suites and processes
132
- print(
133
- f"Running {len(test_suites)} test suites ({discover_suite.countTestCases()} total tests) across {process_count} processes",
134
- file=sys.stderr,
135
- )
136
- if args.verbose > 1:
137
- print(file=sys.stderr)
166
+ if RUNNING_IN_TEAMCITY:
167
+ print(f"##teamcity[testSuiteStarted name='{TEST_SUITE_NAME}']") # NVIDIA Modification for TC
168
+
169
+ if not args.serial_fallback:
170
+ # Report test suites and processes
171
+ print(
172
+ f"Running {len(test_suites)} test suites ({discover_suite.countTestCases()} total tests) across {process_count} processes",
173
+ file=sys.stderr,
174
+ )
175
+ if args.verbose > 1:
176
+ print(file=sys.stderr)
177
+
178
+ # Run the tests in parallel
179
+ start_time = time.perf_counter()
180
+
181
+ if args.disable_concurrent_futures:
182
+ multiprocessing_context = multiprocessing.get_context(method="spawn")
183
+ maxtasksperchild = 1 if args.disable_process_pooling else None
184
+ with multiprocessing_context.Pool(
185
+ process_count,
186
+ maxtasksperchild=maxtasksperchild,
187
+ initializer=set_worker_cache,
188
+ initargs=(args, temp_dir),
189
+ ) as pool, multiprocessing.Manager() as manager:
190
+ test_manager = ParallelTestManager(manager, args, temp_dir)
191
+ results = pool.map(test_manager.run_tests, test_suites)
192
+ else:
193
+ # NVIDIA Modification added concurrent.futures
194
+ with concurrent.futures.ProcessPoolExecutor(
195
+ max_workers=process_count,
196
+ mp_context=multiprocessing.get_context(method="spawn"),
197
+ initializer=set_worker_cache,
198
+ initargs=(args, temp_dir),
199
+ ) as executor, multiprocessing.Manager() as manager:
200
+ test_manager = ParallelTestManager(manager, args, temp_dir)
201
+ results = list(executor.map(test_manager.run_tests, test_suites, timeout=3600))
202
+ else:
203
+ # This entire path is an NVIDIA Modification
204
+
205
+ # Report test suites and processes
206
+ print(f"Running {discover_suite.countTestCases()} total tests (serial fallback)", file=sys.stderr)
207
+ if args.verbose > 1:
208
+ print(file=sys.stderr)
209
+
210
+ import warp as wp
211
+
212
+ # force rebuild of all kernels
213
+ wp.build.clear_kernel_cache()
214
+ print("Cleared Warp kernel cache")
215
+
216
+ # Run the tests in serial
217
+ start_time = time.perf_counter()
218
+
219
+ with multiprocessing.Manager() as manager:
220
+ test_manager = ParallelTestManager(manager, args, temp_dir)
221
+ results = [test_manager.run_tests(discover_suite)]
138
222
 
139
- # Run the tests in parallel
140
- start_time = time.perf_counter()
141
- multiprocessing_context = multiprocessing.get_context(method="spawn")
142
- maxtasksperchild = 1 if args.disable_process_pooling else None
143
- with multiprocessing_context.Pool(
144
- process_count, maxtasksperchild=maxtasksperchild
145
- ) as pool, multiprocessing.Manager() as manager:
146
- test_manager = ParallelTestManager(manager, args, temp_dir)
147
- results = pool.map(test_manager.run_tests, test_suites)
148
223
  stop_time = time.perf_counter()
149
224
  test_duration = stop_time - start_time
150
225
 
226
+ if RUNNING_IN_TEAMCITY:
227
+ print(f"##teamcity[testSuiteFinished name='{TEST_SUITE_NAME}']") # NVIDIA Modification for TC
228
+
151
229
  # Aggregate parallel test run results
152
230
  tests_run = 0
153
231
  errors = []
@@ -195,14 +273,15 @@ def main(argv=None):
195
273
 
196
274
  # Return an error status on failure
197
275
  if not is_success:
276
+ if RUNNING_IN_TEAMCITY:
277
+ print("##teamcity[buildStatus status='FAILURE']") # NVIDIA Modification for TC
198
278
  parser.exit(status=len(errors) + len(failures) + unexpected_successes)
199
279
 
200
280
  # Coverage?
201
281
  if args.coverage:
202
282
  # Combine the coverage files
203
283
  cov_options = {}
204
- if args.coverage_rcfile is not None:
205
- cov_options["config_file"] = args.coverage_rcfile
284
+ cov_options["config_file"] = True # Grab configuration from pyproject.toml (must install coverage[toml])
206
285
  cov = coverage.Coverage(**cov_options)
207
286
  cov.combine(data_paths=[os.path.join(temp_dir, x) for x in os.listdir(temp_dir)])
208
287
 
@@ -225,7 +304,7 @@ def main(argv=None):
225
304
 
226
305
 
227
306
  def _convert_select_pattern(pattern):
228
- if not "*" in pattern:
307
+ if "*" not in pattern:
229
308
  return f"*{pattern}*"
230
309
  return pattern
231
310
 
@@ -242,12 +321,9 @@ def _coverage(args, temp_dir):
242
321
  cov_options = {
243
322
  "branch": args.coverage_branch,
244
323
  "data_file": coverage_file.name,
245
- "include": args.coverage_include,
246
- "omit": (args.coverage_omit if args.coverage_omit else []) + [__file__],
247
- "source": args.coverage_source,
324
+ # NVIDIA Modification removed unneeded options
248
325
  }
249
- if args.coverage_rcfile is not None:
250
- cov_options["config_file"] = args.coverage_rcfile
326
+ cov_options["config_file"] = True # Grab configuration from pyproject.toml (must install coverage[toml])
251
327
  cov = coverage.Coverage(**cov_options)
252
328
  try:
253
329
  # Start measuring code coverage
@@ -307,7 +383,9 @@ class ParallelTestManager:
307
383
  with _coverage(self.args, self.temp_dir):
308
384
  runner = unittest.TextTestRunner(
309
385
  stream=StringIO(),
310
- resultclass=ParallelTextTestResult,
386
+ resultclass=ParallelTeamCityTestResult
387
+ if RUNNING_IN_TEAMCITY
388
+ else ParallelTextTestResult, # NVIDIA Modification for TC
311
389
  verbosity=self.args.verbose,
312
390
  failfast=self.args.failfast,
313
391
  buffer=self.args.buffer,
@@ -384,3 +462,128 @@ class ParallelTextTestResult(unittest.TextTestResult):
384
462
 
385
463
  def printErrors(self):
386
464
  pass
465
+
466
+
467
+ # NVIDIA Modifications from here until end of file
468
+
469
+
470
+ def set_worker_cache(args, temp_dir):
471
+ """This function is run at the start of ever new process. It changes the Warp cache to avoid conflicts."""
472
+
473
+ with _coverage(args, temp_dir):
474
+ import warp as wp
475
+ from warp.thirdparty import appdirs
476
+
477
+ pid = os.getpid()
478
+ cache_root_dir = appdirs.user_cache_dir(
479
+ appname="warp", appauthor="NVIDIA Corporation", version=f"{wp.config.version}-{pid}"
480
+ )
481
+
482
+ wp.config.kernel_cache_dir = cache_root_dir
483
+
484
+ wp.build.clear_kernel_cache()
485
+
486
+
487
+ def _tc_escape(s):
488
+ s = s.replace("|", "||")
489
+ s = s.replace("\n", "|n")
490
+ s = s.replace("\r", "|r")
491
+ s = s.replace("'", "|'")
492
+ s = s.replace("[", "|[")
493
+ s = s.replace("]", "|]")
494
+ return s
495
+
496
+
497
+ class ParallelTeamCityTestResult(unittest.TextTestResult):
498
+ def __init__(self, stream, descriptions, verbosity):
499
+ stream = type(stream)(sys.stderr)
500
+ super().__init__(stream, descriptions, verbosity)
501
+
502
+ def startTest(self, test):
503
+ if self.showAll:
504
+ self.stream.writeln(f"{self.getDescription(test)} ...")
505
+ self.stream.flush()
506
+ self.start_time = time.perf_counter_ns()
507
+ super(unittest.TextTestResult, self).startTest(test)
508
+
509
+ def _add_helper(self, test, dots_message, show_all_message):
510
+ if self.showAll:
511
+ self.stream.writeln(f"{self.getDescription(test)} ... {show_all_message}")
512
+ elif self.dots:
513
+ self.stream.write(dots_message)
514
+ self.stream.flush()
515
+
516
+ def addSuccess(self, test):
517
+ super(unittest.TextTestResult, self).addSuccess(test)
518
+ self._add_helper(test, ".", "ok")
519
+ self.reportSuccess(test)
520
+
521
+ def addError(self, test, err):
522
+ super(unittest.TextTestResult, self).addError(test, err)
523
+ self._add_helper(test, "E", "ERROR")
524
+ self.reportFailure(test, err)
525
+
526
+ def addFailure(self, test, err):
527
+ super(unittest.TextTestResult, self).addFailure(test, err)
528
+ self._add_helper(test, "F", "FAIL")
529
+ self.reportFailure(test, err)
530
+
531
+ def addSkip(self, test, reason):
532
+ super(unittest.TextTestResult, self).addSkip(test, reason)
533
+ self._add_helper(test, "s", f"skipped {reason!r}")
534
+ self.reportIgnored(test, reason)
535
+
536
+ def addExpectedFailure(self, test, err):
537
+ super(unittest.TextTestResult, self).addExpectedFailure(test, err)
538
+ self._add_helper(test, "x", "expected failure")
539
+ self.reportSuccess(test)
540
+
541
+ def addUnexpectedSuccess(self, test):
542
+ super(unittest.TextTestResult, self).addUnexpectedSuccess(test)
543
+ self._add_helper(test, "u", "unexpected success")
544
+ self.reportFailure(test, "unexpected success")
545
+
546
+ def addSubTest(self, test, subtest, err):
547
+ super(unittest.TextTestResult, self).addSubTest(test, subtest, err)
548
+ if err is not None:
549
+ self._add_helper(test, "E", "ERROR")
550
+ self.reportSubTestFailure(test, err)
551
+
552
+ def printErrors(self):
553
+ pass
554
+
555
+ def reportIgnored(self, test, reason):
556
+ test_id = test.id()
557
+ reason_str = str(reason)
558
+ print(reason_str)
559
+ self.stream.writeln(f"##teamcity[testIgnored name='{test_id}' message='{_tc_escape(str(reason))}']")
560
+ self.stream.flush()
561
+
562
+ def reportSuccess(self, test):
563
+ duration = round((time.perf_counter_ns() - self.start_time) / 1e6) # [ms]
564
+ test_id = test.id()
565
+ self.stream.writeln(f"##teamcity[testStarted name='{test_id}']")
566
+ self.stream.writeln(f"##teamcity[testFinished name='{test_id}' duration='{duration}']")
567
+ self.stream.flush()
568
+
569
+ def reportFailure(self, test, err):
570
+ test_id = test.id()
571
+ self.stream.writeln(f"##teamcity[testStarted name='{test_id}']")
572
+ self.stream.writeln(
573
+ f"##teamcity[testFailed name='{test_id}' message='{_tc_escape(str(err[1]))}' details='{_tc_escape(str(err[2]))}']"
574
+ )
575
+ self.stream.writeln(f"##teamcity[testFinished name='{test_id}']")
576
+ self.stream.flush()
577
+
578
+ def reportSubTestFailure(self, test, err):
579
+ test_id = test.id()
580
+ self.stream.writeln(f"##teamcity[testStarted name='{test_id}']")
581
+ self.stream.writeln(
582
+ f"##teamcity[testFailed name='{test_id}' message='{_tc_escape(str(err[1]))}' details='{_tc_escape(self._exc_info_to_string(err, test))}']"
583
+ )
584
+ self.stream.writeln(f"##teamcity[testFinished name='{test_id}']")
585
+ self.stream.flush()
586
+
587
+
588
+ if __name__ == "__main__": # pragma: no cover
589
+ main()