示例#1
0
 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'
     )
示例#2
0
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')]
示例#3
0
 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)))
示例#4
0
 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)
         )
     )
示例#5
0
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,
示例#7
0
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)
示例#8
0
# 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,
示例#9
0
    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,
示例#10
0
#
# 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,
示例#11
0
    :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')),
    })

示例#12
0
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)
示例#13
0
 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')
示例#14
0
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
示例#15
0
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()
示例#16
0
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)
示例#17
0
    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