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 o._replace(netloc="piston-meta.mojang.com").geturl()
return url 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 datetime import datetime
from typing import Optional, List, Dict, Any, Iterator from typing import Optional, List, Dict, Any, Iterator
import pydantic import pydantic
from pydantic import Field, validator 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 META_FORMAT_VERSION = 1
@ -119,6 +120,40 @@ class MetaBase(pydantic.BaseModel):
with open(file_path, "w") as f: with open(file_path, "w") as f:
f.write(self.json()) 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: class Config:
allow_population_by_field_name = True allow_population_by_field_name = True