-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
bpo-29546: Improve from-import error message with location #103
Conversation
7124949
to
ff44351
Compare
Python/ceval.c
Outdated
@@ -5022,12 +5022,23 @@ import_from(PyObject *v, PyObject *name) | |||
return x; | |||
error: | |||
pkgpath = PyModule_GetFilenameObject(v); | |||
if (name == NULL){ |
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.
Missing a space between )
and {
.
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.
Yep, that's exactly the format I was thinking! Great work.
|
Good, and thanks. I'll cleanup and add tests then ! |
ff44351
to
36c8950
Compare
Added tests, Misc/NEWS, What's new. The only thing I'm unsure is what the module's It's also a bit ugly if a module has neither name not a file:
But that seem to be rare from how it's currently tested: class AlwaysAttributeError:
def __getattr__(self, _):
raise AttributeError
module_name = 'test_from_import_AttributeError'
self.addCleanup(unload, module_name)
sys.modules[module_name] = AlwaysAttributeError() |
On Feb 15, 2017, at 07:56 PM, Matthias Bussonnier wrote:
It's also a bit ugly if a module has neither name not a file:
> "cannot import name 'does_not_exist' from '<unknown module name>' (unknown location)"
But that seem to be rare from how it's currently tested:
Agreed it's ugly, but if it won't happen commonly in practice, it's probably
not worth dealing with specially. I'm also not sure how you'd print that any
better - it is worth knowing what's unknowable. :)
|
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 review the potential reference counting bugs.
Python/ceval.c
Outdated
pkgname_or_unknown = PyUnicode_FromString("<unknown module name>"); | ||
} else { | ||
pkgname_or_unknown = pkgname; | ||
} |
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 there are some reference counting bugs lurking here.
- It's possible the code jumps to
error:
afterpkgname
is decref'd. I think that decref should be deferred until just before the good-path return. pkgname_or_unknown
will be a new reference ifpkgname
is NULL, or it will steal thepkgname
reference if it's not. In either case, theerror
stanza should decrefpkgname_or_unknown
, which will take care of ensuring the object gets decref for anygoto error
path.pkgpath
doesn't get decref'd. I think you shouldPy_XDECREF
it before thereturn NULL
just in casepkgpath
is itself NULL.
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 detailed explanation, I still need to get used to do manual ref counting.
I've push changes. Let me know if I got things rights.
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.
@Carreau Yes, I think the refcounting is right now. It can sometimes be difficult to trace all the various exit paths to make sure that everything gets decref'd and incref'd properly, but as best I can tell, you've got it right now. Thanks!
The only other thing is that it's possible for the PyUnicode_FromString("<unknown module name>")
to fail and return NULL. Probably the only realistic cause of that would be a memory error (not sure if an encoding error could do it given that this is an ascii C string). If you want to be pedanditc, it would be useful to check for that error condition and do something more reasonable in that case.
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.
If you want to be pedanditc, it would be useful to check for that error condition and do something more reasonable in that case
I'm unsure what "more reasonable" is, I check and failed with the original error message in that case, but I don't see how if allocating PyUnicode_FromString("<unknown module name>")
fails we can do something sensible.
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.
Probably the best you can do is to just decref any objects that may still have a reference count, and then immediately return NULL. The PyUnicode_FromString failure would have already set an exception, so that's the one you'll see. Something like:
1 file changed, 4 insertions(+)
Python/ceval.c | 4 ++++
modified Python/ceval.c
@@ -5024,6 +5024,10 @@ import_from(PyObject *v, PyObject *name)
pkgpath = PyModule_GetFilenameObject(v);
if (pkgname == NULL) {
pkgname_or_unknown = PyUnicode_FromString("<unknown module name>");
+ if (pkgname_or_unknown == NULL) {
+ Py_XDECREF(pkgpath);
+ return NULL;
+ }
} else {
pkgname_or_unknown = pkgname;
}
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.
Semicolons to end lines.
Please check for PyUnicode_FromString()
returning NULL.
Python/ceval.c
Outdated
} | ||
|
||
Py_XDECREF(pkgname_or_unknown) | ||
Py_XDECREF(pkgpath) |
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.
Oh whoops, these lines need to end with semicolons.
0e29d44
to
e757eec
Compare
semicolon added |
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.
Two more small comments, but I think this is really close!
Python/ceval.c
Outdated
pkgname_or_unknown = PyUnicode_FromString("<unknown module name>"); | ||
} else { | ||
pkgname_or_unknown = pkgname; | ||
} |
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.
Probably the best you can do is to just decref any objects that may still have a reference count, and then immediately return NULL. The PyUnicode_FromString failure would have already set an exception, so that's the one you'll see. Something like:
1 file changed, 4 insertions(+)
Python/ceval.c | 4 ++++
modified Python/ceval.c
@@ -5024,6 +5024,10 @@ import_from(PyObject *v, PyObject *name)
pkgpath = PyModule_GetFilenameObject(v);
if (pkgname == NULL) {
pkgname_or_unknown = PyUnicode_FromString("<unknown module name>");
+ if (pkgname_or_unknown == NULL) {
+ Py_XDECREF(pkgpath);
+ return NULL;
+ }
} else {
pkgname_or_unknown = pkgname;
}
Python/ceval.c
Outdated
|
||
if (pkgpath == NULL || !PyUnicode_Check(pkgpath)) { | ||
if (pkgname_or_unknown == NULL){ |
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.
You need a space between the paren and open brace.
Add location information like canonical module name where identifier cannot be found and file location if available. First iteration of this was pythongh-91
from Barry Warsaw: - It's possible the code jumps to error: after pkgname is decref'd. I think that decref should be deferred until just before the good-path return. - pkgname_or_unknown will be a new reference if pkgname is NULL, or it will steal the pkgname reference if it's not. In either case, the error stanza should decref pkgname_or_unknown, which will take care of ensuring the object gets decref for any goto error path. - pkgpath doesn't get decref'd. I think you should Py_XDECREF it before the return NULL just in case pkgpath is itself NULL.
dfa3512
to
1b6e462
Compare
Comments should be addressed. Thanks ! |
@Carreau Thanks, this LGTM now. I'm pushing the big green button. |
Thanks ! |
Fix an invalid assertion during interpreter shutdown and add a test case for this problem. https://bitbucket.org/stackless-dev/stackless/issues/103 (grafted from a2f660260c93e911fde4969dac79c9eb6cc03e72)
The reworked C-function slp_kill_tasks_with_stacks() didn't work correctly for deeply nested tasklets. Therefore I had to rework it again. This version first kills a tasklet and only then clears the tstate of its cstacks. I added several new test cases and reorganised them a bit. https://bitbucket.org/stackless-dev/stackless/issues/103 (grafted from 130a60b8d3719e06807acd7e9b63c07bd5435c32)
Add location information like canonical module name where identifier
cannot be found and file location if available.
First iteration of this was gh-91
Testless for now, I can add tests once the exact format has been agreed upon.