Coverage for sources/librovore/inventories/sphinx/detection.py: 15%
69 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-06 02:25 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-06 02:25 +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''' Inventory detection implementations. '''
24from urllib.parse import ParseResult as _Url
26import sphobjinv as _sphobjinv
28from . import __
31class SphinxInventoryDetection( __.InventoryDetection ):
32 ''' Detection result for Sphinx inventory sources. '''
34 @classmethod
35 async def from_source(
36 selfclass,
37 auxdata: __.ApplicationGlobals,
38 processor: __.Processor,
39 source: str,
40 ) -> __.typx.Self:
41 ''' Constructs Sphinx inventory detection from source. '''
42 # TODO: Figure out why this is not used.
43 # This is not used in current implementation
44 return selfclass( processor = processor, confidence = 0.0 )
46 async def filter_inventory(
47 self,
48 auxdata: __.ApplicationGlobals,
49 source: str, /, *,
50 filters: __.cabc.Mapping[ str, __.typx.Any ],
51 ) -> tuple[ __.InventoryObject, ... ]:
52 ''' Filters inventory objects from Sphinx source. '''
53 objects = await filter_inventory(
54 source, filters = filters )
55 return tuple( objects )
58def derive_inventory_url( base_url: _Url ) -> _Url:
59 ''' Derives objects.inv URL from base URL ParseResult. '''
60 new_path = f"{base_url.path}/objects.inv"
61 # TODO: Do not rely on named tuple internals.
62 return base_url._replace( path = new_path )
65def extract_inventory( base_url: _Url ) -> _sphobjinv.Inventory:
66 ''' Extracts and parses Sphinx inventory from URL or file path. '''
67 url = derive_inventory_url( base_url )
68 url_s = url.geturl( )
69 nomargs: __.NominativeArguments = { }
70 match url.scheme:
71 case 'http' | 'https': nomargs[ 'url' ] = url_s
72 case 'file': nomargs[ 'fname_zlib' ] = url.path
73 case _:
74 raise __.InventoryUrlNoSupport(
75 url, component = 'scheme', value = url.scheme )
76 try: return _sphobjinv.Inventory( **nomargs )
77 except ( ConnectionError, OSError, TimeoutError ) as exc:
78 raise __.InventoryInaccessibility(
79 url_s, cause = exc ) from exc
80 except Exception as exc:
81 raise __.InventoryInvalidity( url_s, cause = exc ) from exc
84async def filter_inventory(
85 source: str, /, *,
86 filters: __.cabc.Mapping[ str, __.typx.Any ],
87) -> tuple[ __.InventoryObject, ... ]:
88 ''' Extracts and filters inventory objects by structural criteria only. '''
89 domain = filters.get( 'domain', '' ) or __.absent
90 role = filters.get( 'role', '' ) or __.absent
91 priority = filters.get( 'priority', '' ) or __.absent
92 base_url = __.normalize_base_url( source )
93 inventory = extract_inventory( base_url )
94 all_objects: list[ __.InventoryObject ] = [ ]
95 for objct in inventory.objects:
96 if not __.is_absent( domain ) and objct.domain != domain: continue
97 if not __.is_absent( role ) and objct.role != role: continue
98 if not __.is_absent( priority ) and objct.priority != priority:
99 continue
100 obj = format_inventory_object(
101 objct, inventory, source )
102 all_objects.append( obj )
103 return tuple( all_objects )
106class SphinxInventoryObject( __.InventoryObject ):
107 ''' Sphinx-specific inventory object with domain-aware formatting. '''
109 def render_specifics_markdown(
110 self, /, *,
111 reveal_internals: bool = False,
112 ) -> tuple[ str, ... ]:
113 ''' Renders Sphinx specifics with domain and role information. '''
114 lines: list[ str ] = [ ]
115 role = self.specifics.get( 'role' )
116 if role:
117 lines.append( f"- **Type:** {role}" )
118 if reveal_internals:
119 domain = self.specifics.get( 'domain' )
120 if domain:
121 lines.append( f"- **Domain:** {domain}" )
122 priority = self.specifics.get( 'priority' )
123 if priority is not None:
124 lines.append( f"- **Priority:** {priority}" )
125 project = self.specifics.get( 'inventory_project' )
126 if project:
127 lines.append( f"- **Project:** {project}" )
128 version = self.specifics.get( 'inventory_version' )
129 if version:
130 lines.append( f"- **Version:** {version}" )
131 return tuple( lines )
133 def render_specifics_json(
134 self, /, *,
135 reveal_internals: bool = False,
136 ) -> __.immut.Dictionary[ str, __.typx.Any ]:
137 ''' Renders Sphinx specifics with structured format information. '''
138 base_data = { 'role': self.specifics.get( 'role' ) }
139 if reveal_internals:
140 base_data.update( {
141 'domain': self.specifics.get( 'domain' ),
142 'priority': self.specifics.get( 'priority' ),
143 'inventory_project': self.specifics.get( 'inventory_project' ),
144 'inventory_version': self.specifics.get( 'inventory_version' ),
145 } )
146 return __.immut.Dictionary( base_data )
149def format_inventory_object(
150 objct: __.typx.Any,
151 inventory: __.typx.Any,
152 location_url: str,
153) -> SphinxInventoryObject:
154 ''' Formats Sphinx inventory object with complete attribution. '''
155 return SphinxInventoryObject(
156 name = objct.name,
157 uri = objct.uri,
158 inventory_type = 'sphinx_objects_inv',
159 location_url = location_url,
160 display_name = (
161 objct.dispname
162 if objct.dispname != '-'
163 else None ),
164 specifics = __.immut.Dictionary(
165 domain = objct.domain,
166 role = objct.role,
167 priority = objct.priority,
168 inventory_project = inventory.project,
169 inventory_version = inventory.version ) )