Coverage for sources/librovore/structures/mkdocs/detection.py: 20%
55 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''' 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 include_snippets: bool = True,
58 ) -> tuple[ __.ContentDocument, ... ]:
59 ''' Extracts documentation content for specified objects. '''
60 theme_value = self.theme if self.theme is not None else __.absent
61 documents = await _extraction.extract_contents(
62 auxdata, source, objects,
63 theme = theme_value,
64 include_snippets = include_snippets )
65 return tuple( documents )
69async def check_mkdocs_yml(
70 auxdata: __.ApplicationGlobals, source: _Url
71) -> bool:
72 ''' Checks if mkdocs.yml exists (indicates MkDocs site). '''
73 url = source._replace( path = f"{source.path}/mkdocs.yml" )
74 return await __.probe_url( auxdata.probe_cache, url )
77async def check_mkdocs_html_markers(
78 auxdata: __.ApplicationGlobals, source: _Url
79) -> float:
80 ''' Checks HTML content for MkDocs-specific markers. '''
81 html_candidates = [
82 source._replace( path = f"{source.path}/" ),
83 source._replace( path = f"{source.path}/index.html" ),
84 ]
85 html_content = None
86 for html_url in html_candidates:
87 try:
88 html_content = await __.retrieve_url_as_text(
89 auxdata.content_cache,
90 html_url, duration_max = 10.0 )
91 except __.DocumentationInaccessibility: continue # noqa: PERF203
92 else: break
93 if not html_content: return 0.0
94 confidence = 0.0
95 html_content_lower = html_content.lower( )
96 if 'mkdocs' in html_content_lower:
97 confidence += 0.3
98 if 'mkdocs-material' in html_content_lower:
99 confidence += 0.2
100 if '_mkdocstrings' in html_content_lower:
101 confidence += 0.2
102 if ( 'name="generator"' in html_content_lower
103 and 'mkdocs' in html_content_lower
104 ):
105 confidence += 0.3
106 return min( confidence, 0.5 )
109async def detect_theme(
110 auxdata: __.ApplicationGlobals, source: _Url
111) -> dict[ str, __.typx.Any ]:
112 ''' Detects MkDocs theme and other metadata. '''
113 theme_metadata: dict[ str, __.typx.Any ] = { }
114 html_candidates = [
115 source._replace( path = f"{source.path}/" ),
116 source._replace( path = f"{source.path}/index.html" ),
117 ]
118 html_content = None
119 for html_url in html_candidates:
120 # TODO: Use probe_url instead of `try`.
121 try:
122 html_content = await __.retrieve_url_as_text(
123 auxdata.content_cache,
124 html_url, duration_max = 10.0 )
125 except __.DocumentationInaccessibility: continue # noqa: PERF203
126 else: break
127 if html_content:
128 html_content_lower = html_content.lower( )
129 if ( 'material' in html_content_lower
130 or 'mkdocs-material' in html_content_lower
131 ): theme_metadata[ 'theme' ] = 'material'
132 elif 'readthedocs' in html_content_lower:
133 theme_metadata[ 'theme' ] = 'readthedocs'
134 return theme_metadata