Coverage for sources/mimeogram/__/inscription.py: 100%
63 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-07 04:07 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-07 04:07 +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(
37 metaclass = __.ImmutableStandardDataclass,
38 decorators = ( __.standard_dataclass, ),
39):
40 ''' Logging and debug printing behavior. '''
42 mode: Modes = Modes.Null
43 level: __.typx.Optional[ __.typx.Literal[
44 'debug', 'info', 'warn', 'error', 'critical' # noqa: F821
45 ] ] = None
47 # TODO? Support capture file and stream choice.
50def prepare( control: Control ) -> None:
51 ''' Prepares various scribes in a sensible manner. '''
52 prepare_scribe_icecream( control = control )
53 prepare_scribe_logging( control = control )
56def prepare_scribe_icecream( control: Control ) -> None:
57 ''' Prepares Icecream debug printing. '''
58 from os import environ
59 match environ.get( '_DEVELOPMENT_MODE_', 'FALSE' ).upper( ):
60 case '1' | 'ON' | 'T' | 'TRUE' | 'Y' | 'YES': pass
61 case _:
62 import builtins
63 setattr( builtins, 'ic', _passthrough )
64 return
65 from icecream import ic, install
66 nomargs: dict[ str, __.typx.Any ] = dict(
67 includeContext = True, prefix = 'DEBUG ' )
68 match control.mode:
69 case Modes.Null:
70 ic.configureOutput( **nomargs )
71 ic.disable( )
72 case Modes.Pass:
73 ic.configureOutput( **nomargs )
74 case Modes.Rich: # pragma: no branch
75 from rich.pretty import pretty_repr
76 ic.configureOutput( argToStringFunction = pretty_repr, **nomargs )
77 install( )
80def prepare_scribe_logging( control: Control ) -> None:
81 ''' Prepares standard Python logging. '''
82 # https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library
83 import logging
84 level_name = _discover_inscription_level_name( control )
85 level = getattr( logging, level_name.upper( ) )
86 scribe = __.produce_scribe( _nomina.package_name )
87 scribe.propagate = False # prevent double-logging
88 scribe.setLevel( level )
89 match control.mode:
90 case Modes.Null:
91 scribe.addHandler( logging.NullHandler( ) )
92 case Modes.Pass:
93 scribe.propagate = True
94 case Modes.Rich: # pragma: no branch
95 from rich.console import Console
96 from rich.logging import RichHandler
97 formatter = logging.Formatter( "%(name)s: %(message)s" )
98 handler = RichHandler(
99 console = Console( stderr = True ),
100 rich_tracebacks = True,
101 show_time = False )
102 handler.setFormatter( formatter )
103 scribe.addHandler( handler )
104 scribe.debug( "Logging initialized." )
107def _discover_inscription_level_name( control: Control ) -> str:
108 if control.level is None:
109 from os import environ
110 for envvar_name_base in ( 'INSCRIPTION', 'LOG' ):
111 envvar_name = (
112 "{name}_{base}_LEVEL".format(
113 base = envvar_name_base,
114 name = _nomina.package_name.upper( ) ) )
115 if envvar_name not in environ: continue
116 return environ[ envvar_name ]
117 return 'INFO'
118 return control.level
121def _passthrough( *args: __.typx.Any ) -> __.cabc.Sequence[ __.typx.Any ]:
122 return args