Skip to content

Commit

Permalink
add mutually exclusive arg check which is necessary after is_eager ap…
Browse files Browse the repository at this point in the history
…plied to --force-color and --no-color
  • Loading branch information
bckohan committed Jan 27, 2024
1 parent 7e8669b commit b3d0b33
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 64 deletions.
41 changes: 10 additions & 31 deletions django_typer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import contextlib
import inspect
import sys
import os
import typing as t
from copy import deepcopy
from importlib import import_module
Expand All @@ -22,6 +23,10 @@
from django.core.management import get_commands
from django.core.management.base import BaseCommand
from django.utils.translation import gettext as _

if '--no-color' in sys.argv and '--force-color' not in sys.argv:
os.environ["NO_COLOR"] = "1"

from typer import Typer
from typer.core import TyperCommand as CoreTyperCommand
from typer.core import TyperGroup as CoreTyperGroup
Expand Down Expand Up @@ -70,23 +75,6 @@
behavior should align with native django commands
"""

try:
# todo - this monkey patch is required because typer does
# not expose a good way to custom configure the Console objects
# it uses.
from typer import rich_utils
console_getter = rich_utils._get_rich_console
def get_console():
console = console_getter()
ctx = click.get_current_context(silent=True)
if ctx and ctx.params.get('no_color', False):
console._color_system = None
return console
rich_utils._get_rich_console = get_console
except ImportError:
pass


def traceback_config() -> t.Union[bool, t.Dict[str, t.Any]]:
"""
Fetch the rich traceback installation parameters from our settings. By default
Expand Down Expand Up @@ -132,7 +120,7 @@ def _common_options(
force_color: ForceColor = False,
skip_checks: SkipChecks = False,
):
pass # pragma: no cover
pass


# cache common params to avoid this extra work on every command
Expand Down Expand Up @@ -164,14 +152,6 @@ def _get_kwargs(self):
return {"args": self.args, **COMMON_DEFAULTS}


# class _Augment:
# pass


# def augment(cls):
# return type('', (_Augment, cls), {})


class Context(TyperContext):
"""
An extension of the click.Context class that adds a reference to
Expand Down Expand Up @@ -378,11 +358,10 @@ def bind(self, django_command_cls: t.Type["TyperCommand"]):
self.django_command_cls.typer_app.add_typer(deepcopy(self))

def callback(self, *args, **kwargs):
raise NotImplementedError(
_(
"callback is not supported - the function decorated by group() is the callback."
)
)
raise NotImplementedError(_(
"callback is not supported - the function decorated by group() is the "
"callback."
))

def command(
self,
Expand Down
48 changes: 16 additions & 32 deletions django_typer/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,6 @@ def similarity(text1, text2):
TESTS_DIR = Path(__file__).parent


class NoColorMixin:
default_color_system: str

def setUp(self):
# colors in terminal output screw up github CI runs - todo less intrusive
# way around this??
try:
from typer import rich_utils

self.default_color_system = rich_utils.COLOR_SYSTEM
rich_utils.COLOR_SYSTEM = None
except ImportError:
pass
return super().setUp()

def tearDown(self):
try:
from typer import rich_utils

rich_utils.COLOR_SYSTEM = self.default_color_system
except ImportError:
pass
return super().tearDown()


def get_named_arguments(function):
sig = inspect.signature(function)
return [
Expand All @@ -72,14 +47,18 @@ def get_named_arguments(function):
]


def run_command(command, *args, parse_json=True):
def run_command(command, *args, parse_json=True, no_color=True):
cwd = os.getcwd()
try:
env = os.environ.copy()
if no_color:
env['NO_COLOR'] = '1'
os.chdir(manage_py.parent)
result = subprocess.run(
[sys.executable, f"./{manage_py.name}", command, *args],
capture_output=True,
text=True,
env=env
)

# Check the return code to ensure the script ran successfully
Expand All @@ -100,6 +79,11 @@ def run_command(command, *args, parse_json=True):


class BasicTests(TestCase):

def test_common_options_function(self):
from django_typer import _common_options
self.assertIsNone(_common_options())

def test_command_line(self):
self.assertEqual(
run_command("basic", "a1", "a2"),
Expand Down Expand Up @@ -358,7 +342,7 @@ def test_get_command(self):
get_command("callback1", "init")


class CallbackTests(NoColorMixin, TestCase):
class CallbackTests(TestCase):
cmd_name = "callback1"

def test_helps(self, top_level_only=False):
Expand Down Expand Up @@ -601,12 +585,12 @@ def test_settings(self):

def test_color_params(self):
for cmd, args in self.commands:
run_command(cmd, "--no-color", *args)
run_command(cmd, "--no-color", *args, no_color=False)
self.assertEqual(read_django_parameters().get("no_color", False), True)
run_command(cmd, "--force-color", *args)
run_command(cmd, "--force-color", *args, no_color=False)
self.assertEqual(read_django_parameters().get("no_color", True), False)

result = run_command(cmd, "--force-color", "--no-color", *args)
result = run_command(cmd, "--force-color", "--no-color", *args, no_color=False)
self.assertTrue("CommandError" in result)
self.assertTrue("--no-color" in result)
self.assertTrue("--force-color" in result)
Expand Down Expand Up @@ -709,7 +693,7 @@ def test_verbosity(self):
self.assertEqual(read_django_parameters().get("verbosity", None), 0)


class TestHelpPrecedence(NoColorMixin, TestCase):
class TestHelpPrecedence(TestCase):
def test_help_precedence1(self):
buffer = StringIO()
cmd = get_command("help_precedence1", stdout=buffer)
Expand Down Expand Up @@ -783,7 +767,7 @@ def test_help_precedence6(self):
)


class TestGroups(NoColorMixin, TestCase):
class TestGroups(TestCase):
"""
A collection of tests that test complex grouping commands and also that
command inheritance behaves as expected.
Expand Down
21 changes: 20 additions & 1 deletion django_typer/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
"""

import sys
import os
from pathlib import Path
from typing import Annotated, Optional

from django.core.management import CommandError
from django.utils.translation import gettext_lazy as _
from typer import Option

Expand All @@ -22,6 +23,22 @@ def print_version(context, _, value):
sys.exit()


def set_no_color(context, param, value):
"""
A callback to run the get_version() routine of the
command when --version is specified.
"""
if value:
if not context.params.get('force_color', False):
os.environ["NO_COLOR"] = "1"
try:
from rich.console import Console
Console._environ = os.environ
except ImportError:
pass
else:
raise CommandError(_('--no-color and --force-color are mutually exclusive.'))

"""
https://docs.djangoproject.com/en/stable/howto/custom-management-commands/#django.core.management.BaseCommand.get_version
"""
Expand Down Expand Up @@ -103,6 +120,7 @@ def print_version(context, _, value):
"--no-color",
help=_("Don't colorize the command output."),
is_eager=True,
callback=set_no_color,
rich_help_panel=COMMON_PANEL,
),
]
Expand All @@ -116,6 +134,7 @@ def print_version(context, _, value):
Option(
"--force-color",
help=_("Force colorization of the command output."),
is_eager=True,
rich_help_panel=COMMON_PANEL,
),
]
Expand Down

0 comments on commit b3d0b33

Please sign in to comment.