Skip to content

Commit

Permalink
Drop Python 2.7 support (#2481)
Browse files Browse the repository at this point in the history
About dropping Python 2.7 support, 3 years ago [I stated](#2014 (comment)):

>  [...] not a chance, for many years to come. [Python 2.7] currently represents 7-10% of total downloads, aka around 70k /100k downloads per day

3 years later (and to my surprise) **downloads for Python 2.7 dropped to 0.36%**. These are downloads per month:

```
$ pypinfo --percent psutil pyversion
Served from cache: False
Data processed: 4.65 GiB
Data billed: 4.65 GiB
Estimated cost: $0.03

| python_version | percent | download_count |
| -------------- | ------- | -------------- |
| 3.10           |  23.84% |     26,354,506 |
| 3.8            |  18.87% |     20,862,015 |
| 3.7            |  17.38% |     19,217,960 |
| 3.9            |  17.00% |     18,798,843 |
| 3.11           |  13.63% |     15,066,706 |
| 3.12           |   7.01% |      7,754,751 |
| 3.13           |   1.15% |      1,267,008 |
| 3.6            |   0.73% |        803,189 |
| 2.7            |   0.36% |        402,111 |
| 3.5            |   0.03% |         28,656 |
| Total          |         |    110,555,745 |
```

According to [pypistats.org](https://archive.is/wip/knzql) it's 0.28% of the total, and around 15.000 downloads per day.

Maintaining 2.7 support has become increasingly difficult, but still possible. E.g. we can still run tests by using [old PYPI backports](https://github.com/giampaolo/psutil/blob/fbb6d9ce98f930d3d101b7df5a4f4d0f1d2b35a3/setup.py#L76-L85). GitHub Actions can still be [tweaked](https://github.com/giampaolo/psutil/blob/fbb6d9ce98f930d3d101b7df5a4f4d0f1d2b35a3/.github/workflows/build.yml#L77-L112) to run tests and produce wheels on Linux and macOS. Not Windows though, for which we have to use a separate service (Appveyor). 

Still, the amount of hacks in psutil source code necessary to support Python 2.7 piled up over the years, and became quite big. Some disadvantages that come to mind:

* (high) having to maintain various python compatibility layers (e.g. [psutil/_compat.py](https://github.com/giampaolo/psutil/blob/fbb6d9ce98f930d3d101b7df5a4f4d0f1d2b35a3/psutil/_compat.py#L1)) + all the compromises that come with it (extra imports, extra code, str vs. unicode differences, etc.)
* (medium) having to maintain a C compatibility layer (`#if PY_MAJOR_VERSION <= 3`, etc.)
* (medium) inability to use modern language features, especially f-strings
* (low) inability to freely use `enum`s, which creates a difference on how CONSTANTS are exposed in terms of API
* (medium) having to install a specific version of pip and other (outdated) [deps](https://github.com/giampaolo/psutil/blob/fbb6d9ce98f930d3d101b7df5a4f4d0f1d2b35a3/setup.py#L76-L85)
* (high) relying on third-party Appveyor CI service, just to run tests on python 2.7 and produce wheels, when we could rely on a single CI service instead (GitHub)
  * (high) soon I want to distribute wheels via GitHub instead of manually via `twine`, so that'll be a problem (CC @potiuk)
* (high) gradual lack of support from third-party libraries and services
* (medium) 4 extra CI jobs which are run on every commit (Linux, macOS, Windows 32-bit, Windows 64-bit) 
* (medium) the distribution of 7 wheels specific for Python 2.7. From last release: 
  * psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl
  * psutil-6.1.1-cp27-none-win32.whl
  * psutil-6.1.1-cp27-none-win_amd64.whl
  * psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl                                                                          
  * psutil-6.1.1-cp27-cp27m-manylinux2010_x86_64.whl                                                                        
  * psutil-6.1.1-cp27-cp27mu-manylinux2010_i686.whl                                                                         
  * psutil-6.1.1-cp27-cp27mu-manylinux2010_x86_64.whl                                                                       
* etc. 

As such I decided to finally **drop support for Python 2.7**. Current psutil 6.1.1 release will still support Python 2.7, but next 7.0.0 will not. 

We can still make a promise that the 6.1.* line (EDIT: see [python2 branch](https://github.com/giampaolo/psutil/tree/python2)) will keep supporting Python 2.7 and will **receive critical bug-fixes only** (no new features).

In 7.0.0 we can keep the [setup.py](https://github.com/giampaolo/psutil/blob/fbb6d9ce98f930d3d101b7df5a4f4d0f1d2b35a3/setup.py) script compatible with Python 2.7 in terms of syntax, so that it can emit an informative error message on pip install. E.g. the user  will see something like this:

```
$ pip2 install psutil
As of version 7.0.0 psutil no longer supports Python 2.7. 
Latest version supporting Python 2.7 is psutil 6.1.X.  
Install it with: "pip2 install psutil==6.1.*".
```

Related tickets:
* 2017-06: #1053
* 2022-04: #2099
* 2023-04: #2246
* giampaolo/pyftpdlib#635
  • Loading branch information
giampaolo authored Dec 20, 2024
1 parent fbb6d9c commit e957628
Show file tree
Hide file tree
Showing 80 changed files with 709 additions and 2,291 deletions.
57 changes: 17 additions & 40 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Runs CI tests and generates wheels on the following platforms:
#
# * Linux (py2 and py3)
# * macOS (py2 and py3)
# * Windows (py3, py2 is done by appveyor)
# * Linux
# * macOS
# * Windows
#
# Useful URLs:
# * https://github.com/pypa/cibuildwheel
Expand All @@ -16,9 +15,10 @@ concurrency:
group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.sha || '' }}
cancel-in-progress: true
jobs:
# Linux + macOS + Windows Python 3
py3:
name: "py3, ${{ matrix.os }}, ${{ matrix.arch }}"

# Run tests on Linux, macOS, Windows
tests:
name: "tests, ${{ matrix.os }}, ${{ matrix.arch }}"
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
Expand Down Expand Up @@ -64,7 +64,7 @@ jobs:
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-py3-${{ matrix.os }}-${{ matrix.arch }}
name: wheels-${{ matrix.os }}-${{ matrix.arch }}
path: wheelhouse

- name: Generate .tar.gz
Expand All @@ -74,42 +74,19 @@ jobs:
python setup.py sdist
mv dist/psutil*.tar.gz wheelhouse/
# Linux + macOS + Python 2
py2:
name: py2, ${{ matrix.os }}
runs-on: ${{ matrix.os }}
# Test python 2.7 fallback installation message produced by setup.py
py2-fallback:
name: py2.7 setup.py check
runs-on: ubuntu-24.04
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-13]
env:
CIBW_BUILD: 'cp27-*'
CIBW_TEST_EXTRAS: test
CIBW_TEST_COMMAND:
make -C {project} PYTHON="env python" PSUTIL_SCRIPTS_DIR="{project}/scripts" install-sysdeps install-pydeps-test install print-sysinfo test test-memleaks

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.9

- name: Create wheels + run tests
uses: pypa/cibuildwheel@v1.12.0

- name: Upload wheels
uses: actions/upload-artifact@v4
- uses: LizardByte/setup-python-action@master
with:
name: wheels-py2-${{ matrix.os }}
path: wheelhouse

- name: Generate .tar.gz
if: matrix.os == 'ubuntu-latest'
run: |
make generate-manifest
python setup.py sdist
mv dist/psutil*.tar.gz wheelhouse/
python-version: '2.7'
- run: python scripts/internal/test_python2_setup_py.py

# Run linters
linters:
Expand All @@ -124,9 +101,9 @@ jobs:
python3 -m pip install ruff black rstcheck toml-sort sphinx
make lint-all
# upload weels as a single artefact
# Produce wheels as artifacts.
upload-wheels:
needs: [py2, py3]
needs: [tests]
runs-on: ubuntu-latest
steps:
- uses: actions/upload-artifact/merge@v4
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
on the situation.
"""

from __future__ import print_function

import functools
import json
Expand Down Expand Up @@ -42,7 +41,7 @@
"windows", "win32", "WinError", "WindowsError", "win10", "win7",
"win ", "mingw", "msys", "studio", "microsoft", "make.bat",
"CloseHandle", "GetLastError", "NtQuery", "DLL", "MSVC", "TCHAR",
"WCHAR", ".bat", "OpenProcess", "TerminateProcess", "appveyor",
"WCHAR", ".bat", "OpenProcess", "TerminateProcess",
"windows error", "NtWow64", "NTSTATUS", "Visual Studio",
],
"macos": [
Expand Down Expand Up @@ -89,7 +88,7 @@
],
# tests
"tests": [
" test ", "tests", "travis", "coverage", "cirrus", "appveyor",
" test ", "tests", "travis", "coverage", "cirrus",
"continuous integration", "unittest", "pytest", "unit test",
],
# critical errors
Expand Down
14 changes: 14 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
*Bug tracker at https://github.com/giampaolo/psutil/issues*

7.0.0 (IN DEVELOPMENT)
======================

XXXX-XX-XX

**Enhancements**

- 2480_: Dropped Python 2.7 support.

**Compatibility notes**

- 2480_: Python 2.7 is no longer supported. Latest version supporting Python
2.7 is psutil 6.1.X. Install it with: ``pip2 install psutil==6.1.*``.

6.1.1
=====

Expand Down
1 change: 0 additions & 1 deletion INSTALL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ Troubleshooting
Install pip
-----------

Pip is shipped by default with Python 2.7.9+ and 3.4+.
If you don't have pip you can install it with wget::

wget https://bootstrap.pypa.io/get-pip.py -O - | python3
Expand Down
6 changes: 2 additions & 4 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ include docs/requirements.txt
include make.bat
include psutil/__init__.py
include psutil/_common.py
include psutil/_compat.py
include psutil/_psaix.py
include psutil/_psbsd.py
include psutil/_pslinux.py
Expand Down Expand Up @@ -177,14 +176,12 @@ include scripts/fans.py
include scripts/free.py
include scripts/ifconfig.py
include scripts/internal/README
include scripts/internal/appveyor_run_with_compiler.cmd
include scripts/internal/bench_oneshot.py
include scripts/internal/bench_oneshot_2.py
include scripts/internal/check_broken_links.py
include scripts/internal/clinter.py
include scripts/internal/convert_readme.py
include scripts/internal/download_wheels_appveyor.py
include scripts/internal/download_wheels_github.py
include scripts/internal/download_wheels.py
include scripts/internal/generate_manifest.py
include scripts/internal/git_pre_commit.py
include scripts/internal/install-sysdeps.sh
Expand All @@ -197,6 +194,7 @@ include scripts/internal/print_downloads.py
include scripts/internal/print_hashes.py
include scripts/internal/print_timeline.py
include scripts/internal/purge_installation.py
include scripts/internal/test_python2_setup_py.py
include scripts/internal/winmake.py
include scripts/iotop.py
include scripts/killall.py
Expand Down
21 changes: 5 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@
PYTHON = python3
ARGS =

# "python3 setup.py build" can be parallelized on Python >= 3.6.
SETUP_BUILD_EXT_ARGS = `$(PYTHON) -c \
"import sys, os; \
py36 = sys.version_info[:2] >= (3, 6); \
cpus = os.cpu_count() or 1 if py36 else 1; \
print('--parallel %s' % cpus if cpus > 1 else '')"`

# In not in a virtualenv, add --user options for install commands.
SETUP_INSTALL_ARGS = `$(PYTHON) -c \
"import sys; print('' if hasattr(sys, 'real_prefix') or hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix else '--user')"`
Expand Down Expand Up @@ -55,14 +48,15 @@ clean: ## Remove all build files.
dist/ \
docs/_build/ \
htmlcov/ \
pytest-cache* \
wheelhouse

.PHONY: build
build: ## Compile (in parallel) without installing.
@# "build_ext -i" copies compiled *.so files in ./psutil directory in order
@# to allow "import psutil" when using the interactive interpreter from
@# within this directory.
$(PYTHON_ENV_VARS) $(PYTHON) setup.py build_ext -i $(SETUP_BUILD_EXT_ARGS)
$(PYTHON_ENV_VARS) $(PYTHON) setup.py build_ext -i --parallel 4
$(PYTHON_ENV_VARS) $(PYTHON) -c "import psutil" # make sure it actually worked

install: ## Install this package as current user in "edit" mode.
Expand Down Expand Up @@ -224,12 +218,8 @@ sdist: ## Create tar.gz source distribution.
${MAKE} generate-manifest
$(PYTHON_ENV_VARS) $(PYTHON) setup.py sdist

download-wheels-github: ## Download latest wheels hosted on github.
$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/download_wheels_github.py --tokenfile=~/.github.token
${MAKE} print-dist

download-wheels-appveyor: ## Download latest wheels hosted on appveyor.
$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/download_wheels_appveyor.py
download-wheels: ## Download latest wheels hosted on github.
$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/download_wheels.py --tokenfile=~/.github.token
${MAKE} print-dist

create-wheels: ## Create .whl files
Expand Down Expand Up @@ -265,8 +255,7 @@ pre-release: ## Check if we're ready to produce a new release.
assert ver in doc, '%r not found in docs/index.rst' % ver; \
assert ver in history, '%r not found in HISTORY.rst' % ver; \
assert 'XXXX' not in history, 'XXXX found in HISTORY.rst';"
${MAKE} download-wheels-github
${MAKE} download-wheels-appveyor
${MAKE} download-wheels
${MAKE} check-wheels
${MAKE} print-hashes
${MAKE} print-dist
Expand Down
11 changes: 4 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
| |downloads| |stars| |forks| |contributors| |coverage|
| |version| |py-versions| |packages| |license|
| |github-actions-wheels| |github-actions-bsd| |appveyor| |doc| |twitter| |tidelift|
| |github-actions-wheels| |github-actions-bsd| |doc| |twitter| |tidelift|
.. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg
:target: https://pepy.tech/project/psutil
Expand All @@ -26,10 +26,6 @@
:target: https://github.com/giampaolo/psutil/actions?query=workflow%3Absd-tests
:alt: FreeBSD, NetBSD, OpenBSD

.. |appveyor| image:: https://img.shields.io/appveyor/build/giampaolo/psutil/master.svg?maxAge=3600&label=Windows%20(py2)
:target: https://ci.appveyor.com/project/giampaolo/psutil
:alt: Windows (Appveyor)

.. |coverage| image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
:alt: Test coverage (coverall.io)
Expand Down Expand Up @@ -98,8 +94,9 @@ psutil currently supports the following platforms:
- **Sun Solaris**
- **AIX**

Supported Python versions are **2.7**, **3.6+** and
`PyPy <http://pypy.org/>`__.
Supported Python versions are cPython 3.6+ and `PyPy <https://pypy.org/>`__.
Latest psutil version supporting Python 2.7 is
`psutil 6.1.1 <https://pypi.org/project/psutil/6.1.1/>`__.

Funding
=======
Expand Down
83 changes: 0 additions & 83 deletions appveyor.yml

This file was deleted.

2 changes: 0 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
Expand Down
18 changes: 15 additions & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ CPU

.. function:: cpu_count(logical=True)

Return the number of logical CPUs in the system (same as `os.cpu_count`_
in Python 3.4) or ``None`` if undetermined.
Return the number of logical CPUs in the system (same as `os.cpu_count`_)
or ``None`` if undetermined.
"logical CPUs" means the number of physical cores multiplied by the number
of threads that can run on each core (this is known as Hyper Threading).
If *logical* is ``False`` return the number of physical cores only, or
Expand Down Expand Up @@ -1203,7 +1203,7 @@ Process class

>>> import psutil
>>> psutil.Process().exe()
'/usr/bin/python2.7'
'/usr/bin/python3'

.. method:: cmdline()

Expand Down Expand Up @@ -2637,6 +2637,18 @@ On Windows:
set PSUTIL_DEBUG=1 python.exe script.py
psutil-debug [psutil/arch/windows/proc.c:90]> NtWow64ReadVirtualMemory64(pbi64.PebBaseAddress) -> 998 (Unknown error) (ignored)

Python 2.7
==========

Latest version spporting Python 2.7 is `psutil 6.1.1 <https://pypi.org/project/psutil/6.1.1/>`__.
The 6.1.X serie may receive critical bug-fixes but no new features. It will
be maintained in the dedicated
`python2 <https://github.com/giampaolo/psutil/tree/python2>`__ branch.
To install it:

::

$ python2 -m pip install psutil==6.1.*

Security
========
Expand Down
Loading

0 comments on commit e957628

Please sign in to comment.