python-model: Support importing multiple versions

This commit is contained in:
Filippo Cremonese
2022-01-25 16:00:10 +01:00
parent 07fe830202
commit b209e09374
14 changed files with 194 additions and 2 deletions
+29 -2
View File
@@ -10,12 +10,29 @@ from pydantic.main import ModelMetaclass
def get_monkey_patching_metaclass(
substitutions: Dict[str, type],
register_global_yaml_helpers=False,
):
"""Returns a metaclass which transparently substitutes some types with others. This way pydantic uses the substitute
types when creating the validators for its types, without the need to modify the autogenerated classes.
"""
class MonkeyPatchingMetaClass(ModelMetaclass):
class YamlLoader(yaml.Loader):
pass
class YamlDumper(yaml.Dumper):
def increase_indent(self, flow=False, indentless=False):
"""Improves indentation"""
return super(MonkeyPatchingMetaClass.YamlDumper, self).increase_indent(flow, False)
def analyze_scalar(self, scalar):
"""Ensures literals starting with ? are quoted to make LLVM YAML parser happy"""
analysis = super(MonkeyPatchingMetaClass.YamlDumper, self).analyze_scalar(scalar)
if isinstance(analysis.scalar, str) and analysis.scalar.startswith("?"):
analysis.allow_flow_plain = False
analysis.allow_block_plain = False
return analysis
@staticmethod
def __new__(mcs, clsname, bases, namespace):
substitution = substitutions.get(clsname)
@@ -43,17 +60,25 @@ def get_monkey_patching_metaclass(
{k: v for k, v in instance._iter(exclude_none=True)},
)
yaml.add_representer(
mcs.YamlDumper.add_representer(
created_class,
yaml_representer,
)
if register_global_yaml_helpers:
yaml.add_representer(
created_class,
yaml_representer,
)
def yaml_constructor(loader, node):
mapping = loader.construct_mapping(node, deep=True)
return created_class(**mapping)
tag = f"!{clsname}"
yaml.add_constructor(tag, yaml_constructor)
mcs.YamlLoader.add_constructor(tag, yaml_constructor)
if register_global_yaml_helpers:
yaml.add_constructor(tag, yaml_constructor)
return created_class
@@ -62,10 +87,12 @@ def get_monkey_patching_metaclass(
def get_monkey_patching_base_class(
substitutions: Dict[str, type],
register_global_yaml_helpers=False,
):
"""Returns a base class which transparently substitutes some model types with others"""
MonkeyPatchingMetaClass = get_monkey_patching_metaclass(
substitutions,
register_global_yaml_helpers=register_global_yaml_helpers,
)
class MonkeyPatchingBaseClass(BaseModel, metaclass=MonkeyPatchingMetaClass):
+8
View File
@@ -1,8 +1,12 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
from typing import IO, Text, Union
import yaml
from ._generated import *
from .base import YamlLoader, YamlDumper
from .metaaddress import MetaAddress, MetaAddressType
from .reference import Reference
from .._common.monkeypatches import (
@@ -55,3 +59,7 @@ hashable_types = [
for t, attr_name in hashable_types:
make_hashable_using_attribute(t, attr_name)
def load_model(stream: Union[bytes, IO[bytes], Text, IO[Text]]):
return yaml.load(stream, Loader=YamlLoader)
+5
View File
@@ -12,4 +12,9 @@ _substitutions = {
MonkeyPatchingBaseClass = get_monkey_patching_base_class(
_substitutions,
register_global_yaml_helpers=False,
)
YamlDumper = MonkeyPatchingBaseClass.YamlDumper
YamlLoader = MonkeyPatchingBaseClass.YamlLoader
# Allows to deserialize a model YAML to a Binary object using yaml.load(stream, Loader=YamlLoader)
YamlLoader.add_path_resolver("!Binary", [])