Source code for apache_beam.yaml.yaml_utils

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import uuid
from collections.abc import Iterable
from collections.abc import Mapping

from yaml import SafeLoader


[docs] class SafeLineLoader(SafeLoader): """A yaml loader that attaches line information to mappings and strings."""
[docs] class TaggedString(str): """A string class to which we can attach metadata. This is primarily used to trace a string's origin back to its place in a yaml file. """ def __reduce__(self): # Pickle as an ordinary string. return str, (str(self), )
[docs] def construct_scalar(self, node): value = super().construct_scalar(node) if isinstance(value, str): value = SafeLineLoader.TaggedString(value) value._line_ = node.start_mark.line + 1 return value
[docs] def construct_mapping(self, node, deep=False): mapping = super().construct_mapping(node, deep=deep) mapping['__line__'] = node.start_mark.line + 1 mapping['__uuid__'] = self.create_uuid() return mapping
[docs] @classmethod def create_uuid(cls): return str(uuid.uuid4())
[docs] @classmethod def strip_metadata(cls, spec, tagged_str=True): if isinstance(spec, Mapping): return { cls.strip_metadata(key, tagged_str): cls.strip_metadata(value, tagged_str) for (key, value) in spec.items() if key not in ('__line__', '__uuid__') } elif isinstance(spec, Iterable) and not isinstance(spec, (str, bytes)): return [cls.strip_metadata(value, tagged_str) for value in spec] elif isinstance(spec, SafeLineLoader.TaggedString) and tagged_str: return str(spec) else: return spec
[docs] @staticmethod def get_line(obj): if isinstance(obj, dict): return obj.get('__line__', 'unknown') else: return getattr(obj, '_line_', 'unknown')