Coverage for sources/librovore/inventories/sphinx/detection.py: 16%
66 statements
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-29 01:14 +0000
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-29 01:14 +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 details: __.InventoryQueryDetails = (
52 __.InventoryQueryDetails.Documentation ),
53 ) -> tuple[ __.InventoryObject, ... ]:
54 ''' Filters inventory objects from Sphinx source. '''
55 objects = await filter_inventory(
56 source, filters = filters, details = details )
57 return tuple( objects )
60def derive_inventory_url( base_url: _Url ) -> _Url:
61 ''' Derives objects.inv URL from base URL ParseResult. '''
62 new_path = f"{base_url.path}/objects.inv"
63 # TODO: Do not rely on named tuple internals.
64 return base_url._replace( path = new_path )
67def extract_inventory( base_url: _Url ) -> _sphobjinv.Inventory:
68 ''' Extracts and parses Sphinx inventory from URL or file path. '''
69 url = derive_inventory_url( base_url )
70 url_s = url.geturl( )
71 nomargs: __.NominativeArguments = { }
72 match url.scheme:
73 case 'http' | 'https': nomargs[ 'url' ] = url_s
74 case 'file': nomargs[ 'fname_zlib' ] = url.path
75 case _:
76 raise __.InventoryUrlNoSupport(
77 url, component = 'scheme', value = url.scheme )
78 try: return _sphobjinv.Inventory( **nomargs )
79 except ( ConnectionError, OSError, TimeoutError ) as exc:
80 raise __.InventoryInaccessibility(
81 url_s, cause = exc ) from exc
82 except Exception as exc:
83 raise __.InventoryInvalidity( url_s, cause = exc ) from exc
86async def filter_inventory(
87 source: str, /, *,
88 filters: __.cabc.Mapping[ str, __.typx.Any ],
89 details: __.InventoryQueryDetails = (
90 __.InventoryQueryDetails.Documentation ),
91) -> tuple[ __.InventoryObject, ... ]:
92 ''' Extracts and filters inventory objects by structural criteria only. '''
93 domain = filters.get( 'domain', '' ) or __.absent
94 role = filters.get( 'role', '' ) or __.absent
95 priority = filters.get( 'priority', '' ) or __.absent
96 base_url = __.normalize_base_url( source )
97 inventory = extract_inventory( base_url )
98 all_objects: list[ __.InventoryObject ] = [ ]
99 for objct in inventory.objects:
100 if not __.is_absent( domain ) and objct.domain != domain: continue
101 if not __.is_absent( role ) and objct.role != role: continue
102 if not __.is_absent( priority ) and objct.priority != priority:
103 continue
104 obj = format_inventory_object(
105 objct, inventory, source )
106 all_objects.append( obj )
107 return tuple( all_objects )
110class SphinxInventoryObject( __.InventoryObject ):
111 ''' Sphinx-specific inventory object with domain-aware formatting. '''
113 def render_specifics_markdown(
114 self, /, *,
115 reveal_internals: bool = True,
116 ) -> tuple[ str, ... ]:
117 ''' Renders Sphinx specifics with domain and role information. '''
118 lines: list[ str ] = [ ]
119 role = self.specifics.get( 'role' )
120 if role:
121 lines.append( f"- **Type:** {role}" )
122 domain = self.specifics.get( 'domain' )
123 if domain:
124 lines.append( f"- **Domain:** {domain}" )
125 if reveal_internals:
126 priority = self.specifics.get( 'priority' )
127 if priority is not None:
128 lines.append( f"- **Priority:** {priority}" )
129 project = self.specifics.get( 'inventory_project' )
130 if project:
131 lines.append( f"- **Project:** {project}" )
132 version = self.specifics.get( 'inventory_version' )
133 if version:
134 lines.append( f"- **Version:** {version}" )
135 return tuple( lines )
137 def render_specifics_json(
138 self
139 ) -> __.immut.Dictionary[ str, __.typx.Any ]:
140 ''' Renders Sphinx specifics with structured format information. '''
141 return __.immut.Dictionary(
142 role = self.specifics.get( 'role' ),
143 domain = self.specifics.get( 'domain' ),
144 priority = self.specifics.get( 'priority' ),
145 inventory_project = self.specifics.get( 'inventory_project' ),
146 inventory_version = self.specifics.get( 'inventory_version' ),
147 )
150def format_inventory_object(
151 objct: __.typx.Any,
152 inventory: __.typx.Any,
153 location_url: str,
154) -> SphinxInventoryObject:
155 ''' Formats Sphinx inventory object with complete attribution. '''
156 return SphinxInventoryObject(
157 name = objct.name,
158 uri = objct.uri,
159 inventory_type = 'sphinx_objects_inv',
160 location_url = location_url,
161 display_name = (
162 objct.dispname
163 if objct.dispname != '-'
164 else None ),
165 specifics = __.immut.Dictionary(
166 domain = objct.domain,
167 role = objct.role,
168 priority = objct.priority,
169 inventory_project = inventory.project,
170 inventory_version = inventory.version ) )