diff --git a/.editorconfig b/.editorconfig index 96ded61..8cc1511 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,12 +9,6 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[*.{bat,cmd,ps1}] -end_of_line = crlf - -[*.{html,css,js}] -insert_final_newline = false - [*.py] max_line_length = 100 @@ -23,4 +17,4 @@ indent_style = tab insert_final_newline = false [*.yml] -indent_style = tab \ No newline at end of file +indent_size = 2 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index adbb631..74f2d2a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,6 +16,9 @@ jobs: fail-fast: false matrix: python-version: ["3.11", "3.10", "3.9"] + env: + PYTHONUNBUFFERED: 1 + PYTHONWARNINGS: always steps: - uses: actions/checkout@v2 with: diff --git a/cli.py b/cli.py index a69763d..bfade8d 100755 --- a/cli.py +++ b/cli.py @@ -43,7 +43,7 @@ PIP_PATH = BIN_PATH / f'pip{FILE_EXT}' PIP_SYNC_PATH = BIN_PATH / f'pip-sync{FILE_EXT}' -DEP_LOCK_PATH = BASE_PATH / 'requirements' / 'develop.txt' +DEP_LOCK_PATH = BASE_PATH / 'requirements.develop.txt' DEP_HASH_PATH = VENV_PATH / '.dep_hash' # script file defined in pyproject.toml as [console_scripts] diff --git a/manageprojects/cli/cli_app.py b/manageprojects/cli/cli_app.py index 6910ba3..e430838 100644 --- a/manageprojects/cli/cli_app.py +++ b/manageprojects/cli/cli_app.py @@ -81,20 +81,21 @@ def update(): '--allow-unsafe', '--generate-hashes', '--resolver=backtracking', - 'requirements/production.in', + 'pyproject.toml', ] verbose_check_call( # develop + production *base_command, - 'requirements/develop.in', + '--extra', + 'dev', '--output-file', - 'requirements/develop.txt', + 'requirements.develop.txt', ) verbose_check_call( # production only *base_command, '--output-file', - 'requirements/production.txt', + 'requirements.txt', ) - verbose_check_call('pip-sync', 'requirements/develop.txt') + verbose_check_call('pip-sync', 'requirements.develop.txt') @app.command() @@ -389,8 +390,21 @@ def test(): """ Run unittests """ + args = sys.argv[2:] + if not args: + args = ('--verbose', '--locals', '--buffer') # Use the CLI from unittest module and pass all args to it: - verbose_check_call(sys.executable, '-m', 'unittest', *sys.argv[2:]) + verbose_check_call( + sys.executable, + '-m', + 'unittest', + *args, + timeout=15 * 60, + extra_env=dict( + PYTHONUNBUFFERED='1', + PYTHONWARNINGS='always', + ), + ) def main(): diff --git a/manageprojects/cookiecutter_templates.py b/manageprojects/cookiecutter_templates.py index 68b3692..9c87002 100644 --- a/manageprojects/cookiecutter_templates.py +++ b/manageprojects/cookiecutter_templates.py @@ -140,7 +140,7 @@ def update_managed_project( print('Seems that the patch was not applied correctly!') print('Hint: run wiggle on the project:') print() - print(f'./mp wiggle {project_path}') + print(f'./cli.py wiggle {project_path}') print() ############################################################################# diff --git a/manageprojects/git.py b/manageprojects/git.py index 0d53ab4..e47bcaa 100644 --- a/manageprojects/git.py +++ b/manageprojects/git.py @@ -1,5 +1,6 @@ import datetime import logging +import os import subprocess # nosec B404 from pathlib import Path from shutil import which @@ -49,12 +50,17 @@ def __init__(self, *, cwd: Path, detect_root: bool = True): if not self.git_bin: raise GitBinNotFoundError() + self.env = dict(os.environ) + # no translated git command output ;) + self.env['LANG'] = 'en_US.UTF-8' + self.env['LANGUAGE'] = 'en_US' + def git_verbose_check_call(self, *popenargs, **kwargs): popenargs = [self.git_bin, *popenargs] return verbose_check_call( *popenargs, cwd=self.cwd, - env=dict(), # Empty env -> no translated git command output ;) + env=self.env, **kwargs, ) @@ -63,7 +69,7 @@ def git_verbose_check_output(self, *popenargs, **kwargs): return verbose_check_output( *popenargs, cwd=self.cwd, - env=dict(), # Empty env -> no translated git command output ;) + env=self.env, **kwargs, ) diff --git a/manageprojects/test_utils/logs.py b/manageprojects/test_utils/logs.py new file mode 100644 index 0000000..0ec2b9a --- /dev/null +++ b/manageprojects/test_utils/logs.py @@ -0,0 +1,42 @@ +import logging +from pathlib import Path +from unittest import TestCase + + +class AssertLogs: + """ + Capture and assert log output from different loggers. + """ + + def __init__( + self, + test_case: TestCase, + loggers: tuple[str] = ('manageprojects', 'cookiecutter'), + level=logging.DEBUG, + ): + assertLogs = test_case.assertLogs + + self.logs = [] + for logger in loggers: + self.logs.append(assertLogs(logger, level=level)) + + self.context_managers = None + + def __enter__(self): + self.context_managers = [log.__enter__() for log in self.logs] + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + for log in self.logs: + log.__exit__(exc_type, exc_val, exc_tb) + + def assert_in(self, *test_parts): + outputs = [] + for cm in self.context_managers: + outputs.extend(cm.output) + + output = '\n'.join(outputs) + for part in test_parts: + if isinstance(part, Path): + part = str(part) + assert part in output, f'Log part {part!r} not found in:\n{output}' diff --git a/manageprojects/tests/__init__.py b/manageprojects/tests/__init__.py index d64c245..10561ce 100644 --- a/manageprojects/tests/__init__.py +++ b/manageprojects/tests/__init__.py @@ -1,4 +1,8 @@ from manageprojects.utilities.log_utils import log_config -log_config(log_in_file=False) +log_config( + format='%(levelname)s %(name)s.%(funcName)s %(lineno)d | %(message)s', + log_in_file=False, + raise_log_output=True, +) diff --git a/manageprojects/tests/test_cookiecutter_api.py b/manageprojects/tests/test_cookiecutter_api.py index a36e4bd..977dd1b 100644 --- a/manageprojects/tests/test_cookiecutter_api.py +++ b/manageprojects/tests/test_cookiecutter_api.py @@ -4,6 +4,7 @@ from bx_py_utils.path import assert_is_dir from manageprojects.cookiecutter_api import get_repo_path +from manageprojects.test_utils.logs import AssertLogs from manageprojects.tests.base import BaseTestCase @@ -13,11 +14,14 @@ def test_get_repo_path(self): cookiecutter_template = f'https://github.com/jedie/{repro_name}/' directory = 'test_template1' - repo_path = get_repo_path( - template=cookiecutter_template, - directory=directory, - checkout='84d23bf', # Old version - ) + with AssertLogs(self) as logs: + repo_path = get_repo_path( + template=cookiecutter_template, + directory=directory, + checkout='84d23bf', # Old version + ) + logs.assert_in('repo_dir', repo_path) + self.assertIsInstance(repo_path, Path) self.assertEqual(repo_path.name, directory) assert_is_dir(repo_path.parent / '.git') @@ -34,11 +38,14 @@ def test_get_repo_path(self): ), ) - repo_path = get_repo_path( - template=cookiecutter_template, - directory=directory, - checkout=None, # Current main branch - ) + with AssertLogs(self) as logs: + repo_path = get_repo_path( + template=cookiecutter_template, + directory=directory, + checkout=None, # Current main branch + ) + logs.assert_in('repo_dir', repo_path) + self.assertIsInstance(repo_path, Path) self.assertEqual(repo_path.name, directory) assert_is_dir(repo_path.parent / '.git') diff --git a/manageprojects/tests/test_cookiecutter_templates.py b/manageprojects/tests/test_cookiecutter_templates.py index 6bab045..121b9ce 100644 --- a/manageprojects/tests/test_cookiecutter_templates.py +++ b/manageprojects/tests/test_cookiecutter_templates.py @@ -14,6 +14,7 @@ ManageProjectsMeta, ) from manageprojects.test_utils.git_utils import init_git +from manageprojects.test_utils.logs import AssertLogs from manageprojects.tests.base import BaseTestCase from manageprojects.utilities.pyproject_toml import PyProjectToml from manageprojects.utilities.temp_path import TemporaryDirectory @@ -44,17 +45,20 @@ def test_start_managed_project(self): assert cookiecutter_output_dir.exists() is False assert cookiecutters_dir.exists() is False - result: CookiecutterResult = start_managed_project( - template=cookiecutter_template, - output_dir=cookiecutter_output_dir, - no_input=True, - directory=directory, - config_file=config_file_path, - extra_context={ - 'dir_name': 'a_dir_name', - 'file_name': 'a_file_name', - }, - ) + with AssertLogs(self) as logs: + result: CookiecutterResult = start_managed_project( + template=cookiecutter_template, + output_dir=cookiecutter_output_dir, + no_input=True, + directory=directory, + config_file=config_file_path, + extra_context={ + 'dir_name': 'a_dir_name', + 'file_name': 'a_file_name', + }, + ) + logs.assert_in('Cookiecutter generated here', cookiecutter_output_dir) + self.assertIsInstance(result, CookiecutterResult) git_path = cookiecutters_dir / repro_name self.assertEqual(result.git_path, git_path) @@ -80,8 +84,10 @@ def test_start_managed_project(self): project_path = cookiecutter_output_dir / 'a_dir_name' # pyproject.toml created? - toml = PyProjectToml(project_path=project_path) - result: ManageProjectsMeta = toml.get_mp_meta() + with AssertLogs(self, loggers=('manageprojects',)) as logs: + toml = PyProjectToml(project_path=project_path) + result: ManageProjectsMeta = toml.get_mp_meta() + logs.assert_in('Read existing pyproject.toml') self.assertIsInstance(result, ManageProjectsMeta) self.assertEqual( result, @@ -105,8 +111,14 @@ def test_start_managed_project(self): # Test clone a existing project cloned_path = main_temp_path / 'cloned_project' - clone_result: CookiecutterResult = clone_project( - project_path=project_path, destination=cloned_path, no_input=True + with AssertLogs(self) as logs: + clone_result: CookiecutterResult = clone_project( + project_path=project_path, destination=cloned_path, no_input=True + ) + logs.assert_in( + 'Read existing pyproject.toml', + "Call 'cookiecutter'", + 'Create new pyproject.toml', ) self.assertEqual( clone_result.cookiecutter_context, @@ -123,8 +135,10 @@ def test_start_managed_project(self): self.assertEqual(clone_result.destination_path, end_path) # pyproject.toml created? - toml = PyProjectToml(project_path=end_path) - result: ManageProjectsMeta = toml.get_mp_meta() + with AssertLogs(self, loggers=('manageprojects',)) as logs: + toml = PyProjectToml(project_path=end_path) + result: ManageProjectsMeta = toml.get_mp_meta() + logs.assert_in('Read existing pyproject.toml') self.assertIsInstance(result, ManageProjectsMeta) self.assertEqual( result, @@ -204,13 +218,15 @@ def test_update_project(self): git, from_rev = init_git(template_path, comment='Git init template.') from_date = git.get_commit_date(verbose=False) - toml = PyProjectToml(project_path=project_path) - toml.init( - revision=from_rev, - dt=from_date, - template=str(template_path), - directory=template_dir_name, - ) + with AssertLogs(self, loggers=('manageprojects',)) as logs: + toml = PyProjectToml(project_path=project_path) + toml.init( + revision=from_rev, + dt=from_date, + template=str(template_path), + directory=template_dir_name, + ) + logs.assert_in('Create new pyproject.toml') toml.create_or_update_cookiecutter_context(context=context) toml.save() toml_content = toml.path.read_text() @@ -249,12 +265,18 @@ def test_update_project(self): ) self.assertFalse(patch_file_path.exists()) - result = update_managed_project( - project_path=project_path, - password=None, - config_file=config_file_path, - cleanup=False, # Keep temp files if this test fails, for better debugging - no_input=True, # No user input in tests ;) + with AssertLogs(self) as logs: + result = update_managed_project( + project_path=project_path, + password=None, + config_file=config_file_path, + cleanup=False, # Keep temp files if this test fails, for better debugging + no_input=True, # No user input in tests ;) + ) + logs.assert_in( + 'No temp files cleanup', + 'Cookiecutter generated', + 'Read existing pyproject.toml', ) self.assert_file_content( @@ -294,7 +316,9 @@ def test_update_project(self): ) # Check updated toml file: - toml = PyProjectToml(project_path=project_path) - mp_meta: ManageProjectsMeta = toml.get_mp_meta() + with AssertLogs(self, loggers=('manageprojects',)) as logs: + toml = PyProjectToml(project_path=project_path) + mp_meta: ManageProjectsMeta = toml.get_mp_meta() + logs.assert_in('Read existing pyproject.toml') self.assertEqual(mp_meta.initial_revision, from_rev) self.assertEqual(mp_meta.applied_migrations, [to_rev]) diff --git a/manageprojects/tests/test_git.py b/manageprojects/tests/test_git.py index 6eebe4f..066c800 100644 --- a/manageprojects/tests/test_git.py +++ b/manageprojects/tests/test_git.py @@ -63,8 +63,8 @@ def test_own_git_repo(self): commit_date = git.get_commit_date(verbose=False) self.assertIsInstance(commit_date, datetime.datetime) - self.assertGreater(commit_date, parse_dt('2022-10-25T00:00:00+0000')) - self.assertLess(commit_date, parse_dt('2023-01-01T00:00:00+0000')) # ;) + self.assertGreater(commit_date, parse_dt('2023-01-01T00:00:00+0000')) + self.assertLess(commit_date, parse_dt('2024-01-01T00:00:00+0000')) # ;) def test_init_git(self): with TemporaryDirectory(prefix='test_init_git_') as temp_path: diff --git a/manageprojects/tests/test_patching.py b/manageprojects/tests/test_patching.py index 8e90ce2..bbcd716 100644 --- a/manageprojects/tests/test_patching.py +++ b/manageprojects/tests/test_patching.py @@ -8,6 +8,7 @@ from manageprojects.data_classes import GenerateTemplatePatchResult from manageprojects.patching import generate_template_patch, make_git_diff from manageprojects.test_utils.git_utils import init_git +from manageprojects.test_utils.logs import AssertLogs from manageprojects.tests.base import BaseTestCase from manageprojects.utilities.temp_path import TemporaryDirectory @@ -33,12 +34,14 @@ def test_make_git_diff(self): Path(from_path, 'old_name.txt').write_text(renamed_file_content) Path(to_path, 'new_name.txt').write_text(renamed_file_content) - patch = make_git_diff( - temp_path=main_temp_path, - from_path=from_path, - to_path=to_path, - verbose=True, - ) + with AssertLogs(self, loggers=('manageprojects',)) as logs: + patch = make_git_diff( + temp_path=main_temp_path, + from_path=from_path, + to_path=to_path, + verbose=True, + ) + logs.assert_in('old_name.txt', 'new_name.txt') self.assertIn('diff --git a/file1.txt b/file1.txt', patch) self.assertIn('-Rev 1', patch) self.assertIn('+Rev 2', patch) @@ -104,15 +107,17 @@ def test_generate_template_patch(self): ) self.assertFalse(patch_file_path.exists()) - result = generate_template_patch( - project_path=project_path, - template=str(repo_path), - directory=None, - from_rev=from_rev, - replay_context={}, - cleanup=False, # Keep temp files if this test fails, for better debugging - no_input=True, # No user input in tests ;) - ) + with AssertLogs(self) as logs: + result = generate_template_patch( + project_path=project_path, + template=str(repo_path), + directory=None, + from_rev=from_rev, + replay_context={}, + cleanup=False, # Keep temp files if this test fails, for better debugging + no_input=True, # No user input in tests ;) + ) + logs.assert_in("Call 'cookiecutter'", 'Write patch file') self.assertIsInstance(result, GenerateTemplatePatchResult) self.assertEqual(result.patch_file_path, patch_file_path) diff --git a/manageprojects/tests/test_utilities_pyproject_toml.py b/manageprojects/tests/test_utilities_pyproject_toml.py index 3738be1..7c66c32 100644 --- a/manageprojects/tests/test_utilities_pyproject_toml.py +++ b/manageprojects/tests/test_utilities_pyproject_toml.py @@ -3,6 +3,7 @@ from bx_py_utils.test_utils.datetime import parse_dt from manageprojects.data_classes import ManageProjectsMeta +from manageprojects.test_utils.logs import AssertLogs from manageprojects.tests.base import BaseTestCase from manageprojects.utilities.pyproject_toml import PyProjectToml from manageprojects.utilities.temp_path import TemporaryDirectory @@ -12,8 +13,11 @@ class PyProjectTomlTestCase(BaseTestCase): maxDiff = None def test_basic(self): - with TemporaryDirectory(prefix='test_basic') as temp_path: + with TemporaryDirectory(prefix='test_basic') as temp_path, AssertLogs( + self, loggers=('manageprojects',) + ) as logs: toml = PyProjectToml(project_path=temp_path) + logs.assert_in('Create new pyproject.toml') self.assertEqual(toml.path, temp_path / 'pyproject.toml') self.assertFalse(toml.path.exists()) @@ -196,9 +200,12 @@ def test_basic(self): ) self.assertIsInstance(data.cookiecutter_context, dict) self.assertEqual(type(data.cookiecutter_context), dict) + logs.assert_in('Create new pyproject.toml', 'Read existing pyproject.toml') def test_expand_existing_toml(self): - with TemporaryDirectory(prefix='test_basic') as temp_path: + with TemporaryDirectory(prefix='test_basic') as temp_path, AssertLogs( + self, loggers=('manageprojects',) + ) as logs: file_path = temp_path / 'pyproject.toml' file_path.write_text( inspect.cleandoc( @@ -214,14 +221,16 @@ def test_expand_existing_toml(self): ) ) - toml = PyProjectToml(project_path=temp_path) - toml.init( - revision='abc0001', - dt=parse_dt('2000-01-01T00:00:00+0000'), - template='/foo/bar/template', - directory=None, - ) - toml.save() + with AssertLogs(self, loggers=('manageprojects',)) as logs: + toml = PyProjectToml(project_path=temp_path) + toml.init( + revision='abc0001', + dt=parse_dt('2000-01-01T00:00:00+0000'), + template='/foo/bar/template', + directory=None, + ) + toml.save() + logs.assert_in('Read existing pyproject.toml') self.assert_file_content( file_path, @@ -253,3 +262,4 @@ def test_expand_existing_toml(self): cookiecutter_context=None, ), ) + logs.assert_in('Read existing pyproject.toml') diff --git a/manageprojects/utilities/log_utils.py b/manageprojects/utilities/log_utils.py index 4919d7b..fa1efe8 100644 --- a/manageprojects/utilities/log_utils.py +++ b/manageprojects/utilities/log_utils.py @@ -2,21 +2,25 @@ import logging import tempfile +from bx_py_utils.test_utils.log_utils import RaiseLogUsage -def logger_setup(*, logger_name, level, format, log_filename): + +def logger_setup(*, logger_name, level, format, log_filename, raise_log_output): logger = logging.getLogger(logger_name) is_configured = logger.handlers and logger.level if not is_configured: logger.setLevel(level) - if log_filename: - ch = logging.FileHandler(filename=log_filename) + if raise_log_output: + handler = RaiseLogUsage() + elif log_filename: + handler = logging.FileHandler(filename=log_filename) else: - ch = logging.StreamHandler() - ch.setLevel(level) - ch.setFormatter(logging.Formatter(format)) + handler = logging.StreamHandler() + handler.setLevel(level) + handler.setFormatter(logging.Formatter(format)) - logger.addHandler(ch) + logger.addHandler(handler) def print_log_info(filename): @@ -27,6 +31,7 @@ def log_config( level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s.%(funcName)s %(lineno)d | %(message)s', log_in_file=True, + raise_log_output=False, ): if log_in_file: log_file = tempfile.NamedTemporaryFile( @@ -41,12 +46,14 @@ def log_config( level=level, format=format, log_filename=log_filename, + raise_log_output=raise_log_output, ) logger_setup( logger_name='cookiecutter', level=level, format=format, log_filename=log_filename, + raise_log_output=raise_log_output, ) if log_filename: diff --git a/pyproject.toml b/pyproject.toml index 9ed6c13..c5a6676 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,34 @@ [project] name = "manageprojects" -version = "0.3.3" +version = "0.4.0" description = "Manage Python / Django projects" readme = "README.md" authors = [ {name = 'Jens Diemer', email = 'mamageprojects@jensdiemer.de'} ] requires-python = ">=3.9,<4" +dependencies = [ + "cookiecutter", + "tomlkit", + "bx_py_utils", # https://github.com/boxine/bx_py_utils + "rich", + "typer[all]", # https://github.com/tiangolo/typer +] +[project.optional-dependencies] +dev = [ + "pip-tools", # https://github.com/jazzband/pip-tools/ + "tox", # https://github.com/tox-dev/tox + "coveralls", # https://github.com/TheKevJames/coveralls-python + "darker", # https://github.com/akaihola/pytest-darker + "isort", # https://github.com/pycqa/isort + "flake8", # https://github.com/pycqa/flake8 + "EditorConfig", # https://github.com/editorconfig/editorconfig-core-py + "safety", # https://github.com/pyupio/safety + "mypy", # https://github.com/python/mypy + "tomli", # https://github.com/hukkin/tomli + "twine", # https://github.com/pypa/twine + "poetry-publish", # https://github.com/jedie/poetry-publish +] [project.urls] Documentation = "https://github.com/jedie/manageprojects" @@ -15,8 +37,9 @@ Source = "https://github.com/jedie/manageprojects" [project.scripts] manageprojects = "manageprojects.__main__:main" -[tool.setuptools] -packages = ["manageprojects"] +[tool.setuptools.packages.find] +where = ["."] +include = ["manageprojects*"] [build-system] requires = ["setuptools>=61.0"] @@ -62,7 +85,7 @@ exclude = ''' branch = true source = ['.'] omit = ['.*', '*/tests/*'] -command_line = '-m unittest --locals --verbose' +command_line = '-m unittest --verbose --locals --buffer' [tool.coverage.report] skip_empty = true diff --git a/requirements/develop.txt b/requirements.develop.txt similarity index 95% rename from requirements/develop.txt rename to requirements.develop.txt index 4272c1e..2f36111 100644 --- a/requirements/develop.txt +++ b/requirements.develop.txt @@ -1,8 +1,8 @@ # -# This file is autogenerated by pip-compile with python 3.10 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: # -# pip-compile --allow-unsafe --generate-hashes --output-file=requirements/develop.txt --resolver=backtracking requirements/develop.in requirements/production.in +# pip-compile --allow-unsafe --extra=dev --generate-hashes --output-file=requirements.develop.txt --resolver=backtracking pyproject.toml # arrow==1.2.3 \ --hash=sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1 \ @@ -37,7 +37,7 @@ build==0.9.0 \ bx-py-utils==71 \ --hash=sha256:02150263d58fa280caf5e0afbe99c10470f9b25f0cd69e4a2cc525c875e5ad70 \ --hash=sha256:ceff6b29b41b6a797b87b3006f94d5394b067a551b004567d4ada7e1a6544806 - # via -r requirements/production.in + # via manageprojects (pyproject.toml) cachetools==5.2.0 \ --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db @@ -144,7 +144,7 @@ commonmark==0.9.1 \ cookiecutter==2.1.1 \ --hash=sha256:9f3ab027cec4f70916e28f03470bdb41e637a3ad354b4d65c765d93aad160022 \ --hash=sha256:f3982be8d9c53dac1261864013fdec7f83afd2e42ede6f6dd069c5e149c540d5 - # via -r requirements/production.in + # via manageprojects (pyproject.toml) coverage==6.5.0 \ --hash=sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79 \ --hash=sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a \ @@ -200,7 +200,7 @@ coverage==6.5.0 \ coveralls==3.3.1 \ --hash=sha256:b32a8bb5d2df585207c119d6c01567b81fba690c9c10a753bfe27a335bfc43ea \ --hash=sha256:f42015f31d386b351d4226389b387ae173207058832fbf5c8ec4b40e27b16026 - # via -r requirements/develop.in + # via manageprojects (pyproject.toml) cryptography==38.0.4 \ --hash=sha256:0e70da4bdff7601b0ef48e6348339e490ebfb0cbe638e083c9c41fb49f00c8bd \ --hash=sha256:10652dd7282de17990b88679cb82f832752c4e8237f0c714be518044269415db \ @@ -229,10 +229,10 @@ cryptography==38.0.4 \ --hash=sha256:ca57eb3ddaccd1112c18fc80abe41db443cc2e9dcb1917078e02dfa010a4f353 \ --hash=sha256:ce127dd0a6a0811c251a6cddd014d292728484e530d80e872ad9806cfb1c5b3c # via secretstorage -darker==1.6.0 \ - --hash=sha256:435f82cc7c672e399ecfe6688dc862082f37cac1219508d9b60a50417a21b96b \ - --hash=sha256:d41bed9e852d48b07aeaecfe7f9525afa6a7d5c0ca2a6b0778ebbdd9346ff443 - # via -r requirements/develop.in +darker==1.6.1 \ + --hash=sha256:9f4805f3f105c9107f2c4868bcdadac91f4aa189940e6080e2e5b2f5007bd509 \ + --hash=sha256:adcf696679bdc5db9fefe90aa7ee5c71cda3edac2e0671266f1d5e621bab1686 + # via manageprojects (pyproject.toml) distlib==0.3.6 \ --hash=sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46 \ --hash=sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e @@ -253,17 +253,17 @@ dparse==0.6.2 \ editorconfig==0.12.3 \ --hash=sha256:57f8ce78afcba15c8b18d46b5170848c88d56fd38f05c2ec60dbbfcb8996e89e \ --hash=sha256:6b0851425aa875b08b16789ee0eeadbd4ab59666e9ebe728e526314c4a2e52c1 - # via -r requirements/develop.in -filelock==3.8.2 \ - --hash=sha256:7565f628ea56bfcd8e54e42bdc55da899c85c1abfe1b5bcfd147e9188cebb3b2 \ - --hash=sha256:8df285554452285f79c035efb0c861eb33a4bcfa5b7a137016e32e6a90f9792c + # via manageprojects (pyproject.toml) +filelock==3.9.0 \ + --hash=sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de \ + --hash=sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d # via # tox # virtualenv flake8==6.0.0 \ --hash=sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7 \ --hash=sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181 - # via -r requirements/develop.in + # via manageprojects (pyproject.toml) idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 @@ -274,10 +274,10 @@ importlib-metadata==5.2.0 \ # via # keyring # twine -isort==5.11.3 \ - --hash=sha256:83155ffa936239d986b0f190347a3f2285f42a9b9e1725c89d865b27dd0627e5 \ - --hash=sha256:a8ca25fbfad0f7d5d8447a4314837298d9f6b23aed8618584c894574f626b64b - # via -r requirements/develop.in +isort==5.11.4 \ + --hash=sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6 \ + --hash=sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b + # via manageprojects (pyproject.toml) jaraco-classes==3.2.3 \ --hash=sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158 \ --hash=sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a @@ -383,7 +383,7 @@ mypy==0.991 \ --hash=sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372 \ --hash=sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb \ --hash=sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef - # via -r requirements/develop.in + # via manageprojects (pyproject.toml) mypy-extensions==0.4.3 \ --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 @@ -407,17 +407,21 @@ pep517==0.13.0 \ --hash=sha256:4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b \ --hash=sha256:ae69927c5c172be1add9203726d4b84cf3ebad1edcd5f71fcdc746e66e829f59 # via build +pip==22.3.1 \ + --hash=sha256:65fd48317359f3af8e593943e6ae1506b66325085ea64b706a998c6e83eeaf38 \ + --hash=sha256:908c78e6bc29b676ede1c4d57981d490cb892eb45cd8c214ab6298125119e077 + # via pip-tools pip-tools==6.12.1 \ --hash=sha256:88efb7b29a923ffeac0713e6f23ef8529cc6175527d42b93f73756cc94387293 \ --hash=sha256:f0c0c0ec57b58250afce458e2e6058b1f30a4263db895b7d72fd6311bf1dc6f7 - # via -r requirements/develop.in + # via manageprojects (pyproject.toml) pkginfo==1.9.2 \ --hash=sha256:ac03e37e4d601aaee40f8087f63fc4a2a6c9814dda2c8fa6aab1b1829653bdfa \ --hash=sha256:d580059503f2f4549ad6e4c106d7437356dbd430e2c7df99ee1efe03d75f691e # via twine -platformdirs==2.6.0 \ - --hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca \ - --hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e +platformdirs==2.6.2 \ + --hash=sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490 \ + --hash=sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2 # via # black # tox @@ -429,7 +433,7 @@ pluggy==1.0.0 \ poetry-publish==0.5.0 \ --hash=sha256:41db2e004595051b4bc0ccd09017f5f81e0fa9b5673bb718ab3d26c2da5dd8f3 \ --hash=sha256:7ebc7782ee318c099715518177446122e3a752347cebf8883828e110b7da0e9d - # via -r requirements/develop.in + # via manageprojects (pyproject.toml) pycodestyle==2.10.0 \ --hash=sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053 \ --hash=sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610 @@ -531,7 +535,7 @@ rich==12.6.0 \ --hash=sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e \ --hash=sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0 # via - # -r requirements/production.in + # manageprojects (pyproject.toml) # twine # typer ruamel-yaml==0.17.21 \ @@ -577,11 +581,17 @@ ruamel-yaml-clib==0.2.7 \ safety==2.3.4 \ --hash=sha256:6224dcd9b20986a2b2c5e7acfdfba6bca42bb11b2783b24ed04f32317e5167ea \ --hash=sha256:b9e74e794e82f54d11f4091c5d820c4d2d81de9f953bf0b4f33ac8bc402ae72c - # via -r requirements/develop.in + # via manageprojects (pyproject.toml) secretstorage==3.3.3 \ --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 # via keyring +setuptools==65.6.3 \ + --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \ + --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75 + # via + # pip-tools + # safety shellingham==1.5.0 \ --hash=sha256:72fb7f5c63103ca2cb91b23dee0c71fe8ad6fbfd46418ef17dbe40db51592dad \ --hash=sha256:a8f02ba61b69baaa13facdba62908ca8690a94b8119b69f5ec5873ea85f7391b @@ -606,9 +616,9 @@ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via - # -r requirements/develop.in # black # build + # manageprojects (pyproject.toml) # mypy # pep517 # pyproject-api @@ -616,21 +626,21 @@ tomli==2.0.1 \ tomlkit==0.11.6 \ --hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b \ --hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73 - # via -r requirements/production.in -tox==4.0.16 \ - --hash=sha256:1ba98d4a67b815403e616cf6ded707aeb0fadff10702928f9b990274c9703e9f \ - --hash=sha256:968fc4e27110defdf15972893cb15fe1669f338c8408d8835077462fb07e07fe - # via -r requirements/develop.in + # via manageprojects (pyproject.toml) +tox==4.1.1 \ + --hash=sha256:5d214ce3e480e3b2cce72dbc9e832296387e7311f76b70de4a649636d02e34c9 \ + --hash=sha256:d6b9f9f77796fcb1260d46f12dd4d6ebcc16bb73e72f7a683421b365491a912e + # via manageprojects (pyproject.toml) twine==4.0.2 \ --hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \ --hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8 # via - # -r requirements/develop.in + # manageprojects (pyproject.toml) # poetry-publish typer[all]==0.7.0 \ --hash=sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d \ --hash=sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165 - # via -r requirements/production.in + # via manageprojects (pyproject.toml) typing-extensions==4.4.0 \ --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \ --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e @@ -657,15 +667,3 @@ zipp==3.11.0 \ --hash=sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa \ --hash=sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766 # via importlib-metadata - -# The following packages are considered to be unsafe in a requirements file: -pip==22.3.1 \ - --hash=sha256:65fd48317359f3af8e593943e6ae1506b66325085ea64b706a998c6e83eeaf38 \ - --hash=sha256:908c78e6bc29b676ede1c4d57981d490cb892eb45cd8c214ab6298125119e077 - # via pip-tools -setuptools==65.6.3 \ - --hash=sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54 \ - --hash=sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75 - # via - # pip-tools - # safety diff --git a/requirements/production.txt b/requirements.txt similarity index 97% rename from requirements/production.txt rename to requirements.txt index 04d0d11..d99f836 100644 --- a/requirements/production.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ # -# This file is autogenerated by pip-compile with python 3.10 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: # -# pip-compile --allow-unsafe --generate-hashes --output-file=requirements/production.txt --resolver=backtracking requirements/production.in +# pip-compile --allow-unsafe --generate-hashes --output-file=requirements.txt --resolver=backtracking pyproject.toml # arrow==1.2.3 \ --hash=sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1 \ @@ -15,7 +15,7 @@ binaryornot==0.4.4 \ bx-py-utils==71 \ --hash=sha256:02150263d58fa280caf5e0afbe99c10470f9b25f0cd69e4a2cc525c875e5ad70 \ --hash=sha256:ceff6b29b41b6a797b87b3006f94d5394b067a551b004567d4ada7e1a6544806 - # via -r requirements/production.in + # via manageprojects (pyproject.toml) certifi==2022.12.7 \ --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 @@ -45,7 +45,7 @@ commonmark==0.9.1 \ cookiecutter==2.1.1 \ --hash=sha256:9f3ab027cec4f70916e28f03470bdb41e637a3ad354b4d65c765d93aad160022 \ --hash=sha256:f3982be8d9c53dac1261864013fdec7f83afd2e42ede6f6dd069c5e149c540d5 - # via -r requirements/production.in + # via manageprojects (pyproject.toml) idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 @@ -164,7 +164,7 @@ rich==12.6.0 \ --hash=sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e \ --hash=sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0 # via - # -r requirements/production.in + # manageprojects (pyproject.toml) # typer shellingham==1.5.0 \ --hash=sha256:72fb7f5c63103ca2cb91b23dee0c71fe8ad6fbfd46418ef17dbe40db51592dad \ @@ -181,11 +181,11 @@ text-unidecode==1.3 \ tomlkit==0.11.6 \ --hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b \ --hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73 - # via -r requirements/production.in + # via manageprojects (pyproject.toml) typer[all]==0.7.0 \ --hash=sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d \ --hash=sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165 - # via -r requirements/production.in + # via manageprojects (pyproject.toml) urllib3==1.26.13 \ --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \ --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8 diff --git a/requirements/develop.in b/requirements/develop.in deleted file mode 100644 index dc640f5..0000000 --- a/requirements/develop.in +++ /dev/null @@ -1,12 +0,0 @@ -pip-tools # https://github.com/jazzband/pip-tools/ -tox # https://github.com/tox-dev/tox -coveralls # http://github.com/TheKevJames/coveralls-python -darker # https://github.com/akaihola/pytest-darker -isort # https://github.com/pycqa/isort -flake8 # https://github.com/pycqa/flake8 -EditorConfig # https://github.com/editorconfig/editorconfig-core-py -safety # https://github.com/pyupio/safety -mypy # https://github.com/python/mypy -tomli # https://github.com/hukkin/tomli -twine # https://github.com/pypa/twine -poetry-publish # https://github.com/jedie/poetry-publish diff --git a/requirements/production.in b/requirements/production.in deleted file mode 100644 index cd14c7a..0000000 --- a/requirements/production.in +++ /dev/null @@ -1,5 +0,0 @@ -cookiecutter -tomlkit -bx_py_utils # https://github.com/boxine/bx_py_utils -rich -typer[all] # https://github.com/tiangolo/typer