Coverage for sources/mimeogram/__/inscription.py: 100%
63 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 19:46 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 19:46 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Scribes for debugging and logging. '''
24from . import imports as __
25from . import nomina as _nomina
28class Modes( __.enum.Enum ): # TODO: Python 3.11: StrEnum
29 ''' Possible modes for logging output. '''
31 Null = 'null' # suppress library logs
32 Pass = 'pass' # pass library logs to root logger # noqa: S105
33 Rich = 'rich' # print rich library logs to stderr
36class Control( __.immut.DataclassObject ):
37 ''' Logging and debug printing behavior. '''
39 mode: Modes = Modes.Null
40 level: __.typx.Optional[ __.typx.Literal[
41 'debug', 'info', 'warn', 'error', 'critical' # noqa: F821
42 ] ] = None
44 # TODO? Support capture file and stream choice.
47def prepare( control: Control ) -> None:
48 ''' Prepares various scribes in a sensible manner. '''
49 prepare_scribe_icecream( control = control )
50 prepare_scribe_logging( control = control )
53def prepare_scribe_icecream( control: Control ) -> None:
54 ''' Prepares Icecream debug printing. '''
55 from os import environ
56 match environ.get( '_DEVELOPMENT_MODE_', 'FALSE' ).upper( ):
57 case '1' | 'ON' | 'T' | 'TRUE' | 'Y' | 'YES': pass
58 case _:
59 import builtins
60 setattr( builtins, 'ic', _passthrough )
61 return
62 from icecream import ic, install
63 nomargs: dict[ str, __.typx.Any ] = dict(
64 includeContext = True, prefix = 'DEBUG ' )
65 match control.mode:
66 case Modes.Null:
67 ic.configureOutput( **nomargs )
68 ic.disable( )
69 case Modes.Pass:
70 ic.configureOutput( **nomargs )
71 case Modes.Rich: # pragma: no branch
72 from rich.pretty import pretty_repr
73 ic.configureOutput( argToStringFunction = pretty_repr, **nomargs )
74 install( )
77def prepare_scribe_logging( control: Control ) -> None:
78 ''' Prepares standard Python logging. '''
79 # https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library
80 import logging
81 level_name = _discover_inscription_level_name( control )
82 level = getattr( logging, level_name.upper( ) )
83 scribe = __.produce_scribe( _nomina.package_name )
84 scribe.propagate = False # prevent double-logging
85 scribe.setLevel( level )
86 match control.mode:
87 case Modes.Null:
88 scribe.addHandler( logging.NullHandler( ) )
89 case Modes.Pass:
90 scribe.propagate = True
91 case Modes.Rich: # pragma: no branch
92 from rich.console import Console
93 from rich.logging import RichHandler
94 formatter = logging.Formatter( "%(name)s: %(message)s" )
95 handler = RichHandler(
96 console = Console( stderr = True ),
97 rich_tracebacks = True,
98 show_time = False )
99 handler.setFormatter( formatter )
100 scribe.addHandler( handler )
101 scribe.debug( "Logging initialized." )
104def _discover_inscription_level_name( control: Control ) -> str:
105 if control.level is None:
106 from os import environ
107 for envvar_name_base in ( 'INSCRIPTION', 'LOG' ):
108 envvar_name = (
109 "{name}_{base}_LEVEL".format(
110 base = envvar_name_base,
111 name = _nomina.package_name.upper( ) ) )
112 if envvar_name not in environ: continue
113 return environ[ envvar_name ]
114 return 'INFO'
115 return control.level
118def _passthrough( *args: __.typx.Any ) -> __.cabc.Sequence[ __.typx.Any ]:
119 return args