xobjects 0.6.10__tar.gz → 0.7.1__tar.gz

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 (62) hide show
  1. {xobjects-0.6.10/xobjects.egg-info → xobjects-0.7.1}/PKG-INFO +1 -1
  2. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_capi.py +39 -0
  3. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_general.py +94 -84
  4. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_hybrid_class.py +22 -0
  5. xobjects-0.7.1/tests/test_raw_union.py +78 -0
  6. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/__init__.py +1 -0
  7. xobjects-0.7.1/xobjects/_version.py +1 -0
  8. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/array.py +2 -2
  9. xobjects-0.7.1/xobjects/capi.py +1010 -0
  10. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/context.py +3 -3
  11. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/context_cpu.py +98 -15
  12. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/context_cupy.py +5 -3
  13. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/general.py +1 -1
  14. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/headers/atomicadd.h +14 -0
  15. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/hybrid_class.py +7 -1
  16. xobjects-0.7.1/xobjects/raw_union.py +111 -0
  17. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/ref.py +4 -4
  18. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/scalar.py +2 -2
  19. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/settings.py +80 -68
  20. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/string.py +2 -2
  21. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/struct.py +12 -6
  22. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/union.py +2 -2
  23. {xobjects-0.6.10 → xobjects-0.7.1/xobjects.egg-info}/PKG-INFO +1 -1
  24. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects.egg-info/SOURCES.txt +2 -0
  25. xobjects-0.6.10/xobjects/_version.py +0 -1
  26. xobjects-0.6.10/xobjects/capi.py +0 -654
  27. {xobjects-0.6.10 → xobjects-0.7.1}/Architecture.md +0 -0
  28. {xobjects-0.6.10 → xobjects-0.7.1}/LICENSE +0 -0
  29. {xobjects-0.6.10 → xobjects-0.7.1}/MANIFEST.in +0 -0
  30. {xobjects-0.6.10 → xobjects-0.7.1}/README.md +0 -0
  31. {xobjects-0.6.10 → xobjects-0.7.1}/pyproject.toml +0 -0
  32. {xobjects-0.6.10 → xobjects-0.7.1}/setup.cfg +0 -0
  33. {xobjects-0.6.10 → xobjects-0.7.1}/setup.py +0 -0
  34. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_align.py +0 -0
  35. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_array.py +0 -0
  36. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_buffer.py +0 -0
  37. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_chunk.py +0 -0
  38. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_common.py +0 -0
  39. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_context_opencl.py +0 -0
  40. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_kernel.py +0 -0
  41. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_linked_array.py +0 -0
  42. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_nplike_arrays.py +0 -0
  43. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_ref.py +0 -0
  44. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_scalars.py +0 -0
  45. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_shared_memory.py +0 -0
  46. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_strides.py +0 -0
  47. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_string.py +0 -0
  48. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_struct.py +0 -0
  49. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_to_dict.py +0 -0
  50. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_typeutils.py +0 -0
  51. {xobjects-0.6.10 → xobjects-0.7.1}/tests/test_unionref.py +0 -0
  52. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/_patch_pyopencl_array.py +0 -0
  53. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/context_pyopencl.py +0 -0
  54. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/headers/common.h +0 -0
  55. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/linkedarray.py +0 -0
  56. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/specialize_source.py +0 -0
  57. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/test_helpers.py +0 -0
  58. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects/typeutils.py +0 -0
  59. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects.egg-info/dependency_links.txt +0 -0
  60. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects.egg-info/entry_points.txt +0 -0
  61. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects.egg-info/requires.txt +0 -0
  62. {xobjects-0.6.10 → xobjects-0.7.1}/xobjects.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xobjects
3
- Version: 0.6.10
3
+ Version: 0.7.1
4
4
  Summary: In-memory serialization and code generator for CPU and GPU
5
5
  Home-page: https://xsuite.readthedocs.io/
6
6
  Download-URL: https://pypi.python.org/pypi/xobjects
@@ -21,6 +21,15 @@ class Struct1(xo.Struct):
21
21
  field2 = xo.Float64
22
22
 
23
23
 
24
+ class RawValue(xo.RawUnion):
25
+ scalar = xo.Float64
26
+ bits = xo.UInt64
27
+
28
+
29
+ class StructRawUnion(xo.Struct):
30
+ value = RawValue
31
+
32
+
24
33
  class Struct2(xo.Struct):
25
34
  field1 = xo.Int32
26
35
  field2 = xo.Float64[:]
@@ -243,6 +252,36 @@ def test_struct1():
243
252
  assert p2[0] == s1.field2
244
253
 
245
254
 
255
+ def test_raw_union_member_getters():
256
+ kernels = StructRawUnion._gen_kernels()
257
+ ctx = xo.ContextCpu()
258
+ ctx.add_kernels(kernels=kernels)
259
+
260
+ source = StructRawUnion._gen_c_api().source
261
+ assert "StructRawUnion_get_value_scalar" in source
262
+ assert "StructRawUnion_get_value_bits" in source
263
+ assert "StructRawUnion_get_value(" not in source
264
+
265
+ value = 3.5
266
+ value_bits = np.array([value], dtype=np.float64).view(np.uint64)[0]
267
+ s1 = StructRawUnion(value=value)
268
+ s2 = StructRawUnion(value=("bits", value_bits))
269
+ raw_value = RawValue(value)
270
+
271
+ assert isinstance(s1.value, RawValue)
272
+ assert s1.value.scalar == value
273
+ assert s1.value.bits == value_bits
274
+ assert s2.value.scalar == value
275
+ assert s2.value.bits == value_bits
276
+ assert raw_value.scalar == value
277
+ assert raw_value.bits == value_bits
278
+
279
+ assert ctx.kernels.StructRawUnion_get_value_scalar(obj=s1) == value
280
+ assert ctx.kernels.StructRawUnion_get_value_bits(obj=s1) == value_bits
281
+ assert ctx.kernels.StructRawUnion_get_value_scalar(obj=s2) == value
282
+ assert ctx.kernels.StructRawUnion_get_value_bits(obj=s2) == value_bits
283
+
284
+
246
285
  def test_struct2():
247
286
  s2 = Struct2(field1=2, field2=5)
248
287
 
@@ -12,44 +12,44 @@ from xobjects.test_helpers import allow_kernel_compilation
12
12
  def test_print_mode_default(capsys):
13
13
  printer = Print()
14
14
 
15
- printer('visible')
15
+ printer("visible")
16
16
 
17
- assert capsys.readouterr().out == 'visible\n'
17
+ assert capsys.readouterr().out == "visible\n"
18
18
 
19
19
 
20
20
  def test_print_mode_suppressed(capsys):
21
21
  printer = Print()
22
- with xo.settings.override(print_mode='suppress'):
23
- printer('hidden')
22
+ with xo.settings.override(print_mode="suppress"):
23
+ printer("hidden")
24
24
 
25
- assert capsys.readouterr().out == ''
25
+ assert capsys.readouterr().out == ""
26
26
 
27
27
 
28
28
  def test_settings_control_xsuite_printer(capsys):
29
- with xo.settings.override(print_mode='suppress'):
30
- xo._print('hidden')
29
+ with xo.settings.override(print_mode="suppress"):
30
+ xo._print("hidden")
31
31
 
32
- assert capsys.readouterr().out == ''
32
+ assert capsys.readouterr().out == ""
33
33
 
34
34
 
35
35
  def test_python_setting_overrides_environment_default(capsys):
36
- with xo.settings.override(print_mode='print'):
37
- xo._print('visible')
36
+ with xo.settings.override(print_mode="print"):
37
+ xo._print("visible")
38
38
 
39
- assert capsys.readouterr().out == 'visible\n'
39
+ assert capsys.readouterr().out == "visible\n"
40
40
 
41
41
 
42
42
  def test_invalid_print_mode_setting():
43
- with pytest.raises(ValueError, match='XSUITE_PRINT_MODE.*print.*suppress'):
44
- xo.settings.print_mode = 'invalid'
43
+ with pytest.raises(ValueError, match="XSUITE_PRINT_MODE.*print.*suppress"):
44
+ xo.settings.print_mode = "invalid"
45
45
 
46
46
 
47
47
  def test_settings_override_restores_value_after_error():
48
48
  original = xo.settings.print_mode
49
49
 
50
50
  with pytest.raises(RuntimeError):
51
- with xo.settings.override(print_mode='suppress'):
52
- assert xo.settings.print_mode == 'suppress'
51
+ with xo.settings.override(print_mode="suppress"):
52
+ assert xo.settings.print_mode == "suppress"
53
53
  raise RuntimeError
54
54
 
55
55
  assert xo.settings.print_mode == original
@@ -57,84 +57,88 @@ def test_settings_override_restores_value_after_error():
57
57
 
58
58
  def test_settings_are_discoverable():
59
59
  expected_settings = {
60
- 'print_mode',
61
- 'progress_indicator',
62
- 'allow_kernel_compilation',
63
- 'force_kernel_compilation',
64
- 'show_kernel_diagnostics',
65
- 'cffi_forbid_compile',
66
- 'cffi_keep_build_files',
67
- 'cuda_backend',
68
- 'cuda_fast_compile',
69
- 'cuda_compiler',
60
+ "print_mode",
61
+ "progress_indicator",
62
+ "allow_kernel_compilation",
63
+ "force_kernel_compilation",
64
+ "show_kernel_diagnostics",
65
+ "cffi_forbid_compile",
66
+ "cffi_keep_build_files",
67
+ "cuda_backend",
68
+ "cuda_fast_compile",
69
+ "cuda_compiler",
70
70
  }
71
71
 
72
72
  assert expected_settings <= set(dir(xo.settings))
73
73
  for name in expected_settings:
74
- assert f'{name}=' in repr(xo.settings)
74
+ assert f"{name}=" in repr(xo.settings)
75
75
  assert name in type(xo.settings).__doc__
76
76
 
77
77
 
78
78
  def test_print_mode_environment_variable_is_startup_default():
79
79
  environment = os.environ.copy()
80
- environment['XSUITE_PRINT_MODE'] = 'suppress'
80
+ environment["XSUITE_PRINT_MODE"] = "suppress"
81
81
  code = (
82
- 'import xobjects as xo; '
82
+ "import xobjects as xo; "
83
83
  'assert xo.settings.print_mode == "suppress"; '
84
- 'xo._print("hidden")')
84
+ 'xo._print("hidden")'
85
+ )
85
86
 
86
87
  completed = subprocess.run(
87
- [sys.executable, '-c', code],
88
+ [sys.executable, "-c", code],
88
89
  env=environment,
89
90
  capture_output=True,
90
91
  text=True,
91
92
  check=True,
92
93
  )
93
94
 
94
- assert completed.stdout == ''
95
+ assert completed.stdout == ""
95
96
 
96
97
 
97
98
  def test_print_mode_environment_variable_can_be_overridden_in_python():
98
99
  environment = os.environ.copy()
99
- environment['XSUITE_PRINT_MODE'] = 'suppress'
100
+ environment["XSUITE_PRINT_MODE"] = "suppress"
100
101
  code = (
101
- 'import xobjects as xo; '
102
+ "import xobjects as xo; "
102
103
  'xo.settings.print_mode = "print"; '
103
104
  'assert xo.settings.print_mode == "print"; '
104
- 'xo._print("visible")')
105
+ 'xo._print("visible")'
106
+ )
105
107
 
106
108
  completed = subprocess.run(
107
- [sys.executable, '-c', code],
109
+ [sys.executable, "-c", code],
108
110
  env=environment,
109
111
  capture_output=True,
110
112
  text=True,
111
113
  check=True,
112
114
  )
113
115
 
114
- assert completed.stdout == 'visible\n'
116
+ assert completed.stdout == "visible\n"
115
117
 
116
118
 
117
119
  def test_environment_change_after_import_does_not_override_python_setting(
118
- capsys, monkeypatch):
119
- with xo.settings.override(print_mode='print'):
120
- monkeypatch.setenv('XSUITE_PRINT_MODE', 'suppress')
121
- xo._print('visible')
120
+ capsys, monkeypatch
121
+ ):
122
+ with xo.settings.override(print_mode="print"):
123
+ monkeypatch.setenv("XSUITE_PRINT_MODE", "suppress")
124
+ xo._print("visible")
122
125
 
123
- assert capsys.readouterr().out == 'visible\n'
126
+ assert capsys.readouterr().out == "visible\n"
124
127
 
125
128
 
126
- @pytest.mark.parametrize('value', ['1', 'true', 'YES', 'on'])
129
+ @pytest.mark.parametrize("value", ["1", "true", "YES", "on"])
127
130
  def test_boolean_environment_true_values(value):
128
131
  environment = os.environ.copy()
129
- environment['XSUITE_ALLOW_KERNEL_COMPILATION'] = value
132
+ environment["XSUITE_ALLOW_KERNEL_COMPILATION"] = value
130
133
  code = (
131
- 'import xobjects as xo; '
132
- 'assert xo.settings.allow_kernel_compilation is True; '
133
- 'xo.settings.allow_kernel_compilation = False; '
134
- 'assert xo.settings.allow_kernel_compilation is False')
134
+ "import xobjects as xo; "
135
+ "assert xo.settings.allow_kernel_compilation is True; "
136
+ "xo.settings.allow_kernel_compilation = False; "
137
+ "assert xo.settings.allow_kernel_compilation is False"
138
+ )
135
139
 
136
140
  subprocess.run(
137
- [sys.executable, '-c', code],
141
+ [sys.executable, "-c", code],
138
142
  env=environment,
139
143
  capture_output=True,
140
144
  text=True,
@@ -142,16 +146,17 @@ def test_boolean_environment_true_values(value):
142
146
  )
143
147
 
144
148
 
145
- @pytest.mark.parametrize('value', ['0', 'false', 'NO', 'off'])
149
+ @pytest.mark.parametrize("value", ["0", "false", "NO", "off"])
146
150
  def test_boolean_environment_false_values(value):
147
151
  environment = os.environ.copy()
148
- environment['XSUITE_FORCE_KERNEL_COMPILATION'] = value
152
+ environment["XSUITE_FORCE_KERNEL_COMPILATION"] = value
149
153
  code = (
150
- 'import xobjects as xo; '
151
- 'assert xo.settings.force_kernel_compilation is False')
154
+ "import xobjects as xo; "
155
+ "assert xo.settings.force_kernel_compilation is False"
156
+ )
152
157
 
153
158
  subprocess.run(
154
- [sys.executable, '-c', code],
159
+ [sys.executable, "-c", code],
155
160
  env=environment,
156
161
  capture_output=True,
157
162
  text=True,
@@ -161,46 +166,49 @@ def test_boolean_environment_false_values(value):
161
166
 
162
167
  def test_invalid_boolean_environment_value():
163
168
  environment = os.environ.copy()
164
- environment['XSUITE_CFFI_FORBID_COMPILE'] = 'sometimes'
169
+ environment["XSUITE_CFFI_FORBID_COMPILE"] = "sometimes"
165
170
 
166
171
  completed = subprocess.run(
167
- [sys.executable, '-c', 'import xobjects'],
172
+ [sys.executable, "-c", "import xobjects"],
168
173
  env=environment,
169
174
  capture_output=True,
170
175
  text=True,
171
176
  )
172
177
 
173
178
  assert completed.returncode != 0
174
- assert 'Invalid boolean value' in completed.stderr
175
- assert 'xobjects.settings.cffi_forbid_compile' in completed.stderr
176
- assert 'XSUITE_CFFI_FORBID_COMPILE' in completed.stderr
179
+ assert "Invalid boolean value" in completed.stderr
180
+ assert "xobjects.settings.cffi_forbid_compile" in completed.stderr
181
+ assert "XSUITE_CFFI_FORBID_COMPILE" in completed.stderr
177
182
 
178
183
 
179
184
  def test_runtime_settings_environment_defaults():
180
185
  environment = os.environ.copy()
181
- environment.update({
182
- 'XSUITE_PROGRESS_INDICATOR': 'text',
183
- 'XSUITE_FORCE_KERNEL_COMPILATION': 'yes',
184
- 'XSUITE_SHOW_KERNEL_DIAGNOSTICS': 'on',
185
- 'XSUITE_CFFI_FORBID_COMPILE': 'true',
186
- 'XSUITE_CFFI_KEEP_BUILD_FILES': '1',
187
- 'XSUITE_CUDA_BACKEND': 'clang',
188
- 'XSUITE_CUDA_FAST_COMPILE': 'false',
189
- 'XSUITE_CUDA_COMPILER': '/path/to/clang++',
190
- })
186
+ environment.update(
187
+ {
188
+ "XSUITE_PROGRESS_INDICATOR": "text",
189
+ "XSUITE_FORCE_KERNEL_COMPILATION": "yes",
190
+ "XSUITE_SHOW_KERNEL_DIAGNOSTICS": "on",
191
+ "XSUITE_CFFI_FORBID_COMPILE": "true",
192
+ "XSUITE_CFFI_KEEP_BUILD_FILES": "1",
193
+ "XSUITE_CUDA_BACKEND": "clang",
194
+ "XSUITE_CUDA_FAST_COMPILE": "false",
195
+ "XSUITE_CUDA_COMPILER": "/path/to/clang++",
196
+ }
197
+ )
191
198
  code = (
192
- 'import xobjects as xo; '
199
+ "import xobjects as xo; "
193
200
  'assert xo.settings.progress_indicator == "text"; '
194
- 'assert xo.settings.force_kernel_compilation is True; '
195
- 'assert xo.settings.show_kernel_diagnostics is True; '
196
- 'assert xo.settings.cffi_forbid_compile is True; '
197
- 'assert xo.settings.cffi_keep_build_files is True; '
201
+ "assert xo.settings.force_kernel_compilation is True; "
202
+ "assert xo.settings.show_kernel_diagnostics is True; "
203
+ "assert xo.settings.cffi_forbid_compile is True; "
204
+ "assert xo.settings.cffi_keep_build_files is True; "
198
205
  'assert xo.settings.cuda_backend == "clang"; '
199
- 'assert xo.settings.cuda_fast_compile is False; '
200
- 'assert xo.settings.cuda_compiler == "/path/to/clang++"')
206
+ "assert xo.settings.cuda_fast_compile is False; "
207
+ 'assert xo.settings.cuda_compiler == "/path/to/clang++"'
208
+ )
201
209
 
202
210
  subprocess.run(
203
- [sys.executable, '-c', code],
211
+ [sys.executable, "-c", code],
204
212
  env=environment,
205
213
  capture_output=True,
206
214
  text=True,
@@ -209,7 +217,7 @@ def test_runtime_settings_environment_defaults():
209
217
 
210
218
 
211
219
  @pytest.mark.parametrize(
212
- 'allow, force, compilation_allowed',
220
+ "allow, force, compilation_allowed",
213
221
  [
214
222
  (False, False, False),
215
223
  (True, False, True),
@@ -222,12 +230,14 @@ def test_kernel_compilation_settings(allow, force, compilation_allowed):
222
230
  allow_kernel_compilation=allow,
223
231
  force_kernel_compilation=force,
224
232
  ):
225
- assert xo.context_cpu.kernel_compilation_allowed(
226
- xo.ContextCpu()) is compilation_allowed
233
+ assert (
234
+ xo.context_cpu.kernel_compilation_allowed(xo.ContextCpu())
235
+ is compilation_allowed
236
+ )
227
237
 
228
238
 
229
239
  def test_user_context_environment_variable(monkeypatch):
230
- monkeypatch.setenv('XOBJECTS_USER_CONTEXT', 'ContextCpu:auto')
240
+ monkeypatch.setenv("XOBJECTS_USER_CONTEXT", "ContextCpu:auto")
231
241
  context = xo.get_user_context()
232
242
 
233
243
  assert context.openmp_enabled
@@ -235,8 +245,8 @@ def test_user_context_environment_variable(monkeypatch):
235
245
 
236
246
  def test_test_contexts_environment_variable(monkeypatch):
237
247
  monkeypatch.setenv(
238
- 'XOBJECTS_TEST_CONTEXTS',
239
- 'ContextCpu;ContextCpu:auto',
248
+ "XOBJECTS_TEST_CONTEXTS",
249
+ "ContextCpu;ContextCpu:auto",
240
250
  )
241
251
 
242
252
  contexts = list(xo.context.get_test_contexts())
@@ -252,8 +262,8 @@ def test_cffi_forbid_compile_setting():
252
262
  xo.ContextCpu().build_kernels({})
253
263
 
254
264
  message = str(err.value)
255
- assert 'xobjects.settings.cffi_forbid_compile' in message
256
- assert 'XSUITE_CFFI_FORBID_COMPILE' in message
265
+ assert "xobjects.settings.cffi_forbid_compile" in message
266
+ assert "XSUITE_CFFI_FORBID_COMPILE" in message
257
267
 
258
268
 
259
269
  def test_allow_kernel_compilation_decorator_restores_state():
@@ -332,6 +332,28 @@ def test_to_json_defaults():
332
332
  assert b_dict == {}
333
333
 
334
334
 
335
+ def test_to_dict_scalar_raw_union_defaults():
336
+ class ScalarUnion(xo.RawUnion):
337
+ scalar = xo.Float64
338
+ bits = xo.UInt64
339
+
340
+ @classmethod
341
+ def _from_buffer(cls, buffer, offset=0, container=None):
342
+ return xo.Float64._from_buffer(buffer, offset)
343
+
344
+ class A(xo.HybridClass):
345
+ _xofields = {
346
+ "a": ScalarUnion,
347
+ "b": xo.Field(ScalarUnion, default=2.5),
348
+ "c": xo.Field(ScalarUnion, default_factory=lambda: 3.5),
349
+ }
350
+
351
+ assert A().to_dict() == {"__class__": "A"}
352
+ values = {"__class__": "A", "a": 1.5, "b": 0.0, "c": 0.0}
353
+ for copy_to_cpu in (True, False):
354
+ assert A.from_dict(values).to_dict(copy_to_cpu=copy_to_cpu) == values
355
+
356
+
335
357
  def test_to_dict_python_vars():
336
358
  class TD(xo.HybridClass):
337
359
  _xofields = {
@@ -0,0 +1,78 @@
1
+ # copyright ################################# #
2
+ # This file is part of the Xobjects Package. #
3
+ # Copyright (c) CERN, 2026. #
4
+ # ########################################### #
5
+
6
+ import numpy as np
7
+ import pytest
8
+
9
+ import xobjects as xo
10
+
11
+
12
+ class RawValue(xo.RawUnion):
13
+ scalar = xo.Float64
14
+ bits = xo.UInt64
15
+
16
+
17
+ class Holder(xo.Struct):
18
+ value = RawValue
19
+
20
+
21
+ def _float_bits(value):
22
+ return np.array([value], dtype=np.float64).view(np.uint64)[0]
23
+
24
+
25
+ def test_raw_union_declaration_consumes_member_attributes():
26
+ assert RawValue._members == {"scalar": xo.Float64, "bits": xo.UInt64}
27
+ assert RawValue._size == 8
28
+
29
+ assert not hasattr(RawValue, "scalar")
30
+ assert not hasattr(RawValue, "bits")
31
+
32
+
33
+ def test_raw_union_standalone_instance_reads_explicit_members():
34
+ value = 3.5
35
+ raw_value = RawValue(value)
36
+
37
+ assert isinstance(raw_value, RawValue)
38
+ assert raw_value.scalar == value
39
+ assert raw_value.bits == _float_bits(value)
40
+ assert "scalar" in dir(raw_value)
41
+ assert "bits" in dir(raw_value)
42
+
43
+ with pytest.raises(AttributeError, match="missing"):
44
+ raw_value.missing
45
+
46
+
47
+ def test_raw_union_struct_field_reads_explicit_members():
48
+ value = 3.5
49
+ holder = Holder(value=value)
50
+
51
+ assert isinstance(holder.value, RawValue)
52
+ assert holder.value.scalar == value
53
+ assert holder.value.bits == _float_bits(value)
54
+
55
+ with pytest.raises(TypeError):
56
+ float(holder.value)
57
+
58
+
59
+ def test_raw_union_constructor_accepts_explicit_member():
60
+ value = 3.5
61
+ value_bits = _float_bits(value)
62
+ holder = Holder(value=("bits", value_bits))
63
+
64
+ assert holder.value.scalar == value
65
+ assert holder.value.bits == value_bits
66
+
67
+
68
+ def test_raw_union_copy_from_same_type():
69
+ source = RawValue(3.5)
70
+ holder = Holder(value=0.0)
71
+
72
+ holder.value = source
73
+ assert holder.value.scalar == source.scalar
74
+ assert holder.value.bits == source.bits
75
+
76
+ copied = RawValue(source)
77
+ assert copied.scalar == source.scalar
78
+ assert copied.bits == source.bits
@@ -16,6 +16,7 @@ from .scalar import (
16
16
  UInt8,
17
17
  )
18
18
  from .array import Array
19
+ from .raw_union import RawUnion
19
20
  from .string import String
20
21
  from .struct import Struct, Field, ThisClass
21
22
  from .ref import Ref, UnionRef
@@ -0,0 +1 @@
1
+ __version__ = "0.7.1"
@@ -414,7 +414,7 @@ class Array(metaclass=MetaArray):
414
414
  return info
415
415
 
416
416
  @classmethod
417
- def _from_buffer(cls, buffer, offset=0):
417
+ def _from_buffer(cls, buffer, offset=0, container=None):
418
418
  self = object.__new__(cls)
419
419
  self._buffer = buffer
420
420
  self._offset = offset
@@ -451,7 +451,7 @@ class Array(metaclass=MetaArray):
451
451
  return self
452
452
 
453
453
  @classmethod
454
- def _to_buffer(cls, buffer, offset, value, info=None):
454
+ def _to_buffer(cls, buffer, offset, value, info=None, container=None):
455
455
  if info is None:
456
456
  info = cls._inspect_args(value)
457
457
  value = info.value # can be None if value contained shape info