mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
python-model: Support importing multiple versions
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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", [])
|
||||
|
||||
Reference in New Issue
Block a user