Coverage for pyquickhelper/sphinxext/sphinx_ext_helper.py: 96%
79 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-03 02:21 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-03 02:21 +0200
1"""
2@file
3@brief Few helpers for :epkg:`Sphinx`.
4"""
5import io
6import logging
7import os
8import pickle
9import urllib.parse as urllib_parse
10import urllib.request as urllib_request
11from urllib.parse import urljoin
12from sphinx.util.inventory import InventoryFile
15def info_blocref(app, doctree, fromdocname, class_name,
16 entry_name, class_node, class_node_list):
17 """
18 Log information with :epkg:`Sphinx`.
20 @param app application (Sphinx)
21 @param doctree document tree
22 @param fromdocname document currently being compiled
23 @param class_name name of the node
24 @param entry_name entry name in ``TITLES``
25 @param class_node class node (@see cl blocref_node)
26 @param class_node_list class node list (@see cl blocreflist)
27 """
28 incconf = f'{class_name}_include_{class_name}s'
29 rows2 = []
30 for node in doctree.traverse(class_node_list):
31 breftag = node.get("breftag", None)
32 rows2.append(f"tag={breftag} do={app.config[incconf]}")
33 if len(rows2) == 0:
34 return False
36 attr_name = f'{class_name}_all_{class_name}s'
37 env = app.builder.env
38 if hasattr(env, attr_name):
39 bloc_list_env = getattr(env, attr_name)
40 else:
41 bloc_list_env = []
43 rows = [" [info_blocref]",
44 f"len(bloc_list_env)={len(bloc_list_env)}", ]
45 rows.extend(rows2)
46 rows.extend([f"fromdocname='{fromdocname}'",
47 f"entry_name='{entry_name}'",
48 f"class_name='{class_name}'",
49 f"class_node='{class_node}'",
50 f"class_node_list='{class_node_list}'",
51 f"doctree='{type(doctree)}'",
52 f"#doctree={len(doctree)}"])
53 message = " ".join(rows)
54 logger = logging.getLogger("info_blocref")
55 logger.info(message)
56 return True
59def sphinx_lang(env, default_value='en'):
60 """
61 Returns the language defined in the configuration file.
63 @param env environment
64 @param default_value default value
65 @return language
66 """
67 if hasattr(env, "settings"):
68 settings = env.settings
69 if hasattr(settings, "language_code"):
70 lang = env.settings.language_code # pragma: no cover
71 else:
72 lang = "en"
73 else:
74 settings = None # pragma: no cover
75 lang = "en" # pragma: no cover
76 return lang
79class TinyNode:
80 """
81 Returned by @see fn traverse.
82 """
84 def __init__(self, parent):
85 """
86 Create a note
88 @param parent parent node
89 """
90 self.parent = parent
93class NodeEnter(TinyNode):
94 """
95 Returned by function @see fn traverse.
96 """
97 pass
100class NodeLeave(TinyNode):
101 """
102 Returned by function @see fn traverse.
103 """
104 pass
107class WrappedNode:
108 """
109 Wraps a docutils node.
110 """
112 def __init__(self, node):
113 self.node = node
116def traverse(node, depth=0):
117 """
118 Enumerates through all children but insert a node whenever
119 digging or leaving the childrens nodes.
121 @param node node (from doctree)
122 @param depth current depth
123 @return enumerate (depth, node)
125 @see cl NodeEnter and @see cl NodeLeave are returned whenever entering or leaving nodes.
126 """
127 if isinstance(node, WrappedNode):
128 node = node.node
129 ne = NodeEnter(node)
130 nl = NodeLeave(node)
131 yield (depth, ne)
132 yield (depth, node)
133 for n in node.children:
134 for r in traverse(n, depth + 1):
135 yield r
136 yield (depth, nl)
139def _get_data(url):
140 """
141 Loads file ``objects.inv`` generated by
142 extension :epkg:`sphinx.ext.intersphinx`.
144 @param url url of documentation, example
145 ``https://pandas.pydata.org/docs/``
146 @return instance of `InventoryFile`
147 """
148 url_inv = urljoin(url, "objects.inv")
149 if urllib_parse.urlparse(url_inv).scheme in ('http', 'https'):
150 user_agent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11' # noqa: E501
151 headers = {'User-Agent': user_agent}
152 req = urllib_request.Request(url_inv, None, headers)
153 resp = urllib_request.urlopen(req)
154 data = resp.read()
155 else:
156 with open(url, 'rb') as fid:
157 data = fid.read()
159 inv = InventoryFile.load(io.BytesIO(data), url, urljoin)
160 return inv
163def get_index(index_url, cache_dir):
164 """
165 Retrieves documentation data for a specific module.
167 @param url url of documentation, example
168 ``https://pandas.pydata.org/docs/``
169 @param cache_dir restore a cached inventory stored with pickle
170 @return instance of `InventoryFile`
171 """
172 if cache_dir is not None:
173 base_file = index_url.replace("/", "_").split(':')[-1] + ".pkl"
174 full_file = os.path.join(cache_dir, base_file)
175 if os.path.exists(full_file):
176 with open(full_file, "rb") as f:
177 return pickle.load(f)
178 index = _get_data(index_url)
179 if cache_dir is not None:
180 with open(full_file, "wb") as f:
181 pickle.dump(index, f)
182 return index