-
Notifications
You must be signed in to change notification settings - Fork 203
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.open: more useful warnings #4434
node.open: more useful warnings #4434
Conversation
a6c0f11
to
ac1479a
Compare
Example warning:
It's a bit ugly that
from this but that also seemed like overkill. |
Codecov Report
@@ Coverage Diff @@
## develop #4434 +/- ##
===========================================
- Coverage 79.36% 79.35% -0.00%
===========================================
Files 476 476
Lines 34951 34959 +8
===========================================
+ Hits 27736 27739 +3
- Misses 7215 7220 +5
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
aiida/orm/nodes/node.py
Outdated
msg = f'\n`Node.{method}` used outside context manager for {self._name}.\n' + \ | ||
'Please use `with <node>.open(): ...` instead. ' + \ | ||
'This will raise starting from `aiida-core==2.0.0`\n' | ||
caller_frame = inspect.currentframe().f_back.f_back |
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 wonder if there is a possibility that this code fails - maybe we can just wrap it in a try / except such that it fails gracefully?
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.
Done (for the case when f_back
returns None
aiida/orm/nodes/node.py
Outdated
msg = '`{}` used without context manager for {}. This will raise starting from `aiida-core==2.0.0`'.format( | ||
method, self._name | ||
) | ||
msg = f'\n`Node.{method}` used outside context manager for {self._name}.\n' + \ |
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.
The Node.{method}
is not actually correct and may be misleading. The method
here is what is actually called on the return value of Node.open
. Normally this is a filelike object, but now it is this instance of WarnWhenNotEntered
that we added. You can see this when this object is garbage collected, because it will then say Node.del used outside ..
but Node
doesn't have a del
method. Same goes for read
though.
Consider following example:
handle = node.open()
content = handle.read()
It is when read
is called on handle
that we get the warning, not on the node. Likewise, it is del handle
that is called when it is garbage collected that incurs the second warning.
This shows another potential problem, with the example above, the line of code that you will include in your warning will be content = handle.read()
and people may be confused by you to tell them that this should be with node.open()
. Note that in this case, the fix may be obvious, because they will go to the line mentioned, and see the node.open()
call straight above it. However, they are not necessarily very close. They could have passed the handle to some function, so then it may not be clear at all where the actual problem is.
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.
The
Node.{method}
is not actually correct and may be misleading. Themethod
here is what is actually called on the return value ofNode.open
.
Right, I've now tried to rephrase the message to make this clearer. Further suggestions welcome.
the line of code that you will include in your warning will be
content = handle.read()
and people may be confused by you to tell them that this should bewith node.open()
You are very welcome to suggest a better way.
In my view, this warning already improves the situation enormously, since it shows which call caused the warning rather than where the warning is defined.
For me this is good enough.
aiida/orm/nodes/node.py
Outdated
'This will raise starting from `aiida-core==2.0.0`\n' | ||
caller_frame = inspect.currentframe().f_back.f_back | ||
caller_tb = inspect.getframeinfo(caller_frame) | ||
msg += f'File {caller_tb.filename}, line {caller_tb.lineno} in module {caller_tb.function}' |
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.
Not sure why, but I see the line with File {caller_tb.filename} ..
twice
/home/sph/code/aiida/env/dev/aiida-core/aiida/orm/nodes/node.py:62: AiidaDeprecationWarning:
`Node.read` used outside context manager for <ForceConstantsData: uuid: 6444b4db-4c69-484d-87d1-5ab6d38d8e46 (unstored)>.
Please use `with <node>.open(): ...` instead. This will raise starting from `aiida-core==2.0.0`
File /home/sph/code/aiida/env/dev/aiida-quantumespresso/aiida_quantumespresso/data/force_constants.py, line 22 in module set_file File "/home/sph/code/aiida/env/dev/aiida-quantumespresso/aiida_quantumespresso/data/force_constants.py", line 22, in set_file
content = handle.read().splitlines()
warnings.warn(msg, AiidaDeprecationWarning) # pylint: disable=no-member
Any idea why?
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.
Sorry, this didn't show up for me since I was working inside the ipython shell, and so I thought I had to recreate this line manually.
I've removed it now; should be fixed.
@ltalirz I think it would be good to try and get this into the v1.5.0 release as well. Do you have the time to still take a look at this? |
Yes |
ac1479a
to
cf99009
Compare
cf99009
to
fdbe999
Compare
aiida/orm/nodes/node.py
Outdated
msg = f'\n`{method}` called outside Node.open() context manager for {self._name}.\n' + \ | ||
'Please wrap this call inside `with <node instance>.open(): ...` to silence this warning. ' + \ | ||
'This will raise starting from `aiida-core==2.0.0`\n' | ||
try: | ||
caller_frame = inspect.currentframe().f_back.f_back | ||
except AttributeError: | ||
warnings.warn(msg, AiidaDeprecationWarning) | ||
return | ||
|
||
caller_traceback = traceback.extract_stack(caller_frame, limit=1) | ||
for item in traceback.StackSummary.from_list(caller_traceback).format(): | ||
msg += item | ||
warnings.warn(msg, AiidaDeprecationWarning) # pylint: disable=no-member |
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 think putting the one call in try/except helps but is potentially not enough. We really want to avoid exceptions occurring in this handler. I also think the code to extract the relevant line of code can be much simpler. I propose the following for the entire method, which has updated warning message and stack extraction:
if not self._was_entered:
msg = f'\nThe method `{method}` was called on the return value of `{self._name}.open()` outside of a context manager.\n' + \
'Please wrap this call inside `with <node instance>.open(): ...` to silence this warning. ' + \
'This will raise an exception, starting from `aiida-core==2.0.0`.\n'
try:
caller = traceback.format_stack()[-3]
except Exception: # pylint: disable=broad-except
msg += 'Could not determine the line of code responsible for triggering this warning.'
else:
msg += f'The offending call comes from:\n{caller}'
warnings.warn(msg, AiidaDeprecationWarning) # pylint: disable=no-member
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.
sounds good to me!
fdbe999
to
ef4ddbf
Compare
aiida-core started warning when methods like `Node.read` and `Node.del` are used outside a context manager. The warning, however, did not include any indication of where the problematic function call was made (nor did it include instructions on how to fix it). Furthermore, this PR fixes an overlooked use of `Node.read` in aiida-core that did not rely on the context manager.
ef4ddbf
to
a7f4867
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 @ltalirz
aiida-core started warning when methods like
Node.read
andNode.del
are used outside a context manager.
The warning, however, did not include any indication of where the
problematic function call was made (nor did it include instructions on
how to fix it).
Furthermore, this PR fixes an overlooked use of
Node.read
inaiida-core that did not rely on the context manager.