easyscience 1.0.0__tar.gz → 1.1.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 (64) hide show
  1. {easyscience-1.0.0 → easyscience-1.1.0}/PKG-INFO +5 -7
  2. {easyscience-1.0.0 → easyscience-1.1.0}/pyproject.toml +7 -10
  3. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/Groups.py +11 -8
  4. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/ObjectClasses.py +11 -3
  5. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/Variable.py +2 -2
  6. easyscience-1.1.0/src/easyscience/Objects/new_variable/__init__.py +11 -0
  7. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/new_variable/descriptor_base.py +5 -7
  8. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/new_variable/descriptor_number.py +70 -66
  9. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/new_variable/parameter.py +109 -101
  10. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/virtual.py +1 -1
  11. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/classTools.py +4 -6
  12. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/io/template.py +7 -3
  13. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/__init__.py +12 -9
  14. easyscience-1.1.0/src/easyscience/__version__.py +1 -0
  15. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/available_minimizers.py +33 -24
  16. easyscience-1.1.0/src/easyscience/fitting/minimizers/factory.py +25 -0
  17. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/minimizers/minimizer_base.py +16 -17
  18. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/minimizers/minimizer_bumps.py +5 -10
  19. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/minimizers/minimizer_dfo.py +8 -14
  20. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/minimizers/minimizer_lmfit.py +6 -9
  21. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/global_object/map.py +6 -17
  22. easyscience-1.0.0/src/easyscience/Objects/new_variable/__init__.py +0 -4
  23. easyscience-1.0.0/src/easyscience/__version__.py +0 -1
  24. easyscience-1.0.0/src/easyscience/fitting/minimizers/factory.py +0 -43
  25. {easyscience-1.0.0 → easyscience-1.1.0}/.gitignore +0 -0
  26. {easyscience-1.0.0 → easyscience-1.1.0}/LICENSE +0 -0
  27. {easyscience-1.0.0 → easyscience-1.1.0}/README.md +0 -0
  28. {easyscience-1.0.0/src/easyscience/fitting → easyscience-1.1.0/src/easyscience}/Constraints.py +0 -0
  29. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Datasets/__init__.py +0 -0
  30. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Datasets/xarray.py +0 -0
  31. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/Inferface.py +0 -0
  32. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/__init__.py +0 -0
  33. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/core.py +0 -0
  34. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/job/__init__.py +0 -0
  35. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/job/analysis.py +0 -0
  36. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/job/experiment.py +0 -0
  37. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/job/job.py +0 -0
  38. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/job/theoreticalmodel.py +0 -0
  39. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/new_variable/descriptor_bool.py +0 -0
  40. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Objects/new_variable/descriptor_str.py +0 -0
  41. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/REDIRECT.py +0 -0
  42. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/Exceptions.py +0 -0
  43. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/__init__.py +0 -0
  44. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/classUtils.py +0 -0
  45. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/decorators.py +0 -0
  46. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/io/__init__.py +0 -0
  47. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/io/dict.py +0 -0
  48. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/io/json.py +0 -0
  49. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/io/xml.py +0 -0
  50. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/Utils/string.py +0 -0
  51. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/__init__.py +0 -0
  52. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/fitter.py +0 -0
  53. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/minimizers/__init__.py +0 -0
  54. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/minimizers/utils.py +0 -0
  55. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/fitting/multi_fitter.py +0 -0
  56. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/global_object/__init__.py +0 -0
  57. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/global_object/global_object.py +0 -0
  58. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/global_object/hugger/__init__.py +0 -0
  59. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/global_object/hugger/hugger.py +0 -0
  60. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/global_object/hugger/property.py +0 -0
  61. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/global_object/logger.py +0 -0
  62. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/global_object/undo_redo.py +0 -0
  63. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/models/__init__.py +0 -0
  64. {easyscience-1.0.0 → easyscience-1.1.0}/src/easyscience/models/polynomial.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: easyscience
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Generic logic for easyScience libraries
5
- Project-URL: homepage, https://docs.easyscience.org
6
- Project-URL: documentation, https://docs.easyscience.org
5
+ Project-URL: homepage, https://github.com/EasyScience/EasyScience
6
+ Project-URL: documentation, https://easyscience.github.io/EasyScience/
7
7
  Author: EasyScience contributors
8
8
  License: BSD 3-Clause License
9
9
 
@@ -40,13 +40,12 @@ Classifier: License :: OSI Approved :: BSD License
40
40
  Classifier: Operating System :: OS Independent
41
41
  Classifier: Programming Language :: Python :: 3
42
42
  Classifier: Programming Language :: Python :: 3 :: Only
43
- Classifier: Programming Language :: Python :: 3.8
44
43
  Classifier: Programming Language :: Python :: 3.9
45
44
  Classifier: Programming Language :: Python :: 3.10
46
45
  Classifier: Programming Language :: Python :: 3.11
47
46
  Classifier: Programming Language :: Python :: 3.12
48
47
  Classifier: Topic :: Scientific/Engineering
49
- Requires-Python: <3.12,>=3.8
48
+ Requires-Python: <3.13,>=3.9
50
49
  Requires-Dist: asteval
51
50
  Requires-Dist: bumps
52
51
  Requires-Dist: dfo-ls
@@ -68,10 +67,9 @@ Requires-Dist: tox-gh-actions; extra == 'dev'
68
67
  Provides-Extra: docs
69
68
  Requires-Dist: doc8; extra == 'docs'
70
69
  Requires-Dist: readme-renderer; extra == 'docs'
71
- Requires-Dist: sphinx; extra == 'docs'
72
70
  Requires-Dist: sphinx-autodoc-typehints; extra == 'docs'
71
+ Requires-Dist: sphinx-book-theme; extra == 'docs'
73
72
  Requires-Dist: sphinx-gallery; extra == 'docs'
74
- Requires-Dist: sphinx-rtd-theme; extra == 'docs'
75
73
  Requires-Dist: toml; extra == 'docs'
76
74
  Description-Content-Type: text/markdown
77
75
 
@@ -21,14 +21,13 @@ classifiers = [
21
21
  "Topic :: Scientific/Engineering",
22
22
  "Programming Language :: Python :: 3",
23
23
  "Programming Language :: Python :: 3 :: Only",
24
- "Programming Language :: Python :: 3.8",
25
24
  "Programming Language :: Python :: 3.9",
26
25
  "Programming Language :: Python :: 3.10",
27
26
  "Programming Language :: Python :: 3.11",
28
27
  "Programming Language :: Python :: 3.12",
29
28
  "Development Status :: 3 - Alpha"
30
29
  ]
31
- requires-python = ">=3.8,<3.12"
30
+ requires-python = ">=3.9,<3.13"
32
31
  dependencies = [
33
32
  "asteval",
34
33
  "bumps",
@@ -55,16 +54,15 @@ dev = [
55
54
  docs = [
56
55
  "doc8",
57
56
  "readme-renderer",
58
- "Sphinx",
59
- "sphinx-rtd-theme",
60
- "sphinx-autodoc-typehints",
61
- "sphinx-gallery",
57
+ "sphinx_autodoc_typehints",
58
+ "sphinx_book_theme",
59
+ "sphinx_gallery",
62
60
  "toml"
63
61
  ]
64
62
 
65
63
  [project.urls]
66
- homepage = "https://docs.easyscience.org"
67
- documentation = "https://docs.easyscience.org"
64
+ homepage = "https://github.com/EasyScience/EasyScience"
65
+ documentation = "https://easyscience.github.io/EasyScience/"
68
66
 
69
67
  [tool.hatch.version]
70
68
  path = "src/easyscience/__version__.py"
@@ -130,10 +128,9 @@ force-single-line = true
130
128
  legacy_tox_ini = """
131
129
  [tox]
132
130
  isolated_build = True
133
- envlist = py{3.8,3.9,3.10,3.11,3.12}
131
+ envlist = py{3.9,3.10,3.11,3.12}
134
132
  [gh-actions]
135
133
  python =
136
- 3.8: py38
137
134
  3.9: py39
138
135
  3.10: py310
139
136
  3.11: py311
@@ -18,6 +18,7 @@ from typing import Tuple
18
18
  from typing import Union
19
19
 
20
20
  from easyscience.global_object.undo_redo import NotarizedDict
21
+ from easyscience.Objects.new_variable.descriptor_base import DescriptorBase
21
22
  from easyscience.Objects.ObjectClasses import BasedBase
22
23
  from easyscience.Objects.ObjectClasses import Descriptor
23
24
 
@@ -40,6 +41,7 @@ class BaseCollection(BasedBase, MutableSequence):
40
41
  name: str,
41
42
  *args: Union[B, V],
42
43
  interface: Optional[iF] = None,
44
+ unique_name: Optional[str] = None,
43
45
  **kwargs,
44
46
  ):
45
47
  """
@@ -51,7 +53,7 @@ class BaseCollection(BasedBase, MutableSequence):
51
53
  :param _kwargs: Fields which this class should contain
52
54
  :type _kwargs: dict
53
55
  """
54
- BasedBase.__init__(self, name)
56
+ BasedBase.__init__(self, name, unique_name=unique_name)
55
57
  kwargs = {key: kwargs[key] for key in kwargs.keys() if kwargs[key] is not None}
56
58
  _args = []
57
59
  for item in args:
@@ -67,7 +69,7 @@ class BaseCollection(BasedBase, MutableSequence):
67
69
  _kwargs[key] = item
68
70
  kwargs = _kwargs
69
71
  for item in list(kwargs.values()) + _args:
70
- if not issubclass(type(item), (Descriptor, BasedBase)):
72
+ if not issubclass(type(item), (Descriptor, DescriptorBase, BasedBase)):
71
73
  raise AttributeError('A collection can only be formed from easyscience objects.')
72
74
  args = _args
73
75
  _kwargs = {}
@@ -83,10 +85,11 @@ class BaseCollection(BasedBase, MutableSequence):
83
85
  for key in kwargs.keys():
84
86
  if key in self.__dict__.keys() or key in self.__slots__:
85
87
  raise AttributeError(f'Given kwarg: `{key}`, is an internal attribute. Please rename.')
86
- self._global_object.map.add_edge(self, kwargs[key])
87
- self._global_object.map.reset_type(kwargs[key], 'created_internal')
88
- if interface is not None:
89
- kwargs[key].interface = interface
88
+ if kwargs[key]: # Might be None (empty tuple or list)
89
+ self._global_object.map.add_edge(self, kwargs[key])
90
+ self._global_object.map.reset_type(kwargs[key], 'created_internal')
91
+ if interface is not None:
92
+ kwargs[key].interface = interface
90
93
  # TODO wrap getter and setter in Logger
91
94
  if interface is not None:
92
95
  self.interface = interface
@@ -104,7 +107,7 @@ class BaseCollection(BasedBase, MutableSequence):
104
107
  :rtype: None
105
108
  """
106
109
  t_ = type(value)
107
- if issubclass(t_, (BasedBase, Descriptor)):
110
+ if issubclass(t_, (BasedBase, Descriptor, DescriptorBase)):
108
111
  update_key = list(self._kwargs.keys())
109
112
  values = list(self._kwargs.values())
110
113
  # Update the internal dict
@@ -165,7 +168,7 @@ class BaseCollection(BasedBase, MutableSequence):
165
168
  if isinstance(value, Number): # noqa: S3827
166
169
  item = self.__getitem__(key)
167
170
  item.value = value
168
- elif issubclass(type(value), BasedBase) or issubclass(type(value), Descriptor):
171
+ elif issubclass(type(value), (BasedBase, Descriptor, DescriptorBase)):
169
172
  update_key = list(self._kwargs.keys())
170
173
  values = list(self._kwargs.values())
171
174
  old_item = values[key]
@@ -28,7 +28,7 @@ from .Variable import Descriptor
28
28
  from .Variable import Parameter
29
29
 
30
30
  if TYPE_CHECKING:
31
- from easyscience.fitting.Constraints import C
31
+ from easyscience.Constraints import C
32
32
  from easyscience.Objects.Inferface import iF
33
33
  from easyscience.Objects.Variable import V
34
34
 
@@ -186,7 +186,7 @@ class BasedBase(ComponentSerializer):
186
186
  for key, item in self._kwargs.items():
187
187
  if hasattr(item, '_get_linkable_attributes'):
188
188
  item_list = [*item_list, *item._get_linkable_attributes()]
189
- elif issubclass(type(item), Descriptor) or issubclass(type(item), DescriptorBase):
189
+ elif issubclass(type(item), (Descriptor, DescriptorBase)):
190
190
  item_list.append(item)
191
191
  return item_list
192
192
 
@@ -215,6 +215,12 @@ class BasedBase(ComponentSerializer):
215
215
  new_class_objs = list(k for k in dir(self.__class__) if not k.startswith('_'))
216
216
  return sorted(new_class_objs)
217
217
 
218
+ def __copy__(self) -> BasedBase:
219
+ """Return a copy of the object."""
220
+ temp = self.as_dict(skip=['unique_name'])
221
+ new_obj = self.__class__.from_dict(temp)
222
+ return new_obj
223
+
218
224
 
219
225
  if TYPE_CHECKING:
220
226
  B = TypeVar('B', bound=BasedBase)
@@ -346,7 +352,9 @@ class BaseObj(BasedBase):
346
352
  @staticmethod
347
353
  def __setter(key: str) -> Callable[[BV], None]:
348
354
  def setter(obj: BV, value: float) -> None:
349
- if issubclass(obj._kwargs[key].__class__, Descriptor) and not issubclass(value.__class__, Descriptor):
355
+ if issubclass(obj._kwargs[key].__class__, (Descriptor, DescriptorBase)) and not issubclass(
356
+ value.__class__, (Descriptor, DescriptorBase)
357
+ ):
350
358
  obj._kwargs[key].value = value
351
359
  else:
352
360
  obj._kwargs[key] = value
@@ -30,14 +30,14 @@ import numpy as np
30
30
  from easyscience import global_object
31
31
  from easyscience import pint
32
32
  from easyscience import ureg
33
- from easyscience.fitting.Constraints import SelfConstraint
33
+ from easyscience.Constraints import SelfConstraint
34
34
  from easyscience.global_object.undo_redo import property_stack_deco
35
35
  from easyscience.Objects.core import ComponentSerializer
36
36
  from easyscience.Utils.classTools import addProp
37
37
  from easyscience.Utils.Exceptions import CoreSetException
38
38
 
39
39
  if TYPE_CHECKING:
40
- from easyscience.fitting.Constraints import C
40
+ from easyscience.Constraints import C
41
41
 
42
42
  Q_ = ureg.Quantity
43
43
  M_ = ureg.Measurement
@@ -0,0 +1,11 @@
1
+ from .descriptor_bool import DescriptorBool
2
+ from .descriptor_number import DescriptorNumber
3
+ from .descriptor_str import DescriptorStr
4
+ from .parameter import Parameter
5
+
6
+ __all__ = [
7
+ DescriptorBool,
8
+ DescriptorNumber,
9
+ DescriptorStr,
10
+ Parameter,
11
+ ]
@@ -27,7 +27,6 @@ class DescriptorBase(ComponentSerializer, metaclass=abc.ABCMeta):
27
27
  # Used by serializer
28
28
  _REDIRECT = {'parent': None}
29
29
 
30
- _global_object = global_object
31
30
 
32
31
  def __init__(
33
32
  self,
@@ -55,7 +54,7 @@ class DescriptorBase(ComponentSerializer, metaclass=abc.ABCMeta):
55
54
  """
56
55
 
57
56
  if unique_name is None:
58
- unique_name = self._global_object.generate_unique_name(self.__class__.__name__)
57
+ unique_name = global_object.generate_unique_name(self.__class__.__name__)
59
58
  self._unique_name = unique_name
60
59
 
61
60
  if not isinstance(name, str):
@@ -80,10 +79,10 @@ class DescriptorBase(ComponentSerializer, metaclass=abc.ABCMeta):
80
79
 
81
80
  # Let the collective know we've been assimilated
82
81
  self._parent = parent
83
- self._global_object.map.add_vertex(self, obj_type='created')
82
+ global_object.map.add_vertex(self, obj_type='created')
84
83
  # Make the connection between self and parent
85
84
  if parent is not None:
86
- self._global_object.map.add_edge(parent, self)
85
+ global_object.map.add_edge(parent, self)
87
86
 
88
87
  @property
89
88
  def name(self) -> str:
@@ -187,7 +186,7 @@ class DescriptorBase(ComponentSerializer, metaclass=abc.ABCMeta):
187
186
  if not isinstance(new_unique_name, str):
188
187
  raise TypeError('Unique name has to be a string.')
189
188
  self._unique_name = new_unique_name
190
- self._global_object.map.add_vertex(self)
189
+ global_object.map.add_vertex(self)
191
190
 
192
191
  @property
193
192
  @abc.abstractmethod
@@ -205,7 +204,6 @@ class DescriptorBase(ComponentSerializer, metaclass=abc.ABCMeta):
205
204
 
206
205
  def __copy__(self) -> DescriptorBase:
207
206
  """Return a copy of the object."""
208
- temp = self.as_dict()
209
- temp['unique_name'] = None
207
+ temp = self.as_dict(skip=['unique_name'])
210
208
  new_obj = self.__class__.from_dict(temp)
211
209
  return new_obj
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import numbers
4
4
  from typing import Any
5
5
  from typing import Dict
6
+ from typing import List
6
7
  from typing import Optional
7
8
  from typing import Union
8
9
 
@@ -89,7 +90,6 @@ class DescriptorNumber(DescriptorBase):
89
90
  raise TypeError(f'{full_value=} must be a scipp scalar')
90
91
  return cls(name=name, value=full_value.value, unit=full_value.unit, variance=full_value.variance, **kwargs)
91
92
 
92
-
93
93
  @property
94
94
  def full_value(self) -> Variable:
95
95
  """
@@ -101,8 +101,10 @@ class DescriptorNumber(DescriptorBase):
101
101
 
102
102
  @full_value.setter
103
103
  def full_value(self, full_value: Variable) -> None:
104
- raise AttributeError(f'Full_value is read-only. Change the value and variance seperately. Or create a new {self.__class__.__name__}.') # noqa: E501
105
-
104
+ raise AttributeError(
105
+ f'Full_value is read-only. Change the value and variance seperately. Or create a new {self.__class__.__name__}.'
106
+ )
107
+
106
108
  @property
107
109
  def value(self) -> numbers.Number:
108
110
  """
@@ -135,7 +137,12 @@ class DescriptorNumber(DescriptorBase):
135
137
 
136
138
  @unit.setter
137
139
  def unit(self, unit_str: str) -> None:
138
- raise AttributeError(f'Unit is read-only. Use convert_unit to change the unit between allowed types or create a new {self.__class__.__name__} with the desired unit.') # noqa: E501
140
+ raise AttributeError(
141
+ (
142
+ f'Unit is read-only. Use convert_unit to change the unit between allowed types '
143
+ f'or create a new {self.__class__.__name__} with the desired unit.'
144
+ )
145
+ ) # noqa: E501
139
146
 
140
147
  @property
141
148
  def variance(self) -> float:
@@ -162,7 +169,6 @@ class DescriptorNumber(DescriptorBase):
162
169
  variance_float = float(variance_float)
163
170
  self._scalar.variance = variance_float
164
171
 
165
-
166
172
  @property
167
173
  def error(self) -> float:
168
174
  """
@@ -205,94 +211,92 @@ class DescriptorNumber(DescriptorBase):
205
211
  # Just to get return type right
206
212
  def __copy__(self) -> DescriptorNumber:
207
213
  return super().__copy__()
208
-
214
+
209
215
  def __repr__(self) -> str:
210
216
  """Return printable representation."""
211
- string='<'
212
- string+= self.__class__.__name__+' '
213
- string+=f"'{self._name}': "
214
- string+= f'{self._scalar.value:.4f}'
217
+ string = '<'
218
+ string += self.__class__.__name__ + ' '
219
+ string += f"'{self._name}': "
220
+ string += f'{self._scalar.value:.4f}'
215
221
  if self.variance:
216
- string += f' \u00B1 {self.error:.4f}'
222
+ string += f' \u00b1 {self.error:.4f}'
217
223
  obj_unit = self._scalar.unit
218
224
  if obj_unit == 'dimensionless':
219
225
  obj_unit = ''
220
226
  else:
221
227
  obj_unit = f' {obj_unit}'
222
- string+= obj_unit
223
- string+='>'
228
+ string += obj_unit
229
+ string += '>'
224
230
  return string
225
231
  # return f"<{class_name} '{obj_name}': {obj_value:0.04f}{obj_unit}>"
226
232
 
227
- def as_dict(self) -> Dict[str, Any]:
228
- raw_dict = super().as_dict()
233
+ def as_dict(self, skip: Optional[List[str]] = None) -> Dict[str, Any]:
234
+ raw_dict = super().as_dict(skip=skip)
229
235
  raw_dict['value'] = self._scalar.value
230
236
  raw_dict['unit'] = str(self._scalar.unit)
231
237
  raw_dict['variance'] = self._scalar.variance
232
238
  return raw_dict
233
-
239
+
234
240
  def __add__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
235
241
  if isinstance(other, numbers.Number):
236
242
  if self.unit != 'dimensionless':
237
- raise UnitError("Numbers can only be added to dimensionless values")
238
- new_value = self.full_value + other
243
+ raise UnitError('Numbers can only be added to dimensionless values')
244
+ new_value = self.full_value + other
239
245
  elif type(other) is DescriptorNumber:
240
246
  original_unit = other.unit
241
247
  try:
242
248
  other.convert_unit(self.unit)
243
249
  except UnitError:
244
- raise UnitError(f"Values with units {self.unit} and {other.unit} cannot be added") from None
250
+ raise UnitError(f'Values with units {self.unit} and {other.unit} cannot be added') from None
245
251
  new_value = self.full_value + other.full_value
246
252
  other.convert_unit(original_unit)
247
253
  else:
248
254
  return NotImplemented
249
- descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
250
- descriptor_number.name=descriptor_number.unique_name
255
+ descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
256
+ descriptor_number.name = descriptor_number.unique_name
251
257
  return descriptor_number
252
-
253
-
254
258
 
255
259
  def __radd__(self, other: numbers.Number) -> DescriptorNumber:
256
260
  if isinstance(other, numbers.Number):
257
261
  if self.unit != 'dimensionless':
258
- raise UnitError("Numbers can only be added to dimensionless values")
262
+ raise UnitError('Numbers can only be added to dimensionless values')
259
263
  new_value = other + self.full_value
260
264
  else:
261
265
  return NotImplemented
262
- descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
263
- descriptor_number.name=descriptor_number.unique_name
266
+ descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
267
+ descriptor_number.name = descriptor_number.unique_name
264
268
  return descriptor_number
265
269
 
266
270
  def __sub__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
267
271
  if isinstance(other, numbers.Number):
268
272
  if self.unit != 'dimensionless':
269
- raise UnitError("Numbers can only be subtracted from dimensionless values")
273
+ raise UnitError('Numbers can only be subtracted from dimensionless values')
270
274
  new_value = self.full_value - other
271
275
  elif type(other) is DescriptorNumber:
272
276
  original_unit = other.unit
273
277
  try:
274
278
  other.convert_unit(self.unit)
275
279
  except UnitError:
276
- raise UnitError(f"Values with units {self.unit} and {other.unit} cannot be subtracted") from None
280
+ raise UnitError(f'Values with units {self.unit} and {other.unit} cannot be subtracted') from None
277
281
  new_value = self.full_value - other.full_value
278
282
  other.convert_unit(original_unit)
279
283
  else:
280
284
  return NotImplemented
281
- descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
282
- descriptor_number.name=descriptor_number.unique_name
285
+ descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
286
+ descriptor_number.name = descriptor_number.unique_name
283
287
  return descriptor_number
284
-
288
+
285
289
  def __rsub__(self, other: numbers.Number) -> DescriptorNumber:
286
290
  if isinstance(other, numbers.Number):
287
291
  if self.unit != 'dimensionless':
288
- raise UnitError("Numbers can only be subtracted from dimensionless values")
292
+ raise UnitError('Numbers can only be subtracted from dimensionless values')
289
293
  new_value = other - self.full_value
290
294
  else:
291
295
  return NotImplemented
292
- descriptor= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
293
- descriptor.name=descriptor.unique_name
296
+ descriptor = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
297
+ descriptor.name = descriptor.unique_name
294
298
  return descriptor
295
-
299
+
296
300
  def __mul__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
297
301
  if isinstance(other, numbers.Number):
298
302
  new_value = self.full_value * other
@@ -302,46 +306,46 @@ class DescriptorNumber(DescriptorBase):
302
306
  return NotImplemented
303
307
  descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
304
308
  descriptor_number.convert_unit(descriptor_number._base_unit())
305
- descriptor_number.name=descriptor_number.unique_name
309
+ descriptor_number.name = descriptor_number.unique_name
306
310
  return descriptor_number
307
-
311
+
308
312
  def __rmul__(self, other: numbers.Number) -> DescriptorNumber:
309
313
  if isinstance(other, numbers.Number):
310
314
  new_value = other * self.full_value
311
315
  else:
312
316
  return NotImplemented
313
- descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
314
- descriptor_number.name=descriptor_number.unique_name
317
+ descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
318
+ descriptor_number.name = descriptor_number.unique_name
315
319
  return descriptor_number
316
-
320
+
317
321
  def __truediv__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
318
322
  if isinstance(other, numbers.Number):
319
323
  original_other = other
320
324
  if other == 0:
321
- raise ZeroDivisionError("Cannot divide by zero")
325
+ raise ZeroDivisionError('Cannot divide by zero')
322
326
  new_value = self.full_value / other
323
327
  elif type(other) is DescriptorNumber:
324
328
  original_other = other.value
325
329
  if original_other == 0:
326
- raise ZeroDivisionError("Cannot divide by zero")
330
+ raise ZeroDivisionError('Cannot divide by zero')
327
331
  new_value = self.full_value / other.full_value
328
332
  other.value = original_other
329
333
  else:
330
334
  return NotImplemented
331
335
  descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
332
336
  descriptor_number.convert_unit(descriptor_number._base_unit())
333
- descriptor_number.name=descriptor_number.unique_name
337
+ descriptor_number.name = descriptor_number.unique_name
334
338
  return descriptor_number
335
-
339
+
336
340
  def __rtruediv__(self, other: numbers.Number) -> DescriptorNumber:
337
341
  if isinstance(other, numbers.Number):
338
342
  if self.value == 0:
339
- raise ZeroDivisionError("Cannot divide by zero")
343
+ raise ZeroDivisionError('Cannot divide by zero')
340
344
  new_value = other / self.full_value
341
345
  else:
342
346
  return NotImplemented
343
- descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
344
- descriptor_number.name=descriptor_number.unique_name
347
+ descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
348
+ descriptor_number.name = descriptor_number.unique_name
345
349
  return descriptor_number
346
350
 
347
351
  def __pow__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
@@ -349,51 +353,51 @@ class DescriptorNumber(DescriptorBase):
349
353
  exponent = other
350
354
  elif type(other) is DescriptorNumber:
351
355
  if other.unit != 'dimensionless':
352
- raise UnitError("Exponents must be dimensionless")
356
+ raise UnitError('Exponents must be dimensionless')
353
357
  if other.variance is not None:
354
- raise ValueError("Exponents must not have variance")
358
+ raise ValueError('Exponents must not have variance')
355
359
  exponent = other.value
356
360
  else:
357
361
  return NotImplemented
358
362
  try:
359
- new_value = self.full_value ** exponent
363
+ new_value = self.full_value**exponent
360
364
  except Exception as message:
361
365
  raise message from None
362
366
  if np.isnan(new_value.value):
363
- raise ValueError("The result of the exponentiation is not a number")
364
- descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
365
- descriptor_number.name=descriptor_number.unique_name
367
+ raise ValueError('The result of the exponentiation is not a number')
368
+ descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
369
+ descriptor_number.name = descriptor_number.unique_name
366
370
  return descriptor_number
367
-
371
+
368
372
  def __rpow__(self, other: numbers.Number) -> numbers.Number:
369
373
  if isinstance(other, numbers.Number):
370
374
  if self.unit != 'dimensionless':
371
- raise UnitError("Exponents must be dimensionless")
375
+ raise UnitError('Exponents must be dimensionless')
372
376
  if self.variance is not None:
373
- raise ValueError("Exponents must not have variance")
374
- new_value = other ** self.value
377
+ raise ValueError('Exponents must not have variance')
378
+ new_value = other**self.value
375
379
  else:
376
380
  return NotImplemented
377
381
  return new_value
378
382
 
379
383
  def __neg__(self) -> DescriptorNumber:
380
384
  new_value = -self.full_value
381
- descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
382
- descriptor_number.name=descriptor_number.unique_name
385
+ descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
386
+ descriptor_number.name = descriptor_number.unique_name
383
387
  return descriptor_number
384
-
388
+
385
389
  def __abs__(self) -> DescriptorNumber:
386
390
  new_value = abs(self.full_value)
387
- descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
388
- descriptor_number.name=descriptor_number.unique_name
391
+ descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
392
+ descriptor_number.name = descriptor_number.unique_name
389
393
  return descriptor_number
390
394
 
391
395
  def _base_unit(self) -> str:
392
396
  string = str(self._scalar.unit)
393
397
  for i, letter in enumerate(string):
394
- if letter == "e":
395
- if string[i:i+2] not in ["e+", "e-"]:
398
+ if letter == 'e':
399
+ if string[i : i + 2] not in ['e+', 'e-']:
396
400
  return string[i:]
397
- elif letter not in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "+", "-"]:
401
+ elif letter not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '+', '-']:
398
402
  return string[i:]
399
- return ""
403
+ return ''