예제 #1
0
파일: scores.py 프로젝트: questionlp/wwdtm
    def __init__(
        self,
        connect_dict: Optional[Dict[str, Any]] = None,
        database_connection: Optional[connect] = None,
    ):
        """Class initialization method."""
        if connect_dict:
            self.connect_dict = connect_dict
            self.database_connection = connect(**connect_dict)
        elif database_connection:
            if not database_connection.is_connected():
                database_connection.reconnect()

            self.database_connection = database_connection

        self.utility = PanelistUtility(database_connection=self.database_connection)
예제 #2
0
파일: scores.py 프로젝트: questionlp/wwdtm
class PanelistScores:
    """This class contains functions used to retrieve panelist scores
    from a copy of the Wait Wait Stats database.

    :param connect_dict: Dictionary containing database connection
        settings as required by mysql.connector.connect
    :param database_connection: mysql.connector.connect database
        connection
    """

    def __init__(
        self,
        connect_dict: Optional[Dict[str, Any]] = None,
        database_connection: Optional[connect] = None,
    ):
        """Class initialization method."""
        if connect_dict:
            self.connect_dict = connect_dict
            self.database_connection = connect(**connect_dict)
        elif database_connection:
            if not database_connection.is_connected():
                database_connection.reconnect()

            self.database_connection = database_connection

        self.utility = PanelistUtility(database_connection=self.database_connection)

    @lru_cache(typed=True)
    def retrieve_scores_by_id(self, panelist_id: int) -> List[int]:
        """Returns a list of panelist scores for appearances for the
        requested panelist ID.

        :param panelist_id: Panelist ID
        :return: List containing panelist scores. If panelist scores
            could not be retrieved, an empty list is returned.
        """
        if not valid_int_id(panelist_id):
            return []

        scores = []
        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT pm.panelistscore AS score "
            "FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE panelistid = %s "
            "AND s.bestof = 0 and s.repeatshowid IS NULL "
            "ORDER BY s.showdate ASC;"
        )
        cursor.execute(query, (panelist_id,))
        result = cursor.fetchall()
        cursor.close()

        if not result:
            return []

        for appearance in result:
            if appearance.score:
                scores.append(appearance.score)

        return scores

    @lru_cache(typed=True)
    def retrieve_scores_by_slug(self, panelist_slug: str) -> List[int]:
        """Returns a list of panelist scores for appearances for the
        requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: List containing panelist scores. If panelist scores
            could not be retrieved, an empty list is returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return []

        return self.retrieve_scores_by_id(id_)

    @lru_cache(typed=True)
    def retrieve_scores_grouped_list_by_id(
        self, panelist_id: int
    ) -> Dict[str, List[int]]:
        """Returns a panelist's score grouping for the requested
        panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing two lists, one containing scores
            and one containing counts of those scores. If panelist
            scores could not be retrieved, an empty dictionary is
            returned.
        """
        if not valid_int_id(panelist_id):
            return {}

        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT MIN(pm.panelistscore) AS min, "
            "MAX(pm.panelistscore) AS max "
            "FROM ww_showpnlmap pm "
            "LIMIT 1;"
        )
        cursor.execute(query)
        result = cursor.fetchone()

        if not result:
            return {}

        min_score = result.min
        max_score = result.max

        scores = {}
        for score in range(min_score, max_score + 1):
            scores[score] = 0

        query = (
            "SELECT pm.panelistscore AS score, "
            "COUNT(pm.panelistscore) AS score_count "
            "FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s "
            "AND s.bestof = 0 AND s.repeatshowid IS NULL "
            "AND pm.panelistscore IS NOT NULL "
            "GROUP BY pm.panelistscore "
            "ORDER BY pm.panelistscore ASC;"
        )
        cursor.execute(query, (panelist_id,))
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return {}

        for row in results:
            scores[row.score] = row.score_count

        return {
            "score": list(scores.keys()),
            "count": list(scores.values()),
        }

    @lru_cache(typed=True)
    def retrieve_scores_grouped_list_by_slug(
        self, panelist_slug: str
    ) -> Dict[str, List[int]]:
        """Returns a panelist's score grouping for the requested
        panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing two lists, one containing scores
            and one containing counts of those scores. If panelist
            scores could not be retrieved, an empty dictionary is
            returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return {}

        return self.retrieve_scores_grouped_list_by_id(id_)

    @lru_cache(typed=True)
    def retrieve_scores_grouped_ordered_pair_by_id(
        self, panelist_id: int
    ) -> List[Tuple[int, int]]:
        """Returns a list of tuples containing a score and the
        corresponding number of instances a panelist has scored that amount
        for the requested panelist ID.

        :param panelist_id: Panelist ID
        :return: List of tuples containing scores and score counts. If
            panelist scores could not be retrieved, an empty list is
            returned.
        """
        if not valid_int_id(panelist_id):
            return []

        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT MIN(pm.panelistscore) AS min, "
            "MAX(pm.panelistscore) AS max "
            "FROM ww_showpnlmap pm;"
        )
        cursor.execute(query)
        result = cursor.fetchone()

        if not result:
            return []

        min_score = result.min
        max_score = result.max

        scores = {}
        for score in range(min_score, max_score + 1):
            scores[score] = 0

        query = (
            "SELECT pm.panelistscore AS score, "
            "COUNT(pm.panelistscore) AS score_count "
            "FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s "
            "AND s.bestof = 0 AND s.repeatshowid IS NULL "
            "AND pm.panelistscore IS NOT NULL "
            "GROUP BY pm.panelistscore "
            "ORDER BY pm.panelistscore ASC;"
        )
        cursor.execute(query, (panelist_id,))
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return []

        for row in results:
            scores[row.score] = row.score_count

        return list(scores.items())

    @lru_cache(typed=True)
    def retrieve_scores_grouped_ordered_pair_by_slug(
        self,
        panelist_slug: str,
    ) -> List[Tuple[int, int]]:
        """Returns a list of tuples containing a score and the
        corresponding number of instances a panelist has scored that amount
        for the requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: List of tuples containing scores and score counts. If
            panelist scores could not be retrieved, an empty list is
            returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return []

        return self.retrieve_scores_grouped_ordered_pair_by_id(id_)

    @lru_cache(typed=True)
    def retrieve_scores_list_by_id(
        self,
        panelist_id: int,
    ) -> Dict[str, List]:
        """Returns a dictionary containing two lists, one with show
        dates and one with corresponding scores for the requested
        panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing a list show dates and a list
            of scores. If panelist scores could not be retrieved, an
            empty dictionary is returned.
        """
        if not valid_int_id(panelist_id):
            return {}

        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT s.showdate AS date, pm.panelistscore AS score "
            "FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s "
            "AND s.bestof = 0 AND s.repeatshowid IS NULL "
            "AND pm.panelistscore IS NOT NULL "
            "ORDER BY s.showdate ASC;"
        )
        cursor.execute(query, (panelist_id,))
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return {}

        show_list = []
        score_list = []
        for shows in results:
            show_list.append(shows.date.isoformat())
            score_list.append(shows.score)

        return {
            "shows": show_list,
            "scores": score_list,
        }

    @lru_cache(typed=True)
    def retrieve_scores_list_by_slug(
        self,
        panelist_slug: str,
    ) -> Dict[str, List]:
        """Returns a dictionary containing two lists, one with show
        dates and one with corresponding scores for the requested
        panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing a list show dates and a list
            of scores. If panelist scores could not be retrieved, an
            empty dictionary is returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return {}

        return self.retrieve_scores_list_by_id(id_)

    @lru_cache(typed=True)
    def retrieve_scores_ordered_pair_by_id(
        self, panelist_id: int
    ) -> List[Tuple[str, int]]:
        """Returns a list of tuples containing a show date and the
        corresponding score for the requested panelist ID.

        :param panelist_id: Panelist ID
        :return: List of tuples containing show dates and scores. If
            panelist scores could not be retrieved, an empty list is
            returned.
        """
        if not valid_int_id(panelist_id):
            return []

        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT s.showdate AS date, pm.panelistscore AS score "
            "FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s "
            "AND s.bestof = 0 AND s.repeatshowid IS NULL "
            "AND pm.panelistscore IS NOT NULL "
            "ORDER BY s.showdate ASC;"
        )
        cursor.execute(query, (panelist_id,))
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return []

        scores = []
        for show in results:
            show_date = show.date.isoformat()
            score = show.score
            scores.append((show_date, score))

        return scores

    @lru_cache(typed=True)
    def retrieve_scores_ordered_pair_by_slug(
        self,
        panelist_slug: str,
    ) -> List[Tuple[str, int]]:
        """Returns a list of tuples containing a show date and the
        corresponding score for the requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: List of tuples containing show dates and scores. If
            panelist scores could not be retrieved, an empty list is
            returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return []

        return self.retrieve_scores_ordered_pair_by_id(id_)
예제 #3
0
class Panelist:
    """This class contains functions used to retrieve panelist data
    from a copy of the Wait Wait Stats database.

    :param connect_dict: Dictionary containing database connection
        settings as required by mysql.connector.connect
    :param database_connection: mysql.connector.connect database
        connection
    """
    def __init__(
        self,
        connect_dict: Optional[Dict[str, Any]] = None,
        database_connection: Optional[connect] = None,
    ):
        """Class initialization method."""
        if connect_dict:
            self.connect_dict = connect_dict
            self.database_connection = connect(**connect_dict)
        elif database_connection:
            if not database_connection.is_connected():
                database_connection.reconnect()

            self.database_connection = database_connection

        self.appearances = PanelistAppearances(
            database_connection=self.database_connection)
        self.statistics = PanelistStatistics(
            database_connection=self.database_connection)
        self.utility = PanelistUtility(
            database_connection=self.database_connection)

    def retrieve_all(self) -> List[Dict[str, Any]]:
        """Returns a list of dictionary objects containing panelist ID,
        name and slug string for all panelists.

        :return: List of all panelists and their corresponding
            information. If panelists could not be retrieved, an empty
            list is returned.
        """
        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT panelistid AS id, panelist AS name, panelistslug AS slug, "
            "panelistgender AS gender "
            "FROM ww_panelists "
            "WHERE panelistslug != 'multiple' "
            "ORDER BY panelist ASC;")
        cursor.execute(query)
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return []

        panelists = []
        for row in results:
            panelists.append({
                "id":
                row.id,
                "name":
                row.name,
                "slug":
                row.slug if row.slug else slugify(row.name),
                "gender":
                row.gender,
            })

        return panelists

    def retrieve_all_details(self) -> List[Dict[str, Any]]:
        """Returns a list of dictionary objects containing panelist ID,
        name, slug string and appearance information for all panelists.

        :return: List of all panelists and their corresponding
            information and appearances. If panelists could not be
            retrieved, an empty list is returned.
        """
        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT panelistid AS id, panelist AS name, panelistslug AS slug, "
            "panelistgender AS gender "
            "FROM ww_panelists "
            "WHERE panelistslug != 'multiple' "
            "ORDER BY panelist ASC;")
        cursor.execute(query)
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return []

        panelists = []
        for row in results:
            panelists.append({
                "id":
                row.id,
                "name":
                row.name,
                "slug":
                row.slug if row.slug else slugify(row.name),
                "gender":
                row.gender,
                "statistics":
                self.statistics.retrieve_statistics_by_id(row.id),
                "bluffs":
                self.statistics.retrieve_bluffs_by_id(row.id),
                "appearances":
                self.appearances.retrieve_appearances_by_id(row.id),
            })

        return panelists

    def retrieve_all_ids(self) -> List[int]:
        """Returns a list of all panelist IDs from the database, sorted
        by panelist name.

        :return: List of all panelist IDs. If panelist IDs could not be
            retrieved, an empty list is returned.
        """
        cursor = self.database_connection.cursor(dictionary=False)
        query = ("SELECT panelistid FROM ww_panelists "
                 "WHERE panelistslug != 'multiple' "
                 "ORDER BY panelist ASC;")
        cursor.execute(query)
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return []

        return [v[0] for v in results]

    def retrieve_all_slugs(self) -> List[str]:
        """Returns a list of all panelist slug strings from the
        database, sorted by panelist name.

        :return: List of all panelist slug strings. If panelist slug
            strings could not be retrieved, an empty list is returned.
        """
        cursor = self.database_connection.cursor(dictionary=False)
        query = ("SELECT panelistslug FROM ww_panelists "
                 "WHERE panelistslug != 'multiple' "
                 "ORDER BY panelist ASC;")
        cursor.execute(query)
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return []

        return [v[0] for v in results]

    @lru_cache(typed=True)
    def retrieve_by_id(self, panelist_id: int) -> Dict[str, Any]:
        """Returns a dictionary object containing panelist ID, name and
        slug string for the requested panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing panelist information. If panelist
            information could not be retrieved, an empty dictionary is
            returned.
        """
        if not valid_int_id(panelist_id):
            return {}

        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT panelistid AS id, panelist AS name, panelistslug AS slug, "
            "panelistgender AS gender "
            "FROM ww_panelists "
            "WHERE panelistid = %s "
            "LIMIT 1;")
        cursor.execute(query, (panelist_id, ))
        result = cursor.fetchone()
        cursor.close()

        if not result:
            return {}

        return {
            "id": result.id,
            "name": result.name,
            "slug": result.slug if result.slug else slugify(result.name),
            "gender": result.gender,
        }

    @lru_cache(typed=True)
    def retrieve_by_slug(self, panelist_slug: str) -> Dict[str, Any]:
        """Returns a dictionary object containing panelist ID, name and
        slug string for the requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing panelist information. If panelist
            information could not be retrieved, an empty dictionary is
            returned.
        """
        try:
            slug = panelist_slug.strip()
            if not slug:
                return {}
        except AttributeError:
            return {}

        id_ = self.utility.convert_slug_to_id(slug)
        if not id_:
            return {}

        return self.retrieve_by_id(id_)

    @lru_cache(typed=True)
    def retrieve_details_by_id(self, panelist_id: int) -> Dict[str, Any]:
        """Returns a dictionary object containing panelist ID, name, slug
        string and appearance information for the requested panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing panelist information and their
            appearances. If panelist information could not be retrieved,
            an empty dictionary is returned.
        """
        if not valid_int_id(panelist_id):
            return {}

        info = self.retrieve_by_id(panelist_id)
        if not info:
            return {}

        info["statistics"] = self.statistics.retrieve_statistics_by_id(
            panelist_id)
        info["bluffs"] = self.statistics.retrieve_bluffs_by_id(panelist_id)
        info["appearances"] = self.appearances.retrieve_appearances_by_id(
            panelist_id)

        return info

    @lru_cache(typed=True)
    def retrieve_details_by_slug(self, panelist_slug: str) -> Dict[str, Any]:
        """Returns a dictionary object containing panelist ID, name, slug
        string and appearance information for the requested Panelist slug
        string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing panelist information and their
            appearances. If panelist information could not be retrieved,
            an empty dictionary is returned.
        """
        try:
            slug = panelist_slug.strip()
            if not slug:
                return {}
        except AttributeError:
            return {}

        id_ = self.utility.convert_slug_to_id(slug)
        if not id_:
            return {}

        return self.retrieve_details_by_id(id_)
예제 #4
0
class PanelistAppearances:
    """This class contains functions that retrieve panelist appearance
    information from a copy of the Wait Wait Stats database.

    :param connect_dict: Dictionary containing database connection
        settings as required by mysql.connector.connect
    :param database_connection: mysql.connector.connect database
        connection
    """
    def __init__(
        self,
        connect_dict: Optional[Dict[str, Any]] = None,
        database_connection: Optional[connect] = None,
    ):
        """Class initialization method."""
        if connect_dict:
            self.connect_dict = connect_dict
            self.database_connection = connect(**connect_dict)
        elif database_connection:
            if not database_connection.is_connected():
                database_connection.reconnect()

            self.database_connection = database_connection

        self.utility = PanelistUtility(
            database_connection=self.database_connection)

    @lru_cache(typed=True)
    def retrieve_appearances_by_id(self, panelist_id: int) -> Dict[str, Any]:
        """Returns a list of dictionary objects containing appearance
        information for the requested panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing appearance counts and list of
            appearances for a panelist. If panelist appearances could
            not be retrieved, an empty dictionary is returned.
        """
        if not valid_int_id(panelist_id):
            return {}

        cursor = self.database_connection.cursor(named_tuple=True)
        query = ("SELECT ( "
                 "SELECT COUNT(pm.showid) FROM ww_showpnlmap pm "
                 "JOIN ww_shows s ON s.showid = pm.showid "
                 "WHERE s.bestof = 0 AND s.repeatshowid IS NULL AND "
                 "pm.panelistid = %s ) AS regular_shows, ( "
                 "SELECT COUNT(pm.showid) FROM ww_showpnlmap pm "
                 "JOIN ww_shows s ON s.showid = pm.showid "
                 "WHERE pm.panelistid = %s ) AS all_shows, ( "
                 "SELECT COUNT(pm.panelistid) FROM ww_showpnlmap pm "
                 "JOIN ww_shows s ON pm.showid = s.showid "
                 "WHERE pm.panelistid = %s AND s.bestof = 0 AND "
                 "s.repeatshowid IS NULL "
                 "AND pm.panelistscore IS NOT NULL ) "
                 "AS shows_with_scores;")
        cursor.execute(
            query,
            (
                panelist_id,
                panelist_id,
                panelist_id,
            ),
        )
        result = cursor.fetchone()

        if result:
            appearance_counts = {
                "regular_shows": result.regular_shows,
                "all_shows": result.all_shows,
                "shows_with_scores": result.shows_with_scores,
            }
        else:
            appearance_counts = {
                "regular_shows": 0,
                "all_shows": 0,
                "shows_with_scores": 0,
            }

        query = (
            "SELECT MIN(s.showid) AS first_id, MIN(s.showdate) AS first, "
            "MAX(s.showid) AS most_recent_id, MAX(s.showdate) AS most_recent "
            "FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE s.bestof = 0 AND s.repeatshowid IS NULL "
            "AND pm.panelistid = %s "
            "ORDER BY s.showdate ASC;")
        cursor.execute(query, (panelist_id, ))
        result = cursor.fetchone()

        if result and result.first_id:
            first = {
                "show_id": result.first_id,
                "show_date": result.first.isoformat(),
            }

            most_recent = {
                "show_id": result.most_recent_id,
                "show_date": result.most_recent.isoformat(),
            }

            milestones = {
                "first": first,
                "most_recent": most_recent,
            }

            appearance_info = {
                "milestones": milestones,
            }
        else:
            appearance_info = {
                "milestones": None,
            }

        query = ("SELECT pm.showid AS show_id, s.showdate AS date, "
                 "s.bestof AS best_of, s.repeatshowid AS repeat_show_id, "
                 "pm.panelistlrndstart AS start, "
                 "pm.panelistlrndcorrect AS correct, "
                 "pm.panelistscore AS score, "
                 "pm.showpnlrank AS pnl_rank FROM ww_showpnlmap pm "
                 "JOIN ww_panelists p ON p.panelistid = pm.panelistid "
                 "JOIN ww_shows s ON s.showid = pm.showid "
                 "WHERE pm.panelistid = %s "
                 "ORDER BY s.showdate ASC;")
        cursor.execute(query, (panelist_id, ))
        results = cursor.fetchall()
        cursor.close()

        if result:
            appearances = []
            for appearance in results:
                info = {
                    "show_id":
                    appearance.show_id,
                    "date":
                    appearance.date.isoformat(),
                    "best_of":
                    bool(appearance.best_of),
                    "repeat_show":
                    bool(appearance.repeat_show_id),
                    "lightning_round_start":
                    appearance.start,
                    "lightning_round_correct":
                    appearance.correct,
                    "score":
                    appearance.score,
                    "rank":
                    appearance.pnl_rank
                    if appearance.pnl_rank is not None else None,
                }
                appearances.append(info)

            appearance_info["count"] = appearance_counts
            appearance_info["shows"] = appearances
        else:
            appearance_info["count"] = appearance_counts
            appearance_info["shows"] = []

        return appearance_info

    @lru_cache(typed=True)
    def retrieve_appearances_by_slug(self,
                                     panelist_slug: str) -> Dict[str, Any]:
        """Returns a list of dictionary objects containing appearance
        information for the requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing appearance counts and list of
            appearances for a panelist. If panelist appearances could
            not be retrieved, an empty dictionary is returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return {}

        return self.retrieve_appearances_by_id(id_)

    @lru_cache(typed=True)
    def retrieve_yearly_appearances_by_id(self,
                                          panelist_id: int) -> Dict[int, int]:
        """Returns a dictionary containing panelist appearances broken
        down by year, for the requested panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing scoring breakdown by year. If
            panelist appearances could not be retrieved, an empty
            dictionary is returned.
        """
        if not valid_int_id(panelist_id):
            return {}

        years = {}
        cursor = self.database_connection.cursor(named_tuple=True)
        query = ("SELECT DISTINCT YEAR(s.showdate) AS year "
                 "FROM ww_shows s "
                 "ORDER BY YEAR(s.showdate) ASC;")
        cursor.execute(query)
        results = cursor.fetchall()

        if not results:
            return {}

        for row in results:
            years[row.year] = 0

        query = ("SELECT YEAR(s.showdate) AS year, "
                 "COUNT(p.panelist) AS count "
                 "FROM ww_showpnlmap pm "
                 "JOIN ww_shows s ON s.showid = pm.showid "
                 "JOIN ww_panelists p ON p.panelistid = pm.panelistid "
                 "WHERE pm.panelistid = %s AND s.bestof = 0 "
                 "AND s.repeatshowid IS NULL "
                 "GROUP BY p.panelist, YEAR(s.showdate) "
                 "ORDER BY p.panelist ASC, YEAR(s.showdate) ASC;")
        cursor.execute(query, (panelist_id, ))
        results = cursor.fetchall()
        cursor.close()

        if not results:
            return {}

        for row in results:
            years[row.year] = row.count

        return years

    @lru_cache(typed=True)
    def retrieve_yearly_appearances_by_slug(
            self, panelist_slug: str) -> Dict[int, int]:
        """Returns a dictionary containing panelist appearances broken
        down by year, for the requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing scoring breakdown by year. If
            panelist appearances could not be retrieved, an empty
            dictionary is returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return {}

        return self.retrieve_yearly_appearances_by_id(id_)
예제 #5
0
class PanelistStatistics:
    """This class contains functions used to retrieve data from a copy
    of the Wait Wait Stats database and calculate statistics for
    panelists.

    :param connect_dict: Dictionary containing database connection
        settings as required by mysql.connector.connect
    :param database_connection: mysql.connector.connect database
        connection
    """
    def __init__(
        self,
        connect_dict: Optional[Dict[str, Any]] = None,
        database_connection: Optional[connect] = None,
    ):
        """Class initialization method."""
        if connect_dict:
            self.connect_dict = connect_dict
            self.database_connection = connect(**connect_dict)
        elif database_connection:
            if not database_connection.is_connected():
                database_connection.reconnect()

            self.database_connection = database_connection

        self.scores = PanelistScores(
            database_connection=self.database_connection)
        self.utility = PanelistUtility(
            database_connection=self.database_connection)

    @lru_cache(typed=True)
    def retrieve_bluffs_by_id(self, panelist_id: int) -> Dict[str, int]:
        """Returns a dictionary containing the number of chosen Bluffs
        and correct Bluffs for the requested panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing panelist Bluff counts. If
            panelist Bluff counts could not be returned, an empty
            dictionary will be returned.
        """
        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT ( "
            "SELECT COUNT(blm.chosenbluffpnlid) FROM ww_showbluffmap blm "
            "JOIN ww_shows s ON s.showid = blm.showid "
            "WHERE s.repeatshowid IS NULL AND blm.chosenbluffpnlid = %s "
            ") AS chosen, ( "
            "SELECT COUNT(blm.correctbluffpnlid) FROM ww_showbluffmap blm "
            "JOIN ww_shows s ON s.showid = blm.showid "
            "WHERE s.repeatshowid IS NULL AND blm.correctbluffpnlid = %s "
            ") AS correct;")
        cursor.execute(
            query,
            (
                panelist_id,
                panelist_id,
            ),
        )
        result = cursor.fetchone()
        cursor.close()

        if not result:
            return {}

        return {
            "chosen": result.chosen,
            "correct": result.correct,
        }

    @lru_cache(typed=True)
    def retrieve_bluffs_by_slug(self, panelist_slug: str) -> Dict[str, int]:
        """Returns a dictionary containing the number of chosen Bluffs
        and correct Bluffs for the requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing panelist Bluff counts. If
            panelist Bluff counts could not be returned, an empty
            dictionary will be returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return {}

        return self.retrieve_bluffs_by_id(id_)

    @lru_cache(typed=True)
    def retrieve_rank_info_by_id(self, panelist_id: int) -> Dict[str, int]:
        """Returns a dictionary with ranking information for the
        requested panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing panelist ranking information. If
            panelist ranking information could not be returned, an empty
            dictionary will be returned.
        """
        if not valid_int_id(panelist_id):
            return {}

        cursor = self.database_connection.cursor(named_tuple=True)
        query = (
            "SELECT ( "
            "SELECT COUNT(pm.showpnlrank) FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s AND pm.showpnlrank = '1' AND "
            "s.bestof = 0 and s.repeatshowid IS NULL) as 'first', ( "
            "SELECT COUNT(pm.showpnlrank) FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s AND pm.showpnlrank = '1t' AND "
            "s.bestof = 0 and s.repeatshowid IS NULL) as 'first_tied', ( "
            "SELECT COUNT(pm.showpnlrank) FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s AND pm.showpnlrank = '2' AND "
            "s.bestof = 0 and s.repeatshowid IS NULL) as 'second', ( "
            "SELECT COUNT(pm.showpnlrank) FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s AND pm.showpnlrank = '2t' AND "
            "s.bestof = 0 and s.repeatshowid IS NULL) as 'second_tied', ( "
            "SELECT COUNT(pm.showpnlrank) FROM ww_showpnlmap pm "
            "JOIN ww_shows s ON s.showid = pm.showid "
            "WHERE pm.panelistid = %s AND pm.showpnlrank = '3' AND "
            "s.bestof = 0 and s.repeatshowid IS NULL "
            ") as 'third';")
        cursor.execute(
            query,
            (
                panelist_id,
                panelist_id,
                panelist_id,
                panelist_id,
                panelist_id,
            ),
        )
        result = cursor.fetchone()
        cursor.close()

        if not result:
            return {}

        return {
            "first": result.first,
            "first_tied": result.first_tied,
            "second": result.second,
            "second_tied": result.second_tied,
            "third": result.third,
        }

    @lru_cache(typed=True)
    def retrieve_rank_info_by_slug(self, panelist_slug: str) -> Dict[str, int]:
        """Returns a dictionary with ranking information for the
        requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing panelist ranking information. If
            panelist ranking information could not be returned, an empty
            dictionary will be returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return {}

        return self.retrieve_rank_info_by_id(id_)

    @lru_cache(typed=True)
    def retrieve_statistics_by_id(self, panelist_id: int) -> Dict[str, Any]:
        """Returns a dictionary containing panelist statistics, ranking
        data, and scoring data for the requested panelist ID.

        :param panelist_id: Panelist ID
        :return: Dictionary containing panelist statistics. If panelist
            statistics could not be returned, an empty dictionary will
            be returned.
        """
        if not valid_int_id(panelist_id):
            return {}

        score_data = self.scores.retrieve_scores_by_id(panelist_id)
        ranks = self.retrieve_rank_info_by_id(panelist_id)

        if not score_data or not ranks:
            return {}

        appearance_count = len(score_data)
        scoring = {
            "minimum": int(numpy.amin(score_data)),
            "maximum": int(numpy.amax(score_data)),
            "mean": round(numpy.mean(score_data), 4),
            "median": int(numpy.median(score_data)),
            "standard_deviation": round(numpy.std(score_data), 4),
            "total": int(numpy.sum(score_data)),
        }

        ranks_first = round(100 * (ranks["first"] / appearance_count), 4)
        ranks_first_tied = round(
            100 * (ranks["first_tied"] / appearance_count), 4)
        ranks_second = round(100 * (ranks["second"] / appearance_count), 4)
        ranks_second_tied = round(
            100 * (ranks["second_tied"] / appearance_count), 4)
        ranks_third = round(100 * (ranks["third"] / appearance_count), 4)

        ranks_percentage = {
            "first": ranks_first,
            "first_tied": ranks_first_tied,
            "second": ranks_second,
            "second_tied": ranks_second_tied,
            "third": ranks_third,
        }

        ranking = {
            "rank": ranks,
            "percentage": ranks_percentage,
        }

        return {
            "scoring": scoring,
            "ranking": ranking,
        }

    @lru_cache(typed=True)
    def retrieve_statistics_by_slug(self,
                                    panelist_slug: str) -> Dict[str, Any]:
        """Returns a dictionary containing panelist statistics, ranking
        data, and scoring data for the requested panelist slug string.

        :param panelist_slug: Panelist slug string
        :return: Dictionary containing panelist statistics. If panelist
            statistics could not be returned, an empty dictionary will
            be returned.
        """
        id_ = self.utility.convert_slug_to_id(panelist_slug)
        if not id_:
            return {}

        return self.retrieve_statistics_by_id(id_)