2025-12-25 upload
This commit is contained in:
49
venv/Lib/site-packages/ruamel/yaml/__init__.py
Normal file
49
venv/Lib/site-packages/ruamel/yaml/__init__.py
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Dict, Any # NOQA
|
||||
|
||||
_package_data = dict(
|
||||
full_package_name='ruamel.yaml',
|
||||
version_info=(0, 18, 16),
|
||||
__version__='0.18.16',
|
||||
version_timestamp='2025-10-22 19:50:12',
|
||||
author='Anthon van der Neut',
|
||||
author_email='a.van.der.neut@ruamel.eu',
|
||||
description='ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order', # NOQA
|
||||
entry_points=None,
|
||||
since=2014,
|
||||
extras_require={
|
||||
':platform_python_implementation=="CPython" and python_version<"3.14"': ['ruamel.yaml.clib>=0.2.7'], # NOQA
|
||||
'jinja2': ['ruamel.yaml.jinja2>=0.2'],
|
||||
'docs': ['ryd', 'mercurial>5.7'],
|
||||
},
|
||||
classifiers=[
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Text Processing :: Markup',
|
||||
'Typing :: Typed',
|
||||
],
|
||||
keywords='yaml 1.2 parser round-trip preserve quotes order config',
|
||||
url_doc='https://yaml.dev/doc/{full_package_name}',
|
||||
tox=dict(
|
||||
env='*',
|
||||
fl8excl='_test/lib,branch_default',
|
||||
),
|
||||
# universal=True,
|
||||
supported=[(3, 8)], # minimum
|
||||
) # type: Dict[Any, Any]
|
||||
|
||||
|
||||
version_info = _package_data['version_info']
|
||||
__version__ = _package_data['__version__']
|
||||
|
||||
try:
|
||||
from .cyaml import * # NOQA
|
||||
|
||||
__with_libyaml__ = True
|
||||
except (ImportError, ValueError): # for Jython
|
||||
__with_libyaml__ = False
|
||||
|
||||
from ruamel.yaml.main import * # NOQA
|
||||
20
venv/Lib/site-packages/ruamel/yaml/anchor.py
Normal file
20
venv/Lib/site-packages/ruamel/yaml/anchor.py
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List, Union, Iterator # NOQA
|
||||
|
||||
anchor_attrib = '_yaml_anchor'
|
||||
|
||||
|
||||
class Anchor:
|
||||
__slots__ = 'value', 'always_dump'
|
||||
attrib = anchor_attrib
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.value = None
|
||||
self.always_dump = False
|
||||
|
||||
def __repr__(self) -> Any:
|
||||
ad = ', (always dump)' if self.always_dump else ""
|
||||
return f'Anchor({self.value!r}{ad})'
|
||||
1208
venv/Lib/site-packages/ruamel/yaml/comments.py
Normal file
1208
venv/Lib/site-packages/ruamel/yaml/comments.py
Normal file
File diff suppressed because it is too large
Load Diff
236
venv/Lib/site-packages/ruamel/yaml/compat.py
Normal file
236
venv/Lib/site-packages/ruamel/yaml/compat.py
Normal file
@@ -0,0 +1,236 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# partially from package six by Benjamin Peterson
|
||||
|
||||
import sys
|
||||
import os
|
||||
import io
|
||||
from abc import abstractmethod
|
||||
import collections.abc
|
||||
|
||||
|
||||
from ruamel.yaml.docinfo import Version # NOQA
|
||||
# fmt: off
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List, Union, BinaryIO, IO, Text, Tuple # NOQA
|
||||
from typing import Optional # NOQA
|
||||
try:
|
||||
from typing import SupportsIndex as SupportsIndex # in order to reexport for mypy
|
||||
except ImportError:
|
||||
SupportsIndex = int # type: ignore
|
||||
|
||||
StreamType = Any
|
||||
StreamTextType = StreamType
|
||||
VersionType = Union[str , Tuple[int, int] , List[int] , Version , None]
|
||||
# fmt: on
|
||||
|
||||
_DEFAULT_YAML_VERSION = (1, 2)
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from ordereddict import OrderedDict # type: ignore
|
||||
|
||||
# to get the right name import ... as ordereddict doesn't do that
|
||||
|
||||
|
||||
class ordereddict(OrderedDict): # type: ignore
|
||||
if not hasattr(OrderedDict, 'insert'):
|
||||
|
||||
def insert(self, pos: int, key: Any, value: Any) -> None:
|
||||
if pos >= len(self):
|
||||
self[key] = value
|
||||
return
|
||||
od = ordereddict()
|
||||
od.update(self)
|
||||
for k in od:
|
||||
del self[k]
|
||||
for index, old_key in enumerate(od):
|
||||
if pos == index:
|
||||
self[key] = value
|
||||
self[old_key] = od[old_key]
|
||||
|
||||
|
||||
StringIO = io.StringIO
|
||||
BytesIO = io.BytesIO
|
||||
|
||||
|
||||
builtins_module = 'builtins'
|
||||
|
||||
|
||||
def with_metaclass(meta: Any, *bases: Any) -> Any:
|
||||
"""Create a base class with a metaclass."""
|
||||
return meta('NewBase', bases, {})
|
||||
|
||||
|
||||
DBG_TOKEN = 1
|
||||
DBG_EVENT = 2
|
||||
DBG_NODE = 4
|
||||
|
||||
|
||||
_debug: Optional[int] = None
|
||||
if 'RUAMEL_DEBUG' in os.environ:
|
||||
_debugx = os.environ.get('RUAMEL_DEBUG')
|
||||
if _debugx is None:
|
||||
_debug = 0
|
||||
else:
|
||||
_debug = int(_debugx)
|
||||
|
||||
|
||||
if bool(_debug):
|
||||
|
||||
class ObjectCounter:
|
||||
def __init__(self) -> None:
|
||||
self.map: Dict[Any, Any] = {}
|
||||
|
||||
def __call__(self, k: Any) -> None:
|
||||
self.map[k] = self.map.get(k, 0) + 1
|
||||
|
||||
def dump(self) -> None:
|
||||
for k in sorted(self.map):
|
||||
sys.stdout.write(f'{k} -> {self.map[k]}')
|
||||
|
||||
object_counter = ObjectCounter()
|
||||
|
||||
|
||||
# used from yaml util when testing
|
||||
def dbg(val: Any = None) -> Any:
|
||||
debug = _debug
|
||||
if debug is None:
|
||||
# set to true or false
|
||||
_debugx = os.environ.get('YAMLDEBUG')
|
||||
if _debugx is None:
|
||||
debug = 0
|
||||
else:
|
||||
debug = int(_debugx)
|
||||
if val is None:
|
||||
return debug
|
||||
return debug & val
|
||||
|
||||
|
||||
class Nprint:
|
||||
def __init__(self, file_name: Any = None) -> None:
|
||||
self._max_print: Any = None
|
||||
self._count: Any = None
|
||||
self._file_name = file_name
|
||||
|
||||
def __call__(self, *args: Any, **kw: Any) -> None:
|
||||
if not bool(_debug):
|
||||
return
|
||||
import traceback
|
||||
|
||||
out = sys.stdout if self._file_name is None else open(self._file_name, 'a')
|
||||
dbgprint = print # to fool checking for print statements by dv utility
|
||||
kw1 = kw.copy()
|
||||
kw1['file'] = out
|
||||
dbgprint(*args, **kw1)
|
||||
out.flush()
|
||||
if self._max_print is not None:
|
||||
if self._count is None:
|
||||
self._count = self._max_print
|
||||
self._count -= 1
|
||||
if self._count == 0:
|
||||
dbgprint('forced exit\n')
|
||||
traceback.print_stack()
|
||||
out.flush()
|
||||
sys.exit(0)
|
||||
if self._file_name:
|
||||
out.close()
|
||||
|
||||
def set_max_print(self, i: int) -> None:
|
||||
self._max_print = i
|
||||
self._count = None
|
||||
|
||||
def fp(self, mode: str = 'a') -> Any:
|
||||
out = sys.stdout if self._file_name is None else open(self._file_name, mode)
|
||||
return out
|
||||
|
||||
|
||||
nprint = Nprint()
|
||||
nprintf = Nprint('/var/tmp/ruamel.yaml.log')
|
||||
|
||||
# char checkers following production rules
|
||||
|
||||
|
||||
def check_namespace_char(ch: Any) -> bool:
|
||||
if '\x21' <= ch <= '\x7E': # ! to ~
|
||||
return True
|
||||
if '\xA0' <= ch <= '\uD7FF':
|
||||
return True
|
||||
if ('\uE000' <= ch <= '\uFFFD') and ch != '\uFEFF': # excl. byte order mark
|
||||
return True
|
||||
if '\U00010000' <= ch <= '\U0010FFFF':
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def check_anchorname_char(ch: Any) -> bool:
|
||||
if ch in ',[]{}':
|
||||
return False
|
||||
return check_namespace_char(ch)
|
||||
|
||||
|
||||
def version_tnf(t1: Any, t2: Any = None) -> Any:
|
||||
"""
|
||||
return True if ruamel.yaml version_info < t1, None if t2 is specified and bigger else False
|
||||
"""
|
||||
from ruamel.yaml import version_info # NOQA
|
||||
|
||||
if version_info < t1:
|
||||
return True
|
||||
if t2 is not None and version_info < t2:
|
||||
return None
|
||||
return False
|
||||
|
||||
|
||||
class MutableSliceableSequence(collections.abc.MutableSequence): # type: ignore
|
||||
__slots__ = ()
|
||||
|
||||
def __getitem__(self, index: Any) -> Any:
|
||||
if not isinstance(index, slice):
|
||||
return self.__getsingleitem__(index)
|
||||
return type(self)([self[i] for i in range(*index.indices(len(self)))]) # type: ignore
|
||||
|
||||
def __setitem__(self, index: Any, value: Any) -> None:
|
||||
if not isinstance(index, slice):
|
||||
return self.__setsingleitem__(index, value)
|
||||
assert iter(value)
|
||||
# nprint(index.start, index.stop, index.step, index.indices(len(self)))
|
||||
if index.step is None:
|
||||
del self[index.start : index.stop]
|
||||
for elem in reversed(value):
|
||||
self.insert(0 if index.start is None else index.start, elem)
|
||||
else:
|
||||
range_parms = index.indices(len(self))
|
||||
nr_assigned_items = (range_parms[1] - range_parms[0] - 1) // range_parms[2] + 1
|
||||
# need to test before changing, in case TypeError is caught
|
||||
if nr_assigned_items < len(value):
|
||||
raise TypeError(
|
||||
f'too many elements in value {nr_assigned_items} < {len(value)}',
|
||||
)
|
||||
elif nr_assigned_items > len(value):
|
||||
raise TypeError(
|
||||
f'not enough elements in value {nr_assigned_items} > {len(value)}',
|
||||
)
|
||||
for idx, i in enumerate(range(*range_parms)):
|
||||
self[i] = value[idx]
|
||||
|
||||
def __delitem__(self, index: Any) -> None:
|
||||
if not isinstance(index, slice):
|
||||
return self.__delsingleitem__(index)
|
||||
# nprint(index.start, index.stop, index.step, index.indices(len(self)))
|
||||
for i in reversed(range(*index.indices(len(self)))):
|
||||
del self[i]
|
||||
|
||||
@abstractmethod
|
||||
def __getsingleitem__(self, index: Any) -> Any:
|
||||
raise IndexError
|
||||
|
||||
@abstractmethod
|
||||
def __setsingleitem__(self, index: Any, value: Any) -> None:
|
||||
raise IndexError
|
||||
|
||||
@abstractmethod
|
||||
def __delsingleitem__(self, index: Any) -> None:
|
||||
raise IndexError
|
||||
231
venv/Lib/site-packages/ruamel/yaml/composer.py
Normal file
231
venv/Lib/site-packages/ruamel/yaml/composer.py
Normal file
@@ -0,0 +1,231 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
|
||||
from ruamel.yaml.error import MarkedYAMLError, ReusedAnchorWarning
|
||||
from ruamel.yaml.compat import nprint, nprintf # NOQA
|
||||
|
||||
from ruamel.yaml.events import (
|
||||
StreamStartEvent,
|
||||
StreamEndEvent,
|
||||
MappingStartEvent,
|
||||
MappingEndEvent,
|
||||
SequenceStartEvent,
|
||||
SequenceEndEvent,
|
||||
AliasEvent,
|
||||
ScalarEvent,
|
||||
)
|
||||
from ruamel.yaml.nodes import MappingNode, ScalarNode, SequenceNode
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List # NOQA
|
||||
|
||||
__all__ = ['Composer', 'ComposerError']
|
||||
|
||||
|
||||
class ComposerError(MarkedYAMLError):
|
||||
pass
|
||||
|
||||
|
||||
class Composer:
|
||||
def __init__(self, loader: Any = None) -> None:
|
||||
self.loader = loader
|
||||
if self.loader is not None and getattr(self.loader, '_composer', None) is None:
|
||||
self.loader._composer = self
|
||||
self.anchors: Dict[Any, Any] = {}
|
||||
self.warn_double_anchors = True
|
||||
|
||||
@property
|
||||
def parser(self) -> Any:
|
||||
if hasattr(self.loader, 'typ'):
|
||||
self.loader.parser
|
||||
return self.loader._parser
|
||||
|
||||
@property
|
||||
def resolver(self) -> Any:
|
||||
# assert self.loader._resolver is not None
|
||||
if hasattr(self.loader, 'typ'):
|
||||
self.loader.resolver
|
||||
return self.loader._resolver
|
||||
|
||||
def check_node(self) -> Any:
|
||||
# Drop the STREAM-START event.
|
||||
if self.parser.check_event(StreamStartEvent):
|
||||
self.parser.get_event()
|
||||
|
||||
# If there are more documents available?
|
||||
return not self.parser.check_event(StreamEndEvent)
|
||||
|
||||
def get_node(self) -> Any:
|
||||
# Get the root node of the next document.
|
||||
if not self.parser.check_event(StreamEndEvent):
|
||||
return self.compose_document()
|
||||
|
||||
def get_single_node(self) -> Any:
|
||||
# Drop the STREAM-START event.
|
||||
self.parser.get_event()
|
||||
|
||||
# Compose a document if the stream is not empty.
|
||||
document: Any = None
|
||||
if not self.parser.check_event(StreamEndEvent):
|
||||
document = self.compose_document()
|
||||
|
||||
# Ensure that the stream contains no more documents.
|
||||
if not self.parser.check_event(StreamEndEvent):
|
||||
event = self.parser.get_event()
|
||||
raise ComposerError(
|
||||
'expected a single document in the stream',
|
||||
document.start_mark,
|
||||
'but found another document',
|
||||
event.start_mark,
|
||||
)
|
||||
|
||||
# Drop the STREAM-END event.
|
||||
self.parser.get_event()
|
||||
|
||||
return document
|
||||
|
||||
def compose_document(self: Any) -> Any:
|
||||
self.anchors = {}
|
||||
# Drop the DOCUMENT-START event.
|
||||
self.parser.get_event()
|
||||
|
||||
# Compose the root node.
|
||||
node = self.compose_node(None, None)
|
||||
|
||||
# Drop the DOCUMENT-END event.
|
||||
self.parser.get_event()
|
||||
|
||||
return node
|
||||
|
||||
def return_alias(self, a: Any) -> Any:
|
||||
return a
|
||||
|
||||
def compose_node(self, parent: Any, index: Any) -> Any:
|
||||
if self.parser.check_event(AliasEvent):
|
||||
event = self.parser.get_event()
|
||||
alias = event.anchor
|
||||
if alias not in self.anchors:
|
||||
raise ComposerError(
|
||||
None, None, f'found undefined alias {alias!r}', event.start_mark,
|
||||
)
|
||||
return self.return_alias(self.anchors[alias])
|
||||
event = self.parser.peek_event()
|
||||
anchor = event.anchor
|
||||
if anchor is not None: # have an anchor
|
||||
if self.warn_double_anchors and anchor in self.anchors:
|
||||
ws = (
|
||||
f'\nfound duplicate anchor {anchor!r}\n'
|
||||
f'first occurrence {self.anchors[anchor].start_mark}\n'
|
||||
f'second occurrence {event.start_mark}'
|
||||
)
|
||||
warnings.warn(ws, ReusedAnchorWarning, stacklevel=2)
|
||||
self.resolver.descend_resolver(parent, index)
|
||||
if self.parser.check_event(ScalarEvent):
|
||||
node = self.compose_scalar_node(anchor)
|
||||
elif self.parser.check_event(SequenceStartEvent):
|
||||
node = self.compose_sequence_node(anchor)
|
||||
elif self.parser.check_event(MappingStartEvent):
|
||||
node = self.compose_mapping_node(anchor)
|
||||
self.resolver.ascend_resolver()
|
||||
return node
|
||||
|
||||
def compose_scalar_node(self, anchor: Any) -> Any:
|
||||
event = self.parser.get_event()
|
||||
tag = event.ctag
|
||||
if tag is None or str(tag) == '!':
|
||||
tag = self.resolver.resolve(ScalarNode, event.value, event.implicit)
|
||||
assert not isinstance(tag, str)
|
||||
# e.g tag.yaml.org,2002:str
|
||||
node = ScalarNode(
|
||||
tag,
|
||||
event.value,
|
||||
event.start_mark,
|
||||
event.end_mark,
|
||||
style=event.style,
|
||||
comment=event.comment,
|
||||
anchor=anchor,
|
||||
)
|
||||
if anchor is not None:
|
||||
self.anchors[anchor] = node
|
||||
return node
|
||||
|
||||
def compose_sequence_node(self, anchor: Any) -> Any:
|
||||
start_event = self.parser.get_event()
|
||||
tag = start_event.ctag
|
||||
if tag is None or str(tag) == '!':
|
||||
tag = self.resolver.resolve(SequenceNode, None, start_event.implicit)
|
||||
assert not isinstance(tag, str)
|
||||
node = SequenceNode(
|
||||
tag,
|
||||
[],
|
||||
start_event.start_mark,
|
||||
None,
|
||||
flow_style=start_event.flow_style,
|
||||
comment=start_event.comment,
|
||||
anchor=anchor,
|
||||
)
|
||||
if anchor is not None:
|
||||
self.anchors[anchor] = node
|
||||
index = 0
|
||||
while not self.parser.check_event(SequenceEndEvent):
|
||||
node.value.append(self.compose_node(node, index))
|
||||
index += 1
|
||||
end_event = self.parser.get_event()
|
||||
if node.flow_style is True and end_event.comment is not None:
|
||||
if node.comment is not None:
|
||||
x = node.flow_style
|
||||
nprint(
|
||||
f'Warning: unexpected end_event commment in sequence node {x}\n',
|
||||
' if possible, please report an issue with reproducable data/code',
|
||||
)
|
||||
node.comment = end_event.comment
|
||||
node.end_mark = end_event.end_mark
|
||||
self.check_end_doc_comment(end_event, node)
|
||||
return node
|
||||
|
||||
def compose_mapping_node(self, anchor: Any) -> Any:
|
||||
start_event = self.parser.get_event()
|
||||
tag = start_event.ctag
|
||||
if tag is None or str(tag) == '!':
|
||||
tag = self.resolver.resolve(MappingNode, None, start_event.implicit)
|
||||
assert not isinstance(tag, str)
|
||||
node = MappingNode(
|
||||
tag,
|
||||
[],
|
||||
start_event.start_mark,
|
||||
None,
|
||||
flow_style=start_event.flow_style,
|
||||
comment=start_event.comment,
|
||||
anchor=anchor,
|
||||
)
|
||||
if anchor is not None:
|
||||
self.anchors[anchor] = node
|
||||
while not self.parser.check_event(MappingEndEvent):
|
||||
# key_event = self.parser.peek_event()
|
||||
item_key = self.compose_node(node, None)
|
||||
# if item_key in node.value:
|
||||
# raise ComposerError("while composing a mapping",
|
||||
# start_event.start_mark,
|
||||
# "found duplicate key", key_event.start_mark)
|
||||
item_value = self.compose_node(node, item_key)
|
||||
# node.value[item_key] = item_value
|
||||
node.value.append((item_key, item_value))
|
||||
end_event = self.parser.get_event()
|
||||
if node.flow_style is True and end_event.comment is not None:
|
||||
node.comment = end_event.comment
|
||||
node.end_mark = end_event.end_mark
|
||||
self.check_end_doc_comment(end_event, node)
|
||||
return node
|
||||
|
||||
def check_end_doc_comment(self, end_event: Any, node: Any) -> None:
|
||||
if end_event.comment and end_event.comment[1]:
|
||||
# pre comments on an end_event, no following to move to
|
||||
if node.comment is None:
|
||||
node.comment = [None, None]
|
||||
assert not isinstance(node, ScalarEvent)
|
||||
# this is a post comment on a mapping node, add as third element
|
||||
# in the list
|
||||
node.comment.append(end_event.comment[1])
|
||||
end_event.comment[1] = None
|
||||
17
venv/Lib/site-packages/ruamel/yaml/configobjwalker.py
Normal file
17
venv/Lib/site-packages/ruamel/yaml/configobjwalker.py
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
|
||||
from ruamel.yaml.util import configobj_walker as new_configobj_walker
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any
|
||||
|
||||
|
||||
def configobj_walker(cfg: Any) -> Any:
|
||||
warnings.warn(
|
||||
'configobj_walker has moved to ruamel.yaml.util, please update your code',
|
||||
stacklevel=2,
|
||||
)
|
||||
return new_configobj_walker(cfg)
|
||||
1724
venv/Lib/site-packages/ruamel/yaml/constructor.py
Normal file
1724
venv/Lib/site-packages/ruamel/yaml/constructor.py
Normal file
File diff suppressed because it is too large
Load Diff
197
venv/Lib/site-packages/ruamel/yaml/cyaml.py
Normal file
197
venv/Lib/site-packages/ruamel/yaml/cyaml.py
Normal file
@@ -0,0 +1,197 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from _ruamel_yaml import CParser, CEmitter # type: ignore
|
||||
|
||||
from ruamel.yaml.constructor import Constructor, BaseConstructor, SafeConstructor
|
||||
from ruamel.yaml.representer import Representer, SafeRepresenter, BaseRepresenter
|
||||
from ruamel.yaml.resolver import Resolver, BaseResolver
|
||||
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Union, Optional # NOQA
|
||||
from ruamel.yaml.compat import StreamTextType, StreamType, VersionType # NOQA
|
||||
|
||||
__all__ = ['CBaseLoader', 'CSafeLoader', 'CLoader', 'CBaseDumper', 'CSafeDumper', 'CDumper']
|
||||
|
||||
|
||||
# this includes some hacks to solve the usage of resolver by lower level
|
||||
# parts of the parser
|
||||
|
||||
|
||||
class CBaseLoader(CParser, BaseConstructor, BaseResolver): # type: ignore
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamTextType,
|
||||
version: Optional[VersionType] = None,
|
||||
preserve_quotes: Optional[bool] = None,
|
||||
) -> None:
|
||||
CParser.__init__(self, stream)
|
||||
self._parser = self._composer = self
|
||||
BaseConstructor.__init__(self, loader=self)
|
||||
BaseResolver.__init__(self, loadumper=self)
|
||||
# self.descend_resolver = self._resolver.descend_resolver
|
||||
# self.ascend_resolver = self._resolver.ascend_resolver
|
||||
# self.resolve = self._resolver.resolve
|
||||
|
||||
|
||||
class CSafeLoader(CParser, SafeConstructor, Resolver): # type: ignore
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamTextType,
|
||||
version: Optional[VersionType] = None,
|
||||
preserve_quotes: Optional[bool] = None,
|
||||
) -> None:
|
||||
CParser.__init__(self, stream)
|
||||
self._parser = self._composer = self
|
||||
SafeConstructor.__init__(self, loader=self)
|
||||
Resolver.__init__(self, loadumper=self)
|
||||
# self.descend_resolver = self._resolver.descend_resolver
|
||||
# self.ascend_resolver = self._resolver.ascend_resolver
|
||||
# self.resolve = self._resolver.resolve
|
||||
|
||||
|
||||
class CLoader(CParser, Constructor, Resolver): # type: ignore
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamTextType,
|
||||
version: Optional[VersionType] = None,
|
||||
preserve_quotes: Optional[bool] = None,
|
||||
) -> None:
|
||||
CParser.__init__(self, stream)
|
||||
self._parser = self._composer = self
|
||||
Constructor.__init__(self, loader=self)
|
||||
Resolver.__init__(self, loadumper=self)
|
||||
# self.descend_resolver = self._resolver.descend_resolver
|
||||
# self.ascend_resolver = self._resolver.ascend_resolver
|
||||
# self.resolve = self._resolver.resolve
|
||||
|
||||
|
||||
class CBaseDumper(CEmitter, BaseRepresenter, BaseResolver): # type: ignore
|
||||
def __init__(
|
||||
self: StreamType,
|
||||
stream: Any,
|
||||
default_style: Any = None,
|
||||
default_flow_style: Any = None,
|
||||
canonical: Optional[bool] = None,
|
||||
indent: Optional[int] = None,
|
||||
width: Optional[int] = None,
|
||||
allow_unicode: Optional[bool] = None,
|
||||
line_break: Any = None,
|
||||
encoding: Any = None,
|
||||
explicit_start: Optional[bool] = None,
|
||||
explicit_end: Optional[bool] = None,
|
||||
version: Any = None,
|
||||
tags: Any = None,
|
||||
block_seq_indent: Any = None,
|
||||
top_level_colon_align: Any = None,
|
||||
prefix_colon: Any = None,
|
||||
) -> None:
|
||||
# NOQA
|
||||
CEmitter.__init__(
|
||||
self,
|
||||
stream,
|
||||
canonical=canonical,
|
||||
indent=indent,
|
||||
width=width,
|
||||
encoding=encoding,
|
||||
allow_unicode=allow_unicode,
|
||||
line_break=line_break,
|
||||
explicit_start=explicit_start,
|
||||
explicit_end=explicit_end,
|
||||
version=version,
|
||||
tags=tags,
|
||||
)
|
||||
self._emitter = self._serializer = self._representer = self
|
||||
BaseRepresenter.__init__(
|
||||
self,
|
||||
default_style=default_style,
|
||||
default_flow_style=default_flow_style,
|
||||
dumper=self,
|
||||
)
|
||||
BaseResolver.__init__(self, loadumper=self)
|
||||
|
||||
|
||||
class CSafeDumper(CEmitter, SafeRepresenter, Resolver): # type: ignore
|
||||
def __init__(
|
||||
self: StreamType,
|
||||
stream: Any,
|
||||
default_style: Any = None,
|
||||
default_flow_style: Any = None,
|
||||
canonical: Optional[bool] = None,
|
||||
indent: Optional[int] = None,
|
||||
width: Optional[int] = None,
|
||||
allow_unicode: Optional[bool] = None,
|
||||
line_break: Any = None,
|
||||
encoding: Any = None,
|
||||
explicit_start: Optional[bool] = None,
|
||||
explicit_end: Optional[bool] = None,
|
||||
version: Any = None,
|
||||
tags: Any = None,
|
||||
block_seq_indent: Any = None,
|
||||
top_level_colon_align: Any = None,
|
||||
prefix_colon: Any = None,
|
||||
) -> None:
|
||||
# NOQA
|
||||
self._emitter = self._serializer = self._representer = self
|
||||
CEmitter.__init__(
|
||||
self,
|
||||
stream,
|
||||
canonical=canonical,
|
||||
indent=indent,
|
||||
width=width,
|
||||
encoding=encoding,
|
||||
allow_unicode=allow_unicode,
|
||||
line_break=line_break,
|
||||
explicit_start=explicit_start,
|
||||
explicit_end=explicit_end,
|
||||
version=version,
|
||||
tags=tags,
|
||||
)
|
||||
self._emitter = self._serializer = self._representer = self
|
||||
SafeRepresenter.__init__(
|
||||
self, default_style=default_style, default_flow_style=default_flow_style,
|
||||
)
|
||||
Resolver.__init__(self)
|
||||
|
||||
|
||||
class CDumper(CEmitter, Representer, Resolver): # type: ignore
|
||||
def __init__(
|
||||
self: StreamType,
|
||||
stream: Any,
|
||||
default_style: Any = None,
|
||||
default_flow_style: Any = None,
|
||||
canonical: Optional[bool] = None,
|
||||
indent: Optional[int] = None,
|
||||
width: Optional[int] = None,
|
||||
allow_unicode: Optional[bool] = None,
|
||||
line_break: Any = None,
|
||||
encoding: Any = None,
|
||||
explicit_start: Optional[bool] = None,
|
||||
explicit_end: Optional[bool] = None,
|
||||
version: Any = None,
|
||||
tags: Any = None,
|
||||
block_seq_indent: Any = None,
|
||||
top_level_colon_align: Any = None,
|
||||
prefix_colon: Any = None,
|
||||
) -> None:
|
||||
# NOQA
|
||||
CEmitter.__init__(
|
||||
self,
|
||||
stream,
|
||||
canonical=canonical,
|
||||
indent=indent,
|
||||
width=width,
|
||||
encoding=encoding,
|
||||
allow_unicode=allow_unicode,
|
||||
line_break=line_break,
|
||||
explicit_start=explicit_start,
|
||||
explicit_end=explicit_end,
|
||||
version=version,
|
||||
tags=tags,
|
||||
)
|
||||
self._emitter = self._serializer = self._representer = self
|
||||
Representer.__init__(
|
||||
self, default_style=default_style, default_flow_style=default_flow_style,
|
||||
)
|
||||
Resolver.__init__(self)
|
||||
130
venv/Lib/site-packages/ruamel/yaml/docinfo.py
Normal file
130
venv/Lib/site-packages/ruamel/yaml/docinfo.py
Normal file
@@ -0,0 +1,130 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
"""
|
||||
DocInfo
|
||||
|
||||
Although it was possible to read tag directives before this, all handle/prefix
|
||||
pairs for all documents in all streams were stored in one dictionary per
|
||||
YAML instance, making it impossible to distinguish where such a pair came
|
||||
from without sublassing the scanner.
|
||||
|
||||
ToDo:
|
||||
DocInfo can be used by a yaml dumper to dump a class
|
||||
- if connected to the root of a data structure
|
||||
- if provided to the dumper?
|
||||
"""
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Optional, Tuple, Any
|
||||
|
||||
# from dataclasses import dataclass, field, MISSING # NOQA
|
||||
|
||||
|
||||
# @dataclass(order=True, frozen=True)
|
||||
class Version:
|
||||
# major: int
|
||||
# minor: int
|
||||
def __init__(self, major: int, minor: int) -> None:
|
||||
self._major = major
|
||||
self._minor = minor
|
||||
|
||||
@property
|
||||
def major(self) -> int:
|
||||
return self._major
|
||||
|
||||
@property
|
||||
def minor(self) -> int:
|
||||
return self._minor
|
||||
|
||||
def __eq__(self, v: Any) -> bool:
|
||||
if not isinstance(v, Version):
|
||||
return False
|
||||
return self._major == v._major and self._minor == v._minor
|
||||
|
||||
def __lt__(self, v: Version) -> bool:
|
||||
if self._major < v._major:
|
||||
return True
|
||||
if self._major > v._major:
|
||||
return False
|
||||
return self._minor < v._minor
|
||||
|
||||
def __le__(self, v: Version) -> bool:
|
||||
if self._major < v._major:
|
||||
return True
|
||||
if self._major > v._major:
|
||||
return False
|
||||
return self._minor <= v._minor
|
||||
|
||||
def __gt__(self, v: Version) -> bool:
|
||||
if self._major > v._major:
|
||||
return True
|
||||
if self._major < v._major:
|
||||
return False
|
||||
return self._minor > v._minor
|
||||
|
||||
def __ge__(self, v: Version) -> bool:
|
||||
if self._major > v._major:
|
||||
return True
|
||||
if self._major < v._major:
|
||||
return False
|
||||
return self._minor >= v._minor
|
||||
|
||||
|
||||
def version(
|
||||
major: int | str | Tuple[int, int] | None,
|
||||
minor: Optional[int] = None,
|
||||
) -> Optional[Version]:
|
||||
if major is None:
|
||||
assert minor is None
|
||||
return None
|
||||
if isinstance(major, str):
|
||||
assert minor is None
|
||||
parts = major.split('.')
|
||||
assert len(parts) == 2
|
||||
return Version(int(parts[0]), int(parts[1]))
|
||||
elif isinstance(major, tuple):
|
||||
assert minor is None
|
||||
assert len(major) == 2
|
||||
major, minor = major
|
||||
assert minor is not None
|
||||
return Version(major, minor)
|
||||
|
||||
|
||||
# @dataclass(frozen=True)
|
||||
class Tag:
|
||||
# handle: str
|
||||
# prefix: str
|
||||
def __init__(self, handle: str, prefix: str) -> None:
|
||||
self._handle = handle
|
||||
self._prefix = prefix
|
||||
|
||||
@property
|
||||
def handle(self) -> str:
|
||||
return self._handle
|
||||
|
||||
@property
|
||||
def prefix(self) -> str:
|
||||
return self._prefix
|
||||
|
||||
|
||||
# @dataclass
|
||||
class DocInfo:
|
||||
"""
|
||||
Store document information, can be used for analysis of a loaded YAML document
|
||||
requested_version: if explicitly set before load
|
||||
doc_version: from %YAML directive
|
||||
tags: from %TAG directives in scanned order
|
||||
"""
|
||||
# requested_version: Optional[Version] = None
|
||||
# doc_version: Optional[Version] = None
|
||||
# tags: list[Tag] = field(default_factory=list)
|
||||
def __init__(
|
||||
self,
|
||||
requested_version: Optional[Version] = None,
|
||||
doc_version: Optional[Version] = None,
|
||||
tags: Optional[list[Tag]] = None,
|
||||
):
|
||||
self.requested_version = requested_version
|
||||
self.doc_version = doc_version
|
||||
self.tags = [] if tags is None else tags
|
||||
220
venv/Lib/site-packages/ruamel/yaml/dumper.py
Normal file
220
venv/Lib/site-packages/ruamel/yaml/dumper.py
Normal file
@@ -0,0 +1,220 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ruamel.yaml.emitter import Emitter
|
||||
from ruamel.yaml.serializer import Serializer
|
||||
from ruamel.yaml.representer import (
|
||||
Representer,
|
||||
SafeRepresenter,
|
||||
BaseRepresenter,
|
||||
RoundTripRepresenter,
|
||||
)
|
||||
from ruamel.yaml.resolver import Resolver, BaseResolver, VersionedResolver
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, List, Union, Optional # NOQA
|
||||
from ruamel.yaml.compat import StreamType, VersionType # NOQA
|
||||
|
||||
__all__ = ['BaseDumper', 'SafeDumper', 'Dumper', 'RoundTripDumper']
|
||||
|
||||
|
||||
class BaseDumper(Emitter, Serializer, BaseRepresenter, BaseResolver):
|
||||
def __init__(
|
||||
self: Any,
|
||||
stream: StreamType,
|
||||
default_style: Any = None,
|
||||
default_flow_style: Any = None,
|
||||
canonical: Optional[bool] = None,
|
||||
indent: Optional[int] = None,
|
||||
width: Optional[int] = None,
|
||||
allow_unicode: Optional[bool] = None,
|
||||
line_break: Any = None,
|
||||
encoding: Any = None,
|
||||
explicit_start: Optional[bool] = None,
|
||||
explicit_end: Optional[bool] = None,
|
||||
version: Any = None,
|
||||
tags: Any = None,
|
||||
block_seq_indent: Any = None,
|
||||
top_level_colon_align: Any = None,
|
||||
prefix_colon: Any = None,
|
||||
) -> None:
|
||||
# NOQA
|
||||
Emitter.__init__(
|
||||
self,
|
||||
stream,
|
||||
canonical=canonical,
|
||||
indent=indent,
|
||||
width=width,
|
||||
allow_unicode=allow_unicode,
|
||||
line_break=line_break,
|
||||
block_seq_indent=block_seq_indent,
|
||||
dumper=self,
|
||||
)
|
||||
Serializer.__init__(
|
||||
self,
|
||||
encoding=encoding,
|
||||
explicit_start=explicit_start,
|
||||
explicit_end=explicit_end,
|
||||
version=version,
|
||||
tags=tags,
|
||||
dumper=self,
|
||||
)
|
||||
BaseRepresenter.__init__(
|
||||
self,
|
||||
default_style=default_style,
|
||||
default_flow_style=default_flow_style,
|
||||
dumper=self,
|
||||
)
|
||||
BaseResolver.__init__(self, loadumper=self)
|
||||
|
||||
|
||||
class SafeDumper(Emitter, Serializer, SafeRepresenter, Resolver):
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamType,
|
||||
default_style: Any = None,
|
||||
default_flow_style: Any = None,
|
||||
canonical: Optional[bool] = None,
|
||||
indent: Optional[int] = None,
|
||||
width: Optional[int] = None,
|
||||
allow_unicode: Optional[bool] = None,
|
||||
line_break: Any = None,
|
||||
encoding: Any = None,
|
||||
explicit_start: Optional[bool] = None,
|
||||
explicit_end: Optional[bool] = None,
|
||||
version: Any = None,
|
||||
tags: Any = None,
|
||||
block_seq_indent: Any = None,
|
||||
top_level_colon_align: Any = None,
|
||||
prefix_colon: Any = None,
|
||||
) -> None:
|
||||
# NOQA
|
||||
Emitter.__init__(
|
||||
self,
|
||||
stream,
|
||||
canonical=canonical,
|
||||
indent=indent,
|
||||
width=width,
|
||||
allow_unicode=allow_unicode,
|
||||
line_break=line_break,
|
||||
block_seq_indent=block_seq_indent,
|
||||
dumper=self,
|
||||
)
|
||||
Serializer.__init__(
|
||||
self,
|
||||
encoding=encoding,
|
||||
explicit_start=explicit_start,
|
||||
explicit_end=explicit_end,
|
||||
version=version,
|
||||
tags=tags,
|
||||
dumper=self,
|
||||
)
|
||||
SafeRepresenter.__init__(
|
||||
self,
|
||||
default_style=default_style,
|
||||
default_flow_style=default_flow_style,
|
||||
dumper=self,
|
||||
)
|
||||
Resolver.__init__(self, loadumper=self)
|
||||
|
||||
|
||||
class Dumper(Emitter, Serializer, Representer, Resolver):
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamType,
|
||||
default_style: Any = None,
|
||||
default_flow_style: Any = None,
|
||||
canonical: Optional[bool] = None,
|
||||
indent: Optional[int] = None,
|
||||
width: Optional[int] = None,
|
||||
allow_unicode: Optional[bool] = None,
|
||||
line_break: Any = None,
|
||||
encoding: Any = None,
|
||||
explicit_start: Optional[bool] = None,
|
||||
explicit_end: Optional[bool] = None,
|
||||
version: Any = None,
|
||||
tags: Any = None,
|
||||
block_seq_indent: Any = None,
|
||||
top_level_colon_align: Any = None,
|
||||
prefix_colon: Any = None,
|
||||
) -> None:
|
||||
# NOQA
|
||||
Emitter.__init__(
|
||||
self,
|
||||
stream,
|
||||
canonical=canonical,
|
||||
indent=indent,
|
||||
width=width,
|
||||
allow_unicode=allow_unicode,
|
||||
line_break=line_break,
|
||||
block_seq_indent=block_seq_indent,
|
||||
dumper=self,
|
||||
)
|
||||
Serializer.__init__(
|
||||
self,
|
||||
encoding=encoding,
|
||||
explicit_start=explicit_start,
|
||||
explicit_end=explicit_end,
|
||||
version=version,
|
||||
tags=tags,
|
||||
dumper=self,
|
||||
)
|
||||
Representer.__init__(
|
||||
self,
|
||||
default_style=default_style,
|
||||
default_flow_style=default_flow_style,
|
||||
dumper=self,
|
||||
)
|
||||
Resolver.__init__(self, loadumper=self)
|
||||
|
||||
|
||||
class RoundTripDumper(Emitter, Serializer, RoundTripRepresenter, VersionedResolver):
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamType,
|
||||
default_style: Any = None,
|
||||
default_flow_style: Optional[bool] = None,
|
||||
canonical: Optional[int] = None,
|
||||
indent: Optional[int] = None,
|
||||
width: Optional[int] = None,
|
||||
allow_unicode: Optional[bool] = None,
|
||||
line_break: Any = None,
|
||||
encoding: Any = None,
|
||||
explicit_start: Optional[bool] = None,
|
||||
explicit_end: Optional[bool] = None,
|
||||
version: Any = None,
|
||||
tags: Any = None,
|
||||
block_seq_indent: Any = None,
|
||||
top_level_colon_align: Any = None,
|
||||
prefix_colon: Any = None,
|
||||
) -> None:
|
||||
# NOQA
|
||||
Emitter.__init__(
|
||||
self,
|
||||
stream,
|
||||
canonical=canonical,
|
||||
indent=indent,
|
||||
width=width,
|
||||
allow_unicode=allow_unicode,
|
||||
line_break=line_break,
|
||||
block_seq_indent=block_seq_indent,
|
||||
top_level_colon_align=top_level_colon_align,
|
||||
prefix_colon=prefix_colon,
|
||||
dumper=self,
|
||||
)
|
||||
Serializer.__init__(
|
||||
self,
|
||||
encoding=encoding,
|
||||
explicit_start=explicit_start,
|
||||
explicit_end=explicit_end,
|
||||
version=version,
|
||||
tags=tags,
|
||||
dumper=self,
|
||||
)
|
||||
RoundTripRepresenter.__init__(
|
||||
self,
|
||||
default_style=default_style,
|
||||
default_flow_style=default_flow_style,
|
||||
dumper=self,
|
||||
)
|
||||
VersionedResolver.__init__(self, loader=self)
|
||||
1802
venv/Lib/site-packages/ruamel/yaml/emitter.py
Normal file
1802
venv/Lib/site-packages/ruamel/yaml/emitter.py
Normal file
File diff suppressed because it is too large
Load Diff
328
venv/Lib/site-packages/ruamel/yaml/error.py
Normal file
328
venv/Lib/site-packages/ruamel/yaml/error.py
Normal file
@@ -0,0 +1,328 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
# import textwrap
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List, Text # NOQA
|
||||
|
||||
|
||||
__all__ = [
|
||||
'FileMark',
|
||||
'StringMark',
|
||||
'CommentMark',
|
||||
'YAMLError',
|
||||
'MarkedYAMLError',
|
||||
'ReusedAnchorWarning',
|
||||
'UnsafeLoaderWarning',
|
||||
'MarkedYAMLWarning',
|
||||
'MarkedYAMLFutureWarning',
|
||||
]
|
||||
|
||||
|
||||
class StreamMark:
|
||||
__slots__ = 'name', 'index', 'line', 'column'
|
||||
|
||||
def __init__(self, name: Any, index: int, line: int, column: int) -> None:
|
||||
self.name = name
|
||||
self.index = index
|
||||
self.line = line
|
||||
self.column = column
|
||||
|
||||
def __str__(self) -> Any:
|
||||
where = f' in "{self.name!s}", line {self.line + 1:d}, column {self.column + 1:d}'
|
||||
return where
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
if self.line != other.line or self.column != other.column:
|
||||
return False
|
||||
if self.name != other.name or self.index != other.index:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __ne__(self, other: Any) -> bool:
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class FileMark(StreamMark):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
class StringMark(StreamMark):
|
||||
__slots__ = 'name', 'index', 'line', 'column', 'buffer', 'pointer'
|
||||
|
||||
def __init__(
|
||||
self, name: Any, index: int, line: int, column: int, buffer: Any, pointer: Any,
|
||||
) -> None:
|
||||
StreamMark.__init__(self, name, index, line, column)
|
||||
self.buffer = buffer
|
||||
self.pointer = pointer
|
||||
|
||||
def get_snippet(self, indent: int = 4, max_length: int = 75) -> Any:
|
||||
if self.buffer is None: # always False
|
||||
return None
|
||||
head = ""
|
||||
start = self.pointer
|
||||
while start > 0 and self.buffer[start - 1] not in '\0\r\n\x85\u2028\u2029':
|
||||
start -= 1
|
||||
if self.pointer - start > max_length / 2 - 1:
|
||||
head = ' ... '
|
||||
start += 5
|
||||
break
|
||||
tail = ""
|
||||
end = self.pointer
|
||||
while end < len(self.buffer) and self.buffer[end] not in '\0\r\n\x85\u2028\u2029':
|
||||
end += 1
|
||||
if end - self.pointer > max_length / 2 - 1:
|
||||
tail = ' ... '
|
||||
end -= 5
|
||||
break
|
||||
snippet = self.buffer[start:end]
|
||||
caret = '^'
|
||||
caret = f'^ (line: {self.line + 1})'
|
||||
return (
|
||||
' ' * indent
|
||||
+ head
|
||||
+ snippet
|
||||
+ tail
|
||||
+ '\n'
|
||||
+ ' ' * (indent + self.pointer - start + len(head))
|
||||
+ caret
|
||||
)
|
||||
|
||||
def __str__(self) -> Any:
|
||||
snippet = self.get_snippet()
|
||||
where = f' in "{self.name!s}", line {self.line + 1:d}, column {self.column + 1:d}'
|
||||
if snippet is not None:
|
||||
where += ':\n' + snippet
|
||||
return where
|
||||
|
||||
def __repr__(self) -> Any:
|
||||
snippet = self.get_snippet()
|
||||
where = f' in "{self.name!s}", line {self.line + 1:d}, column {self.column + 1:d}'
|
||||
if snippet is not None:
|
||||
where += ':\n' + snippet
|
||||
return where
|
||||
|
||||
|
||||
class CommentMark:
|
||||
__slots__ = ('column',)
|
||||
|
||||
def __init__(self, column: Any) -> None:
|
||||
self.column = column
|
||||
|
||||
|
||||
class YAMLError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MarkedYAMLError(YAMLError):
|
||||
def __init__(
|
||||
self,
|
||||
context: Any = None,
|
||||
context_mark: Any = None,
|
||||
problem: Any = None,
|
||||
problem_mark: Any = None,
|
||||
note: Any = None,
|
||||
warn: Any = None,
|
||||
) -> None:
|
||||
self.context = context
|
||||
self.context_mark = context_mark
|
||||
self.problem = problem
|
||||
self.problem_mark = problem_mark
|
||||
self.note = note
|
||||
# warn is ignored
|
||||
|
||||
def __str__(self) -> Any:
|
||||
lines: list[str] = []
|
||||
if self.context is not None:
|
||||
lines.append(self.context)
|
||||
if self.context_mark is not None and (
|
||||
self.problem is None
|
||||
or self.problem_mark is None
|
||||
or self.context_mark.name != self.problem_mark.name
|
||||
or self.context_mark.line != self.problem_mark.line
|
||||
or self.context_mark.column != self.problem_mark.column
|
||||
):
|
||||
lines.append(str(self.context_mark))
|
||||
if self.problem is not None:
|
||||
lines.append(self.problem)
|
||||
if self.problem_mark is not None:
|
||||
lines.append(str(self.problem_mark))
|
||||
# if self.note is not None and self.note:
|
||||
# note = textwrap.dedent(self.note)
|
||||
# lines.append(note)
|
||||
self.check_append(lines, self.note)
|
||||
return '\n'.join(lines)
|
||||
|
||||
def check_append(self, lines: list[str], val: Optional[str]) -> None:
|
||||
if val is None or not val:
|
||||
return
|
||||
import textwrap
|
||||
|
||||
note = textwrap.dedent(val)
|
||||
lines.append(note)
|
||||
|
||||
|
||||
class YAMLStreamError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class YAMLWarning(Warning):
|
||||
pass
|
||||
|
||||
|
||||
class MarkedYAMLWarning(YAMLWarning):
|
||||
def __init__(
|
||||
self,
|
||||
context: Any = None,
|
||||
context_mark: Any = None,
|
||||
problem: Any = None,
|
||||
problem_mark: Any = None,
|
||||
note: Any = None,
|
||||
warn: Any = None,
|
||||
) -> None:
|
||||
self.context = context
|
||||
self.context_mark = context_mark
|
||||
self.problem = problem
|
||||
self.problem_mark = problem_mark
|
||||
self.note = note
|
||||
self.warn = warn
|
||||
|
||||
def __str__(self) -> Any:
|
||||
lines: List[str] = []
|
||||
if self.context is not None:
|
||||
lines.append(self.context)
|
||||
if self.context_mark is not None and (
|
||||
self.problem is None
|
||||
or self.problem_mark is None
|
||||
or self.context_mark.name != self.problem_mark.name
|
||||
or self.context_mark.line != self.problem_mark.line
|
||||
or self.context_mark.column != self.problem_mark.column
|
||||
):
|
||||
lines.append(str(self.context_mark))
|
||||
if self.problem is not None:
|
||||
lines.append(self.problem)
|
||||
if self.problem_mark is not None:
|
||||
lines.append(str(self.problem_mark))
|
||||
# if self.note is not None and self.note:
|
||||
# note = textwrap.dedent(self.note)
|
||||
# lines.append(note)
|
||||
self.check_append(lines, self.note)
|
||||
# if self.warn is not None and self.warn:
|
||||
# warn = textwrap.dedent(self.warn)
|
||||
# lines.append(warn)
|
||||
self.check_append(lines, self.warn)
|
||||
return '\n'.join(lines)
|
||||
|
||||
def check_append(self, lines: list[str], val: Optional[str]) -> None:
|
||||
if val is None or not val:
|
||||
return
|
||||
import textwrap
|
||||
|
||||
note = textwrap.dedent(val)
|
||||
lines.append(note)
|
||||
|
||||
|
||||
class ReusedAnchorWarning(YAMLWarning):
|
||||
pass
|
||||
|
||||
|
||||
class UnsafeLoaderWarning(YAMLWarning):
|
||||
text = """
|
||||
The default 'Loader' for 'load(stream)' without further arguments can be unsafe.
|
||||
Use 'load(stream, Loader=ruamel.yaml.Loader)' explicitly if that is OK.
|
||||
Alternatively include the following in your code:
|
||||
|
||||
import warnings
|
||||
warnings.simplefilter('ignore', ruamel.yaml.error.UnsafeLoaderWarning)
|
||||
|
||||
In most other cases you should consider using 'safe_load(stream)'"""
|
||||
pass
|
||||
|
||||
|
||||
warnings.simplefilter('once', UnsafeLoaderWarning)
|
||||
|
||||
|
||||
class MantissaNoDotYAML1_1Warning(YAMLWarning):
|
||||
def __init__(self, node: Any, flt_str: Any) -> None:
|
||||
self.node = node
|
||||
self.flt = flt_str
|
||||
|
||||
def __str__(self) -> Any:
|
||||
line = self.node.start_mark.line
|
||||
col = self.node.start_mark.column
|
||||
return f"""
|
||||
In YAML 1.1 floating point values should have a dot ('.') in their mantissa.
|
||||
See the Floating-Point Language-Independent Type for YAML™ Version 1.1 specification
|
||||
( http://yaml.org/type/float.html ). This dot is not required for JSON nor for YAML 1.2
|
||||
|
||||
Correct your float: "{self.flt}" on line: {line}, column: {col}
|
||||
|
||||
or alternatively include the following in your code:
|
||||
|
||||
import warnings
|
||||
warnings.simplefilter('ignore', ruamel.yaml.error.MantissaNoDotYAML1_1Warning)
|
||||
|
||||
"""
|
||||
|
||||
|
||||
warnings.simplefilter('once', MantissaNoDotYAML1_1Warning)
|
||||
|
||||
|
||||
class YAMLFutureWarning(Warning):
|
||||
pass
|
||||
|
||||
|
||||
class MarkedYAMLFutureWarning(YAMLFutureWarning):
|
||||
def __init__(
|
||||
self,
|
||||
context: Any = None,
|
||||
context_mark: Any = None,
|
||||
problem: Any = None,
|
||||
problem_mark: Any = None,
|
||||
note: Any = None,
|
||||
warn: Any = None,
|
||||
) -> None:
|
||||
self.context = context
|
||||
self.context_mark = context_mark
|
||||
self.problem = problem
|
||||
self.problem_mark = problem_mark
|
||||
self.note = note
|
||||
self.warn = warn
|
||||
|
||||
def __str__(self) -> Any:
|
||||
lines: List[str] = []
|
||||
if self.context is not None:
|
||||
lines.append(self.context)
|
||||
|
||||
if self.context_mark is not None and (
|
||||
self.problem is None
|
||||
or self.problem_mark is None
|
||||
or self.context_mark.name != self.problem_mark.name
|
||||
or self.context_mark.line != self.problem_mark.line
|
||||
or self.context_mark.column != self.problem_mark.column
|
||||
):
|
||||
lines.append(str(self.context_mark))
|
||||
if self.problem is not None:
|
||||
lines.append(self.problem)
|
||||
if self.problem_mark is not None:
|
||||
lines.append(str(self.problem_mark))
|
||||
# if self.note is not None and self.note:
|
||||
# note = textwrap.dedent(self.note)
|
||||
# lines.append(note)
|
||||
self.check_append(lines, self.note)
|
||||
# if self.warn is not None and self.warn:
|
||||
# warn = textwrap.dedent(self.warn)
|
||||
# lines.append(warn)
|
||||
self.check_append(lines, self.warn)
|
||||
return '\n'.join(lines)
|
||||
|
||||
def check_append(self, lines: list[str], val: Optional[str]) -> None:
|
||||
if val is None or not val:
|
||||
return
|
||||
import textwrap
|
||||
|
||||
note = textwrap.dedent(val)
|
||||
lines.append(note)
|
||||
266
venv/Lib/site-packages/ruamel/yaml/events.py
Normal file
266
venv/Lib/site-packages/ruamel/yaml/events.py
Normal file
@@ -0,0 +1,266 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# Abstract classes.
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List # NOQA
|
||||
from ruamel.yaml.tag import Tag
|
||||
|
||||
SHOW_LINES = False
|
||||
|
||||
|
||||
def CommentCheck() -> None:
|
||||
pass
|
||||
|
||||
|
||||
class Event:
|
||||
__slots__ = 'start_mark', 'end_mark', 'comment'
|
||||
crepr = 'Unspecified Event'
|
||||
|
||||
def __init__(
|
||||
self, start_mark: Any = None, end_mark: Any = None, comment: Any = CommentCheck,
|
||||
) -> None:
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
# assert comment is not CommentCheck
|
||||
if comment is CommentCheck:
|
||||
comment = None
|
||||
self.comment = comment
|
||||
|
||||
def __repr__(self) -> Any:
|
||||
if True:
|
||||
arguments = []
|
||||
if hasattr(self, 'value'):
|
||||
# if you use repr(getattr(self, 'value')) then flake8 complains about
|
||||
# abuse of getattr with a constant. When you change to self.value
|
||||
# then mypy throws an error
|
||||
arguments.append(repr(self.value))
|
||||
for key in ['anchor', 'tag', 'implicit', 'flow_style', 'style']:
|
||||
v = getattr(self, key, None)
|
||||
if v is not None:
|
||||
arguments.append(f'{key!s}={v!r}')
|
||||
if self.comment not in [None, CommentCheck]:
|
||||
arguments.append(f'comment={self.comment!r}')
|
||||
if SHOW_LINES:
|
||||
arguments.append(
|
||||
f'({self.start_mark.line}:{self.start_mark.column}/'
|
||||
f'{self.end_mark.line}:{self.end_mark.column})',
|
||||
)
|
||||
arguments = ', '.join(arguments) # type: ignore
|
||||
else:
|
||||
attributes = [
|
||||
key
|
||||
for key in ['anchor', 'tag', 'implicit', 'value', 'flow_style', 'style']
|
||||
if hasattr(self, key)
|
||||
]
|
||||
arguments = ', '.join([f'{key!s}={getattr(self, key)!r}' for key in attributes])
|
||||
if self.comment not in [None, CommentCheck]:
|
||||
arguments += f', comment={self.comment!r}'
|
||||
return f'{self.__class__.__name__!s}({arguments!s})'
|
||||
|
||||
def compact_repr(self) -> str:
|
||||
return f'{self.crepr}'
|
||||
|
||||
|
||||
class NodeEvent(Event):
|
||||
__slots__ = ('anchor',)
|
||||
|
||||
def __init__(
|
||||
self, anchor: Any, start_mark: Any = None, end_mark: Any = None, comment: Any = None,
|
||||
) -> None:
|
||||
Event.__init__(self, start_mark, end_mark, comment)
|
||||
self.anchor = anchor
|
||||
|
||||
|
||||
class CollectionStartEvent(NodeEvent):
|
||||
__slots__ = 'ctag', 'implicit', 'flow_style', 'nr_items'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
anchor: Any,
|
||||
tag: Any,
|
||||
implicit: Any,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
flow_style: Any = None,
|
||||
comment: Any = None,
|
||||
nr_items: Optional[int] = None,
|
||||
) -> None:
|
||||
NodeEvent.__init__(self, anchor, start_mark, end_mark, comment)
|
||||
self.ctag = tag
|
||||
self.implicit = implicit
|
||||
self.flow_style = flow_style
|
||||
self.nr_items = nr_items
|
||||
|
||||
@property
|
||||
def tag(self) -> Optional[str]:
|
||||
return None if self.ctag is None else str(self.ctag)
|
||||
|
||||
|
||||
class CollectionEndEvent(Event):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
# Implementations.
|
||||
|
||||
|
||||
class StreamStartEvent(Event):
|
||||
__slots__ = ('encoding',)
|
||||
crepr = '+STR'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
encoding: Any = None,
|
||||
comment: Any = None,
|
||||
) -> None:
|
||||
Event.__init__(self, start_mark, end_mark, comment)
|
||||
self.encoding = encoding
|
||||
|
||||
|
||||
class StreamEndEvent(Event):
|
||||
__slots__ = ()
|
||||
crepr = '-STR'
|
||||
|
||||
|
||||
class DocumentStartEvent(Event):
|
||||
__slots__ = 'explicit', 'version', 'tags'
|
||||
crepr = '+DOC'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
explicit: Any = None,
|
||||
version: Any = None,
|
||||
tags: Any = None,
|
||||
comment: Any = None,
|
||||
) -> None:
|
||||
Event.__init__(self, start_mark, end_mark, comment)
|
||||
self.explicit = explicit
|
||||
self.version = version
|
||||
self.tags = tags
|
||||
|
||||
def compact_repr(self) -> str:
|
||||
start = ' ---' if self.explicit else ''
|
||||
return f'{self.crepr}{start}'
|
||||
|
||||
|
||||
class DocumentEndEvent(Event):
|
||||
__slots__ = ('explicit',)
|
||||
crepr = '-DOC'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
explicit: Any = None,
|
||||
comment: Any = None,
|
||||
) -> None:
|
||||
Event.__init__(self, start_mark, end_mark, comment)
|
||||
self.explicit = explicit
|
||||
|
||||
def compact_repr(self) -> str:
|
||||
end = ' ...' if self.explicit else ''
|
||||
return f'{self.crepr}{end}'
|
||||
|
||||
|
||||
class AliasEvent(NodeEvent):
|
||||
__slots__ = 'style'
|
||||
crepr = '=ALI'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
anchor: Any,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
style: Any = None,
|
||||
comment: Any = None,
|
||||
) -> None:
|
||||
NodeEvent.__init__(self, anchor, start_mark, end_mark, comment)
|
||||
self.style = style
|
||||
|
||||
def compact_repr(self) -> str:
|
||||
return f'{self.crepr} *{self.anchor}'
|
||||
|
||||
|
||||
class ScalarEvent(NodeEvent):
|
||||
__slots__ = 'ctag', 'implicit', 'value', 'style'
|
||||
crepr = '=VAL'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
anchor: Any,
|
||||
tag: Any,
|
||||
implicit: Any,
|
||||
value: Any,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
style: Any = None,
|
||||
comment: Any = None,
|
||||
) -> None:
|
||||
NodeEvent.__init__(self, anchor, start_mark, end_mark, comment)
|
||||
self.ctag = tag
|
||||
self.implicit = implicit
|
||||
self.value = value
|
||||
self.style = style
|
||||
|
||||
@property
|
||||
def tag(self) -> Optional[str]:
|
||||
return None if self.ctag is None else str(self.ctag)
|
||||
|
||||
@tag.setter
|
||||
def tag(self, val: Any) -> None:
|
||||
if isinstance(val, str):
|
||||
val = Tag(suffix=val)
|
||||
self.ctag = val
|
||||
|
||||
def compact_repr(self) -> str:
|
||||
style = ':' if self.style is None else self.style
|
||||
anchor = f'&{self.anchor} ' if self.anchor else ''
|
||||
tag = f'<{self.tag!s}> ' if self.tag else ''
|
||||
value = self.value
|
||||
for ch, rep in [
|
||||
('\\', '\\\\'),
|
||||
('\t', '\\t'),
|
||||
('\n', '\\n'),
|
||||
('\a', ''), # remove from folded
|
||||
('\r', '\\r'),
|
||||
('\b', '\\b'),
|
||||
]:
|
||||
value = value.replace(ch, rep)
|
||||
return f'{self.crepr} {anchor}{tag}{style}{value}'
|
||||
|
||||
|
||||
class SequenceStartEvent(CollectionStartEvent):
|
||||
__slots__ = ()
|
||||
crepr = '+SEQ'
|
||||
|
||||
def compact_repr(self) -> str:
|
||||
flow = ' []' if self.flow_style else ''
|
||||
anchor = f' &{self.anchor}' if self.anchor else ''
|
||||
tag = f' <{self.tag!s}>' if self.tag else ''
|
||||
return f'{self.crepr}{flow}{anchor}{tag}'
|
||||
|
||||
|
||||
class SequenceEndEvent(CollectionEndEvent):
|
||||
__slots__ = ()
|
||||
crepr = '-SEQ'
|
||||
|
||||
|
||||
class MappingStartEvent(CollectionStartEvent):
|
||||
__slots__ = ()
|
||||
crepr = '+MAP'
|
||||
|
||||
def compact_repr(self) -> str:
|
||||
flow = ' {}' if self.flow_style else ''
|
||||
anchor = f' &{self.anchor}' if self.anchor else ''
|
||||
tag = f' <{self.tag!s}>' if self.tag else ''
|
||||
return f'{self.crepr}{flow}{anchor}{tag}'
|
||||
|
||||
|
||||
class MappingEndEvent(CollectionEndEvent):
|
||||
__slots__ = ()
|
||||
crepr = '-MAP'
|
||||
92
venv/Lib/site-packages/ruamel/yaml/loader.py
Normal file
92
venv/Lib/site-packages/ruamel/yaml/loader.py
Normal file
@@ -0,0 +1,92 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ruamel.yaml.reader import Reader
|
||||
from ruamel.yaml.scanner import Scanner, RoundTripScanner
|
||||
from ruamel.yaml.parser import Parser, RoundTripParser
|
||||
from ruamel.yaml.composer import Composer
|
||||
from ruamel.yaml.constructor import (
|
||||
BaseConstructor,
|
||||
SafeConstructor,
|
||||
Constructor,
|
||||
RoundTripConstructor,
|
||||
)
|
||||
from ruamel.yaml.resolver import VersionedResolver
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, List, Union, Optional # NOQA
|
||||
from ruamel.yaml.compat import StreamTextType, VersionType # NOQA
|
||||
|
||||
__all__ = ['BaseLoader', 'SafeLoader', 'Loader', 'RoundTripLoader']
|
||||
|
||||
|
||||
class BaseLoader(Reader, Scanner, Parser, Composer, BaseConstructor, VersionedResolver):
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamTextType,
|
||||
version: Optional[VersionType] = None,
|
||||
preserve_quotes: Optional[bool] = None,
|
||||
) -> None:
|
||||
self.comment_handling = None
|
||||
Reader.__init__(self, stream, loader=self)
|
||||
Scanner.__init__(self, loader=self)
|
||||
Parser.__init__(self, loader=self)
|
||||
Composer.__init__(self, loader=self)
|
||||
BaseConstructor.__init__(self, loader=self)
|
||||
VersionedResolver.__init__(self, version, loader=self)
|
||||
|
||||
|
||||
class SafeLoader(Reader, Scanner, Parser, Composer, SafeConstructor, VersionedResolver):
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamTextType,
|
||||
version: Optional[VersionType] = None,
|
||||
preserve_quotes: Optional[bool] = None,
|
||||
) -> None:
|
||||
self.comment_handling = None
|
||||
Reader.__init__(self, stream, loader=self)
|
||||
Scanner.__init__(self, loader=self)
|
||||
Parser.__init__(self, loader=self)
|
||||
Composer.__init__(self, loader=self)
|
||||
SafeConstructor.__init__(self, loader=self)
|
||||
VersionedResolver.__init__(self, version, loader=self)
|
||||
|
||||
|
||||
class Loader(Reader, Scanner, Parser, Composer, Constructor, VersionedResolver):
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamTextType,
|
||||
version: Optional[VersionType] = None,
|
||||
preserve_quotes: Optional[bool] = None,
|
||||
) -> None:
|
||||
self.comment_handling = None
|
||||
Reader.__init__(self, stream, loader=self)
|
||||
Scanner.__init__(self, loader=self)
|
||||
Parser.__init__(self, loader=self)
|
||||
Composer.__init__(self, loader=self)
|
||||
Constructor.__init__(self, loader=self)
|
||||
VersionedResolver.__init__(self, version, loader=self)
|
||||
|
||||
|
||||
class RoundTripLoader(
|
||||
Reader,
|
||||
RoundTripScanner,
|
||||
RoundTripParser,
|
||||
Composer,
|
||||
RoundTripConstructor,
|
||||
VersionedResolver,
|
||||
):
|
||||
def __init__(
|
||||
self,
|
||||
stream: StreamTextType,
|
||||
version: Optional[VersionType] = None,
|
||||
preserve_quotes: Optional[bool] = None,
|
||||
) -> None:
|
||||
# self.reader = Reader.__init__(self, stream)
|
||||
self.comment_handling = None # issue 385
|
||||
Reader.__init__(self, stream, loader=self)
|
||||
RoundTripScanner.__init__(self, loader=self)
|
||||
RoundTripParser.__init__(self, loader=self)
|
||||
Composer.__init__(self, loader=self)
|
||||
RoundTripConstructor.__init__(self, preserve_quotes=preserve_quotes, loader=self)
|
||||
VersionedResolver.__init__(self, version, loader=self)
|
||||
1517
venv/Lib/site-packages/ruamel/yaml/main.py
Normal file
1517
venv/Lib/site-packages/ruamel/yaml/main.py
Normal file
File diff suppressed because it is too large
Load Diff
39
venv/Lib/site-packages/ruamel/yaml/mergevalue.py
Normal file
39
venv/Lib/site-packages/ruamel/yaml/mergevalue.py
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, List, Union, Optional, Iterator # NOQA
|
||||
|
||||
|
||||
merge_attrib = '_yaml_merge'
|
||||
|
||||
|
||||
class MergeValue:
|
||||
attrib = merge_attrib
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.value: List[Any] = []
|
||||
self.sequence = None
|
||||
self.merge_pos: Optional[int] = None # position of merge in the mapping
|
||||
|
||||
def __getitem__(self, index: Any) -> Any:
|
||||
return self.value[index]
|
||||
|
||||
def __setitem__(self, index: Any, val: Any) -> None:
|
||||
self.value[index] = val
|
||||
|
||||
def __repr__(self) -> Any:
|
||||
return f'MergeValue({self.value!r})'
|
||||
|
||||
def __len__(self) -> Any:
|
||||
return len(self.value)
|
||||
|
||||
def append(self, elem: Any) -> Any:
|
||||
self.value.append(elem)
|
||||
|
||||
def extend(self, elements: Any) -> None:
|
||||
self.value.extend(elements)
|
||||
|
||||
def set_sequence(self, seq: Any) -> None:
|
||||
# print('mergevalue.set_sequence node', node.anchor)
|
||||
self.sequence = seq
|
||||
149
venv/Lib/site-packages/ruamel/yaml/nodes.py
Normal file
149
venv/Lib/site-packages/ruamel/yaml/nodes.py
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Dict, Any, Text, Optional # NOQA
|
||||
from ruamel.yaml.tag import Tag
|
||||
|
||||
|
||||
class Node:
|
||||
__slots__ = 'ctag', 'value', 'start_mark', 'end_mark', 'comment', 'anchor'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tag: Any,
|
||||
value: Any,
|
||||
start_mark: Any,
|
||||
end_mark: Any,
|
||||
comment: Any = None,
|
||||
anchor: Any = None,
|
||||
) -> None:
|
||||
# you can still get a string from the serializer
|
||||
self.ctag = tag if isinstance(tag, Tag) else Tag(suffix=tag)
|
||||
self.value = value
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
self.comment = comment
|
||||
self.anchor = anchor
|
||||
|
||||
@property
|
||||
def tag(self) -> Optional[str]:
|
||||
return None if self.ctag is None else str(self.ctag)
|
||||
|
||||
@tag.setter
|
||||
def tag(self, val: Any) -> None:
|
||||
if isinstance(val, str):
|
||||
val = Tag(suffix=val)
|
||||
self.ctag = val
|
||||
|
||||
def __repr__(self) -> Any:
|
||||
value = self.value
|
||||
# if isinstance(value, list):
|
||||
# if len(value) == 0:
|
||||
# value = '<empty>'
|
||||
# elif len(value) == 1:
|
||||
# value = '<1 item>'
|
||||
# else:
|
||||
# value = f'<{len(value)} items>'
|
||||
# else:
|
||||
# if len(value) > 75:
|
||||
# value = repr(value[:70]+' ... ')
|
||||
# else:
|
||||
# value = repr(value)
|
||||
value = repr(value)
|
||||
if self.anchor is not None:
|
||||
return f'{self.__class__.__name__!s}(tag={self.tag!r}, anchor={self.anchor!r}, value={value!s})' # NOQA
|
||||
return f'{self.__class__.__name__!s}(tag={self.tag!r}, value={value!s})'
|
||||
|
||||
def dump(self, indent: int = 0) -> None:
|
||||
xx = self.__class__.__name__
|
||||
xi = ' ' * indent
|
||||
if isinstance(self.value, str):
|
||||
sys.stdout.write(f'{xi}{xx}(tag={self.tag!r}, value={self.value!r})\n')
|
||||
if self.comment:
|
||||
sys.stdout.write(f' {xi}comment: {self.comment})\n')
|
||||
return
|
||||
sys.stdout.write(f'{xi}{xx}(tag={self.tag!r})\n')
|
||||
if self.comment:
|
||||
sys.stdout.write(f' {xi}comment: {self.comment})\n')
|
||||
for v in self.value:
|
||||
if isinstance(v, tuple):
|
||||
for v1 in v:
|
||||
v1.dump(indent + 1)
|
||||
elif isinstance(v, Node):
|
||||
v.dump(indent + 1)
|
||||
else:
|
||||
sys.stdout.write(f'Node value type? {type(v)}\n')
|
||||
|
||||
|
||||
class ScalarNode(Node):
|
||||
"""
|
||||
styles:
|
||||
? -> set() ? key, no value
|
||||
- -> suppressable null value in set
|
||||
" -> double quoted
|
||||
' -> single quoted
|
||||
| -> literal style
|
||||
> -> folding style
|
||||
"""
|
||||
|
||||
__slots__ = ('style',)
|
||||
id = 'scalar'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tag: Any,
|
||||
value: Any,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
style: Any = None,
|
||||
comment: Any = None,
|
||||
anchor: Any = None,
|
||||
) -> None:
|
||||
Node.__init__(self, tag, value, start_mark, end_mark, comment=comment, anchor=anchor)
|
||||
self.style = style
|
||||
|
||||
|
||||
class CollectionNode(Node):
|
||||
__slots__ = ('flow_style',)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tag: Any,
|
||||
value: Any,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
flow_style: Any = None,
|
||||
comment: Any = None,
|
||||
anchor: Any = None,
|
||||
) -> None:
|
||||
Node.__init__(self, tag, value, start_mark, end_mark, comment=comment)
|
||||
self.flow_style = flow_style
|
||||
self.anchor = anchor
|
||||
|
||||
|
||||
class SequenceNode(CollectionNode):
|
||||
__slots__ = ()
|
||||
id = 'sequence'
|
||||
|
||||
|
||||
class MappingNode(CollectionNode):
|
||||
__slots__ = ('merge',)
|
||||
id = 'mapping'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tag: Any,
|
||||
value: Any,
|
||||
start_mark: Any = None,
|
||||
end_mark: Any = None,
|
||||
flow_style: Any = None,
|
||||
comment: Any = None,
|
||||
anchor: Any = None,
|
||||
) -> None:
|
||||
CollectionNode.__init__(
|
||||
self, tag, value, start_mark, end_mark, flow_style, comment, anchor,
|
||||
)
|
||||
self.merge = None
|
||||
862
venv/Lib/site-packages/ruamel/yaml/parser.py
Normal file
862
venv/Lib/site-packages/ruamel/yaml/parser.py
Normal file
@@ -0,0 +1,862 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# The following YAML grammar is LL(1) and is parsed by a recursive descent
|
||||
# parser.
|
||||
#
|
||||
# stream ::= STREAM-START implicit_document? explicit_document*
|
||||
# STREAM-END
|
||||
# implicit_document ::= block_node DOCUMENT-END*
|
||||
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||
# block_node_or_indentless_sequence ::=
|
||||
# ALIAS
|
||||
# | properties (block_content |
|
||||
# indentless_block_sequence)?
|
||||
# | block_content
|
||||
# | indentless_block_sequence
|
||||
# block_node ::= ALIAS
|
||||
# | properties block_content?
|
||||
# | block_content
|
||||
# flow_node ::= ALIAS
|
||||
# | properties flow_content?
|
||||
# | flow_content
|
||||
# properties ::= TAG ANCHOR? | ANCHOR TAG?
|
||||
# block_content ::= block_collection | flow_collection | SCALAR
|
||||
# flow_content ::= flow_collection | SCALAR
|
||||
# block_collection ::= block_sequence | block_mapping
|
||||
# flow_collection ::= flow_sequence | flow_mapping
|
||||
# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
|
||||
# BLOCK-END
|
||||
# indentless_sequence ::= (BLOCK-ENTRY block_node?)+
|
||||
# block_mapping ::= BLOCK-MAPPING_START
|
||||
# ((KEY block_node_or_indentless_sequence?)?
|
||||
# (VALUE block_node_or_indentless_sequence?)?)*
|
||||
# BLOCK-END
|
||||
# flow_sequence ::= FLOW-SEQUENCE-START
|
||||
# (flow_sequence_entry FLOW-ENTRY)*
|
||||
# flow_sequence_entry?
|
||||
# FLOW-SEQUENCE-END
|
||||
# flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
# flow_mapping ::= FLOW-MAPPING-START
|
||||
# (flow_mapping_entry FLOW-ENTRY)*
|
||||
# flow_mapping_entry?
|
||||
# FLOW-MAPPING-END
|
||||
# flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
#
|
||||
# FIRST sets:
|
||||
#
|
||||
# stream: { STREAM-START <}
|
||||
# explicit_document: { DIRECTIVE DOCUMENT-START }
|
||||
# implicit_document: FIRST(block_node)
|
||||
# block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START
|
||||
# BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
||||
# flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
||||
# block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START
|
||||
# FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
|
||||
# flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
|
||||
# block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
|
||||
# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
||||
# block_sequence: { BLOCK-SEQUENCE-START }
|
||||
# block_mapping: { BLOCK-MAPPING-START }
|
||||
# block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR
|
||||
# BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START
|
||||
# FLOW-MAPPING-START BLOCK-ENTRY }
|
||||
# indentless_sequence: { ENTRY }
|
||||
# flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
|
||||
# flow_sequence: { FLOW-SEQUENCE-START }
|
||||
# flow_mapping: { FLOW-MAPPING-START }
|
||||
# flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START
|
||||
# FLOW-MAPPING-START KEY }
|
||||
# flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START
|
||||
# FLOW-MAPPING-START KEY }
|
||||
|
||||
# need to have full path with import, as pkg_resources tries to load parser.py in __init__.py
|
||||
# only to not do anything with the package afterwards
|
||||
# and for Jython too
|
||||
|
||||
|
||||
from ruamel.yaml.error import MarkedYAMLError
|
||||
from ruamel.yaml.tokens import * # NOQA
|
||||
from ruamel.yaml.events import * # NOQA
|
||||
from ruamel.yaml.scanner import Scanner, RoundTripScanner, ScannerError # NOQA
|
||||
from ruamel.yaml.scanner import BlankLineComment
|
||||
from ruamel.yaml.comments import C_PRE, C_POST, C_SPLIT_ON_FIRST_BLANK
|
||||
from ruamel.yaml.compat import nprint, nprintf # NOQA
|
||||
from ruamel.yaml.tag import Tag
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List, Optional # NOQA
|
||||
|
||||
__all__ = ['Parser', 'RoundTripParser', 'ParserError']
|
||||
|
||||
|
||||
def xprintf(*args: Any, **kw: Any) -> Any:
|
||||
return nprintf(*args, **kw)
|
||||
pass
|
||||
|
||||
|
||||
class ParserError(MarkedYAMLError):
|
||||
pass
|
||||
|
||||
|
||||
class Parser:
|
||||
# Since writing a recursive-descendant parser is a straightforward task, we
|
||||
# do not give many comments here.
|
||||
|
||||
DEFAULT_TAGS = {'!': '!', '!!': 'tag:yaml.org,2002:'}
|
||||
|
||||
def __init__(self, loader: Any) -> None:
|
||||
self.loader = loader
|
||||
if self.loader is not None and getattr(self.loader, '_parser', None) is None:
|
||||
self.loader._parser = self
|
||||
self.reset_parser()
|
||||
|
||||
def reset_parser(self) -> None:
|
||||
# Reset the state attributes (to clear self-references)
|
||||
self.current_event = self.last_event = None
|
||||
self.tag_handles: Dict[Any, Any] = {}
|
||||
self.states: List[Any] = []
|
||||
self.marks: List[Any] = []
|
||||
self.state: Any = self.parse_stream_start
|
||||
|
||||
def dispose(self) -> None:
|
||||
self.reset_parser()
|
||||
|
||||
@property
|
||||
def scanner(self) -> Any:
|
||||
if hasattr(self.loader, 'typ'):
|
||||
return self.loader.scanner
|
||||
return self.loader._scanner
|
||||
|
||||
@property
|
||||
def resolver(self) -> Any:
|
||||
if hasattr(self.loader, 'typ'):
|
||||
return self.loader.resolver
|
||||
return self.loader._resolver
|
||||
|
||||
def check_event(self, *choices: Any) -> bool:
|
||||
# Check the type of the next event.
|
||||
if self.current_event is None:
|
||||
if self.state:
|
||||
self.current_event = self.state()
|
||||
if self.current_event is not None:
|
||||
if not choices:
|
||||
return True
|
||||
for choice in choices:
|
||||
if isinstance(self.current_event, choice):
|
||||
return True
|
||||
return False
|
||||
|
||||
def peek_event(self) -> Any:
|
||||
# Get the next event.
|
||||
if self.current_event is None:
|
||||
if self.state:
|
||||
self.current_event = self.state()
|
||||
return self.current_event
|
||||
|
||||
def get_event(self) -> Any:
|
||||
# Get the next event and proceed further.
|
||||
if self.current_event is None:
|
||||
if self.state:
|
||||
self.current_event = self.state()
|
||||
# assert self.current_event is not None
|
||||
# if self.current_event.end_mark.line != self.peek_event().start_mark.line:
|
||||
# xprintf('get_event', repr(self.current_event), self.peek_event().start_mark.line)
|
||||
self.last_event = value = self.current_event
|
||||
self.current_event = None
|
||||
return value
|
||||
|
||||
# stream ::= STREAM-START implicit_document? explicit_document*
|
||||
# STREAM-END
|
||||
# implicit_document ::= block_node DOCUMENT-END*
|
||||
# explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
|
||||
|
||||
def parse_stream_start(self) -> Any:
|
||||
# Parse the stream start.
|
||||
token = self.scanner.get_token()
|
||||
self.move_token_comment(token)
|
||||
event = StreamStartEvent(token.start_mark, token.end_mark, encoding=token.encoding)
|
||||
|
||||
# Prepare the next state.
|
||||
self.state = self.parse_implicit_document_start
|
||||
|
||||
return event
|
||||
|
||||
def parse_implicit_document_start(self) -> Any:
|
||||
# Parse an implicit document.
|
||||
if not self.scanner.check_token(DirectiveToken, DocumentStartToken, StreamEndToken):
|
||||
# don't need copy, as an implicit tag doesn't add tag_handles
|
||||
self.tag_handles = self.DEFAULT_TAGS
|
||||
token = self.scanner.peek_token()
|
||||
start_mark = end_mark = token.start_mark
|
||||
event = DocumentStartEvent(start_mark, end_mark, explicit=False)
|
||||
|
||||
# Prepare the next state.
|
||||
self.states.append(self.parse_document_end)
|
||||
self.state = self.parse_block_node
|
||||
|
||||
return event
|
||||
|
||||
else:
|
||||
return self.parse_document_start()
|
||||
|
||||
def parse_document_start(self) -> Any:
|
||||
# Parse any extra document end indicators.
|
||||
while self.scanner.check_token(DocumentEndToken):
|
||||
self.scanner.get_token()
|
||||
# Parse an explicit document.
|
||||
if not self.scanner.check_token(StreamEndToken):
|
||||
version, tags = self.process_directives()
|
||||
if not self.scanner.check_token(DocumentStartToken):
|
||||
raise ParserError(
|
||||
None,
|
||||
None,
|
||||
"expected '<document start>', "
|
||||
f'but found {self.scanner.peek_token().id,!r}',
|
||||
self.scanner.peek_token().start_mark,
|
||||
)
|
||||
token = self.scanner.get_token()
|
||||
start_mark = token.start_mark
|
||||
end_mark = token.end_mark
|
||||
# if self.loader is not None and \
|
||||
# end_mark.line != self.scanner.peek_token().start_mark.line:
|
||||
# self.loader.scalar_after_indicator = False
|
||||
event: Any = DocumentStartEvent(
|
||||
start_mark,
|
||||
end_mark,
|
||||
explicit=True,
|
||||
version=version,
|
||||
tags=tags,
|
||||
comment=token.comment,
|
||||
)
|
||||
self.states.append(self.parse_document_end)
|
||||
self.state = self.parse_document_content
|
||||
else:
|
||||
# Parse the end of the stream.
|
||||
token = self.scanner.get_token()
|
||||
event = StreamEndEvent(token.start_mark, token.end_mark, comment=token.comment)
|
||||
assert not self.states
|
||||
assert not self.marks
|
||||
self.state = None
|
||||
return event
|
||||
|
||||
def parse_document_end(self) -> Any:
|
||||
# Parse the document end.
|
||||
token = self.scanner.peek_token()
|
||||
start_mark = end_mark = token.start_mark
|
||||
explicit = False
|
||||
if self.scanner.check_token(DocumentEndToken):
|
||||
token = self.scanner.get_token()
|
||||
# if token.end_mark.line != self.peek_event().start_mark.line:
|
||||
pt = self.scanner.peek_token()
|
||||
if not isinstance(pt, StreamEndToken) and (
|
||||
token.end_mark.line == pt.start_mark.line
|
||||
):
|
||||
raise ParserError(
|
||||
None,
|
||||
None,
|
||||
'found non-comment content after document end marker, '
|
||||
f'{self.scanner.peek_token().id,!r}',
|
||||
self.scanner.peek_token().start_mark,
|
||||
)
|
||||
end_mark = token.end_mark
|
||||
explicit = True
|
||||
event = DocumentEndEvent(start_mark, end_mark, explicit=explicit)
|
||||
|
||||
# Prepare the next state.
|
||||
if self.resolver.processing_version == (1, 1):
|
||||
self.state = self.parse_document_start
|
||||
else:
|
||||
if explicit:
|
||||
# found a document end marker, can be followed by implicit document
|
||||
self.state = self.parse_implicit_document_start
|
||||
else:
|
||||
self.state = self.parse_document_start
|
||||
|
||||
return event
|
||||
|
||||
def parse_document_content(self) -> Any:
|
||||
if self.scanner.check_token(
|
||||
DirectiveToken, DocumentStartToken, DocumentEndToken, StreamEndToken,
|
||||
):
|
||||
event = self.process_empty_scalar(self.scanner.peek_token().start_mark)
|
||||
self.state = self.states.pop()
|
||||
return event
|
||||
else:
|
||||
return self.parse_block_node()
|
||||
|
||||
def process_directives(self) -> Any:
|
||||
yaml_version = None
|
||||
self.tag_handles = {}
|
||||
while self.scanner.check_token(DirectiveToken):
|
||||
token = self.scanner.get_token()
|
||||
if token.name == 'YAML':
|
||||
if yaml_version is not None:
|
||||
raise ParserError(
|
||||
None, None, 'found duplicate YAML directive', token.start_mark,
|
||||
)
|
||||
major, minor = token.value
|
||||
if major != 1:
|
||||
raise ParserError(
|
||||
None,
|
||||
None,
|
||||
'found incompatible YAML document (version 1.* is required)',
|
||||
token.start_mark,
|
||||
)
|
||||
yaml_version = token.value
|
||||
elif token.name == 'TAG':
|
||||
handle, prefix = token.value
|
||||
if handle in self.tag_handles:
|
||||
raise ParserError(
|
||||
None, None, f'duplicate tag handle {handle!r}', token.start_mark,
|
||||
)
|
||||
self.tag_handles[handle] = prefix
|
||||
if bool(self.tag_handles):
|
||||
value: Any = (yaml_version, self.tag_handles.copy())
|
||||
else:
|
||||
value = yaml_version, None
|
||||
if self.loader is not None and hasattr(self.loader, 'tags'):
|
||||
# ToDo: this is used to keep a single loaded file from losing its version
|
||||
# info, but it affects following versions that have no explicit directive
|
||||
self.loader.version = yaml_version
|
||||
if self.loader.tags is None:
|
||||
self.loader.tags = {}
|
||||
for k in self.tag_handles:
|
||||
self.loader.tags[k] = self.tag_handles[k]
|
||||
self.loader.doc_infos[-1].tags.append((k, self.tag_handles[k]))
|
||||
for key in self.DEFAULT_TAGS:
|
||||
if key not in self.tag_handles:
|
||||
self.tag_handles[key] = self.DEFAULT_TAGS[key]
|
||||
return value
|
||||
|
||||
# block_node_or_indentless_sequence ::= ALIAS
|
||||
# | properties (block_content | indentless_block_sequence)?
|
||||
# | block_content
|
||||
# | indentless_block_sequence
|
||||
# block_node ::= ALIAS
|
||||
# | properties block_content?
|
||||
# | block_content
|
||||
# flow_node ::= ALIAS
|
||||
# | properties flow_content?
|
||||
# | flow_content
|
||||
# properties ::= TAG ANCHOR? | ANCHOR TAG?
|
||||
# block_content ::= block_collection | flow_collection | SCALAR
|
||||
# flow_content ::= flow_collection | SCALAR
|
||||
# block_collection ::= block_sequence | block_mapping
|
||||
# flow_collection ::= flow_sequence | flow_mapping
|
||||
|
||||
def parse_block_node(self) -> Any:
|
||||
return self.parse_node(block=True)
|
||||
|
||||
def parse_flow_node(self) -> Any:
|
||||
return self.parse_node()
|
||||
|
||||
def parse_block_node_or_indentless_sequence(self) -> Any:
|
||||
return self.parse_node(block=True, indentless_sequence=True)
|
||||
|
||||
# def transform_tag(self, handle: Any, suffix: Any) -> Any:
|
||||
# return self.tag_handles[handle] + suffix
|
||||
|
||||
def select_tag_transform(self, tag: Tag) -> None:
|
||||
if tag is None:
|
||||
return
|
||||
tag.select_transform(False)
|
||||
|
||||
def parse_node(self, block: bool = False, indentless_sequence: bool = False) -> Any:
|
||||
if self.scanner.check_token(AliasToken):
|
||||
token = self.scanner.get_token()
|
||||
event: Any = AliasEvent(token.value, token.start_mark, token.end_mark)
|
||||
self.state = self.states.pop()
|
||||
return event
|
||||
|
||||
anchor = None
|
||||
tag = None
|
||||
start_mark = end_mark = tag_mark = None
|
||||
if self.scanner.check_token(AnchorToken):
|
||||
token = self.scanner.get_token()
|
||||
self.move_token_comment(token)
|
||||
start_mark = token.start_mark
|
||||
end_mark = token.end_mark
|
||||
anchor = token.value
|
||||
if self.scanner.check_token(TagToken):
|
||||
token = self.scanner.get_token()
|
||||
tag_mark = token.start_mark
|
||||
end_mark = token.end_mark
|
||||
# tag = token.value
|
||||
tag = Tag(
|
||||
handle=token.value[0], suffix=token.value[1], handles=self.tag_handles,
|
||||
)
|
||||
elif self.scanner.check_token(TagToken):
|
||||
token = self.scanner.get_token()
|
||||
try:
|
||||
self.move_token_comment(token)
|
||||
except NotImplementedError:
|
||||
pass
|
||||
start_mark = tag_mark = token.start_mark
|
||||
end_mark = token.end_mark
|
||||
# tag = token.value
|
||||
tag = Tag(handle=token.value[0], suffix=token.value[1], handles=self.tag_handles)
|
||||
if self.scanner.check_token(AnchorToken):
|
||||
token = self.scanner.get_token()
|
||||
start_mark = tag_mark = token.start_mark
|
||||
end_mark = token.end_mark
|
||||
anchor = token.value
|
||||
if tag is not None:
|
||||
self.select_tag_transform(tag)
|
||||
if tag.check_handle():
|
||||
raise ParserError(
|
||||
'while parsing a node',
|
||||
start_mark,
|
||||
f'found undefined tag handle {tag.handle!r}',
|
||||
tag_mark,
|
||||
)
|
||||
if start_mark is None:
|
||||
start_mark = end_mark = self.scanner.peek_token().start_mark
|
||||
event = None
|
||||
implicit = tag is None or str(tag) == '!'
|
||||
if indentless_sequence and self.scanner.check_token(BlockEntryToken):
|
||||
comment = None
|
||||
pt = self.scanner.peek_token()
|
||||
if self.loader and self.loader.comment_handling is None:
|
||||
if pt.comment and pt.comment[0]:
|
||||
comment = [pt.comment[0], []]
|
||||
pt.comment[0] = None
|
||||
elif pt.comment and pt.comment[0] is None and pt.comment[1]:
|
||||
comment = [None, pt.comment[1]]
|
||||
pt.comment[1] = None
|
||||
elif self.loader:
|
||||
if pt.comment:
|
||||
comment = pt.comment
|
||||
end_mark = self.scanner.peek_token().end_mark
|
||||
event = SequenceStartEvent(
|
||||
anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,
|
||||
)
|
||||
self.state = self.parse_indentless_sequence_entry
|
||||
return event
|
||||
|
||||
if self.scanner.check_token(ScalarToken):
|
||||
token = self.scanner.get_token()
|
||||
# self.scanner.peek_token_same_line_comment(token)
|
||||
end_mark = token.end_mark
|
||||
if (token.plain and tag is None) or str(tag) == '!':
|
||||
dimplicit = (True, False)
|
||||
elif tag is None:
|
||||
dimplicit = (False, True)
|
||||
else:
|
||||
dimplicit = (False, False)
|
||||
event = ScalarEvent(
|
||||
anchor,
|
||||
tag,
|
||||
dimplicit,
|
||||
token.value,
|
||||
start_mark,
|
||||
end_mark,
|
||||
style=token.style,
|
||||
comment=token.comment,
|
||||
)
|
||||
self.state = self.states.pop()
|
||||
elif self.scanner.check_token(FlowSequenceStartToken):
|
||||
pt = self.scanner.peek_token()
|
||||
end_mark = pt.end_mark
|
||||
event = SequenceStartEvent(
|
||||
anchor,
|
||||
tag,
|
||||
implicit,
|
||||
start_mark,
|
||||
end_mark,
|
||||
flow_style=True,
|
||||
comment=pt.comment,
|
||||
)
|
||||
self.state = self.parse_flow_sequence_first_entry
|
||||
elif self.scanner.check_token(FlowMappingStartToken):
|
||||
pt = self.scanner.peek_token()
|
||||
end_mark = pt.end_mark
|
||||
event = MappingStartEvent(
|
||||
anchor,
|
||||
tag,
|
||||
implicit,
|
||||
start_mark,
|
||||
end_mark,
|
||||
flow_style=True,
|
||||
comment=pt.comment,
|
||||
)
|
||||
self.state = self.parse_flow_mapping_first_key
|
||||
elif block and self.scanner.check_token(BlockSequenceStartToken):
|
||||
end_mark = self.scanner.peek_token().start_mark
|
||||
# should inserting the comment be dependent on the
|
||||
# indentation?
|
||||
pt = self.scanner.peek_token()
|
||||
comment = pt.comment
|
||||
# nprint('pt0', type(pt))
|
||||
if comment is None or comment[1] is None:
|
||||
comment = pt.split_old_comment()
|
||||
# nprint('pt1', comment)
|
||||
event = SequenceStartEvent(
|
||||
anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,
|
||||
)
|
||||
self.state = self.parse_block_sequence_first_entry
|
||||
elif block and self.scanner.check_token(BlockMappingStartToken):
|
||||
end_mark = self.scanner.peek_token().start_mark
|
||||
comment = self.scanner.peek_token().comment
|
||||
event = MappingStartEvent(
|
||||
anchor, tag, implicit, start_mark, end_mark, flow_style=False, comment=comment,
|
||||
)
|
||||
self.state = self.parse_block_mapping_first_key
|
||||
elif anchor is not None or tag is not None:
|
||||
# Empty scalars are allowed even if a tag or an anchor is
|
||||
# specified.
|
||||
event = ScalarEvent(anchor, tag, (implicit, False), "", start_mark, end_mark)
|
||||
self.state = self.states.pop()
|
||||
else:
|
||||
if block:
|
||||
node = 'block'
|
||||
else:
|
||||
node = 'flow'
|
||||
token = self.scanner.peek_token()
|
||||
raise ParserError(
|
||||
f'while parsing a {node!s} node',
|
||||
start_mark,
|
||||
f'expected the node content, but found {token.id!r}',
|
||||
token.start_mark,
|
||||
)
|
||||
return event
|
||||
|
||||
# block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
|
||||
# BLOCK-END
|
||||
|
||||
def parse_block_sequence_first_entry(self) -> Any:
|
||||
token = self.scanner.get_token()
|
||||
# move any comment from start token
|
||||
# self.move_token_comment(token)
|
||||
self.marks.append(token.start_mark)
|
||||
return self.parse_block_sequence_entry()
|
||||
|
||||
def parse_block_sequence_entry(self) -> Any:
|
||||
if self.scanner.check_token(BlockEntryToken):
|
||||
token = self.scanner.get_token()
|
||||
self.move_token_comment(token)
|
||||
if not self.scanner.check_token(BlockEntryToken, BlockEndToken):
|
||||
self.states.append(self.parse_block_sequence_entry)
|
||||
return self.parse_block_node()
|
||||
else:
|
||||
self.state = self.parse_block_sequence_entry
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
if not self.scanner.check_token(BlockEndToken):
|
||||
token = self.scanner.peek_token()
|
||||
raise ParserError(
|
||||
'while parsing a block collection',
|
||||
self.marks[-1],
|
||||
f'expected <block end>, but found {token.id!r}',
|
||||
token.start_mark,
|
||||
)
|
||||
token = self.scanner.get_token() # BlockEndToken
|
||||
event = SequenceEndEvent(token.start_mark, token.end_mark, comment=token.comment)
|
||||
self.state = self.states.pop()
|
||||
self.marks.pop()
|
||||
return event
|
||||
|
||||
# indentless_sequence ::= (BLOCK-ENTRY block_node?)+
|
||||
|
||||
# indentless_sequence?
|
||||
# sequence:
|
||||
# - entry
|
||||
# - nested
|
||||
|
||||
def parse_indentless_sequence_entry(self) -> Any:
|
||||
if self.scanner.check_token(BlockEntryToken):
|
||||
token = self.scanner.get_token()
|
||||
self.move_token_comment(token)
|
||||
if not self.scanner.check_token(
|
||||
BlockEntryToken, KeyToken, ValueToken, BlockEndToken,
|
||||
):
|
||||
self.states.append(self.parse_indentless_sequence_entry)
|
||||
return self.parse_block_node()
|
||||
else:
|
||||
self.state = self.parse_indentless_sequence_entry
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
token = self.scanner.peek_token()
|
||||
c = None
|
||||
if self.loader and self.loader.comment_handling is None:
|
||||
c = token.comment
|
||||
start_mark = token.start_mark
|
||||
else:
|
||||
start_mark = self.last_event.end_mark # type: ignore
|
||||
c = self.distribute_comment(token.comment, start_mark.line) # type: ignore
|
||||
event = SequenceEndEvent(start_mark, start_mark, comment=c)
|
||||
self.state = self.states.pop()
|
||||
return event
|
||||
|
||||
# block_mapping ::= BLOCK-MAPPING_START
|
||||
# ((KEY block_node_or_indentless_sequence?)?
|
||||
# (VALUE block_node_or_indentless_sequence?)?)*
|
||||
# BLOCK-END
|
||||
|
||||
def parse_block_mapping_first_key(self) -> Any:
|
||||
token = self.scanner.get_token()
|
||||
self.marks.append(token.start_mark)
|
||||
return self.parse_block_mapping_key()
|
||||
|
||||
def parse_block_mapping_key(self) -> Any:
|
||||
if self.scanner.check_token(KeyToken):
|
||||
token = self.scanner.get_token()
|
||||
self.move_token_comment(token)
|
||||
if not self.scanner.check_token(KeyToken, ValueToken, BlockEndToken):
|
||||
self.states.append(self.parse_block_mapping_value)
|
||||
return self.parse_block_node_or_indentless_sequence()
|
||||
else:
|
||||
self.state = self.parse_block_mapping_value
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
if self.resolver.processing_version > (1, 1) and self.scanner.check_token(ValueToken):
|
||||
self.state = self.parse_block_mapping_value
|
||||
return self.process_empty_scalar(self.scanner.peek_token().start_mark)
|
||||
if not self.scanner.check_token(BlockEndToken):
|
||||
token = self.scanner.peek_token()
|
||||
raise ParserError(
|
||||
'while parsing a block mapping',
|
||||
self.marks[-1],
|
||||
f'expected <block end>, but found {token.id!r}',
|
||||
token.start_mark,
|
||||
)
|
||||
token = self.scanner.get_token()
|
||||
self.move_token_comment(token)
|
||||
event = MappingEndEvent(token.start_mark, token.end_mark, comment=token.comment)
|
||||
self.state = self.states.pop()
|
||||
self.marks.pop()
|
||||
return event
|
||||
|
||||
def parse_block_mapping_value(self) -> Any:
|
||||
if self.scanner.check_token(ValueToken):
|
||||
token = self.scanner.get_token()
|
||||
# value token might have post comment move it to e.g. block
|
||||
if self.scanner.check_token(ValueToken):
|
||||
self.move_token_comment(token)
|
||||
else:
|
||||
if not self.scanner.check_token(KeyToken):
|
||||
self.move_token_comment(token, empty=True)
|
||||
# else: empty value for this key cannot move token.comment
|
||||
if not self.scanner.check_token(KeyToken, ValueToken, BlockEndToken):
|
||||
self.states.append(self.parse_block_mapping_key)
|
||||
return self.parse_block_node_or_indentless_sequence()
|
||||
else:
|
||||
self.state = self.parse_block_mapping_key
|
||||
comment = token.comment
|
||||
if comment is None:
|
||||
token = self.scanner.peek_token()
|
||||
comment = token.comment
|
||||
if comment:
|
||||
token._comment = [None, comment[1]]
|
||||
comment = [comment[0], None]
|
||||
return self.process_empty_scalar(token.end_mark, comment=comment)
|
||||
else:
|
||||
self.state = self.parse_block_mapping_key
|
||||
token = self.scanner.peek_token()
|
||||
return self.process_empty_scalar(token.start_mark)
|
||||
|
||||
# flow_sequence ::= FLOW-SEQUENCE-START
|
||||
# (flow_sequence_entry FLOW-ENTRY)*
|
||||
# flow_sequence_entry?
|
||||
# FLOW-SEQUENCE-END
|
||||
# flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
#
|
||||
# Note that while production rules for both flow_sequence_entry and
|
||||
# flow_mapping_entry are equal, their interpretations are different.
|
||||
# For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
|
||||
# generate an inline mapping (set syntax).
|
||||
|
||||
def parse_flow_sequence_first_entry(self) -> Any:
|
||||
token = self.scanner.get_token()
|
||||
self.marks.append(token.start_mark)
|
||||
return self.parse_flow_sequence_entry(first=True)
|
||||
|
||||
def parse_flow_sequence_entry(self, first: bool = False) -> Any:
|
||||
if not self.scanner.check_token(FlowSequenceEndToken):
|
||||
if not first:
|
||||
if self.scanner.check_token(FlowEntryToken):
|
||||
self.scanner.get_token()
|
||||
else:
|
||||
token = self.scanner.peek_token()
|
||||
raise ParserError(
|
||||
'while parsing a flow sequence',
|
||||
self.marks[-1],
|
||||
f"expected ',' or ']', but got {token.id!r}",
|
||||
token.start_mark,
|
||||
)
|
||||
|
||||
if self.scanner.check_token(KeyToken):
|
||||
token = self.scanner.peek_token()
|
||||
event: Any = MappingStartEvent(
|
||||
None, None, True, token.start_mark, token.end_mark, flow_style=True,
|
||||
)
|
||||
self.state = self.parse_flow_sequence_entry_mapping_key
|
||||
return event
|
||||
elif not self.scanner.check_token(FlowSequenceEndToken):
|
||||
self.states.append(self.parse_flow_sequence_entry)
|
||||
return self.parse_flow_node()
|
||||
token = self.scanner.get_token()
|
||||
event = SequenceEndEvent(token.start_mark, token.end_mark, comment=token.comment)
|
||||
self.state = self.states.pop()
|
||||
self.marks.pop()
|
||||
return event
|
||||
|
||||
def parse_flow_sequence_entry_mapping_key(self) -> Any:
|
||||
token = self.scanner.get_token()
|
||||
if not self.scanner.check_token(ValueToken, FlowEntryToken, FlowSequenceEndToken):
|
||||
self.states.append(self.parse_flow_sequence_entry_mapping_value)
|
||||
return self.parse_flow_node()
|
||||
else:
|
||||
self.state = self.parse_flow_sequence_entry_mapping_value
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
|
||||
def parse_flow_sequence_entry_mapping_value(self) -> Any:
|
||||
if self.scanner.check_token(ValueToken):
|
||||
token = self.scanner.get_token()
|
||||
if not self.scanner.check_token(FlowEntryToken, FlowSequenceEndToken):
|
||||
self.states.append(self.parse_flow_sequence_entry_mapping_end)
|
||||
return self.parse_flow_node()
|
||||
else:
|
||||
self.state = self.parse_flow_sequence_entry_mapping_end
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
else:
|
||||
self.state = self.parse_flow_sequence_entry_mapping_end
|
||||
token = self.scanner.peek_token()
|
||||
return self.process_empty_scalar(token.start_mark)
|
||||
|
||||
def parse_flow_sequence_entry_mapping_end(self) -> Any:
|
||||
self.state = self.parse_flow_sequence_entry
|
||||
token = self.scanner.peek_token()
|
||||
return MappingEndEvent(token.start_mark, token.start_mark)
|
||||
|
||||
# flow_mapping ::= FLOW-MAPPING-START
|
||||
# (flow_mapping_entry FLOW-ENTRY)*
|
||||
# flow_mapping_entry?
|
||||
# FLOW-MAPPING-END
|
||||
# flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
|
||||
|
||||
def parse_flow_mapping_first_key(self) -> Any:
|
||||
token = self.scanner.get_token()
|
||||
self.marks.append(token.start_mark)
|
||||
return self.parse_flow_mapping_key(first=True)
|
||||
|
||||
def parse_flow_mapping_key(self, first: Any = False) -> Any:
|
||||
if not self.scanner.check_token(FlowMappingEndToken):
|
||||
if not first:
|
||||
if self.scanner.check_token(FlowEntryToken):
|
||||
self.scanner.get_token()
|
||||
else:
|
||||
token = self.scanner.peek_token()
|
||||
raise ParserError(
|
||||
'while parsing a flow mapping',
|
||||
self.marks[-1],
|
||||
f"expected ',' or '}}', but got {token.id!r}",
|
||||
token.start_mark,
|
||||
)
|
||||
if self.scanner.check_token(KeyToken):
|
||||
token = self.scanner.get_token()
|
||||
if not self.scanner.check_token(
|
||||
ValueToken, FlowEntryToken, FlowMappingEndToken,
|
||||
):
|
||||
self.states.append(self.parse_flow_mapping_value)
|
||||
return self.parse_flow_node()
|
||||
else:
|
||||
self.state = self.parse_flow_mapping_value
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
elif self.resolver.processing_version > (1, 1) and self.scanner.check_token(
|
||||
ValueToken,
|
||||
):
|
||||
self.state = self.parse_flow_mapping_value
|
||||
return self.process_empty_scalar(self.scanner.peek_token().end_mark)
|
||||
elif not self.scanner.check_token(FlowMappingEndToken):
|
||||
self.states.append(self.parse_flow_mapping_empty_value)
|
||||
return self.parse_flow_node()
|
||||
token = self.scanner.get_token()
|
||||
event = MappingEndEvent(token.start_mark, token.end_mark, comment=token.comment)
|
||||
self.state = self.states.pop()
|
||||
self.marks.pop()
|
||||
return event
|
||||
|
||||
def parse_flow_mapping_value(self) -> Any:
|
||||
if self.scanner.check_token(ValueToken):
|
||||
token = self.scanner.get_token()
|
||||
if not self.scanner.check_token(FlowEntryToken, FlowMappingEndToken):
|
||||
self.states.append(self.parse_flow_mapping_key)
|
||||
return self.parse_flow_node()
|
||||
else:
|
||||
self.state = self.parse_flow_mapping_key
|
||||
return self.process_empty_scalar(token.end_mark)
|
||||
else:
|
||||
self.state = self.parse_flow_mapping_key
|
||||
token = self.scanner.peek_token()
|
||||
return self.process_empty_scalar(token.start_mark)
|
||||
|
||||
def parse_flow_mapping_empty_value(self) -> Any:
|
||||
self.state = self.parse_flow_mapping_key
|
||||
return self.process_empty_scalar(self.scanner.peek_token().start_mark)
|
||||
|
||||
def process_empty_scalar(self, mark: Any, comment: Any = None) -> Any:
|
||||
return ScalarEvent(None, None, (True, False), "", mark, mark, comment=comment)
|
||||
|
||||
def move_token_comment(
|
||||
self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False,
|
||||
) -> Any:
|
||||
pass
|
||||
|
||||
|
||||
class RoundTripParser(Parser):
|
||||
"""roundtrip is a safe loader, that wants to see the unmangled tag"""
|
||||
|
||||
def select_tag_transform(self, tag: Tag) -> None:
|
||||
if tag is None:
|
||||
return
|
||||
tag.select_transform(True)
|
||||
|
||||
def move_token_comment(
|
||||
self, token: Any, nt: Optional[Any] = None, empty: Optional[bool] = False,
|
||||
) -> Any:
|
||||
token.move_old_comment(self.scanner.peek_token() if nt is None else nt, empty=empty)
|
||||
|
||||
|
||||
class RoundTripParserSC(RoundTripParser):
|
||||
"""roundtrip is a safe loader, that wants to see the unmangled tag"""
|
||||
|
||||
# some of the differences are based on the superclass testing
|
||||
# if self.loader.comment_handling is not None
|
||||
|
||||
def move_token_comment(
|
||||
self: Any, token: Any, nt: Any = None, empty: Optional[bool] = False,
|
||||
) -> None:
|
||||
token.move_new_comment(self.scanner.peek_token() if nt is None else nt, empty=empty)
|
||||
|
||||
def distribute_comment(self, comment: Any, line: Any) -> Any:
|
||||
# ToDo, look at indentation of the comment to determine attachment
|
||||
if comment is None:
|
||||
return None
|
||||
if not comment[0]:
|
||||
return None
|
||||
# if comment[0][0] != line + 1:
|
||||
# nprintf('>>>dcxxx', comment, line)
|
||||
assert comment[0][0] == line + 1
|
||||
# if comment[0] - line > 1:
|
||||
# return
|
||||
typ = self.loader.comment_handling & 0b11
|
||||
# nprintf('>>>dca', comment, line, typ)
|
||||
if typ == C_POST:
|
||||
return None
|
||||
if typ == C_PRE:
|
||||
c = [None, None, comment[0]]
|
||||
comment[0] = None
|
||||
return c
|
||||
# nprintf('>>>dcb', comment[0])
|
||||
for _idx, cmntidx in enumerate(comment[0]):
|
||||
# nprintf('>>>dcb', cmntidx)
|
||||
if isinstance(self.scanner.comments[cmntidx], BlankLineComment):
|
||||
break
|
||||
else:
|
||||
return None # no space found
|
||||
if _idx == 0:
|
||||
return None # first line was blank
|
||||
# nprintf('>>>dcc', idx)
|
||||
if typ == C_SPLIT_ON_FIRST_BLANK:
|
||||
c = [None, None, comment[0][:_idx]]
|
||||
comment[0] = comment[0][_idx:]
|
||||
return c
|
||||
raise NotImplementedError # reserved
|
||||
0
venv/Lib/site-packages/ruamel/yaml/py.typed
Normal file
0
venv/Lib/site-packages/ruamel/yaml/py.typed
Normal file
277
venv/Lib/site-packages/ruamel/yaml/reader.py
Normal file
277
venv/Lib/site-packages/ruamel/yaml/reader.py
Normal file
@@ -0,0 +1,277 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# This module contains abstractions for the input stream. You don't have to
|
||||
# looks further, there are no pretty code.
|
||||
#
|
||||
# We define two classes here.
|
||||
#
|
||||
# Mark(source, line, column)
|
||||
# It's just a record and its only use is producing nice error messages.
|
||||
# Parser does not use it for any other purposes.
|
||||
#
|
||||
# Reader(source, data)
|
||||
# Reader determines the encoding of `data` and converts it to unicode.
|
||||
# Reader provides the following methods and attributes:
|
||||
# reader.peek(length=1) - return the next `length` characters
|
||||
# reader.forward(length=1) - move the current position to `length`
|
||||
# characters.
|
||||
# reader.index - the number of the current character.
|
||||
# reader.line, stream.column - the line and the column of the current
|
||||
# character.
|
||||
|
||||
import codecs
|
||||
|
||||
from ruamel.yaml.error import YAMLError, FileMark, StringMark, YAMLStreamError
|
||||
from ruamel.yaml.util import RegExp
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List, Union, Text, Tuple, Optional # NOQA
|
||||
# from ruamel.yaml.compat import StreamTextType # NOQA
|
||||
|
||||
__all__ = ['Reader', 'ReaderError']
|
||||
|
||||
|
||||
class ReaderError(YAMLError):
|
||||
def __init__(
|
||||
self, name: Any, position: Any, character: Any, encoding: Any, reason: Any,
|
||||
) -> None:
|
||||
self.name = name
|
||||
self.character = character
|
||||
self.position = position
|
||||
self.encoding = encoding
|
||||
self.reason = reason
|
||||
|
||||
def __str__(self) -> Any:
|
||||
if isinstance(self.character, bytes):
|
||||
return (
|
||||
f"'{self.encoding!s}' codec can't decode byte #x{ord(self.character):02x}: "
|
||||
f'{self.reason!s}\n'
|
||||
f' in "{self.name!s}", position {self.position:d}'
|
||||
)
|
||||
else:
|
||||
return (
|
||||
f'unacceptable character #x{self.character:04x}: {self.reason!s}\n'
|
||||
f' in "{self.name!s}", position {self.position:d}'
|
||||
)
|
||||
|
||||
|
||||
class Reader:
|
||||
# Reader:
|
||||
# - determines the data encoding and converts it to a unicode string,
|
||||
# - checks if characters are in allowed range,
|
||||
# - adds '\0' to the end.
|
||||
|
||||
# Reader accepts
|
||||
# - a `bytes` object,
|
||||
# - a `str` object,
|
||||
# - a file-like object with its `read` method returning `str`,
|
||||
# - a file-like object with its `read` method returning `unicode`.
|
||||
|
||||
# Yeah, it's ugly and slow.
|
||||
|
||||
def __init__(self, stream: Any, loader: Any = None) -> None:
|
||||
self.loader = loader
|
||||
if self.loader is not None and getattr(self.loader, '_reader', None) is None:
|
||||
self.loader._reader = self
|
||||
self.reset_reader()
|
||||
self.stream: Any = stream # as .read is called
|
||||
|
||||
def reset_reader(self) -> None:
|
||||
self.name: Any = None
|
||||
self.stream_pointer = 0
|
||||
self.eof = True
|
||||
self.buffer = ""
|
||||
self.pointer = 0
|
||||
self.raw_buffer: Any = None
|
||||
self.raw_decode = None
|
||||
self.encoding: Optional[Text] = None
|
||||
self.index = 0
|
||||
self.line = 0
|
||||
self.column = 0
|
||||
|
||||
@property
|
||||
def stream(self) -> Any:
|
||||
try:
|
||||
return self._stream
|
||||
except AttributeError:
|
||||
raise YAMLStreamError('input stream needs to be specified')
|
||||
|
||||
@stream.setter
|
||||
def stream(self, val: Any) -> None:
|
||||
if val is None:
|
||||
return
|
||||
self._stream = None
|
||||
if isinstance(val, str):
|
||||
self.name = '<unicode string>'
|
||||
self.check_printable(val)
|
||||
self.buffer = val + '\0'
|
||||
elif isinstance(val, bytes):
|
||||
self.name = '<byte string>'
|
||||
self.raw_buffer = val
|
||||
self.determine_encoding()
|
||||
else:
|
||||
if not hasattr(val, 'read'):
|
||||
raise YAMLStreamError('stream argument needs to have a read() method')
|
||||
self._stream = val
|
||||
self.name = getattr(self.stream, 'name', '<file>')
|
||||
self.eof = False
|
||||
self.raw_buffer = None
|
||||
self.determine_encoding()
|
||||
|
||||
def peek(self, index: int = 0) -> Text:
|
||||
try:
|
||||
return self.buffer[self.pointer + index]
|
||||
except IndexError:
|
||||
self.update(index + 1)
|
||||
return self.buffer[self.pointer + index]
|
||||
|
||||
def prefix(self, length: int = 1) -> Any:
|
||||
if self.pointer + length >= len(self.buffer):
|
||||
self.update(length)
|
||||
return self.buffer[self.pointer : self.pointer + length]
|
||||
|
||||
def forward_1_1(self, length: int = 1) -> None:
|
||||
if self.pointer + length + 1 >= len(self.buffer):
|
||||
self.update(length + 1)
|
||||
while length != 0:
|
||||
ch = self.buffer[self.pointer]
|
||||
self.pointer += 1
|
||||
self.index += 1
|
||||
if ch in '\n\x85\u2028\u2029' or (
|
||||
ch == '\r' and self.buffer[self.pointer] != '\n'
|
||||
):
|
||||
self.line += 1
|
||||
self.column = 0
|
||||
elif ch != '\uFEFF':
|
||||
self.column += 1
|
||||
length -= 1
|
||||
|
||||
def forward(self, length: int = 1) -> None:
|
||||
if self.pointer + length + 1 >= len(self.buffer):
|
||||
self.update(length + 1)
|
||||
while length != 0:
|
||||
ch = self.buffer[self.pointer]
|
||||
self.pointer += 1
|
||||
self.index += 1
|
||||
if ch == '\n' or (ch == '\r' and self.buffer[self.pointer] != '\n'):
|
||||
self.line += 1
|
||||
self.column = 0
|
||||
elif ch != '\uFEFF':
|
||||
self.column += 1
|
||||
length -= 1
|
||||
|
||||
def get_mark(self) -> Any:
|
||||
if self.stream is None:
|
||||
return StringMark(
|
||||
self.name, self.index, self.line, self.column, self.buffer, self.pointer,
|
||||
)
|
||||
else:
|
||||
return FileMark(self.name, self.index, self.line, self.column)
|
||||
|
||||
def determine_encoding(self) -> None:
|
||||
while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2):
|
||||
self.update_raw()
|
||||
if isinstance(self.raw_buffer, bytes):
|
||||
if self.raw_buffer.startswith(codecs.BOM_UTF16_LE):
|
||||
self.raw_decode = codecs.utf_16_le_decode # type: ignore
|
||||
self.encoding = 'utf-16-le'
|
||||
elif self.raw_buffer.startswith(codecs.BOM_UTF16_BE):
|
||||
self.raw_decode = codecs.utf_16_be_decode # type: ignore
|
||||
self.encoding = 'utf-16-be'
|
||||
else:
|
||||
self.raw_decode = codecs.utf_8_decode # type: ignore
|
||||
self.encoding = 'utf-8'
|
||||
self.update(1)
|
||||
|
||||
NON_PRINTABLE = RegExp(
|
||||
'[^\x09\x0A\x0D\x20-\x7E\x85' '\xA0-\uD7FF' '\uE000-\uFFFD' '\U00010000-\U0010FFFF' ']' # NOQA
|
||||
)
|
||||
|
||||
_printable_ascii = ('\x09\x0A\x0D' + "".join(map(chr, range(0x20, 0x7F)))).encode('ascii')
|
||||
|
||||
@classmethod
|
||||
def _get_non_printable_ascii(cls: Text, data: bytes) -> Optional[Tuple[int, Text]]: # type: ignore # NOQA
|
||||
ascii_bytes = data.encode('ascii') # type: ignore
|
||||
non_printables = ascii_bytes.translate(None, cls._printable_ascii) # type: ignore
|
||||
if not non_printables:
|
||||
return None
|
||||
non_printable = non_printables[:1]
|
||||
return ascii_bytes.index(non_printable), non_printable.decode('ascii')
|
||||
|
||||
@classmethod
|
||||
def _get_non_printable_regex(cls, data: Text) -> Optional[Tuple[int, Text]]:
|
||||
match = cls.NON_PRINTABLE.search(data)
|
||||
if not bool(match):
|
||||
return None
|
||||
return match.start(), match.group()
|
||||
|
||||
@classmethod
|
||||
def _get_non_printable(cls, data: Text) -> Optional[Tuple[int, Text]]:
|
||||
try:
|
||||
return cls._get_non_printable_ascii(data) # type: ignore
|
||||
except UnicodeEncodeError:
|
||||
return cls._get_non_printable_regex(data)
|
||||
|
||||
def check_printable(self, data: Any) -> None:
|
||||
non_printable_match = self._get_non_printable(data)
|
||||
if non_printable_match is not None:
|
||||
start, character = non_printable_match
|
||||
position = self.index + (len(self.buffer) - self.pointer) + start
|
||||
raise ReaderError(
|
||||
self.name,
|
||||
position,
|
||||
ord(character),
|
||||
'unicode',
|
||||
'special characters are not allowed',
|
||||
)
|
||||
|
||||
def update(self, length: int) -> None:
|
||||
if self.raw_buffer is None:
|
||||
return
|
||||
self.buffer = self.buffer[self.pointer :]
|
||||
self.pointer = 0
|
||||
while len(self.buffer) < length:
|
||||
if not self.eof:
|
||||
self.update_raw()
|
||||
if self.raw_decode is not None:
|
||||
try:
|
||||
data, converted = self.raw_decode(self.raw_buffer, 'strict', self.eof)
|
||||
except UnicodeDecodeError as exc:
|
||||
character = self.raw_buffer[exc.start]
|
||||
if self.stream is not None:
|
||||
position = self.stream_pointer - len(self.raw_buffer) + exc.start
|
||||
elif self.stream is not None:
|
||||
position = self.stream_pointer - len(self.raw_buffer) + exc.start
|
||||
else:
|
||||
position = exc.start
|
||||
raise ReaderError(self.name, position, character, exc.encoding, exc.reason)
|
||||
else:
|
||||
data = self.raw_buffer
|
||||
converted = len(data)
|
||||
self.check_printable(data)
|
||||
self.buffer += data
|
||||
self.raw_buffer = self.raw_buffer[converted:]
|
||||
if self.eof:
|
||||
self.buffer += '\0'
|
||||
self.raw_buffer = None
|
||||
break
|
||||
|
||||
def update_raw(self, size: Optional[int] = None) -> None:
|
||||
if size is None:
|
||||
size = 4096
|
||||
data = self.stream.read(size)
|
||||
if self.raw_buffer is None:
|
||||
self.raw_buffer = data
|
||||
else:
|
||||
self.raw_buffer += data
|
||||
self.stream_pointer += len(data)
|
||||
if not data:
|
||||
self.eof = True
|
||||
|
||||
|
||||
# try:
|
||||
# import psyco
|
||||
# psyco.bind(Reader)
|
||||
# except ImportError:
|
||||
# pass
|
||||
1139
venv/Lib/site-packages/ruamel/yaml/representer.py
Normal file
1139
venv/Lib/site-packages/ruamel/yaml/representer.py
Normal file
File diff suppressed because it is too large
Load Diff
392
venv/Lib/site-packages/ruamel/yaml/resolver.py
Normal file
392
venv/Lib/site-packages/ruamel/yaml/resolver.py
Normal file
@@ -0,0 +1,392 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, List, Union, Text, Optional # NOQA
|
||||
from ruamel.yaml.compat import VersionType # NOQA
|
||||
|
||||
from ruamel.yaml.tag import Tag
|
||||
from ruamel.yaml.compat import _DEFAULT_YAML_VERSION # NOQA
|
||||
from ruamel.yaml.error import * # NOQA
|
||||
from ruamel.yaml.nodes import MappingNode, ScalarNode, SequenceNode # NOQA
|
||||
from ruamel.yaml.util import RegExp # NOQA
|
||||
|
||||
__all__ = ['BaseResolver', 'Resolver', 'VersionedResolver']
|
||||
|
||||
|
||||
# fmt: off
|
||||
# resolvers consist of
|
||||
# - a list of applicable version
|
||||
# - a tag
|
||||
# - a regexp
|
||||
# - a list of first characters to match
|
||||
implicit_resolvers = [
|
||||
([(1, 2)],
|
||||
'tag:yaml.org,2002:bool',
|
||||
RegExp('''^(?:true|True|TRUE|false|False|FALSE)$''', re.X),
|
||||
list('tTfF')),
|
||||
([(1, 1)],
|
||||
'tag:yaml.org,2002:bool',
|
||||
RegExp('''^(?:y|Y|yes|Yes|YES|n|N|no|No|NO
|
||||
|true|True|TRUE|false|False|FALSE
|
||||
|on|On|ON|off|Off|OFF)$''', re.X),
|
||||
list('yYnNtTfFoO')),
|
||||
([(1, 2)],
|
||||
'tag:yaml.org,2002:float',
|
||||
RegExp('''^(?:
|
||||
[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
|
||||
|[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
|
||||
|[-+]?\\.[0-9_]+(?:[eE][-+][0-9]+)?
|
||||
|[-+]?\\.(?:inf|Inf|INF)
|
||||
|\\.(?:nan|NaN|NAN))$''', re.X),
|
||||
list('-+0123456789.')),
|
||||
([(1, 1)],
|
||||
'tag:yaml.org,2002:float',
|
||||
RegExp('''^(?:
|
||||
[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
|
||||
|[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
|
||||
|\\.[0-9_]+(?:[eE][-+][0-9]+)?
|
||||
|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]* # sexagesimal float
|
||||
|[-+]?\\.(?:inf|Inf|INF)
|
||||
|\\.(?:nan|NaN|NAN))$''', re.X),
|
||||
list('-+0123456789.')),
|
||||
([(1, 2)],
|
||||
'tag:yaml.org,2002:int',
|
||||
RegExp('''^(?:[-+]?0b[0-1_]+
|
||||
|[-+]?0o?[0-7_]+
|
||||
|[-+]?[0-9_]+
|
||||
|[-+]?0x[0-9a-fA-F_]+)$''', re.X),
|
||||
list('-+0123456789')),
|
||||
([(1, 1)],
|
||||
'tag:yaml.org,2002:int',
|
||||
RegExp('''^(?:[-+]?0b[0-1_]+
|
||||
|[-+]?0?[0-7_]+
|
||||
|[-+]?(?:0|[1-9][0-9_]*)
|
||||
|[-+]?0x[0-9a-fA-F_]+
|
||||
|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X), # sexagesimal int
|
||||
list('-+0123456789')),
|
||||
([(1, 2), (1, 1)],
|
||||
'tag:yaml.org,2002:merge',
|
||||
RegExp('^(?:<<)$'),
|
||||
['<']),
|
||||
([(1, 2), (1, 1)],
|
||||
'tag:yaml.org,2002:null',
|
||||
RegExp('''^(?: ~
|
||||
|null|Null|NULL
|
||||
| )$''', re.X),
|
||||
['~', 'n', 'N', '']),
|
||||
([(1, 2), (1, 1)],
|
||||
'tag:yaml.org,2002:timestamp',
|
||||
RegExp('''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
|
||||
|[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
|
||||
(?:[Tt]|[ \\t]+)[0-9][0-9]?
|
||||
:[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?
|
||||
(?:[ \\t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
|
||||
list('0123456789')),
|
||||
([(1, 2), (1, 1)],
|
||||
'tag:yaml.org,2002:value',
|
||||
RegExp('^(?:=)$'),
|
||||
['=']),
|
||||
# The following resolver is only for documentation purposes. It cannot work
|
||||
# because plain scalars cannot start with '!', '&', or '*'.
|
||||
([(1, 2), (1, 1)],
|
||||
'tag:yaml.org,2002:yaml',
|
||||
RegExp('^(?:!|&|\\*)$'),
|
||||
list('!&*')),
|
||||
]
|
||||
# fmt: on
|
||||
|
||||
|
||||
class ResolverError(YAMLError):
|
||||
pass
|
||||
|
||||
|
||||
class BaseResolver:
|
||||
|
||||
DEFAULT_SCALAR_TAG = Tag(suffix='tag:yaml.org,2002:str')
|
||||
DEFAULT_SEQUENCE_TAG = Tag(suffix='tag:yaml.org,2002:seq')
|
||||
DEFAULT_MAPPING_TAG = Tag(suffix='tag:yaml.org,2002:map')
|
||||
|
||||
yaml_implicit_resolvers: Dict[Any, Any] = {}
|
||||
yaml_path_resolvers: Dict[Any, Any] = {}
|
||||
|
||||
def __init__(self: Any, loadumper: Any = None) -> None:
|
||||
self.loadumper = loadumper
|
||||
if self.loadumper is not None and getattr(self.loadumper, '_resolver', None) is None:
|
||||
self.loadumper._resolver = self.loadumper
|
||||
self._loader_version: Any = None
|
||||
self.resolver_exact_paths: List[Any] = []
|
||||
self.resolver_prefix_paths: List[Any] = []
|
||||
|
||||
@property
|
||||
def parser(self) -> Any:
|
||||
if self.loadumper is not None:
|
||||
if hasattr(self.loadumper, 'typ'):
|
||||
return self.loadumper.parser
|
||||
return self.loadumper._parser
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def add_implicit_resolver_base(cls, tag: Any, regexp: Any, first: Any) -> None:
|
||||
if 'yaml_implicit_resolvers' not in cls.__dict__:
|
||||
# deepcopy doesn't work here
|
||||
cls.yaml_implicit_resolvers = {
|
||||
k: cls.yaml_implicit_resolvers[k][:] for k in cls.yaml_implicit_resolvers
|
||||
}
|
||||
if first is None:
|
||||
first = [None]
|
||||
for ch in first:
|
||||
cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))
|
||||
|
||||
@classmethod
|
||||
def add_implicit_resolver(cls, tag: Any, regexp: Any, first: Any) -> None:
|
||||
if 'yaml_implicit_resolvers' not in cls.__dict__:
|
||||
# deepcopy doesn't work here
|
||||
cls.yaml_implicit_resolvers = {
|
||||
k: cls.yaml_implicit_resolvers[k][:] for k in cls.yaml_implicit_resolvers
|
||||
}
|
||||
if first is None:
|
||||
first = [None]
|
||||
for ch in first:
|
||||
cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))
|
||||
implicit_resolvers.append(([(1, 2), (1, 1)], tag, regexp, first))
|
||||
|
||||
# @classmethod
|
||||
# def add_implicit_resolver(cls, tag, regexp, first):
|
||||
|
||||
@classmethod
|
||||
def add_path_resolver(cls, tag: Any, path: Any, kind: Any = None) -> None:
|
||||
# Note: `add_path_resolver` is experimental. The API could be changed.
|
||||
# `new_path` is a pattern that is matched against the path from the
|
||||
# root to the node that is being considered. `node_path` elements are
|
||||
# tuples `(node_check, index_check)`. `node_check` is a node class:
|
||||
# `ScalarNode`, `SequenceNode`, `MappingNode` or `None`. `None`
|
||||
# matches any kind of a node. `index_check` could be `None`, a boolean
|
||||
# value, a string value, or a number. `None` and `False` match against
|
||||
# any _value_ of sequence and mapping nodes. `True` matches against
|
||||
# any _key_ of a mapping node. A string `index_check` matches against
|
||||
# a mapping value that corresponds to a scalar key which content is
|
||||
# equal to the `index_check` value. An integer `index_check` matches
|
||||
# against a sequence value with the index equal to `index_check`.
|
||||
if 'yaml_path_resolvers' not in cls.__dict__:
|
||||
cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy()
|
||||
new_path: List[Any] = []
|
||||
for element in path:
|
||||
if isinstance(element, (list, tuple)):
|
||||
if len(element) == 2:
|
||||
node_check, index_check = element
|
||||
elif len(element) == 1:
|
||||
node_check = element[0]
|
||||
index_check = True
|
||||
else:
|
||||
raise ResolverError(f'Invalid path element: {element!s}')
|
||||
else:
|
||||
node_check = None
|
||||
index_check = element
|
||||
if node_check is str:
|
||||
node_check = ScalarNode
|
||||
elif node_check is list:
|
||||
node_check = SequenceNode
|
||||
elif node_check is dict:
|
||||
node_check = MappingNode
|
||||
elif (
|
||||
node_check not in [ScalarNode, SequenceNode, MappingNode]
|
||||
and not isinstance(node_check, str)
|
||||
and node_check is not None
|
||||
):
|
||||
raise ResolverError(f'Invalid node checker: {node_check!s}')
|
||||
if not isinstance(index_check, (str, int)) and index_check is not None:
|
||||
raise ResolverError(f'Invalid index checker: {index_check!s}')
|
||||
new_path.append((node_check, index_check))
|
||||
if kind is str:
|
||||
kind = ScalarNode
|
||||
elif kind is list:
|
||||
kind = SequenceNode
|
||||
elif kind is dict:
|
||||
kind = MappingNode
|
||||
elif kind not in [ScalarNode, SequenceNode, MappingNode] and kind is not None:
|
||||
raise ResolverError(f'Invalid node kind: {kind!s}')
|
||||
cls.yaml_path_resolvers[tuple(new_path), kind] = tag
|
||||
|
||||
def descend_resolver(self, current_node: Any, current_index: Any) -> None:
|
||||
if not self.yaml_path_resolvers:
|
||||
return
|
||||
exact_paths = {}
|
||||
prefix_paths = []
|
||||
if current_node:
|
||||
depth = len(self.resolver_prefix_paths)
|
||||
for path, kind in self.resolver_prefix_paths[-1]:
|
||||
if self.check_resolver_prefix(depth, path, kind, current_node, current_index):
|
||||
if len(path) > depth:
|
||||
prefix_paths.append((path, kind))
|
||||
else:
|
||||
exact_paths[kind] = self.yaml_path_resolvers[path, kind]
|
||||
else:
|
||||
for path, kind in self.yaml_path_resolvers:
|
||||
if not path:
|
||||
exact_paths[kind] = self.yaml_path_resolvers[path, kind]
|
||||
else:
|
||||
prefix_paths.append((path, kind))
|
||||
self.resolver_exact_paths.append(exact_paths)
|
||||
self.resolver_prefix_paths.append(prefix_paths)
|
||||
|
||||
def ascend_resolver(self) -> None:
|
||||
if not self.yaml_path_resolvers:
|
||||
return
|
||||
self.resolver_exact_paths.pop()
|
||||
self.resolver_prefix_paths.pop()
|
||||
|
||||
def check_resolver_prefix(
|
||||
self, depth: int, path: Any, kind: Any, current_node: Any, current_index: Any,
|
||||
) -> bool:
|
||||
node_check, index_check = path[depth - 1]
|
||||
if isinstance(node_check, str):
|
||||
if current_node.tag != node_check:
|
||||
return False
|
||||
elif node_check is not None:
|
||||
if not isinstance(current_node, node_check):
|
||||
return False
|
||||
if index_check is True and current_index is not None:
|
||||
return False
|
||||
if (index_check is False or index_check is None) and current_index is None:
|
||||
return False
|
||||
if isinstance(index_check, str):
|
||||
if not (
|
||||
isinstance(current_index, ScalarNode) and index_check == current_index.value
|
||||
):
|
||||
return False
|
||||
elif isinstance(index_check, int) and not isinstance(index_check, bool):
|
||||
if index_check != current_index:
|
||||
return False
|
||||
return True
|
||||
|
||||
def resolve(self, kind: Any, value: Any, implicit: Any) -> Any:
|
||||
if kind is ScalarNode and implicit[0]:
|
||||
if value == "":
|
||||
resolvers = self.yaml_implicit_resolvers.get("", [])
|
||||
else:
|
||||
resolvers = self.yaml_implicit_resolvers.get(value[0], [])
|
||||
resolvers += self.yaml_implicit_resolvers.get(None, [])
|
||||
for tag, regexp in resolvers:
|
||||
if regexp.match(value):
|
||||
return Tag(suffix=tag)
|
||||
implicit = implicit[1]
|
||||
if bool(self.yaml_path_resolvers):
|
||||
exact_paths = self.resolver_exact_paths[-1]
|
||||
if kind in exact_paths:
|
||||
return Tag(suffix=exact_paths[kind])
|
||||
if None in exact_paths:
|
||||
return Tag(suffix=exact_paths[None])
|
||||
if kind is ScalarNode:
|
||||
return self.DEFAULT_SCALAR_TAG
|
||||
elif kind is SequenceNode:
|
||||
return self.DEFAULT_SEQUENCE_TAG
|
||||
elif kind is MappingNode:
|
||||
return self.DEFAULT_MAPPING_TAG
|
||||
|
||||
@property
|
||||
def processing_version(self) -> Any:
|
||||
return None
|
||||
|
||||
|
||||
class Resolver(BaseResolver):
|
||||
pass
|
||||
|
||||
|
||||
for ir in implicit_resolvers:
|
||||
if (1, 2) in ir[0]:
|
||||
Resolver.add_implicit_resolver_base(*ir[1:])
|
||||
|
||||
|
||||
class VersionedResolver(BaseResolver):
|
||||
"""
|
||||
contrary to the "normal" resolver, the smart resolver delays loading
|
||||
the pattern matching rules. That way it can decide to load 1.1 rules
|
||||
or the (default) 1.2 rules, that no longer support octal without 0o, sexagesimals
|
||||
and Yes/No/On/Off booleans.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, version: Optional[VersionType] = None, loader: Any = None, loadumper: Any = None,
|
||||
) -> None:
|
||||
if loader is None and loadumper is not None:
|
||||
loader = loadumper
|
||||
BaseResolver.__init__(self, loader)
|
||||
self._loader_version = self.get_loader_version(version)
|
||||
self._version_implicit_resolver: Dict[Any, Any] = {}
|
||||
|
||||
def add_version_implicit_resolver(
|
||||
self, version: VersionType, tag: Any, regexp: Any, first: Any,
|
||||
) -> None:
|
||||
if first is None:
|
||||
first = [None]
|
||||
impl_resolver = self._version_implicit_resolver.setdefault(version, {})
|
||||
for ch in first:
|
||||
impl_resolver.setdefault(ch, []).append((tag, regexp))
|
||||
|
||||
def get_loader_version(self, version: Optional[VersionType]) -> Any:
|
||||
if version is None or isinstance(version, tuple):
|
||||
return version
|
||||
if isinstance(version, list):
|
||||
return tuple(version)
|
||||
# assume string
|
||||
assert isinstance(version, str)
|
||||
return tuple(map(int, version.split('.')))
|
||||
|
||||
@property
|
||||
def versioned_resolver(self) -> Any:
|
||||
"""
|
||||
select the resolver based on the version we are parsing
|
||||
"""
|
||||
version = self.processing_version
|
||||
if isinstance(version, str):
|
||||
version = tuple(map(int, version.split('.')))
|
||||
if version not in self._version_implicit_resolver:
|
||||
for x in implicit_resolvers:
|
||||
if version in x[0]:
|
||||
self.add_version_implicit_resolver(version, x[1], x[2], x[3])
|
||||
return self._version_implicit_resolver[version]
|
||||
|
||||
def resolve(self, kind: Any, value: Any, implicit: Any) -> Any:
|
||||
if kind is ScalarNode and implicit[0]:
|
||||
if value == "":
|
||||
resolvers = self.versioned_resolver.get("", [])
|
||||
else:
|
||||
resolvers = self.versioned_resolver.get(value[0], [])
|
||||
resolvers += self.versioned_resolver.get(None, [])
|
||||
for tag, regexp in resolvers:
|
||||
if regexp.match(value):
|
||||
return Tag(suffix=tag)
|
||||
implicit = implicit[1]
|
||||
if bool(self.yaml_path_resolvers):
|
||||
exact_paths = self.resolver_exact_paths[-1]
|
||||
if kind in exact_paths:
|
||||
return Tag(suffix=exact_paths[kind])
|
||||
if None in exact_paths:
|
||||
return Tag(suffix=exact_paths[None])
|
||||
if kind is ScalarNode:
|
||||
return self.DEFAULT_SCALAR_TAG
|
||||
elif kind is SequenceNode:
|
||||
return self.DEFAULT_SEQUENCE_TAG
|
||||
elif kind is MappingNode:
|
||||
return self.DEFAULT_MAPPING_TAG
|
||||
|
||||
@property
|
||||
def processing_version(self) -> Any:
|
||||
try:
|
||||
version = self.loadumper._scanner.yaml_version
|
||||
except AttributeError:
|
||||
try:
|
||||
if hasattr(self.loadumper, 'typ'):
|
||||
version = self.loadumper.version
|
||||
else:
|
||||
version = self.loadumper._serializer.use_version # dumping
|
||||
except AttributeError:
|
||||
version = None
|
||||
if version is None:
|
||||
version = self._loader_version
|
||||
if version is None:
|
||||
version = _DEFAULT_YAML_VERSION
|
||||
return version
|
||||
43
venv/Lib/site-packages/ruamel/yaml/scalarbool.py
Normal file
43
venv/Lib/site-packages/ruamel/yaml/scalarbool.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""
|
||||
You cannot subclass bool, and this is necessary for round-tripping anchored
|
||||
bool values (and also if you want to preserve the original way of writing)
|
||||
|
||||
bool.__bases__ is type 'int', so that is what is used as the basis for ScalarBoolean as well.
|
||||
|
||||
You can use these in an if statement, but not when testing equivalence
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ruamel.yaml.anchor import Anchor
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Text, Any, Dict, List # NOQA
|
||||
|
||||
__all__ = ['ScalarBoolean']
|
||||
|
||||
|
||||
class ScalarBoolean(int):
|
||||
def __new__(cls: Any, *args: Any, **kw: Any) -> Any:
|
||||
anchor = kw.pop('anchor', None)
|
||||
b = int.__new__(cls, *args, **kw)
|
||||
if anchor is not None:
|
||||
b.yaml_set_anchor(anchor, always_dump=True)
|
||||
return b
|
||||
|
||||
@property
|
||||
def anchor(self) -> Any:
|
||||
if not hasattr(self, Anchor.attrib):
|
||||
setattr(self, Anchor.attrib, Anchor())
|
||||
return getattr(self, Anchor.attrib)
|
||||
|
||||
def yaml_anchor(self, any: bool = False) -> Any:
|
||||
if not hasattr(self, Anchor.attrib):
|
||||
return None
|
||||
if any or self.anchor.always_dump:
|
||||
return self.anchor
|
||||
return None
|
||||
|
||||
def yaml_set_anchor(self, value: Any, always_dump: bool = False) -> None:
|
||||
self.anchor.value = value
|
||||
self.anchor.always_dump = always_dump
|
||||
105
venv/Lib/site-packages/ruamel/yaml/scalarfloat.py
Normal file
105
venv/Lib/site-packages/ruamel/yaml/scalarfloat.py
Normal file
@@ -0,0 +1,105 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from ruamel.yaml.anchor import Anchor
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Text, Any, Dict, List # NOQA
|
||||
|
||||
__all__ = ['ScalarFloat', 'ExponentialFloat', 'ExponentialCapsFloat']
|
||||
|
||||
|
||||
class ScalarFloat(float):
|
||||
def __new__(cls: Any, *args: Any, **kw: Any) -> Any:
|
||||
width = kw.pop('width', None)
|
||||
prec = kw.pop('prec', None)
|
||||
m_sign = kw.pop('m_sign', None)
|
||||
m_lead0 = kw.pop('m_lead0', 0)
|
||||
exp = kw.pop('exp', None)
|
||||
e_width = kw.pop('e_width', None)
|
||||
e_sign = kw.pop('e_sign', None)
|
||||
underscore = kw.pop('underscore', None)
|
||||
anchor = kw.pop('anchor', None)
|
||||
v = float.__new__(cls, *args, **kw)
|
||||
v._width = width
|
||||
v._prec = prec
|
||||
v._m_sign = m_sign
|
||||
v._m_lead0 = m_lead0
|
||||
v._exp = exp
|
||||
v._e_width = e_width
|
||||
v._e_sign = e_sign
|
||||
v._underscore = underscore
|
||||
if anchor is not None:
|
||||
v.yaml_set_anchor(anchor, always_dump=True)
|
||||
return v
|
||||
|
||||
def __iadd__(self, a: Any) -> Any: # type: ignore
|
||||
return float(self) + a
|
||||
x = type(self)(self + a)
|
||||
x._width = self._width
|
||||
x._underscore = self._underscore[:] if self._underscore is not None else None # NOQA
|
||||
return x
|
||||
|
||||
def __ifloordiv__(self, a: Any) -> Any: # type: ignore
|
||||
return float(self) // a
|
||||
x = type(self)(self // a)
|
||||
x._width = self._width
|
||||
x._underscore = self._underscore[:] if self._underscore is not None else None # NOQA
|
||||
return x
|
||||
|
||||
def __imul__(self, a: Any) -> Any: # type: ignore
|
||||
return float(self) * a
|
||||
x = type(self)(self * a)
|
||||
x._width = self._width
|
||||
x._underscore = self._underscore[:] if self._underscore is not None else None # NOQA
|
||||
x._prec = self._prec # check for others
|
||||
return x
|
||||
|
||||
def __ipow__(self, a: Any) -> Any: # type: ignore
|
||||
return float(self) ** a
|
||||
x = type(self)(self ** a)
|
||||
x._width = self._width
|
||||
x._underscore = self._underscore[:] if self._underscore is not None else None # NOQA
|
||||
return x
|
||||
|
||||
def __isub__(self, a: Any) -> Any: # type: ignore
|
||||
return float(self) - a
|
||||
x = type(self)(self - a)
|
||||
x._width = self._width
|
||||
x._underscore = self._underscore[:] if self._underscore is not None else None # NOQA
|
||||
return x
|
||||
|
||||
@property
|
||||
def anchor(self) -> Any:
|
||||
if not hasattr(self, Anchor.attrib):
|
||||
setattr(self, Anchor.attrib, Anchor())
|
||||
return getattr(self, Anchor.attrib)
|
||||
|
||||
def yaml_anchor(self, any: bool = False) -> Any:
|
||||
if not hasattr(self, Anchor.attrib):
|
||||
return None
|
||||
if any or self.anchor.always_dump:
|
||||
return self.anchor
|
||||
return None
|
||||
|
||||
def yaml_set_anchor(self, value: Any, always_dump: bool = False) -> None:
|
||||
self.anchor.value = value
|
||||
self.anchor.always_dump = always_dump
|
||||
|
||||
def dump(self, out: Any = sys.stdout) -> None:
|
||||
out.write(
|
||||
f'ScalarFloat({self}| w:{self._width}, p:{self._prec}, ' # type: ignore
|
||||
f's:{self._m_sign}, lz:{self._m_lead0}, _:{self._underscore}|{self._exp}'
|
||||
f', w:{self._e_width}, s:{self._e_sign})\n',
|
||||
)
|
||||
|
||||
|
||||
class ExponentialFloat(ScalarFloat):
|
||||
def __new__(cls, value: Any, width: Any = None, underscore: Any = None) -> Any:
|
||||
return ScalarFloat.__new__(cls, value, width=width, underscore=underscore)
|
||||
|
||||
|
||||
class ExponentialCapsFloat(ScalarFloat):
|
||||
def __new__(cls, value: Any, width: Any = None, underscore: Any = None) -> Any:
|
||||
return ScalarFloat.__new__(cls, value, width=width, underscore=underscore)
|
||||
124
venv/Lib/site-packages/ruamel/yaml/scalarint.py
Normal file
124
venv/Lib/site-packages/ruamel/yaml/scalarint.py
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ruamel.yaml.anchor import Anchor
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Text, Any, Dict, List # NOQA
|
||||
|
||||
__all__ = ['ScalarInt', 'BinaryInt', 'OctalInt', 'HexInt', 'HexCapsInt', 'DecimalInt']
|
||||
|
||||
|
||||
class ScalarInt(int):
|
||||
def __new__(cls: Any, *args: Any, **kw: Any) -> Any:
|
||||
width = kw.pop('width', None)
|
||||
underscore = kw.pop('underscore', None)
|
||||
anchor = kw.pop('anchor', None)
|
||||
v = int.__new__(cls, *args, **kw)
|
||||
v._width = width
|
||||
v._underscore = underscore
|
||||
if anchor is not None:
|
||||
v.yaml_set_anchor(anchor, always_dump=True)
|
||||
return v
|
||||
|
||||
def __iadd__(self, a: Any) -> Any: # type: ignore
|
||||
x = type(self)(self + a)
|
||||
x._width = self._width # type: ignore
|
||||
x._underscore = ( # type: ignore
|
||||
self._underscore[:] if self._underscore is not None else None # type: ignore
|
||||
) # NOQA
|
||||
return x
|
||||
|
||||
def __ifloordiv__(self, a: Any) -> Any: # type: ignore
|
||||
x = type(self)(self // a)
|
||||
x._width = self._width # type: ignore
|
||||
x._underscore = ( # type: ignore
|
||||
self._underscore[:] if self._underscore is not None else None # type: ignore
|
||||
) # NOQA
|
||||
return x
|
||||
|
||||
def __imul__(self, a: Any) -> Any: # type: ignore
|
||||
x = type(self)(self * a)
|
||||
x._width = self._width # type: ignore
|
||||
x._underscore = ( # type: ignore
|
||||
self._underscore[:] if self._underscore is not None else None # type: ignore
|
||||
) # NOQA
|
||||
return x
|
||||
|
||||
def __ipow__(self, a: Any) -> Any: # type: ignore
|
||||
x = type(self)(self ** a)
|
||||
x._width = self._width # type: ignore
|
||||
x._underscore = ( # type: ignore
|
||||
self._underscore[:] if self._underscore is not None else None # type: ignore
|
||||
) # NOQA
|
||||
return x
|
||||
|
||||
def __isub__(self, a: Any) -> Any: # type: ignore
|
||||
x = type(self)(self - a)
|
||||
x._width = self._width # type: ignore
|
||||
x._underscore = ( # type: ignore
|
||||
self._underscore[:] if self._underscore is not None else None # type: ignore
|
||||
) # NOQA
|
||||
return x
|
||||
|
||||
@property
|
||||
def anchor(self) -> Any:
|
||||
if not hasattr(self, Anchor.attrib):
|
||||
setattr(self, Anchor.attrib, Anchor())
|
||||
return getattr(self, Anchor.attrib)
|
||||
|
||||
def yaml_anchor(self, any: bool = False) -> Any:
|
||||
if not hasattr(self, Anchor.attrib):
|
||||
return None
|
||||
if any or self.anchor.always_dump:
|
||||
return self.anchor
|
||||
return None
|
||||
|
||||
def yaml_set_anchor(self, value: Any, always_dump: bool = False) -> None:
|
||||
self.anchor.value = value
|
||||
self.anchor.always_dump = always_dump
|
||||
|
||||
|
||||
class BinaryInt(ScalarInt):
|
||||
def __new__(
|
||||
cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None,
|
||||
) -> Any:
|
||||
return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor)
|
||||
|
||||
|
||||
class OctalInt(ScalarInt):
|
||||
def __new__(
|
||||
cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None,
|
||||
) -> Any:
|
||||
return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor)
|
||||
|
||||
|
||||
# mixed casing of A-F is not supported, when loading the first non digit
|
||||
# determines the case
|
||||
|
||||
|
||||
class HexInt(ScalarInt):
|
||||
"""uses lower case (a-f)"""
|
||||
|
||||
def __new__(
|
||||
cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None,
|
||||
) -> Any:
|
||||
return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor)
|
||||
|
||||
|
||||
class HexCapsInt(ScalarInt):
|
||||
"""uses upper case (A-F)"""
|
||||
|
||||
def __new__(
|
||||
cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None,
|
||||
) -> Any:
|
||||
return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor)
|
||||
|
||||
|
||||
class DecimalInt(ScalarInt):
|
||||
"""needed if anchor"""
|
||||
|
||||
def __new__(
|
||||
cls, value: Any, width: Any = None, underscore: Any = None, anchor: Any = None,
|
||||
) -> Any:
|
||||
return ScalarInt.__new__(cls, value, width=width, underscore=underscore, anchor=anchor)
|
||||
142
venv/Lib/site-packages/ruamel/yaml/scalarstring.py
Normal file
142
venv/Lib/site-packages/ruamel/yaml/scalarstring.py
Normal file
@@ -0,0 +1,142 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ruamel.yaml.anchor import Anchor
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Text, Any, Dict, List # NOQA
|
||||
from ruamel.yaml.compat import SupportsIndex
|
||||
|
||||
__all__ = [
|
||||
'ScalarString',
|
||||
'LiteralScalarString',
|
||||
'FoldedScalarString',
|
||||
'SingleQuotedScalarString',
|
||||
'DoubleQuotedScalarString',
|
||||
'PlainScalarString',
|
||||
# PreservedScalarString is the old name, as it was the first to be preserved on rt,
|
||||
# use LiteralScalarString instead
|
||||
'PreservedScalarString',
|
||||
]
|
||||
|
||||
|
||||
class ScalarString(str):
|
||||
__slots__ = Anchor.attrib
|
||||
|
||||
def __new__(cls, *args: Any, **kw: Any) -> Any:
|
||||
anchor = kw.pop('anchor', None)
|
||||
ret_val = str.__new__(cls, *args, **kw)
|
||||
if anchor is not None:
|
||||
ret_val.yaml_set_anchor(anchor, always_dump=True)
|
||||
return ret_val
|
||||
|
||||
def replace(self, old: Any, new: Any, maxreplace: SupportsIndex = -1) -> Any:
|
||||
return type(self)((str.replace(self, old, new, maxreplace)))
|
||||
|
||||
@property
|
||||
def anchor(self) -> Any:
|
||||
if not hasattr(self, Anchor.attrib):
|
||||
setattr(self, Anchor.attrib, Anchor())
|
||||
return getattr(self, Anchor.attrib)
|
||||
|
||||
def yaml_anchor(self, any: bool = False) -> Any:
|
||||
if not hasattr(self, Anchor.attrib):
|
||||
return None
|
||||
if any or self.anchor.always_dump:
|
||||
return self.anchor
|
||||
return None
|
||||
|
||||
def yaml_set_anchor(self, value: Any, always_dump: bool = False) -> None:
|
||||
self.anchor.value = value
|
||||
self.anchor.always_dump = always_dump
|
||||
|
||||
|
||||
class LiteralScalarString(ScalarString):
|
||||
__slots__ = 'comment' # the comment after the | on the first line
|
||||
|
||||
style = '|'
|
||||
|
||||
def __new__(cls, value: Text, anchor: Any = None) -> Any:
|
||||
return ScalarString.__new__(cls, value, anchor=anchor)
|
||||
|
||||
|
||||
PreservedScalarString = LiteralScalarString
|
||||
|
||||
|
||||
class FoldedScalarString(ScalarString):
|
||||
__slots__ = ('fold_pos', 'comment') # the comment after the > on the first line
|
||||
|
||||
style = '>'
|
||||
|
||||
def __new__(cls, value: Text, anchor: Any = None) -> Any:
|
||||
return ScalarString.__new__(cls, value, anchor=anchor)
|
||||
|
||||
|
||||
class SingleQuotedScalarString(ScalarString):
|
||||
__slots__ = ()
|
||||
|
||||
style = "'"
|
||||
|
||||
def __new__(cls, value: Text, anchor: Any = None) -> Any:
|
||||
return ScalarString.__new__(cls, value, anchor=anchor)
|
||||
|
||||
|
||||
class DoubleQuotedScalarString(ScalarString):
|
||||
__slots__ = ()
|
||||
|
||||
style = '"'
|
||||
|
||||
def __new__(cls, value: Text, anchor: Any = None) -> Any:
|
||||
return ScalarString.__new__(cls, value, anchor=anchor)
|
||||
|
||||
|
||||
class PlainScalarString(ScalarString):
|
||||
__slots__ = ()
|
||||
|
||||
style = ''
|
||||
|
||||
def __new__(cls, value: Text, anchor: Any = None) -> Any:
|
||||
return ScalarString.__new__(cls, value, anchor=anchor)
|
||||
|
||||
|
||||
def preserve_literal(s: Text) -> Text:
|
||||
return LiteralScalarString(s.replace('\r\n', '\n').replace('\r', '\n'))
|
||||
|
||||
|
||||
def walk_tree(base: Any, map: Any = None) -> None:
|
||||
"""
|
||||
the routine here walks over a simple yaml tree (recursing in
|
||||
dict values and list items) and converts strings that
|
||||
have multiple lines to literal scalars
|
||||
|
||||
You can also provide an explicit (ordered) mapping for multiple transforms
|
||||
(first of which is executed):
|
||||
map = ruamel.yaml.compat.ordereddict
|
||||
map['\n'] = preserve_literal
|
||||
map[':'] = SingleQuotedScalarString
|
||||
walk_tree(data, map=map)
|
||||
"""
|
||||
from collections.abc import MutableMapping, MutableSequence
|
||||
|
||||
if map is None:
|
||||
map = {'\n': preserve_literal}
|
||||
|
||||
if isinstance(base, MutableMapping):
|
||||
for k in base:
|
||||
v: Text = base[k]
|
||||
if isinstance(v, str):
|
||||
for ch in map:
|
||||
if ch in v:
|
||||
base[k] = map[ch](v)
|
||||
break
|
||||
else:
|
||||
walk_tree(v, map=map)
|
||||
elif isinstance(base, MutableSequence):
|
||||
for idx, elem in enumerate(base):
|
||||
if isinstance(elem, str):
|
||||
for ch in map:
|
||||
if ch in elem:
|
||||
base[idx] = map[ch](elem)
|
||||
break
|
||||
else:
|
||||
walk_tree(elem, map=map)
|
||||
2390
venv/Lib/site-packages/ruamel/yaml/scanner.py
Normal file
2390
venv/Lib/site-packages/ruamel/yaml/scanner.py
Normal file
File diff suppressed because it is too large
Load Diff
233
venv/Lib/site-packages/ruamel/yaml/serializer.py
Normal file
233
venv/Lib/site-packages/ruamel/yaml/serializer.py
Normal file
@@ -0,0 +1,233 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ruamel.yaml.error import YAMLError
|
||||
from ruamel.yaml.compat import nprint, DBG_NODE, dbg, nprintf # NOQA
|
||||
from ruamel.yaml.util import RegExp
|
||||
|
||||
from ruamel.yaml.events import (
|
||||
StreamStartEvent,
|
||||
StreamEndEvent,
|
||||
MappingStartEvent,
|
||||
MappingEndEvent,
|
||||
SequenceStartEvent,
|
||||
SequenceEndEvent,
|
||||
AliasEvent,
|
||||
ScalarEvent,
|
||||
DocumentStartEvent,
|
||||
DocumentEndEvent,
|
||||
)
|
||||
from ruamel.yaml.nodes import MappingNode, ScalarNode, SequenceNode
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Union, Text, Optional # NOQA
|
||||
from ruamel.yaml.compat import VersionType # NOQA
|
||||
|
||||
__all__ = ['Serializer', 'SerializerError']
|
||||
|
||||
|
||||
class SerializerError(YAMLError):
|
||||
pass
|
||||
|
||||
|
||||
class Serializer:
|
||||
|
||||
# 'id' and 3+ numbers, but not 000
|
||||
ANCHOR_TEMPLATE = 'id{:03d}'
|
||||
ANCHOR_RE = RegExp('id(?!000$)\\d{3,}')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
encoding: Any = None,
|
||||
explicit_start: Optional[bool] = None,
|
||||
explicit_end: Optional[bool] = None,
|
||||
version: Optional[VersionType] = None,
|
||||
tags: Any = None,
|
||||
dumper: Any = None,
|
||||
) -> None:
|
||||
# NOQA
|
||||
self.dumper = dumper
|
||||
if self.dumper is not None:
|
||||
self.dumper._serializer = self
|
||||
self.use_encoding = encoding
|
||||
self.use_explicit_start = explicit_start
|
||||
self.use_explicit_end = explicit_end
|
||||
if isinstance(version, str):
|
||||
self.use_version = tuple(map(int, version.split('.')))
|
||||
else:
|
||||
self.use_version = version # type: ignore
|
||||
self.use_tags = tags
|
||||
self.serialized_nodes: Dict[Any, Any] = {}
|
||||
self.anchors: Dict[Any, Any] = {}
|
||||
self.last_anchor_id = 0
|
||||
self.closed: Optional[bool] = None
|
||||
self._templated_id = None
|
||||
|
||||
@property
|
||||
def emitter(self) -> Any:
|
||||
if hasattr(self.dumper, 'typ'):
|
||||
return self.dumper.emitter
|
||||
return self.dumper._emitter
|
||||
|
||||
@property
|
||||
def resolver(self) -> Any:
|
||||
if hasattr(self.dumper, 'typ'):
|
||||
self.dumper.resolver
|
||||
return self.dumper._resolver
|
||||
|
||||
def open(self) -> None:
|
||||
if self.closed is None:
|
||||
self.emitter.emit(StreamStartEvent(encoding=self.use_encoding))
|
||||
self.closed = False
|
||||
elif self.closed:
|
||||
raise SerializerError('serializer is closed')
|
||||
else:
|
||||
raise SerializerError('serializer is already opened')
|
||||
|
||||
def close(self) -> None:
|
||||
if self.closed is None:
|
||||
raise SerializerError('serializer is not opened')
|
||||
elif not self.closed:
|
||||
self.emitter.emit(StreamEndEvent())
|
||||
self.closed = True
|
||||
|
||||
# def __del__(self):
|
||||
# self.close()
|
||||
|
||||
def serialize(self, node: Any) -> None:
|
||||
if dbg(DBG_NODE):
|
||||
nprint('Serializing nodes')
|
||||
node.dump()
|
||||
if self.closed is None:
|
||||
raise SerializerError('serializer is not opened')
|
||||
elif self.closed:
|
||||
raise SerializerError('serializer is closed')
|
||||
self.emitter.emit(
|
||||
DocumentStartEvent(
|
||||
explicit=self.use_explicit_start, version=self.use_version, tags=self.use_tags,
|
||||
),
|
||||
)
|
||||
self.anchor_node(node)
|
||||
self.serialize_node(node, None, None)
|
||||
self.emitter.emit(DocumentEndEvent(explicit=self.use_explicit_end))
|
||||
self.serialized_nodes = {}
|
||||
self.anchors = {}
|
||||
self.last_anchor_id = 0
|
||||
|
||||
def anchor_node(self, node: Any) -> None:
|
||||
if node in self.anchors:
|
||||
if self.anchors[node] is None:
|
||||
self.anchors[node] = self.generate_anchor(node)
|
||||
else:
|
||||
anchor = None
|
||||
try:
|
||||
if node.anchor.always_dump:
|
||||
anchor = node.anchor.value
|
||||
except: # NOQA
|
||||
pass
|
||||
self.anchors[node] = anchor
|
||||
if isinstance(node, SequenceNode):
|
||||
for item in node.value:
|
||||
self.anchor_node(item)
|
||||
elif isinstance(node, MappingNode):
|
||||
for key, value in node.value:
|
||||
self.anchor_node(key)
|
||||
self.anchor_node(value)
|
||||
|
||||
def generate_anchor(self, node: Any) -> Any:
|
||||
try:
|
||||
anchor = node.anchor.value
|
||||
except: # NOQA
|
||||
anchor = None
|
||||
if anchor is None:
|
||||
self.last_anchor_id += 1
|
||||
return self.ANCHOR_TEMPLATE.format(self.last_anchor_id)
|
||||
return anchor
|
||||
|
||||
def serialize_node(self, node: Any, parent: Any, index: Any) -> None:
|
||||
alias = self.anchors[node]
|
||||
if node in self.serialized_nodes:
|
||||
node_style = getattr(node, 'style', None)
|
||||
if node_style != '?':
|
||||
node_style = None
|
||||
self.emitter.emit(AliasEvent(alias, style=node_style))
|
||||
else:
|
||||
self.serialized_nodes[node] = True
|
||||
self.resolver.descend_resolver(parent, index)
|
||||
if isinstance(node, ScalarNode):
|
||||
# here check if the node.tag equals the one that would result from parsing
|
||||
# if not equal quoting is necessary for strings
|
||||
detected_tag = self.resolver.resolve(ScalarNode, node.value, (True, False))
|
||||
default_tag = self.resolver.resolve(ScalarNode, node.value, (False, True))
|
||||
implicit = (
|
||||
(node.ctag == detected_tag),
|
||||
(node.ctag == default_tag),
|
||||
node.tag.startswith('tag:yaml.org,2002:'), # type: ignore
|
||||
)
|
||||
self.emitter.emit(
|
||||
ScalarEvent(
|
||||
alias,
|
||||
node.ctag,
|
||||
implicit,
|
||||
node.value,
|
||||
style=node.style,
|
||||
comment=node.comment,
|
||||
),
|
||||
)
|
||||
elif isinstance(node, SequenceNode):
|
||||
implicit = node.ctag == self.resolver.resolve(SequenceNode, node.value, True)
|
||||
comment = node.comment
|
||||
end_comment = None
|
||||
seq_comment = None
|
||||
if node.flow_style is True:
|
||||
if comment: # eol comment on flow style sequence
|
||||
seq_comment = comment[0]
|
||||
# comment[0] = None
|
||||
if comment and len(comment) > 2:
|
||||
end_comment = comment[2]
|
||||
else:
|
||||
end_comment = None
|
||||
self.emitter.emit(
|
||||
SequenceStartEvent(
|
||||
alias,
|
||||
node.ctag,
|
||||
implicit,
|
||||
flow_style=node.flow_style,
|
||||
comment=node.comment,
|
||||
),
|
||||
)
|
||||
index = 0
|
||||
for item in node.value:
|
||||
self.serialize_node(item, node, index)
|
||||
index += 1
|
||||
self.emitter.emit(SequenceEndEvent(comment=[seq_comment, end_comment]))
|
||||
elif isinstance(node, MappingNode):
|
||||
implicit = node.ctag == self.resolver.resolve(MappingNode, node.value, True)
|
||||
comment = node.comment
|
||||
end_comment = None
|
||||
map_comment = None
|
||||
if node.flow_style is True:
|
||||
if comment: # eol comment on flow style sequence
|
||||
map_comment = comment[0]
|
||||
# comment[0] = None
|
||||
if comment and len(comment) > 2:
|
||||
end_comment = comment[2]
|
||||
self.emitter.emit(
|
||||
MappingStartEvent(
|
||||
alias,
|
||||
node.ctag,
|
||||
implicit,
|
||||
flow_style=node.flow_style,
|
||||
comment=node.comment,
|
||||
nr_items=len(node.value),
|
||||
),
|
||||
)
|
||||
for key, value in node.value:
|
||||
self.serialize_node(key, node, None)
|
||||
self.serialize_node(value, node, key)
|
||||
self.emitter.emit(MappingEndEvent(comment=[map_comment, end_comment]))
|
||||
self.resolver.ascend_resolver()
|
||||
|
||||
|
||||
def templated_id(s: Text) -> Any:
|
||||
return Serializer.ANCHOR_RE.match(s)
|
||||
126
venv/Lib/site-packages/ruamel/yaml/tag.py
Normal file
126
venv/Lib/site-packages/ruamel/yaml/tag.py
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
"""
|
||||
In round-trip mode the original tag needs to be preserved, but the tag
|
||||
transformed based on the directives needs to be available as well.
|
||||
|
||||
A Tag that is created during loading has a handle and a suffix.
|
||||
Not all objects loaded currently have a Tag, that .tag attribute can be None
|
||||
A Tag that is created for dumping only (on an object loaded without a tag) has a suffix
|
||||
only.
|
||||
"""
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List, Union, Iterator # NOQA
|
||||
|
||||
tag_attrib = '_yaml_tag'
|
||||
|
||||
|
||||
class Tag:
|
||||
"""store original tag information for roundtripping"""
|
||||
|
||||
attrib = tag_attrib
|
||||
|
||||
def __init__(self, handle: Any = None, suffix: Any = None, handles: Any = None) -> None:
|
||||
self.handle = handle
|
||||
self.suffix = suffix
|
||||
self.handles = handles
|
||||
self._transform_type: Optional[bool] = None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'{self.__class__.__name__}({self.trval!r})'
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f'{self.trval}'
|
||||
|
||||
def __hash__(self) -> int:
|
||||
try:
|
||||
return self._hash_id # type: ignore
|
||||
except AttributeError:
|
||||
self._hash_id = res = hash((self.handle, self.suffix))
|
||||
return res
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
# other should not be a string, but the serializer sometimes provides these
|
||||
if isinstance(other, str):
|
||||
return self.trval == other
|
||||
return bool(self.trval == other.trval)
|
||||
|
||||
def startswith(self, x: str) -> bool:
|
||||
if self.trval is not None:
|
||||
return self.trval.startswith(x)
|
||||
return False
|
||||
|
||||
@property
|
||||
def trval(self) -> Optional[str]:
|
||||
try:
|
||||
return self._trval
|
||||
except AttributeError:
|
||||
pass
|
||||
if self.handle is None:
|
||||
self._trval: Optional[str] = self.uri_decoded_suffix
|
||||
return self._trval
|
||||
assert self._transform_type is not None
|
||||
if not self._transform_type:
|
||||
# the non-round-trip case
|
||||
self._trval = self.handles[self.handle] + self.uri_decoded_suffix
|
||||
return self._trval
|
||||
# round-trip case
|
||||
if self.handle == '!!' and self.suffix in (
|
||||
'null',
|
||||
'bool',
|
||||
'int',
|
||||
'float',
|
||||
'binary',
|
||||
'timestamp',
|
||||
'omap',
|
||||
'pairs',
|
||||
'set',
|
||||
'str',
|
||||
'seq',
|
||||
'map',
|
||||
):
|
||||
self._trval = self.handles[self.handle] + self.uri_decoded_suffix
|
||||
else:
|
||||
# self._trval = self.handle + self.suffix
|
||||
self._trval = self.handles[self.handle] + self.uri_decoded_suffix
|
||||
return self._trval
|
||||
|
||||
value = trval
|
||||
|
||||
@property
|
||||
def uri_decoded_suffix(self) -> Optional[str]:
|
||||
try:
|
||||
return self._uri_decoded_suffix
|
||||
except AttributeError:
|
||||
pass
|
||||
if self.suffix is None:
|
||||
self._uri_decoded_suffix: Optional[str] = None
|
||||
return None
|
||||
res = ''
|
||||
# don't have to check for scanner errors here
|
||||
idx = 0
|
||||
while idx < len(self.suffix):
|
||||
ch = self.suffix[idx]
|
||||
idx += 1
|
||||
if ch != '%':
|
||||
res += ch
|
||||
else:
|
||||
res += chr(int(self.suffix[idx : idx + 2], 16))
|
||||
idx += 2
|
||||
self._uri_decoded_suffix = res
|
||||
return res
|
||||
|
||||
def select_transform(self, val: bool) -> None:
|
||||
"""
|
||||
val: False -> non-round-trip
|
||||
True -> round-trip
|
||||
"""
|
||||
assert self._transform_type is None
|
||||
self._transform_type = val
|
||||
|
||||
def check_handle(self) -> bool:
|
||||
if self.handle is None:
|
||||
return False
|
||||
return self.handle not in self.handles
|
||||
63
venv/Lib/site-packages/ruamel/yaml/timestamp.py
Normal file
63
venv/Lib/site-packages/ruamel/yaml/timestamp.py
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import datetime
|
||||
|
||||
# ToDo: at least on PY3 you could probably attach the tzinfo correctly to the object
|
||||
# a more complete datetime might be used by safe loading as well
|
||||
#
|
||||
# add type information (iso8601, spaced)
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List # NOQA
|
||||
|
||||
|
||||
class TimeStamp(datetime.datetime):
|
||||
def __init__(self, *args: Any, **kw: Any) -> None:
|
||||
self._yaml: Dict[str, Any] = dict(t=False, tz=None, delta=0)
|
||||
|
||||
def __new__(cls, *args: Any, **kw: Any) -> Any: # datetime is immutable
|
||||
return datetime.datetime.__new__(cls, *args, **kw)
|
||||
|
||||
def __deepcopy__(self, memo: Any) -> Any:
|
||||
ts = TimeStamp(self.year, self.month, self.day, self.hour, self.minute, self.second)
|
||||
ts._yaml = copy.deepcopy(self._yaml)
|
||||
return ts
|
||||
|
||||
def replace(
|
||||
self,
|
||||
year: Any = None,
|
||||
month: Any = None,
|
||||
day: Any = None,
|
||||
hour: Any = None,
|
||||
minute: Any = None,
|
||||
second: Any = None,
|
||||
microsecond: Any = None,
|
||||
tzinfo: Any = True,
|
||||
fold: Any = None,
|
||||
) -> Any:
|
||||
if year is None:
|
||||
year = self.year
|
||||
if month is None:
|
||||
month = self.month
|
||||
if day is None:
|
||||
day = self.day
|
||||
if hour is None:
|
||||
hour = self.hour
|
||||
if minute is None:
|
||||
minute = self.minute
|
||||
if second is None:
|
||||
second = self.second
|
||||
if microsecond is None:
|
||||
microsecond = self.microsecond
|
||||
if tzinfo is True:
|
||||
tzinfo = self.tzinfo
|
||||
if fold is None:
|
||||
fold = self.fold
|
||||
ts = type(self)(year, month, day, hour, minute, second, microsecond, tzinfo, fold=fold)
|
||||
ts._yaml = copy.deepcopy(self._yaml)
|
||||
return ts
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.isoformat('T' if self._yaml['t'] else ' ')
|
||||
384
venv/Lib/site-packages/ruamel/yaml/tokens.py
Normal file
384
venv/Lib/site-packages/ruamel/yaml/tokens.py
Normal file
@@ -0,0 +1,384 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from ruamel.yaml.compat import nprintf # NOQA
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Text, Any, Dict, Optional, List # NOQA
|
||||
from .error import StreamMark # NOQA
|
||||
|
||||
SHOW_LINES = True
|
||||
|
||||
|
||||
class Token:
|
||||
__slots__ = 'start_mark', 'end_mark', '_comment'
|
||||
|
||||
def __init__(self, start_mark: StreamMark, end_mark: StreamMark) -> None:
|
||||
self.start_mark = start_mark
|
||||
self.end_mark = end_mark
|
||||
|
||||
def __repr__(self) -> Any:
|
||||
# attributes = [key for key in self.__slots__ if not key.endswith('_mark') and
|
||||
# hasattr('self', key)]
|
||||
attributes = [key for key in self.__slots__ if not key.endswith('_mark')]
|
||||
attributes.sort()
|
||||
# arguments = ', '.join(
|
||||
# [f'{key!s}={getattr(self, key)!r})' for key in attributes]
|
||||
# )
|
||||
arguments = [f'{key!s}={getattr(self, key)!r}' for key in attributes]
|
||||
if SHOW_LINES:
|
||||
try:
|
||||
arguments.append('line: ' + str(self.start_mark.line))
|
||||
except: # NOQA
|
||||
pass
|
||||
try:
|
||||
arguments.append('comment: ' + str(self._comment))
|
||||
except: # NOQA
|
||||
pass
|
||||
return f'{self.__class__.__name__}({", ".join(arguments)})'
|
||||
|
||||
@property
|
||||
def column(self) -> int:
|
||||
return self.start_mark.column
|
||||
|
||||
@column.setter
|
||||
def column(self, pos: Any) -> None:
|
||||
self.start_mark.column = pos
|
||||
|
||||
# old style ( <= 0.17) is a TWO element list with first being the EOL
|
||||
# comment concatenated with following FLC/BLNK; and second being a list of FLC/BLNK
|
||||
# preceding the token
|
||||
# new style ( >= 0.17 ) is a THREE element list with the first being a list of
|
||||
# preceding FLC/BLNK, the second EOL and the third following FLC/BLNK
|
||||
# note that new style has differing order, and does not consist of CommentToken(s)
|
||||
# but of CommentInfo instances
|
||||
# any non-assigned values in new style are None, but first and last can be empty list
|
||||
# new style routines add one comment at a time
|
||||
|
||||
# going to be deprecated in favour of add_comment_eol/post
|
||||
def add_post_comment(self, comment: Any) -> None:
|
||||
if not hasattr(self, '_comment'):
|
||||
self._comment = [None, None]
|
||||
else:
|
||||
assert len(self._comment) in [2, 5] # make sure it is version 0
|
||||
# if isinstance(comment, CommentToken):
|
||||
# if comment.value.startswith('# C09'):
|
||||
# raise
|
||||
self._comment[0] = comment
|
||||
|
||||
# going to be deprecated in favour of add_comment_pre
|
||||
def add_pre_comments(self, comments: Any) -> None:
|
||||
if not hasattr(self, '_comment'):
|
||||
self._comment = [None, None]
|
||||
else:
|
||||
assert len(self._comment) == 2 # make sure it is version 0
|
||||
assert self._comment[1] is None
|
||||
self._comment[1] = comments
|
||||
return
|
||||
|
||||
# new style
|
||||
def add_comment_pre(self, comment: Any) -> None:
|
||||
if not hasattr(self, '_comment'):
|
||||
self._comment = [[], None, None] # type: ignore
|
||||
else:
|
||||
assert len(self._comment) == 3
|
||||
if self._comment[0] is None:
|
||||
self._comment[0] = [] # type: ignore
|
||||
self._comment[0].append(comment) # type: ignore
|
||||
|
||||
def add_comment_eol(self, comment: Any, comment_type: Any) -> None:
|
||||
if not hasattr(self, '_comment'):
|
||||
self._comment = [None, None, None]
|
||||
else:
|
||||
assert len(self._comment) == 3
|
||||
assert self._comment[1] is None
|
||||
if self.comment[1] is None:
|
||||
self._comment[1] = [] # type: ignore
|
||||
self._comment[1].extend([None] * (comment_type + 1 - len(self.comment[1]))) # type: ignore # NOQA
|
||||
# nprintf('commy', self.comment, comment_type)
|
||||
self._comment[1][comment_type] = comment # type: ignore
|
||||
|
||||
def add_comment_post(self, comment: Any) -> None:
|
||||
if not hasattr(self, '_comment'):
|
||||
self._comment = [None, None, []] # type: ignore
|
||||
else:
|
||||
assert len(self._comment) == 3
|
||||
if self._comment[2] is None:
|
||||
self._comment[2] = [] # type: ignore
|
||||
self._comment[2].append(comment) # type: ignore
|
||||
|
||||
# def get_comment(self) -> Any:
|
||||
# return getattr(self, '_comment', None)
|
||||
|
||||
@property
|
||||
def comment(self) -> Any:
|
||||
return getattr(self, '_comment', None)
|
||||
|
||||
def move_old_comment(self, target: Any, empty: bool = False) -> Any:
|
||||
"""move a comment from this token to target (normally next token)
|
||||
used to combine e.g. comments before a BlockEntryToken to the
|
||||
ScalarToken that follows it
|
||||
empty is a special for empty values -> comment after key
|
||||
"""
|
||||
c = self.comment
|
||||
if c is None:
|
||||
return
|
||||
# don't push beyond last element
|
||||
if isinstance(target, (StreamEndToken, DocumentStartToken)):
|
||||
return
|
||||
delattr(self, '_comment')
|
||||
tc = target.comment
|
||||
if not tc: # target comment, just insert
|
||||
# special for empty value in key: value issue 25
|
||||
if empty:
|
||||
c = [c[0], c[1], None, None, c[0]]
|
||||
target._comment = c
|
||||
# nprint('mco2:', self, target, target.comment, empty)
|
||||
return self
|
||||
if c[0] and tc[0] or c[1] and tc[1]:
|
||||
if isinstance(c[1], list) and isinstance(tc[1], list):
|
||||
c[1].extend(tc[1])
|
||||
else:
|
||||
raise NotImplementedError(f'overlap in comment {c!r} {tc!r}')
|
||||
if c[0]:
|
||||
tc[0] = c[0]
|
||||
if c[1]:
|
||||
tc[1] = c[1]
|
||||
return self
|
||||
|
||||
def split_old_comment(self) -> Any:
|
||||
""" split the post part of a comment, and return it
|
||||
as comment to be added. Delete second part if [None, None]
|
||||
abc: # this goes to sequence
|
||||
# this goes to first element
|
||||
- first element
|
||||
"""
|
||||
comment = self.comment
|
||||
if comment is None or comment[0] is None:
|
||||
return None # nothing to do
|
||||
ret_val = [comment[0], None]
|
||||
if comment[1] is None:
|
||||
delattr(self, '_comment')
|
||||
return ret_val
|
||||
|
||||
def move_new_comment(self, target: Any, empty: bool = False) -> Any:
|
||||
"""move a comment from this token to target (normally next token)
|
||||
used to combine e.g. comments before a BlockEntryToken to the
|
||||
ScalarToken that follows it
|
||||
empty is a special for empty values -> comment after key
|
||||
"""
|
||||
c = self.comment
|
||||
if c is None:
|
||||
return
|
||||
# don't push beyond last element
|
||||
if isinstance(target, (StreamEndToken, DocumentStartToken)):
|
||||
return
|
||||
delattr(self, '_comment')
|
||||
tc = target.comment
|
||||
if not tc: # target comment, just insert
|
||||
# special for empty value in key: value issue 25
|
||||
if empty:
|
||||
c = [c[0], c[1], c[2]]
|
||||
target._comment = c
|
||||
# nprint('mco2:', self, target, target.comment, empty)
|
||||
return self
|
||||
# if self and target have both pre, eol or post comments, something seems wrong
|
||||
for idx in range(3):
|
||||
if c[idx] is not None and tc[idx] is not None:
|
||||
raise NotImplementedError(f'overlap in comment {c!r} {tc!r}')
|
||||
# move the comment parts
|
||||
for idx in range(3):
|
||||
if c[idx]:
|
||||
tc[idx] = c[idx]
|
||||
return self
|
||||
|
||||
|
||||
# class BOMToken(Token):
|
||||
# id = '<byte order mark>'
|
||||
|
||||
|
||||
class DirectiveToken(Token):
|
||||
__slots__ = 'name', 'value'
|
||||
id = '<directive>'
|
||||
|
||||
def __init__(self, name: Any, value: Any, start_mark: Any, end_mark: Any) -> None:
|
||||
Token.__init__(self, start_mark, end_mark)
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
|
||||
class DocumentStartToken(Token):
|
||||
__slots__ = ()
|
||||
id = '<document start>'
|
||||
|
||||
|
||||
class DocumentEndToken(Token):
|
||||
__slots__ = ()
|
||||
id = '<document end>'
|
||||
|
||||
|
||||
class StreamStartToken(Token):
|
||||
__slots__ = ('encoding',)
|
||||
id = '<stream start>'
|
||||
|
||||
def __init__(
|
||||
self, start_mark: Any = None, end_mark: Any = None, encoding: Any = None,
|
||||
) -> None:
|
||||
Token.__init__(self, start_mark, end_mark)
|
||||
self.encoding = encoding
|
||||
|
||||
|
||||
class StreamEndToken(Token):
|
||||
__slots__ = ()
|
||||
id = '<stream end>'
|
||||
|
||||
|
||||
class BlockSequenceStartToken(Token):
|
||||
__slots__ = ()
|
||||
id = '<block sequence start>'
|
||||
|
||||
|
||||
class BlockMappingStartToken(Token):
|
||||
__slots__ = ()
|
||||
id = '<block mapping start>'
|
||||
|
||||
|
||||
class BlockEndToken(Token):
|
||||
__slots__ = ()
|
||||
id = '<block end>'
|
||||
|
||||
|
||||
class FlowSequenceStartToken(Token):
|
||||
__slots__ = ()
|
||||
id = '['
|
||||
|
||||
|
||||
class FlowMappingStartToken(Token):
|
||||
__slots__ = ()
|
||||
id = '{'
|
||||
|
||||
|
||||
class FlowSequenceEndToken(Token):
|
||||
__slots__ = ()
|
||||
id = ']'
|
||||
|
||||
|
||||
class FlowMappingEndToken(Token):
|
||||
__slots__ = ()
|
||||
id = '}'
|
||||
|
||||
|
||||
class KeyToken(Token):
|
||||
__slots__ = ()
|
||||
id = '?'
|
||||
|
||||
# def x__repr__(self):
|
||||
# return f'KeyToken({self.start_mark.buffer[self.start_mark.index:].split(None, 1)[0]})'
|
||||
|
||||
|
||||
class ValueToken(Token):
|
||||
__slots__ = ()
|
||||
id = ':'
|
||||
|
||||
|
||||
class BlockEntryToken(Token):
|
||||
__slots__ = ()
|
||||
id = '-'
|
||||
|
||||
|
||||
class FlowEntryToken(Token):
|
||||
__slots__ = ()
|
||||
id = ','
|
||||
|
||||
|
||||
class AliasToken(Token):
|
||||
__slots__ = ('value',)
|
||||
id = '<alias>'
|
||||
|
||||
def __init__(self, value: Any, start_mark: Any, end_mark: Any) -> None:
|
||||
Token.__init__(self, start_mark, end_mark)
|
||||
self.value = value
|
||||
|
||||
|
||||
class AnchorToken(Token):
|
||||
__slots__ = ('value',)
|
||||
id = '<anchor>'
|
||||
|
||||
def __init__(self, value: Any, start_mark: Any, end_mark: Any) -> None:
|
||||
Token.__init__(self, start_mark, end_mark)
|
||||
self.value = value
|
||||
|
||||
|
||||
class TagToken(Token):
|
||||
__slots__ = ('value',)
|
||||
id = '<tag>'
|
||||
|
||||
def __init__(self, value: Any, start_mark: Any, end_mark: Any) -> None:
|
||||
Token.__init__(self, start_mark, end_mark)
|
||||
self.value = value
|
||||
|
||||
|
||||
class ScalarToken(Token):
|
||||
__slots__ = 'value', 'plain', 'style'
|
||||
id = '<scalar>'
|
||||
|
||||
def __init__(
|
||||
self, value: Any, plain: Any, start_mark: Any, end_mark: Any, style: Any = None,
|
||||
) -> None:
|
||||
Token.__init__(self, start_mark, end_mark)
|
||||
self.value = value
|
||||
self.plain = plain
|
||||
self.style = style
|
||||
|
||||
|
||||
class CommentToken(Token):
|
||||
__slots__ = '_value', '_column', 'pre_done'
|
||||
id = '<comment>'
|
||||
|
||||
def __init__(
|
||||
self, value: Any, start_mark: Any = None, end_mark: Any = None, column: Any = None,
|
||||
) -> None:
|
||||
if start_mark is None:
|
||||
assert column is not None
|
||||
self._column = column
|
||||
Token.__init__(self, start_mark, end_mark)
|
||||
self._value = value
|
||||
|
||||
@property
|
||||
def value(self) -> str:
|
||||
if isinstance(self._value, str):
|
||||
return self._value
|
||||
return "".join(self._value)
|
||||
|
||||
@value.setter
|
||||
def value(self, val: Any) -> None:
|
||||
self._value = val
|
||||
|
||||
def reset(self) -> None:
|
||||
if hasattr(self, 'pre_done'):
|
||||
delattr(self, 'pre_done')
|
||||
|
||||
def __repr__(self) -> Any:
|
||||
v = f'{self.value!r}'
|
||||
if SHOW_LINES:
|
||||
try:
|
||||
v += ', line: ' + str(self.start_mark.line)
|
||||
except: # NOQA
|
||||
pass
|
||||
try:
|
||||
v += ', col: ' + str(self.start_mark.column)
|
||||
except: # NOQA
|
||||
pass
|
||||
return f'CommentToken({v})'
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
if self.start_mark != other.start_mark:
|
||||
return False
|
||||
if self.end_mark != other.end_mark:
|
||||
return False
|
||||
if self.value != other.value:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __ne__(self, other: Any) -> bool:
|
||||
return not self.__eq__(other)
|
||||
264
venv/Lib/site-packages/ruamel/yaml/util.py
Normal file
264
venv/Lib/site-packages/ruamel/yaml/util.py
Normal file
@@ -0,0 +1,264 @@
|
||||
|
||||
|
||||
"""
|
||||
some helper functions that might be generally useful
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
from functools import partial
|
||||
import re
|
||||
|
||||
|
||||
if False: # MYPY
|
||||
from typing import Any, Dict, Optional, List, Text, Callable, Union # NOQA
|
||||
from .compat import StreamTextType # NOQA
|
||||
|
||||
|
||||
class LazyEval:
|
||||
"""
|
||||
Lightweight wrapper around lazily evaluated func(*args, **kwargs).
|
||||
|
||||
func is only evaluated when any attribute of its return value is accessed.
|
||||
Every attribute access is passed through to the wrapped value.
|
||||
(This only excludes special cases like method-wrappers, e.g., __hash__.)
|
||||
The sole additional attribute is the lazy_self function which holds the
|
||||
return value (or, prior to evaluation, func and arguments), in its closure.
|
||||
"""
|
||||
|
||||
def __init__(self, func: Callable[..., Any], *args: Any, **kwargs: Any) -> None:
|
||||
def lazy_self() -> Any:
|
||||
return_value = func(*args, **kwargs)
|
||||
object.__setattr__(self, 'lazy_self', lambda: return_value)
|
||||
return return_value
|
||||
|
||||
object.__setattr__(self, 'lazy_self', lazy_self)
|
||||
|
||||
def __getattribute__(self, name: str) -> Any:
|
||||
lazy_self = object.__getattribute__(self, 'lazy_self')
|
||||
if name == 'lazy_self':
|
||||
return lazy_self
|
||||
return getattr(lazy_self(), name)
|
||||
|
||||
def __setattr__(self, name: str, value: Any) -> None:
|
||||
setattr(self.lazy_self(), name, value)
|
||||
|
||||
|
||||
RegExp = partial(LazyEval, re.compile)
|
||||
|
||||
timestamp_regexp = RegExp(
|
||||
"""^(?P<year>[0-9][0-9][0-9][0-9])
|
||||
-(?P<month>[0-9][0-9]?)
|
||||
-(?P<day>[0-9][0-9]?)
|
||||
(?:((?P<t>[Tt])|[ \\t]+) # explictly not retaining extra spaces
|
||||
(?P<hour>[0-9][0-9]?)
|
||||
:(?P<minute>[0-9][0-9])
|
||||
:(?P<second>[0-9][0-9])
|
||||
(?:\\.(?P<fraction>[0-9]*))?
|
||||
(?:[ \\t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
|
||||
(?::(?P<tz_minute>[0-9][0-9]))?))?)?$""",
|
||||
re.X,
|
||||
)
|
||||
|
||||
|
||||
def create_timestamp(
|
||||
year: Any,
|
||||
month: Any,
|
||||
day: Any,
|
||||
t: Any,
|
||||
hour: Any,
|
||||
minute: Any,
|
||||
second: Any,
|
||||
fraction: Any,
|
||||
tz: Any,
|
||||
tz_sign: Any,
|
||||
tz_hour: Any,
|
||||
tz_minute: Any,
|
||||
) -> Union[datetime.datetime, datetime.date]:
|
||||
# create a timestamp from matching against timestamp_regexp
|
||||
MAX_FRAC = 999999
|
||||
year = int(year)
|
||||
month = int(month)
|
||||
day = int(day)
|
||||
if hour is None:
|
||||
return datetime.date(year, month, day)
|
||||
hour = int(hour)
|
||||
minute = int(minute)
|
||||
second = int(second)
|
||||
frac = 0
|
||||
if fraction:
|
||||
frac_s = fraction[:6]
|
||||
while len(frac_s) < 6:
|
||||
frac_s += '0'
|
||||
frac = int(frac_s)
|
||||
if len(fraction) > 6 and int(fraction[6]) > 4:
|
||||
frac += 1
|
||||
if frac > MAX_FRAC:
|
||||
fraction = 0
|
||||
else:
|
||||
fraction = frac
|
||||
else:
|
||||
fraction = 0
|
||||
tzinfo = None
|
||||
delta = None
|
||||
if tz_sign:
|
||||
tz_hour = int(tz_hour)
|
||||
tz_minute = int(tz_minute) if tz_minute else 0
|
||||
td = datetime.timedelta(
|
||||
hours=tz_hour, minutes=tz_minute,
|
||||
)
|
||||
if tz_sign == '-':
|
||||
td = -td
|
||||
tzinfo = datetime.timezone(td, name=tz)
|
||||
elif tz == 'Z':
|
||||
tzinfo = datetime.timezone(datetime.timedelta(hours=0), name=tz)
|
||||
if frac > MAX_FRAC:
|
||||
delta = -datetime.timedelta(seconds=1)
|
||||
# should do something else instead (or hook this up to the preceding if statement
|
||||
# in reverse
|
||||
# if delta is None:
|
||||
# return datetime.datetime(year, month, day, hour, minute, second, fraction)
|
||||
# return datetime.datetime(year, month, day, hour, minute, second, fraction,
|
||||
# datetime.timezone.utc)
|
||||
# the above is not good enough though, should provide tzinfo. In Python3 that is easily
|
||||
# doable drop that kind of support for Python2 as it has not native tzinfo
|
||||
data = datetime.datetime(year, month, day, hour, minute, second, fraction, tzinfo)
|
||||
if delta:
|
||||
data -= delta
|
||||
return data
|
||||
|
||||
|
||||
# originally as comment
|
||||
# https://github.com/pre-commit/pre-commit/pull/211#issuecomment-186466605
|
||||
# if you use this in your code, I suggest adding a test in your test suite
|
||||
# that check this routines output against a known piece of your YAML
|
||||
# before upgrades to this code break your round-tripped YAML
|
||||
def load_yaml_guess_indent(stream: StreamTextType, **kw: Any) -> Any:
|
||||
"""guess the indent and block sequence indent of yaml stream/string
|
||||
|
||||
returns round_trip_loaded stream, indent level, block sequence indent
|
||||
- block sequence indent is the number of spaces before a dash relative to previous indent
|
||||
- if there are no block sequences, indent is taken from nested mappings, block sequence
|
||||
indent is unset (None) in that case
|
||||
"""
|
||||
from .main import YAML
|
||||
|
||||
# load a YAML document, guess the indentation, if you use TABs you are on your own
|
||||
def leading_spaces(line: Any) -> int:
|
||||
idx = 0
|
||||
while idx < len(line) and line[idx] == ' ':
|
||||
idx += 1
|
||||
return idx
|
||||
|
||||
if isinstance(stream, str):
|
||||
yaml_str: Any = stream
|
||||
elif isinstance(stream, bytes):
|
||||
# most likely, but the Reader checks BOM for this
|
||||
yaml_str = stream.decode('utf-8')
|
||||
else:
|
||||
yaml_str = stream.read()
|
||||
map_indent = None
|
||||
indent = None # default if not found for some reason
|
||||
block_seq_indent = None
|
||||
prev_line_key_only = None
|
||||
key_indent = 0
|
||||
for line in yaml_str.splitlines():
|
||||
rline = line.rstrip()
|
||||
lline = rline.lstrip()
|
||||
if lline.startswith('- '):
|
||||
l_s = leading_spaces(line)
|
||||
block_seq_indent = l_s - key_indent
|
||||
idx = l_s + 1
|
||||
while line[idx] == ' ': # this will end as we rstripped
|
||||
idx += 1
|
||||
if line[idx] == '#': # comment after -
|
||||
continue
|
||||
indent = idx - key_indent
|
||||
break
|
||||
if map_indent is None and prev_line_key_only is not None and rline:
|
||||
idx = 0
|
||||
while line[idx] in ' -':
|
||||
idx += 1
|
||||
if idx > prev_line_key_only:
|
||||
map_indent = idx - prev_line_key_only
|
||||
if rline.endswith(':'):
|
||||
key_indent = leading_spaces(line)
|
||||
idx = 0
|
||||
while line[idx] == ' ': # this will end on ':'
|
||||
idx += 1
|
||||
prev_line_key_only = idx
|
||||
continue
|
||||
prev_line_key_only = None
|
||||
if indent is None and map_indent is not None:
|
||||
indent = map_indent
|
||||
yaml = YAML() if 'yaml' not in kw else kw.pop('yaml')
|
||||
return yaml.load(yaml_str, **kw), indent, block_seq_indent
|
||||
|
||||
|
||||
def configobj_walker(cfg: Any) -> Any:
|
||||
"""
|
||||
walks over a ConfigObj (INI file with comments) generating
|
||||
corresponding YAML output (including comments
|
||||
"""
|
||||
from configobj import ConfigObj # type: ignore
|
||||
|
||||
assert isinstance(cfg, ConfigObj)
|
||||
for c in cfg.initial_comment:
|
||||
if c.strip():
|
||||
yield c
|
||||
for s in _walk_section(cfg):
|
||||
if s.strip():
|
||||
yield s
|
||||
for c in cfg.final_comment:
|
||||
if c.strip():
|
||||
yield c
|
||||
|
||||
|
||||
def _walk_section(s: Any, level: int = 0) -> Any:
|
||||
from configobj import Section
|
||||
|
||||
assert isinstance(s, Section)
|
||||
indent = ' ' * level
|
||||
for name in s.scalars:
|
||||
for c in s.comments[name]:
|
||||
yield indent + c.strip()
|
||||
x = s[name]
|
||||
if '\n' in x:
|
||||
i = indent + ' '
|
||||
x = '|\n' + i + x.strip().replace('\n', '\n' + i)
|
||||
elif ':' in x:
|
||||
x = "'" + x.replace("'", "''") + "'"
|
||||
line = f'{indent}{name}: {x}'
|
||||
c = s.inline_comments[name]
|
||||
if c:
|
||||
line += ' ' + c
|
||||
yield line
|
||||
for name in s.sections:
|
||||
for c in s.comments[name]:
|
||||
yield indent + c.strip()
|
||||
line = f'{indent}{name}:'
|
||||
c = s.inline_comments[name]
|
||||
if c:
|
||||
line += ' ' + c
|
||||
yield line
|
||||
for val in _walk_section(s[name], level=level + 1):
|
||||
yield val
|
||||
|
||||
|
||||
# def config_obj_2_rt_yaml(cfg):
|
||||
# from .comments import CommentedMap, CommentedSeq
|
||||
# from configobj import ConfigObj
|
||||
# assert isinstance(cfg, ConfigObj)
|
||||
# #for c in cfg.initial_comment:
|
||||
# # if c.strip():
|
||||
# # pass
|
||||
# cm = CommentedMap()
|
||||
# for name in s.sections:
|
||||
# cm[name] = d = CommentedMap()
|
||||
#
|
||||
#
|
||||
# #for c in cfg.final_comment:
|
||||
# # if c.strip():
|
||||
# # yield c
|
||||
# return cm
|
||||
Reference in New Issue
Block a user