mkdocs-include-markdown-plugin 7.0.1__tar.gz → 7.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/PKG-INFO +35 -3
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/README.md +34 -2
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/pyproject.toml +1 -1
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/cache.py +49 -24
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/config.py +9 -0
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/directive.py +47 -27
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/event.py +45 -31
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/plugin.py +15 -22
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/process.py +51 -23
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/.gitignore +0 -0
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/LICENSE +0 -0
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/__init__.py +0 -0
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/files_watcher.py +0 -0
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/logger.py +0 -0
- {mkdocs_include_markdown_plugin-7.0.1 → mkdocs_include_markdown_plugin-7.1.2}/src/mkdocs_include_markdown_plugin/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: mkdocs-include-markdown-plugin
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.1.2
|
|
4
4
|
Summary: Mkdocs Markdown includer plugin.
|
|
5
5
|
Project-URL: Source, https://github.com/mondeja/mkdocs-include-markdown-plugin
|
|
6
6
|
Project-URL: Documentation, https://github.com/mondeja/mkdocs-include-markdown-plugin#documentation
|
|
@@ -135,14 +135,46 @@ plugins:
|
|
|
135
135
|
cache: 600
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
In order to use this feature, the dependency [platformdirs] must be installed
|
|
139
|
-
|
|
138
|
+
In order to use this feature, the dependency [platformdirs] must be installed
|
|
139
|
+
or the setting [`cache_dir`](#cache_dir) must be defined. You can include
|
|
140
|
+
[platformdirs] in the installation of the plugin adding the `cache` extra:
|
|
140
141
|
|
|
141
142
|
```txt
|
|
142
143
|
# requirements.txt
|
|
143
144
|
mkdocs-include-markdown-plugin[cache]
|
|
144
145
|
```
|
|
145
146
|
|
|
147
|
+
<!-- mdpo-disable-next-line -->
|
|
148
|
+
|
|
149
|
+
#### `cache_dir`
|
|
150
|
+
|
|
151
|
+
Directory where cached HTTP requests will be stored. If set, [platformdirs] is not
|
|
152
|
+
needed to be installed to use [`cache`](#cache).
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
plugins:
|
|
156
|
+
- include-markdown:
|
|
157
|
+
cache: 600
|
|
158
|
+
cache_dir: ./mkdocs-include-markdown-cache
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
A _.gitignore_ file will be added to the cache directory if not exists to avoid
|
|
162
|
+
committing the cache files.
|
|
163
|
+
|
|
164
|
+
<!-- mdpo-disable-next-line -->
|
|
165
|
+
|
|
166
|
+
#### `directives`
|
|
167
|
+
|
|
168
|
+
Customize the names of the directives.
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
plugins:
|
|
172
|
+
- include-markdown:
|
|
173
|
+
directives:
|
|
174
|
+
include-markdown: include-md
|
|
175
|
+
include: replace
|
|
176
|
+
```
|
|
177
|
+
|
|
146
178
|
### Reference
|
|
147
179
|
|
|
148
180
|
This plugin provides two directives, one to include Markdown files and another
|
|
@@ -101,14 +101,46 @@ plugins:
|
|
|
101
101
|
cache: 600
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
In order to use this feature, the dependency [platformdirs] must be installed
|
|
105
|
-
|
|
104
|
+
In order to use this feature, the dependency [platformdirs] must be installed
|
|
105
|
+
or the setting [`cache_dir`](#cache_dir) must be defined. You can include
|
|
106
|
+
[platformdirs] in the installation of the plugin adding the `cache` extra:
|
|
106
107
|
|
|
107
108
|
```txt
|
|
108
109
|
# requirements.txt
|
|
109
110
|
mkdocs-include-markdown-plugin[cache]
|
|
110
111
|
```
|
|
111
112
|
|
|
113
|
+
<!-- mdpo-disable-next-line -->
|
|
114
|
+
|
|
115
|
+
#### `cache_dir`
|
|
116
|
+
|
|
117
|
+
Directory where cached HTTP requests will be stored. If set, [platformdirs] is not
|
|
118
|
+
needed to be installed to use [`cache`](#cache).
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
plugins:
|
|
122
|
+
- include-markdown:
|
|
123
|
+
cache: 600
|
|
124
|
+
cache_dir: ./mkdocs-include-markdown-cache
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
A _.gitignore_ file will be added to the cache directory if not exists to avoid
|
|
128
|
+
committing the cache files.
|
|
129
|
+
|
|
130
|
+
<!-- mdpo-disable-next-line -->
|
|
131
|
+
|
|
132
|
+
#### `directives`
|
|
133
|
+
|
|
134
|
+
Customize the names of the directives.
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
plugins:
|
|
138
|
+
- include-markdown:
|
|
139
|
+
directives:
|
|
140
|
+
include-markdown: include-md
|
|
141
|
+
include: replace
|
|
142
|
+
```
|
|
143
|
+
|
|
112
144
|
### Reference
|
|
113
145
|
|
|
114
146
|
This plugin provides two directives, one to include Markdown files and another
|
|
@@ -4,15 +4,9 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import hashlib
|
|
6
6
|
import os
|
|
7
|
+
import stat
|
|
7
8
|
import time
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
try:
|
|
11
|
-
from platformdirs import user_data_dir
|
|
12
|
-
except ImportError: # pragma: no cover
|
|
13
|
-
CACHE_AVAILABLE = False
|
|
14
|
-
else:
|
|
15
|
-
CACHE_AVAILABLE = True
|
|
9
|
+
from importlib.util import find_spec
|
|
16
10
|
|
|
17
11
|
|
|
18
12
|
class Cache:
|
|
@@ -37,13 +31,19 @@ class Cache:
|
|
|
37
31
|
return hashlib.blake2b(url.encode(), digest_size=16).digest().hex()
|
|
38
32
|
|
|
39
33
|
def read_file(self, fpath: str, encoding: str = 'utf-8') -> str: # noqa: D102
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
f = open(fpath, encoding=encoding) # noqa: SIM115
|
|
35
|
+
content = f.read().split('\n', 1)[1]
|
|
36
|
+
f.close()
|
|
37
|
+
return content
|
|
42
38
|
|
|
43
39
|
def get_(self, url: str, encoding: str = 'utf-8') -> str | None: # noqa: D102
|
|
44
40
|
key = self.generate_unique_key_from_url(url)
|
|
45
41
|
fpath = os.path.join(self.cache_dir, key)
|
|
46
|
-
|
|
42
|
+
try:
|
|
43
|
+
is_file = stat.S_ISREG(os.stat(fpath).st_mode)
|
|
44
|
+
except (FileNotFoundError, OSError): # pragma: no cover
|
|
45
|
+
return None
|
|
46
|
+
if is_file:
|
|
47
47
|
creation_time = self.get_creation_time_from_fpath(fpath)
|
|
48
48
|
if time.time() < creation_time + self.expiration_seconds:
|
|
49
49
|
return self.read_file(fpath, encoding=encoding)
|
|
@@ -61,27 +61,52 @@ class Cache:
|
|
|
61
61
|
def clean(self) -> None:
|
|
62
62
|
"""Clean expired entries from the cache."""
|
|
63
63
|
for fname in os.listdir(self.cache_dir):
|
|
64
|
+
if fname == '.gitignore':
|
|
65
|
+
continue
|
|
64
66
|
fpath = os.path.join(self.cache_dir, fname)
|
|
65
67
|
creation_time = self.get_creation_time_from_fpath(fpath)
|
|
66
68
|
if time.time() > creation_time + self.expiration_seconds:
|
|
67
69
|
os.remove(fpath)
|
|
68
70
|
|
|
69
71
|
|
|
70
|
-
def get_cache_directory() -> str | None:
|
|
71
|
-
"""Get
|
|
72
|
-
if
|
|
73
|
-
return
|
|
72
|
+
def get_cache_directory(cache_dir: str) -> str | None:
|
|
73
|
+
"""Get cache directory."""
|
|
74
|
+
if cache_dir:
|
|
75
|
+
return cache_dir
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
os.makedirs(cache_dir)
|
|
77
|
+
if not is_platformdirs_installed():
|
|
78
|
+
return None
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
try:
|
|
81
|
+
from platformdirs import user_data_dir
|
|
82
|
+
except ImportError:
|
|
83
|
+
return None
|
|
84
|
+
else:
|
|
85
|
+
return user_data_dir('mkdocs-include-markdown-plugin')
|
|
80
86
|
|
|
81
87
|
|
|
82
|
-
def initialize_cache(expiration_seconds: int) -> Cache | None:
|
|
88
|
+
def initialize_cache(expiration_seconds: int, cache_dir: str) -> Cache | None:
|
|
83
89
|
"""Initialize a cache instance."""
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
cache_directory = get_cache_directory(cache_dir)
|
|
91
|
+
|
|
92
|
+
if cache_directory is None:
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
os.makedirs(cache_directory, exist_ok=True)
|
|
96
|
+
|
|
97
|
+
# Add a `.gitignore` file to prevent the cache directory from being
|
|
98
|
+
# included in the repository. This is needed because the cache directory
|
|
99
|
+
# can be configured as a relative path with `cache_dir` setting.
|
|
100
|
+
gitignore = os.path.join(cache_directory, '.gitignore')
|
|
101
|
+
if not os.path.exists(gitignore):
|
|
102
|
+
with open(gitignore, 'wb') as f:
|
|
103
|
+
f.write(b'*\n')
|
|
104
|
+
|
|
105
|
+
cache = Cache(cache_directory, expiration_seconds)
|
|
106
|
+
cache.clean()
|
|
107
|
+
return cache
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def is_platformdirs_installed() -> bool:
|
|
111
|
+
"""Check if `platformdirs` package is installed without importing it."""
|
|
112
|
+
return find_spec('platformdirs') is not None
|
|
@@ -24,4 +24,13 @@ class PluginConfig(Config): # noqa: D101
|
|
|
24
24
|
end = Optional(MkType(str))
|
|
25
25
|
exclude = ListOfItems(MkType(str), default=[])
|
|
26
26
|
cache = MkType(int, default=0)
|
|
27
|
+
cache_dir = MkType(str, default='')
|
|
27
28
|
recursive = MkType(bool, default=True)
|
|
29
|
+
directives = MkType(
|
|
30
|
+
dict,
|
|
31
|
+
default={
|
|
32
|
+
'__default': '',
|
|
33
|
+
'include': 'include',
|
|
34
|
+
'include-markdown': 'include-markdown',
|
|
35
|
+
},
|
|
36
|
+
)
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import functools
|
|
5
6
|
import os
|
|
6
7
|
import re
|
|
8
|
+
import stat
|
|
7
9
|
import string
|
|
8
10
|
from dataclasses import dataclass
|
|
9
11
|
from typing import TYPE_CHECKING
|
|
@@ -22,7 +24,7 @@ class DirectiveBoolArgument: # noqa: D101
|
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
if TYPE_CHECKING: # pragma: no cover
|
|
25
|
-
from typing import Literal, TypedDict
|
|
27
|
+
from typing import Callable, Literal, TypedDict
|
|
26
28
|
|
|
27
29
|
DirectiveBoolArgumentsDict = dict[str, DirectiveBoolArgument]
|
|
28
30
|
|
|
@@ -73,11 +75,13 @@ TRUE_FALSE_BOOL_STR = {
|
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
|
|
78
|
+
@functools.lru_cache
|
|
76
79
|
def arg(arg: str) -> re.Pattern[str]:
|
|
77
80
|
"""Return a compiled regexp to match a boolean argument."""
|
|
78
81
|
return re.compile(rf'{arg}=([{RE_ESCAPED_PUNCTUATION}\w]*)')
|
|
79
82
|
|
|
80
83
|
|
|
84
|
+
@functools.lru_cache
|
|
81
85
|
def str_arg(arg: str) -> re.Pattern[str]:
|
|
82
86
|
"""Return a compiled regexp to match a string argument."""
|
|
83
87
|
return re.compile(
|
|
@@ -87,21 +91,23 @@ def str_arg(arg: str) -> re.Pattern[str]:
|
|
|
87
91
|
|
|
88
92
|
|
|
89
93
|
ARGUMENT_REGEXES = {
|
|
90
|
-
'start': str_arg
|
|
91
|
-
'end': str_arg
|
|
92
|
-
'exclude': str_arg
|
|
93
|
-
'encoding': str_arg
|
|
94
|
+
'start': functools.partial(str_arg, 'start'),
|
|
95
|
+
'end': functools.partial(str_arg, 'end'),
|
|
96
|
+
'exclude': functools.partial(str_arg, 'exclude'),
|
|
97
|
+
'encoding': functools.partial(str_arg, 'encoding'),
|
|
94
98
|
|
|
95
99
|
# bool
|
|
96
|
-
'comments': arg
|
|
97
|
-
'preserve-includer-indent':
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
'
|
|
101
|
-
'
|
|
100
|
+
'comments': functools.partial(arg, 'comments'),
|
|
101
|
+
'preserve-includer-indent': functools.partial(
|
|
102
|
+
arg, 'preserve-includer-indent',
|
|
103
|
+
),
|
|
104
|
+
'dedent': functools.partial(arg, 'dedent'),
|
|
105
|
+
'trailing-newlines': functools.partial(arg, 'trailing-newlines'),
|
|
106
|
+
'rewrite-relative-urls': functools.partial(arg, 'rewrite-relative-urls'),
|
|
107
|
+
'recursive': functools.partial(arg, 'recursive'),
|
|
102
108
|
|
|
103
109
|
# int
|
|
104
|
-
'heading-offset': arg
|
|
110
|
+
'heading-offset': functools.partial(arg, 'heading-offset'),
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
INCLUDE_DIRECTIVE_ARGS = {
|
|
@@ -110,8 +116,6 @@ INCLUDE_DIRECTIVE_ARGS = {
|
|
|
110
116
|
)
|
|
111
117
|
}
|
|
112
118
|
|
|
113
|
-
INCLUDE_MARKDOWN_DIRECTIVE_ARGS = set(ARGUMENT_REGEXES)
|
|
114
|
-
|
|
115
119
|
WARN_INVALID_DIRECTIVE_ARGS_REGEX = re.compile(
|
|
116
120
|
rf'[\w-]*=[{RE_ESCAPED_PUNCTUATION}\w]*',
|
|
117
121
|
)
|
|
@@ -119,7 +123,7 @@ WARN_INVALID_DIRECTIVE_ARGS_REGEX = re.compile(
|
|
|
119
123
|
|
|
120
124
|
def warn_invalid_directive_arguments(
|
|
121
125
|
arguments_string: str,
|
|
122
|
-
directive_lineno: int,
|
|
126
|
+
directive_lineno: Callable[[], int],
|
|
123
127
|
directive: Literal['include', 'include-markdown'],
|
|
124
128
|
page_src_path: str | None,
|
|
125
129
|
docs_dir: str,
|
|
@@ -127,15 +131,14 @@ def warn_invalid_directive_arguments(
|
|
|
127
131
|
"""Warns about the invalid arguments passed to a directive."""
|
|
128
132
|
valid_args = (
|
|
129
133
|
INCLUDE_DIRECTIVE_ARGS if directive == 'include'
|
|
130
|
-
else
|
|
134
|
+
else set(ARGUMENT_REGEXES)
|
|
131
135
|
)
|
|
132
|
-
for arg_value in
|
|
133
|
-
WARN_INVALID_DIRECTIVE_ARGS_REGEX,
|
|
136
|
+
for arg_value in WARN_INVALID_DIRECTIVE_ARGS_REGEX.findall(
|
|
134
137
|
arguments_string,
|
|
135
138
|
):
|
|
136
139
|
if arg_value.split('=', 1)[0] not in valid_args:
|
|
137
140
|
location = process.file_lineno_message(
|
|
138
|
-
page_src_path, docs_dir, directive_lineno,
|
|
141
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
139
142
|
)
|
|
140
143
|
logger.warning(
|
|
141
144
|
f"Invalid argument '{arg_value}' in"
|
|
@@ -172,7 +175,7 @@ def parse_string_argument(match: re.Match[str]) -> str | None:
|
|
|
172
175
|
|
|
173
176
|
|
|
174
177
|
def create_include_tag(
|
|
175
|
-
opening_tag: str, closing_tag: str, tag: str
|
|
178
|
+
opening_tag: str, closing_tag: str, tag: str,
|
|
176
179
|
) -> re.Pattern[str]:
|
|
177
180
|
"""Create a regex pattern to match an inclusion tag directive.
|
|
178
181
|
|
|
@@ -199,7 +202,7 @@ def parse_bool_options(
|
|
|
199
202
|
for option_name in option_names:
|
|
200
203
|
bool_options[option_name] = DirectiveBoolArgument(
|
|
201
204
|
value=defaults[option_name], # type: ignore
|
|
202
|
-
regex=ARGUMENT_REGEXES[option_name],
|
|
205
|
+
regex=ARGUMENT_REGEXES[option_name](),
|
|
203
206
|
)
|
|
204
207
|
|
|
205
208
|
for arg_name, arg in bool_options.items():
|
|
@@ -226,19 +229,28 @@ def resolve_file_paths_to_include( # noqa: PLR0912
|
|
|
226
229
|
return [include_string], True
|
|
227
230
|
|
|
228
231
|
if process.is_absolute_path(include_string):
|
|
229
|
-
if os.name == 'nt': # pragma:
|
|
232
|
+
if os.name == 'nt': # pragma: no cover
|
|
230
233
|
# Windows
|
|
231
234
|
fpath = os.path.normpath(include_string)
|
|
232
|
-
|
|
235
|
+
try:
|
|
236
|
+
is_file = stat.S_ISREG(os.stat(fpath).st_mode)
|
|
237
|
+
except (FileNotFoundError, OSError):
|
|
238
|
+
is_file = False
|
|
239
|
+
if not is_file:
|
|
233
240
|
return [], False
|
|
234
241
|
|
|
235
242
|
return process.filter_paths(
|
|
236
243
|
[fpath], ignore_paths,
|
|
237
244
|
), False
|
|
238
245
|
|
|
246
|
+
try:
|
|
247
|
+
is_file = stat.S_ISREG(os.stat(include_string).st_mode)
|
|
248
|
+
except (FileNotFoundError, OSError):
|
|
249
|
+
is_file = False
|
|
239
250
|
return process.filter_paths(
|
|
240
|
-
[include_string] if
|
|
241
|
-
|
|
251
|
+
[include_string] if is_file else glob.iglob(
|
|
252
|
+
include_string, flags=GLOB_FLAGS,
|
|
253
|
+
),
|
|
242
254
|
ignore_paths), False
|
|
243
255
|
|
|
244
256
|
if process.is_relative_path(include_string):
|
|
@@ -253,7 +265,11 @@ def resolve_file_paths_to_include( # noqa: PLR0912
|
|
|
253
265
|
)
|
|
254
266
|
paths = []
|
|
255
267
|
include_path = os.path.join(root_dir, include_string)
|
|
256
|
-
|
|
268
|
+
try:
|
|
269
|
+
is_file = stat.S_ISREG(os.stat(include_path).st_mode)
|
|
270
|
+
except (FileNotFoundError, OSError):
|
|
271
|
+
is_file = False
|
|
272
|
+
if is_file:
|
|
257
273
|
paths.append(include_path)
|
|
258
274
|
else:
|
|
259
275
|
for fp in glob.iglob(
|
|
@@ -268,7 +284,11 @@ def resolve_file_paths_to_include( # noqa: PLR0912
|
|
|
268
284
|
paths = []
|
|
269
285
|
root_dir = docs_dir
|
|
270
286
|
include_path = os.path.join(root_dir, include_string)
|
|
271
|
-
|
|
287
|
+
try:
|
|
288
|
+
is_file = stat.S_ISREG(os.stat(include_path).st_mode)
|
|
289
|
+
except (FileNotFoundError, OSError):
|
|
290
|
+
is_file = False
|
|
291
|
+
if is_file:
|
|
272
292
|
paths.append(include_path)
|
|
273
293
|
else:
|
|
274
294
|
for fp in glob.iglob(
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import functools
|
|
5
6
|
import html
|
|
6
7
|
import os
|
|
7
8
|
import re
|
|
@@ -17,6 +18,7 @@ from mkdocs_include_markdown_plugin.cache import Cache
|
|
|
17
18
|
from mkdocs_include_markdown_plugin.directive import (
|
|
18
19
|
ARGUMENT_REGEXES,
|
|
19
20
|
GLOB_FLAGS,
|
|
21
|
+
create_include_tag,
|
|
20
22
|
parse_bool_options,
|
|
21
23
|
parse_filename_argument,
|
|
22
24
|
parse_string_argument,
|
|
@@ -104,7 +106,8 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
104
106
|
match: re.Match[str],
|
|
105
107
|
) -> str:
|
|
106
108
|
directive_match_start = match.start()
|
|
107
|
-
directive_lineno =
|
|
109
|
+
directive_lineno = functools.partial(
|
|
110
|
+
process.lineno_from_content_start,
|
|
108
111
|
markdown,
|
|
109
112
|
directive_match_start,
|
|
110
113
|
)
|
|
@@ -114,7 +117,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
114
117
|
filename, raw_filename = parse_filename_argument(match)
|
|
115
118
|
if filename is None:
|
|
116
119
|
location = process.file_lineno_message(
|
|
117
|
-
page_src_path, docs_dir, directive_lineno,
|
|
120
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
118
121
|
)
|
|
119
122
|
raise PluginError(
|
|
120
123
|
"Found no path passed including with 'include'"
|
|
@@ -131,13 +134,13 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
131
134
|
docs_dir,
|
|
132
135
|
)
|
|
133
136
|
|
|
134
|
-
exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string)
|
|
137
|
+
exclude_match = ARGUMENT_REGEXES['exclude']().search(arguments_string)
|
|
135
138
|
ignore_paths = [*settings_ignore_paths]
|
|
136
139
|
if exclude_match is not None:
|
|
137
140
|
exclude_string = parse_string_argument(exclude_match)
|
|
138
141
|
if exclude_string is None:
|
|
139
142
|
location = process.file_lineno_message(
|
|
140
|
-
page_src_path, docs_dir, directive_lineno,
|
|
143
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
141
144
|
)
|
|
142
145
|
raise PluginError(
|
|
143
146
|
"Invalid empty 'exclude' argument in 'include'"
|
|
@@ -159,7 +162,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
159
162
|
|
|
160
163
|
if not file_paths_to_include:
|
|
161
164
|
location = process.file_lineno_message(
|
|
162
|
-
page_src_path, docs_dir, directive_lineno,
|
|
165
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
163
166
|
)
|
|
164
167
|
raise PluginError(
|
|
165
168
|
f"No files found including '{raw_filename}' at {location}",
|
|
@@ -176,7 +179,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
176
179
|
)
|
|
177
180
|
if invalid_bool_args:
|
|
178
181
|
location = process.file_lineno_message(
|
|
179
|
-
page_src_path, docs_dir, directive_lineno,
|
|
182
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
180
183
|
)
|
|
181
184
|
raise PluginError(
|
|
182
185
|
f"Invalid value for '{invalid_bool_args[0]}' argument of"
|
|
@@ -184,12 +187,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
184
187
|
f' Possible values are true or false.',
|
|
185
188
|
)
|
|
186
189
|
|
|
187
|
-
start_match = ARGUMENT_REGEXES['start'].search(arguments_string)
|
|
190
|
+
start_match = ARGUMENT_REGEXES['start']().search(arguments_string)
|
|
188
191
|
if start_match:
|
|
189
192
|
start = parse_string_argument(start_match)
|
|
190
193
|
if start is None:
|
|
191
194
|
location = process.file_lineno_message(
|
|
192
|
-
page_src_path, docs_dir, directive_lineno,
|
|
195
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
193
196
|
)
|
|
194
197
|
raise PluginError(
|
|
195
198
|
"Invalid empty 'start' argument in 'include' directive at"
|
|
@@ -198,12 +201,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
198
201
|
else:
|
|
199
202
|
start = defaults['start']
|
|
200
203
|
|
|
201
|
-
end_match = ARGUMENT_REGEXES['end'].search(arguments_string)
|
|
204
|
+
end_match = ARGUMENT_REGEXES['end']().search(arguments_string)
|
|
202
205
|
if end_match:
|
|
203
206
|
end = parse_string_argument(end_match)
|
|
204
207
|
if end is None:
|
|
205
208
|
location = process.file_lineno_message(
|
|
206
|
-
page_src_path, docs_dir, directive_lineno,
|
|
209
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
207
210
|
)
|
|
208
211
|
raise PluginError(
|
|
209
212
|
"Invalid empty 'end' argument in 'include' directive at"
|
|
@@ -212,12 +215,13 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
212
215
|
else:
|
|
213
216
|
end = defaults['end']
|
|
214
217
|
|
|
215
|
-
encoding_match = ARGUMENT_REGEXES['encoding'].search(
|
|
218
|
+
encoding_match = ARGUMENT_REGEXES['encoding']().search(
|
|
219
|
+
arguments_string)
|
|
216
220
|
if encoding_match:
|
|
217
221
|
encoding = parse_string_argument(encoding_match)
|
|
218
222
|
if encoding is None:
|
|
219
223
|
location = process.file_lineno_message(
|
|
220
|
-
page_src_path, docs_dir, directive_lineno,
|
|
224
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
221
225
|
)
|
|
222
226
|
raise PluginError(
|
|
223
227
|
"Invalid empty 'encoding' argument in 'include'"
|
|
@@ -294,7 +298,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
294
298
|
])
|
|
295
299
|
plural_suffix = 's' if len(file_paths_to_include) > 1 else ''
|
|
296
300
|
location = process.file_lineno_message(
|
|
297
|
-
page_src_path, docs_dir, directive_lineno,
|
|
301
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
298
302
|
)
|
|
299
303
|
logger.warning(
|
|
300
304
|
f"Delimiter {delimiter_name} '{delimiter_value}'"
|
|
@@ -313,7 +317,8 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
313
317
|
match: re.Match[str],
|
|
314
318
|
) -> str:
|
|
315
319
|
directive_match_start = match.start()
|
|
316
|
-
directive_lineno =
|
|
320
|
+
directive_lineno = functools.partial(
|
|
321
|
+
process.lineno_from_content_start,
|
|
317
322
|
markdown,
|
|
318
323
|
directive_match_start,
|
|
319
324
|
)
|
|
@@ -324,7 +329,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
324
329
|
filename, raw_filename = parse_filename_argument(match)
|
|
325
330
|
if filename is None:
|
|
326
331
|
location = process.file_lineno_message(
|
|
327
|
-
page_src_path, docs_dir, directive_lineno,
|
|
332
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
328
333
|
)
|
|
329
334
|
raise PluginError(
|
|
330
335
|
"Found no path passed including with 'include-markdown'"
|
|
@@ -341,13 +346,13 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
341
346
|
docs_dir,
|
|
342
347
|
)
|
|
343
348
|
|
|
344
|
-
exclude_match = ARGUMENT_REGEXES['exclude'].search(arguments_string)
|
|
349
|
+
exclude_match = ARGUMENT_REGEXES['exclude']().search(arguments_string)
|
|
345
350
|
ignore_paths = [*settings_ignore_paths]
|
|
346
351
|
if exclude_match is not None:
|
|
347
352
|
exclude_string = parse_string_argument(exclude_match)
|
|
348
353
|
if exclude_string is None:
|
|
349
354
|
location = process.file_lineno_message(
|
|
350
|
-
page_src_path, docs_dir, directive_lineno,
|
|
355
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
351
356
|
)
|
|
352
357
|
raise PluginError(
|
|
353
358
|
"Invalid empty 'exclude' argument in 'include-markdown'"
|
|
@@ -368,7 +373,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
368
373
|
|
|
369
374
|
if not file_paths_to_include:
|
|
370
375
|
location = process.file_lineno_message(
|
|
371
|
-
page_src_path, docs_dir, directive_lineno,
|
|
376
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
372
377
|
)
|
|
373
378
|
raise PluginError(
|
|
374
379
|
f"No files found including '{raw_filename}' at {location}",
|
|
@@ -388,7 +393,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
388
393
|
)
|
|
389
394
|
if invalid_bool_args:
|
|
390
395
|
location = process.file_lineno_message(
|
|
391
|
-
page_src_path, docs_dir, directive_lineno,
|
|
396
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
392
397
|
)
|
|
393
398
|
raise PluginError(
|
|
394
399
|
f"Invalid value for '{invalid_bool_args[0]}' argument of"
|
|
@@ -397,12 +402,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
397
402
|
)
|
|
398
403
|
|
|
399
404
|
# start and end arguments
|
|
400
|
-
start_match = ARGUMENT_REGEXES['start'].search(arguments_string)
|
|
405
|
+
start_match = ARGUMENT_REGEXES['start']().search(arguments_string)
|
|
401
406
|
if start_match:
|
|
402
407
|
start = parse_string_argument(start_match)
|
|
403
408
|
if start is None:
|
|
404
409
|
location = process.file_lineno_message(
|
|
405
|
-
page_src_path, docs_dir, directive_lineno,
|
|
410
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
406
411
|
)
|
|
407
412
|
raise PluginError(
|
|
408
413
|
"Invalid empty 'start' argument in 'include-markdown'"
|
|
@@ -411,12 +416,12 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
411
416
|
else:
|
|
412
417
|
start = defaults['start']
|
|
413
418
|
|
|
414
|
-
end_match = ARGUMENT_REGEXES['end'].search(arguments_string)
|
|
419
|
+
end_match = ARGUMENT_REGEXES['end']().search(arguments_string)
|
|
415
420
|
if end_match:
|
|
416
421
|
end = parse_string_argument(end_match)
|
|
417
422
|
if end is None:
|
|
418
423
|
location = process.file_lineno_message(
|
|
419
|
-
page_src_path, docs_dir, directive_lineno,
|
|
424
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
420
425
|
)
|
|
421
426
|
raise PluginError(
|
|
422
427
|
"Invalid empty 'end' argument in 'include-markdown'"
|
|
@@ -425,12 +430,13 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
425
430
|
else:
|
|
426
431
|
end = defaults['end']
|
|
427
432
|
|
|
428
|
-
encoding_match = ARGUMENT_REGEXES['encoding'].search(
|
|
433
|
+
encoding_match = ARGUMENT_REGEXES['encoding']().search(
|
|
434
|
+
arguments_string)
|
|
429
435
|
if encoding_match:
|
|
430
436
|
encoding = parse_string_argument(encoding_match)
|
|
431
437
|
if encoding is None:
|
|
432
438
|
location = process.file_lineno_message(
|
|
433
|
-
page_src_path, docs_dir, directive_lineno,
|
|
439
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
434
440
|
)
|
|
435
441
|
raise PluginError(
|
|
436
442
|
"Invalid empty 'encoding' argument in 'include-markdown'"
|
|
@@ -440,14 +446,14 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
440
446
|
encoding = defaults['encoding']
|
|
441
447
|
|
|
442
448
|
# heading offset
|
|
443
|
-
offset_match = ARGUMENT_REGEXES['heading-offset'].search(
|
|
449
|
+
offset_match = ARGUMENT_REGEXES['heading-offset']().search(
|
|
444
450
|
arguments_string,
|
|
445
451
|
)
|
|
446
452
|
if offset_match:
|
|
447
453
|
offset_raw_value = offset_match[1]
|
|
448
454
|
if offset_raw_value == '':
|
|
449
455
|
location = process.file_lineno_message(
|
|
450
|
-
page_src_path, docs_dir, directive_lineno,
|
|
456
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
451
457
|
)
|
|
452
458
|
raise PluginError(
|
|
453
459
|
"Invalid empty 'heading-offset' argument in"
|
|
@@ -457,7 +463,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
457
463
|
offset = int(offset_raw_value)
|
|
458
464
|
except ValueError:
|
|
459
465
|
location = process.file_lineno_message(
|
|
460
|
-
page_src_path, docs_dir, directive_lineno,
|
|
466
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
461
467
|
)
|
|
462
468
|
raise PluginError(
|
|
463
469
|
f"Invalid 'heading-offset' argument \"{offset_raw_value}\""
|
|
@@ -579,7 +585,7 @@ def get_file_content( # noqa: PLR0913, PLR0915
|
|
|
579
585
|
])
|
|
580
586
|
plural_suffix = 's' if len(file_paths_to_include) > 1 else ''
|
|
581
587
|
location = process.file_lineno_message(
|
|
582
|
-
page_src_path, docs_dir, directive_lineno,
|
|
588
|
+
page_src_path, docs_dir, directive_lineno(),
|
|
583
589
|
)
|
|
584
590
|
logger.warning(
|
|
585
591
|
f"Delimiter {delimiter_name} '{delimiter_value}' of"
|
|
@@ -630,8 +636,16 @@ def on_page_markdown(
|
|
|
630
636
|
page.file.abs_src_path,
|
|
631
637
|
docs_dir,
|
|
632
638
|
{
|
|
633
|
-
'include':
|
|
634
|
-
|
|
639
|
+
'include': create_include_tag(
|
|
640
|
+
config.opening_tag,
|
|
641
|
+
config.closing_tag,
|
|
642
|
+
config.directives.get('include', 'include'),
|
|
643
|
+
),
|
|
644
|
+
'include-markdown': create_include_tag(
|
|
645
|
+
config.opening_tag,
|
|
646
|
+
config.closing_tag,
|
|
647
|
+
config.directives.get('include-markdown', 'include-markdown'),
|
|
648
|
+
),
|
|
635
649
|
},
|
|
636
650
|
{
|
|
637
651
|
'encoding': config.encoding,
|
|
@@ -7,20 +7,18 @@ from functools import cached_property
|
|
|
7
7
|
from typing import TYPE_CHECKING
|
|
8
8
|
|
|
9
9
|
from mkdocs.exceptions import PluginError
|
|
10
|
-
from mkdocs.livereload import LiveReloadServer
|
|
11
10
|
from mkdocs.plugins import BasePlugin, event_priority
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
if TYPE_CHECKING: # pragma: no cover
|
|
15
|
-
import re
|
|
16
14
|
|
|
17
15
|
from mkdocs.config.defaults import MkDocsConfig
|
|
16
|
+
from mkdocs.livereload import LiveReloadServer
|
|
18
17
|
from mkdocs.structure.files import Files
|
|
19
18
|
from mkdocs.structure.pages import Page
|
|
20
19
|
|
|
21
20
|
from mkdocs_include_markdown_plugin.cache import Cache, initialize_cache
|
|
22
21
|
from mkdocs_include_markdown_plugin.config import PluginConfig
|
|
23
|
-
from mkdocs_include_markdown_plugin.directive import create_include_tag
|
|
24
22
|
from mkdocs_include_markdown_plugin.event import (
|
|
25
23
|
on_page_markdown as _on_page_markdown,
|
|
26
24
|
)
|
|
@@ -33,31 +31,26 @@ class IncludeMarkdownPlugin(BasePlugin[PluginConfig]):
|
|
|
33
31
|
|
|
34
32
|
def on_config(self, config: MkDocsConfig) -> MkDocsConfig:
|
|
35
33
|
if self.config.cache > 0:
|
|
36
|
-
cache = initialize_cache(self.config.cache)
|
|
34
|
+
cache = initialize_cache(self.config.cache, self.config.cache_dir)
|
|
37
35
|
if cache is None:
|
|
38
36
|
raise PluginError(
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
' mkdocs-include-markdown-plugin
|
|
42
|
-
' extra to install
|
|
37
|
+
'Either `cache_dir` global setting must be configured or'
|
|
38
|
+
' `platformdirs` package is required to use the'
|
|
39
|
+
' `cache` option. Install mkdocs-include-markdown-plugin'
|
|
40
|
+
" with the 'cache' extra to install `platformdirs`.",
|
|
43
41
|
)
|
|
44
|
-
cache.clean()
|
|
45
42
|
self._cache = cache
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
if '__default' not in self.config.directives: # pragma: no cover
|
|
45
|
+
for directive in self.config.directives:
|
|
46
|
+
if directive not in ('include', 'include-markdown'):
|
|
47
|
+
raise PluginError(
|
|
48
|
+
f"Invalid directive name '{directive}' at 'directives'"
|
|
49
|
+
' global setting. Valid values are "include" and'
|
|
50
|
+
' "include-markdown".',
|
|
51
|
+
)
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
return create_include_tag(
|
|
57
|
-
self.config.opening_tag,
|
|
58
|
-
self.config.closing_tag,
|
|
59
|
-
tag='include-markdown',
|
|
60
|
-
)
|
|
53
|
+
return config
|
|
61
54
|
|
|
62
55
|
@cached_property
|
|
63
56
|
def _files_watcher(self) -> FilesWatcher:
|
|
@@ -6,10 +6,9 @@ import functools
|
|
|
6
6
|
import io
|
|
7
7
|
import os
|
|
8
8
|
import re
|
|
9
|
+
import stat
|
|
9
10
|
from collections.abc import Callable, Iterator
|
|
10
|
-
from typing import TYPE_CHECKING
|
|
11
|
-
from urllib.parse import urlparse, urlunparse
|
|
12
|
-
from urllib.request import Request, urlopen
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
if TYPE_CHECKING: # pragma: no cover
|
|
@@ -245,11 +244,13 @@ def rewrite_relative_urls(
|
|
|
245
244
|
``source_path`` will still work when inserted into a file at
|
|
246
245
|
``destination_path``.
|
|
247
246
|
"""
|
|
247
|
+
from urllib.parse import urlparse, urlunparse
|
|
248
|
+
|
|
248
249
|
def rewrite_url(url: str) -> str:
|
|
249
250
|
scheme, netloc, path, params, query, fragment = urlparse(url)
|
|
250
251
|
|
|
251
252
|
# absolute or mail
|
|
252
|
-
if
|
|
253
|
+
if path.startswith('/') or scheme == 'mailto':
|
|
253
254
|
return url
|
|
254
255
|
|
|
255
256
|
new_path = os.path.relpath(
|
|
@@ -260,10 +261,13 @@ def rewrite_relative_urls(
|
|
|
260
261
|
# ensure forward slashes are used, on Windows
|
|
261
262
|
new_path = new_path.replace('\\', '/').replace('//', '/')
|
|
262
263
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
try:
|
|
265
|
+
if path[-1] == '/':
|
|
266
|
+
# the above operation removes a trailing slash,
|
|
267
|
+
# so add it back if it was present in the input
|
|
268
|
+
new_path += '/'
|
|
269
|
+
except IndexError: # pragma: no cover
|
|
270
|
+
pass
|
|
267
271
|
|
|
268
272
|
return urlunparse((scheme, netloc, new_path, params, query, fragment))
|
|
269
273
|
|
|
@@ -351,9 +355,10 @@ def filter_inclusions( # noqa: PLR0912
|
|
|
351
355
|
if end not in text_to_include:
|
|
352
356
|
expected_end_not_found = True
|
|
353
357
|
|
|
358
|
+
start_split = text_to_include.split(start)
|
|
354
359
|
text_parts = (
|
|
355
|
-
|
|
356
|
-
if
|
|
360
|
+
start_split[1:]
|
|
361
|
+
if len(start_split) > 1 else [text_to_include]
|
|
357
362
|
)
|
|
358
363
|
|
|
359
364
|
for start_text in text_parts:
|
|
@@ -374,20 +379,34 @@ def _transform_negative_offset_func_factory(
|
|
|
374
379
|
offset: int,
|
|
375
380
|
) -> Callable[[str], str]:
|
|
376
381
|
heading_prefix = '#' * abs(offset)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
+
|
|
383
|
+
def transform(line: str) -> str:
|
|
384
|
+
try:
|
|
385
|
+
if line[0] != '#':
|
|
386
|
+
return line
|
|
387
|
+
except IndexError: # pragma: no cover
|
|
388
|
+
return line
|
|
389
|
+
if line.startswith(heading_prefix):
|
|
390
|
+
return heading_prefix + line.lstrip('#')
|
|
391
|
+
return '#' + line.lstrip('#')
|
|
392
|
+
|
|
393
|
+
return transform
|
|
382
394
|
|
|
383
395
|
|
|
384
396
|
def _transform_positive_offset_func_factory(
|
|
385
397
|
offset: int,
|
|
386
398
|
) -> Callable[[str], str]:
|
|
387
399
|
heading_prefix = '#' * offset
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
400
|
+
|
|
401
|
+
def transform(line: str) -> str:
|
|
402
|
+
try:
|
|
403
|
+
prefix = line[0]
|
|
404
|
+
except IndexError: # pragma: no cover
|
|
405
|
+
return line
|
|
406
|
+
else:
|
|
407
|
+
return heading_prefix + line if prefix == '#' else line
|
|
408
|
+
|
|
409
|
+
return transform
|
|
391
410
|
|
|
392
411
|
|
|
393
412
|
def increase_headings_offset(markdown: str, offset: int = 0) -> str:
|
|
@@ -403,7 +422,7 @@ def increase_headings_offset(markdown: str, offset: int = 0) -> str:
|
|
|
403
422
|
|
|
404
423
|
def rstrip_trailing_newlines(content: str) -> str:
|
|
405
424
|
"""Removes trailing newlines from a string."""
|
|
406
|
-
while content.endswith('\n'
|
|
425
|
+
while content.endswith(('\n', '\r')):
|
|
407
426
|
content = content.rstrip('\r\n')
|
|
408
427
|
return content
|
|
409
428
|
|
|
@@ -442,8 +461,11 @@ def filter_paths(
|
|
|
442
461
|
continue
|
|
443
462
|
|
|
444
463
|
# ignore if is a directory
|
|
445
|
-
|
|
446
|
-
|
|
464
|
+
try:
|
|
465
|
+
if not stat.S_ISDIR(os.stat(filepath).st_mode):
|
|
466
|
+
response.append(filepath)
|
|
467
|
+
except (FileNotFoundError, OSError): # pragma: no cover
|
|
468
|
+
continue
|
|
447
469
|
response.sort()
|
|
448
470
|
return response
|
|
449
471
|
|
|
@@ -452,6 +474,8 @@ def is_url(string: str) -> bool:
|
|
|
452
474
|
"""Determine if a string is an URL."""
|
|
453
475
|
if ':' not in string: # fast path
|
|
454
476
|
return False
|
|
477
|
+
from urllib.parse import urlparse
|
|
478
|
+
|
|
455
479
|
try:
|
|
456
480
|
result = urlparse(string)
|
|
457
481
|
return all([result.scheme, result.netloc])
|
|
@@ -471,8 +495,10 @@ def is_absolute_path(string: str) -> bool:
|
|
|
471
495
|
|
|
472
496
|
def read_file(file_path: str, encoding: str) -> str:
|
|
473
497
|
"""Read a file and return its content."""
|
|
474
|
-
|
|
475
|
-
|
|
498
|
+
f = open(file_path, encoding=encoding) # noqa: SIM115
|
|
499
|
+
content = f.read()
|
|
500
|
+
f.close()
|
|
501
|
+
return content
|
|
476
502
|
|
|
477
503
|
|
|
478
504
|
def read_url(
|
|
@@ -481,6 +507,8 @@ def read_url(
|
|
|
481
507
|
encoding: str = 'utf-8',
|
|
482
508
|
) -> Any:
|
|
483
509
|
"""Read an HTTP location and return its content."""
|
|
510
|
+
from urllib.request import Request, urlopen
|
|
511
|
+
|
|
484
512
|
if http_cache is not None:
|
|
485
513
|
cached_content = http_cache.get_(url, encoding)
|
|
486
514
|
if cached_content is not None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|