-
Notifications
You must be signed in to change notification settings - Fork 2
Add get_all_variables method to EasyList for collection querying #242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rozyczko
wants to merge
3
commits into
develop
Choose a base branch
from
easylist_extended
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,11 @@ | ||
| # SPDX-FileCopyrightText: 2025 EasyScience contributors <https://github.com/easyscience> | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| from ..legacy.collection_base import CollectionBase | ||
| from ..legacy.obj_base import ObjBase | ||
| from .based_base import BasedBase | ||
| from .collection_base import CollectionBase | ||
| from .easy_list import EasyList | ||
| from .model_base import ModelBase | ||
| from .new_base import NewBase | ||
| from .obj_base import ObjBase | ||
|
|
||
| __all__ = [BasedBase, CollectionBase, ObjBase, ModelBase, NewBase, EasyList] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,251 +1,18 @@ | ||
| # SPDX-FileCopyrightText: 2026 EasyScience contributors <https://github.com/easyscience> | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from collections.abc import MutableSequence | ||
| from numbers import Number | ||
| from typing import TYPE_CHECKING | ||
| from typing import Any | ||
| from typing import Callable | ||
| from typing import List | ||
| from typing import Optional | ||
| from typing import Tuple | ||
| from typing import Union | ||
|
|
||
| from easyscience.base_classes.new_base import NewBase | ||
| from easyscience.global_object.undo_redo import NotarizedDict | ||
|
|
||
| from ..variable.descriptor_base import DescriptorBase | ||
| from .based_base import BasedBase | ||
|
|
||
| if TYPE_CHECKING: | ||
| from ..fitting.calculators import InterfaceFactoryTemplate | ||
|
|
||
|
|
||
| class CollectionBase(BasedBase, MutableSequence): | ||
| """This is the base class for which all higher level classes are | ||
| built off of. | ||
|
|
||
| NOTE: This object is serializable only if parameters are supplied as: | ||
| `ObjBase(a=value, b=value)`. For `Parameter` or `Descriptor` objects we can | ||
| cheat with `ObjBase(*[Descriptor(...), Parameter(...), ...])`. | ||
| """ | ||
|
|
||
| def __init__( | ||
| self, | ||
| name: str, | ||
| *args: Union[BasedBase, DescriptorBase, NewBase], | ||
| interface: Optional[InterfaceFactoryTemplate] = None, | ||
| unique_name: Optional[str] = None, | ||
| **kwargs, | ||
| ): | ||
| """Set up the base collection class. | ||
|
|
||
| :param name: Name of this object | ||
| :type name: str | ||
| :param args: selection of | ||
| :param _kwargs: Fields which this class should contain | ||
| :type _kwargs: dict | ||
| """ | ||
| BasedBase.__init__(self, name, unique_name=unique_name) | ||
| kwargs = {key: kwargs[key] for key in kwargs.keys() if kwargs[key] is not None} | ||
| _args = [] | ||
| for item in args: | ||
| if not isinstance(item, list): | ||
| _args.append(item) | ||
| else: | ||
| _args += item | ||
| _kwargs = {} | ||
| for key, item in kwargs.items(): | ||
| if isinstance(item, list) and len(item) > 0: | ||
| _args += item | ||
| else: | ||
| _kwargs[key] = item | ||
| kwargs = _kwargs | ||
| for item in list(kwargs.values()) + _args: | ||
| if not issubclass(type(item), (DescriptorBase, BasedBase, NewBase)): | ||
| raise AttributeError('A collection can only be formed from easyscience objects.') | ||
| args = _args | ||
| _kwargs = {} | ||
| for key, item in kwargs.items(): | ||
| _kwargs[key] = item | ||
| for arg in args: | ||
| kwargs[arg.unique_name] = arg | ||
| _kwargs[arg.unique_name] = arg | ||
|
|
||
| # Set kwargs, also useful for serialization | ||
| self._kwargs = NotarizedDict(**_kwargs) | ||
|
|
||
| for key in kwargs.keys(): | ||
| if key in self.__dict__.keys() or key in self.__slots__: | ||
| raise AttributeError( | ||
| f'Given kwarg: `{key}`, is an internal attribute. Please rename.' | ||
| ) | ||
| if kwargs[key]: # Might be None (empty tuple or list) | ||
| self._global_object.map.add_edge(self, kwargs[key]) | ||
| self._global_object.map.reset_type(kwargs[key], 'created_internal') | ||
| if interface is not None: | ||
| kwargs[key].interface = interface | ||
| # TODO wrap getter and setter in Logger | ||
| if interface is not None: | ||
| self.interface = interface | ||
| self._kwargs._stack_enabled = True | ||
|
|
||
| def insert(self, index: int, value: Union[DescriptorBase, BasedBase, NewBase]) -> None: | ||
| """Insert an object into the collection at an index. | ||
|
|
||
| :param index: Index for EasyScience object to be inserted. | ||
| :type index: int | ||
| :param value: Object to be inserted. | ||
| :type value: Union[BasedBase, DescriptorBase, NewBase] | ||
| :return: None | ||
| :rtype: None | ||
| """ | ||
| t_ = type(value) | ||
| if issubclass(t_, (BasedBase, DescriptorBase, NewBase)): | ||
| update_key = list(self._kwargs.keys()) | ||
| values = list(self._kwargs.values()) | ||
| # Update the internal dict | ||
| new_key = value.unique_name | ||
| update_key.insert(index, new_key) | ||
| values.insert(index, value) | ||
| self._kwargs.reorder(**{k: v for k, v in zip(update_key, values)}) | ||
| # ADD EDGE | ||
| self._global_object.map.add_edge(self, value) | ||
| self._global_object.map.reset_type(value, 'created_internal') | ||
| value.interface = self.interface | ||
| else: | ||
| raise AttributeError('Only EasyScience objects can be put into an EasyScience group') | ||
|
|
||
| def __getitem__(self, idx: Union[int, slice]) -> Union[DescriptorBase, BasedBase, NewBase]: | ||
| """Get an item in the collection based on its index. | ||
|
|
||
| :param idx: index or slice of the collection. | ||
| :type idx: Union[int, slice] | ||
| :return: Object at index `idx` | ||
| :rtype: Union[Parameter, Descriptor, ObjBase, 'CollectionBase'] | ||
| """ | ||
| if isinstance(idx, slice): | ||
| start, stop, step = idx.indices(len(self)) | ||
| return self.__class__( | ||
| getattr(self, 'name'), *[self[i] for i in range(start, stop, step)] | ||
| ) | ||
| if str(idx) in self._kwargs.keys(): | ||
| return self._kwargs[str(idx)] | ||
| if isinstance(idx, str): | ||
| idx = [index for index, item in enumerate(self) if item.name == idx] | ||
| noi = len(idx) | ||
| if noi == 0: | ||
| raise IndexError('Given index does not exist') | ||
| elif noi == 1: | ||
| idx = idx[0] | ||
| else: | ||
| return self.__class__(getattr(self, 'name'), *[self[i] for i in idx]) | ||
| elif not isinstance(idx, int) or isinstance(idx, bool): | ||
| if isinstance(idx, bool): | ||
| raise TypeError('Boolean indexing is not supported at the moment') | ||
| try: | ||
| if idx > len(self): | ||
| raise IndexError(f'Given index {idx} is out of bounds') | ||
| except TypeError: | ||
| raise IndexError('Index must be of type `int`/`slice` or an item name (`str`)') | ||
| keys = list(self._kwargs.keys()) | ||
| return self._kwargs[keys[idx]] | ||
|
|
||
| def __setitem__(self, key: int, value: Union[BasedBase, DescriptorBase, NewBase]) -> None: | ||
| """Set an item via it's index. | ||
|
|
||
| :param key: Index in self. | ||
| :type key: int | ||
| :param value: Value which index key should be set to. | ||
| :type value: Any | ||
| """ | ||
| if isinstance(value, Number): # noqa: S3827 | ||
| item = self.__getitem__(key) | ||
| item.value = value | ||
| elif issubclass(type(value), (BasedBase, DescriptorBase, NewBase)): | ||
| update_key = list(self._kwargs.keys()) | ||
| values = list(self._kwargs.values()) | ||
| old_item = values[key] | ||
| # Update the internal dict | ||
| update_dict = {update_key[key]: value} | ||
| self._kwargs.update(update_dict) | ||
| # ADD EDGE | ||
| self._global_object.map.add_edge(self, value) | ||
| self._global_object.map.reset_type(value, 'created_internal') | ||
| value.interface = self.interface | ||
| # REMOVE EDGE | ||
| self._global_object.map.prune_vertex_from_edge(self, old_item) | ||
| else: | ||
| raise NotImplementedError( | ||
| 'At the moment only numerical values or EasyScience objects can be set.' | ||
| ) | ||
|
|
||
| def __delitem__(self, key: int) -> None: | ||
| """Try to delete an idem by key. | ||
|
|
||
| :param key: | ||
| :type key: | ||
| :return: | ||
| :rtype: | ||
| """ | ||
| keys = list(self._kwargs.keys()) | ||
| item = self._kwargs[keys[key]] | ||
| self._global_object.map.prune_vertex_from_edge(self, item) | ||
| del self._kwargs[keys[key]] | ||
|
|
||
| def __len__(self) -> int: | ||
| """Get the number of items in this collection. | ||
|
|
||
| :return: Number of items in this collection. | ||
| :rtype: int | ||
| """ | ||
| return len(self._kwargs.keys()) | ||
|
|
||
| def _convert_to_dict(self, in_dict, encoder, skip: List[str] = [], **kwargs) -> dict: | ||
| """Convert ones self into a serialized form. | ||
|
|
||
| :return: dictionary of ones self | ||
| :rtype: dict | ||
| """ | ||
| d = {} | ||
| if hasattr(self, '_modify_dict'): | ||
| # any extra keys defined on the inheriting class | ||
| d = self._modify_dict(skip=skip, **kwargs) | ||
| in_dict['data'] = [encoder._convert_to_dict(item, skip=skip, **kwargs) for item in self] | ||
| out_dict = {**in_dict, **d} | ||
| return out_dict | ||
|
|
||
| @property | ||
| def data(self) -> Tuple: | ||
| """The data function returns a tuple of the keyword arguments | ||
| passed to the constructor. This is useful for when you need to | ||
| pass in a dictionary of data to other functions, such as with | ||
| matplotlib's plot function. | ||
|
|
||
| :param self: Access attributes of the class within the method | ||
| :return: The values of the attributes in a tuple :doc-author: | ||
| Trelent | ||
| """ | ||
| return tuple(self._kwargs.values()) | ||
|
|
||
| def __repr__(self) -> str: | ||
| return f'{self.__class__.__name__} `{getattr(self, "name")}` of length {len(self)}' | ||
|
|
||
| def sort( | ||
| self, | ||
| mapping: Callable[[Union[BasedBase, DescriptorBase, NewBase]], Any], | ||
| reverse: bool = False, | ||
| ) -> None: | ||
| """Sort the collection according to the given mapping. | ||
|
|
||
| :param mapping: mapping function to sort the collection. i.e. | ||
| lambda parameter: parameter.value | ||
| :type mapping: Callable | ||
| :param reverse: Reverse the sorting. | ||
| :type reverse: bool | ||
| """ | ||
| i = list(self._kwargs.items()) | ||
| i.sort(key=lambda x: mapping(x[1]), reverse=reverse) | ||
| self._kwargs.reorder(**{k[0]: k[1] for k in i}) | ||
| """ | ||
| .. deprecated:: | ||
| This module has been moved to `easyscience.legacy.collection_base`. | ||
| Please update your imports. | ||
| """ | ||
|
|
||
| import warnings | ||
|
|
||
| from ..legacy.collection_base import CollectionBase # noqa: F401 | ||
|
|
||
| warnings.warn( | ||
| 'easyscience.base_classes.collection_base is deprecated. ' | ||
| 'Please import from easyscience.legacy.collection_base instead.', | ||
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.