def field_definitions(cls): return relationship( cls.__fieldset_definition__['class'], cascade="all, delete-orphan", collection_class=mapped_collection(lambda field_def: field_def.uuid), backref='fieldset' )
class Package(TableBase): u"""An abstract "package", for grouping similar packages in different Collections""" __tablename__ = 'packages' name = Column( Unicode(), primary_key=True, nullable=False, doc=u"The package name") status = Column( Unicode(), ForeignKey(Status.ident), nullable=False, doc=u"Summarized status") by_collection = relationship( 'CollectionPackage', collection_class=mapped_collection(lambda cp: cp.collection.ident)) status_obj = relationship( 'Status', backref=backref('packages')) def __repr__(self): return '<{} {}>'.format(type(self).__qualname__, self.name) @property def pending_requirements(self): return [r for r in self.requirements if r.status not in ('released', 'dropped')] @property def pending_requirers(self): return [r for r in self.requirers if r.status not in ('released', 'dropped')]
def owner(cls): return relationship( cls.__fieldset_owner__['class'], backref=backref( 'fieldsets', cascade="all, delete-orphan", collection_class=mapped_collection( lambda fieldset_assoc: fieldset_assoc.fieldset_uuid)))
def owner(cls): return relationship( cls.__fieldset_owner__['class'], backref=backref( 'fieldsets', cascade="all, delete-orphan", collection_class=mapped_collection(lambda fieldset_assoc: fieldset_assoc.fieldset_uuid) ) )
class Package(TableBase): u"""An abstract "package", for grouping similar packages in different Collections""" __tablename__ = 'packages' name = Column( Unicode(), primary_key=True, nullable=False, doc=u"The package name") status = Column( Unicode(), ForeignKey(Status.ident), nullable=False, doc=u"Summarized status") loc_python = Column( Integer(), nullable=True, doc="Approximate number of Python lines of code") loc_capi = Column( Integer(), nullable=True, doc="Approximate number of C lines of code that uses the CPython API") loc_total = Column( Integer(), nullable=True, doc="Approximate total number of lines of code (in any language)") loc_version = Column( Integer(), nullable=True, doc="Package version for which line-of-code stats were gathered") by_collection = relationship( 'CollectionPackage', collection_class=mapped_collection(lambda cp: cp.collection.ident)) status_obj = relationship( 'Status', backref=backref('packages')) def __repr__(self): return '<{} {}>'.format(type(self).__qualname__, self.name) @property def pending_requirements(self): return [r for r in self.requirements if r.status not in ('released', 'dropped')] @property def pending_requirers(self): return [r for r in self.requirers if r.status not in ('released', 'dropped')] @property def nonblocking(self): return any(cp.nonblocking for cp in self.collection_packages)
''' In these relationships, there are two important attributes to check for: - collection_class defines how the objects linked by the relationship will be presented. Usually, objects are contained inside a regular list. The mapped_collection function allows us to present them as dictionaries whose keys are defined by a callable function. - lazy defines how the relationship query should be executed. In this case, select means that a separate select query will be performed and no object will be retrieved if the user does not explicitly refers to the relationship. ''' Current_Status.host = relationship(Host, primaryjoin = Current_Status.component_id == Host.id, foreign_keys = [Host.__table__.c.id], collection_class = mapped_collection(lambda item: (item.hostname, ",".join([socket.inet_ntoa(x.ip) for x in item.host_ips]))), lazy='false', passive_deletes='all') Current_Status.net = relationship(Net, primaryjoin = Current_Status.component_id == Net.id, foreign_keys = [Net.__table__.c.id], collection_class = mapped_collection(lambda item: (item.name, ",".join([x.cidr for x in item.net_cidrs]))), lazy='false', passive_deletes=True) Current_Status.user = relationship(Users, primaryjoin = Current_Status.component_id == Users.uuid, foreign_keys = [Users.__table__.c.uuid], collection_class = mapped_collection(lambda item: (item.name, '')), lazy='false', passive_deletes=True) Current_Status.server = relationship(Server,
class User(Base): """ Model comment """ __tablename__ = 'users' # sqlalchemy wants it _ignored = sa.Column(sa.String) # Annotated column: type will be taken from the annotation # In no other case an annotated column will be tested annotated_int: int = sa.Column(sa.String, primary_key=True) # Column(Integer): type will be taken from the column type int = sa.Column(sa.Integer) # Interesting special type that depends on another enum = sa.Column(sa.Enum(EnumType)) # Optional and required columns optional = sa.Column(sa.String, nullable=True) required = sa.Column(sa.String, nullable=False) # Field with a default default = sa.Column(sa.String, nullable=False, default='value') # Documented field documented = sa.Column(sa.String, doc="Some descriptive text") # JSON field, as_mutable() # NOTE: cannot call it just `json` because that's Pydantic's reserved method json_attr = sa.Column(MutableDict.as_mutable(sa.JSON)) # An untyped property becomes `Any` @property def property_without_type(self): return None # A typed property: type taken from the annotation @property def property_typed(self) -> str: return 'b' @property @loads_attributes_readcode() # the only property that knows what it loads def property_documented(self): """ Documented property """ return self.documented @property def property_nullable(self) -> Optional[str]: return 'o' # A writable typed property @property def property_writable(self) -> str: return 'a' @property_writable.setter def property_writable(self, v='default'): pass # A hybrid property: same behavior as @property @hybrid_property def hybrid_property_typed(self) -> str: return 'c' @hybrid_property def hybrid_property_writable(self) -> str: pass @hybrid_property_writable.setter def hybrid_property_writable(self, v='default'): pass # A hybrid method @hybrid_method def hybrid_method_attr(self, a: int, b: int): return False # Column property: a selectable using multiple columns expression = sa.orm.column_property(int + annotated_int) # Composite type: uses two columns point = sa.orm.composite(Point, int, annotated_int) # Synonym synonym = sa.orm.synonym('point') # Relationship articles_list = sa.orm.relationship(lambda: Article, back_populates='user') articles_set = sa.orm.relationship(lambda: Article, collection_class=set, viewonly=True) articles_dict_attr = sa.orm.relationship(lambda: Article, collection_class=attribute_mapped_collection('id')) articles_dict_keyfun = sa.orm.relationship(lambda: Article, collection_class=mapped_collection(lambda note: note.id + 1000)) # Association proxy article_titles = association_proxy( 'articles_list', 'title' ) article_authors = association_proxy( 'articles_list', 'user', ) # Dynamic loader articles_q = sa.orm.dynamic_loader(lambda: Article)
# notice that we are identifying each mapper to its connecting # relation by just the class itself. mapper(_EntityField, entity_fields) mapper( _EntityValue, entity_values, properties = { 'field' : relation(_EntityField, lazy=False, cascade='all') } ) mapper(Entity, entities, properties = { '_entities' : relation( _EntityValue, lazy=False, cascade='all', collection_class=mapped_collection(lambda entityvalue: entityvalue.field.name) ) }) session = Session() entity1 = Entity( title = 'this is the first entity', name = 'this is the name', price = 43, data = ('hello', 'there') ) entity2 = Entity( title = 'this is the second entity', name = 'this is another name', price = 50,
objects are contained inside a regular list. The mapped_collection function allows us to present them as dictionaries whose keys are defined by a callable function. - lazy defines how the relationship query should be executed. In this case, select means that a separate select query will be performed and no object will be retrieved if the user does not explicitly refers to the relationship. ''' #Current_Status.message = relationship(Status_Message, # primaryjoin = Current_Status.message_id == Status_Message.id, # foreign_keys = [Status_Message.__table__.c.id], # lazy='false') # Current_Status.host = relationship(Host, primaryjoin=Current_Status.component_id == Host.id, foreign_keys=[Host.__table__.c.id], collection_class=mapped_collection(lambda item: (item.hostname, ",".join([socket.inet_ntoa(x.ip) for x in item.host_ips]))), lazy='false', passive_deletes='all') Current_Status.net = relationship(Net, primaryjoin=Current_Status.component_id == Net.id, foreign_keys=[Net.__table__.c.id], collection_class=mapped_collection(lambda item: (item.name, ",".join([x.cidr for x in item.net_cidrs]))), lazy='false', passive_deletes=True) Current_Status.user = relationship(Users, primaryjoin=Current_Status.component_id == Users.uuid, foreign_keys=[Users.__table__.c.uuid], collection_class=mapped_collection(lambda item: (item.name, '')), lazy='false', passive_deletes=True) Current_Status.server = relationship(Server,
# # Mappers # mapper( Package, PackageTable, properties={ # listings is here for compatibility. Will be removed in 0.4.x 'listings': relation(PackageListing), 'listings2': relation(PackageListing, backref=backref('package'), collection_class=mapped_collection(collection_alias)) }) mapper(PackageListing, PackageListingTable, properties={ 'people': relation(PersonPackageListing), 'people2': relation(PersonPackageListing, backref=backref('packagelisting'), collection_class=attribute_mapped_collection('username')), 'groups': relation(GroupPackageListing), 'groups2': relation(GroupPackageListing,
:arg pkg_listing: PackageListing to find the Collection for. :returns: Collection Alias. This is either the branchname or a combination of the collection name and version. This is used to make Branch keys for the dictionary mapping of pkg listings into packages. ''' return pkg_listing.collection.simple_name # # Mappers # mapper(Package, PackageTable, properties={ # listings is here for compatibility. Will be removed in 0.4.x 'listings': relation(PackageListing), 'listings2': relation(PackageListing, backref=backref('package'), collection_class=mapped_collection(collection_alias)) }) mapper(PackageListing, PackageListingTable, properties={ 'people': relation(PersonPackageListing), 'people2': relation(PersonPackageListing, backref=backref('packagelisting'), collection_class = attribute_mapped_collection('username')), 'groups': relation(GroupPackageListing), 'groups2': relation(GroupPackageListing, backref=backref('packagelisting'), collection_class = attribute_mapped_collection('groupname')), })
class Game(bot_declarative_base): """ Represents a single inhouse game, currently only supporting LoL and standard roles """ __tablename__ = "game" # Auto-incremented ID field id = Column(Integer, primary_key=True) # Game creation date start = Column(DateTime) # Server the game was played from server_id = Column(BigInteger) # Predicted outcome before the game was played blue_expected_winrate = Column(Float) # Winner, updated at the end of the game winner = Column(side_enum) # ORM relationship to participants in the game, defined as a [team, role] dictionary participants = relationship( "GameParticipant", collection_class=mapped_collection( lambda participant: (participant.side, participant.role)), backref="game", cascade="all, delete-orphan", ) # We define teams only as properties as it should be easier to work with @property def teams(self): from inhouse_bot.orm import GameParticipant @dataclass class Teams: BLUE: List[GameParticipant] RED: List[GameParticipant] return Teams( BLUE=[self.participants["BLUE", role] for role in roles_list], RED=[self.participants["RED", role] for role in roles_list], ) @property def matchmaking_score(self): return abs(0.5 - self.blue_expected_winrate) @property def player_ids_list(self): return [p.player_id for p in self.participants.values()] def __str__(self): return tabulate( { "BLUE": [p.short_name for p in self.teams.BLUE], "RED": [p.short_name for p in self.teams.BLUE] }, headers="keys", ) def add_game_field(self, embed: Embed, validated_players: Optional[List[int]] = None) -> Embed: # TODO This warrants a rewrite + a new function that returns the right embed directly for side in ("BLUE", "RED"): embed.add_field( name=side, value="\n".join([ f"{get_role_emoji(roles_list[idx])}" # We start with the role emoji + ( # Then add ? or ✅ if we are looking at a validation embed "" if validated_players is None else " ❔" if p.player_id not in validated_players else " ✅") + f" {p.short_name}" # And finally add the player name for idx, p in enumerate(getattr(self.teams, side)) ]), ) return embed def __init__(self, players: Dict[Tuple[str, str], Player]): """ Creates a Game object and its GameParticipant children. Args: players: [team, role] -> Player dictionary """ # We use local imports to not have circular imports from inhouse_bot.orm import GameParticipant from inhouse_bot.matchmaking_logic import evaluate_game self.start = datetime.datetime.now() # First, we write down the participants self.participants = {(team, role): GameParticipant(team, role, players[team, role]) for team, role in players} self.server_id = list(self.participants.values())[0].player_server_id # Then, we compute the expected blue side winrate (which we use for matchmaking) self.blue_expected_winrate = evaluate_game(self)
def field_definitions(cls): return relationship(cls.__fieldset_definition__['class'], cascade="all, delete-orphan", collection_class=mapped_collection( lambda field_def: field_def.uuid), backref='fieldset')
class World(GameState): """The world object which controls the game states for a player.""" colonies = db.relationship('Colony', backref='world') """All colonies ('players') which exist in this world.""" ants = db.relationship('Ant', backref='world') """All ants that exist in this world.""" foods = db.relationship('Food', backref='world') """All foods which exist in this world.""" age = db.Column(db.Integer) """How long this world has been running for.""" width = db.Column(db.Integer) """The horizontal size of the world.""" height = db.Column(db.Integer) """The vertical size of the world.""" maps = db.relationship( 'Map', collection_class=mapped_collection(lambda _map: (_map.x, _map.y)), backref='world') """The mapping of objects in the world to their coordinates.""" pheromones = db.relationship( 'Pheromone', collection_class=mapped_collection(lambda _pheromone: ( _pheromone.colony_id, _pheromone.x, _pheromone.y)), backref='world') """The mapping of pheromones in the world to their coordinates.""" def __init__(self, width=50, height=50): self.age = 0 self.width = width self.height = height def add_object(self, object_to_be_added): """Adds the object to this world. Args: object_to_be_added (Object): The object to be added to the world. """ new_mapping = Map.add_object(self.id, object_to_be_added) if new_mapping: object_to_be_added.save() new_mapping.ref_id = object_to_be_added.id return True else: return False def remove_object(self, object_to_be_removed): """Removes the object from this world. Args: object_to_be_removed (Object): The object to be removed. """ Map.remove_object(object_to_be_removed) object_to_be_removed.query.delete() def get_object_at_location(self, x, y): """Returns the object located at given coordinates. Args: x (int): X coordinate y (int): Y coordinates Returns: Object: The object located at those coordinates. None if nothing exists there. """ object_map_at_target_location = self.maps.get((x, y)) if not object_map_at_target_location: return None return object_map_at_target_location.get_real_object() def generate_food(self): """Creates a food object randomly somewhere in this world.""" x = random.randint(0, self.width) y = random.randint(0, self.height) new_food = Food(self.id, x, y) food_created = self.add_object(new_food) if not food_created: existing_object = self.get_object_at_location(x, y) if isinstance(existing_object, Food): existing_object.value += 1 def add_pheromone_trail(self, colony_id, old_x, old_y, x, y): existing_trail = self.pheromones.get((colony_id, x, y)) if not existing_trail: degrees = (math.degrees(math.atan2(old_y - y, old_x - x))) % 360 new_trail = Pheromone.add_pheromone(self.id, 1, x, y, 'food-path', degrees, 1) elif existing_trail.colony_id == 1: existing_trail.strength += 1
class Game(sql_alchemy_base): """Represents a single inhouse game, currently only supporting LoL and standard roles.""" __tablename__ = "game" # Auto-incremented ID field id = Column(Integer, primary_key=True) # Game creation date date = Column(DateTime) # Predicted outcome before the game was played blue_side_predicted_winrate = Column(Float) # Winner, updated at the end of the game winner = Column(team_enum) # ORM relationship to participants in the game, defined as a [team, role] dictionary participants = relationship( "GameParticipant", collection_class=mapped_collection( lambda participant: (participant.team, participant.role)), backref="game", cascade="all, delete-orphan", ) def __str__(self): return tabulate( { team_column.capitalize(): [ self.participants[team, role].player.name for (team, role) in sorted(self.participants, key=lambda x: roles_list.index(x[1])) if team == team_column ] for team_column in ["blue", "red"] }, headers="keys", ) def __init__(self, players: dict): """ Creates a Game object and its GameParticipant children. :param players: [team, role] -> Player dictionary """ self.date = datetime.datetime.now() self.blue_side_predicted_winrate = trueskill_blue_side_winrate(players) self.participants = {(team, role): GameParticipant(self, team, role, players[team, role]) for team, role in players} def update_trueskill(self): """ Updates the game’s participants TrueSkill values based on the game result. """ import trueskill session = object_session(self) # participant.trueskill represents pre-game values # p.player.ratings[p.role] is the PlayerRating relevant to the game that was scored team_ratings = { team: { p.player.ratings[p.role]: trueskill.Rating(p.trueskill_mu, p.trueskill_sigma) for p in self.participants.values() if p.team == team } for team in ["blue", "red"] } if self.winner == "blue": new_ratings = trueskill.rate( [team_ratings["blue"], team_ratings["red"]]) else: new_ratings = trueskill.rate( [team_ratings["red"], team_ratings["blue"]]) for team in new_ratings: for player_rating in team: player_rating.trueskill_mu = team[player_rating].mu player_rating.trueskill_sigma = team[player_rating].sigma session.add(player_rating) session.commit()
class Game(bot_declarative_base): """ Represents a single inhouse game, currently only supporting LoL and standard roles """ __tablename__ = "game" # Auto-incremented ID field id = Column(Integer, primary_key=True) # Game creation date start = Column(DateTime) # Server the game was played from server_id = Column(BigInteger) # Predicted outcome before the game was played blue_expected_winrate = Column(Float) # Winner, updated at the end of the game winner = Column(side_enum) # ORM relationship to participants in the game, defined as a [team, role] dictionary participants = relationship( "GameParticipant", collection_class=mapped_collection( lambda participant: (participant.side, participant.role)), backref="game", cascade="all, delete-orphan", ) # We define teams only as properties as it should be easier to work with @property def teams(self): from inhouse_bot.database_orm import GameParticipant @dataclass class Teams: BLUE: List[GameParticipant] RED: List[GameParticipant] return Teams( BLUE=[self.participants["BLUE", role] for role in roles_list], RED=[self.participants["RED", role] for role in roles_list], ) @property def matchmaking_score(self): return abs(0.5 - self.blue_expected_winrate) @property def player_ids_list(self): return [p.player_id for p in self.participants.values()] @property def players_ping(self) -> str: return f"||{' '.join([f'<@{discord_id}>' for discord_id in self.player_ids_list])}||\n" def __str__(self): return tabulate( { "BLUE": [p.short_name for p in self.teams.BLUE], "RED": [p.short_name for p in self.teams.BLUE] }, headers="keys", ) def get_embed(self, embed_type: str, validated_players: Optional[List[int]] = None, bot=None) -> Embed: if embed_type == "GAME_FOUND": embed = Embed( title="📢 Game found 📢", description= f"Blue side expected winrate is {self.blue_expected_winrate * 100:.1f}%\n" "If you are ready to play, press ✅\n" "If you cannot play, press ❌", ) elif embed_type == "GAME_ACCEPTED": embed = Embed( title="📢 Game accepted 📢", description= f"Game {self.id} has been validated and added to the database\n" f"Once the game has been played, one of the winners can score it with `!won`\n" f"If you wish to cancel the game, use `!cancel`", ) else: raise ValueError # Not the prettiest piece of code but it works well for side in ("BLUE", "RED"): embed.add_field( name=side, value="\n".join( # This adds one side as an inline field [ f"{get_role_emoji(roles_list[idx])}" # We start with the role emoji + ( # Then add loading or ✅ if we are looking at a validation embed "" if embed_type != "GAME_FOUND" else f" {get_champion_emoji('loading', bot)}" if p.player_id not in validated_players else " ✅") + f" {p.short_name}" # And finally add the player name for idx, p in enumerate(getattr(self.teams, side)) ]), ) return embed def __init__(self, players: Dict[Tuple[str, str], Player]): """ Creates a Game object and its GameParticipant children. Args: players: [team, role] -> Player dictionary """ # We use local imports to not have circular imports from inhouse_bot.database_orm import GameParticipant from inhouse_bot.matchmaking_logic import evaluate_game self.start = datetime.datetime.now() # First, we write down the participants self.participants = {(team, role): GameParticipant(team, role, players[team, role]) for team, role in players} self.server_id = list(self.participants.values())[0].player_server_id # Then, we compute the expected blue side winrate (which we use for matchmaking) self.blue_expected_winrate = evaluate_game(self)
value = property(_get_value, _set_value) # the mappers are a straightforward eager chain of # Entity--(1->many)->EntityValue-(many->1)->EntityField # notice that we are identifying each mapper to its connecting # relation by just the class itself. mapper(EntityField, entity_fields) mapper( EntityValue, entity_values, properties = { 'field' : relation(EntityField, lazy=False, cascade='all') } ) mapper(Entity, entities, properties = { '_entities' : relation(EntityValue, lazy=False, cascade='all', collection_class=mapped_collection(lambda entityvalue: entityvalue.field.name)) }) # create two entities. the objects can be used about as regularly as # any object can. session = Session() entity = Entity() entity.title = 'this is the first entity' entity.name = 'this is the name' entity.price = 43 entity.data = ('hello', 'there') entity2 = Entity() entity2.title = 'this is the second entity' entity2.name = 'this is another name' entity2.price = 50