Coverage for sources/librovore/xtnsmgr/configuration.py: 58%
41 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-03 21:59 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-03 21:59 +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''' Extension configuration loading and validation. '''
24from . import __
27ExtensionArguments: __.typx.TypeAlias = __.typx.Annotated[
28 __.cabc.Mapping[ str, __.typx.Any ],
29 __.ddoc.Doc( ''' Arguments to pass to extension/processor. ''' )
30]
31ExtensionConfig: __.typx.TypeAlias = __.typx.Annotated[
32 __.cabc.Mapping[ str, __.typx.Any ],
33 __.ddoc.Doc( ''' Configuration for a single extension/processor. ''' )
34]
37def validate_extension( config: ExtensionConfig ) -> None:
38 ''' Validates single extension configuration. '''
39 name = config.get( 'name' )
40 if not name or not isinstance( name, str ):
41 raise __.ExtensionConfigurationInvalidity(
42 name or '<unnamed>',
43 "Required field 'name' must be a non-empty string" )
44 enabled = config.get( 'enabled', True )
45 if not isinstance( enabled, bool ):
46 raise __.ExtensionConfigurationInvalidity(
47 name, "Field 'enabled' must be a boolean" )
48 package = config.get( 'package' )
49 if package is not None and not isinstance( package, str ):
50 raise __.ExtensionConfigurationInvalidity(
51 name, "Field 'package' must be a string" )
52 arguments = config.get( 'arguments', { } )
53 if not isinstance( arguments, dict ):
54 raise __.ExtensionConfigurationInvalidity(
55 name, "Field 'arguments' must be a dictionary" )
58def extract_inventory_extensions(
59 auxdata: __.Globals
60) -> tuple[ ExtensionConfig, ... ]:
61 ''' Loads and validates inventory extensions configuration. '''
62 return _extract_extension_type( auxdata, 'inventory-extensions' )
65def extract_structure_extensions(
66 auxdata: __.Globals
67) -> tuple[ ExtensionConfig, ... ]:
68 ''' Loads and validates structure extensions configuration. '''
69 return _extract_extension_type( auxdata, 'structure-extensions' )
74def _extract_extension_type(
75 auxdata: __.Globals,
76 extension_type: str
77) -> tuple[ ExtensionConfig, ... ]:
78 ''' Loads and validates extensions of specific type. '''
79 configuration = auxdata.configuration
80 if not configuration: return ( )
81 raw = configuration.get( extension_type, [ ] )
82 if not isinstance( raw, list ):
83 raise __.ExtensionConfigurationInvalidity(
84 '<root>', f"Configuration '{extension_type}' must be a list" )
85 raw = __.typx.cast( list[ __.typx.Any ], raw )
86 extensions: list[ ExtensionConfig ] = [ ]
87 for i, config in enumerate( raw ):
88 if not isinstance( config, dict ):
89 raise __.ExtensionConfigurationInvalidity(
90 f'<{extension_type}[{i}]>',
91 f"{extension_type.title()} configuration must be dict" )
92 typed_config = __.typx.cast( ExtensionConfig, config )
93 validate_extension( typed_config )
94 extensions.append( typed_config )
95 return tuple( extensions )
98def select_active_extensions(
99 extensions: __.cabc.Sequence[ ExtensionConfig ]
100) -> tuple[ ExtensionConfig, ... ]:
101 ''' Filters extensions to only enabled ones. '''
102 return tuple( ext for ext in extensions if ext.get( 'enabled', True ) )
105def select_intrinsic_extensions(
106 extensions: __.cabc.Sequence[ ExtensionConfig ]
107) -> tuple[ ExtensionConfig, ... ]:
108 ''' Filters extensions to only built-in ones (no package field). '''
109 return tuple( ext for ext in extensions if ext.get( 'package' ) is None )
112def extract_extension_arguments(
113 extension: ExtensionConfig
114) -> ExtensionArguments:
115 ''' Extracts arguments dictionary from extension configuration. '''
116 return extension.get( 'arguments', { } )