-
-
Notifications
You must be signed in to change notification settings - Fork 20
/
plugin.py
135 lines (105 loc) · 5.5 KB
/
plugin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import os
import re
import logging
from mkdocs.plugins import BasePlugin
from mkdocs.config import config_options
from mkdocs.exceptions import ConfigurationError
from mkdocs_table_reader_plugin.safe_eval import parse_argkwarg
from mkdocs_table_reader_plugin.readers import READERS
from mkdocs_table_reader_plugin.markdown import fix_indentation
logger = logging.getLogger("mkdocs.plugins")
class TableReaderPlugin(BasePlugin):
config_scheme = (
("base_path", config_options.Choice(['docs_dir','config_dir'], default="config_dir")),
("data_path", config_options.Type(str, default=".")),
("search_page_directory", config_options.Type(bool, default=True)),
("allow_missing_files", config_options.Type(bool, default=False)),
("select_readers", config_options.ListOfItems(config_options.Choice(list(READERS.keys())), default = list(READERS.keys()))),
)
def on_config(self, config, **kwargs):
"""
See https://www.mkdocs.org/user-guide/plugins/#on_config.
Args:
config
Returns:
Config
"""
self.readers = {reader: READERS[reader].set_config_context(mkdocs_config=config, plugin_config=self.config) for reader in self.config.get('select_readers') if reader in self.config.get('select_readers',[])}
plugins = [p for p in config.get("plugins")]
# Plugins required before table-reader
for post_load_plugin in ["markdownextradata"]:
if post_load_plugin in plugins:
if plugins.index("table-reader") > plugins.index(post_load_plugin):
raise ConfigurationError(f"[table-reader]: Incompatible plugin order: Define 'table-reader' before '{post_load_plugin}' in your mkdocs.yml.")
# Plugins required after table-reader
for post_load_plugin in ["macros"]:
if post_load_plugin in plugins:
if plugins.index("table-reader") < plugins.index(post_load_plugin):
raise ConfigurationError(f"[table-reader]: Incompatible plugin order: Define 'table-reader' after '{post_load_plugin}' in your mkdocs.yml.")
if "macros" in config.plugins:
config.plugins['macros'].macros.update(self.readers)
config.plugins['macros'].variables['macros'].update(self.readers)
config.plugins['macros'].env.globals.update(self.readers)
self.external_jinja_engine = True
else:
self.external_jinja_engine = False
def on_pre_page(self, page, config, **kwargs):
"""
See https://www.mkdocs.org/dev-guide/plugins/#on_pre_page.
Args:
page: mkdocs.nav.Page instance
config: global configuration object
Returns:
Page
"""
# store the current page in the plugin config
# because the readers have access to the plugin config, they can know where the current page is
# this way, they can check that directory too
self.config._current_page = page.file.abs_src_path
return page
def on_page_markdown(self, markdown, page, config, files, **kwargs):
"""
Replace jinja tag {{ read_csv() }} in markdown with markdown table.
The page_markdown event is called after the page's markdown is loaded
from file and can be used to alter the Markdown source text.
The meta- data has been stripped off and is available as page.meta
at this point.
https://www.mkdocs.org/user-guide/plugins/#on_page_markdown
Args:
markdown (str): Markdown source text of page as string
page: mkdocs.nav.Page instance
config: global configuration object
site_navigation: global navigation object
Returns:
str: Markdown source text of page as string
"""
if self.external_jinja_engine:
return markdown
for reader in self.readers:
function = self.readers[reader]
# Regex pattern for tags like {{ read_csv(..) }}
# match group 0: to extract any leading whitespace
# match group 1: to extract the arguments (positional and keywords)
tag_pattern = re.compile(
r"( *)\{\{\s+%s\((.+)\)\s+\}\}" % reader, flags=re.IGNORECASE
)
matches = re.findall(tag_pattern, markdown)
for result in matches:
# Deal with indentation
# So we can fix inserting tables.
# f.e. relevant when used inside content tabs
leading_spaces = result[0]
# Safely parse the arguments
pd_args, pd_kwargs = parse_argkwarg(result[1])
# Load the table
# note we use the first valid file paths,
# where we first search the 'data_path' and then the page's directory.
markdown_table = function(*pd_args, **pd_kwargs)
markdown_table = fix_indentation(leading_spaces, markdown_table)
# Insert markdown table
# By replacing only the first occurrence of the regex pattern
# You might insert multiple CSVs with a single reader like read_csv
# Because of the replacement, the next occurrence will be the first match for .sub() again.
# This is always why when allow_missing_files=True we replaced the input tag.
markdown = tag_pattern.sub(markdown_table, markdown, count=1)
return markdown