Skip to content

Commit

Permalink
Drop Python 2.7 support / Require Python 3.10 (#2519)
Browse files Browse the repository at this point in the history
* Drop Python 2.7 support / Require Python 3.10

Only test on Python 3 and bump minimal required python version to 3.10.

* Update CHANGELOG

* Allow to install on Python 3.4

* State intend to not artifially raise the required Python version
  • Loading branch information
peace-maker authored Jan 26, 2025
1 parent e51bc74 commit 6748a78
Show file tree
Hide file tree
Showing 23 changed files with 56 additions and 219 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Thanks for contributing to Pwntools!

When reporting an issue, be sure that you are running the latest released version of pwntools (`pip install --upgrade pwntools`).

Please verify that your issue occurs on 64-bit Ubuntu 14.04. You can use the Dockerfile on `docker.io` for quick testing.
Please verify that your issue occurs on 64-bit Ubuntu 22.04. You can use the Dockerfile on `docker.io` for quick testing.

```
$ docker pull pwntools/pwntools:stable
Expand Down
28 changes: 0 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ jobs:
matrix:
python_version: ['3.10', '3.12']
os: [ubuntu-latest]
include:
- python_version: '2.7'
os: ubuntu-22.04
runs-on: ${{ matrix.os }}
timeout-minutes: 30
services:
Expand Down Expand Up @@ -66,17 +63,8 @@ jobs:
sudo apt-get update && sudo apt-get install -y python3-pip gdb gdbserver
/usr/bin/python -m pip install --break-system-packages rpyc || /usr/bin/python -m pip install rpyc
gdb --batch --quiet --nx --nh --ex 'py import rpyc; print(rpyc.version.version)'
- name: Cache for pip
uses: actions/cache@v4
if: matrix.python_version == '2.7'
with:
path: ~/.cache/pip
key: ${{ matrix.os }}-${{ matrix.python_version }}-cache-pip-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
restore-keys: ${{ matrix.os }}-${{ matrix.python_version }}-cache-pip-
- name: Set up Python ${{ matrix.python_version }}
if: matrix.python_version != '2.7'
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python_version }}
Expand All @@ -85,17 +73,6 @@ jobs:
**/pyproject.toml
**/requirements*.txt
- name: Set up Python 2.7
if: matrix.python_version == '2.7'
run: |
sudo apt-get update
sudo apt-get install -y \
python2.7 python2.7-dev python2-pip-whl
sudo ln -sf python2.7 /usr/bin/python
export PYTHONPATH=`echo /usr/share/python-wheels/pip-*py2*.whl`
sudo --preserve-env=PYTHONPATH python -m pip install --upgrade pip setuptools wheel
sudo chown -R $USER /usr/local/lib/python2.7
- name: Verify tag against version
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
Expand Down Expand Up @@ -155,10 +132,6 @@ jobs:
- name: Install documentation dependencies
run: pip install -r docs/requirements.txt

- name: Manually install non-broken Unicorn
if: matrix.python_version == '2.7'
run: pip install unicorn==2.0.0rc7

- name: Disable yama ptrace_scope
run: |
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope # required by some gdb doctests
Expand Down Expand Up @@ -244,7 +217,6 @@ jobs:
pwn libcdb hash b229d1da1e161f95e839cf90cded5f719e5de308
- name: Build source and wheel distributions
if: matrix.python_version != '2.7'
run: |
python -m build
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,16 @@ The table below shows which release corresponds to each branch, and what date th
| [2.2.0](#220) | | Jan 5, 2015

## 5.0.0 (`dev`)

- [#2519][2519] Drop Python 2.7 support / Require Python 3.10
- [#2507][2507] Add `+LINUX` and `+WINDOWS` doctest options and start proper testing on Windows
- [#2522][2522] Support starting a kitty debugging window with the 'kitten' command
- [#2524][2524] Raise EOFError during `process.recv` when stdout closes on Windows
- [#2526][2526] Properly make use of extra arguments in `packing` utilities. `sign` parameter requires keyword syntax to specify it.
- [#2517][2517] Allow to passthru kwargs on `ssh.__getattr__` convenience function to fix SSH motd problems
- [#2527][2527] Allow setting debugger path via `context.gdb_binary`

[2519]: https://github.com/Gallopsled/pwntools/pull/2519
[2507]: https://github.com/Gallopsled/pwntools/pull/2507
[2522]: https://github.com/Gallopsled/pwntools/pull/2522
[2524]: https://github.com/Gallopsled/pwntools/pull/2524
Expand All @@ -88,6 +91,7 @@ The table below shows which release corresponds to each branch, and what date th
[2527]: https://github.com/Gallopsled/pwntools/pull/2527

## 4.15.0 (`beta`)

- [#2508][2508] Ignore a warning when compiling with asm on nix
- [#2471][2471] Properly close spawned kitty window
- [#2358][2358] Cache output of `asm()`
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ To get you started, we've provided some example solutions for past CTF challenge

# Installation

Pwntools is best supported on 64-bit Ubuntu LTS releases (18.04, 20.04, 22.04, and 24.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).
Pwntools is best supported on 64-bit Ubuntu LTS releases (22.04 and 24.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).

Python3 is suggested, but Pwntools still works with Python 2.7. Most of the functionality of pwntools is self-contained and Python-only. You should be able to get running quickly with
Pwntools supports Python 3.10+ since version 5.0.0. Use Pwntools 4.x for older versions as well as Python 2.7. Most of the functionality of pwntools is self-contained and Python-only. You should be able to get running quickly with

```sh
sudo apt-get update
Expand Down
4 changes: 2 additions & 2 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Pwntools makes extensive use of unit tests and integration tests to ensure every

## Test Suite

To run the test suite, it is best to use Ubuntu 12.04 or 14.04, and run the following commands. **Be aware** that this will add a user to the machine, and create a public key for SSH login!
To run the test suite, it is best to use Ubuntu 22.04 or 24.04, and run the following commands. **Be aware** that this will add a user to the machine, and create a public key for SSH login!

```sh
bash travis/install.sh
Expand All @@ -15,7 +15,7 @@ PWNLIB_NOTERM=1 make -C docs doctest

## Testing in Docker

A `Dockerfile` has been provided which has a clean testing environment with Ubuntu Xenial. It is very similar to the online Travis CI testing environment, but uses a more modern version of Ubuntu.
A `Dockerfile` has been provided which has a clean testing environment with Ubuntu Jammy. It is very similar to the online Github Actions CI testing environment, but uses a more modern version of Ubuntu.

See `travis/docker/README.md` for more information.

Expand Down
9 changes: 3 additions & 6 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@ capstone
coverage[toml]
python-dateutil
doc2dash
docutils<0.18; python_version<'3'
docutils>=0.18; python_version>='3'
docutils>=0.18
intervaltree
isort
mako>=1.0.0
paramiko>=1.15.2
pip>=6.0.8
pyelftools>=0.29, <0.30; python_version<'3'
pyelftools>=0.29; python_version>='3'
pyelftools>=0.29
pygments>=2.0
pypandoc
pyserial>=2.7
pysocks
psutil
requests>=2.5.1
ropgadget>=5.3
sphinx==1.8.6; python_version<'3'
sphinx>=8.1.3, <9; python_version>='3'
sphinx>=8.1.3, <9
sphinx_rtd_theme
sphinxcontrib-autoprogram<=0.1.5
55 changes: 8 additions & 47 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ def __setattr__(self, name, value):
travis_ci = os.environ.get('USER') == 'travis'
local_doctest = os.environ.get('USER') == 'pwntools'
skip_android = True
is_python2 = six.PY2
'''

autoclass_content = 'both'
Expand Down Expand Up @@ -388,16 +387,13 @@ def linkcode_resolve(domain, info):


# -- Customization to Sphinx autodoc generation --------------------------------------------
import sphinx.ext.autodoc

# Test hidden members (e.g. def _foo(...))
def dont_skip_any_doctests(app, what, name, obj, skip, options):
return None

autodoc_default_options = {'special-members': None, 'private-members': None}

class _DummyClass(object): pass

# doctest optionflags for platform-specific tests
# they are skipped on other platforms
WINDOWS = doctest.register_optionflag('WINDOWS')
Expand All @@ -407,33 +403,6 @@ class _DummyClass(object): pass
# doctest optionflag for tests that haven't been looked at yet
TODO = doctest.register_optionflag('TODO')

class Py2OutputChecker(_DummyClass, doctest.OutputChecker):
def check_output(self, want, got, optionflags):
sup = super(Py2OutputChecker, self).check_output
if sup(want, got, optionflags):
return True
try:
rly_want = pwnlib.util.safeeval.const(want)
if sup(repr(rly_want), got, optionflags):
return True
rly_got = pwnlib.util.safeeval.const(got)
if rly_want == rly_got:
return True
except ValueError:
pass
rly_want = ' '.join(x[:2].replace('b"','"').replace("b'","'")+x[2:] for x in want.replace('\n','\n ').split(' ')).replace('\n ','\n')
if sup(rly_want, got, optionflags):
return True
rly_want = ' '.join(x[:2].replace('b"',' "').replace("b'"," '")+x[2:] for x in want.replace('\n','\n ').split(' ')).replace('\n ','\n')
if sup(rly_want, got, optionflags):
return True
for wantl, gotl in six.moves.zip_longest(want.splitlines(), got.splitlines(), fillvalue=''):
rly_want1 = '['.join(x[:2].replace('b"','"').replace("b'","'")+x[2:] for x in wantl.split('['))
rly_want2 = ' '.join(x[:2].replace('b"',' "').replace("b'"," '")+x[2:] for x in wantl.split(' '))
if not sup(rly_want1, gotl, optionflags) and not sup(rly_want2, gotl, optionflags):
return False
return True

import sphinx.ext.doctest

class PlatformDocTestRunner(sphinx.ext.doctest.SphinxDocTestRunner):
Expand Down Expand Up @@ -471,24 +440,16 @@ def test_runner(self):
def test_runner(self, value):
self._test_runner = PlatformDocTestRunner(value._checker, value._verbose, value.optionflags)

def py2_doctest_init(self, checker=None, verbose=None, optionflags=0):
if checker is None:
checker = Py2OutputChecker()
doctest.DocTestRunner.__init__(self, checker, verbose, optionflags)

if 'doctest' in sys.argv:
def setup(app):
app.add_builder(PlatformDocTestBuilder, override=True)
# app.connect('autodoc-skip-member', dont_skip_any_doctests)
# monkey patching paramiko due to https://github.com/paramiko/paramiko/pull/1661
import paramiko.client
import binascii
paramiko.client.hexlify = lambda x: binascii.hexlify(x).decode()
paramiko.util.safe_string = lambda x: '' # function result never *actually used*

if sys.version_info[:1] < (3,):
sphinx.ext.doctest.SphinxDocTestRunner.__init__ = py2_doctest_init
else:
def setup(app):
app.add_builder(PlatformDocTestBuilder, override=True)
# app.connect('autodoc-skip-member', dont_skip_any_doctests)
# monkey patching paramiko due to https://github.com/paramiko/paramiko/pull/1661
import paramiko.client
import binascii
paramiko.client.hexlify = lambda x: binascii.hexlify(x).decode()
paramiko.util.safe_string = lambda x: '' # function result never *actually used*
class EndlessLoop(Exception): pass
if hasattr(signal, 'alarm'):
def alrm_handler(sig, frame):
Expand Down
8 changes: 6 additions & 2 deletions docs/source/install.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Installation
============

Pwntools is best supported on 64-bit Ubuntu LTS releases (14.04, 16.04, 18.04, and 20.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).
Pwntools is best supported on 64-bit Ubuntu LTS releases (22.04 and 24.04). Most functionality should work on any Posix-like distribution (Debian, Arch, FreeBSD, OSX, etc.).

Prerequisites
-------------
Expand All @@ -21,11 +21,13 @@ Note: For Mac OS X you will need to have cmake ``brew install cmake`` and pkg-co
Released Version
-----------------

pwntools is available as a ``pip`` package for both Python2 and Python3.
pwntools is available as a ``pip`` package for Python3. Version v5.0.0 supports Python3.10 or later. Use v4 if you use earlier versions of Python.

Python3
^^^^^^^

The Python version required for installing Pwntools is kept as low as possible on a best-effort basis. However, new features target Python3.10 and later.

.. code-block:: bash
$ sudo apt-get update
Expand All @@ -37,6 +39,8 @@ Python3
Python2 (Deprecated)
^^^^^^^^^^^^^^^^^^^^

Python2 support has been removed in Pwntools v5.0.0. The last version to support Python2 was v4.15.0.

NOTE: Pwntools maintainers STRONGLY recommend using Python3 for all future Pwntools-based scripts and projects.

Additionally, due to `pip` dropping support for Python2, a specfic version of `pip` must be installed.
Expand Down
5 changes: 0 additions & 5 deletions extra/docker/base/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ RUN apt-get update \
git \
libssl-dev \
libffi-dev \
python2.7 \
python2.7-dev \
python2-pip-whl \
python3 \
python3-pip \
python3-dev \
Expand All @@ -40,8 +37,6 @@ RUN apt-get update \
patchelf \
&& locale-gen en_US.UTF-8 \
&& update-locale LANG=en_US.UTF-8 \
&& PYTHONPATH=`echo /usr/share/python-wheels/pip-*.whl` python2.7 -m pip install --no-cache-dir --upgrade pip setuptools wheel \
&& python2.7 -m pip install --no-cache-dir --upgrade pwntools \
&& python3 -m pip install --no-cache-dir --upgrade pip \
&& python3 -m pip install --no-cache-dir --upgrade pwntools \
&& PWNLIB_NOTERM=1 pwn update \
Expand Down
3 changes: 1 addition & 2 deletions extra/docker/beta/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
FROM pwntools/pwntools:stable

USER root
RUN python2.7 -m pip install --no-cache-dir --upgrade git+https://github.com/Gallopsled/pwntools@beta \
&& python3 -m pip install --no-cache-dir --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@beta
RUN python3 -m pip install --no-cache-dir --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@beta
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
8 changes: 0 additions & 8 deletions extra/docker/buster/Dockerfile

This file was deleted.

3 changes: 1 addition & 2 deletions extra/docker/dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
FROM pwntools/pwntools:stable

USER root
RUN python2.7 -m pip install --upgrade git+https://github.com/Gallopsled/pwntools@dev \
&& python3 -m pip install --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@dev
RUN python3 -m pip install --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@dev
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
10 changes: 3 additions & 7 deletions extra/docker/develop/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ ENV HISTFILE=/home/pwntools/.history

# Uninstall existing versions of pwntools
USER root
RUN python2.7 -m pip uninstall -q -y pwntools \
&& python3 -m pip uninstall -q -y pwntools
RUN python3 -m pip uninstall -q -y pwntools

# Switch back to the pwntools user from here forward
USER pwntools
Expand All @@ -18,17 +17,14 @@ ENV PATH="/home/pwntools/.local/bin:${PATH}"

# Install Pwntools to the home directory, make it an editable install
RUN git clone https://github.com/Gallopsled/pwntools \
&& python2.7 -m pip install --upgrade --editable pwntools \
&& python3 -m pip install --upgrade --editable pwntools \
&& PWNLIB_NOTERM=1 pwn version

# Requirements for running the tests
RUN python2.7 -m pip install --upgrade --requirement pwntools/docs/requirements.txt \
&& python3 -m pip install --upgrade --requirement pwntools/docs/requirements.txt
RUN python3 -m pip install --upgrade --requirement pwntools/docs/requirements.txt

# Python niceties for debugging
RUN python2.7 -m pip install -U ipython ipdb \
&& python3 -m pip install -U ipython ipdb
RUN python3 -m pip install -U ipython ipdb

# Dependencies from .travis.yml addons -> apt -> packages
ARG DEBIAN_FRONTEND=noninteractive
Expand Down
3 changes: 1 addition & 2 deletions extra/docker/stable/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
FROM pwntools/pwntools:base

USER root
RUN python2.7 -m pip install --no-cache-dir --upgrade git+https://github.com/Gallopsled/pwntools@stable \
&& python3 -m pip install --no-cache-dir --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@stable
RUN python3 -m pip install --no-cache-dir --force-reinstall --upgrade git+https://github.com/Gallopsled/pwntools@stable
RUN PWNLIB_NOTERM=1 pwn update
USER pwntools
6 changes: 0 additions & 6 deletions pwnlib/gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,9 +587,6 @@ def debug(args, gdbscript=None, gdb_args=None, exe=None, ssh=None, env=None, por
Using GDB Python API:
.. doctest::
:skipif: is_python2
Debug a new process
>>> io = gdb.debug(['echo', 'foo'], api=True)
Expand Down Expand Up @@ -994,9 +991,6 @@ def attach(target, gdbscript = '', exe = None, gdb_args = None, ssh = None, sysr
Using GDB Python API:
.. doctest::
:skipif: is_python2
>>> io = process('bash')
Attach a debugger
Expand Down
Loading

0 comments on commit 6748a78

Please sign in to comment.