Skip to content

Commit

Permalink
Merge pull request #107 from jedie/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
jedie authored Dec 1, 2023
2 parents 4c790ce + 008d43b commit bab7aa1
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 102 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
__pycache__
/dist/
/coverage.*
*.orig

!.github
!.editorconfig
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ Usage: ./dev-cli.py [OPTIONS] COMMAND [ARGS]...
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────╮
│ check-code-style Check code style by calling darker + flake8 │
│ coverage Run and show coverage.
│ coverage Run tests and show coverage report.
│ fix-code-style Fix code style of all manageprojects source code files via darker │
│ install Run pip-sync and install 'manageprojects' via pip as editable. │
│ mypy Run Mypy (configured in pyproject.toml) │
Expand All @@ -322,6 +322,7 @@ See also git tags: https://github.com/jedie/manageprojects/tags
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)

* [**dev**](https://github.com/jedie/manageprojects/compare/v0.15.4...main)
* 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 Down
9 changes: 9 additions & 0 deletions manageprojects/cli/cli_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from cli_base.cli_tools.verbosity import OPTION_KWARGS_VERBOSE
from cli_base.cli_tools.version_info import print_version
from rich import print # noqa
from rich.console import Console
from rich.traceback import install as rich_traceback_install
from rich_click import RichGroup

import manageprojects
Expand Down Expand Up @@ -422,6 +424,13 @@ def version():

def main():
print_version(manageprojects)
console = Console()
rich_traceback_install(
width=console.size.width, # full terminal width
show_locals=True,
suppress=[click],
max_frames=2,
)

# Execute Click CLI:
cli.name = './cli.py'
Expand Down
142 changes: 52 additions & 90 deletions manageprojects/cli/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

import rich_click as click
from bx_py_utils.path import assert_is_file
from cli_base.cli_tools.dev_tools import run_coverage, run_tox, run_unittest_cli
from cli_base.cli_tools.subprocess_utils import verbose_check_call
from cli_base.cli_tools.test_utils.snapshot import UpdateTestSnapshotFiles
from cli_base.cli_tools.verbosity import OPTION_KWARGS_VERBOSE
from cli_base.cli_tools.version_info import print_version
from rich import print # noqa; noqa
from rich.console import Console
from rich.traceback import install as rich_traceback_install
from rich_click import RichGroup

import manageprojects
Expand Down Expand Up @@ -59,31 +63,15 @@ def cli():


@click.command()
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
def mypy(verbose: bool = True):
@click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE)
def mypy(verbosity: int):
"""Run Mypy (configured in pyproject.toml)"""
verbose_check_call('mypy', '.', cwd=PACKAGE_ROOT, verbose=verbose, exit_on_error=True)
verbose_check_call('mypy', '.', cwd=PACKAGE_ROOT, verbose=verbosity > 0, exit_on_error=True)


cli.add_command(mypy)


@click.command()
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
def coverage(verbose: bool = True):
"""
Run and show coverage.
"""
verbose_check_call('coverage', 'run', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'combine', '--append', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'report', '--fail-under=30', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'xml', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'json', verbose=verbose, exit_on_error=True)


cli.add_command(coverage)


@click.command()
def install():
"""
Expand Down Expand Up @@ -163,7 +151,7 @@ def publish():
"""
Build and upload this project to PyPi
"""
_run_unittest_cli(verbose=False, exit_after_run=False) # Don't publish a broken state
run_unittest_cli(verbose=False, exit_after_run=False) # Don't publish a broken state

publish_package(
module=manageprojects,
Expand All @@ -177,116 +165,79 @@ def publish():

@click.command()
@click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
def fix_code_style(color: bool = True, verbose: bool = False):
@click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE)
def fix_code_style(color: bool, verbosity: int):
"""
Fix code style of all manageprojects source code files via darker
"""
code_style.fix(package_root=PACKAGE_ROOT, color=color, verbose=verbose)
code_style.fix(package_root=PACKAGE_ROOT, color=color, verbose=verbosity > 0)


cli.add_command(fix_code_style)


@click.command()
@click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
def check_code_style(color: bool = True, verbose: bool = False):
@click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE)
def check_code_style(color: bool, verbosity: int):
"""
Check code style by calling darker + flake8
"""
code_style.check(package_root=PACKAGE_ROOT, color=color, verbose=verbose)
code_style.check(package_root=PACKAGE_ROOT, color=color, verbose=verbosity > 0)


cli.add_command(check_code_style)


@click.command()
def update_test_snapshot_files():
@click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE)
def update_test_snapshot_files(verbosity: int):
"""
Update all test snapshot files (by remove and recreate all snapshot files)
"""

def iter_snapshot_files():
yield from PACKAGE_ROOT.rglob('*.snapshot.*')

removed_file_count = 0
for item in iter_snapshot_files():
item.unlink()
removed_file_count += 1
print(f'{removed_file_count} test snapshot files removed... run tests...')

# Just recreate them by running tests:
_run_unittest_cli(
extra_env=dict(
RAISE_SNAPSHOT_ERRORS='0', # Recreate snapshot files without error
),
verbose=False,
exit_after_run=False,
)

new_files = len(list(iter_snapshot_files()))
print(f'{new_files} test snapshot files created, ok.\n')
with UpdateTestSnapshotFiles(root_path=PACKAGE_ROOT, verbose=verbosity > 0):
# Just recreate them by running tests:
run_unittest_cli(
extra_env=dict(
RAISE_SNAPSHOT_ERRORS='0', # Recreate snapshot files without error
),
verbose=verbosity > 1,
exit_after_run=False,
)


cli.add_command(update_test_snapshot_files)


def _run_unittest_cli(extra_env=None, verbose=True, exit_after_run=True):
@click.command() # Dummy command
def test():
"""
Call the origin unittest CLI and pass all args to it.
Run unittests
"""
if extra_env is None:
extra_env = dict()

extra_env.update(
dict(
PYTHONUNBUFFERED='1',
PYTHONWARNINGS='always',
)
)
run_unittest_cli()

args = sys.argv[2:]
if not args:
if verbose:
args = ('--verbose', '--locals', '--buffer')
else:
args = ('--locals', '--buffer')

verbose_check_call(
sys.executable,
'-m',
'unittest',
*args,
timeout=15 * 60,
extra_env=extra_env,
)
if exit_after_run:
sys.exit(0)
cli.add_command(test)


@click.command() # Dummy command
def test():
def coverage():
"""
Run unittests
Run tests and show coverage report.
"""
_run_unittest_cli()
run_coverage()


cli.add_command(test)


def _run_tox():
verbose_check_call(sys.executable, '-m', 'tox', *sys.argv[2:])
sys.exit(0)
cli.add_command(coverage)


@click.command() # Dummy "tox" command
def tox():
"""
Run tox
"""
_run_tox()
run_tox()


cli.add_command(tox)
Expand All @@ -305,13 +256,24 @@ def version():
def main():
print_version(manageprojects)

console = Console()
rich_traceback_install(
width=console.size.width, # full terminal width
show_locals=True,
suppress=[click],
max_frames=2,
)

if len(sys.argv) >= 2:
# Check if we just pass a command call
# Check if we can just pass a command call to origin CLI:
command = sys.argv[1]
if command == 'test':
_run_unittest_cli()
elif command == 'tox':
_run_tox()
command_map = {
'test': run_unittest_cli,
'tox': run_tox,
'coverage': run_coverage,
}
if real_func := command_map.get(command):
real_func(argv=sys.argv, exit_after_run=True)

# Execute Click CLI:
cli()
32 changes: 24 additions & 8 deletions manageprojects/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import os
import unittest.util
from pathlib import Path

from manageprojects.utilities.log_utils import log_config
from bx_py_utils.test_utils.deny_requests import deny_any_real_request
from cli_base.cli_tools.verbosity import MAX_LOG_LEVEL, setup_logging
from rich import print # noqa


# Hacky way to expand the failed test output:
unittest.util._MAX_LENGTH = os.environ.get('UNITTEST_MAX_LENGTH', 300)
def pre_configure_tests() -> None:
print(f'Configure unittests via "load_tests Protocol" from {Path(__file__).relative_to(Path.cwd())}')

# Hacky way to display more "assert"-Context in failing tests:
_MIN_MAX_DIFF = unittest.util._MAX_LENGTH - unittest.util._MIN_DIFF_LEN
unittest.util._MAX_LENGTH = int(os.environ.get('UNITTEST_MAX_LENGTH', 300))
unittest.util._MIN_DIFF_LEN = unittest.util._MAX_LENGTH - _MIN_MAX_DIFF

log_config(
format='%(levelname)s %(name)s.%(funcName)s %(lineno)d | %(message)s',
log_in_file=False,
raise_log_output=True,
)
# Deny any request via docket/urllib3 because tests they should mock all requests:
deny_any_real_request()

# Display DEBUG logs in tests:
setup_logging(verbosity=MAX_LOG_LEVEL)


def load_tests(loader, tests, pattern):
"""
Use unittest "load_tests Protocol" as a hook to setup test environment before running tests.
https://docs.python.org/3/library/unittest.html#load-tests-protocol
"""
pre_configure_tests()
return loader.discover(start_dir=Path(__file__).parent, pattern=pattern)
4 changes: 1 addition & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,6 @@ commands_pre =
pip-sync requirements.dev.txt
commands =
{envpython} -m coverage run --context='{envname}'
{envpython} -m coverage combine --append
{envpython} -m coverage xml
{envpython} -m coverage report
"""


Expand Down Expand Up @@ -165,6 +162,7 @@ applied_migrations = [
"8d0ebe1", # 2023-08-17T18:15:10+02:00
"be3f649", # 2023-08-22T19:36:57+02:00
"385f654", # 2023-10-08T21:09:24+02:00
"d1ed4b1", # 2023-12-01T21:41:29+01:00
]

[manageprojects.cookiecutter_context.cookiecutter]
Expand Down

0 comments on commit bab7aa1

Please sign in to comment.