Skip to content

DescriptorBase now is a NewBase class - #306

Open
rozyczko wants to merge 6 commits into
easylist-on-multifitterfrom
modelbase-on-descriptor
Open

DescriptorBase now is a NewBase class#306
rozyczko wants to merge 6 commits into
easylist-on-multifitterfrom
modelbase-on-descriptor

Conversation

@rozyczko

@rozyczko rozyczko commented Sep 4, 2026

Copy link
Copy Markdown
Member

DescriptorBase now inherits from NewBase instead of SerializerComponent, and uses SerializerBase for serialization. The to_dict method is introduced as the standard serialization method, with as_dict provided as an alias for backward compatibility.

The serialization interface for descriptor and parameter classes (DescriptorNumber, DescriptorArray, DescriptorAnyType, Parameter) is unified to use to_dict, replacing previous as_dict implementations.

EasyList used in MultiFitter now only accepts ModelBase members, preventing bare parameters or foreign objects from being silently ignored during fitting.

@rozyczko rozyczko added [scope] maintenance Code/tooling cleanup, no feature or bugfix (major.minor.PATCH) [priority] high Should be prioritized soon [area] base classes Changes to or creation of new base classes labels Sep 4, 2026
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.50000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.81%. Comparing base (2e9d9c2) to head (03f86be).

Files with missing lines Patch % Lines
src/easyscience/job/theoreticalmodel.py 0.00% 2 Missing ⚠️
src/easyscience/io/serializer_component.py 50.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                     Coverage Diff                     @@
##           easylist-on-multifitter     #306      +/-   ##
===========================================================
+ Coverage                    83.66%   83.81%   +0.14%     
===========================================================
  Files                           68       68              
  Lines                         5271     5332      +61     
===========================================================
+ Hits                          4410     4469      +59     
- Misses                         861      863       +2     
Flag Coverage Δ
unittests 83.81% <87.50%> (+0.14%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/easyscience/base_classes/based_base.py 83.48% <100.00%> (ø)
src/easyscience/base_classes/easy_list.py 96.20% <ø> (ø)
src/easyscience/base_classes/new_base.py 100.00% <ø> (ø)
src/easyscience/fitting/multi_fitter.py 98.70% <100.00%> (ø)
src/easyscience/io/serializer_base.py 90.20% <ø> (ø)
src/easyscience/variable/descriptor_any_type.py 96.87% <100.00%> (ø)
src/easyscience/variable/descriptor_array.py 89.56% <100.00%> (ø)
src/easyscience/variable/descriptor_base.py 95.83% <100.00%> (+1.26%) ⬆️
src/easyscience/variable/descriptor_bool.py 96.42% <ø> (-0.13%) ⬇️
src/easyscience/variable/descriptor_number.py 95.40% <100.00%> (ø)
... and 4 more

... and 14 files with indirect coverage changes

@rozyczko rozyczko changed the title DescriptorBase now is a ModelBase class DescriptorBase now is a NewBase class Sep 7, 2026

@damskii9992 damskii9992 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More work to do. You forgot the biggest part of the change, the removal of the name attribute.

Comment on lines +31 to +45
``DescriptorBase`` is a ``NewBase`` object. As such every descriptor
is registered in the global object map under its ``unique_name``,
has an optional ``display_name`` and is serialized with
``to_dict``/``from_dict``. Descriptors and parameters can
therefore be held directly by an ``EasyList``.

Following the ``NewBase`` design, a ``unique_name`` that was
generated automatically is *not* written by ``to_dict``; a
deserialized descriptor is simply assigned a fresh one. Only a
``unique_name`` passed explicitly to the constructor is serialized.

Descriptors no longer provide the ``SerializerComponent`` methods
``encode``, ``decode`` and ``encode_data``. Use a serializer
directly instead, e.g. ``SerializerDict().encode(descriptor)`` and
``SerializerDict.decode(data)``.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't keep these comments. You can just look at the NewBase class to see its design, and I also wouldn't describe the difference from the old implementation.


def __init__(
self,
name: str,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to get rid of the name attribute. This was part of the reason to move to NewBase.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As described below

Comment on lines +98 to +99
# Registers the descriptor with the global object map and takes
# care of `unique_name` and `display_name`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also get rid of parent? I think that is only used in the global_object map . . .

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a larger scope but fitting here so will add this

Comment on lines 153 to 154
@property
def display_name(self) -> str:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed when we remove name.

Comment thread src/easyscience/fitting/multi_fitter.py Outdated
Comment on lines +50 to +53
# Only ModelBase members are accepted: EasyList harvests parameters
# from ModelBase items alone, so any other NewBase (a bare Parameter,
# say) would be accepted and then silently sit out the fit.
self._fit_objects = EasyList(*fit_objects, protected_types=ModelBase)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I guess we would need to edit the EasyList to also return bare Parameters, otherwise we can't get rid of ObjBase to use the Fitter in standalone fitting.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe have Fitter.__init__ accept a plain list (or tuple) of parameters and wrap it in an EasyList itself? so users don't even need to know the container exists.

Comment thread docs/docs/api-reference/index.md Outdated
Comment on lines +12 to +13
`ModelBase`, `EasyList`; the legacy `ObjBase` and `CollectionBase` are
deprecated).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove line about legacy, they will be removed in 3.0, when this is released, so they won't even exist anymore.

Comment on lines +231 to +234
def test_is_a_new_base(self, descriptor: DescriptorBase):
# When Then Expect
assert isinstance(descriptor, NewBase)
assert not isinstance(descriptor, SerializerComponent)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

. . . Huh? Why? XD

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

legacy check, but can remove.

Comment on lines +241 to +259
def test_to_dict_drops_generated_unique_name(self, clear):
"""Descriptors follow the ``NewBase`` design: an auto-generated
unique_name is not serialized, so a decoded descriptor is given
a fresh one instead of colliding with the original."""
# When
descriptor = DescriptorNumber(name='name', value=1.0)

# Then Expect
assert descriptor._default_unique_name
assert 'unique_name' not in descriptor.to_dict()

def test_to_dict_keeps_explicit_unique_name(self, clear):
"""An explicitly supplied unique_name is still serialized."""
# When
descriptor = DescriptorNumber(name='name', value=1.0, unique_name='explicit_name')

# Then Expect
assert not descriptor._default_unique_name
assert descriptor.to_dict()['unique_name'] == 'explicit_name'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is tested in NewBase, no need to test it again.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Comment on lines +261 to +269
def test_can_be_held_by_an_easy_list(self, clear):
"""Descriptors are NewBase objects, so EasyList accepts them."""
# When
descriptor = DescriptorNumber(name='name', value=1.0)
easy_list = EasyList(descriptor)

# Then Expect
assert list(easy_list) == [descriptor]
assert easy_list[descriptor.unique_name] is descriptor

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant test, I'd say. At least it should be covered by our integration tests, not a unit test.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

@rozyczko

Copy link
Copy Markdown
Member Author

More work to do. You forgot the biggest part of the change, the removal of the name attribute.

I prefer to do it in a separate PR. The changes required are quite substantial.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[area] base classes Changes to or creation of new base classes [priority] high Should be prioritized soon [scope] maintenance Code/tooling cleanup, no feature or bugfix (major.minor.PATCH)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants