Skip to content

Commit ba70801

Browse files
Filter warnings, configure logging, format
1 parent 87cf396 commit ba70801

File tree

5 files changed

+39
-51
lines changed

5 files changed

+39
-51
lines changed

shared/python/console.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
import textwrap
1515
import threading
1616

17-
from logging_config import ensure_configured
18-
17+
from logging_config import configure_logging
18+
configure_logging()
1919

2020
# ------------------------------
2121
# CONSTANTS
@@ -122,7 +122,6 @@ def _print_log(message: str, prefix: str = '', color: str = '', output: str = ''
122122
blank_below (bool, optional): Whether to print a blank line below.
123123
wrap_lines (bool, optional): Whether to wrap lines to fit console width.
124124
"""
125-
ensure_configured()
126125

127126
time_str = f' ⌚ {datetime.datetime.now().time()}' if show_time else ''
128127
output_str = f' {output}' if output else ''
@@ -167,9 +166,9 @@ def print_info(msg: str, blank_above: bool = False) -> None:
167166
"""Print an informational message."""
168167
_print_log(msg, 'ℹ️ ', BOLD_B, blank_above = blank_above, level = logging.INFO)
169168

170-
def print_message(msg: str, output: str = '', duration: str = '', blank_above: bool = False) -> None:
169+
def print_message(msg: str, output: str = '', duration: str = '', blank_above: bool = False, blank_below: bool = False) -> None:
171170
"""Print a general message."""
172-
_print_log(msg, 'ℹ️ ', BOLD_G, output, duration, True, blank_above, level = logging.INFO)
171+
_print_log(msg, 'ℹ️ ', BOLD_G, output, duration, True, blank_above, blank_below, level = logging.INFO)
173172

174173
def print_ok(msg: str, output: str = '', duration: str = '', blank_above: bool = False) -> None:
175174
"""Print an OK/success message."""

shared/python/infrastructures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def deploy_infrastructure(self, is_update: bool = False) -> utils.Output:
258258
output = az.run(
259259
f'az deployment group create --name {self.infra.value} --resource-group {self.rg_name} --template-file "{main_bicep_path}" --parameters "{params_file_path}" --query "properties.outputs"',
260260
f"Deployment '{self.infra.value}' succeeded",
261-
f"Deployment '{self.infra.value}' failed."
261+
utils.get_deployment_failure_message(self.infra.value)
262262
)
263263

264264
# ------------------------------

shared/python/logging_config.py

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import logging.config
1616
import os
1717
import threading
18-
import warnings
1918
from pathlib import Path
2019
from typing import Final
2120

@@ -31,28 +30,7 @@
3130
_ENV_FILE_NAME: Final[str] = '.env'
3231

3332
_config_lock = threading.Lock()
34-
_state: dict[str, bool] = {'configured': False, 'dotenv_loaded': False, 'warnings_configured': False}
35-
36-
37-
def _configure_warnings_once() -> None:
38-
"""Configure global warning filters once per process.
39-
40-
This keeps notebook output clean while remaining surgical: we only suppress a
41-
single, well-known IPython message that is frequently triggered when a
42-
`SystemExit` is raised in an interactive context.
43-
"""
44-
45-
with _config_lock:
46-
if _state['warnings_configured']:
47-
return
48-
_state['warnings_configured'] = True
49-
50-
warnings.filterwarnings(
51-
'ignore',
52-
message=r"To exit: use 'exit', 'quit', or Ctrl-D\.",
53-
category=UserWarning,
54-
module=r'IPython\\.core\\.interactiveshell',
55-
)
33+
_state: dict[str, bool] = {'configured': False, 'dotenv_loaded': False}
5634

5735

5836
def _find_env_file() -> Path | None:
@@ -179,13 +157,6 @@ def configure_logging(*, level: str | None = None, force: bool = False) -> None:
179157
_state['configured'] = True
180158

181159

182-
def ensure_configured() -> None:
183-
"""Ensure logging is configured (idempotent)."""
184-
185-
configure_logging(force=False)
186-
_configure_warnings_once()
187-
188-
189160
def is_debug_enabled(logger: logging.Logger | None = None) -> bool:
190161
"""Return True if DEBUG is enabled for the given logger (or root)."""
191162

shared/python/utils.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,48 @@
1212
import secrets
1313
import base64
1414
import inspect
15+
import warnings
1516
from pathlib import Path
1617
from typing import Any
1718

1819
# APIM Samples imports
1920
import azure_resources as az
2021
from apimtypes import APIM_SKU, HTTP_VERB, INFRASTRUCTURE, Endpoints, Output, get_project_root
2122
from console import print_error, print_info, print_message, print_ok, print_plain, print_warning, print_val
23+
from logging_config import get_configured_level_name
24+
25+
# Configure warning filter to suppress IPython exit warnings
26+
warnings.filterwarnings(
27+
'ignore',
28+
message = r"To exit: use 'exit', 'quit', or Ctrl-D\.",
29+
category = UserWarning,
30+
module = r'IPython\.core\.interactiveshell',
31+
)
2232

2333

2434
# ------------------------------
2535
# HELPER FUNCTIONS
2636
# ------------------------------
2737

38+
def get_deployment_failure_message(deployment_name: str) -> str:
39+
"""
40+
Generate a deployment failure message that conditionally includes debug instruction.
41+
42+
Args:
43+
deployment_name (str): The name of the failed deployment.
44+
45+
Returns:
46+
str: Appropriate failure message based on current logging level.
47+
"""
48+
base_message = f"Deployment '{deployment_name}' failed. View deployment details in Azure Portal."
49+
50+
# Only suggest enabling DEBUG logging if it's not already enabled
51+
current_level = get_configured_level_name()
52+
if current_level != 'DEBUG':
53+
return f"{base_message} Enable DEBUG logging in workspace root .env file, then rerun to see details."
54+
55+
return base_message
56+
2857
def build_infrastructure_tags(infrastructure: str | INFRASTRUCTURE, custom_tags: dict | None = None) -> dict:
2958
"""
3059
Build standard tags for infrastructure resource groups, including required 'infrastructure' tag.
@@ -83,7 +112,7 @@ def __init__(self, rg_location: str, deployment: INFRASTRUCTURE, index: int, api
83112
self.index = index
84113
self.apim_sku = apim_sku
85114

86-
print_message('Initializing Infrastructure Notebook Helper with the following parameters:', blank_above=True)
115+
print_message('Initializing Infrastructure Notebook Helper with the following parameters:', blank_above = True, blank_below = True)
87116
print_val('Location', self.rg_location)
88117
print_val('Infrastructure', self.deployment.value)
89118
print_val('Index', self.index)
@@ -166,7 +195,6 @@ def create_infrastructure(self, bypass_infrastructure_check: bool = False, allow
166195
process.wait()
167196

168197
if process.returncode:
169-
print_error('Infrastructure creation failed!')
170198
raise SystemExit(1)
171199

172200
return True
@@ -595,7 +623,7 @@ def create_bicep_deployment_group(rg_name: str, rg_location: str, deployment: st
595623
cmd += ' --debug'
596624

597625
print_plain('\nDeploying bicep...\n')
598-
return az.run(cmd, f"Deployment '{deployment_name}' succeeded", f"Deployment '{deployment_name}' failed.")
626+
return az.run(cmd, f"Deployment '{deployment_name}' succeeded", get_deployment_failure_message(deployment_name))
599627

600628
# TODO: Reconcile this with apimtypes.py get_project_root
601629
def find_project_root() -> str:
@@ -689,7 +717,7 @@ def _prompt_for_infrastructure_update(rg_name: str) -> tuple[bool, int | None]:
689717
- new_index: None if no index change, integer if user selected option 2
690718
"""
691719
print_ok(f'Infrastructure already exists: {rg_name}')
692-
print_plain('🔄 Infrastructure Update Options:\n')
720+
print_plain('🔄 Infrastructure Update Options:\n', blank_above = True)
693721
print_plain(' This infrastructure notebook can update the existing infrastructure.')
694722
print_plain(' Updates are additive and will:')
695723
print_plain(' • Add new APIs and policy fragments defined in the infrastructure')
@@ -751,7 +779,7 @@ def does_infrastructure_exist(infrastructure: INFRASTRUCTURE, index: int, allow_
751779
print_ok(f'Infrastructure already exists: {rg_name}')
752780

753781
if allow_update_option:
754-
print_plain('🔄 Infrastructure Update Options:\n')
782+
print_plain('🔄 Infrastructure Update Options:\n', blank_above = True)
755783
print_plain(' This infrastructure notebook can update the existing infrastructure. Updates are additive and will:\n')
756784
print_plain(' • Add new APIs and policy fragments defined in the infrastructure')
757785
print_plain(' • Update existing infrastructure components to match the template')

tests/python/test_logging_config.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,3 @@ def test_should_print_traceback_from_env(level: str, expected: bool, monkeypatch
9595
monkeypatch.setenv('APIM_SAMPLES_LOG_LEVEL', level)
9696

9797
assert logging_config.should_print_traceback() is expected
98-
99-
100-
def test_configure_warnings_once_is_idempotent(monkeypatch: pytest.MonkeyPatch) -> None:
101-
mock_filter = Mock()
102-
monkeypatch.setattr(logging_config.warnings, 'filterwarnings', mock_filter)
103-
104-
logging_config._configure_warnings_once()
105-
logging_config._configure_warnings_once()
106-
107-
mock_filter.assert_called_once()

0 commit comments

Comments
 (0)