xobjects 0.3.1__tar.gz → 0.4.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 (51) hide show
  1. {xobjects-0.3.1/xobjects.egg-info → xobjects-0.4.1}/PKG-INFO +1 -1
  2. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_array.py +6 -0
  3. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_hybrid_class.py +20 -0
  4. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/__init__.py +2 -0
  5. xobjects-0.4.1/xobjects/_version.py +1 -0
  6. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/array.py +8 -4
  7. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/context_cpu.py +6 -4
  8. xobjects-0.4.1/xobjects/general.py +24 -0
  9. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/hybrid_class.py +56 -24
  10. {xobjects-0.3.1 → xobjects-0.4.1/xobjects.egg-info}/PKG-INFO +1 -1
  11. xobjects-0.3.1/xobjects/_version.py +0 -1
  12. xobjects-0.3.1/xobjects/general.py +0 -9
  13. {xobjects-0.3.1 → xobjects-0.4.1}/LICENSE +0 -0
  14. {xobjects-0.3.1 → xobjects-0.4.1}/pyproject.toml +0 -0
  15. {xobjects-0.3.1 → xobjects-0.4.1}/setup.cfg +0 -0
  16. {xobjects-0.3.1 → xobjects-0.4.1}/setup.py +0 -0
  17. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_align.py +0 -0
  18. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_buffer.py +0 -0
  19. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_capi.py +0 -0
  20. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_chunk.py +0 -0
  21. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_context_opencl.py +0 -0
  22. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_kernel.py +0 -0
  23. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_linked_array.py +0 -0
  24. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_nplike_arrays.py +0 -0
  25. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_ref.py +0 -0
  26. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_scalars.py +0 -0
  27. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_shared_memory.py +0 -0
  28. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_strides.py +0 -0
  29. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_string.py +0 -0
  30. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_struct.py +0 -0
  31. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_to_json.py +0 -0
  32. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_typeutils.py +0 -0
  33. {xobjects-0.3.1 → xobjects-0.4.1}/tests/test_unionref.py +0 -0
  34. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/_patch_pyopencl_array.py +0 -0
  35. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/capi.py +0 -0
  36. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/context.py +0 -0
  37. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/context_cupy.py +0 -0
  38. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/context_pyopencl.py +0 -0
  39. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/linkedarray.py +0 -0
  40. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/ref.py +0 -0
  41. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/scalar.py +0 -0
  42. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/specialize_source.py +0 -0
  43. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/string.py +0 -0
  44. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/struct.py +0 -0
  45. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/test_helpers.py +0 -0
  46. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/typeutils.py +0 -0
  47. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects/union.py +0 -0
  48. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects.egg-info/SOURCES.txt +0 -0
  49. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects.egg-info/dependency_links.txt +0 -0
  50. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects.egg-info/requires.txt +0 -0
  51. {xobjects-0.3.1 → xobjects-0.4.1}/xobjects.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xobjects
3
- Version: 0.3.1
3
+ Version: 0.4.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
@@ -125,6 +125,12 @@ def test_array_allocation():
125
125
  assert ss._itemtype == xo.Int64
126
126
 
127
127
 
128
+ def test_static_array_allocation_with_none():
129
+ MyArray = xo.Int64[10]
130
+ ss = MyArray(None)
131
+ assert ss._itemtype == xo.Int64
132
+
133
+
128
134
  def test_array_sshape_stype():
129
135
  Array1D = xo.Int64[3]
130
136
  Array2D = xo.Int64[2, 3]
@@ -310,3 +310,23 @@ def test_move_field_of_nested_fails(classes_for_test_hybrid_class_ref):
310
310
 
311
311
  with pytest.raises(MemoryError):
312
312
  outer.inner.move(_buffer=different_buffer)
313
+
314
+
315
+ def test_to_json_defaults():
316
+ class A(xo.HybridClass):
317
+ _xofields = {
318
+ "a": xo.Float64[3],
319
+ "b": xo.Int64,
320
+ "c": xo.Field(xo.Int32, default=42),
321
+ "d": xo.Field(xo.Int32, default_factory=lambda: 7),
322
+ }
323
+
324
+ a = A(c=42)
325
+ assert a.to_dict() == {"__class__": "A"}
326
+
327
+ b = A(a=[1, 2, 3], d=8)
328
+ b_dict = b.to_dict()
329
+ assert b_dict.pop("__class__") == "A"
330
+ assert np.all(b_dict.pop("a") == [1, 2, 3])
331
+ assert b_dict.pop("d") == 8
332
+ assert b_dict == {}
@@ -36,4 +36,6 @@ from .linkedarray import BypassLinked
36
36
 
37
37
  from .general import _print
38
38
 
39
+ from .general import assert_allclose
40
+
39
41
  from ._version import __version__
@@ -0,0 +1 @@
1
+ __version__ = "0.4.1"
@@ -307,10 +307,14 @@ class Array(metaclass=MetaArray):
307
307
  if len(args) == 0:
308
308
  value = None
309
309
  elif len(args) == 1:
310
- shape = get_shape_from_array(args[0], len(cls._shape))
311
- if shape != cls._shape:
312
- raise ValueError(f"shape not valid for {args[0]} ")
313
- value = args[0]
310
+ (arg,) = args
311
+ if arg is None:
312
+ value = None
313
+ else:
314
+ shape = get_shape_from_array(arg, len(cls._shape))
315
+ if shape != cls._shape:
316
+ raise ValueError(f"shape not valid for {arg} ")
317
+ value = arg
314
318
  elif len(args) > 1:
315
319
  raise ValueError("too many arguments")
316
320
  size = cls._size
@@ -146,7 +146,7 @@ class ContextCpu(XContext):
146
146
  """
147
147
  super().__init__()
148
148
  self.omp_num_threads = omp_num_threads
149
- if omp_num_threads==0:
149
+ if omp_num_threads == 0:
150
150
  self.allow_prebuilt_kernels = True
151
151
 
152
152
  def __str__(self):
@@ -517,10 +517,12 @@ class ContextCpu(XContext):
517
517
  def cffi_module_for_c_types(c_types, containing_dir="."):
518
518
  path = Path(containing_dir)
519
519
  for file in path.iterdir():
520
- if not file.suffix in ['.so', '.dylib', '.dll']:
520
+ if not file.suffix in [".so", ".dylib", ".dll"]:
521
521
  continue
522
- module_name = file.name.split('.')[0]
523
- spec = importlib.util.spec_from_file_location(module_name, str(file))
522
+ module_name = file.name.split(".")[0]
523
+ spec = importlib.util.spec_from_file_location(
524
+ module_name, str(file)
525
+ )
524
526
  module = importlib.util.module_from_spec(spec)
525
527
 
526
528
  typedefs = module.ffi.list_types()[0]
@@ -0,0 +1,24 @@
1
+ # copyright ################################# #
2
+ # This file is part of the Xobjects Package. #
3
+ # Copyright (c) CERN, 2024. #
4
+ # ########################################### #
5
+ from numpy.testing import assert_allclose as np_assert_allclose
6
+
7
+
8
+ class Print:
9
+ suppress = False
10
+
11
+ def __call__(self, *args, **kwargs):
12
+ if not self.suppress:
13
+ print(*args, **kwargs)
14
+
15
+
16
+ _print = Print()
17
+
18
+
19
+ def assert_allclose(a, b, rtol=1e-7, atol=1e-7):
20
+ if hasattr(a, "get"):
21
+ a = a.get()
22
+ if hasattr(b, "get"):
23
+ b = b.get()
24
+ np_assert_allclose(a, b, rtol=rtol, atol=atol)
@@ -40,13 +40,17 @@ class _FieldOfDressed:
40
40
  if self.isnplikearray:
41
41
  self.__get__(container=container)[:] = value
42
42
  elif hasattr(value, "_xobject"): # value is a dressed xobject
43
+
43
44
  # Copy xobject data from value inside self._xobject
44
45
  # (unless same memory area or Ref and same buffer,
45
46
  # in the latter case reference mechanism is used)
46
47
  if not (
47
48
  container._xobject._buffer is value._xobject._buffer
48
- and getattr(container._xobject, self.name)._offset
49
- == value._xobject._offset
49
+ and (
50
+ getattr(container._xobject, self.name) is not None
51
+ and getattr(container._xobject, self.name)._offset
52
+ == value._xobject._offset
53
+ )
50
54
  ):
51
55
  setattr(container._xobject, self.name, value._xobject)
52
56
 
@@ -198,15 +202,16 @@ class MetaHybridClass(type):
198
202
  class HybridClass(metaclass=MetaHybridClass):
199
203
  _movable = True
200
204
  _overridable = True
205
+ _force_moveable = False
201
206
 
202
207
  def move(self, _context=None, _buffer=None, _offset=None):
203
- if not self._movable:
208
+ if not self._movable and not self._force_moveable:
204
209
  raise MemoryError(
205
210
  "This object cannot be moved, likely because it "
206
211
  "lives within another. Please, make a copy."
207
212
  )
208
213
 
209
- if self._xobject._has_refs:
214
+ if self._xobject._has_refs and not self._force_moveable:
210
215
  raise MemoryError(
211
216
  "This object cannot be moved, as it contains "
212
217
  "references to other objects."
@@ -285,34 +290,33 @@ class HybridClass(metaclass=MetaHybridClass):
285
290
  else:
286
291
  obj = self
287
292
 
288
- for ff in obj._fields:
289
- if (
290
- hasattr(self, "_skip_in_to_dict")
291
- and ff in self._skip_in_to_dict
292
- ):
293
- continue
293
+ skip_fields = set(getattr(obj, "_skip_in_to_dict", []))
294
+ additional_fields = set(getattr(obj, "_store_in_to_dict", []))
295
+ fields_to_store = (set(obj._fields) - skip_fields) | additional_fields
296
+
297
+ defaults = {}
298
+ for field in obj._XoStruct._fields:
299
+ try:
300
+ defaults[field.name] = field.get_default()
301
+ except (TypeError, ValueError):
302
+ # The above can fail with different error types
303
+ # if a field type is dynamic.
304
+ pass
305
+
306
+ for ff in fields_to_store:
294
307
  vv = getattr(obj, ff)
295
308
  if hasattr(vv, "to_dict"):
296
309
  out[ff] = vv.to_dict()
297
310
  elif hasattr(vv, "_to_dict"):
298
311
  out[ff] = vv._to_dict()
299
- else:
312
+ elif np.any(defaults.get(ff) != vv):
313
+ # Only include those scalar values that are not default.
300
314
  out[ff] = vv
301
315
 
302
- if hasattr(obj, "_store_in_to_dict"):
303
- for nn in obj._store_in_to_dict:
304
- ww = getattr(obj, nn)
305
- if hasattr(ww, "to_dict"):
306
- out[nn] = ww.to_dict()
307
- elif hasattr(ww, "_to_dict"):
308
- out[nn] = ww._to_dict()
309
- else:
310
- out[nn] = ww
311
-
312
316
  return out
313
317
 
314
- @classmethod
315
- def from_dict(cls, dct, _context=None, _buffer=None, _offset=None):
318
+ @staticmethod
319
+ def _static_from_dict(cls, dct, _context=None, _buffer=None, _offset=None):
316
320
  return cls(
317
321
  **dct,
318
322
  _context=_context,
@@ -321,6 +325,16 @@ class HybridClass(metaclass=MetaHybridClass):
321
325
  _kwargs_name_check=False,
322
326
  )
323
327
 
328
+ @classmethod
329
+ def from_dict(cls, dct, _context=None, _buffer=None, _offset=None):
330
+ return HybridClass._static_from_dict(
331
+ cls,
332
+ dct,
333
+ _context=_context,
334
+ _buffer=_buffer,
335
+ _offset=_offset,
336
+ )
337
+
324
338
  def copy(self, _context=None, _buffer=None, _offset=None):
325
339
  if _context is None and _buffer is None:
326
340
  _context = self._xobject._buffer.context
@@ -367,7 +381,25 @@ class HybridClass(metaclass=MetaHybridClass):
367
381
  return self._xobject.compile_kernels(*args, **kwargs)
368
382
 
369
383
  def __repr__(self):
370
- args = [f"{fname}={getattr(self, fname)}" for fname in self._fields]
384
+
385
+ if hasattr(self, "_repr_fields"):
386
+ fnames = self._repr_fields
387
+ else:
388
+ fnames = []
389
+ if hasattr(self, "_add_to_repr"):
390
+ fnames += self._add_to_repr
391
+ fnames += [fname for fname in self._fields]
392
+ if hasattr(self, "_skip_in_repr"):
393
+ fnames = [ff for ff in fnames if ff not in self._skip_in_repr]
394
+
395
+ args = []
396
+ for fname in fnames:
397
+ vv = getattr(self, fname)
398
+ if isinstance(vv, float):
399
+ vvrepr = f"{vv:.3g}"
400
+ else:
401
+ vvrepr = repr(vv)
402
+ args.append(f"{fname}={vvrepr}")
371
403
  return f'{type(self).__name__}({", ".join(args)})'
372
404
 
373
405
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xobjects
3
- Version: 0.3.1
3
+ Version: 0.4.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
@@ -1 +0,0 @@
1
- __version__ = "0.3.1"
@@ -1,9 +0,0 @@
1
- class Print:
2
- suppress = False
3
-
4
- def __call__(self, *args, **kwargs):
5
- if not self.suppress:
6
- print(*args, **kwargs)
7
-
8
-
9
- _print = Print()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes