Coverage for sources/librovore/structures/mkdocs/detection.py: 20%
55 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''' MkDocs detection and metadata extraction. '''
24from urllib.parse import ParseResult as _Url
26from . import __
27from . import extraction as _extraction
30_scribe = __.acquire_scribe( __name__ )
33class MkDocsDetection( __.StructureDetection ):
34 ''' Detection result for MkDocs documentation sources. '''
36 source: str
37 has_mkdocs_yml: bool = False
38 normalized_source: str = ''
39 theme: __.typx.Optional[ str ] = None
41 @classmethod
42 async def from_source(
43 selfclass,
44 auxdata: __.ApplicationGlobals,
45 processor: __.Processor,
46 source: str,
47 ) -> __.typx.Self:
48 ''' Constructs detection from source location. '''
49 detection = await processor.detect( auxdata, source )
50 return __.typx.cast( __.typx.Self, detection )
52 async def extract_contents(
53 self,
54 auxdata: __.ApplicationGlobals,
55 source: str,
56 objects: __.cabc.Sequence[ __.InventoryObject ], /,
57 ) -> tuple[ __.ContentDocument, ... ]:
58 ''' Extracts documentation content for specified objects. '''
59 theme_value = self.theme if self.theme is not None else __.absent
60 documents = await _extraction.extract_contents(
61 auxdata, source, objects, theme = theme_value )
62 return tuple( documents )
66async def check_mkdocs_yml(
67 auxdata: __.ApplicationGlobals, source: _Url
68) -> bool:
69 ''' Checks if mkdocs.yml exists (indicates MkDocs site). '''
70 url = source._replace( path = f"{source.path}/mkdocs.yml" )
71 return await __.probe_url( auxdata.probe_cache, url )
74async def check_mkdocs_html_markers(
75 auxdata: __.ApplicationGlobals, source: _Url
76) -> float:
77 ''' Checks HTML content for MkDocs-specific markers. '''
78 html_candidates = [
79 source._replace( path = f"{source.path}/" ),
80 source._replace( path = f"{source.path}/index.html" ),
81 ]
82 html_content = None
83 for html_url in html_candidates:
84 try:
85 html_content = await __.retrieve_url_as_text(
86 auxdata.content_cache,
87 html_url, duration_max = 10.0 )
88 except __.DocumentationInaccessibility: continue # noqa: PERF203
89 else: break
90 if not html_content: return 0.0
91 confidence = 0.0
92 html_content_lower = html_content.lower( )
93 if 'mkdocs' in html_content_lower:
94 confidence += 0.3
95 if 'mkdocs-material' in html_content_lower:
96 confidence += 0.2
97 if '_mkdocstrings' in html_content_lower:
98 confidence += 0.2
99 if ( 'name="generator"' in html_content_lower
100 and 'mkdocs' in html_content_lower
101 ):
102 confidence += 0.3
103 return min( confidence, 0.5 )
106async def detect_theme(
107 auxdata: __.ApplicationGlobals, source: _Url
108) -> dict[ str, __.typx.Any ]:
109 ''' Detects MkDocs theme and other metadata. '''
110 theme_metadata: dict[ str, __.typx.Any ] = { }
111 html_candidates = [
112 source._replace( path = f"{source.path}/" ),
113 source._replace( path = f"{source.path}/index.html" ),
114 ]
115 html_content = None
116 for html_url in html_candidates:
117 # TODO: Use probe_url instead of `try`.
118 try:
119 html_content = await __.retrieve_url_as_text(
120 auxdata.content_cache,
121 html_url, duration_max = 10.0 )
122 except __.DocumentationInaccessibility: continue # noqa: PERF203
123 else: break
124 if html_content:
125 html_content_lower = html_content.lower( )
126 if ( 'material' in html_content_lower
127 or 'mkdocs-material' in html_content_lower
128 ): theme_metadata[ 'theme' ] = 'material'
129 elif 'readthedocs' in html_content_lower:
130 theme_metadata[ 'theme' ] = 'readthedocs'
131 return theme_metadata