diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8e33dff..85facf0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,10 +16,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.12", "3.11", "3.10", "3.9"] - env: - PYTHONUNBUFFERED: 1 - PYTHONWARNINGS: always + python-version: ["3.12", "3.11", "3.10"] steps: - name: Checkout run: | @@ -34,7 +31,7 @@ jobs: with: python-version: '${{ matrix.python-version }}' cache: 'pip' # caching pip dependencies - cache-dependency-path: '**/requirements.dev.txt' + cache-dependency-path: '**/requirements.*.txt' - name: 'Bootstrap app venv' # The first CLI call will create the .venv @@ -59,6 +56,9 @@ jobs: ./dev-cli.py safety - name: 'Run tests with Python v${{ matrix.python-version }}' + env: + PYTHONUNBUFFERED: 1 + PYTHONWARNINGS: always run: | ./dev-cli.py coverage diff --git a/README.md b/README.md index 159c424..c5268e0 100644 --- a/README.md +++ b/README.md @@ -255,7 +255,7 @@ Usage: ./cli.py format-file [OPTIONS] FILE_PATH ╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮ │ --py-version TEXT Fallback Python version for darker/pyupgrade, if │ │ version is not defined in pyproject.toml │ -│ [default: 3.9] │ +│ [default: 3.10] │ │ --max-line-length -l INTEGER Fallback max. line length for darker/isort etc., if │ │ not defined in .editorconfig │ │ [default: 119] │ @@ -332,6 +332,10 @@ See also git tags: https://github.com/jedie/manageprojects/tags [comment]: <> (✂✂✂ auto generated history start ✂✂✂) +* [v0.17.0](https://github.com/jedie/manageprojects/compare/v0.16.2...v0.17.0) + * 2023-12-21 - Unify BASE_PATH / PACKAGE_ROOT etc. + * 2023-12-21 - Apply manageprojects updates: Skip Python 3.9 support + * 2023-12-21 - Update requirements * [v0.16.2](https://github.com/jedie/manageprojects/compare/v0.16.1...v0.16.2) * 2023-12-16 - Update pre-commit-config * 2023-12-16 - Skip test_readme_history() on CI @@ -344,11 +348,11 @@ See also git tags: https://github.com/jedie/manageprojects/tags * 2023-12-02 - Use code style tooling from cli-base-utilities * 2023-12-01 - Apply https://github.com/jedie/cookiecutter_templates updates * 2023-12-01 - Use: cli_base.cli_tools.test_utils.logs.AssertLogs -* [v0.15.4](https://github.com/jedie/manageprojects/compare/v0.15.3...v0.15.4) - * 2023-11-27 - Use "flake8-bugbear", too.
Expand older history entries ... +* [v0.15.4](https://github.com/jedie/manageprojects/compare/v0.15.3...v0.15.4) + * 2023-11-27 - Use "flake8-bugbear", too. * [v0.15.3](https://github.com/jedie/manageprojects/compare/v0.15.2...v0.15.3) * 2023-11-09 - Bugfix "reverse" if context contains a list * 2023-11-07 - Update requirements diff --git a/cli.py b/cli.py index 4043912..175bb51 100755 --- a/cli.py +++ b/cli.py @@ -8,6 +8,7 @@ """ import hashlib +import shlex import subprocess import sys import venv @@ -32,7 +33,7 @@ def print_no_pip_error(): sys.exit(-1) -assert sys.version_info >= (3, 9), 'Python version is too old!' +assert sys.version_info >= (3, 10), f'Python version {sys.version_info} is too old!' if sys.platform == 'win32': # wtf @@ -77,7 +78,7 @@ def venv_up2date(): def verbose_check_call(*popen_args): - print(f'\n+ {" ".join(str(arg) for arg in popen_args)}\n') + print(f'\n+ {shlex.join(str(arg) for arg in popen_args)}\n') return subprocess.check_call(popen_args) diff --git a/dev-cli.py b/dev-cli.py index 3449618..6f46420 100755 --- a/dev-cli.py +++ b/dev-cli.py @@ -8,6 +8,7 @@ """ import hashlib +import shlex import subprocess import sys import venv @@ -32,7 +33,7 @@ def print_no_pip_error(): sys.exit(-1) -assert sys.version_info >= (3, 9), 'Python version is too old!' +assert sys.version_info >= (3, 10), f'Python version {sys.version_info} is too old!' if sys.platform == 'win32': # wtf @@ -77,7 +78,7 @@ def venv_up2date(): def verbose_check_call(*popen_args): - print(f'\n+ {" ".join(str(arg) for arg in popen_args)}\n') + print(f'\n+ {shlex.join(str(arg) for arg in popen_args)}\n') return subprocess.check_call(popen_args) diff --git a/manageprojects/__init__.py b/manageprojects/__init__.py index 4ff16de..6a1c5da 100644 --- a/manageprojects/__init__.py +++ b/manageprojects/__init__.py @@ -3,5 +3,5 @@ Manage Python / Django projects """ -__version__ = '0.16.2' +__version__ = '0.17.0' __author__ = 'Jens Diemer ' diff --git a/manageprojects/cli/cli_app.py b/manageprojects/cli/cli_app.py index 5311ded..972487e 100644 --- a/manageprojects/cli/cli_app.py +++ b/manageprojects/cli/cli_app.py @@ -6,10 +6,9 @@ import subprocess import sys from pathlib import Path -from typing import Optional import rich_click as click -from bx_py_utils.path import assert_is_dir, assert_is_file +from bx_py_utils.path import assert_is_dir from cli_base.cli_tools.subprocess_utils import verbose_check_call from cli_base.cli_tools.verbosity import OPTION_KWARGS_VERBOSE from cli_base.cli_tools.version_info import print_version @@ -39,9 +38,6 @@ logger = logging.getLogger(__name__) -PACKAGE_ROOT = Path(manageprojects.__file__).parent.parent -assert_is_file(PACKAGE_ROOT / 'pyproject.toml') - OPTION_ARGS_DEFAULT_TRUE = dict(is_flag=True, show_default=True, default=True) OPTION_ARGS_DEFAULT_FALSE = dict(is_flag=True, show_default=True, default=False) ARGUMENT_EXISTING_DIR = dict( @@ -116,12 +112,12 @@ def cli(): def start_project( template: str, output_dir: Path, - directory: Optional[str], - checkout: Optional[str], + directory: str | None, + checkout: str | None, input: bool, replay: bool, - password: Optional[str], - config_file: Optional[Path], + password: str | None, + config_file: Path | None, ): """ Start a new "managed" project via a CookieCutter Template. @@ -199,8 +195,8 @@ def start_project( def update_project( project_path: Path, overwrite: bool, - password: Optional[str], - config_file: Optional[Path], + password: str | None, + config_file: Path | None, input: bool, cleanup: bool, ): @@ -250,9 +246,9 @@ def clone_project( project_path: Path, output_dir: Path, input: bool, - checkout: Optional[str] = None, - password: Optional[str] = None, - config_file: Optional[Path] = None, + checkout: str | None = None, + password: str | None = None, + config_file: Path | None = None, ): """ Clone existing project by replay the cookiecutter template in a new directory. diff --git a/manageprojects/cli/dev.py b/manageprojects/cli/dev.py index 27cfee8..489e7e5 100644 --- a/manageprojects/cli/dev.py +++ b/manageprojects/cli/dev.py @@ -19,13 +19,14 @@ import manageprojects from manageprojects import constants +from manageprojects.constants import BASE_PATH from manageprojects.utilities.publish import publish_package logger = logging.getLogger(__name__) -PACKAGE_ROOT = Path(manageprojects.__file__).parent.parent +PACKAGE_ROOT = BASE_PATH.parent assert_is_file(PACKAGE_ROOT / 'pyproject.toml') OPTION_ARGS_DEFAULT_TRUE = dict(is_flag=True, show_default=True, default=True) diff --git a/manageprojects/constants.py b/manageprojects/constants.py index a541791..323eafd 100644 --- a/manageprojects/constants.py +++ b/manageprojects/constants.py @@ -1,6 +1,8 @@ import sys from pathlib import Path +import manageprojects + INITIAL_REVISION = 'initial_revision' INITIAL_DATE = 'initial_date' @@ -24,7 +26,8 @@ ] ) ) -FORMAT_PY_FILE_DEFAULT_MIN_PYTON_VERSION = '3.9' +FORMAT_PY_FILE_DEFAULT_MIN_PYTON_VERSION = '3.10' FORMAT_PY_FILE_DEFAULT_MAX_LINE_LENGTH = 119 PY_BIN_PATH = Path(sys.executable).parent +BASE_PATH = Path(manageprojects.__file__).parent diff --git a/manageprojects/tests/base.py b/manageprojects/tests/base.py index a36a77e..030d9d4 100644 --- a/manageprojects/tests/base.py +++ b/manageprojects/tests/base.py @@ -7,11 +7,9 @@ from bx_py_utils.path import assert_is_file -import manageprojects from manageprojects.utilities.pyproject_toml import TomlDocument, get_toml_document -PROJECT_PATH = Path(manageprojects.__file__).parent.parent GIT_BIN_PARENT = Path(shutil.which('git')).parent diff --git a/manageprojects/tests/test_cli.py b/manageprojects/tests/test_cli.py index 624e4f6..03e4077 100644 --- a/manageprojects/tests/test_cli.py +++ b/manageprojects/tests/test_cli.py @@ -4,7 +4,8 @@ from unittest.mock import MagicMock from manageprojects.cli import cli_app -from manageprojects.cli.cli_app import PACKAGE_ROOT, start_project, update_project +from manageprojects.cli.cli_app import start_project, update_project +from manageprojects.cli.dev import PACKAGE_ROOT from manageprojects.cli.dev import cli as dev_cli from manageprojects.constants import PY_BIN_PATH from manageprojects.data_classes import CookiecutterResult diff --git a/manageprojects/tests/test_format_file.py b/manageprojects/tests/test_format_file.py index 2e482ea..dfc0005 100644 --- a/manageprojects/tests/test_format_file.py +++ b/manageprojects/tests/test_format_file.py @@ -5,6 +5,7 @@ from cli_base.cli_tools.test_utils.logs import AssertLogs from packaging.version import Version +from manageprojects.cli.dev import PACKAGE_ROOT from manageprojects.constants import PY_BIN_PATH from manageprojects.format_file import ( Config, @@ -17,7 +18,7 @@ get_pyproject_info, ) from manageprojects.test_utils.subprocess import SimpleRunReturnCallback, SubprocessCallMock -from manageprojects.tests.base import GIT_BIN_PARENT, PROJECT_PATH +from manageprojects.tests.base import GIT_BIN_PARENT from manageprojects.utilities.temp_path import TemporaryDirectory @@ -111,9 +112,9 @@ def test_get_pyproject_info(self): self.assertEqual( get_pyproject_info(file_path=Path(__file__), default_min_py_version='3.7'), PyProjectInfo( - pyproject_toml_path=PROJECT_PATH / 'pyproject.toml', - py_min_ver=Version('3.9'), - raw_py_ver_req='>=3.9,<4', + pyproject_toml_path=PACKAGE_ROOT / 'pyproject.toml', + py_min_ver=Version('3.10'), + raw_py_ver_req='>=3.10', ), ) @@ -129,11 +130,11 @@ def test_get_config(self): self.assertEqual( config, Config( - git_info=GitInfo(cwd=PROJECT_PATH, main_branch_name='main'), + git_info=GitInfo(cwd=PACKAGE_ROOT, main_branch_name='main'), pyproject_info=PyProjectInfo( - pyproject_toml_path=PROJECT_PATH / 'pyproject.toml', - py_min_ver=Version('3.9'), - raw_py_ver_req='>=3.9,<4', + pyproject_toml_path=PACKAGE_ROOT / 'pyproject.toml', + py_min_ver=Version('3.10'), + raw_py_ver_req='>=3.10', ), max_line_length=119, ), @@ -146,7 +147,7 @@ def test_get_config(self): Config( git_info=None, pyproject_info=PyProjectInfo( - py_min_ver=Version('3.9'), pyproject_toml_path=None, raw_py_ver_req=None + py_min_ver=Version('3.10'), pyproject_toml_path=None, raw_py_ver_req=None ), max_line_length=119, ), @@ -173,7 +174,7 @@ def test_format_one_file(self): [ '.../pyupgrade', '--exit-zero-even-if-changed', - '--py39-plus', + '--py310-plus', 'manageprojects/tests/test_format_file.py', ], [ @@ -201,7 +202,7 @@ def test_format_one_file(self): '--line-length', '119', '--target-version', - 'py39', + 'py310', 'manageprojects/tests/test_format_file.py', ], ['.../flake8', '--max-line-length', '119', 'manageprojects/tests/test_format_file.py'], @@ -238,7 +239,7 @@ def test_format_one_file(self): [ '.../pyupgrade', '--exit-zero-even-if-changed', - '--py39-plus', + '--py310-plus', 'manageprojects/tests/test_format_file.py', ], ['.../autoflake', '--in-place', 'manageprojects/tests/test_format_file.py'], diff --git a/manageprojects/tests/test_project_setup.py b/manageprojects/tests/test_project_setup.py index a9dc7be..8b994f5 100644 --- a/manageprojects/tests/test_project_setup.py +++ b/manageprojects/tests/test_project_setup.py @@ -6,7 +6,7 @@ from packaging.version import Version from manageprojects import __version__ -from manageprojects.cli.cli_app import PACKAGE_ROOT +from manageprojects.cli.dev import PACKAGE_ROOT from manageprojects.test_utils.project_setup import check_editor_config, get_py_max_line_length diff --git a/manageprojects/tests/test_readme.py b/manageprojects/tests/test_readme.py index b02c845..999f483 100644 --- a/manageprojects/tests/test_readme.py +++ b/manageprojects/tests/test_readme.py @@ -2,7 +2,8 @@ from bx_py_utils.path import assert_is_file from manageprojects import constants -from manageprojects.cli.cli_app import PACKAGE_ROOT, cli +from manageprojects.cli.cli_app import cli +from manageprojects.cli.dev import PACKAGE_ROOT from manageprojects.cli.dev import cli as dev_cli from manageprojects.test_utils.click_cli_utils import invoke_click from manageprojects.tests.base import BaseTestCase diff --git a/manageprojects/tests/test_utilities_pyproject_toml.py b/manageprojects/tests/test_utilities_pyproject_toml.py index 358f21d..96bbb1d 100644 --- a/manageprojects/tests/test_utilities_pyproject_toml.py +++ b/manageprojects/tests/test_utilities_pyproject_toml.py @@ -5,7 +5,7 @@ from bx_py_utils.test_utils.datetime import parse_dt from cli_base.cli_tools.test_utils.logs import AssertLogs -import manageprojects +from manageprojects.constants import BASE_PATH from manageprojects.data_classes import ManageProjectsMeta from manageprojects.tests.base import BaseTestCase from manageprojects.utilities.pyproject_toml import PyProjectToml, find_pyproject_toml @@ -268,7 +268,7 @@ def test_expand_existing_toml(self): logs.assert_in('Read existing pyproject.toml') def test_find_pyproject_toml(self): - own_pyproject_toml = Path(manageprojects.__file__).parent.parent / 'pyproject.toml' + own_pyproject_toml = BASE_PATH.parent / 'pyproject.toml' assert_is_file(own_pyproject_toml) self.assertEqual(find_pyproject_toml(file_path=Path(__file__)), own_pyproject_toml) diff --git a/pyproject.toml b/pyproject.toml index cdaae18..5650511 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ readme = "README.md" authors = [ {name = 'Jens Diemer', email = 'mamageprojects@jensdiemer.de'} ] -requires-python = ">=3.9,<4" +requires-python = ">=3.10" dependencies = [ "cookiecutter>=2.4.0", # https://github.com/cookiecutter/cookiecutter "tomlkit", @@ -28,7 +28,7 @@ dependencies = [ "codespell", # https://github.com/codespell-project/codespell "mypy", # https://github.com/python/mypy - "cli-base-utilities>=0.7.0rc2", # https://github.com/jedie/cli-base-utilities + "cli-base-utilities", # https://github.com/jedie/cli-base-utilities "click", # https://github.com/pallets/click/ "rich-click", # https://github.com/ewels/rich-click "rich", # https://github.com/Textualize/rich @@ -125,7 +125,7 @@ exclude_lines = [ legacy_tox_ini = """ [tox] isolated_build = True -envlist = py{312,311,310,39} +envlist = py{312,311,310} skip_missing_interpreters = True [testenv] @@ -168,6 +168,7 @@ applied_migrations = [ "be3f649", # 2023-08-22T19:36:57+02:00 "385f654", # 2023-10-08T21:09:24+02:00 "d1ed4b1", # 2023-12-01T21:41:29+01:00 + "c538ae7", # 2023-12-21T20:21:58+01:00 ] [manageprojects.cookiecutter_context.cookiecutter] diff --git a/requirements.dev.txt b/requirements.dev.txt index 1f2cb83..0279029 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # ./dev-cli.py update @@ -97,9 +97,7 @@ astor==0.8.1 \ async-timeout==4.0.3 \ --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 - # via - # aiohttp - # cli-base-utilities + # via cli-base-utilities attrs==23.1.0 \ --hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \ --hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015 @@ -1047,19 +1045,9 @@ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via - # autoflake - # autopep8 - # black - # build # cli-base-utilities - # dparse # flynt # manageprojects (pyproject.toml) - # mypy - # pip-tools - # pyproject-api - # pyproject-hooks - # tox tomlkit==0.12.3 \ --hash=sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4 \ --hash=sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba @@ -1082,7 +1070,6 @@ typing-extensions==4.9.0 \ --hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \ --hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd # via - # black # mypy # rich-click urllib3==2.1.0 \ diff --git a/requirements.txt b/requirements.txt index 5c2b888..a47f58f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.10 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # ./dev-cli.py update @@ -97,9 +97,7 @@ astor==0.8.1 \ async-timeout==4.0.3 \ --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 - # via - # aiohttp - # cli-base-utilities + # via cli-base-utilities attrs==23.1.0 \ --hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \ --hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015 @@ -706,12 +704,8 @@ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via - # autoflake - # autopep8 - # black # cli-base-utilities # flynt - # mypy tomlkit==0.12.3 \ --hash=sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4 \ --hash=sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba @@ -726,7 +720,6 @@ typing-extensions==4.9.0 \ --hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \ --hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd # via - # black # mypy # rich-click urllib3==2.1.0 \