MergeableMixin
MergeableMixin adds merge capabilities to any @dataclasses.dataclass.
Basic usage
import dataclasses
from pleroma import MergeableMixin
@dataclasses.dataclass
class ServerConfig(MergeableMixin):
host: str | None = None
port: int | None = None
timeout: int | None = None
base = ServerConfig(host="0.0.0.0", port=8080, timeout=30)
overlay = ServerConfig(port=9090)
result = ServerConfig.merge([base, overlay])
# ServerConfig(host='0.0.0.0', port=9090, timeout=30)
Instance shorthand
merged_with is equivalent to prepending self to the collection:
result = base.merged_with(overlay)
# identical to ServerConfig.merge([base, overlay])
Merge strategy
The default strategy is last non-None wins: for each field, the value
from the rightmost instance that is not None is chosen.
a = ServerConfig(host="a", port=None)
b = ServerConfig(host=None, port=9090)
ServerConfig.merge([a, b])
# ServerConfig(host='a', port=9090, timeout=None)
Strict last-wins
Pass overwrite_none=True to let None values overwrite non-None ones
(strict left-to-right last-wins):
ServerConfig.merge([a, b], overwrite_none=True)
# ServerConfig(host=None, port=9090, timeout=None)
Customisation
Changing traversal order
Override _iter_instances to control which instances participate and in what
order. pleroma provides predefined strategies
(iter_all, iter_reversed, iter_first, iter_last) that cover the most
common cases:
import dataclasses
from pleroma import MergeableMixin, iter_reversed
@dataclasses.dataclass
class Config(MergeableMixin):
host: str | None = None
@classmethod
def _iter_instances(cls, instances):
return iter_reversed(instances)
For custom ordering, implement the override directly:
@dataclasses.dataclass
class PriorityConfig(MergeableMixin):
level: int
value: str | None = None
@classmethod
def _iter_instances(cls, instances):
# merge in ascending priority order so higher priority wins
return iter(sorted(instances, key=lambda c: c.level))
Custom field resolution
Override _merge_two for full control over how two instances are combined:
@dataclasses.dataclass
class TaggedConfig(MergeableMixin):
tags: list[str] | None = None
value: str | None = None
def _merge_two(self, other, *, overwrite_none=False):
# union tags instead of overwriting
self_tags = self.tags or []
other_tags = other.tags or []
merged_tags = list(dict.fromkeys(self_tags + other_tags)) or None
base = super()._merge_two(other, overwrite_none=overwrite_none)
return dataclasses.replace(base, tags=merged_tags)