From 7ae39e171a636ee28bde8b84f2845a4a2de1eee2 Mon Sep 17 00:00:00 2001 From: fwkz <2480867+fwkz@users.noreply.github.com> Date: Tue, 16 Jan 2024 22:31:37 +0100 Subject: [PATCH] Update project Support newer Python versions Update packaging machanism to modern standards --- .github/workflows/test.yml | 20 +++++++------- Makefile | 23 ++++++++-------- pyproject.toml | 55 +++++++++++++++++++++++++++++++++++--- riposte/command.py | 4 +-- riposte/guides.py | 4 +-- riposte/input_streams.py | 6 ++--- riposte/riposte.py | 12 ++++----- setup.cfg | 5 ---- setup.py | 53 ------------------------------------ tests/conftest.py | 22 +++++++++++++++ tests/test_command.py | 7 +++-- 11 files changed, 112 insertions(+), 99 deletions(-) delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aafe840..30b0ac2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,23 +8,23 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - name: Set up Python 3.7 + - name: Set up Python 3.12 uses: actions/setup-python@v1 with: - python-version: 3.7 + python-version: 3.12 - name: Lint run: | pip install -U .[dev] - flake8 - black --check --diff . - isort --check-only --diff . + black --check --diff riposte/ + isort --check-only --diff riposte/ + ruff check --diff riposte/ build: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macOS-10.15, ubuntu-18.04] - python-version: [3.6, 3.7, 3.8] + os: [macOS-13, ubuntu-22.04] + python-version: [3.8, 3.9, "3.10", 3.11, 3.12] steps: - uses: actions/checkout@v1 - name: Set up Python ${{ matrix.python-version }} @@ -36,8 +36,8 @@ jobs: - name: Package run: | source venv/bin/activate - pip install wheel - python setup.py bdist_wheel + pip install build + python -m build --wheel . - name: Install run: | source venv/bin/activate @@ -46,4 +46,4 @@ jobs: run: | source venv/bin/activate rm -rf riposte - pytest tests/ + pytest tests/ \ No newline at end of file diff --git a/Makefile b/Makefile index 1235cf1..c2b5b5f 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +REFORMAT_DIRS:=riposte + define colorecho @tput setaf 6 @echo $1 @@ -9,14 +11,14 @@ endef all: reformat tests lint -.PHONY: build -build: clean +.PHONY: package +package: clean $(call colorecho, "\n Building package distributions...") - python setup.py sdist bdist_wheel + python -m build . .PHONY: publish -publish: build +publish: package twine upload dist/* @@ -29,17 +31,16 @@ tests: clean .PHONY: lint lint: $(call colorecho, "\nLinting...") - flake8 - black --check --diff . - isort --check-only --diff . - + black --check --diff $(REFORMAT_DIRS) + isort --check-only --diff $(REFORMAT_DIRS) + ruff check --diff $(REFORMAT_DIRS) .PHONY: reformat reformat: $(call colorecho, "\nReformatting...") - black . - isort . - + black $(REFORMAT_DIRS) + isort $(REFORMAT_DIRS) + ruff check --fix $(REFORMAT_DIRS) .PHONY: clean clean: diff --git a/pyproject.toml b/pyproject.toml index 0c59069..218734c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,57 @@ [build-system] -requires = ["setuptools", "wheel", "setuptools_scm"] +requires = ["setuptools>=64", "setuptools_scm>=8"] +build-backend = "setuptools.build_meta" + +[project] +name = "riposte" +description="Package for wrapping applications inside a tailored interactive shell." +authors = [ + {name = "Mariusz Kupidura"}, +] +dynamic = ["version"] +requires-python = ">= 3.8" +readme = "README.md" +license = {file = "LICENSE"} +classifiers=[ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Operating System :: POSIX", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "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 :: Only", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: System :: Shells", +] + +[project.urls] +Homepage = "https://github.com/fwkz/riposte" + +[project.optional-dependencies] +dev = [ + "black", + "isort", + "pytest", + "ruff", + "setuptools_scm", + "twine", + "wheel", +] + +[tool.setuptools_scm] +write_to = "riposte/_version.py" +write_to_template = "version = \"{version}\"\n" + +[tool.ruff] +line-length = 80 [tool.black] -line-length = 79 +line-length = 80 py36 = true include = '\.pyi?$' exclude = ''' @@ -25,6 +74,6 @@ force_grid_wrap = false force_sort_within_sections = true include_trailing_comma = true known_first_party = "riposte" -line_length = 79 +line_length = 80 multi_line_output = 3 use_parentheses = true \ No newline at end of file diff --git a/riposte/command.py b/riposte/command.py index c6f59f7..bd118af 100644 --- a/riposte/command.py +++ b/riposte/command.py @@ -89,7 +89,7 @@ def _apply_guides(self, bound_arguments: inspect.BoundArguments) -> List: return processed def _bind_arguments(self, *args) -> inspect.BoundArguments: - """ Check whether given `args` match `_func` signature. """ + """Check whether given `args` match `_func` signature.""" try: return inspect.signature(self._func).bind(*args) except TypeError as e: @@ -106,7 +106,7 @@ def execute(self, *args: str) -> None: return self._func(*self._apply_guides(self._bind_arguments(*args))) def complete(self, *args, **kwargs) -> Sequence: - """ Execute completer function bound to this command. """ + """Execute completer function bound to this command.""" if not self._completer_function: return () diff --git a/riposte/guides.py b/riposte/guides.py index 15933ce..a87da67 100644 --- a/riposte/guides.py +++ b/riposte/guides.py @@ -19,7 +19,7 @@ def encode(value: str) -> Any: def get_guides(annotation) -> Tuple[Callable]: - """ Based on given annotation get chain of guides. """ + """Based on given annotation get chain of guides.""" if annotation in (str, AnyStr, Text): return () @@ -30,7 +30,7 @@ def get_guides(annotation) -> Tuple[Callable]: def extract_guides(func: Callable) -> Dict[str, Tuple[Callable]]: - """ Extract guides out of type-annotations. """ + """Extract guides out of type-annotations.""" return { arg: get_guides(annotation) for arg, annotation in func.__annotations__.items() diff --git a/riposte/input_streams.py b/riposte/input_streams.py index 8099716..1cf95c2 100644 --- a/riposte/input_streams.py +++ b/riposte/input_streams.py @@ -6,17 +6,17 @@ def prompt_input(prompt: Callable) -> Generator[Callable, None, None]: - """ Unexhaustible generator yielding `input` function forever. """ + """Unexhaustible generator yielding `input` function forever.""" yield from itertools.repeat(lambda: input(prompt())) def cli_input(inline_commands: str) -> Generator[Callable, None, None]: - """ Translate inline command provided via '-c' into input stream. """ + """Translate inline command provided via '-c' into input stream.""" yield lambda: inline_commands def file_input(path: Path) -> Generator[Callable, None, None]: - """ Read file and translate it into input stream """ + """Read file and translate it into input stream""" try: with open(path, "r") as file_handler: for line in file_handler: diff --git a/riposte/riposte.py b/riposte/riposte.py index 93e03f8..3fe9d38 100644 --- a/riposte/riposte.py +++ b/riposte/riposte.py @@ -100,7 +100,7 @@ def contextual_complete(self) -> List[str]: def _raw_command_completer( self, text, line, start_index, end_index ) -> List[str]: - """ Complete command w/o any argument """ + """Complete command w/o any argument""" results = [ command for command in self.contextual_complete() @@ -112,7 +112,7 @@ def _raw_command_completer( @staticmethod def _split_inline_commands(line: str) -> List[str]: - """ Split multiple inline commands. """ + """Split multiple inline commands.""" parsed = shlex.split(line, posix=False) commands = [] @@ -139,14 +139,14 @@ def _split_inline_commands(line: str) -> List[str]: @staticmethod def _parse_line(line: str) -> List[str]: - """ Split input line into command's name and its arguments. """ + """Split input line into command's name and its arguments.""" try: return shlex.split(line) except ValueError as err: raise RiposteException(err) def _get_command(self, command_name: str) -> Command: - """ Resolve command name into registered `Command` object. """ + """Resolve command name into registered `Command` object.""" try: return self._commands[command_name] except KeyError: @@ -195,7 +195,7 @@ def command( description: str = "", guides: Dict[str, Iterable[Callable]] = None, ) -> Callable: - """ Decorator for bounding command with handling function. """ + """Decorator for bounding command with handling function.""" def wrapper(func: Callable): if name not in self._commands: @@ -207,7 +207,7 @@ def wrapper(func: Callable): return wrapper def complete(self, command: str) -> Callable: - """ Decorator for bounding complete function with `Command`. """ + """Decorator for bounding complete function with `Command`.""" def wrapper(func: Callable): cmd = self._get_command(command) diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3c71bdc..0000000 --- a/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[metadata] -license_files = LICENSE - -[flake8] -exclude = .cache,.git,.idea,.tox,.eggs,build,docs/*,*/_version.py,*.egg-info diff --git a/setup.py b/setup.py deleted file mode 100644 index 1b5fbe7..0000000 --- a/setup.py +++ /dev/null @@ -1,53 +0,0 @@ -from pathlib import Path - -from setuptools import find_packages, setup - -HERE = Path(__file__).parent.resolve() - -with open("README.md", "r") as fh: - long_description = fh.read() - -setup( - name="riposte", - use_scm_version={ - "root": str(HERE), - "write_to": str(HERE / "riposte" / "_version.py"), - }, - description=( - "Package for wrapping applications inside " - "a tailored interactive shell." - ), - long_description=long_description, - long_description_content_type="text/markdown", - license="MIT", - url="https://github.com/fwkz/riposte", - author="Mariusz Kupidura", - author_email="f4wkes@gmail.com", - packages=find_packages(), - python_requires=">=3.6", - extras_require={ - "dev": [ - "black", - "flake8", - "isort", - "pytest", - "setuptools_scm", - "twine", - "wheel", - ] - }, - classifiers=[ - "Development Status :: 4 - Beta", - "Environment :: Console", - "Operating System :: POSIX", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3 :: Only", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: System :: Shells", - ], -) diff --git a/tests/conftest.py b/tests/conftest.py index a93b916..76fbb16 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,3 +31,25 @@ def command(): func=Mock(name="mocked_handling_function", __annotations__={}), description="foo description", ) + + +FOO = { + "baby_mat": (32, 32, 21), + "balcony_grass": (30, 30, 51), + "baby_changer": (76, 53, 91), + "diaper_bin": (30, 25, 45), + "newborn_crib": (95, 55, 15), + "travel_crib": (28, 28, 80), + "mattress": (120, 60, 15), + "vacuum_cleaner": (37, 50, 34), + "clothes_box": (37, 50, 34), + "umbrella_stroller": (35, 45, 110), + "table+stool+toys": (75, 60, 50), + "books": (40, 56, 25), + "trash_can": (40, 40, 45), + "storage_box": (27, 30, 38), + "storage_box_2": (27, 30, 38), + "baby_dining_chair": (40, 35, 40), + "ukulele": (25, 65, 15), + "humidifier": (17, 15, 25), +} diff --git a/tests/test_command.py b/tests/test_command.py index 9c13ab3..1763a6c 100644 --- a/tests/test_command.py +++ b/tests/test_command.py @@ -1,4 +1,5 @@ import inspect +import unittest.mock from unittest import mock import pytest @@ -48,11 +49,9 @@ def test_attach_completer_already_attached(command): @mock.patch("riposte.command.extract_guides") def test_command_setup_guides_validate(mocked_extract_guides): - with mock.patch.object( Command, "_validate_guides" ) as mocked_validate_guides: - Command("foo", mock.Mock(), "description") mocked_validate_guides.assert_called_once_with() @@ -106,7 +105,7 @@ def test_validate_guides(command, guides): command._validate_guides() -@mock.patch("riposte.command.inspect") +@mock.patch("riposte.command.inspect", new_callable=unittest.mock.MagicMock) def test_bind_arguments(inspect_mock, command): args = (1, 2) command._bind_arguments(*args) @@ -115,7 +114,7 @@ def test_bind_arguments(inspect_mock, command): inspect_mock.signature.return_value.bind.assert_called_once_with(*args) -@mock.patch("riposte.command.inspect") +@mock.patch("riposte.command.inspect", new_callable=unittest.mock.MagicMock) def test_bind_arguments_exception(inspect_mock, command): args = (1, 2) inspect_mock.signature.return_value.bind.side_effect = TypeError