Skip to content
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

NEP 29: new release schedule for scientific python packages #3421

Closed
jngrad opened this issue Jan 19, 2020 · 16 comments
Closed

NEP 29: new release schedule for scientific python packages #3421

jngrad opened this issue Jan 19, 2020 · 16 comments
Assignees

Comments

@jngrad
Copy link
Member

jngrad commented Jan 19, 2020

The NEP 29 - Recommend Python and Numpy version support as a community policy standard proposes a new release schedule for numpy. Major python packages like matplotlib, jupyter and scipy have already adopted NEP 29, which means that most python dependencies of espresso will be affected either directly or indirectly. The proposed release cycle is 42 months, which is slightly shorter than the 48 months time window for espresso (we support the last two Ubuntu LTS).

This has consequences on our own release schedule. There is a handy support table and drop schedule to keep track of when to update our requirements.txt. We'll have to be more strict about version pinning for the few python packages that cannot be installed from Ubuntu repositories, to avoid e.g. #3420. We might have to drop support for Ubuntu 16.04 LTS in the planned espresso 4.1.3 release (due several months after Ubuntu 20.04 LTS is out), and tweak our docker .gitlab-ci.yml to test Ubuntu 16.04 images against the 4.1.2 tag instead of the 4.1 branch.

@RudolfWeeber
Copy link
Contributor

RudolfWeeber commented Jan 19, 2020 via email

@jngrad
Copy link
Member Author

jngrad commented Apr 24, 2020

The requirement MDAnalysis>=0.16 breaks for version 0.16 on Ubuntu 20.04. I'll increase the required version numbers once we're done with the ongoing simplification of CI images.

@jngrad jngrad self-assigned this Apr 24, 2020
jngrad added a commit that referenced this issue Apr 27, 2020
Description of changes:
- reduce number of CI images for CUDA jobs (partial fix for #3611)
- test CUDA 9.1 and 10.1 using compatible compilers without patches (fixes #3654)
- drop support for Ubuntu 16.04
- bump minimal Boost version to 1.65 (partial fix for #3093)
- bump Python packages to the versions available in Ubuntu 18.04 (partial fix for #3421)
- add missing lxml package (fixes #3686)
- fix issues in docs revealed by the new Doxygen and Sphinx versions
@jngrad
Copy link
Member Author

jngrad commented Jun 27, 2020

Currently the centos:7 image still uses numpy 1.12.1. With numpy 1.13.0 and above, it looks like we no longer need the np.copy() trick in the testsuite to cast array_locked to mutable arrays inside np.testing.assert_array_equal().

@jngrad
Copy link
Member Author

jngrad commented Jun 29, 2020

Actually we can only remove the np.copy from the first argument of np.testing.assert_* function, the second argument (the reference value) needs to be writeable, i.e. np.copy() is still required there. Although we'll have to remember that caveat, this still improves the readability of the tests by a lot. I was able to remove 140 superfluous np.copy() in the proof-of-concept bd193ff (100 np.copy() are still present). This requires installing numpy 1.14.0 in centos:7, which is the version we require in non-CentOS images.

@RudolfWeeber would you say the gain in readability is worth the trouble of remembering that the second argument has to be mutable? I would obviously take care of the merge conflicts in the waLBerla branch, and not touch the commented tests to avoid silent regressions.

@RudolfWeeber
Copy link
Contributor

RudolfWeeber commented Jun 30, 2020 via email

@KaiSzuttor
Copy link
Member

is np.copy such a big deal? I think we have more serious issues.

@fweik
Copy link
Contributor

fweik commented Jun 30, 2020

It's a surprising hurdle for writing tests, and as such we would be better off if it was not needed.

@KaiSzuttor
Copy link
Member

I agree, but if we do not get rid of the calls completely I think it is not worth the effort.

@jngrad
Copy link
Member Author

jngrad commented Jun 30, 2020

but if we do not get rid of the calls completely I think it is not worth the effort.

I wish we could remove np.copy() everywhere. Looking at the numpy code, the issue stems from the statement at numpy/numpy:numpy/testing/_private/utils.py#L769-L771. In flagged |= bool_array, bool_array is an array that inherits from our espressomd.utils.array_locked() class, and thus acquires the deleted __ior__() method. On the next flagged |= bool_array statement, flagged throws an exception. Not sure if there is a special member in python classes that could be called when a new object is instantiated from an existing object, to give the existing object an opportunity to return a writeable copy of itself if the type of the new instance is not array_locked (this would come into play when np.testing does bool_(array)).

@jngrad
Copy link
Member Author

jngrad commented Jul 1, 2020

Looking at the exact block where we return a bool_(array_locked) object whose type inherits all our disabled special methods (line 750 in numpy/testing/_private/utils.py#L745-L750) gave me second thoughts. If the numpy project decides to change this if/else block in the future, there's a risk that e.g. the first argument needs to use np.copy() while the second argument doesn't. In that case, we would have to revert my changes.

For a long term solution, I looked at the numpy 1.13.0 new __array_ufunc__ special member callback, that allows you to intercept function calls (including basic matrix operations like multiply or add) and cast away the array_lock on-the-fly. This is what pint actually does to preserve SI units when passing their objects to numpy functions (pint/quantity.py#L1563-L1575). With this change, we could remove the need for np.copy() everywhere. I'll try to work out a solution. If this has unintended side-effects or too much overhead, we could instead inject subok=False for np.isnan() and np.isinf() to remove np.copy() in at least the testsuite.

Relevant numpy docs:
https://numpy.org/doc/stable/reference/arrays.classes.html
https://numpy.org/devdocs/user/basics.subclassing.html

@jngrad
Copy link
Member Author

jngrad commented Jul 1, 2020

Update: we can't inject subok=False without also changing the type of the array_locked, otherwise we have infinite recursion. Changing the type by passing a view of the np.array works without noticeable overhead in the python tests. Once the CentOS 7 image is updated, 334 occurrences of np.copy(), np.array() and obj.copy() can be removed from the tests/samples/cython code. This will improve readability a lot and make CI a smoother experience.

@fweik
Copy link
Contributor

fweik commented Jul 1, 2020

@jngrad is there some immediate issue that needs fixing here? Is it worth putting much thought into this?

@jngrad
Copy link
Member Author

jngrad commented Jul 1, 2020

is there some immediate issue that needs fixing here?

no

Is it worth putting much thought into this?

The fact that we have constructions in the code like np.array(np.copy(array_locked([i,j,k]))) - np.array([x,y,z]) suggests to me that our current array_locked class design goes against developer's expectations. The rightmost array casts the leftmost object into a np.array so the np.array(np.copy()) serves no purpose. We already require a numpy version that offers a stable framework for handling such cases gracefully for all function calls (3f5b195), instead of our currently hardcoded np.copy() special methods that only cover additions and subtractions. We could probably also convert all disabled special methods in array_locked by a set of strings that would be used to raise the exception in __array_ufunc__, as suggested in the numpy docs for ufunc-based class design.

addendum: besides the immediate effect of removing all occurrences of np.copy() and friends everywhere and not having to remember any side-effects in np.testing anymore, we can also do b = np.array([1.,1.,1.]); b *= system.part[0].pos without having to worry about the array_locked silently propagating its immutability to regular numpy arrays.

@fweik
Copy link
Contributor

fweik commented Jul 2, 2020

Just as a side note: The array_locked construction is a hack, which has come back multiple time to bite us. The underlying problem is the impedance mismatch between the reference semantics of python and our wonky interface code. Since we can't bend python to our will, the fundamental solution is to give our side also reference semantics. The reason for the whole array_locked thing is that our interface produces temporary values.

kodiakhq bot added a commit that referenced this issue Aug 28, 2020
Description of changes:
- bump CMake version requirement from 3.10 to 3.11 to get full support for imported targets
    * fixes a cryptic error message when compiling ESPResSo with FFTW3 using CMake 3.10
- bump Python version requirement from 3.5 to 3.6 (NEP 29, see drop table in #3421)
    * enables f-strings
- fix flaw in `espressomd.utils.check_type_or_throw_except()` that lead to subtle errors when arrays had the wrong size
- add tests for functions in `espressomd.utils`
@christophlohrmann
Copy link
Contributor

having to np.copy() values to check them is still an annoyance
https://gitlab.icp.uni-stuttgart.de/espressomd/espresso/-/jobs/257941

kodiakhq bot added a commit that referenced this issue Feb 19, 2021
Description of changes:
- fix numpy 1.20 warnings about deprecated builtin types
- bump Python packages to the versions available in Ubuntu 20.04 (as per #3421)
- prevent running the constant pH tutorial with an unsupported `pint` version
kodiakhq bot added a commit that referenced this issue Jul 28, 2021
Description of changes:
- require Python 3.7+, scipy 1.4.0+, numpy 1.17.4+ (as per #3421, fixes #4258)
- require Boost 1.69+ (enables #3638)
- remove OpenSUSE job from CI (Leap 15.3 doesn't package Python3 and Boost, Leap 15.2 is outdated)
kodiakhq bot added a commit that referenced this issue Apr 6, 2022
Fixes #4488, fixes  #4490, fixes #4491, fixes #4477

Description of changes:
- require Python 3.8+ (as per #3421)
- use `contextlib` in the testsuite to better handle `ImportError` from missing dependencies
- use `pathlib` in the testsuite and scripts for portability on non-Posix environments
- modernize python testsuite, fix broken test cases, improve code coverage
- implement initial position offset for LEbc protocol `OscillatoryShear`
- use new CI infrastructure: run jobs on 4 cores (reduce test runtime by 30%), update labels to better utilize GPU runners
@jngrad
Copy link
Member Author

jngrad commented Jul 1, 2022

The NEP 29 time table is now followed by ESPResSo, since we update dependency versions based on the Ubuntu LTS.

Regarding modernizing array_locked for better compatibility with numpy testing and user scripts (jngrad/espresso@3f5b195d) and removing all instances of np.copy() from the testsuite (jngrad/espresso@41e1c5b9), a majority of the core team opposed the change, and the testsuite has now diverged too much.

This ticket can be closed.

@jngrad jngrad closed this as completed Jul 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants