diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 1ea274a..00b25ce 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -17,11 +17,12 @@ jobs: strategy: matrix: python-version: - - '3.8' - '3.9' - '3.10' - '3.11' - '3.12' + - '3.13' + - '3.14' - 'pypy-3.9' - 'pypy-3.10' steps: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a640a82..a6378cb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,17 @@ Changelog ========= +Version 0.31.3 (IN DEVELOPMENT) +------------------------------- + +Backward incompatible changes: + +- Dropped support for Python 3.8. + +Enhancements: + +- Added support for Python 3.14. + Version 0.31.3 (2024-07-13) --------------------------- diff --git a/docs/index.rst b/docs/index.rst index ffe657b..780ab16 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,7 +4,7 @@ Dependencies ------------ The `argh` library is supported (and tested unless otherwise specified) -on the following versions of Python: 3.8, 3.9, 3.10, 3.11, 3.12, 3.13. +on the following versions of Python: 3.9, 3.10, 3.11, 3.12, 3.13, 3.14. If you need support for ancient Pythons, please use the following versions of Argh (the numeric puns were semi-intentional): diff --git a/pyproject.toml b/pyproject.toml index 83e4761..3de7fa7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "argh" version = "0.31.3" description = "Plain Python functions as CLI commands without boilerplate" readme = "README.rst" -requires-python = ">=3.8" +requires-python = ">=3.9" license = { file = "COPYING.LESSER" } authors = [ { name = "Andy Mikhaylenko", email = "neithere@gmail.com" }, @@ -31,12 +31,12 @@ classifiers = [ "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: User Interfaces", diff --git a/tests/base.py b/tests/base.py index 7710443..a031f25 100644 --- a/tests/base.py +++ b/tests/base.py @@ -4,8 +4,6 @@ """ import io -import os -import sys from collections import namedtuple from argh import ArghParser @@ -72,8 +70,3 @@ def run(parser, command_string, kwargs=None, exit=False): raise AssertionError("Did not exit") return result.exit_code return result - - -def get_usage_string(definitions="{cmd} ..."): - prog = os.path.basename(sys.argv[0]) - return "usage: " + prog + " [-h] " + definitions + "\n\n" diff --git a/tests/test_integration.py b/tests/test_integration.py index 8839265..6fc8a17 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -17,7 +17,7 @@ from argh.utils import unindent from .base import CmdResult as R -from .base import DebugArghParser, get_usage_string, run +from .base import DebugArghParser, run if sys.version_info < (3, 10): HELP_OPTIONS_LABEL = "optional arguments" @@ -796,11 +796,17 @@ def func(): parser = DebugArghParser() parser.set_default_command(func) - assert unindent(func.__doc__) in parser.format_help() + docstring = func.__doc__ + assert docstring + assert unindent(docstring) in parser.format_help() def test_prog(capsys: pytest.CaptureFixture[str]): - "Program name propagates from sys.argv[0]" + """ + Program name propagates to the usage string. + It's not just sys.argv[0], the logic is a bit more complicated in argparse, + so we just reuse whatever it has produced. + """ def cmd(*, foo=1): return foo @@ -808,10 +814,12 @@ def cmd(*, foo=1): parser = DebugArghParser() parser.add_commands([cmd]) - usage = get_usage_string() + usage = f"usage: {parser.prog} [-h]" - assert run(parser, "-h", exit=True) == 0 + exit_code = run(parser, "-h", exit=True) captured = capsys.readouterr() + + assert exit_code == 0 assert captured.out.startswith(usage) @@ -822,8 +830,6 @@ def cmd(*, foo=1): parser = DebugArghParser() parser.set_default_command(cmd) - get_usage_string("[-f FOO]") - assert run(parser, "--foo 1") == R(out="1\n", err="") assert run(parser, "--bar 1", exit=True) == "unrecognized arguments: --bar 1" assert run(parser, "--bar 1", exit=False, kwargs={"skip_unknown_args": True}) == R( diff --git a/tests/test_mapping_policies.py b/tests/test_mapping_policies.py index e77e122..b704733 100644 --- a/tests/test_mapping_policies.py +++ b/tests/test_mapping_policies.py @@ -1,4 +1,3 @@ -import sys from argparse import ArgumentParser, Namespace from typing import Callable, List, Optional @@ -75,11 +74,6 @@ def func(*file_paths) -> str: parser = _make_parser_for_function(func, name_mapping_policy=name_mapping_policy) expected_usage = "usage: test [-h] [file-paths ...]" - # TODO: remove once we drop support for Python 3.8 - if sys.version_info < (3, 9): - # https://github.com/python/cpython/issues/82619 - expected_usage = "usage: test [-h] [file-paths [file-paths ...]]" - assert_usage(parser, expected_usage) diff --git a/tox.ini b/tox.ini index 52615c0..afab154 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,12 @@ [tox] envlist = - py38 py39 py310 py311 py312 py313 + py314 pypy3 - as-module lint docs skipdist = true @@ -17,12 +16,12 @@ skip_missing_interpreters = true [gh-actions] # https://github.com/ymyzk/tox-gh-actions python = - 3.8: py38 3.9: py39 3.10: py310 3.11: py311,lint,as-module 3.12: py312 3.13: py313 + 3.14: py314 pypy-3.9: pypy3 pypy-3.10: pypy3 @@ -30,15 +29,10 @@ python = description = run unit tests extras = test commands = - pytest --cov=argh --cov-report html --cov-fail-under 100 {posargs:tests} + python -m pytest --cov=argh --cov-report html --cov-fail-under 100 {posargs:tests} setenv = PYTHONPATH=src -[testenv:as-module] -description = run unit tests, ensure they don't depend on specific prog name -commands = - python -m pytest {posargs:tests} - [testenv:docs] description = build the HTML docs using sphinx-build extras = docs