├── .github └── workflows │ ├── lint.yml │ └── test.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── all.html ├── build.sh ├── crontask.sh ├── deploy.sh ├── favicon.ico ├── generate.py ├── history-requirements.txt ├── history_get.py ├── history_plot.py ├── index.html ├── package.json ├── pyproject.toml ├── requirements.txt ├── run.sh ├── style.css ├── svg_wheel.py ├── template.py ├── template └── index.html ├── test_utils.py ├── update.sh ├── utils.py └── wheel.css /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | env: 6 | FORCE_COLOR: 1 7 | PIP_DISABLE_PIP_VERSION_CHECK: 1 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: actions/setup-python@v5 19 | with: 20 | python-version: "3.x" 21 | cache: pip 22 | - uses: pre-commit/action@v3.0.1 23 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | permissions: 6 | contents: read 7 | 8 | env: 9 | FORCE_COLOR: 1 10 | 11 | jobs: 12 | test: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | python-version: ["pypy3.10", "3.9", "3.10", "3.11", "3.12", "3.13"] 18 | os: [ubuntu-latest] 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 0 24 | 25 | - name: Set up Python ${{ matrix.python-version }} 26 | uses: actions/setup-python@v5 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | allow-prereleases: true 30 | cache: pip 31 | cache-dependency-path: | 32 | .github/workflows/test.yml 33 | requirements.txt 34 | 35 | - name: Set up node 36 | uses: actions/setup-node@v4 37 | with: 38 | node-version: 16 39 | cache: 'npm' 40 | cache-dependency-path: ".github/workflows/test.yml" 41 | 42 | - name: Install dependencies 43 | run: | 44 | python -m pip install -U pip 45 | python -m pip install -U wheel 46 | python -m pip install -Ur requirements.txt --prefer-binary 47 | npm install svgexport 48 | 49 | - name: Unit tests 50 | run: | 51 | python test_utils.py 52 | 53 | - name: Test run 54 | run: | 55 | ./build.sh 56 | 57 | - name: History charts 58 | run: | 59 | git config remote.origin.fetch +refs/heads/*:refs/remotes/origin/* 60 | git fetch origin 61 | python history_get.py -n 10 62 | python history_plot.py 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | node_modules 3 | 4 | # Generated files 5 | history.jsonl 6 | history.png 7 | python-eol.json 8 | requests-cache.sqlite 9 | results*.json 10 | top-pypi-packages.json 11 | wheel*.png 12 | wheel*.svg 13 | 14 | # Build dir 15 | build 16 | 17 | # IDE 18 | .idea 19 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/astral-sh/ruff-pre-commit 3 | rev: v0.11.4 4 | hooks: 5 | - id: ruff 6 | args: [--exit-non-zero-on-fix] 7 | 8 | - repo: https://github.com/psf/black-pre-commit-mirror 9 | rev: 25.1.0 10 | hooks: 11 | - id: black 12 | 13 | - repo: https://github.com/pre-commit/pre-commit-hooks 14 | rev: v5.0.0 15 | hooks: 16 | - id: check-added-large-files 17 | - id: check-case-conflict 18 | - id: check-merge-conflict 19 | - id: check-json 20 | - id: check-toml 21 | - id: check-yaml 22 | - id: debug-statements 23 | - id: end-of-file-fixer 24 | - id: forbid-submodules 25 | - id: requirements-txt-fixer 26 | - id: trailing-whitespace 27 | 28 | - repo: https://github.com/python-jsonschema/check-jsonschema 29 | rev: 0.32.1 30 | hooks: 31 | - id: check-github-workflows 32 | 33 | - repo: https://github.com/rhysd/actionlint 34 | rev: v1.7.7 35 | hooks: 36 | - id: actionlint 37 | 38 | - repo: https://github.com/tox-dev/pyproject-fmt 39 | rev: v2.5.1 40 | hooks: 41 | - id: pyproject-fmt 42 | 43 | - repo: https://github.com/abravalheri/validate-pyproject 44 | rev: v0.24.1 45 | hooks: 46 | - id: validate-pyproject 47 | - repo: meta 48 | hooks: 49 | - id: check-hooks-apply 50 | - id: check-useless-excludes 51 | 52 | ci: 53 | autoupdate_schedule: quarterly 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Charlie Denton 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Drop Python 2 | 3 | [](https://github.com/hugovk/drop-python/actions/workflows/test.yml) 4 | [](https://github.com/psf/black) 5 | 6 | It's about time to drop support for old Pythons. 7 | 8 | ## How to use 9 | 10 | ```bash 11 | usage: generate.py [-h] [-n NUMBER] [-v VERSION [VERSION ...]] 12 | 13 | Generate 14 | 15 | optional arguments: 16 | -h, --help show this help message and exit 17 | -n NUMBER, --number NUMBER 18 | Number of packages to chart (default: 360) 19 | -v VERSION [VERSION ...], --version VERSION [VERSION ...] 20 | Python version or versions to check (default: ['2.6', 21 | '3.2', '3.3']) 22 | ``` 23 | 24 | For example: 25 | ```bash 26 | $ python3 generate.py 27 | 28 | $ python3 generate.py -v 3.2 -n 100 29 | 30 | $ python3 generate.py -v 2.6 31 | ``` 32 | See also `build.sh`. 33 | 34 | Gets list of packages from [Top PyPI Packages](https://hugovk.github.io/top-pypi-packages/). 35 | 36 | ## How to test locally 37 | 38 | In another terminal: 39 | ```bash 40 | $ python3 -m http.server 8000 41 | ``` 42 | 43 | Then visit http://localhost:8000/ 44 | 45 | ## How to deploy 46 | 47 | Make sure we're on `main` and run `crontask.sh` daily from cron. 48 | 49 | ## Thanks 50 | 51 | This is derivative work from [Python Wheels](https://pythonwheels.com), a site that tracks progress in the new Python package distribution standard called [Wheels](https://pypi.org/project/wheel). Thanks also to [Python 3 Wall of Superpowers](https://python3wos.appspot.com/) for the concept and making their code open source, and see also [Python 3 Readiness](http://py3readiness.org). 52 | -------------------------------------------------------------------------------- /all.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |Old Python versions have reached end of life. It's about time to drop support for them.
99 | 100 |This site shows the top 360 most-downloaded packages on PyPI showing which have dropped support for a Python version.
101 |Packages that are backports (for example, enum34) or known to be deprecated are not included (for example, distribute). If your package is incorrectly listed, please create a ticket.
106 |This is not an official website, just a nice visual way to measure progress. To see the authoritative guide on wheels and other aspects of python packaging, see the Python Packaging User Guide.
107 | 108 |Fantastic, a problem found is a problem fixed. Please create a ticket!
113 |You can also submit a pull request.
114 |Thanks to Python Wheels and Python 3 Wall of Superpowers for the concept and making their code open source.
116 | 117 |Old Python versions have reached end of life. It's about time to drop support for them.
47 | 48 |This site shows the top 360 most-downloaded packages on PyPI (source) showing which have dropped support for a Python version.
49 |Packages that are backports (for example, enum34) or known to be deprecated are not included (for example, distribute). If your package is incorrectly listed, please create a ticket.
54 |See them all.
55 |This is not an official website, just a nice visual way to measure progress. To see the authoritative guide on wheels and other aspects of python packaging, see the Python Packaging User Guide.
56 | 57 |Fantastic, a problem found is a problem fixed. Please create a ticket!
59 |You can also submit a pull request.
60 |Thanks to Python Wheels and Python 3 Wall of Superpowers for the concept and making their code open source.
62 | 63 |For example, no need to install or import unittest2 any more. This:
28 |29 | try: 30 | import unittest2 as unittest # Python 2.6 31 | except ImportError: 32 | import unittest33 |
…can be replaced with: 34 |
35 | import unittest36 | """, # noqa: E501 37 | "new_features": """ 38 |
See what's new. For example: 40 | 41 |
Use set literals:
43 |44 | set([1, 2, 3]) # This can be replaced... 45 | {1, 2, 3} # ... with this46 | 47 |
Update string formatters:
48 |49 | # These can be replaced... 50 | '%s %s' % ('one', 'two') 51 | '{1} {2}'.format('one', 'two') 52 | 53 | # ... with this 54 | '{} {}'.format('one', 'two')55 | 56 |
OrderedDict
and Counter
from collections
57 | Follow this guide: https://python3statement.org/practicalities/ 69 | """, 70 | }, 71 | "3.0": {"template_eol": "27 June 2009"}, 72 | "3.1": {"template_eol": "9 April 2012"}, 73 | "3.2": {"template_eol": "27 February 2016"}, 74 | "3.3": { 75 | "reasons": """ 76 |
breakpoint()
list
and dict
for type annotationsmatch
statement and write union types as X | Y
Python $template_version reached the end of its life on $template_eol. It's about time to drop support for Python $template_version.
27 |This site shows the top 360 most-downloaded packages on PyPI (source) showing which have dropped support for Python $template_version.
33 |Packages that are backports (for example, enum34) or known to be deprecated are not included (for example, distribute). If your package is incorrectly listed, please create a ticket.
38 |This is not an official website, just a nice visual way to measure progress. To see the authoritative guide on wheels and other aspects of python packaging, see the Python Packaging User Guide.
39 |Remove the Trove classifier from setup.py.
42 |43 | 'Programming Language :: Python :: $template_version'44 | 45 |
Remove Python $template_version from your CI. For example Travis CI's .travis.yml:
47 |48 | python: 49 | - $template_version50 |
And for example from Appveyor's appveyor.yml: 51 |
52 | C:\Python${template_major}${template_minor} 53 | C:\Python${template_major}${template_minor}-x6454 |
And tox.ini: 55 |
56 | envlist=py${template_major}${template_minor}57 | 58 |
Remove old Python $template_version-specific code and documentation. Common files to check: 60 |
Search your code for stuff like: 71 |
72 | if sys.version_info < ($template_major, $template_next_minor): 73 | # Python $template_version stuff 74 | 75 | if platform.python_version == "$template_version": 76 | # Python $template_version stuff 77 | 78 | ver = platform.python_version_tuple() 79 | if float('{0}.{1}'.format(*ver[:2])) < $template_next_version: 80 | # Python $template_version stuff 81 | 82 | try: 83 | # Python $template_version 84 | import something 85 | except ImportError: 86 | # Python $template_next_version+ 87 | import something_else 88 | 89 | // In C code 90 | #if PY_VERSION_HEX < 0x0${template_major}0${template_next_minor}0000 91 | -#endif 92 |93 | 94 |
Also search for $template_version
and ${template_major}${template_minor}
.
95 |
96 |
If you test with coverage, look for code which was tested before removing $template_version from your CI. 97 | 98 |
Finally, consider dropping support for Python 2.6 and 3.3, which reached EOL on 2013-10-29 and 2017-09-29 respectively. 99 | 100 | $template_new_features 101 | 102 |
Fantastic, a problem found is a problem fixed. Please create a ticket!
104 |You can also submit a pull request.
105 |Thanks to Python Wheels and Python 3 Wall of Superpowers for the concept and making their code open source.
107 |