Skip to content

DEP: Deprecate NPY_CHAR #8948

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

Merged
merged 5 commits into from
May 3, 2017
Merged

Conversation

juliantaylor
Copy link
Contributor

Do the deprecation that should have happened 7 releases ago.
Attempt to fix f2py but there are no tests for the NPY_CHAR code so it is most likely busted.
As f2pys usage of NPY_CHAR severely hinders further development by blocking addition of new dtypes without breaking ABI or baking more hacks into our existing ABI I say release it and fix as reports come in.

@juliantaylor juliantaylor mentioned this pull request Apr 15, 2017
@juliantaylor juliantaylor force-pushed the deprecate-NPY_CHAR branch 2 times, most recently from f549803 to 34369b7 Compare April 15, 2017 12:54
@mhvk
Copy link
Contributor

mhvk commented Apr 15, 2017

I used f2py quite a bit, so tried to review, but realized I don't understand things well enough to be of much use. Might it be an idea to warn on the mailing list and specifically ask people to add simple test cases for string behaviour that they know works right now? (my own code only passed through numbers, so is of little use, sadly).

@juliantaylor
Copy link
Contributor Author

strings were apparently never really well supported and the few stackoverflow entries I have found are full of confused users. It has never been updated from the numarray times.
So my guess there are probably not too many users out there, but still its a good idea to ping the list.

@rgommers
Copy link
Member

thanks for picking this up Julian!

@pearu
Copy link
Contributor

pearu commented Apr 17, 2017

Fortran character strings and arrays are very common in Fortran codes. So, please do not assume that there are not many users who need to wrap such Fortran codes for Python. I have helped out number of users in private regarding wrapping strings and string arrays. The fundamental trick is to not assume that Fortran strings (mutable) can be mapped directly to Python strings (immutable), and back. I have found that the mutability of strings in different languages is the main source of confusion.

I agree that f2py can be improved regarding strings support and I have promised to do that years ago. However, this work takes some time but it is really hard for me to find couple of weeks to do the required work.

@juliantaylor
Copy link
Contributor Author

we don't need full string supports now, we just need to remove the NPY_CHAR usage.
Can you check if this PR does the correct thing?

@pearu
Copy link
Contributor

pearu commented Apr 18, 2017

I checked this PR with a test case containing

character*5, dimension (10), intent (inout) :: A
!f2py intent(in,out) A

and the test script gives the same output as with NPY_CHAR enabled.
So, with this very limited test I can confirm that the PR does the correct thing.

@juliantaylor juliantaylor added this to the 1.13.0 release milestone Apr 22, 2017
@@ -701,6 +706,15 @@ PyArrayObject* array_from_pyobj(const int type_num,
}

descr = PyArray_DescrFromType(type_num);
/* compatibility with NPY_CHAR */
if (type_num == NPY_STRING) {
descr = PyArray_DescrNew(descr);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one could use PyArray_DESCR_REPLACE but that decrefs and PyArray_DescrFromType does not incref basic types.
I assume that is actually a bug we just get away with it because we likely leak descriptors all over the place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh it does incref I am just to dumb to read

@@ -4435,6 +4436,13 @@ PyArray_DescrFromType(int type)
return NULL;
}
else if ((type == NPY_CHAR) || (type == NPY_CHARLTR)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzled by the distinction between CHAR and CHARLTR - and why this patch seems to translate CHAR into CHARLTR now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It triggers some old numarray compatibility code. It probably doesn't work as f2py might very well be the only remaining user.
But this patch doesn't change anything in this regard.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CHAR_LTR refers to the dtype(...).char attribute, which is the only difference from the string type.

In [1]: dtype('c') == dtype('S1')
Out[1]: True

@charris
Copy link
Member

charris commented Apr 22, 2017

@juliantaylor Needs a release note.

@charris charris added the 56 - Needs Release Note. Needs an entry in doc/release/upcoming_changes label Apr 22, 2017
@charris charris changed the title deprecate NPY_CHAR DEP: Deprecate NPY_CHAR Apr 25, 2017
@charris
Copy link
Member

charris commented Apr 25, 2017

Also needs an entry in numpy/core/tests/test_deprecations.py.


#if !defined _NPY_NO_DEPRECATIONS && \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would look better with the pseudo functional form defined(...).

@@ -4435,6 +4436,13 @@ PyArray_DescrFromType(int type)
return NULL;
}
else if ((type == NPY_CHAR) || (type == NPY_CHARLTR)) {
if (type == NPY_CHAR) {
if (DEPRECATE("The NPY_CHAR type_num is deprecated. "
"Please port your code to use "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need comment with date and numpy version. Something like

        /* 2017-04-25, 1.13 */

@@ -608,6 +609,13 @@ incref_elide_l(PyObject *dummy, PyObject *args)
return res;
}

static PyObject *
npy_char_deprecation(PyObject *dummy)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need a note as to why this is done this way. I assume to get a deprecation warning.

cppmacros[
m] = '#define %s(v,dims) (PyArray_SimpleNewFromData(1,dims,NPY_CHAR,(char *)v))' % (m)
m] = '#define %s(v,dims) (PyArray_New(&PyArray_Type, 1, dims, NPY_STRING, NULL, v, 1, NPY_ARRAY_CARRAY, NULL))' % (m)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be good to break this string into shorter lines. Breaking the index bracket to get a continuation line is just weird, but that is for another day.

@@ -679,6 +679,11 @@ PyArrayObject* array_from_pyobj(const int type_num,
|| ((intent & F2PY_OPTIONAL) && (obj==Py_None))
) {
/* intent(cache), optional, intent(hide) */
int itemsize = 0;
/* compatibility with NPY_CHAR */
Copy link
Member

@charris charris Apr 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No zero sized strings the reason for 1?

EDIT: I am curious as to why it is set to 0 as 'c' is already 'S1'.

return NULL;
}
descr->elsize = 1;
descr->type = NPY_CHARLTR;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to keep using NPY_CHARLTR? The only difference from S1 I can see is that that dtype('c').char is 'c'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably not, but that define doesn't really bother use in a non-cosmetic way.

@@ -691,7 +696,7 @@ PyArrayObject* array_from_pyobj(const int type_num,
}
arr = (PyArrayObject *)
PyArray_New(&PyArray_Type, rank, dims, type_num,
NULL,NULL,0,
NULL,NULL,itemsize,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just set this to 1. It is ignored for types of fixed size, which should be the case for NPY_CHAR and all the numeric types, so only used for string types

PyArray_New(&PyArray_Type, PyArray_NDIM(arr), PyArray_DIMS(arr), type_num,
NULL,NULL,0,
NULL,NULL,itemsize,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

@@ -342,6 +342,10 @@ def test_array_cont(self):
assert_(np.ascontiguousarray(d).flags.c_contiguous)
assert_(np.asfortranarray(d).flags.f_contiguous)

def test_npy_char_deprecation(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Belongs in test_deprecations.py

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't get it to work the test_deprecation way.

class TestNPY_CHAR(_DeprecationTestCase):
    def test_npy_char_deprecation(self):
        from numpy.core.multiarray_tests import npy_char_deprecation
        self.assert_deprecated(npy_char_deprecation)

does not work, it says AssertionError: No error raised during function call. How is the test supposed to look like?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not really important to use that infrastructure anymore I think. That said, this may be correct, since the test checks both that the warning is given, as well as tests that an error is raised when the warning is set to "raise".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, I guess this would work out with that test, if you just return the descriptor in the test function (since it should be NULL on error I guess).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah that was it thanks. Updated.

@charris
Copy link
Member

charris commented May 2, 2017

@juliantaylor Could you finish this up for 1.13?

@juliantaylor juliantaylor force-pushed the deprecate-NPY_CHAR branch from 245a52d to 9c39207 Compare May 3, 2017 00:19
@charris charris merged commit 1d592c1 into numpy:master May 3, 2017
@charris
Copy link
Member

charris commented May 3, 2017

Thanks Julian.

@juliantaylor juliantaylor deleted the deprecate-NPY_CHAR branch May 4, 2017 18:07
DougBurke added a commit to sherpa/sherpa that referenced this pull request Aug 29, 2017
This avoids the following compilation message

sherpa/include/sherpa/extension.hh:32:30: warning: ‘NPY_CHAR’ is deprecated:
Use NPY_STRING [-Wdeprecated-declarations]

and avoids a deprecation warning when running code in NumPy 1.13 and
higher (see numpy/numpy#8948).

The NPY_STRING symbol was added in NumPy 1.7, which I think is early enough
that we don't need to try and support both the old and new versions (i.e.
we do not guarantee support for Sherpa using versions as old as NumPy 1.7).
@charris
Copy link
Member

charris commented Nov 15, 2017

@juliantaylor We finally have a report of an issue, #10027.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants