| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
* Passing a string as the "real" keyword argument is now an error; it should only be passed as a single positional argument. * Passing a complex number as the *real* or *imag* argument is now deprecated; it should only be passed as a single positional argument.
* Share common classes. * Use exactly representable floats and exact tests. * Check the sign of zero components. * Remove duplicated tests (mostly left after merging int and long). * Reorder tests in more consistent way. * Test more error messages. * Add tests for missed cases.
There was a problem hiding this comment.
tmp == NULL condition on L1092 also now only partially covered.
Just checked coverage report after ./python -m test test_complex test_capi.test_complex
Sorry, something went wrong.
| @@ -930,31 +998,23 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) | |||
| if (r == NULL) { | |||
| r = _PyLong_GetZero(); | |||
There was a problem hiding this comment.
This inaccessible.
Sorry, something went wrong.
There was a problem hiding this comment.
It is now covered by a new test added in #119635 for complex(imag=1.5).
Sorry, something went wrong.
| if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, | ||
| "complex() argument 'real' must be a real number, not %T", | ||
| r)) { | ||
| return NULL; |
There was a problem hiding this comment.
Nit: this is not tested. Ditto for other warning.
Sorry, something went wrong.
|
|
||
| /* Special-case for a single argument when type(arg) is complex. */ | ||
| if (PyComplex_CheckExact(r) && i == NULL && | ||
| type == &PyComplex_Type) { |
There was a problem hiding this comment.
Can this be false? If so, this is not tested.
Sorry, something went wrong.
There was a problem hiding this comment.
Yes, it can be false. Added tests.
Sorry, something went wrong.
| } | ||
|
|
||
| tmp = try_complex_special_method(r); | ||
| if (tmp) { |
There was a problem hiding this comment.
else if (PyErr_Occurred()) branch is not tested.
Sorry, something went wrong.
| @@ -970,9 +1030,8 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) | |||
| (nbr->nb_float == NULL && nbr->nb_index == NULL && !PyComplex_Check(r))) | |||
There was a problem hiding this comment.
Hmm, it seems there is a coverage regression, not all branches are tested.
Sorry, something went wrong.
There was a problem hiding this comment.
This should be covered by new tests added in test added in #119635.
Sorry, something went wrong.
There was a problem hiding this comment.
Now it's better, yet one branch seems to be missed:
1029 [ + - ]: 3869 : if (nbr == NULL ||
Looks like it's nbr!=NULL.
Sorry, something went wrong.
| Py_TYPE(r)->tp_name); | ||
| "complex() argument 'real' must be a real number, not %T", | ||
| r); | ||
| if (own_r) { |
There was a problem hiding this comment.
Actually, own_r condition here is inaccessible. If we are here - try_complex_special_method() call above was unsuccessful.
See #109642. Maybe it worth to include constructor-related changes from that pr.
Sorry, something went wrong.
There was a problem hiding this comment.
I'll see.
Sorry, something went wrong.
There was a problem hiding this comment.
This code will be removed after the end of the deprecation period. So it is not worth to spent effort to optimize it.
Sorry, something went wrong.
|
Thank you for your review @skirpichev. Much of coverage is added by test added in #119635. |
Sorry, something went wrong.
| if (nbr == NULL || | ||
| (nbr->nb_float == NULL && nbr->nb_index == NULL)) |
There was a problem hiding this comment.
This also looks untested:
1072 [ + - ]: 10 : if (nbr == NULL ||
1073 [ + - + - ]: 10 : (nbr->nb_float == NULL && nbr->nb_index == NULL))
Sorry, something went wrong.
| Py_complex c = ((PyComplexObject*)arg)->cval; | ||
| res = complex_subtype_from_doubles(type, c.real, c.imag); | ||
| } | ||
| else if ((nbr = Py_TYPE(arg)->tp_as_number) != NULL && |
There was a problem hiding this comment.
One branch missed:
952 [ + - ]: 55 : else if ((nbr = Py_TYPE(arg)->tp_as_number) != NULL &&
953 [ + + + + ]: 55 : (nbr->nb_float != NULL || nbr->nb_index != NULL))
Sorry, something went wrong.
There was a problem hiding this comment.
How to interpret this? It looks to me that all possible combinations are covered.
Sorry, something went wrong.
There was a problem hiding this comment.
Hmm, branch coverage output for C code looks cryptic. Try complex([]), i.e. nbr != NULL, but it has no nb_float/index, that works for me.
Sorry, something went wrong.
There was a problem hiding this comment.
I think complex(MyInt()) (where MyInt has the __int__ method already covers this).
Sorry, something went wrong.
There was a problem hiding this comment.
No. Oh, I see: that should be nbr == NULL condition. So complex(object()) will work too.
Sorry, something went wrong.
| return result; | ||
| } | ||
|
|
||
| static PyObject * |
There was a problem hiding this comment.
Would it be worth adding a comment above this function explaining the purpose (and explaining why this is different from complex_new)?
Sorry, something went wrong.
There was a problem hiding this comment.
LGTM in principle, and works as expected in manual testing. I won't claim to have examined all the branching possibilities, but it looks as though @skirpichev is on top of that. :-)
Sorry, something went wrong.
| else if (PyErr_Occurred()) { | ||
| return NULL; | ||
| } | ||
| else if (PyComplex_Check(arg)) { |
There was a problem hiding this comment.
FYI, this is not tested. But I'm not sure if that's a right logic. Complex subclasses should be covered by try_complex_special_method(), c.f. PyNumber_Float().
Sorry, something went wrong.
There was a problem hiding this comment.
try_complex_special_method is relatively expensive in comparison to PyNumber_Float(), because there is no nb_complex slot. And __complex__ is looked up even for exact complex, float and int. I planned to do something with this, but in a different PR. We can not also completely exclude complex subclasses without __complex__.
Sorry, something went wrong.
There was a problem hiding this comment.
try_complex_special_method is relatively expensive in comparison to PyNumber_Float()
That seems to be an implementation detail. I wonder if we could add nb_complex slot: there is a reserved slot right now anyway.
And complex is looked up even for exact complex, float and int.
The current (i.e. in the main) code - uses here same logic as the float constructor: there is a case for exact complex (as for exact float in PyNumber_Float()).
We can not also completely exclude complex subclasses without complex.
People could break thing in very crazy ways, but should we support such cases? (Looks as a variant of #112636.)
Sorry, something went wrong.
There was a problem hiding this comment.
Sorry, something went wrong.
| Py_complex c = ((PyComplexObject*)arg)->cval; | ||
| res = complex_subtype_from_doubles(type, c.real, c.imag); | ||
| } | ||
| else if ((nbr = Py_TYPE(arg)->tp_as_number) != NULL && |
There was a problem hiding this comment.
Hmm, branch coverage output for C code looks cryptic. Try complex([]), i.e. nbr != NULL, but it has no nb_float/index, that works for me.
Sorry, something went wrong.
| } | ||
| PyObject *orig_r = r; | ||
|
|
||
| tmp = try_complex_special_method(r); |
There was a problem hiding this comment.
IIUIC, this logic will be dropped after a deprecation period as well. I'm not sure if this is obvious, maybe worth a comment.
Sorry, something went wrong.
There was a problem hiding this comment.
LGTM, except for useless PyComplex_Check() branch in the actual_complex_new() and one missing branch coverage here.
The rest, probably, not worth for improving, as it will be eventually removed. Though, I think that removing inaccessible cases (various own_r branches) will make code more readable.
Sorry, something went wrong.
| Py_complex c = ((PyComplexObject*)arg)->cval; | ||
| res = complex_subtype_from_doubles(type, c.real, c.imag); | ||
| } | ||
| else if ((nbr = Py_TYPE(arg)->tp_as_number) != NULL && |
There was a problem hiding this comment.
No. Oh, I see: that should be nbr == NULL condition. So complex(object()) will work too.
Sorry, something went wrong.
| else if (PyComplex_Check(arg)) { | ||
| /* Note that if arg is of a complex subtype, we're only | ||
| retaining its real & imag parts here, and the return | ||
| value is (properly) of the builtin complex type. */ | ||
| Py_complex c = ((PyComplexObject*)arg)->cval; | ||
| res = complex_subtype_from_doubles(type, c.real, c.imag); | ||
| } |
There was a problem hiding this comment.
| else if (PyComplex_Check(arg)) { | |
| /* Note that if arg is of a complex subtype, we're only | |
| retaining its real & imag parts here, and the return | |
| value is (properly) of the builtin complex type. */ | |
| Py_complex c = ((PyComplexObject*)arg)->cval; | |
| res = complex_subtype_from_doubles(type, c.real, c.imag); | |
| } |
That seems redundant (and untested). Complex subclasses have __complex__() dunder, so they should be handled by try_complex_special_method() helper (even if the dunder is broken somehow).
Sorry, something went wrong.
…ythonGH-119620) * Passing a string as the "real" keyword argument is now an error; it should only be passed as a single positional argument. * Passing a complex number as the "real" or "imag" argument is now deprecated; it should only be passed as a single positional argument.
…ythonGH-119620) * Passing a string as the "real" keyword argument is now an error; it should only be passed as a single positional argument. * Passing a complex number as the "real" or "imag" argument is now deprecated; it should only be passed as a single positional argument.
| Back | FazBrowse Home | New Git URL |
📚 Documentation preview 📚: https://cpython-previews--119620.org.readthedocs.build/