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.
- {easyscience-0.6.1 → easyscience-0.9.0}/PKG-INFO +5 -4
- {easyscience-0.6.1 → easyscience-0.9.0}/README.md +1 -1
- {easyscience-0.6.1 → easyscience-0.9.0}/pyproject.toml +4 -3
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Datasets/xarray.py +10 -10
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/Groups.py +12 -13
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/Inferface.py +29 -19
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/ObjectClasses.py +89 -54
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/Variable.py +66 -31
- easyscience-0.9.0/src/easyscience/Objects/job/analysis.py +64 -0
- easyscience-0.6.1/src/easyscience/Objects/Job/Job.py → easyscience-0.9.0/src/easyscience/Objects/job/job.py +6 -8
- easyscience-0.6.1/src/easyscience/Objects/Job/Theory.py → easyscience-0.9.0/src/easyscience/Objects/job/theoreticalmodel.py +3 -3
- easyscience-0.9.0/src/easyscience/Objects/new_variable/__init__.py +4 -0
- easyscience-0.9.0/src/easyscience/Objects/new_variable/descriptor_base.py +223 -0
- easyscience-0.9.0/src/easyscience/Objects/new_variable/descriptor_bool.py +70 -0
- easyscience-0.9.0/src/easyscience/Objects/new_variable/descriptor_number.py +399 -0
- easyscience-0.9.0/src/easyscience/Objects/new_variable/descriptor_str.py +69 -0
- easyscience-0.9.0/src/easyscience/Objects/new_variable/parameter.py +738 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/virtual.py +39 -44
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/classTools.py +6 -6
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/decorators.py +2 -2
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/io/template.py +2 -2
- easyscience-0.9.0/src/easyscience/__init__.py +25 -0
- easyscience-0.9.0/src/easyscience/__version__.py +1 -0
- {easyscience-0.6.1/src/easyscience/Fitting → easyscience-0.9.0/src/easyscience/fitting}/Constraints.py +65 -34
- easyscience-0.9.0/src/easyscience/fitting/__init__.py +7 -0
- easyscience-0.9.0/src/easyscience/fitting/fitter.py +278 -0
- easyscience-0.9.0/src/easyscience/fitting/minimizers/__init__.py +9 -0
- easyscience-0.9.0/src/easyscience/fitting/minimizers/factory.py +107 -0
- easyscience-0.9.0/src/easyscience/fitting/minimizers/minimizer_base.py +285 -0
- easyscience-0.9.0/src/easyscience/fitting/minimizers/minimizer_bumps.py +277 -0
- easyscience-0.9.0/src/easyscience/fitting/minimizers/minimizer_dfo.py +285 -0
- easyscience-0.9.0/src/easyscience/fitting/minimizers/minimizer_lmfit.py +284 -0
- easyscience-0.9.0/src/easyscience/fitting/minimizers/utils.py +62 -0
- easyscience-0.9.0/src/easyscience/fitting/multi_fitter.py +135 -0
- easyscience-0.9.0/src/easyscience/global_object/__init__.py +4 -0
- easyscience-0.6.1/src/easyscience/Objects/Borg.py → easyscience-0.9.0/src/easyscience/global_object/global_object.py +10 -9
- easyscience-0.6.1/src/easyscience/Utils/Hugger/Property.py → easyscience-0.9.0/src/easyscience/global_object/hugger/property.py +39 -38
- easyscience-0.6.1/src/easyscience/Objects/Graph.py → easyscience-0.9.0/src/easyscience/global_object/map.py +80 -118
- easyscience-0.6.1/src/easyscience/Utils/UndoRedo.py → easyscience-0.9.0/src/easyscience/global_object/undo_redo.py +7 -7
- easyscience-0.6.1/src/easyscience/Fitting/DFO_LS.py +0 -288
- easyscience-0.6.1/src/easyscience/Fitting/Fitting.py +0 -473
- easyscience-0.6.1/src/easyscience/Fitting/__init__.py +0 -35
- easyscience-0.6.1/src/easyscience/Fitting/bumps.py +0 -314
- easyscience-0.6.1/src/easyscience/Fitting/fitting_template.py +0 -272
- easyscience-0.6.1/src/easyscience/Fitting/lmfit.py +0 -324
- easyscience-0.6.1/src/easyscience/Objects/Job/Analysis.py +0 -21
- easyscience-0.6.1/src/easyscience/Utils/io/star.py +0 -520
- easyscience-0.6.1/src/easyscience/__init__.py +0 -18
- easyscience-0.6.1/src/easyscience/__version__.py +0 -1
- {easyscience-0.6.1 → easyscience-0.9.0}/.gitignore +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/LICENSE +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Datasets/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Objects/core.py +0 -0
- {easyscience-0.6.1/src/easyscience/Objects/Job → easyscience-0.9.0/src/easyscience/Objects/job}/__init__.py +0 -0
- /easyscience-0.6.1/src/easyscience/Objects/Job/Experiment.py → /easyscience-0.9.0/src/easyscience/Objects/job/experiment.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/REDIRECT.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/Exceptions.py +0 -0
- {easyscience-0.6.1/src/easyscience/Utils/Hugger → easyscience-0.9.0/src/easyscience/Utils}/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/classUtils.py +0 -0
- {easyscience-0.6.1/src/easyscience/Utils → easyscience-0.9.0/src/easyscience/Utils/io}/__init__.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/io/dict.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/io/json.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/io/xml.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/string.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/Utils/typing.py +0 -0
- {easyscience-0.6.1/src/easyscience/Utils/io → easyscience-0.9.0/src/easyscience/global_object/hugger}/__init__.py +0 -0
- /easyscience-0.6.1/src/easyscience/Utils/Hugger/Hugger.py → /easyscience-0.9.0/src/easyscience/global_object/hugger/hugger.py +0 -0
- /easyscience-0.6.1/src/easyscience/Utils/Logging.py → /easyscience-0.9.0/src/easyscience/global_object/logger.py +0 -0
- {easyscience-0.6.1 → easyscience-0.9.0}/src/easyscience/models/__init__.py +0 -0
- {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.
|
|
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,
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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[
|
|
79
|
-
_kwargs[
|
|
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.
|
|
88
|
-
self.
|
|
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 =
|
|
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.
|
|
118
|
-
self.
|
|
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.
|
|
178
|
-
self.
|
|
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.
|
|
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.
|
|
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__ =
|
|
8
|
-
__version__ =
|
|
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(
|
|
20
|
-
_M = TypeVar(
|
|
19
|
+
_C = TypeVar('_C', bound=ABCMeta)
|
|
20
|
+
_M = TypeVar('_M')
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
|
-
from easyscience.
|
|
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(
|
|
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(
|
|
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.
|
|
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(
|
|
77
|
+
raise AttributeError('The user supplied interface is not valid.')
|
|
78
78
|
if fitter is not None:
|
|
79
|
-
if hasattr(fitter,
|
|
80
|
-
obj = getattr(fitter,
|
|
79
|
+
if hasattr(fitter, '_fit_object'):
|
|
80
|
+
obj = getattr(fitter, '_fit_object')
|
|
81
81
|
try:
|
|
82
|
-
if hasattr(obj,
|
|
82
|
+
if hasattr(obj, 'update_bindings'):
|
|
83
83
|
obj.update_bindings()
|
|
84
84
|
except Exception as e:
|
|
85
|
-
print(f
|
|
86
|
-
elif hasattr(fitter,
|
|
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
|
|
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(
|
|
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,
|
|
193
|
-
interface_name = getattr(this_interface,
|
|
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(
|
|
238
|
+
iF = TypeVar('iF', bound=InterfaceFactoryTemplate)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
__author__ =
|
|
4
|
-
__version__ =
|
|
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
|
|
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__ = [
|
|
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.
|
|
40
|
-
|
|
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,
|
|
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,
|
|
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.
|
|
118
|
-
if issubclass(type(self.
|
|
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.
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
202
|
+
if hasattr(item, 'get_fit_parameters'):
|
|
183
203
|
fit_list = [*fit_list, *item.get_fit_parameters()]
|
|
184
|
-
elif isinstance(item, Parameter)
|
|
185
|
-
|
|
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(
|
|
200
|
-
BV = TypeVar(
|
|
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,
|
|
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])
|
|
237
|
-
|
|
238
|
-
self.
|
|
239
|
-
self.
|
|
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.
|
|
273
|
-
self.
|
|
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__,
|
|
325
|
+
hasattr(self.__class__, '__annotations__')
|
|
289
326
|
and key in self.__class__.__annotations__
|
|
290
|
-
and hasattr(self.__class__.__annotations__[key],
|
|
327
|
+
and hasattr(self.__class__.__annotations__[key], '__args__')
|
|
291
328
|
and issubclass(
|
|
292
|
-
getattr(value,
|
|
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.
|
|
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.
|
|
304
|
-
self.
|
|
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,
|
|
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
|