xobjects 0.3.1__tar.gz → 0.4.0__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 (50) hide show
  1. {xobjects-0.3.1/xobjects.egg-info → xobjects-0.4.0}/PKG-INFO +1 -1
  2. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_array.py +6 -0
  3. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_hybrid_class.py +20 -0
  4. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/__init__.py +2 -0
  5. xobjects-0.4.0/xobjects/_version.py +1 -0
  6. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/array.py +8 -4
  7. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/context_cpu.py +6 -4
  8. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/hybrid_class.py +52 -24
  9. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/test_helpers.py +8 -0
  10. {xobjects-0.3.1 → xobjects-0.4.0/xobjects.egg-info}/PKG-INFO +1 -1
  11. xobjects-0.3.1/xobjects/_version.py +0 -1
  12. {xobjects-0.3.1 → xobjects-0.4.0}/LICENSE +0 -0
  13. {xobjects-0.3.1 → xobjects-0.4.0}/pyproject.toml +0 -0
  14. {xobjects-0.3.1 → xobjects-0.4.0}/setup.cfg +0 -0
  15. {xobjects-0.3.1 → xobjects-0.4.0}/setup.py +0 -0
  16. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_align.py +0 -0
  17. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_buffer.py +0 -0
  18. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_capi.py +0 -0
  19. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_chunk.py +0 -0
  20. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_context_opencl.py +0 -0
  21. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_kernel.py +0 -0
  22. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_linked_array.py +0 -0
  23. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_nplike_arrays.py +0 -0
  24. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_ref.py +0 -0
  25. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_scalars.py +0 -0
  26. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_shared_memory.py +0 -0
  27. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_strides.py +0 -0
  28. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_string.py +0 -0
  29. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_struct.py +0 -0
  30. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_to_json.py +0 -0
  31. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_typeutils.py +0 -0
  32. {xobjects-0.3.1 → xobjects-0.4.0}/tests/test_unionref.py +0 -0
  33. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/_patch_pyopencl_array.py +0 -0
  34. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/capi.py +0 -0
  35. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/context.py +0 -0
  36. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/context_cupy.py +0 -0
  37. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/context_pyopencl.py +0 -0
  38. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/general.py +0 -0
  39. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/linkedarray.py +0 -0
  40. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/ref.py +0 -0
  41. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/scalar.py +0 -0
  42. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/specialize_source.py +0 -0
  43. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/string.py +0 -0
  44. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/struct.py +0 -0
  45. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/typeutils.py +0 -0
  46. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects/union.py +0 -0
  47. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects.egg-info/SOURCES.txt +0 -0
  48. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects.egg-info/dependency_links.txt +0 -0
  49. {xobjects-0.3.1 → xobjects-0.4.0}/xobjects.egg-info/requires.txt +0 -0
  50. {xobjects-0.3.1 → xobjects-0.4.0}/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.0
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 .test_helpers import assert_allclose
40
+
39
41
  from ._version import __version__
@@ -0,0 +1 @@
1
+ __version__ = "0.4.0"
@@ -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]
@@ -40,13 +40,14 @@ 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 (getattr(container._xobject, self.name) is not None and
50
+ getattr(container._xobject, self.name)._offset == value._xobject._offset)
50
51
  ):
51
52
  setattr(container._xobject, self.name, value._xobject)
52
53
 
@@ -198,15 +199,16 @@ class MetaHybridClass(type):
198
199
  class HybridClass(metaclass=MetaHybridClass):
199
200
  _movable = True
200
201
  _overridable = True
202
+ _force_moveable = False
201
203
 
202
204
  def move(self, _context=None, _buffer=None, _offset=None):
203
- if not self._movable:
205
+ if not self._movable and not self._force_moveable:
204
206
  raise MemoryError(
205
207
  "This object cannot be moved, likely because it "
206
208
  "lives within another. Please, make a copy."
207
209
  )
208
210
 
209
- if self._xobject._has_refs:
211
+ if self._xobject._has_refs and not self._force_moveable:
210
212
  raise MemoryError(
211
213
  "This object cannot be moved, as it contains "
212
214
  "references to other objects."
@@ -285,34 +287,33 @@ class HybridClass(metaclass=MetaHybridClass):
285
287
  else:
286
288
  obj = self
287
289
 
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
290
+ skip_fields = set(getattr(obj, "_skip_in_to_dict", []))
291
+ additional_fields = set(getattr(obj, "_store_in_to_dict", []))
292
+ fields_to_store = (set(obj._fields) - skip_fields) | additional_fields
293
+
294
+ defaults = {}
295
+ for field in obj._XoStruct._fields:
296
+ try:
297
+ defaults[field.name] = field.get_default()
298
+ except (TypeError, ValueError):
299
+ # The above can fail with different error types
300
+ # if a field type is dynamic.
301
+ pass
302
+
303
+ for ff in fields_to_store:
294
304
  vv = getattr(obj, ff)
295
305
  if hasattr(vv, "to_dict"):
296
306
  out[ff] = vv.to_dict()
297
307
  elif hasattr(vv, "_to_dict"):
298
308
  out[ff] = vv._to_dict()
299
- else:
309
+ elif np.any(defaults.get(ff) != vv):
310
+ # Only include those scalar values that are not default.
300
311
  out[ff] = vv
301
312
 
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
313
  return out
313
314
 
314
- @classmethod
315
- def from_dict(cls, dct, _context=None, _buffer=None, _offset=None):
315
+ @staticmethod
316
+ def _static_from_dict(cls, dct, _context=None, _buffer=None, _offset=None):
316
317
  return cls(
317
318
  **dct,
318
319
  _context=_context,
@@ -321,6 +322,15 @@ class HybridClass(metaclass=MetaHybridClass):
321
322
  _kwargs_name_check=False,
322
323
  )
323
324
 
325
+ @classmethod
326
+ def from_dict(cls, dct, _context=None, _buffer=None, _offset=None):
327
+ return HybridClass._static_from_dict(cls,
328
+ dct,
329
+ _context=_context,
330
+ _buffer=_buffer,
331
+ _offset=_offset,
332
+ )
333
+
324
334
  def copy(self, _context=None, _buffer=None, _offset=None):
325
335
  if _context is None and _buffer is None:
326
336
  _context = self._xobject._buffer.context
@@ -367,7 +377,25 @@ class HybridClass(metaclass=MetaHybridClass):
367
377
  return self._xobject.compile_kernels(*args, **kwargs)
368
378
 
369
379
  def __repr__(self):
370
- args = [f"{fname}={getattr(self, fname)}" for fname in self._fields]
380
+
381
+ if hasattr(self, "_repr_fields"):
382
+ fnames = self._repr_fields
383
+ else:
384
+ fnames = []
385
+ if hasattr(self, "_add_to_repr"):
386
+ fnames += self._add_to_repr
387
+ fnames += [fname for fname in self._fields]
388
+ if hasattr(self, "_skip_in_repr"):
389
+ fnames = [ff for ff in fnames if ff not in self._skip_in_repr]
390
+
391
+ args = []
392
+ for fname in fnames:
393
+ vv = getattr(self, fname)
394
+ if isinstance(vv, float):
395
+ vvrepr = f"{vv:.3g}"
396
+ else:
397
+ vvrepr = repr(vv)
398
+ args.append(f"{fname}={vvrepr}")
371
399
  return f'{type(self).__name__}({", ".join(args)})'
372
400
 
373
401
 
@@ -5,6 +5,7 @@
5
5
 
6
6
  from functools import wraps
7
7
  from typing import Callable, Iterable, Union
8
+ from numpy.testing import assert_allclose as np_assert_allclose
8
9
 
9
10
  import pytest
10
11
 
@@ -83,3 +84,10 @@ def requires_context(context_name: str):
83
84
  return lambda test_function: test_function
84
85
 
85
86
  return pytest.mark.skip(f"{context_name} is unavailable on this platform.")
87
+
88
+ def assert_allclose(a, b, rtol=1e-7, atol=1e-7):
89
+ if hasattr(a, 'get'):
90
+ a = a.get()
91
+ if hasattr(b, 'get'):
92
+ b = b.get()
93
+ np_assert_allclose(a, b, rtol=rtol, atol=atol)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xobjects
3
- Version: 0.3.1
3
+ Version: 0.4.0
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"
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
File without changes