import enum import nanoid from nanoid_dictionary import human_alphabet from slugify import slugify from sqlalchemy import Column, String, inspect from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass def genslug(): return nanoid.generate(human_alphabet[2:], 5) class SlugMixin: slug = Column(String, index=True, unique=True, default=genslug) @property def uri(self): return "-".join([self.slug, slugify(self.name.title().replace(" ", ""), ok="", only_ascii=True, lower=False)]) class BaseObject(MappedAsDataclass, DeclarativeBase): """ Allows for iterating over Model objects' column names and values """ __abstract__ = True def __iter__(self): values = vars(self) for attr in self.__mapper__.columns.keys(): if attr in values: yield attr, values[attr] for relname in self.__mapper__.relationships.keys(): relvals = [] reliter = self.__getattribute__(relname) if not reliter: yield relname, relvals continue for rel in reliter: try: relvals.append({k: v for k, v in vars(rel).items() if not k.startswith("_")}) except TypeError: relvals.append(rel) yield relname, relvals def __json__(self): """ Provide a custom JSON encoder. """ raise NotImplementedError() def __repr__(self): return str(dict(self)) def copy(self): self_as_dict = dict(self.__dict__) self_as_dict.pop("_sa_instance_state") mapper = inspect(self).mapper for primary_key in mapper.primary_key: self_as_dict.pop(primary_key.name) for key in mapper.relationships.keys(): if key in self_as_dict: self_as_dict.pop(key) return self.__class__(**self_as_dict) class EnumField(enum.Enum): """ A serializable enum. """ def __json__(self): return self.value STATS = ["strength", "dexterity", "constitution", "intelligence", "wisdom", "charisma"] CREATURE_TYPES = [ "aberation", "beast", "celestial", "construct", "dragon", "elemental", "fey", "fiend", "Giant", "humanoid", "monstrosity", "ooze", "plant", "undead", ] SIZES = ["Tiny", "Small", "Medium", "Large", "Huge", "Gargantuan"] CreatureTypesEnum = EnumField("CreatureTypesEnum", ((k, k) for k in CREATURE_TYPES)) StatsEnum = EnumField("StatsEnum", ((k, k) for k in STATS)) SizesEnum = EnumField("SizesEnum", ((k, k) for k in SIZES))