Skip to content

Commit

Permalink
Merge pull request #68 from dskrypa/dev
Browse files Browse the repository at this point in the history
Improved RST Table Generation for Documentation & Removed Python 3.8 Support
  • Loading branch information
dskrypa authored Nov 2, 2024
2 parents 93cec6e + 7ff1797 commit 83d77f4
Show file tree
Hide file tree
Showing 29 changed files with 377 additions and 333 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
fail-fast: false
matrix:
language: ["python"]
python-version: ["3.11"]
python-version: ["3.12"]

steps:
- name: Checkout repository
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.11"]
python-version: ["3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- name: Add test locales
run: |
Expand Down
16 changes: 3 additions & 13 deletions docs/_src/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ CLI Command Parser

|downloads| |py_version| |coverage_badge| |build_status| |Ruff|

.. |py_version| image:: https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20-blue
.. |py_version| image:: https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20-blue
:target: https://pypi.org/project/cli-command-parser/

.. |coverage_badge| image:: https://codecov.io/gh/dskrypa/cli_command_parser/branch/main/graph/badge.svg
Expand Down Expand Up @@ -85,18 +85,8 @@ with optional dependencies::
Python Version Compatibility
============================

Python versions 3.8 and above are currently supported. The last release of CLI Command Parser that supported 3.7 was
2023-04-30. Support for Python 3.7 `officially ended on 2023-06-27 <https://devguide.python.org/versions/>`__.

When using Python 3.8, some additional packages that backport functionality that was added in later Python versions
are required for compatibility.

To use the argparse to cli-command-parser conversion script with Python 3.8, there is a dependency on
`astunparse <https://astunparse.readthedocs.io>`__. If you are using Python 3.9 or above, then ``astunparse`` is not
necessary because the relevant code was added to the stdlib ``ast`` module. If you're unsure, you can install
cli-command-parser with the following command to automatically handle whether that extra dependency is needed or not::

$ pip install -U cli-command-parser[conversion]
Python versions 3.9 and above are currently supported. The last release of CLI Command Parser that supported 3.8 was
2024-09-07. Support for Python 3.8 `officially ended on 2024-10-07 <https://devguide.python.org/versions/>`__.


User Guide
Expand Down
11 changes: 1 addition & 10 deletions lib/cli_command_parser/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from collections.abc import Collection, Iterable
from functools import lru_cache
from inspect import isclass
from typing import Union, Optional, get_type_hints as _get_type_hints, get_origin, get_args as _get_args
from typing import Optional, Union, get_args, get_origin, get_type_hints as _get_type_hints

try:
from types import NoneType
Expand Down Expand Up @@ -42,15 +42,6 @@ def get_annotation_value_type(annotation, from_union: bool = True, from_collecti
return None


def get_args(annotation) -> tuple:
"""
Wrapper around :func:`python:typing.get_args` for 3.7~8 compatibility, to make it behave more like it does in 3.9+
"""
if getattr(annotation, '_special', False): # 3.7-3.8 generic collection alias with no content types
return ()
return _get_args(annotation)


def _type_from_union(annotation) -> Optional[type]:
args = get_args(annotation)
# Note: Unions of a single argument return the argument; i.e., Union[T] returns T, so the len can never be 1
Expand Down
10 changes: 0 additions & 10 deletions lib/cli_command_parser/compat.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
"""
Compatibility / Patch module - used to back-port features to Python 3.7 and to avoid breaking changes in Enum/Flag in
3.11.
Contains stdlib CPython functions / classes from Python 3.8 and 3.10.
The :class:`WCTextWrapper` in this module extends the stdlib :class:`python:textwrap.TextWrapper` to support wide
characters.
"""
Expand All @@ -16,8 +11,6 @@

__all__ = ['WCTextWrapper']

# region textwrap


class WCTextWrapper(TextWrapper):
"""
Expand Down Expand Up @@ -119,6 +112,3 @@ def _wrap_chunks(self, chunks: list[str]) -> list[str]:
break

return lines


# endregion
21 changes: 2 additions & 19 deletions lib/cli_command_parser/conversion/utils.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
from __future__ import annotations

from ast import AST, expr, Call, Attribute, Name, Dict, List, Set, Tuple

try:
from ast import unparse
except ImportError: # added in 3.9
try:
from astunparse import unparse as _unparse
except ImportError as e:
raise RuntimeError(
'Missing required dependency: astunparse (only required in Python 3.8 and below'
' - upgrade to 3.9 or above to avoid this dependency)'
)
else:

def unparse(node):
return ''.join(_unparse(node).splitlines())


from typing import Union, Iterator, List as _List
from ast import AST, Attribute, Call, Dict, List, Name, Set, Tuple, expr, unparse
from typing import Iterator, List as _List, Union

__all__ = ['get_name_repr', 'iter_module_parents', 'collection_contents']

Expand Down
2 changes: 1 addition & 1 deletion lib/cli_command_parser/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,6 @@ def write_rst(self, name: str, content: str, subdir: str = None):
path = target_dir.joinpath(name + self.ext)
log.debug(f'{prefix} {path.as_posix()}')
if not self.dry_run:
# Path.write_text on 3.8 does not support `newline`
# Path.write_text on 3.9 does not support `newline`
with path.open('w', encoding=self.encoding, newline=self.newline) as f:
f.write(content)
17 changes: 11 additions & 6 deletions lib/cli_command_parser/formatting/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@

from ..context import NoActiveContext, ctx
from ..core import get_metadata, get_params
from ..parameters.choice_map import ChoiceMap
from ..parameters.groups import ParamGroup
from ..utils import _NotSet, camel_to_snake_case
from .restructured_text import RstTable, spaced_rst_header
from .restructured_text import spaced_rst_header
from .utils import PartWrapper

if TYPE_CHECKING:
Expand Down Expand Up @@ -47,6 +48,7 @@ def maybe_add_groups(self, groups: Iterable[ParamGroup]):
for group in groups:
if group.group: # prevent duplicates
continue

if group.contains_positional:
self.pos_group.add(group)
else:
Expand Down Expand Up @@ -162,14 +164,17 @@ def _cmd_rst_lines(
yield description
yield ''

# TODO: The subcommand names in the group containing subcommand targets should link to their respective
# subcommand sections
for group in self.groups:
if self.pos_group.show_in_help:
# TODO: Nested subcommands' local choices should not repeat the `subcommands` positional arguments section
# that includes the nested subcommand choice being documented
if len(members := self.pos_group.members) == 1 and isinstance(members[0], ChoiceMap):
yield from members[0].formatter.rst_table().iter_build() # noqa
else:
yield from self.pos_group.formatter.rst_table().iter_build()

for group in self.groups[1:]:
if group.show_in_help:
table: RstTable = group.formatter.rst_table() # noqa
yield from table.iter_build()
yield from group.formatter.rst_table().iter_build()

if include_epilog and (epilog := self._meta.format_epilog(config.extended_epilog, allow_sys_argv)):
yield epilog
Expand Down
27 changes: 17 additions & 10 deletions lib/cli_command_parser/formatting/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from ..parameters import ParamGroup, PassThru, TriFlag
from ..parameters.base import BaseOption, BasePositional
from ..parameters.choice_map import Choice, ChoiceMap
from .restructured_text import RstTable
from .restructured_text import Cell, Row, RstTable
from .utils import _should_add_default, format_help_entry

if TYPE_CHECKING:
Expand Down Expand Up @@ -223,6 +223,8 @@ def rst_rows(self) -> Iterator[tuple[str, str]]:


class ChoiceMapHelpFormatter(ParamHelpFormatter, param_cls=ChoiceMap):
"""Formatter for :class:`SubCommand` and :class:`Action` parameters (and any other params that extend ChoiceMap)"""

param: ChoiceMap

@cached_property
Expand Down Expand Up @@ -269,6 +271,7 @@ def rst_table(self) -> RstTable:

def _format_rst_rows(self) -> Iterator[tuple[str, OptStr]]:
mode = ctx.config.cmd_alias_mode or SubcommandAliasHelpMode.ALIAS
# TODO: The subcommand names should link to their respective subcommand sections
for choice_group in self.choice_groups:
for choice, usage, description in choice_group.prepare(mode):
yield f'``{usage}``', description
Expand Down Expand Up @@ -492,15 +495,19 @@ def rst_table(self) -> RstTable:
table = RstTable(self.format_description())
# TODO: non-nested when config.show_group_tree is False; maybe separate options for rst vs help
for member in self.param.members:
if member.show_in_help:
formatter = member.formatter
try:
sub_table: RstTable = formatter.rst_table() # noqa
except AttributeError:
table.add_rows(formatter.rst_rows())
else:
sub_table.show_title = False
table.add_row(sub_table.title, str(sub_table))
if not member.show_in_help:
continue

formatter = member.formatter
try:
sub_table: RstTable = formatter.rst_table() # noqa
except AttributeError:
table.add_rows(formatter.rst_rows())
else:
table._add_row(Row([Cell(str(sub_table), ext_right=True), Cell()]))
# If a config option to switch to the old way is added later, the old approach:
# sub_table.show_title = False
# table.add_row(sub_table.title, str(sub_table))

return table

Expand Down
Loading

0 comments on commit 83d77f4

Please sign in to comment.