@@ -214,7 +214,7 @@ def append_conf(self):
214
214
user_config ['theme' ] = self .DEFAULT_THEME_NAME
215
215
216
216
# Write the modified mkdocs configuration
217
- yaml . safe_dump (
217
+ yaml_dump_safely (
218
218
user_config ,
219
219
open (self .yaml_file , 'w' ),
220
220
)
@@ -326,27 +326,67 @@ class MkdocsHTML(BaseMkdocs):
326
326
build_dir = '_build/html'
327
327
328
328
329
- class SafeLoaderIgnoreUnknown (yaml .SafeLoader ): # pylint: disable=too-many-ancestors
329
+ # TODO: find a better way to integrate with MkDocs.
330
+ # See https://github.com/readthedocs/readthedocs.org/issues/7844
331
+
332
+
333
+ class ProxyPythonName (yaml .YAMLObject ):
334
+ def __init__ (self , value ):
335
+ self .value = value
336
+
337
+ def __eq__ (self , other ):
338
+ return self .value == other .value
339
+
340
+
341
+ class SafeLoader (yaml .SafeLoader ): # pylint: disable=too-many-ancestors
330
342
331
343
"""
332
- YAML loader to ignore unknown tags.
344
+ Safe YAML loader.
345
+
346
+ This loader parses special ``!!python/name:`` tags without actually
347
+ importing or executing code. Every other special tag is ignored.
333
348
334
349
Borrowed from https://stackoverflow.com/a/57121993
350
+ Issue https://github.com/readthedocs/readthedocs.org/issues/7461
335
351
"""
336
352
337
353
def ignore_unknown (self , node ): # pylint: disable=no-self-use, unused-argument
338
354
return None
339
355
356
+ def construct_python_name (self , suffix , node ): # pylint: disable=no-self-use, unused-argument
357
+ return ProxyPythonName (suffix )
358
+
359
+
360
+ class SafeDumper (yaml .SafeDumper ):
340
361
341
- SafeLoaderIgnoreUnknown .add_constructor (None , SafeLoaderIgnoreUnknown .ignore_unknown )
362
+ """
363
+ Safe YAML dumper.
364
+
365
+ This dumper allows to avoid losing values of special tags that
366
+ were parsed by our safe loader.
367
+ """
368
+
369
+ def represent_name (self , data ):
370
+ return self .represent_scalar ("tag:yaml.org,2002:python/name:" + data .value , "" )
371
+
372
+
373
+ SafeLoader .add_multi_constructor ("tag:yaml.org,2002:python/name:" , SafeLoader .construct_python_name )
374
+ SafeLoader .add_constructor (None , SafeLoader .ignore_unknown )
375
+ SafeDumper .add_representer (ProxyPythonName , SafeDumper .represent_name )
342
376
343
377
344
378
def yaml_load_safely (content ):
345
379
"""
346
- Uses ``SafeLoaderIgnoreUnknown `` loader to skip unknown tags.
380
+ Uses ``SafeLoader `` loader to skip unknown tags.
347
381
348
- When a YAML contains ``!!python/name:int`` it will complete ignore it an
349
- return ``None`` for those fields instead of failing. We need this to avoid
350
- executing random code, but still support these YAML files.
382
+ When a YAML contains ``!!python/name:int`` it will store the ``int``
383
+ suffix temporarily to be able to re-dump it later. We need this to avoid
384
+ executing random code, but still support these YAML files without
385
+ information loss.
351
386
"""
352
- return yaml .load (content , Loader = SafeLoaderIgnoreUnknown )
387
+ return yaml .load (content , Loader = SafeLoader )
388
+
389
+
390
+ def yaml_dump_safely (content , stream = None ):
391
+ """Uses ``SafeDumper`` dumper to write YAML contents."""
392
+ return yaml .dump (content , stream = stream , Dumper = SafeDumper )
0 commit comments