Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve terminal logic #990

Merged
merged 1 commit into from
Oct 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/hatch/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ def hatch(ctx: click.Context, env_name, project, verbose, quiet, color, interact
elif os.environ.get(AppEnvVars.FORCE_COLOR) == '1':
color = True

if interactive is None:
interactive = not running_in_ci()
if interactive is None and running_in_ci():
interactive = False

app = Application(ctx.exit, verbose - quiet, color, interactive)

Expand Down
2 changes: 1 addition & 1 deletion src/hatch/cli/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
class Application(Terminal):
def __init__(self, exit_func, *args, **kwargs):
super().__init__(*args, **kwargs)
self.platform = Platform(self.display_raw)
self.platform = Platform(self.output)
self.__exit_func = exit_func

self.config_file = ConfigFile()
Expand Down
72 changes: 48 additions & 24 deletions src/hatch/cli/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(
self,
console: Console,
*,
tty: bool,
is_interactive: bool,
verbosity: int,
spinner_style: str,
waiting_style: Style,
Expand All @@ -49,7 +49,7 @@ def __init__(
finalizer: Callable,
):
self.__console = console
self.__tty = tty
self.__is_interactive = is_interactive
self.__verbosity = verbosity
self.__spinner_style = spinner_style
self.__waiting_style = waiting_style
Expand Down Expand Up @@ -85,7 +85,7 @@ def __enter__(self) -> BorrowedStatus:
return self

message, _ = self.__messages[-1]
if not self.__tty:
if not self.__is_interactive:
self.__output(message)
return self

Expand All @@ -108,7 +108,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):

self.__output(Text(final_text, style=self.__success_style))

if not self.__tty:
if not self.__is_interactive:
return

self.__status.stop()
Expand All @@ -134,9 +134,9 @@ def __output(self, text):
class Terminal:
def __init__(self, verbosity, enable_color, interactive):
self.verbosity = verbosity
self.interactive = interactive
self.console = Console(
force_terminal=enable_color,
force_interactive=interactive,
no_color=enable_color is False,
markup=False,
emoji=False,
Expand All @@ -157,6 +157,28 @@ def __init__(self, verbosity, enable_color, interactive):
# Chosen as the default since it's compatible everywhere and looks nice
self._style_spinner = 'simpleDotsScrolling'

@cached_property
def kv_separator(self) -> Style:
return self.style_warning('->')

def style_success(self, text: str) -> Text:
return Text(text, style=self._style_level_success)

def style_error(self, text: str) -> Text:
return Text(text, style=self._style_level_error)

def style_warning(self, text: str) -> Text:
return Text(text, style=self._style_level_warning)

def style_waiting(self, text: str) -> Text:
return Text(text, style=self._style_level_waiting)

def style_info(self, text: str) -> Text:
return Text(text, style=self._style_level_info)

def style_debug(self, text: str) -> Text:
return Text(text, style=self._style_level_debug)

def initialize_styles(self, styles: dict): # no cov
# Lazily display errors so that they use the correct style
errors = []
Expand Down Expand Up @@ -194,31 +216,31 @@ def display_error(self, text='', *, stderr=True, indent=None, link=None, **kwarg
if self.verbosity < -2: # noqa: PLR2004
return

self.output(text, self._style_level_error, stderr=stderr, indent=indent, link=link, **kwargs)
self._output(text, self._style_level_error, stderr=stderr, indent=indent, link=link, **kwargs)

def display_warning(self, text='', *, stderr=True, indent=None, link=None, **kwargs):
if self.verbosity < -1:
return

self.output(text, self._style_level_warning, stderr=stderr, indent=indent, link=link, **kwargs)
self._output(text, self._style_level_warning, stderr=stderr, indent=indent, link=link, **kwargs)

def display_info(self, text='', *, stderr=True, indent=None, link=None, **kwargs):
if self.verbosity < 0:
return

self.output(text, self._style_level_info, stderr=stderr, indent=indent, link=link, **kwargs)
self._output(text, self._style_level_info, stderr=stderr, indent=indent, link=link, **kwargs)

def display_success(self, text='', *, stderr=True, indent=None, link=None, **kwargs):
if self.verbosity < 0:
return

self.output(text, self._style_level_success, stderr=stderr, indent=indent, link=link, **kwargs)
self._output(text, self._style_level_success, stderr=stderr, indent=indent, link=link, **kwargs)

def display_waiting(self, text='', *, stderr=True, indent=None, link=None, **kwargs):
if self.verbosity < 0:
return

self.output(text, self._style_level_waiting, stderr=stderr, indent=indent, link=link, **kwargs)
self._output(text, self._style_level_waiting, stderr=stderr, indent=indent, link=link, **kwargs)

def display_debug(self, text='', level=1, *, stderr=True, indent=None, link=None, **kwargs):
if not 1 <= level <= 3: # noqa: PLR2004
Expand All @@ -227,7 +249,7 @@ def display_debug(self, text='', level=1, *, stderr=True, indent=None, link=None
elif self.verbosity < level:
return

self.output(text, self._style_level_debug, stderr=stderr, indent=indent, link=link, **kwargs)
self._output(text, self._style_level_debug, stderr=stderr, indent=indent, link=link, **kwargs)

def display_mini_header(self, text, *, stderr=False, indent=None, link=None):
if self.verbosity < 0:
Expand All @@ -243,7 +265,10 @@ def display_header(self, title='', *, stderr=False):
def display_markdown(self, text, **kwargs): # no cov
from rich.markdown import Markdown

self.display_raw(Markdown(text), **kwargs)
self.output(Markdown(text), **kwargs)

def display_pair(self, key, value):
self.output(self.style_success(key), self.kv_separator, value)

def display_table(self, title, columns, *, show_lines=False, column_options=None, force_ascii=False, num_rows=0):
from rich.table import Table
Expand Down Expand Up @@ -284,7 +309,7 @@ def display_table(self, title, columns, *, show_lines=False, column_options=None
def status(self) -> BorrowedStatus:
return BorrowedStatus(
self.console,
tty=self.interactive and self.console.is_terminal,
is_interactive=self.console.is_interactive,
verbosity=self.verbosity,
spinner_style=self._style_spinner,
waiting_style=self._style_level_waiting,
Expand All @@ -296,30 +321,29 @@ def status(self) -> BorrowedStatus:
def status_if(self, *args, condition: bool, **kwargs) -> TerminalStatus:
return self.status(*args, **kwargs) if condition else NullStatus()

def output(self, text='', style=None, *, stderr=False, indent=None, link=None, **kwargs):
kwargs.setdefault('overflow', 'ignore')
kwargs.setdefault('no_wrap', True)
kwargs.setdefault('crop', False)

def _output(self, text='', style=None, *, stderr=False, indent=None, link=None, **kwargs):
if indent:
text = indent_text(text, indent)

if link:
style = style.update_link(self.platform.format_file_uri(link))

self.output(text, stderr=stderr, style=style, **kwargs)

def output(self, *args, stderr=False, **kwargs):
kwargs.setdefault('overflow', 'ignore')
kwargs.setdefault('no_wrap', True)
kwargs.setdefault('crop', False)

if not stderr:
self.console.print(text, style=style, **kwargs)
self.console.print(*args, **kwargs)
else:
self.console.stderr = True
try:
self.console.print(text, style=style, **kwargs)
self.console.print(*args, **kwargs)
finally:
self.console.stderr = False

def display_raw(self, text, **kwargs):
# No styling
self.console.print(text, overflow='ignore', no_wrap=True, crop=False, **kwargs)

@staticmethod
def prompt(text, **kwargs):
return click.prompt(text, **kwargs)
Expand Down
3 changes: 2 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def isolation() -> Generator[Path, None, None]:

with d.as_cwd(default_env_vars):
os.environ.pop(AppEnvVars.ENV_ACTIVE, None)
os.environ.pop(AppEnvVars.FORCE_COLOR, None)
yield d


Expand Down Expand Up @@ -251,7 +252,7 @@ def devpi(tmp_path_factory, worker_id):
for _ in range(60):
output = subprocess.check_output(['docker', 'logs', 'hatch-devpi']).decode('utf-8')
if f'Serving index {dp.user}/{dp.index}' in output:
time.sleep(2)
time.sleep(5)
break

time.sleep(1)
Expand Down