Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -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)
---------------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand All @@ -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",
Expand Down
7 changes: 0 additions & 7 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
"""

import io
import os
import sys
from collections import namedtuple

from argh import ArghParser
Expand Down Expand Up @@ -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"
20 changes: 13 additions & 7 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -796,22 +796,30 @@ 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

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)


Expand All @@ -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(
Expand Down
6 changes: 0 additions & 6 deletions tests/test_mapping_policies.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import sys
from argparse import ArgumentParser, Namespace
from typing import Callable, List, Optional

Expand Down Expand Up @@ -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)


Expand Down
12 changes: 3 additions & 9 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
[tox]
envlist =
py38
py39
py310
py311
py312
py313
py314
pypy3
as-module
lint
docs
skipdist = true
Expand All @@ -17,28 +16,23 @@ 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

[testenv]
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
Expand Down
Loading