-
Notifications
You must be signed in to change notification settings - Fork 192
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
Make Group
sub classable through entry points
#3882
Conversation
@ramirezfranciscof there is only one unit test failing
|
Thanks @sphuber , this makes a lot of sense to me!
Yes. In which sense is this different from creating a subclass of, say, Data?I
Agreed. I'm not sure I'm the best person for reviewing this PR, perhaps some of the ones who worked on the GroupPath / Groups in other contexts may be more suitable. |
In how it should work probably there is no difference, however, where the behavior of the meta class in this PR is too strict, the current behavior for My feeling now is that we should have the following behavior:
|
I'd actually be in favor of keeping the current behavior (error) w.r.t. classes that don't have a corresponding entry point. What is the point of instantiating an object as a specific |
I agree there that that scenario would not make sense, so best to just not allow it. However, this will currently also raise by just importing the class. Since we still have some problems now and again with entry points being properly loaded, it might be a bit aggressive and annoying when you simply import a class and it excepts straight away, just because the corresponding package is not properly installed or its entry points in any case or not (yet) properly recognized. How about the following:
And now that I have you here @greschd :) what do you think the correct behavior is regarding backwards compatibility of code passing an explicit |
Good point, I agree with that behavior. Regarding the
|
Okay, I will try to implement that
No the Just an example to run through it. Currently people can do:
If we add these changes, when running this code, at construction they will get a deprecation warning saying that the |
So instead of ignoring it, you would still use the explicitly passed Yeah, that makes sense to me - probably makes sense for someone else to give his comments on this part, too. |
The only problem that I realize just now, is that will essentially create new groups with the old type strings. For example, currently one of the types is Another design problem I am facing is where to put the warning/exception when trying to store a |
8d2bc61
to
874feac
Compare
Codecov Report
@@ Coverage Diff @@
## develop #3882 +/- ##
===========================================
- Coverage 78.08% 78.05% -0.04%
===========================================
Files 458 460 +2
Lines 33916 33957 +41
===========================================
+ Hits 26485 26505 +20
- Misses 7431 7452 +21
Continue to review full report at Codecov.
|
c3906c6
to
98db2ad
Compare
@ltalirz @greschd @giovannipizzi and @greschd : I have updated the PR with the final behavior as discussed last Friday. In the OP of this PR you will find the descrription of each decision taken. I have added some more tests and documentation. So this should be good for review. |
377994f
to
e1e3463
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @sphuber, very nice work!
Before I forget: there are two typos in the commit message:
If the `GroupMeta` metclass fails cannot retrieve the corresponding
metclass -> metaclass
fails cannot -> cannot
I looked at the discussion, code, tested the Groups behaviour and it all makes total sense to me. Especially the fact that groups with old type strings can still be loaded, but they become a standard Group
, which was the case before. Also, the way deprecated type_string
argument is handled I find very good.
I also see a potential problem here, if (and there is a big if here) there is a user who has been working with groups of custom type_string
, he/she won't be able to add more of such groups. But I think this is acceptable, as the user can make a new group and add nodes from the old one into it.
$ verdi group show test_group
/Users/yakutovicha/Documents/aiida-core/aiida/orm/groups.py:42: UserWarning: could not load entry point `ololo`, falling back onto `Group` base class.
warnings.warn(message) # pylint: disable=no-member
----------------- ----------------
Group label test_group
Group type_string ololo
Group description <no description>
----------------- ----------------
# Nodes:
PK Type Created
---- ------ ----------
1 Dict 2m:15s ago
$ verdi group create test_group_new
Success: Group created with PK = 2 and name 'test_group_new'
$ verdi group copy test_group test_group_new
/Users/yakutovicha/Documents/aiida-core/aiida/orm/groups.py:42: UserWarning: could not load entry point `ololo`, falling back onto `Group` base class.
warnings.warn(message) # pylint: disable=no-member
Success: Nodes copied from group<test_group> to group<test_group_new>
$ verdi group show test_group_new
----------------- ----------------
Group label test_group_new
Group type_string core
Group description <no description>
----------------- ----------------
# Nodes:
PK Type Created
---- ------ -----------
1 Dict 22m:16s ago
I am going to approve.
e1e3463
to
ace335c
Compare
a92be21
to
b2086b8
Compare
We add the `aiida.groups` entry point group where sub classes of the `aiida.orm.groups.Group` class can be registered. A new metaclass is used to automatically set the `type_string` based on the entry point of the `Group` sub class. This will make it possible to reload the correct sub class when reloading from the database. If the `GroupMeta` metaclass cannot retrieve the corresponding entry point of the subclass, a warning is issued that any instances of this class will not be storable and the `__type_string` attribute is set to `None`. This can be checked by the `store` method which will make it fail. We choose to only except in the `store` method such that it is still possible to define and instantiate subclasses of `Group` that have not yet been registered. This is useful for testing and experimenting. Since the group type strings are now based on the entry point names, the existing group type strings in the database have to be migrated: * `user` -> `core` * `data.upf.family` -> `core.upf` * `auto.import` -> `core.import` * `auto.run` -> `core.auto` When loading a `Group` instance from the database, the loader will try to resolve the type string to the corresponding subclass through the entry points. If this fails, a warning is issued and we fallback on the base `Group` class.
b2086b8
to
9c97376
Compare
…up system. From aiida 1.2.0 the class `Group` have been modified to implement new features. This has implications in our plugin because the PseudoFamilies are Groups. In particular there is now an explicit implementation of PsmlFamily and PsfFamily as subclasses of the `Group` class. Moreover PsmlFamily and PsfFamily are registred as entry points making possible to reload the correct sub class when reloading from the database. For more info see: aiidateam/aiida-core#3882
Fixes #3567
We add the
aiida.groups
entry point group where sub classes of theaiida.orm.groups.Group
class can be registered. A new metaclass isused to automatically set the
type_string
based on the entry point ofthe
Group
sub class. This will make it possible to reload the correctsub class when reloading from the database.
If the
GroupMeta
metaclass cannot retrieve the corresponding entrypoint of the subclass, a warning is issued that any instances of this
class will not be storable and the
__type_string
attribute is set toNone
. This can be checked by thestore
method which will make itfail. We choose to only except in the
store
method such that it isstill possible to define and instantiate subclasses of
Group
that havenot yet been registered. This is useful for testing and experimenting.
Since the group type strings are now based on the entry point names, the
existing group type strings in the database have to be migrated:
user
->core
data.upf.family
->core.upf
auto.import
->core.import
auto.run
->core.auto
When loading a
Group
instance from the database, the loader will tryto resolve the type string to the corresponding subclass through the
entry points. If this fails, a warning is issued and we fallback on the
base
Group
class.Remaining questions/features to be discussed:
Group
without an entry point will raise. This should probably be turned into a warning. Decision: allow definition of unregistered subclasses while issuing a warning that storing any instances will not be allowed.type_string
of the baseGroup
should probably becore
instead ofcore.group
, i.e. we should make the entry point name there simplycore
. This will make it the parent hierarchically to all other groups from thecore
namespace. This will be useful when querying with wildcards for target subclasses. Decision: usecore
as type string for the baseGroup
classGroup
subclass and instantiate it without a corresponding entry point? What should the behavior be? It should get the basecore
type string? Should there be a warning that loading the group from the database will load theGroup
base class and not the sub class until an entry point is added. Decision: loading instance with type string that cannot be resolved will fall back on baseGroup
classtype_string
in theGroup
constructor. Currently this is accepted and directly determines thetype_string
set in the database. With this PR this value is determined automatically and currently I raise an exception when it is passed. How to make this backwards compatible? Just issue a warning and discard the value? Maybe better then raising, but still not really backwards compatible. I guess these changes are therefore by definition not fully backwards compatible in the strictest sense of the words. Is this a problem we think? Decision: after discussion we found that keeping this argument as to not break backwards compatibility was impossible if we were also to keep the requirement of not allowing to store group instances of unregistered subclasses. The best option, that is currently implemented, is to issue a warning if an explicittype_string
is passed and that it will be ignored and the basecore
type string will be used.