easyscience 0.6.1__tar.gz → 0.9.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 (71) hide show
  1. {easyscience-0.6.1 → easyscience-0.9.0}/PKG-INFO +5 -4
  2. {easyscience-0.6.1 → easyscience-0.9.0}/README.md +1 -1
  3. {easyscience-0.6.1 → easyscience-0.9.0}/pyproject.toml +4 -3
  4. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Datasets/xarray.py +10 -10
  5. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/Groups.py +12 -13
  6. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/Inferface.py +29 -19
  7. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/ObjectClasses.py +89 -54
  8. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/Variable.py +66 -31
  9. easyscience-0.9.0/src/easyscience/Objects/job/analysis.py +64 -0
  10. easyscience-0.6.1/src/easyscience/Objects/Job/Job.py → easyscience-0.9.0/src/easyscience/Objects/job/job.py +6 -8
  11. easyscience-0.6.1/src/easyscience/Objects/Job/Theory.py → easyscience-0.9.0/src/easyscience/Objects/job/theoreticalmodel.py +3 -3
  12. easyscience-0.9.0/src/easyscience/Objects/new_variable/__init__.py +4 -0
  13. easyscience-0.9.0/src/easyscience/Objects/new_variable/descriptor_base.py +223 -0
  14. easyscience-0.9.0/src/easyscience/Objects/new_variable/descriptor_bool.py +70 -0
  15. easyscience-0.9.0/src/easyscience/Objects/new_variable/descriptor_number.py +399 -0
  16. easyscience-0.9.0/src/easyscience/Objects/new_variable/descriptor_str.py +69 -0
  17. easyscience-0.9.0/src/easyscience/Objects/new_variable/parameter.py +738 -0
  18. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/virtual.py +39 -44
  19. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/classTools.py +6 -6
  20. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/decorators.py +2 -2
  21. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/io/template.py +2 -2
  22. easyscience-0.9.0/src/easyscience/__init__.py +25 -0
  23. easyscience-0.9.0/src/easyscience/__version__.py +1 -0
  24. {easyscience-0.6.1/src/easyscience/Fitting → easyscience-0.9.0/src/easyscience/fitting}/Constraints.py +65 -34
  25. easyscience-0.9.0/src/easyscience/fitting/__init__.py +7 -0
  26. easyscience-0.9.0/src/easyscience/fitting/fitter.py +278 -0
  27. easyscience-0.9.0/src/easyscience/fitting/minimizers/__init__.py +9 -0
  28. easyscience-0.9.0/src/easyscience/fitting/minimizers/factory.py +107 -0
  29. easyscience-0.9.0/src/easyscience/fitting/minimizers/minimizer_base.py +285 -0
  30. easyscience-0.9.0/src/easyscience/fitting/minimizers/minimizer_bumps.py +277 -0
  31. easyscience-0.9.0/src/easyscience/fitting/minimizers/minimizer_dfo.py +285 -0
  32. easyscience-0.9.0/src/easyscience/fitting/minimizers/minimizer_lmfit.py +284 -0
  33. easyscience-0.9.0/src/easyscience/fitting/minimizers/utils.py +62 -0
  34. easyscience-0.9.0/src/easyscience/fitting/multi_fitter.py +135 -0
  35. easyscience-0.9.0/src/easyscience/global_object/__init__.py +4 -0
  36. easyscience-0.6.1/src/easyscience/Objects/Borg.py → easyscience-0.9.0/src/easyscience/global_object/global_object.py +10 -9
  37. easyscience-0.6.1/src/easyscience/Utils/Hugger/Property.py → easyscience-0.9.0/src/easyscience/global_object/hugger/property.py +39 -38
  38. easyscience-0.6.1/src/easyscience/Objects/Graph.py → easyscience-0.9.0/src/easyscience/global_object/map.py +80 -118
  39. easyscience-0.6.1/src/easyscience/Utils/UndoRedo.py → easyscience-0.9.0/src/easyscience/global_object/undo_redo.py +7 -7
  40. easyscience-0.6.1/src/easyscience/Fitting/DFO_LS.py +0 -288
  41. easyscience-0.6.1/src/easyscience/Fitting/Fitting.py +0 -473
  42. easyscience-0.6.1/src/easyscience/Fitting/__init__.py +0 -35
  43. easyscience-0.6.1/src/easyscience/Fitting/bumps.py +0 -314
  44. easyscience-0.6.1/src/easyscience/Fitting/fitting_template.py +0 -272
  45. easyscience-0.6.1/src/easyscience/Fitting/lmfit.py +0 -324
  46. easyscience-0.6.1/src/easyscience/Objects/Job/Analysis.py +0 -21
  47. easyscience-0.6.1/src/easyscience/Utils/io/star.py +0 -520
  48. easyscience-0.6.1/src/easyscience/__init__.py +0 -18
  49. easyscience-0.6.1/src/easyscience/__version__.py +0 -1
  50. {easyscience-0.6.1 → easyscience-0.9.0}/.gitignore +0 -0
  51. {easyscience-0.6.1 → easyscience-0.9.0}/LICENSE +0 -0
  52. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Datasets/__init__.py +0 -0
  53. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/__init__.py +0 -0
  54. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/core.py +0 -0
  55. {easyscience-0.6.1/src/easyscience/Objects/Job → easyscience-0.9.0/src/easyscience/Objects/job}/__init__.py +0 -0
  56. /easyscience-0.6.1/src/easyscience/Objects/Job/Experiment.py → /easyscience-0.9.0/src/easyscience/Objects/job/experiment.py +0 -0
  57. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/REDIRECT.py +0 -0
  58. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/Exceptions.py +0 -0
  59. {easyscience-0.6.1/src/easyscience/Utils/Hugger → easyscience-0.9.0/src/easyscience/Utils}/__init__.py +0 -0
  60. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/classUtils.py +0 -0
  61. {easyscience-0.6.1/src/easyscience/Utils → easyscience-0.9.0/src/easyscience/Utils/io}/__init__.py +0 -0
  62. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/io/dict.py +0 -0
  63. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/io/json.py +0 -0
  64. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/io/xml.py +0 -0
  65. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/string.py +0 -0
  66. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/typing.py +0 -0
  67. {easyscience-0.6.1/src/easyscience/Utils/io → easyscience-0.9.0/src/easyscience/global_object/hugger}/__init__.py +0 -0
  68. /easyscience-0.6.1/src/easyscience/Utils/Hugger/Hugger.py → /easyscience-0.9.0/src/easyscience/global_object/hugger/hugger.py +0 -0
  69. /easyscience-0.6.1/src/easyscience/Utils/Logging.py → /easyscience-0.9.0/src/easyscience/global_object/logger.py +0 -0
  70. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/models/__init__.py +0 -0
  71. {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/models/polynomial.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: easyscience
3
- Version: 0.6.1
3
+ Version: 0.9.0
4
4
  Summary: Generic logic for easyScience libraries
5
5
  Project-URL: homepage, https://docs.easyscience.org
6
6
  Project-URL: documentation, https://docs.easyscience.org
@@ -51,8 +51,9 @@ Requires-Dist: asteval
51
51
  Requires-Dist: bumps
52
52
  Requires-Dist: dfo-ls
53
53
  Requires-Dist: lmfit
54
- Requires-Dist: numpy
55
- Requires-Dist: pint
54
+ Requires-Dist: numpy==1.26
55
+ Requires-Dist: pint==0.23
56
+ Requires-Dist: scipp
56
57
  Requires-Dist: uncertainties
57
58
  Requires-Dist: xarray
58
59
  Provides-Extra: dev
@@ -111,6 +112,6 @@ Documentation can be found at:
111
112
  We absolutely welcome contributions. **EasyScience** is maintained by the ESS and on a volunteer basis and thus we need to foster a community that can support user questions and develop new features to make this software a useful tool for all users while encouraging every member of the community to share their ideas.
112
113
 
113
114
  ## License
114
- While **EasyScience** is under the BSD-3 license, DFO_LS is subject to the GPL license.
115
+ While **EasyScience** is under the BSD-3 license, DFO-LS is subject to the GPL license.
115
116
 
116
117
 
@@ -35,6 +35,6 @@ Documentation can be found at:
35
35
  We absolutely welcome contributions. **EasyScience** is maintained by the ESS and on a volunteer basis and thus we need to foster a community that can support user questions and develop new features to make this software a useful tool for all users while encouraging every member of the community to share their ideas.
36
36
 
37
37
  ## License
38
- While **EasyScience** is under the BSD-3 license, DFO_LS is subject to the GPL license.
38
+ While **EasyScience** is under the BSD-3 license, DFO-LS is subject to the GPL license.
39
39
 
40
40
 
@@ -34,10 +34,11 @@ dependencies = [
34
34
  "bumps",
35
35
  "DFO-LS",
36
36
  "lmfit",
37
- "numpy",
38
- "pint",
37
+ "numpy==1.26", # Should be updated to numpy 2.0
39
38
  "uncertainties",
40
- "xarray"
39
+ "xarray",
40
+ "pint==0.23", # Only to ensure that unit is reported as dimensionless rather than empty string
41
+ "scipp"
41
42
  ]
42
43
 
43
44
  [project.optional-dependencies]
@@ -20,7 +20,7 @@ import numpy as np
20
20
  import xarray as xr
21
21
 
22
22
  from easyscience import ureg
23
- from easyscience.Fitting.fitting_template import FitResults
23
+ from easyscience.fitting import FitResults
24
24
 
25
25
  T_ = TypeVar('T_')
26
26
 
@@ -371,13 +371,13 @@ class EasyScienceDatasetAccessor:
371
371
  **kwargs,
372
372
  ) -> List[FitResults]:
373
373
  """
374
- Perform a fit on one or more DataArrays. This fit utilises a given fitter from `EasyScience.Fitting.Fitter`, though
374
+ Perform a fit on one or more DataArrays. This fit utilises a given fitter from `EasyScience.fitting.Fitter`, though
375
375
  there are a few differences to a standard EasyScience fit. In particular, key-word arguments to control the
376
376
  optimisation algorithm go in the `fit_kwargs` dictionary, fit function key-word arguments go in the `fn_kwargs`
377
377
  and given key-word arguments control the `xarray.apply_ufunc` function.
378
378
 
379
379
  :param fitter: Fitting object which controls the fitting
380
- :type fitter: EasyScience.Fitting.Fitter
380
+ :type fitter: EasyScience.fitting.Fitter
381
381
  :param args: Arguments to go to the fit function
382
382
  :type args: Any
383
383
  :param dask: Dask control string. See `xarray.apply_ufunc` documentation
@@ -612,13 +612,13 @@ class EasyScienceDataarrayAccessor:
612
612
 
613
613
  def fit_prep(self, func_in: Callable, bdims=None, dask_chunks=None) -> Tuple[xr.DataArray, Callable]:
614
614
  """
615
- Generate boradcasted coordinates for fitting and reform the fitting function into one which can handle xarrays
615
+ Generate broadcasted coordinates for fitting and reform the fitting function into one which can handle xarrays.
616
616
 
617
- :param func_in: Function to be wrapped and made xarray fitting compatable.
617
+ :param func_in: Function to be wrapped and made xarray fitting compatible.
618
618
  :type func_in: Callable
619
619
  :param bdims: Optional precomputed broadcasted dimensions.
620
620
  :type bdims: xarray.DataArray
621
- :param dask_chunks: How to split to broadcasted dimensions for dask.
621
+ :param dask_chunks: How to split the broadcasted dimensions for dask.
622
622
  :type dask_chunks: Tuple[int..]
623
623
  :return: Tuple of broadcasted fit arrays and wrapped fit function.
624
624
  :rtype: xarray.DataArray, Callable
@@ -681,13 +681,13 @@ class EasyScienceDataarrayAccessor:
681
681
  **kwargs,
682
682
  ) -> FitResults:
683
683
  """
684
- Perform a fit on the given DataArray. This fit utilises a given fitter from `EasyScience.Fitting.Fitter`, though
684
+ Perform a fit on the given DataArray. This fit utilises a given fitter from `EasyScience.fitting.Fitter`, though
685
685
  there are a few differences to a standard EasyScience fit. In particular, key-word arguments to control the
686
686
  optimisation algorithm go in the `fit_kwargs` dictionary, fit function key-word arguments go in the `fn_kwargs`
687
687
  and given key-word arguments control the `xarray.apply_ufunc` function.
688
688
 
689
689
  :param fitter: Fitting object which controls the fitting
690
- :type fitter: EasyScience.Fitting.Fitter
690
+ :type fitter: EasyScience.fitting.Fitter
691
691
  :param args: Arguments to go to the fit function
692
692
  :type args: Any
693
693
  :param dask: Dask control string. See `xarray.apply_ufunc` documentation
@@ -732,7 +732,7 @@ class EasyScienceDataarrayAccessor:
732
732
 
733
733
  # Set the new callable to the fitter and initialize
734
734
  fitter.initialize(fitter.fit_object, local_fit_func)
735
- # Make EasyScience.Fitting.Fitter compatible `x`
735
+ # Make EasyScience.fitting.Fitter compatible `x`
736
736
  x_for_fit = xr.concat(bdims, dim='fit_dim')
737
737
  x_for_fit = x_for_fit.stack(all_x=[d.name for d in bdims])
738
738
  try:
@@ -803,7 +803,7 @@ def check_sanity_multiple(fit_results: FitResults, originals: List[xr.DataArray]
803
803
  current_results = fit_results.__class__()
804
804
  # Fill out the basic stuff....
805
805
  current_results.engine_result = fit_results.engine_result
806
- current_results.fitting_engine = fit_results.fitting_engine
806
+ current_results.minimizer_engine = fit_results.minimizer_engine
807
807
  current_results.success = fit_results.success
808
808
  current_results.p = fit_results.p
809
809
  current_results.p0 = fit_results.p0
@@ -17,10 +17,9 @@ from typing import Optional
17
17
  from typing import Tuple
18
18
  from typing import Union
19
19
 
20
- from easyscience import borg
20
+ from easyscience.global_object.undo_redo import NotarizedDict
21
21
  from easyscience.Objects.ObjectClasses import BasedBase
22
22
  from easyscience.Objects.ObjectClasses import Descriptor
23
- from easyscience.Utils.UndoRedo import NotarizedDict
24
23
 
25
24
  if TYPE_CHECKING:
26
25
  from easyscience.Utils.typing import B
@@ -75,8 +74,8 @@ class BaseCollection(BasedBase, MutableSequence):
75
74
  for key, item in kwargs.items():
76
75
  _kwargs[key] = item
77
76
  for arg in args:
78
- kwargs[str(borg.map.convert_id_to_key(arg))] = arg
79
- _kwargs[str(borg.map.convert_id_to_key(arg))] = arg
77
+ kwargs[arg.unique_name] = arg
78
+ _kwargs[arg.unique_name] = arg
80
79
 
81
80
  # Set kwargs, also useful for serialization
82
81
  self._kwargs = NotarizedDict(**_kwargs)
@@ -84,8 +83,8 @@ class BaseCollection(BasedBase, MutableSequence):
84
83
  for key in kwargs.keys():
85
84
  if key in self.__dict__.keys() or key in self.__slots__:
86
85
  raise AttributeError(f'Given kwarg: `{key}`, is an internal attribute. Please rename.')
87
- self._borg.map.add_edge(self, kwargs[key])
88
- self._borg.map.reset_type(kwargs[key], 'created_internal')
86
+ self._global_object.map.add_edge(self, kwargs[key])
87
+ self._global_object.map.reset_type(kwargs[key], 'created_internal')
89
88
  if interface is not None:
90
89
  kwargs[key].interface = interface
91
90
  # TODO wrap getter and setter in Logger
@@ -109,13 +108,13 @@ class BaseCollection(BasedBase, MutableSequence):
109
108
  update_key = list(self._kwargs.keys())
110
109
  values = list(self._kwargs.values())
111
110
  # Update the internal dict
112
- new_key = str(borg.map.convert_id_to_key(value))
111
+ new_key = value.unique_name
113
112
  update_key.insert(index, new_key)
114
113
  values.insert(index, value)
115
114
  self._kwargs.reorder(**{k: v for k, v in zip(update_key, values)})
116
115
  # ADD EDGE
117
- self._borg.map.add_edge(self, value)
118
- self._borg.map.reset_type(value, 'created_internal')
116
+ self._global_object.map.add_edge(self, value)
117
+ self._global_object.map.reset_type(value, 'created_internal')
119
118
  value.interface = self.interface
120
119
  else:
121
120
  raise AttributeError('Only EasyScience objects can be put into an EasyScience group')
@@ -174,11 +173,11 @@ class BaseCollection(BasedBase, MutableSequence):
174
173
  update_dict = {update_key[key]: value}
175
174
  self._kwargs.update(update_dict)
176
175
  # ADD EDGE
177
- self._borg.map.add_edge(self, value)
178
- self._borg.map.reset_type(value, 'created_internal')
176
+ self._global_object.map.add_edge(self, value)
177
+ self._global_object.map.reset_type(value, 'created_internal')
179
178
  value.interface = self.interface
180
179
  # REMOVE EDGE
181
- self._borg.map.prune_vertex_from_edge(self, old_item)
180
+ self._global_object.map.prune_vertex_from_edge(self, old_item)
182
181
  else:
183
182
  raise NotImplementedError('At the moment only numerical values or EasyScience objects can be set.')
184
183
 
@@ -193,7 +192,7 @@ class BaseCollection(BasedBase, MutableSequence):
193
192
  """
194
193
  keys = list(self._kwargs.keys())
195
194
  item = self._kwargs[keys[key]]
196
- self._borg.map.prune_vertex_from_edge(self, item)
195
+ self._global_object.map.prune_vertex_from_edge(self, item)
197
196
  del self._kwargs[keys[key]]
198
197
 
199
198
  def __len__(self) -> int:
@@ -4,8 +4,8 @@ from __future__ import annotations
4
4
  # SPDX-License-Identifier: BSD-3-Clause
5
5
  # © 2021-2023 Contributors to the EasyScience project <https://github.com/easyScience/EasyScience
6
6
 
7
- __author__ = "github.com/wardsimon"
8
- __version__ = "0.1.0"
7
+ __author__ = 'github.com/wardsimon'
8
+ __version__ = '0.1.0'
9
9
 
10
10
  from abc import ABCMeta
11
11
  from typing import TYPE_CHECKING
@@ -16,10 +16,10 @@ from typing import Optional
16
16
  from typing import Type
17
17
  from typing import TypeVar
18
18
 
19
- _C = TypeVar("_C", bound=ABCMeta)
20
- _M = TypeVar("_M")
19
+ _C = TypeVar('_C', bound=ABCMeta)
20
+ _M = TypeVar('_M')
21
21
  if TYPE_CHECKING:
22
- from easyscience.Fitting.Fitting import Fitter
22
+ from easyscience.fitting import Fitter
23
23
 
24
24
 
25
25
  class InterfaceFactoryTemplate:
@@ -44,14 +44,14 @@ class InterfaceFactoryTemplate:
44
44
  :return: None
45
45
  :rtype: noneType
46
46
  """
47
- if kwargs.get("interface_name", None) is None:
47
+ if kwargs.get('interface_name', None) is None:
48
48
  if len(self._interfaces) > 0:
49
49
  # Fallback name
50
50
  interface_name = self.return_name(self._interfaces[0])
51
51
  else:
52
52
  raise NotImplementedError
53
53
  else:
54
- interface_name = kwargs.pop("interface_name")
54
+ interface_name = kwargs.pop('interface_name')
55
55
  interfaces = self.available_interfaces
56
56
  if interface_name in interfaces:
57
57
  self._current_interface = self._interfaces[interfaces.index(interface_name)]
@@ -65,7 +65,7 @@ class InterfaceFactoryTemplate:
65
65
  :param new_interface: name of new interface to be created
66
66
  :type new_interface: str
67
67
  :param fitter: Fitting interface which contains the fitting object which may have bindings which will be updated.
68
- :type fitter: EasyScience.Fitting.Fitting.Fitter
68
+ :type fitter: EasyScience.fitting.Fitter
69
69
  :return: None
70
70
  :rtype: noneType
71
71
  """
@@ -74,20 +74,20 @@ class InterfaceFactoryTemplate:
74
74
  self._current_interface = self._interfaces[interfaces.index(new_interface)]
75
75
  self.__interface_obj = self._current_interface()
76
76
  else:
77
- raise AttributeError("The user supplied interface is not valid.")
77
+ raise AttributeError('The user supplied interface is not valid.')
78
78
  if fitter is not None:
79
- if hasattr(fitter, "_fit_object"):
80
- obj = getattr(fitter, "_fit_object")
79
+ if hasattr(fitter, '_fit_object'):
80
+ obj = getattr(fitter, '_fit_object')
81
81
  try:
82
- if hasattr(obj, "update_bindings"):
82
+ if hasattr(obj, 'update_bindings'):
83
83
  obj.update_bindings()
84
84
  except Exception as e:
85
- print(f"Unable to auto generate bindings.\n{e}")
86
- elif hasattr(fitter, "generate_bindings"):
85
+ print(f'Unable to auto generate bindings.\n{e}')
86
+ elif hasattr(fitter, 'generate_bindings'):
87
87
  try:
88
88
  fitter.generate_bindings()
89
89
  except Exception as e:
90
- print(f"Unable to auto generate bindings.\n{e}")
90
+ print(f'Unable to auto generate bindings.\n{e}')
91
91
 
92
92
  @property
93
93
  def available_interfaces(self) -> List[str]:
@@ -152,6 +152,8 @@ class InterfaceFactoryTemplate:
152
152
  :return: binding property
153
153
  :rtype: property
154
154
  """
155
+ import easyscience.Objects.new_variable.parameter
156
+
155
157
  class_links = self.__interface_obj.create(model)
156
158
  props = model._get_linkable_attributes()
157
159
  props_names = [prop.name for prop in props]
@@ -161,8 +163,16 @@ class InterfaceFactoryTemplate:
161
163
  continue
162
164
  idx = props_names.index(item_key)
163
165
  prop = props[idx]
166
+
167
+ ## TODO clean when full move to new_variable
168
+ if isinstance(prop, easyscience.Objects.new_variable.parameter.Parameter):
169
+ # Should be fetched this way to ensure we don't get value from callback
170
+ prop_value = prop.value_no_call_back
171
+ else:
172
+ prop_value = prop.raw_value
173
+
164
174
  prop._callback = item.make_prop(item_key)
165
- prop._callback.fset(prop.raw_value)
175
+ prop._callback.fset(prop_value)
166
176
 
167
177
  def __call__(self, *args, **kwargs) -> _M:
168
178
  return self.__interface_obj
@@ -189,8 +199,8 @@ class InterfaceFactoryTemplate:
189
199
  Return an interfaces name
190
200
  """
191
201
  interface_name = this_interface.__name__
192
- if hasattr(this_interface, "name"):
193
- interface_name = getattr(this_interface, "name")
202
+ if hasattr(this_interface, 'name'):
203
+ interface_name = getattr(this_interface, 'name')
194
204
  return interface_name
195
205
 
196
206
 
@@ -225,4 +235,4 @@ class ItemContainer(NamedTuple):
225
235
  return set_value
226
236
 
227
237
 
228
- iF = TypeVar("iF", bound=InterfaceFactoryTemplate)
238
+ iF = TypeVar('iF', bound=InterfaceFactoryTemplate)
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- __author__ = "github.com/wardsimon"
4
- __version__ = "0.1.0"
3
+ __author__ = 'github.com/wardsimon'
4
+ __version__ = '0.1.0'
5
5
 
6
6
  # SPDX-FileCopyrightText: 2023 EasyScience contributors <core@easyscience.software>
7
7
  # SPDX-License-Identifier: BSD-3-Clause
@@ -16,11 +16,14 @@ from typing import List
16
16
  from typing import Optional
17
17
  from typing import Set
18
18
  from typing import TypeVar
19
+ from typing import Union
19
20
 
20
- from easyscience import borg
21
+ from easyscience import global_object
21
22
  from easyscience.Utils.classTools import addLoggedProp
22
23
 
23
24
  from .core import ComponentSerializer
25
+ from .new_variable import Parameter as NewParameter
26
+ from .new_variable.descriptor_base import DescriptorBase
24
27
  from .Variable import Descriptor
25
28
  from .Variable import Parameter
26
29
 
@@ -31,20 +34,23 @@ if TYPE_CHECKING:
31
34
 
32
35
 
33
36
  class BasedBase(ComponentSerializer):
34
- __slots__ = ["_name", "_borg", "user_data", "_kwargs"]
37
+ __slots__ = ['_name', '_global_object', 'user_data', '_kwargs']
35
38
 
36
39
  _REDIRECT = {}
37
40
 
38
- def __init__(self, name: str, interface: Optional[iF] = None):
39
- self._borg = borg
40
- self._borg.map.add_vertex(self, obj_type="created")
41
+ def __init__(self, name: str, interface: Optional[iF] = None, unique_name: Optional[str] = None):
42
+ self._global_object = global_object
43
+ if unique_name is None:
44
+ unique_name = self._unique_name_generator()
45
+ self._unique_name = unique_name
46
+ self._name = name
47
+ self._global_object.map.add_vertex(self, obj_type="created")
41
48
  self.interface = interface
42
49
  self.user_data: dict = {}
43
- self._name: str = name
44
50
 
45
51
  @property
46
52
  def _arg_spec(self) -> Set[str]:
47
- base_cls = getattr(self, "__old_class__", self.__class__)
53
+ base_cls = getattr(self, '__old_class__', self.__class__)
48
54
  spec = getfullargspec(base_cls.__init__)
49
55
  names = set(spec.args[1:])
50
56
  return names
@@ -58,9 +64,24 @@ class BasedBase(ComponentSerializer):
58
64
  :rtype: tuple
59
65
  """
60
66
  state = self.encode()
61
- cls = getattr(self, "__old_class__", self.__class__)
67
+ cls = getattr(self, '__old_class__', self.__class__)
62
68
  return cls.from_dict, (state,)
63
69
 
70
+ @property
71
+ def unique_name(self) -> str:
72
+ """ Get the unique name of the object."""
73
+ return self._unique_name
74
+
75
+ @unique_name.setter
76
+ def unique_name(self, new_unique_name: str):
77
+ """ Set a new unique name for the object. The old name is still kept in the map.
78
+
79
+ :param new_unique_name: New unique name for the object"""
80
+ if not isinstance(new_unique_name, str):
81
+ raise TypeError("Unique name has to be a string.")
82
+ self._unique_name = new_unique_name
83
+ self._global_object.map.add_vertex(self)
84
+
64
85
  @property
65
86
  def name(self) -> str:
66
87
  """
@@ -109,16 +130,14 @@ class BasedBase(ComponentSerializer):
109
130
  :raises: AttributeError
110
131
  """
111
132
  if self.interface is None:
112
- raise AttributeError(
113
- "Interface error for generating bindings. `interface` has to be set."
114
- )
133
+ raise AttributeError('Interface error for generating bindings. `interface` has to be set.')
115
134
  interfaceable_children = [
116
135
  key
117
- for key in self._borg.map.get_edges(self)
118
- if issubclass(type(self._borg.map.get_item_by_key(key)), BasedBase)
136
+ for key in self._global_object.map.get_edges(self)
137
+ if issubclass(type(self._global_object.map.get_item_by_key(key)), BasedBase)
119
138
  ]
120
139
  for child_key in interfaceable_children:
121
- child = self._borg.map.get_item_by_key(child_key)
140
+ child = self._global_object.map.get_item_by_key(child_key)
122
141
  child.interface = self.interface
123
142
  self.interface.generate_bindings(self)
124
143
 
@@ -127,9 +146,7 @@ class BasedBase(ComponentSerializer):
127
146
  Switch or create a new interface.
128
147
  """
129
148
  if self.interface is None:
130
- raise AttributeError(
131
- "Interface error for generating bindings. `interface` has to be set."
132
- )
149
+ raise AttributeError('Interface error for generating bindings. `interface` has to be set.')
133
150
  self.interface.switch(new_interface_name)
134
151
  self.generate_bindings()
135
152
 
@@ -143,7 +160,8 @@ class BasedBase(ComponentSerializer):
143
160
  constraints.append(con[key])
144
161
  return constraints
145
162
 
146
- def get_parameters(self) -> List[Parameter]:
163
+ ## TODO clean when full move to new_variable
164
+ def get_parameters(self) -> Union[List[Parameter], List[NewParameter]]:
147
165
  """
148
166
  Get all parameter objects as a list.
149
167
 
@@ -151,12 +169,13 @@ class BasedBase(ComponentSerializer):
151
169
  """
152
170
  par_list = []
153
171
  for key, item in self._kwargs.items():
154
- if hasattr(item, "get_parameters"):
172
+ if hasattr(item, 'get_parameters'):
155
173
  par_list = [*par_list, *item.get_parameters()]
156
- elif isinstance(item, Parameter):
174
+ elif isinstance(item, Parameter) or isinstance(item, NewParameter):
157
175
  par_list.append(item)
158
176
  return par_list
159
177
 
178
+ ## TODO clean when full move to new_variable
160
179
  def _get_linkable_attributes(self) -> List[V]:
161
180
  """
162
181
  Get all objects which can be linked against as a list.
@@ -165,13 +184,14 @@ class BasedBase(ComponentSerializer):
165
184
  """
166
185
  item_list = []
167
186
  for key, item in self._kwargs.items():
168
- if hasattr(item, "_get_linkable_attributes"):
187
+ if hasattr(item, '_get_linkable_attributes'):
169
188
  item_list = [*item_list, *item._get_linkable_attributes()]
170
- elif issubclass(type(item), Descriptor):
189
+ elif issubclass(type(item), Descriptor) or issubclass(type(item), DescriptorBase):
171
190
  item_list.append(item)
172
191
  return item_list
173
192
 
174
- def get_fit_parameters(self) -> List[Parameter]:
193
+ ## TODO clean when full move to new_variable
194
+ def get_fit_parameters(self) -> Union[List[Parameter], List[NewParameter]]:
175
195
  """
176
196
  Get all objects which can be fitted (and are not fixed) as a list.
177
197
 
@@ -179,25 +199,39 @@ class BasedBase(ComponentSerializer):
179
199
  """
180
200
  fit_list = []
181
201
  for key, item in self._kwargs.items():
182
- if hasattr(item, "get_fit_parameters"):
202
+ if hasattr(item, 'get_fit_parameters'):
183
203
  fit_list = [*fit_list, *item.get_fit_parameters()]
184
- elif isinstance(item, Parameter) and item.enabled and not item.fixed:
185
- fit_list.append(item)
204
+ elif isinstance(item, Parameter) or isinstance(item, NewParameter):
205
+ if item.enabled and not item.fixed:
206
+ fit_list.append(item)
186
207
  return fit_list
187
208
 
209
+ def _unique_name_generator(self) -> str:
210
+ """
211
+ Generate a generic unique name for the object using the class name and a global iterator.
212
+ """
213
+ class_name = self.__class__.__name__
214
+ iterator_string = str(self._global_object.map._get_name_iterator(class_name))
215
+ name = class_name + "_" + iterator_string
216
+ while name in self._global_object.map.vertices():
217
+ iterator_string = str(self._global_object.map._get_name_iterator(class_name))
218
+ name = class_name + "_" + iterator_string
219
+ return name
220
+
188
221
  def __dir__(self) -> Iterable[str]:
189
222
  """
190
223
  This creates auto-completion and helps out in iPython notebooks.
191
224
 
192
225
  :return: list of function and parameter names for auto-completion
193
226
  """
194
- new_class_objs = list(k for k in dir(self.__class__) if not k.startswith("_"))
227
+ new_class_objs = list(k for k in dir(self.__class__) if not k.startswith('_'))
195
228
  return sorted(new_class_objs)
229
+
196
230
 
197
231
 
198
232
  if TYPE_CHECKING:
199
- B = TypeVar("B", bound=BasedBase)
200
- BV = TypeVar("BV", bound=ComponentSerializer)
233
+ B = TypeVar('B', bound=BasedBase)
234
+ BV = TypeVar('BV', bound=ComponentSerializer)
201
235
 
202
236
 
203
237
  class BaseObj(BasedBase):
@@ -208,9 +242,11 @@ class BaseObj(BasedBase):
208
242
  cheat with `BaseObj(*[Descriptor(...), Parameter(...), ...])`.
209
243
  """
210
244
 
245
+ ## TODO clean when full move to new_variable
211
246
  def __init__(
212
247
  self,
213
248
  name: str,
249
+ unique_name: Optional[str] = None,
214
250
  *args: Optional[BV],
215
251
  **kwargs: Optional[BV],
216
252
  ):
@@ -221,22 +257,22 @@ class BaseObj(BasedBase):
221
257
  :param args: Any arguments?
222
258
  :param kwargs: Fields which this class should contain
223
259
  """
224
- super(BaseObj, self).__init__(name)
260
+ super(BaseObj, self).__init__(name=name, unique_name=unique_name)
225
261
  # If Parameter or Descriptor is given as arguments...
226
262
  for arg in args:
227
- if issubclass(type(arg), (BaseObj, Descriptor)):
228
- kwargs[getattr(arg, "name")] = arg
263
+ if issubclass(type(arg), (BaseObj, Descriptor, DescriptorBase)):
264
+ kwargs[getattr(arg, 'name')] = arg
229
265
  # Set kwargs, also useful for serialization
230
266
  known_keys = self.__dict__.keys()
231
267
  self._kwargs = kwargs
232
268
  for key in kwargs.keys():
233
269
  if key in known_keys:
234
- raise AttributeError
235
- if issubclass(
236
- type(kwargs[key]), (BasedBase, Descriptor)
237
- ) or "BaseCollection" in [c.__name__ for c in type(kwargs[key]).__bases__]:
238
- self._borg.map.add_edge(self, kwargs[key])
239
- self._borg.map.reset_type(kwargs[key], "created_internal")
270
+ raise AttributeError("Kwargs cannot overwrite class attributes in BaseObj.")
271
+ if issubclass(type(kwargs[key]), (BasedBase, Descriptor, DescriptorBase)) or 'BaseCollection' in [
272
+ c.__name__ for c in type(kwargs[key]).__bases__
273
+ ]:
274
+ self._global_object.map.add_edge(self, kwargs[key])
275
+ self._global_object.map.reset_type(kwargs[key], 'created_internal')
240
276
  addLoggedProp(
241
277
  self,
242
278
  key,
@@ -269,8 +305,8 @@ class BaseObj(BasedBase):
269
305
  :return: None
270
306
  """
271
307
  self._kwargs[key] = component
272
- self._borg.map.add_edge(self, component)
273
- self._borg.map.reset_type(component, "created_internal")
308
+ self._global_object.map.add_edge(self, component)
309
+ self._global_object.map.reset_type(component, 'created_internal')
274
310
  addLoggedProp(
275
311
  self,
276
312
  key,
@@ -281,31 +317,32 @@ class BaseObj(BasedBase):
281
317
  test_class=BaseObj,
282
318
  )
283
319
 
320
+ ## TODO clean when full move to new_variable
284
321
  def __setattr__(self, key: str, value: BV) -> None:
285
322
  # Assume that the annotation is a ClassVar
286
323
  old_obj = None
287
324
  if (
288
- hasattr(self.__class__, "__annotations__")
325
+ hasattr(self.__class__, '__annotations__')
289
326
  and key in self.__class__.__annotations__
290
- and hasattr(self.__class__.__annotations__[key], "__args__")
327
+ and hasattr(self.__class__.__annotations__[key], '__args__')
291
328
  and issubclass(
292
- getattr(value, "__old_class__", value.__class__),
329
+ getattr(value, '__old_class__', value.__class__),
293
330
  self.__class__.__annotations__[key].__args__,
294
331
  )
295
332
  ):
296
- if issubclass(type(getattr(self, key, None)), (BasedBase, Descriptor)):
333
+ if issubclass(type(getattr(self, key, None)), (BasedBase, Descriptor, DescriptorBase)):
297
334
  old_obj = self.__getattribute__(key)
298
- self._borg.map.prune_vertex_from_edge(self, old_obj)
335
+ self._global_object.map.prune_vertex_from_edge(self, old_obj)
299
336
  self._add_component(key, value)
300
337
  else:
301
- if hasattr(self, key) and issubclass(type(value), (BasedBase, Descriptor)):
338
+ if hasattr(self, key) and issubclass(type(value), (BasedBase, Descriptor, DescriptorBase)):
302
339
  old_obj = self.__getattribute__(key)
303
- self._borg.map.prune_vertex_from_edge(self, old_obj)
304
- self._borg.map.add_edge(self, value)
340
+ self._global_object.map.prune_vertex_from_edge(self, old_obj)
341
+ self._global_object.map.add_edge(self, value)
305
342
  super(BaseObj, self).__setattr__(key, value)
306
343
  # Update the interface bindings if something changed (BasedBase and Descriptor)
307
344
  if old_obj is not None:
308
- old_interface = getattr(self, "interface", None)
345
+ old_interface = getattr(self, 'interface', None)
309
346
  if old_interface is not None:
310
347
  self.generate_bindings()
311
348
 
@@ -322,9 +359,7 @@ class BaseObj(BasedBase):
322
359
  @staticmethod
323
360
  def __setter(key: str) -> Callable[[BV], None]:
324
361
  def setter(obj: BV, value: float) -> None:
325
- if issubclass(obj._kwargs[key].__class__, Descriptor) and not issubclass(
326
- value.__class__, Descriptor
327
- ):
362
+ if issubclass(obj._kwargs[key].__class__, Descriptor) and not issubclass(value.__class__, Descriptor):
328
363
  obj._kwargs[key].value = value
329
364
  else:
330
365
  obj._kwargs[key] = value