feat: implement merge function for MetaBase

This commit is contained in:
Sefa Eyeoglu 2022-06-26 12:16:11 +02:00
parent d5e359508b
commit 75006147dd
No known key found for this signature in database
GPG Key ID: C10411294912A422
2 changed files with 55 additions and 1 deletions

View File

@ -49,3 +49,22 @@ def replace_old_launchermeta_url(url):
return o._replace(netloc="piston-meta.mojang.com").geturl()
return url
def get_all_bases(cls, bases=None):
bases = bases or []
bases.append(cls)
for c in cls.__bases__:
get_all_bases(c, bases)
return tuple(bases)
def merge_dict(base: dict, overlay: dict):
for k, v in base.items():
if isinstance(v, dict):
merge_dict(v, overlay.setdefault(k, {}))
else:
if k not in overlay:
overlay[k] = v
return overlay

View File

@ -1,10 +1,11 @@
import copy
from datetime import datetime
from typing import Optional, List, Dict, Any, Iterator
import pydantic
from pydantic import Field, validator
from ..common import serialize_datetime, replace_old_launchermeta_url
from ..common import serialize_datetime, replace_old_launchermeta_url, get_all_bases, merge_dict
META_FORMAT_VERSION = 1
@ -119,6 +120,40 @@ class MetaBase(pydantic.BaseModel):
with open(file_path, "w") as f:
f.write(self.json())
def merge(self, other):
"""
Merge other object with self.
- Concatenates lists
- Combines sets
- Merges dictionaries (other takes priority)
- Recurses for all fields that are also MetaBase classes
- Overwrites for any other field type (int, string, ...)
"""
assert type(other) is type(self)
for key, field in self.__fields__.items():
ours = getattr(self, key)
theirs = getattr(other, key)
if theirs is None:
continue
if ours is None:
setattr(self, key, theirs)
continue
if isinstance(ours, list):
ours += theirs
elif isinstance(ours, set):
ours |= theirs
elif isinstance(ours, dict):
result = merge_dict(ours, copy.deepcopy(theirs))
setattr(self, key, result)
elif MetaBase in get_all_bases(field.type_):
ours.merge(theirs)
else:
setattr(self, key, theirs)
def __hash__(self):
return hash(self.json())
class Config:
allow_population_by_field_name = True