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

Bump tox from 4.11.4 to 4.12.0 #1606

Merged
merged 5 commits into from
Jan 16, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/1606.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Updated tox from 4.11.4 to 4.12.0.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ dev = [
"pytest == 7.4.4",
"pytest-xdist == 3.5.0",
"setuptools_scm == 8.0.4",
"tox == 4.11.4",
"tox == 4.12.0",
]
docs = [
"furo == 2023.9.10",
Expand Down
7 changes: 4 additions & 3 deletions src/briefcase/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pathlib import Path

from briefcase.cmdline import parse_cmdline
from briefcase.console import Console, Log
from briefcase.console import Console, Log, Printer
from briefcase.exceptions import (
BriefcaseError,
BriefcaseTestSuiteFailure,
Expand All @@ -15,8 +15,9 @@
def main():
result = 0
command = None
logger = Log()
console = Console()
printer = Printer()
console = Console(printer=printer)
logger = Log(printer=printer)
Comment on lines +18 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Printer doesn't really need to be exposed up here in main; a console initialization function could wrap all this (and future logic) and return just the console and logger. (although, mostly indifferent if this happens now...or when future logic is added)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly - but that likely requires a either more comprehensive refactor so that Log and Console are more closely bound (or even merged entirely); introducing another wrapper object, or a single purpose "construct both" method, that really only avoids creating the printer. At least for now, my inclination is to leave this as is, and be explicit about the fact that there's a single printer, which both the log and the console may write to.

try:
Command, extra_cmdline = parse_cmdline(sys.argv[1:])
command = Command(logger=logger, console=console)
Expand Down
96 changes: 55 additions & 41 deletions src/briefcase/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,32 +71,47 @@ class RichConsoleHighlighter(RegexHighlighter):
class Printer:
"""Interface for printing and managing output to the console and/or log."""

# Console to manage console output.
console = RichConsole(
highlighter=RichConsoleHighlighter(), emoji=False, soft_wrap=True
)
def __init__(self, log_width=180):
"""Create an interface for printing and managing output to the console and/or
log.

# Console to record all logging to a buffer while not printing anything to the console.
# We need to be wide enough to render `sdkmanager --list_installed` output without
# line wrapping.
LOG_FILE_WIDTH = 180
# Rich only records what's being logged if it is actually written somewhere;
# writing to /dev/null allows Rich to do so without needing to print the logs
# in the console or save them to file before it is known a file is wanted.
dev_null = open(os.devnull, "w", encoding="utf-8", errors="ignore")
log = RichConsole(
file=dev_null,
record=True,
width=LOG_FILE_WIDTH,
no_color=True,
markup=False,
emoji=False,
highlight=False,
soft_wrap=True,
)
The default width is wide enough to render the output of ``sdkmanager
--list_installed`` without line wrapping.

@classmethod
def __call__(cls, *messages, stack_offset=5, show=True, **kwargs):
:param width: The width at which content should be wrapped.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: the uninitiated may be misled by this naming and description of width. It sounds like it'll affect both what's printed to the console and the log....while it's only relevant to the log.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed- I've tweaked the naming.

"""
self.log_width = log_width

# A wrapper around the console
self.console = RichConsole(
highlighter=RichConsoleHighlighter(),
emoji=False,
soft_wrap=True,
)

# Rich only records what's being logged if it is actually written somewhere;
# writing to /dev/null allows Rich to do so without needing to print the
# logs in the console or save them to file before it is known a file is
# wanted.
self.dev_null = open(os.devnull, "w", encoding="utf-8", errors="ignore")
self.log = RichConsole(
file=self.dev_null,
record=True,
width=self.log_width,
force_interactive=False,
force_terminal=False,
no_color=True,
color_system=None,
markup=False,
emoji=False,
highlight=False,
soft_wrap=True,
)

def __del__(self):
self.dev_null.close()

def __call__(self, *messages, stack_offset=5, show=True, **kwargs):
"""Entry point for all printing to the console and the log.

The log records all content that is printed whether it is shown in the console
Expand All @@ -111,23 +126,22 @@ def __call__(cls, *messages, stack_offset=5, show=True, **kwargs):
most uses are 5 levels deep from the actual logging.
"""
if show:
cls.to_console(*messages, **kwargs)
cls.to_log(*messages, stack_offset=stack_offset, **kwargs)
self.to_console(*messages, **kwargs)
self.to_log(*messages, stack_offset=stack_offset, **kwargs)

@classmethod
def to_console(cls, *messages, **kwargs):
def to_console(self, *messages, **kwargs):
"""Write only to the console and skip writing to the log."""
cls.console.print(*messages, **kwargs)
self.console.print(*messages, **kwargs)

@classmethod
def to_log(cls, *messages, stack_offset=5, **kwargs):
def to_log(self, *messages, stack_offset=5, **kwargs):
"""Write only to the log and skip writing to the console."""
cls.log.log(*map(sanitize_text, messages), _stack_offset=stack_offset, **kwargs)
self.log.log(
*map(sanitize_text, messages), _stack_offset=stack_offset, **kwargs
)

@classmethod
def export_log(cls):
def export_log(self):
"""Export the text of the entire log; the log is also cleared."""
return cls.log.export_text()
return self.log.export_text()


class RichLoggingStream:
Expand Down Expand Up @@ -162,8 +176,8 @@ class Log:
# subdirectory of command.base_path to store log files
LOG_DIR = "logs"

def __init__(self, printer=Printer(), verbosity: LogLevel = LogLevel.INFO):
self.print = printer
def __init__(self, printer=None, verbosity: LogLevel = LogLevel.INFO):
self.print = Printer() if printer is None else printer
# --verbosity flag: 0 for info, 1 for debug, 2 for deep debug
self.verbosity = verbosity
# --log flag to force logfile creation
Expand Down Expand Up @@ -390,7 +404,7 @@ def _build_log(self, command):
f"{thread} traceback:",
Traceback(
trace=stacktrace,
width=self.print.LOG_FILE_WIDTH,
width=self.print.log_width,
show_locals=True,
),
new_line_start=True,
Expand Down Expand Up @@ -447,11 +461,11 @@ def _build_log(self, command):


class Console:
def __init__(self, printer=Printer(), enabled=True):
def __init__(self, printer=None, enabled=True):
self.enabled = enabled
self.print = printer
self.print = Printer() if printer is None else printer
# Use Rich's input() to read from user
self.input = printer.console.input
self.input = self.print.console.input
self._wait_bar: Progress = None
# Signal that Rich is dynamically controlling the console output. Therefore,
# all output must be printed to the screen by Rich to prevent corruption of
Expand Down
15 changes: 10 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import inspect
import os
import subprocess
import time
from unittest.mock import ANY

import pytest

from briefcase.config import AppConfig
from briefcase.console import Printer

from .utils import create_file


def pytest_sessionfinish(session, exitstatus):
"""When pytest is wrapping up, close the /dev/null file handle for the logfile Rich
Console to avoid spurious ResourceWarning errors."""
Printer.dev_null.close()
def pytest_sessionstart(session):
"""Ensure that tests don't use a color console."""

os.environ["TERM"] = "dumb"
os.environ["NO_COLOR"] = "1"
try:
del os.environ["FORCE_COLOR"]
except KeyError:
pass


# alias so fixtures can still use them
Expand Down