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

Stop support for Python 3.9 #1316

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Stop support for Python 3.9 #1316

wants to merge 6 commits into from

Conversation

Carreau
Copy link
Member

@Carreau Carreau commented Feb 12, 2025

New major version are a good time to drop support for older versions. I thihnk 3.9 should not be an issue, I woudl argue for removal of 3.10 as well.

Carreau and others added 2 commits February 12, 2025 11:38
New major version are a good time to drop support for older versions.
I thihnk 3.9 should not be an issue, I woudl argue for removal of 3.10
as well.
@Carreau Carreau added this to the 7.0 milestone Feb 12, 2025
@davidbrochart
Copy link
Collaborator

Why should we drop Python 3.9, since it has not reached EOL?

@Carreau
Copy link
Member Author

Carreau commented Feb 12, 2025

Please read the description of the PR:

  • We are doing a major version, so it's a good time to drop.

Also:

Waiting for EOL is not a good reason, EOL means that upsrtream have stopped supporting their package, in general it's better to stop before their EOL so that they can stop their support knowing they don't people in the dust.

Saying you need to wait for EOL, is like saying "no it's fine you can use a deprecated feature, it has not been removed.

@Carreau
Copy link
Member Author

Carreau commented Feb 12, 2025

Plus explicitly for 3.9, some test are flaky and annoying only on 3.9

@davidbrochart
Copy link
Collaborator

These are still not valid reasons IMO.
Also, AFAIK we don't do that in other Jupyter projects.

@Carreau
Copy link
Member Author

Carreau commented Feb 12, 2025

Meh, if you don't want that's fine.

I find it a bit strange as for example main numpy is 3.11+, matplotlib is 3.10+ to lag more than 2 years behind and I have a hard time seing how someone that still python 3.9 can justify that they must have ipykernel 7+. It's not like dropping 3.9 support in 7.0 is still going to prevent 6.x to be installed...

Also, AFAIK we don't do that in other Jupyter projects.

This is factually false as IPython does it. Unless you do not consider IPython as a Jupyter project ?

I think you are also adding maintenance burden to yourself and potentially pushing some contributors away.

I personally only have so much free time I'm willing to invest to fix bugs on older Pythons, and there are also limited time I can justify to clients WRT python versions they don't use anymore. The "oh I can't do that because we still support 3.9", writing conditional code for older Python is becoming tiresome.

Feel free to close.

@davidbrochart
Copy link
Collaborator

davidbrochart commented Feb 12, 2025

I'm just saying my opinion, thus not closing.
I'm also not saying IPython is not a Jupyter project, but I don't know any other Jupyter project that does what you suggest.

@Carreau
Copy link
Member Author

Carreau commented Feb 12, 2025

I'm also not saying IPython is not a Jupyter project, but I don't know any other Jupyter project that does what you suggest.

Ah sure, well, but at the same time some project still advertise compatibility for Python 3.8 (jupyter_core, for example), and I don't think many project have discussed the issue, I'm guessing many rely on the maintainer tools default:

But notebook for example test on 3.9+

But this is again bumps because they had to (in my understanding), and I'd love for project to actually discuss python supported window instead of just doing it as late as possible when it's necessary because this is super painful.

Without planning and a clear written rule it's sometime really hard to have discussion with clients.

I would feel much better to know that ipykernel 7+ is Python 3.11+ only, than to have to say that yes, 7.0 to 7.6 is 3.9+, and 7.7 onward in 3.10+ and to be aware of that at the last minute.

@davidbrochart
Copy link
Collaborator

I feel this is something that has to be discussed at the Jupyter level, because one Jupyter project will affect many others, and this is especially true for ipykernel.
My understanding is that we support Python versions until EOL, but I may be wrong.

@ianthomas23
Copy link
Collaborator

Personally I am +1 on this.

@Carreau
Copy link
Member Author

Carreau commented Feb 17, 2025

For what it is worth, I just got annoyed by 3.9, because some_builtin_object|None is invalid at runtime on 3.9, while we use |None everywhere for the rest.

and I really don't see why something released in 2025 need to support something that was release in 2020. There is still the 6.x branch for that.

@Carreau
Copy link
Member Author

Carreau commented Feb 19, 2025

Can we maybe, just for 7.0 get the thought of @ipython/jupyterkernelteam ?

@krassowski
Copy link
Member

I still have a mental image of Python 3.9 as a "recent" version, probably because it was a very nicely feature-packed release and subsequent releases were smaller in terms of features (literally, due to shortened development cycle, more on that later).

I'm also not saying IPython is not a Jupyter project, but I don't know any other Jupyter project that does what you suggest.

There is a precedent for releasing major versions (which we will need to support for a long time afterwards) with a requirement of using a Python version that already met its EOM but not EOL. For example, Python 3.7 was EOL on 2023-06-27 but:

  • JupyterLab 4.0 was released on May 15, 2023 requiring Python 3.8 or newer
  • jupyter-server 2.0 was released Dec 6, 2022 requiring Python 3.8 or newer

Notably, Python release cadence has increased starting with Python 3.9 from once every 18 months to once every 12 months (https://peps.python.org/pep-0602/). One of the arguments for it was to allow more Linux distributions (case of Fedora is explicitly mentioned in the PEP) to synchronise their release schedule and avoid the shipped Python version from falling behind. I think this makes it easier to drop older versions because nowadays operating systems will ship (or offer) more recent versions.

The downside is that dropping Python 3.9 will put downstreams in a position where they would need to test against multiple ipykernel versions as:

IPython itself has already dropped 3.10

I find this a bit of a challenge for downstreams, because moving this fast means:

  • frontends (Jupyter, Spyder) will need to move their main to match the Python version OR ignore ipykernel 7
  • users will continue using older versions of frontends which support Python 3.10 because they cannot update and they cannot tell their admin to update as these versions are still receiving security updates
  • when a new critical security issue gets discovered Jupyter maintainers will be asked to backport it to Jupyter versions which support 3.10; we may not have resources to do so and users will have a choice of not using Jupyter or using a vulnerable version

which is why I am against removal of Python 3.10 support. I think this is much less of problem for Python 3.9 with the current JupyterLab release cadence.

CC @ccordoba12 for opinions.

@Carreau
Copy link
Member Author

Carreau commented Feb 19, 2025

The downside is that dropping Python 3.9 will put downstreams in a position where they would need to test against multiple ipykernel versions as: [...]

I'm confused of what the extra changes are here.
This is already the case that downstream are testing with multiple version of dependencies that are not compatible with some Python version in the CI matrix? That the point of CI matrix and python_requires ?

In CI the python matrix will already install IPython 8.18.1 on 3.9, but 8.x (8.32 currently) on 3.10+ and latest on 3.11+ (which should) soon be 9.0). And that will be true for any direct or indirect (or conditional) dependencies as well.

I'm genuinely confused on what it changes downstream, it's like literally the life of CI that versions of dependencies changes across CI matrix and why ipykernel would need to be different ?

Do you mean that downstream may need to have conditional code based on IPykernel version ?
I agree with that, but that's unrelated to IPykernel being 3.8+, 3.10+ or 3.11+, it just depends on whether we have API change in ipykernel.

frontends (Jupyter, Spyder) will need to move their main to match the Python version OR ignore ipykernel 7

I'm confused as well here. I don't see why users can't use newer version of frontends if they can't update ipykernel? Don't/won't jupyterlab, server and all still work with ipykernel 6 ?
Isn't the point of Jupyter to decouple frontend and kernels ? Did they had to had to "move their main to match the Python " when IPython dropped support for 3.9 ? For 3.10 ? I did not see anyone stop support for IPython 8.19+, so I'm genuinely confused of what you are implying downstream will need to do.

users will continue using older versions of frontends which support Python 3.10 because they cannot update and they cannot tell their admin to update as these versions are still receiving security updates

How is dropping support for something in ipykernel affects security issue in other projects ?

  • If it's an issue in IPykernel than it's ipykernel problem to backport security patches to say the 6.x branch.
  • If Jupyter Server is still compatible 3.10, or even 3.9 and has a security issue it is not affected by ipykernel. It can use ipykernel 6 on 3.9 and ipykernel 7 on 3.12.

I mean we are not speaking of jupyter_client here – which I agree would have a much bigger impact.

All of the above seem to be all the same point that were made for the "Drop python 2" transition; and the reason requires_python was added:

  • Publishing IPykernel 7.x with python_requires = '>=3.whathever' will just mean that on python 3.whatever and below pip and alike will just install 6.x, it does not force anyone downstream to make any changes, and CI will automatically adapt. And because it's a kernel it should not impact any clients.

when a new critical security issue gets discovered Jupyter maintainers will be asked to backport it to Jupyter versions which support 3.10; we may not have resources to do so and users will have a choice of not using Jupyter or using a vulnerable version

Those are different arguments, and those are imho opinions, I can understand those but:

I find the "weed won't have enough resources" also a double edge swords and also a bit of a straw man argument:

  1. You don't have to match CPython security timeline, that's a choice, you can decide to be shorter, other python projects are shorter. And again here I think that kernel and security are one of the most flexible and with the least attack surface compared to say server/lab or hub.

  2. The more python version you support the more work it is. In my own experience the time I spend fixing CI or writing code that is compatible 3.9 and 3.10 is wayyyy more that the time I spend backporting and working on security fixes. So I'll return it the opposite argument: dropping 3.9 – and 3.10 – will free much more time from maintainers to be able to actually spend time backporting security fixes if needed.

@krassowski
Copy link
Member

Yes, the misunderstanding and my poor points come from an implicit assumption that jupyterlab and other frontends will soon require the latest version of ipykernel. Of course, this does not need to be the case. Maybe my thinking here was biased by the failing downstream tests and this release being not backward compatible.

In two points:

  • yes, JupyterLab may need to expand CI matrix because testing subshells integration (currently done by installing alpha) will no longer be possible on older Python version; not a huge deal on one hand, pretty annoying on the other
  • yes, JupyterLab could decide not to upgrade its pin of ipykernel to ipykernel>=7.0 (currently ipykernel>=6.5). Supporting the smallest range of ipykernel makes life easier for JupyterLab.

I agree someone needs to pay some extra maintenance cost and the decision to be made will just shift it between maintainers of ipykernel/users/maintainers of downstream. Some choices might allow to minimize the total cost.

You don't have to match CPython security timeline, that's a choice, you can decide to be shorter, other python projects are shorter. And again here I think that kernel and security are one of the most flexible and with the least attack surface compared to say server/lab

Of course! I just explained what I thought was likely to happen, in a sense worse case scenario. It does not mean that this is a strong argument, or that I personally think this PR should not be merged, but I find value in exploring these scenarios to understand trade-offs. Spelling it out means others, like you, can correct errors in my reasoning.

@Carreau
Copy link
Member Author

Carreau commented Feb 19, 2025

Yes, the misunderstanding and my poor points come from an implicit assumption that jupyterlab and other frontends will soon require the latest version of ipykernel. Of course, this does not need to be the case. Maybe my thinking here was biased by the failing downstream tests and this release being not backward compatible.

Ah with this assumption I understand, and if JupyterLab wants to pin ipykernel, then I agree with your points.

  • yes, JupyterLab may need to expand CI matrix because testing subshells integration (currently done by installing alpha) will no longer be possible on older Python version; not a huge deal on one hand, pretty annoying on the other

It seem that JupyterLab should anyway test kernels that do and do not support subshells, it's understandable that it's more work.

Now this goes into a slight different direction of JupyterLab and Kernel vertical integration.
Jupyter Frontends tries to be kernel and language agnostic, but is it time to start thinking about tighter integration and make the assumption that the kernel is almost always a Python one.

Like if jupyterlab pins ipykernel, then I also expect older jupyterlab to not support ipykernel>7; in which case this is a vertical integration and we should likely merge back ipykernel and the server code into the same, or have releases in lockstep.

Of course! I just explained what I thought was likely to happen, in a sense worse case scenario. It does not mean that this is a strong argument, or that I personally think this PR should not be merged, but I find value in exploring these scenarios to understand trade-offs. Spelling it out means others, like you, can correct errors in my reasoning.

I understand, and I think 3.10 is on the fence, so I won't push for it.

@ccordoba12
Copy link
Member

ccordoba12 commented Feb 20, 2025

Responding to several comments at the same time:

For what it is worth, I just got annoyed by 3.9, because some_builtin_object|None is invalid at runtime on 3.9, while we use |None everywhere for the rest.

I don't see this as a good enough reason to drop support for 3.9 for users (see my next point).

and I really don't see why something released in 2025 need to support something that was release in 2020.

The problem with dropping old versions is, in my opinion, the impact it has on users that started research projects two or three years ago. At that time Python 3.9 was still relatively recent, so it was a valid choice. And since it takes something between one to three years to publish a paper, you usually don't change your Python env in that time to not risk breaking your code.

You could think that's a bit farfetched, but I'm talking from my own experience here. I finished my PhD a few years ago and I was still using an env I created in 2016 or so for one paper, to get results for another, related paper in 2021! For me it was easier to do that rather than updating the env and dealing with the many minor and major changes in more recent versions of Numpy, Pandas, Matplotlib, Seaborn, NetworkX, etc, that broke my code. But I was able to update Spyder/IPython/IPykernel to get bugfixes for them (of course, their code is, for the most part, orthogonal to the scientific libraries one).

That's why we in Spyder support the last Python version that hasn't reached EOL (I think users understand easily that we can't support versions after their EOL). Furthermore, it's a not big deal for us to do that because we're not a compiled library and, in my opinion, most Python 3.7+ versions are quite similar except for annotations (which we don't use heavily).

There is still the 6.x branch for that.

I think the branches are quite different at this point, so it'd be difficult to do backportings.


The downside is that dropping Python 3.9 will put downstreams in a position where they would need to test against multiple ipykernel versions as
Spyder allows Python 3.8 but tests only on 3.9+ (spyder-ide/spyder#23286)

Actually, we still test on Python 3.8 but only with pip packages and will continue to do so until Spyder 6.1.0 is released (we don't drop support for Python versions in bugfix releases and when we released 6.0, 3.8 hadn't reached EOL).

IPython itself has already dropped 3.10
I find this a bit of a challenge for downstreams

I also agree with @krassowski: being a pure Python package, IPython could still support Python 3.10. I mean, I think NEP 29/SPEC 0 is a good thing for compiled libraries because it reduces the effort of creating wheels for a lot of Python versions. But it's not something pure Python packages should adhere strictly to (even some important compiled libraries such as PyZMQ still support Python 3.8).


Do you mean that downstream may need to have conditional code based on IPykernel version ?
I agree with that, but that's unrelated to IPykernel being 3.8+, 3.10+ or 3.11+, it just depends on whether we have API change in ipykernel.

Sure, but it'd be much easier, for instance, to move to support IPykernel 7 only at some point in the future, and keep supporting Python 3.9. Instead, what we've done in the past is to add workarounds for specific IPykernel versions that added/removed this or that so that we can keep supporting older Python versions.

I mean we are not speaking of jupyter_client here – which I agree would have a much bigger impact.

IPykernel is more important for us than Jupyter client. Our Variable Explorer, debugger, Matplotlib integration and several other features are based on it. But I understand it's different for Jupyter.

The more python version you support the more work it is. In my own experience the time I spend fixing CI or writing code that is compatible 3.9 and 3.10 is wayyyy more that the time I spend backporting and working on security fixes.

Not in my experience, sorry. It's a little bit more work for us, but not something that requires constant attention and many resources (otherwise we were not doing it).

So I'll return it the opposite argument: dropping 3.9 – and 3.10 – will free much more time from maintainers to be able to actually spend time backporting security fixes if needed.

But the main argument you've mentioned so far for dropping Python 3.9 here is a nuisance with annotations. As I said at the beginning, I don't think that's strong enough to justify it.

@Carreau
Copy link
Member Author

Carreau commented Feb 20, 2025

also agree with @krassowski: being a pure Python package, IPython could still support Python 3.10. I mean, I think NEP 29/SPEC 0 is a good thing for compiled libraries because it reduces the effort of creating wheels for a lot of Python versions. But it's not something pure Python packages should adhere strictly to (even some important compiled libraries such as PyZMQ still support Python 3.8).

Well IPython had to deal with many things, worst of which are

  • Changes in tokeniser,
  • variation in AST nodes,
  • variation in bytecode
  • Change in how exceptions are printed (with spacing in and new lines that differ)

Which make the code extremely convoluted to understand and update correctly in all the cases.

Like anything sure I could support it, and the annoyance of sending a pull-request to IPython that pass everywhere – except on 3.10 – and need one more iteration and conditional import and installing typing-extension, and ah no, actually typing extension or typeshed don't have the right types, was regularly taking more time that actual features or fixes.

(to be fair 3.9->3.10 had way less annoying changes than 3.10 -> 3.11)

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

Successfully merging this pull request may close these issues.

5 participants