-
Notifications
You must be signed in to change notification settings - Fork 7
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
Node post methods #25
Conversation
@ltalirz, @chrisjsewell any idea about |
Failure related to aiidateam/aiida-core#4989 |
Hi @NinadBhat , sorry for the late reply - do I assume correctly that this is fixed by the changes in the PR (i.e. preventing psycopg2-binary from upgrading to 2.9)? |
@ltalirz I have not sure where the psycopg2-binary version is set. |
It won’t magically fix it here, or for any plugin at the moment I’m afraid, since it is only on the develop branch. You will need to specifically pin it in the setup.json here for now (that’s what I’ve done for aiida-lamps) |
I guess the tests are passing locally for you but not on CI since there it will still download the previous AiiDa release (which does not prevent psycopg2-binary 2.9 from being installed). |
Codecov Report
@@ Coverage Diff @@
## master #25 +/- ##
==========================================
+ Coverage 92.24% 93.06% +0.81%
==========================================
Files 25 26 +1
Lines 761 879 +118
==========================================
+ Hits 702 818 +116
- Misses 59 61 +2
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
@chrisjsewell, @ltalirz |
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 @NinadBhat , looking good!
just a couple of things to fix
Since this is all new functionality, I would suggest you also add add some point a bit of documentation to the docs/ folder.
It doesn't have to be in this PR, but when you get to the processes I would suggest to simply document the steps of submitting a new workflow (including creation of inputs, checking status, etc.) from start to finish.
aiida_restapi/models.py
Outdated
) -> orm.Node: | ||
"Create and Store new Node" | ||
orm_object = load_entry_point_from_full_type(node_type)(**node_dict) | ||
orm_object.set_attribute_many(attributes) |
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.
extras missing?
aiida_restapi/models.py
Outdated
orm_object = load_entry_point_from_full_type(node_type)( | ||
file=io.BytesIO(file), **node_dict | ||
) | ||
orm_object.set_attribute_many(attributes) |
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.
same here
aiida_restapi/routers/nodes.py
Outdated
from aiida.cmdline.utils.decorators import with_dbenv | ||
from fastapi import APIRouter, Depends, File | ||
|
||
from aiida_restapi.models import Node, User |
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.
maybe rather
from aiida_restapi import models
so that you can later user models.Node
in the code (this makes it clear that you are referring to models there, not e.g. ORM objects)
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.
do you agree?
aiida_restapi/routers/nodes.py
Outdated
|
||
node_dict = node.dict(exclude_unset=True) | ||
node_type = node_dict.pop("node_type", None) | ||
attributes = node_dict.pop("attributes", None) |
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.
extras
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.
won't the extra be set when passing parameter using **node_dict?
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.
I see, maybe - can you please add a test?
If this works fine, then perhaps it would also make sense not to treat the attributes
in a special way here since you aren't doing anything specific with them.
I.e. perhaps just leave them in the node_dict
and let the create_new_node
method deal with popping out the attributes instead?
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.
@ltalirz You were correct about extras, I have added extras and test for extras.
aiida_restapi/routers/nodes.py
Outdated
for ep_node in entry_point_nodes: | ||
if ep_node.name == node_type: | ||
orm_object = ep_node.load().create_new_node( | ||
node_type, attributes, node_dict | ||
) |
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.
this is not optimal
- no exception here if entry point string not found
- what if the entry point string was found twice? (ok, should not happen in theory...)
- no need to continue after entry point is found
I would suggest to first check whether instead of a list you can get a dictionary "entry point string" => "entry point object" from the API.
If not, you will need to put some guards in here, e.g. break after entry point is found; after the look check whether it was found and raise if it wasn't
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.
Any updates on this?
aiida_restapi/routers/nodes.py
Outdated
"""Test function for upload file will be merged with create_node later.""" | ||
node_dict = params.dict(exclude_unset=True, exclude_none=True) | ||
node_type = node_dict.pop("node_type", None) | ||
attributes = node_dict.pop("attributes", {}) |
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.
extras
setup.json
Outdated
"aiida.rest.post": [ | ||
"data.str.Str.| = aiida_restapi.models:Node", | ||
"data.float.Float.| = aiida_restapi.models:Node", | ||
"data.int.Int.| = aiida_restapi.models:Node", | ||
"data.bool.Bool.| = aiida_restapi.models:Node", | ||
"data.structure.StructureData.| = aiida_restapi.models:Node", | ||
"data.orbital.OrbitalData.| = aiida_restapi.models:Node", | ||
"data.list.List.| = aiida_restapi.models:Node", | ||
"data.dict.Dict.| = aiida_restapi.models:Node", | ||
"data.singlefile.SingleFileData.| = aiida_restapi.models:Node" |
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.
Specifying entry points in the setup.json/setup.py is the right approach for AiiDA plugins but here it is not ideal since we are adding entry points here that depend on a different package (aiida-core).
I.e. this list would need to change whenever AiiDA adds a new data node type.
It seems to be possible to add entry points dynamically, see
https://stackoverflow.com/a/48666503/1069467
This uses pkg_resources
- perhaps there is a way to do it with importlib as well (not necessarily; if I remember well, in your first PR to AiiDA you already encountered an issue where importlib did lack some of the functionality of the old pkg_resources
)
In any case, this does seem like a use case for dynamically adding entry points (i.e. it could be done in the __init__.py
of aiida_restapi)
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.
I guess this list can be removed now?
Didn't we discuss that we would merge things between the full_type strings known to AiiDa and entrypoints that could be added here?
json={ | ||
"node_type": "data.dict.Dict.|", | ||
"attributes": {"x": 1, "y": 2}, | ||
"label": "test_dict", |
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.
please add a test that checks you get an error if you provide attributes that cannot be set by the user (e.g. uuid, mtime, ...)
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.
have you added it? (sorry if I'm overlooking it)
): # pylint: disable=unused-argument | ||
"""Testing file upload""" | ||
test_file = { | ||
"upload_file": ( |
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.
is this a hardcoded string?
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.
Yes
Hi @NinadBhat , are you going to address the points raised? |
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.
hey @NinadBhat , I just had another look at the PR but it seems there were a couple of comments from my previous review that were not yet addressed?
Could you please look into those?
aiida_restapi/routers/nodes.py
Outdated
for ep_node in entry_point_nodes: | ||
if ep_node.name == node_type: | ||
orm_object = ep_node.load().create_new_node( | ||
node_type, attributes, node_dict | ||
) |
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.
Any updates on this?
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 @NinadBhat , let's get this merged
aiida_restapi/routers/nodes.py
Outdated
get_current_active_user | ||
), # pylint: disable=unused-argument | ||
) -> models.Node: | ||
"""Test function for upload file will be merged with create_node later.""" |
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.
Ah hm... while writing the commit message, I realized that there is still this special endpoint for singlefiledata.
As you mention here, this should be merged with the /nodes
endpoint (we don't want to have a separate endpoint for every node type that requires a file).
@NinadBhat Can you please take care of this?
After this, I think this PR is ready to merge.
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.
@ltalirz I thought we had decided to have two separate endpoints one for normal node and one for file upload. As one uses JSON data and the other uses form data.
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 for the reminder @NinadBhat . After syncing with @chrisjsewell we agree to keep your approach but to move the endpoint under /nodes/singlefile
.
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.
@ltalirz Done
Thanks @NinadBhat ! |
No description provided.