Skip to content

Commit eb22039

Browse files
authored
Merge pull request #244 from sandialabs/15-drop-support-for-python-3.8
chore!: Drop support for Python 3.8
2 parents 65aa685 + 5c448ec commit eb22039

File tree

6 files changed

+40
-70
lines changed

6 files changed

+40
-70
lines changed

.github/workflows/continuous-integration.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
runs-on: ubuntu-latest
2020
strategy:
2121
matrix:
22-
version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
22+
version: ["3.9", "3.10", "3.11", "3.12"]
2323
steps:
2424

2525
- name: Harden Runner

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
[![pre-commit.ci Status](https://results.pre-commit.ci/badge/github/sandialabs/reverse_argparse/master.svg)](https://results.pre-commit.ci/latest/github/sandialabs/reverse_argparse/master)
1818
[![PyPI - Version](https://img.shields.io/pypi/v/reverse-argparse?label=PyPI)](https://pypi.org/project/reverse-argparse/)
1919
![PyPI - Downloads](https://img.shields.io/pypi/dm/reverse-argparse?label=PyPI%20downloads)
20-
![Python Version](https://img.shields.io/badge/Python-3.8|3.9|3.10|3.11|3.12-blue.svg)
20+
![Python Version](https://img.shields.io/badge/Python-3.9|3.10|3.11|3.12-blue.svg)
2121
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
2222

2323
# reverse_argparse

doc/source/index.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ reverse_argparse
6666
.. |PyPI Version| image:: https://img.shields.io/pypi/v/reverse-argparse?label=PyPI
6767
:target: https://pypi.org/project/reverse-argparse/
6868
.. |PyPI Downloads| image:: https://img.shields.io/pypi/dm/reverse-argparse?label=PyPI%20downloads
69-
.. |Python Version| image:: https://img.shields.io/badge/Python-3.8|3.9|3.10|3.11|3.12-blue.svg
69+
.. |Python Version| image:: https://img.shields.io/badge/Python-3.9|3.10|3.11|3.12-blue.svg
7070
.. |Ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
7171
:target: https://github.com/astral-sh/ruff
7272

pyproject.toml

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ classifiers = [
2525
"Operating System :: OS Independent",
2626
"Programming Language :: Python :: 3",
2727
"Programming Language :: Python :: 3 :: Only",
28-
"Programming Language :: Python :: 3.8",
2928
"Programming Language :: Python :: 3.9",
3029
"Programming Language :: Python :: 3.10",
3130
"Programming Language :: Python :: 3.11",

reverse_argparse/reverse_argparse.py

+9-14
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@
1414
# SPDX-License-Identifier: BSD-3-Clause
1515

1616
import re
17-
import sys
1817
from argparse import SUPPRESS, Action, ArgumentParser, Namespace
19-
from typing import List, Sequence
18+
from typing import Sequence
2019

2120

22-
BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION = 9
2321
SHORT_OPTION_LENGTH = 2
2422

2523

@@ -38,20 +36,20 @@ class ReverseArgumentParser:
3836
such that they're able to reproduce a prior run of a script exactly.
3937
4038
Attributes:
41-
_args (List[str]): The list of arguments corresponding to each
39+
_args (list[str]): The list of arguments corresponding to each
4240
:class:`argparse.Action` in the given parser, which is built
4341
up as the arguments are unparsed.
4442
_indent (int): The number of spaces with which to indent
4543
subsequent lines when pretty-printing the effective command
4644
line invocation.
4745
_namespace (Namespace): The parsed arguments.
48-
_parsers (List[argparse.ArgumentParser]): The parser that was
46+
_parsers (list[argparse.ArgumentParser]): The parser that was
4947
used to generate the parsed arguments. This is a ``list``
5048
(conceptually a stack) to allow for sub-parsers, so the
5149
outer-most parser is the first item in the list, and
5250
sub-parsers are pushed onto and popped off of the stack as
5351
they are processed.
54-
_unparsed (List[bool]): A list in which the elements indicate
52+
_unparsed (list[bool]): A list in which the elements indicate
5553
whether the corresponding parser in :attr:`parsers` has been
5654
unparsed.
5755
"""
@@ -136,10 +134,7 @@ def _unparse_action(self, action: Action) -> None: # noqa: C901, PLR0912
136134
self._unparse_sub_parsers_action(action)
137135
elif action_type == "_VersionAction": # pragma: no cover
138136
return
139-
elif (
140-
action_type == "BooleanOptionalAction"
141-
and sys.version_info.minor >= BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION
142-
):
137+
elif action_type == "BooleanOptionalAction":
143138
self._unparse_boolean_optional_action(action)
144139
else: # pragma: no cover
145140
message = (
@@ -202,7 +197,7 @@ def get_pretty_command_line_invocation(self) -> str:
202197

203198
def _get_long_option_strings(
204199
self, option_strings: Sequence[str]
205-
) -> List[str]:
200+
) -> list[str]:
206201
"""
207202
Get the long options from a list of options strings.
208203
@@ -224,7 +219,7 @@ def _get_long_option_strings(
224219

225220
def _get_short_option_strings(
226221
self, option_strings: Sequence[str]
227-
) -> List[str]:
222+
) -> list[str]:
228223
"""
229224
Get the short options from a list of options strings.
230225
@@ -278,7 +273,7 @@ def _get_option_string(
278273
return short_options[0]
279274
return ""
280275

281-
def _append_list_of_list_of_args(self, args: List[List[str]]) -> None:
276+
def _append_list_of_list_of_args(self, args: list[list[str]]) -> None:
282277
"""
283278
Append to the list of unparsed arguments.
284279
@@ -293,7 +288,7 @@ def _append_list_of_list_of_args(self, args: List[List[str]]) -> None:
293288
for line in args:
294289
self._args.append(self._indent_str + " ".join(line))
295290

296-
def _append_list_of_args(self, args: List[str]) -> None:
291+
def _append_list_of_args(self, args: list[str]) -> None:
297292
"""
298293
Append to the list of unparsed arguments.
299294

test/test_reverse_argparse.py

+28-52
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,13 @@
77
# SPDX-License-Identifier: BSD-3-Clause
88

99
import shlex
10-
import sys
11-
from argparse import SUPPRESS, ArgumentParser, Namespace
10+
from argparse import SUPPRESS, ArgumentParser, BooleanOptionalAction, Namespace
1211

1312
import pytest
1413

1514
from reverse_argparse import ReverseArgumentParser
1615

1716

18-
BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION = 9
19-
20-
21-
if sys.version_info.minor >= BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION:
22-
from argparse import BooleanOptionalAction
23-
24-
2517
@pytest.fixture
2618
def parser() -> ArgumentParser:
2719
"""
@@ -51,10 +43,7 @@ def parser() -> ArgumentParser:
5143
)
5244
p.add_argument("--verbose", "-v", action="count", default=2)
5345
p.add_argument("--ext", action="extend", nargs="*")
54-
if sys.version_info.minor >= BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION:
55-
p.add_argument(
56-
"--bool-opt", action=BooleanOptionalAction, default=False
57-
)
46+
p.add_argument("--bool-opt", action=BooleanOptionalAction, default=False)
5847
return p
5948

6049

@@ -144,20 +133,12 @@ def test_get_effective_command_line_invocation(parser, args) -> None:
144133
namespace = parser.parse_args(shlex.split(args))
145134
unparser = ReverseArgumentParser(parser, namespace)
146135
expected = (
147-
(
148-
"--opt1 opt1-val --opt2 opt2-val1 opt2-val2 --store-true "
149-
"--store-false --needs-quotes 'hello world' --default 42 --app1 "
150-
"app1-val1 --app1 app1-val2 --app2 app2-val1 --app2 app2-val2 "
151-
"--app-nargs app-nargs1-val1 app-nargs1-val2 --app-nargs "
152-
"app-nargs2-val --const --app-const1 --app-const2 -vv --ext "
153-
"ext-val1 ext-val2 ext-val3 "
154-
)
155-
+ (
156-
"--no-bool-opt "
157-
if sys.version_info.minor >= BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION
158-
else ""
159-
)
160-
+ "pos1-val1 pos1-val2 pos2-val"
136+
"--opt1 opt1-val --opt2 opt2-val1 opt2-val2 --store-true "
137+
"--store-false --needs-quotes 'hello world' --default 42 --app1 "
138+
"app1-val1 --app1 app1-val2 --app2 app2-val1 --app2 app2-val2 "
139+
"--app-nargs app-nargs1-val1 app-nargs1-val2 --app-nargs "
140+
"app-nargs2-val --const --app-const1 --app-const2 -vv --ext ext-val1 "
141+
"ext-val2 ext-val3 --no-bool-opt pos1-val1 pos1-val2 pos2-val"
161142
)
162143
result = strip_first_entry(
163144
unparser.get_effective_command_line_invocation()
@@ -186,10 +167,9 @@ def test_get_pretty_command_line_invocation(parser, args) -> None:
186167
--app-const1 \\
187168
--app-const2 \\
188169
-vv \\
189-
--ext ext-val1 ext-val2 ext-val3 \\"""
190-
if sys.version_info.minor >= BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION:
191-
expected += "\n --no-bool-opt \\"
192-
expected += """\n pos1-val1 pos1-val2 \\
170+
--ext ext-val1 ext-val2 ext-val3 \\
171+
--no-bool-opt \\
172+
pos1-val1 pos1-val2 \\
193173
pos2-val"""
194174
result = strip_first_line(unparser.get_pretty_command_line_invocation())
195175
assert result == expected
@@ -274,16 +254,15 @@ def test__unparse_args_boolean_optional_action() -> None:
274254
With a ``BooleanOptionalAction``, which became available in Python
275255
3.9.
276256
"""
277-
if sys.version_info.minor >= BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION:
278-
parser = ArgumentParser()
279-
parser.add_argument("--foo", action=BooleanOptionalAction)
280-
try:
281-
namespace = parser.parse_args(shlex.split("--foo"))
282-
except SystemExit:
283-
namespace = Namespace()
284-
unparser = ReverseArgumentParser(parser, namespace)
285-
unparser._unparse_args()
286-
assert unparser._args[1:] == [" --foo"]
257+
parser = ArgumentParser()
258+
parser.add_argument("--foo", action=BooleanOptionalAction)
259+
try:
260+
namespace = parser.parse_args(shlex.split("--foo"))
261+
except SystemExit:
262+
namespace = Namespace()
263+
unparser = ReverseArgumentParser(parser, namespace)
264+
unparser._unparse_args()
265+
assert unparser._args[1:] == [" --foo"]
287266

288267

289268
def test__unparse_args_already_unparsed() -> None:
@@ -635,14 +614,11 @@ def test__unparse_extend_action() -> None:
635614
)
636615
def test__unparse_boolean_optional_action(default, args, expected) -> None:
637616
"""Ensure ``BooleanOptionalAction`` actions are handled appropriately."""
638-
if sys.version_info.minor >= BOOLEAN_OPTIONAL_ACTION_MINOR_VERSION:
639-
parser = ArgumentParser()
640-
action = parser.add_argument(
641-
"--bool-opt", action=BooleanOptionalAction, default=default
642-
)
643-
namespace = parser.parse_args(shlex.split(args))
644-
unparser = ReverseArgumentParser(parser, namespace)
645-
unparser._unparse_boolean_optional_action(action)
646-
assert unparser._args[1:] == (
647-
[expected] if expected is not None else []
648-
)
617+
parser = ArgumentParser()
618+
action = parser.add_argument(
619+
"--bool-opt", action=BooleanOptionalAction, default=default
620+
)
621+
namespace = parser.parse_args(shlex.split(args))
622+
unparser = ReverseArgumentParser(parser, namespace)
623+
unparser._unparse_boolean_optional_action(action)
624+
assert unparser._args[1:] == ([expected] if expected is not None else [])

0 commit comments

Comments
 (0)