Wrapper for the undocumented CodinGame API. Can be used both synchronously and asynchronlously.

Overview

codingame API wrapper

PyPI version info Supported Python versions Lint and test workflow status Documentation build status Code coverage Code style: Black Discord support server

Pythonic wrapper for the undocumented CodinGame API.

Installation

Python 3.6 or higher is required.

Install codingame with pip:

pip install codingame

Quickstart

Create an application, in example.py:

import codingame

client = codingame.Client()

# get a codingamer
codingamer = client.get_codingamer("username")
print(codingamer.pseudo)

# get the global leaderboard
global_leaderboard = client.get_global_leaderboard()
# print the pseudo of the top codingamer
print(global_leaderboard.users[0].pseudo)

See the docs.

Contribute

Support

If you are having issues, please let me know by joining the discord support server at https://discord.gg/8HgtN6E

License

The project is licensed under the MIT license.

Links

Comments
  • [FR] Make Client useable for any authenticated POST request

    [FR] Make Client useable for any authenticated POST request

    Is your feature request related to a problem? Please describe. I made a small app that downloads all my CodinGame solutions. I need to make authenticated API requests to different URLs e.g. https://www.codingame.com/services/Puzzle/findAllMinimalProgress, /Solution/findSolution, etc.

    I've now blocked with the login problem #5 and at the same time I was guessing about some solution you were building it! (wow!)

    Describe the solution you'd like Add codingame.Client.request(service: str, func: str, json: list = []) to the public API for both the sync and async clients.

    Describe alternatives you've considered

    • I think my app could invoke client.request() but as it's undocumented it seems to be an internal API?
    • I could add cookie session in my own repo, but I'd rather rely on some dedicated client to handle the logic.
    • It would be awesome if this client natively supported the various CodinGame APIs my puzzle solution download app needed, but that feels like a big request. Instead, having the generic .request() escape hatch enables the library to be used for any new APIs that CodinGame releases!

    Additional context I'm impressed by this project! Nice!

    enhancement good first issue 
    opened by darthwalsh 2
  • [RELEASE] 1.4.x

    [RELEASE] 1.4.x

    Version 1.4.0

    Added

    • Client.mark_notifications_as_seen and Client.mark_notifications_as_read.
    • Notification.mark_as_seen and Notification.mark_as_read.

    Removed

    • Removed support for python 3.6 as it has reached its end of life. For more information, see PEP 494.
    release 
    opened by takos22 1
  • implement state.current_language

    implement state.current_language

    implement state.current_language

    def str(self) -> str:

    return self[state.current_language]

    https://github.com/takos22/codingame/blob/a169a0c6ccb4b096fe599ffc2b725ea8c90e6bc5/codingame/notification/data.py#L77

    
    import re
    import typing
    from datetime import datetime
    
    from ..abc import Mapping
    from ..types import notification as types
    from ..utils import to_datetime
    from .enums import (
        CommentType,
        ContributionModeratedActionType,
        ContributionType,
        NotificationType,
    )
    
    if typing.TYPE_CHECKING:
        from ..state import ConnectionState
    
    __all__ = (
        "LanguageMapping",
        "NotificationData",
        "AchievementUnlockedData",
        "LeagueData",
        "NewBlogData",
        "ClashInviteData",
        "ClashOverData",
        "Contribution",
        "PuzzleSolution",
        "NewCommentData",
        "ContributionData",
        "FeatureData",
        "NewHintData",
        "ContributionModeratedData",
        "NewPuzzleData",
        "PuzzleOfTheWeekData",
        "QuestCompletedData",
        "FriendRegisteredData",
        "NewLevelData",
        "GenericData",
        "CustomData",
        "CareerCandidateData",
        "TestFinishedData",
        "JobAcceptedData",
        "JobExpiredData",
        "NewWorkBlogData",
        "OfferApplyData",
    )
    
    
    class LanguageMapping(Mapping):
        """Mapping to store text with multiple languages.
    
        This class has the same interface as :class:`dict` for backwards
        compatibility.
    
        Attributes
        -----------
            en: :class:`str`
                The text in english.
    
            fr: :class:`str`
                The text in french.
        """
    
        en: str
        fr: str
    
        __slots__ = ("en", "fr")
    
        def __init__(
            self, state: "ConnectionState", mapping: types.LanguageMapping
        ):
            self.en = mapping["en"]
            self.fr = mapping["fr"]
    
            super().__init__(state, mapping)
    
        # TODO implement state.current_language
        # def __str__(self) -> str:
        #     return self[state.current_language]
    
    
    class NotificationData(Mapping):
        """Base class for the notification data classes.
    
        This class has the same interface as :class:`dict` for backwards
        compatibility.
    
        Attributes
        -----------
            _raw: :class:`dict`
                Raw data of the :class:`Notification`, useful when one of the values
                isn't an attribute.
        """
    
        _raw: dict
    
        def __init__(self, state: "ConnectionState", data: types.NotificationData):
            super().__init__(state, data)
    
        @classmethod
        def from_type(
            cls,
            type: NotificationType,
            state: "ConnectionState",
            data: types.NotificationData,
        ) -> typing.Optional["NotificationData"]:
            """Create the correct :class:`NotificationData` subclass according to
            the :class:`notification type <NotificationType>`.
    
            Parameters
            ----------
                type : :class:`NotificationType`
                    The notification type.
    
                data : :class:`dict`
                    The notification data.
    
            Returns
            -------
                :class:`NotificationData`
                    The parsed data of the notifcation.
            """
    
            NT = NotificationType
            type_to_obj = {
                NT.achievement_unlocked: AchievementUnlockedData,
                NT.new_league: LeagueData,
                NT.eligible_for_next_league: LeagueData,
                NT.promoted_league: LeagueData,
                NT.new_league_opened: LeagueData,
                NT.new_blog: NewBlogData,
                NT.clash_invite: ClashInviteData,
                NT.clash_over: ClashOverData,
                NT.new_comment: NewCommentData,
                NT.new_comment_response: NewCommentData,
                NT.contribution_received: ContributionData,
                NT.contribution_accepted: ContributionData,
                NT.contribution_refused: ContributionData,
                NT.contribution_clash_mode_removed: ContributionData,
                NT.feature: FeatureData,
                NT.new_hint: NewHintData,
                NT.contribution_moderated: ContributionModeratedData,
                NT.new_puzzle: NewPuzzleData,
                NT.puzzle_of_the_week: PuzzleOfTheWeekData,
                NT.quest_completed: QuestCompletedData,
                NT.friend_registered: FriendRegisteredData,
                NT.new_level: NewLevelData,
                NT.info_generic: GenericData,
                NT.warning_generic: GenericData,
                NT.important_generic: GenericData,
                NT.custom: CustomData,
                NT.career_new_candidate: CareerCandidateData,
                NT.career_update_candidate: CareerCandidateData,
                NT.test_finished: TestFinishedData,
                NT.job_accepted: JobAcceptedData,
                NT.job_expired: JobExpiredData,
                NT.new_work_blog: NewWorkBlogData,
                NT.offer_apply: OfferApplyData,
            }
            return (
                type_to_obj.get(type, NotificationData)(state, data)
                if data
                else None
            )
    
    
    # achievement
    
    
    class AchievementUnlockedData(NotificationData):
        """Data of a :attr:`NotificationType.achievement_unlocked` notification."""
    
        id: str
        label: LanguageMapping
        points: int
        level: str
        completion_time: datetime
        image_url: str
    
        __slots__ = (
            "id",
            "label",
            "points",
            "level",
            "completion_time",
            "image_url",
        )
    
        def __init__(
            self, state: "ConnectionState", data: types.AchievementUnlockedData
        ):
            self.id = data["id"]
            self.label = LanguageMapping(state, data["label"])
            self.points = data["points"]
            self.level = data["level"]
            self.completion_time = to_datetime(data["completionTime"])
            self.image_url = state.http.get_file_url(
                data["imageId"], format="notification_picture"
            )
    
            super().__init__(state, data)
    
    
    # arena and new-league-opened
    
    
    class LeagueData(NotificationData):
        """Data of :attr:`NotificationType.new_league`,
        :attr:`NotificationType.eligible_for_next_league`,
        :attr:`NotificationType.promoted_league` and
        :attr:`NotificationType.new_league_opened` notifications."""
    
        title_label: LanguageMapping
        division_index: int
        division_count: int
        division_offset: int
        threshold_index: int
        thumbnail_url: str
        test_session_handle: str
    
        __slots__ = (
            "title_label",
            "division_index",
            "division_count",
            "division_offset",
            "threshold_index",
            "thumbnail_url",
            "test_session_handle",
        )
    
        def __init__(self, state: "ConnectionState", data: types.LeagueData):
            self.title_label = LanguageMapping(state, data["titleLabel"])
            self.division_index = data["divisionIndex"]
            self.division_count = data["divisionCount"]
            self.division_offset = data["divisionOffset"]
            self.threshold_index = data["thresholdIndex"]
            self.thumbnail_url = state.http.get_file_url(
                data["thumbnailBinaryId"], format="notification_picture"
            )
            self.test_session_handle = data["testSessionHandle"]
    
            super().__init__(state, data)
    
    
    # blog
    
    
    class NewBlogData(NotificationData):
        """Data of a :attr:`NotificationType.new_blog` notification."""
    
        title: LanguageMapping
        url: LanguageMapping
    
        __slots__ = (
            "title",
            "url",
        )
    
        def __init__(self, state: "ConnectionState", data: types.NewBlogData):
            self.title = LanguageMapping(state, data["title"])
            self.url = LanguageMapping(state, data["url"])
    
            super().__init__(state, data)
    
    
    # clash
    
    
    class ClashInviteData(NotificationData):
        """Data of a :attr:`NotificationType.clash_invite` notification."""
    
        handle: str
    
        __slots__ = ("handle",)
    
        def __init__(self, state: "ConnectionState", data: types.ClashInviteData):
            self.handle = data["handle"]
    
            super().__init__(state, data)
    
    
    class ClashOverData(NotificationData):
        """Data of a :attr:`NotificationType.clash_over` notification."""
    
        handle: str
        rank: int
        player_count: int
    
        __slots__ = (
            "handle",
            "rank",
            "player_count",
        )
    
        def __init__(self, state: "ConnectionState", data: types.ClashOverData):
            self.handle = data["handle"]
            self.rank = data["rank"]
            self.player_count = data["playerCount"]
    
            super().__init__(state, data)
    
    
    # comment
    
    
    class Contribution(Mapping):
        """Data about a contribution.
    
        This class has the same interface as :class:`dict` for backwards
        compatibility.
        """
    
        handle: str
        title: typing.Optional[str]
        type: typing.Optional[ContributionType]
    
        __slots__ = ("handle", "title", "type")
    
        def __init__(self, state: "ConnectionState", data: types.ContributionData):
            self.handle = data["handle"]
            self.title = data.get("title")
            self.type = ContributionType(data["type"]) if "type" in data else None
    
            super().__init__(state, data)
    
    
    class PuzzleSolution(Mapping):
        """Data about a puzzle solution.
    
        This class has the same interface as :class:`dict` for backwards
        compatibility.
        """
    
        puzzle_id: str
        puzzle_url: typing.Optional[str]
        test_session_submission_id: int
    
        __slots__ = ("puzzle_id", "puzzle_url", "test_session_submission_id")
    
        def __init__(
            self, state: "ConnectionState", data: types.PuzzleSolutionData
        ):
            self.puzzle_id = data["puzzleId"]
            self.puzzle_url = (
                (state.http.BASE_URL + data["puzzleDetailsPageUrl"])
                if "puzzleDetailsPageUrl" in data
                else None
            )
            self.test_session_submission_id = data["testSessionSubmissionId"]
    
            super().__init__(state, data)
    
    
    class NewCommentData(NotificationData):
        """Data of a :attr:`NotificationType.new_comment` and
        :attr:`NotificationType.new_comment_response` notifications."""
    
        type: LanguageMapping
        comment_type: typing.Optional[CommentType]
        type_data: typing.Union[Contribution, PuzzleSolution, None]
        url: typing.Optional[str]
    
        __slots__ = ("type", "comment_type", "type_data", "url")
    
        def __init__(self, state: "ConnectionState", data: types.NewCommentData):
            self.type = LanguageMapping(state, data["type"])
            self.comment_type = (
                CommentType(data["commentType"]) if "commentType" in data else None
            )
            self.type_data = None
            if "typeData" in data:
                self.type_data = (
                    Contribution(state, data["typeData"])
                    if self.comment_type == CommentType.contribution
                    else PuzzleSolution(state, data["typeData"])
                )
            self.url = (
                (state.http.BASE_URL + data["url"]) if "url" in data else None
            )
    
            super().__init__(state, data)
    
    
    # contribution
    
    
    class ContributionData(Mapping):
        """Data of :attr:`NotificationType.contribution_received`,
        :attr:`NotificationType.contribution_accepted`,
        :attr:`NotificationType.contribution_refused` and
        :attr:`NotificationType.contribution_clash_mode_removed` notifications."""
    
        handle: str
        title: typing.Optional[str]
        type: typing.Optional[ContributionType]
    
        __slots__ = ("handle", "title", "type")
    
        def __init__(self, state: "ConnectionState", data: types.ContributionData):
            self.handle = data["handle"]
            self.title = data.get("title")
            self.type = ContributionType(data["type"]) if "type" in data else None
    
            super().__init__(state, data)
    
    
    # feature
    
    
    class FeatureData(NotificationData):
        """Data of a :attr:`NotificationType.feature` notification."""
    
        title: typing.Optional[LanguageMapping]
        description: LanguageMapping
        image_url: str
        url: str
    
        __slots__ = (
            "title",
            "description",
            "image_url",
            "url",
        )
    
        def __init__(self, state: "ConnectionState", data: types.FeatureData):
            self.title = (
                LanguageMapping(state, data["title"]) if "title" in data else None
            )
            self.description = LanguageMapping(state, data["description"])
            self.image_url = data["image-instant"]
            self.url = (
                data["url"]
                if re.match(r"https?://", data["url"])
                else (state.http.BASE_URL + data["url"])
            )
    
            super().__init__(state, data)
    
    
    # hints
    
    
    class NewHintData(NotificationData):
        """Data of a :attr:`NotificationType.new_hint` notification."""
    
        puzzle_title: LanguageMapping
        thumbnail_url: str
        test_session_handle: str
    
        __slots__ = (
            "puzzle_title",
            "thumbnail_url",
            "test_session_handle",
        )
    
        def __init__(self, state: "ConnectionState", data: types.NewHintData):
            self.puzzle_title = LanguageMapping(state, data["puzzleTitle"])
            self.thumbnail_url = state.http.get_file_url(
                data["thumbnailBinaryId"], format="notification_picture"
            )
            self.test_session_handle = data["testSessionHandle"]
    
            super().__init__(state, data)
    
    
    # moderation
    
    
    class ContributionModeratedData(NotificationData):
        """Data of a :attr:`NotificationType.contribution_moderated`
        notification."""
    
        action_type: ContributionModeratedActionType
        contribution: Contribution
    
        __slots__ = (
            "action_type",
            "contribution",
        )
    
        def __init__(
            self, state: "ConnectionState", data: types.ContributionModeratedData
        ):
            self.action_type = ContributionModeratedActionType(data["actionType"])
            self.contribution = Contribution(state, data["contribution"])
    
            super().__init__(state, data)
    
    
    # puzzle
    
    
    class NewPuzzleData(NotificationData):
        """Data of a :attr:`NotificationType.new_puzzle` notification."""
    
        level: LanguageMapping
        name: LanguageMapping
        image_url: str
        puzzle_id: int
    
        __slots__ = (
            "level",
            "name",
            "image_url",
            "puzzle_id",
        )
    
        def __init__(self, state: "ConnectionState", data: types.NewPuzzleData):
            self.level = LanguageMapping(state, data["level"])
            self.name = LanguageMapping(state, data["name"])
            self.image_url = data["image"]
            self.puzzle_id = data["puzzleId"]
    
            super().__init__(state, data)
    
    
    class PuzzleOfTheWeekData(NotificationData):
        """Data of a :attr:`NotificationType.puzzle_of_the_week` notification."""
    
        puzzle_id: int
        puzzle_level: str
        puzzle_pretty_id: str
        puzzle_name: LanguageMapping
        puzzle_image_url: str
        contributor_pseudo: str
        contributor_avatar_url: typing.Optional[str]
    
        __slots__ = (
            "puzzle_id",
            "puzzle_level",
            "puzzle_pretty_id",
            "puzzle_name",
            "puzzle_image_url",
            "contributor_pseudo",
            "contributor_avatar_url",
        )
    
        def __init__(
            self, state: "ConnectionState", data: types.PuzzleOfTheWeekData
        ):
            self.puzzle_id = data["puzzleId"]
            self.puzzle_level = data["puzzleLevel"]
            self.puzzle_pretty_id = data["puzzlePrettyId"]
            self.puzzle_name = LanguageMapping(state, data["puzzleName"])
            self.puzzle_image_url = state.http.get_file_url(
                data["puzzleOfTheWeekImageId"], format="notification_picture"
            )
            self.contributor_pseudo = data["contributorNickname"]
            self.contributor_avatar_url = (
                state.http.get_file_url(
                    data["contributorAvatarId"], format="notification_picture"
                )
                if "contributorAvatarId" in data
                else None
            )
    
            super().__init__(state, data)
    
    
    # quest
    
    
    class QuestCompletedData(NotificationData):
        """Data of a :attr:`NotificationType.quest_completed` notification."""
    
        id: int
        label: LanguageMapping
    
        __slots__ = (
            "id",
            "label",
        )
    
        def __init__(
            self, state: "ConnectionState", data: types.QuestCompletedData
        ):
            self.id = data["questId"]
            self.label = LanguageMapping(state, data["label"])
    
            super().__init__(state, data)
    
    
    # social
    
    
    class FriendRegisteredData(NotificationData):
        """Data of a :attr:`NotificationType.friend_registered` notification."""
    
        name: str
    
        __slots__ = ("name",)
    
        def __init__(
            self, state: "ConnectionState", data: types.FriendRegisteredData
        ):
            self.name = data["name"]
    
            super().__init__(state, data)
    
    
    # xp
    
    
    class NewLevelData(NotificationData):
        """Data of a :attr:`NotificationType.new_level` notification."""
    
        level: int
        reward: typing.Optional[LanguageMapping]
        trigger_career_popup: typing.Optional[bool]
    
        __slots__ = (
            "level",
            "reward",
            "trigger_career_popup",
        )
    
        def __init__(self, state: "ConnectionState", data: types.NewLevelData):
            self.level = data["level"]
            self.reward = (
                LanguageMapping(state, data["reward"]) if "reward" in data else None
            )
            self.trigger_career_popup = data.get("triggerCareerPopup")
    
            super().__init__(state, data)
    
    
    # generic
    
    
    class GenericData(NotificationData):
        """Data of a :attr:`NotificationType.info_generic`,
        :attr:`NotificationType.warning_generic` and
        :attr:`NotificationType.important_generic` notifications."""
    
        title: LanguageMapping
        description: LanguageMapping
        image_url: str
        url: str
    
        __slots__ = (
            "title",
            "description",
            "image_url",
            "url",
        )
    
        def __init__(self, state: "ConnectionState", data: types.GenericData):
            self.description = LanguageMapping(state, data["description"])
            self.url = data["url"]
    
            super().__init__(state, data)
    
    
    # custom
    
    
    class CustomData(NotificationData):
        """Data of a :attr:`NotificationType.custom` notification."""
    
        title: LanguageMapping
        description: LanguageMapping
        image_url: str
        url: str
    
        __slots__ = (
            "title",
            "description",
            "image_url",
            "url",
        )
    
        def __init__(self, state: "ConnectionState", data: types.CustomData):
            self.title = LanguageMapping(state, data["title"])
            self.description = LanguageMapping(state, data["description"])
            self.image_url = state.http.STATIC_URL + data["image"]
            self.url = (
                (state.http.BASE_URL + data["url"])
                if data["url"].startswith("/")
                else data["url"]
            )
    
            super().__init__(state, data)
    
    
    # other
    
    
    class CareerCandidateData(NotificationData):
        """Data of a :attr:`NotificationType.career_new_candidate` and
        :attr:`NotificationType.career_update_candidate` notifications."""
    
        handle: str
        username: typing.Optional[str]
        country: str
        region: str
        avatar_url: typing.Optional[str]
    
        __slots__ = (
            "handle",
            "username",
            "country",
            "region",
            "avatar_url",
        )
    
        def __init__(
            self, state: "ConnectionState", data: types.CareerCandidateData
        ):
            self.handle = data["handle"]
            self.username = data.get("username")
            self.country = data["country"]
            self.region = data["region"]
            self.avatar_url = (
                state.http.get_file_url(
                    data["avatar"], format="notification_picture"
                )
                if "avatar" in data
                else None
            )
    
            super().__init__(state, data)
    
    
    # no category
    
    
    class TestFinishedData(NotificationData):
        """Data of a :attr:`NotificationType.test_finished` notification."""
    
        campaign_id: int
        candidate_id: int
        candidate_name: typing.Optional[str]
        candidate_email: str
    
        __slots__ = (
            "campaign_id",
            "candidate_id",
            "candidate_name",
            "candidate_email",
        )
    
        def __init__(self, state: "ConnectionState", data: types.TestFinishedData):
            self.campaign_id = data["campaignId"]
            self.candidate_id = data["candidateId"]
            self.candidate_name = data.get("candidateName")
            self.candidate_email = data["candidateEmail"]
    
            super().__init__(state, data)
    
    
    class JobAcceptedData(NotificationData):
        """Data of a :attr:`NotificationType.job_accepted` notification."""
    
        job_name: typing.Optional[str]
        job_offer_location: str
        challenge_id: typing.Optional[int]
    
        __slots__ = (
            "job_name",
            "job_offer_location",
            "challenge_id",
        )
    
        def __init__(self, state: "ConnectionState", data: types.JobAcceptedData):
            self.job_name = data.get("jobName")
            self.job_offer_location = data["jobOfferLocation"]
            self.challenge_id = data.get("challengeId")
    
            super().__init__(state, data)
    
    
    class JobExpiredData(NotificationData):
        """Data of a :attr:`NotificationType.job_expired` notification."""
    
        job_name: typing.Optional[str]
    
        __slots__ = ("job_name",)
    
        def __init__(self, state: "ConnectionState", data: types.JobExpiredData):
            self.job_name = data.get("jobName")
    
            super().__init__(state, data)
    
    
    class NewWorkBlogData(NotificationData):
        """Data of a :attr:`NotificationType.new_work_blog` notification."""
    
        title: LanguageMapping
        url: LanguageMapping
    
        __slots__ = (
            "title",
            "url",
        )
    
        def __init__(self, state: "ConnectionState", data: types.NewWorkBlogData):
            self.title = LanguageMapping(state, data["title"])
            self.url = LanguageMapping(
                state,
                {
                    lang: state.http.BASE_URL + path
                    for lang, path in data["url"].items()
                },
            )
    
            super().__init__(state, data)
    
    
    class OfferApplyData(NotificationData):
        """Data of a :attr:`NotificationType.offer_apply` notification."""
    
        candidate_name: str
        job_name: typing.Optional[str]
        job_offer_location: str
        challenge_id: typing.Optional[int]
        job_offer_id: typing.Optional[int]
        job_offer_applicant_id: typing.Optional[int]
    
        __slots__ = (
            "candidate_name",
            "job_name",
            "job_offer_location",
            "challenge_id",
            "job_offer_id",
            "job_offer_applicant_id",
        )
    
        def __init__(self, state: "ConnectionState", data: types.OfferApplyData):
            self.candidate_name = data["candidateName"]
            self.job_name = data.get("jobName")
            self.job_offer_location = data["jobOfferLocation"]
            self.challenge_id = data.get("challengeId")
            self.job_offer_id = data.get("jobOfferId")
            self.job_offer_applicant_id = data.get("jobOfferApplicantId")
    
            super().__init__(state, data)
    
    

    3e717771f317d9ca1ad8ad0078d2a34a832f2ad2

    todo 
    opened by github-actions[bot] 1
  • [RELEASE] v1.2.4

    [RELEASE] v1.2.4

    Version 1.2.4

    Fixed

    • CodinGamer.get_followers and CodinGamer.get_followed now work while being logged in as any user, not just as the user you want to get the followers of.
    release 
    opened by takos22 1
  • Fix docs bug with remember_me_cookie as login param

    Fix docs bug with remember_me_cookie as login param

    codingame.Client() doesn't have param remember_me_cookie Update example code to pass cookie to login()

    (Sorry if the PR isn't based from the right branch; I didn't see CONTRIBUTING docs about which branch the PR should merge into. Maybe it should go to 1.2.x if you are still updating that.)

    opened by darthwalsh 1
  • [FR] Use ID of the logged in user for following endpoints

    [FR] Use ID of the logged in user for following endpoints

    Duplicate of #8

    Generated automatically

    fix this to use [id, logged_in.id]

    https://github.com/takos22/codingame/blob/a09f6bd11a1475c84add70b7231f07bd50246b8e/codingame/http/base.py#L92

    
        ):
            ...  # pragma: no cover
    
        def get_file_url(self, id: int, format: str = None) -> str:
            url = f"https://static.codingame.com/servlet/fileservlet?id={id}"
            if format:
                url += f"&format={format}"
            return url
    
        # Search
    
        def search(self, query: str):
            return self.request("Search", "search", [query, "en", None])
    
        # ProgrammingLanguage
    
        def get_language_ids(self) -> typing.List[str]:
            return self.request("ProgrammingLanguage", "findAllIds")
    
        # CodinGamer
    
        def login(self, email: str, password: str):
            return self.request(
                "CodinGamer", "loginSiteV2", [email, password, True]
            )
    
        def get_codingamer_from_handle(self, handle: str) -> PointsStatsFromHandle:
            return self.request(
                "CodinGamer", "findCodingamePointsStatsByHandle", [handle]
            )
    
        def get_codingamer_from_id(self, id: int) -> CodinGamerFromID:
            return self.request(
                "CodinGamer", "findCodinGamerPublicInformations", [id]
            )
    
        def get_codingamer_followers(self, id: int) -> typing.List[Follower]:
            # TODO fix this to use [id, logged_in.id, None]
            return self.request("CodinGamer", "findFollowers", [id, id, None])
    
        def get_codingamer_follower_ids(self, id: int) -> typing.List[int]:
            return self.request("CodinGamer", "findFollowerIds", [id])
    
        def get_codingamer_following(self, id: int) -> typing.List[Following]:
            # TODO fix this to use [id, logged_in.id]
            return self.request("CodinGamer", "findFollowing", [id, id])
    
        def get_codingamer_following_ids(self, id: int) -> typing.List[int]:
            return self.request("CodinGamer", "findFollowingIds", [id])
    
        # ClashOfCode/
    
        def get_codingamer_clash_of_code_rank(self, id: int) -> int:
            return self.request("ClashOfCode", "getClashRankByCodinGamerId", [id])
    
        def get_clash_of_code_from_handle(self, handle: str) -> ClashOfCode:
            return self.request("ClashOfCode", "findClashByHandle", [handle])
    
        def get_pending_clash_of_code(self) -> ClashOfCode:
            return self.request("ClashOfCode", "findPendingClashes")
    
        # Notification
    
        def get_unread_notifications(self, id: int) -> typing.List[Notification]:
            return self.request("Notification", "findUnreadNotifications", [id])
    
        def get_unseen_notifications(self, id: int) -> typing.List[Notification]:
            return self.request("Notification", "findUnseenNotifications", [id])
    
        def get_last_read_notifications(self, id: int) -> typing.List[Notification]:
            return self.request(
                "Notification", "findLastReadNotifications", [id, None]
            )
    
        # Leaderboards
    
        def get_global_leaderboard(
            self,
    
    

    23aaa6ecba8d489eb5cda32f2848dd0a2601700e

    duplicate todo 
    opened by github-actions[bot] 1
  • [BUG] Login service not found

    [BUG] Login service not found

    Describe the bug

    When logging in to CodinGame API, with Client.login(email, password), a LoginError is raised saying Service not found: codingamer.loginsitev2(3). This means that the endpoint in the API no longer exists, so the login endpoint was changed.

    To Reproduce

    Steps to reproduce the behavior:

    1. Copy this code to a file (you can replace email and password with your own but that doesn't change anything to the error):
      import codingame
      client = codingame.Client()
      client.login("[email protected]", "password")
      
    2. Execute the previously copied code.
    3. See error: codingame.exceptions.LoginError: Service not found: codingamer.loginsitev2(3)

    Expected behavior

    Login works and doesn't raise an error.

    Environment information:

    • OS: Windows 10 (but works on any OS)
    • Python version: 3.7.6 (but works on any version)
    • codingame module version: 1.0.1 (but works on any version)

    Additional context

    The login endpoint was moved to CodinGamer/loginSite and now needs a Captcha or a valid session.

    bug 
    opened by takos22 1
  • Add marking notifications as seen or read

    Add marking notifications as seen or read

    Feature description

    Add Client.mark_notifications_as_seen, Client.mark_notifications_as_read, Notification.mark_as_seen`` andNotification.mark_as_read` to mark a notification as seen or read.

    Added to both the Notification class and Client class for convenience. Client.mark_notifications_as_seen and Client.mark_notifications_as_read take a list of Notification objects or notification IDs to mark them all at the same time and only with one API call.

    Checklist

    • [x] If classes/methods/attributes were added/changed then they have been documented and tested.
      • [x] I have updated the documentation to reflect the changes.
      • [x] I have updated the tests to support the changes.
    • [ ] This PR fixes an issue.
    • [x] This PR adds something new (e.g. new class, method or attribute).
    • [ ] This PR is a breaking change (e.g. classes, methods, attributes or parameters removed/renamed)
    • [ ] This PR is not a code change (e.g. documentation, README, ...)
    • [x] The code follows the style guidelines and passes linting and testing.
    enhancement 
    opened by takos22 0
  • [RELEASE] 1.3.0

    [RELEASE] 1.3.0

    Version 1.3.0

    Added

    • Client.get_unread_notifications.
    • Client.get_read_notifications.
    • PartialCodinGamer.
    • Notification.codingamer.
    • Notification.seen, Notification.seen_date, Notification.read and Notification.read_date.
    • NotificationType and NotificationTypeGroup enums for Notification.type and Notification.type_group.
    • NotificationData and subclasses.

    Changed

    • Deprecated Notification.creation_time in favor of Notification.date

    Removed

    • Removed Notification._raw.
    release 
    opened by takos22 0
  • [RELEASE] v1.2.0

    [RELEASE] v1.2.0

    Version 1.2.0

    Added

    • Client.request to make requests to CodinGame API services that aren't implemented yet in the library. Resolves #7.

    Removed

    • codingame.endpoints submodule.
    release 
    opened by takos22 0
  • [FR] Use ID of the logged in user for follower endpoints

    [FR] Use ID of the logged in user for follower endpoints

    Related problem

    Only the followers and follows of the logged in CodinGamer can be accessed with CodinGamer.get_followers and CodinGamer.get_followed.

    Wanted solution

    Being able to access anyone's followers and follows, the 2nd parameter to the API in HTTPClient.get_codingamer_followers and HTTPClient.get_codingamer_following need to be updated to self.state.codingamer.id

        def get_codingamer_followers(self, id: int) -> typing.List[Follower]:
            # TODO fix this to use [id, logged_in.id, None]
            return self.request("CodinGamer", "findFollowers", [id, id, None])
    
        def get_codingamer_following(self, id: int) -> typing.List[Following]:
            # TODO fix this to use [id, logged_in.id]
            return self.request("CodinGamer", "findFollowing", [id, id])
    

    Considered alternatives

    Using CodinGamer.get_followers_ids and CodinGamer.get_followed_ids, but that would be slower as it requires way more requests to the API.

    Additional context

    None

    enhancement good first issue todo 
    opened by github-actions[bot] 0
  • [FR] Add ConnectionState.current_language

    [FR] Add ConnectionState.current_language

    Related problem

    When dealing with endpoint that give a title/description in both French and English, displaying both is a bit bulky, so having the ConnectionState know its current language would help displaying only the message in the correct language.

    Wanted solution

    Adding a ConnectionState.current_language attribute/property to display texts in the right language.

    Considered alternatives

    None

    Additional context

    None

    enhancement good first issue todo 
    opened by github-actions[bot] 0
Releases(v1.4.0)
  • v1.4.0(Aug 18, 2022)

    Version 1.4.0

    Changelog

    Added

    • Client.mark_notifications_as_seen and Client.mark_notifications_as_read.
    • Notification.mark_as_seen and Notification.mark_as_read.

    Removed

    • Removed support for python 3.6 as it has reached its end of life. For more information, see PEP 494.

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Jun 20, 2022)

    Version 1.3.0

    Changelog

    Added

    • Client.get_unread_notifications.
    • Client.get_read_notifications.
    • PartialCodinGamer.
    • Notification.codingamer.
    • Notification.seen, Notification.seen_date, Notification.read and Notification.read_date.
    • NotificationType and NotificationTypeGroup enums for Notification.type and Notification.type_group.
    • NotificationData and subclasses.

    Changed

    • Deprecated Notification.creation_time in favor of Notification.date

    Removed

    • Removed Notification._raw.

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.2.4(Jun 16, 2022)

    Version 1.2.4

    Changelog

    Fixed

    • CodinGamer.get_followers and CodinGamer.get_followed now work while being logged in as any user, not just as the user you want to get the followers of.

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.2.3(Nov 7, 2021)

    Version 1.2.3

    Changelog

    Fixed

    • ImportError of codingame.types submodule when importing codingame, the 1.2.1 and 1.2.2 fixes don't work.

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.2.2(Nov 6, 2021)

    Version 1.2.2

    Changelog

    Fixed

    • ImportError of codingame.types submodule when importing codingame.

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Nov 6, 2021)

    Version 1.2.1

    Changelog

    Fixed

    • ModuleNotFoundError of codingame.types submodule when importing codingame.

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Nov 4, 2021)

    Version 1.2.0

    Changelog

    Added

    • Client.request to make requests to CodinGame API services that aren't implemented yet in the library.

    Removed

    • codingame.endpoints submodule.

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Nov 1, 2021)

    Version 1.1.0

    Changelog

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Jul 12, 2021)

    Version 1.0.1

    Changelog

    • Add CodinGamer.profile_url

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jul 11, 2021)

    Version 1.0

    Changelog

    • Add support for asynchronous client with Client(is_async=True), see the docs.

    • Add support for context managers:

      # synchronous
      with Client() as client:
          client.get_global_leaderboard()
      
      # asynchronous
      async with Client(is_async=True) as client:
          await client.get_global_leaderboard()
      
    • Remove properties like CodinGamer.followers in favor of methods like CodinGamer.get_followers to better differentiate API calls and to make it compatible with async API calls. Here's a list of all of the changed ones:

      • Client.language_ids -> Client.get_language_ids
      • Client.unseen_notifications -> Client.get_unseen_notifications
      • CodinGamer.followers -> CodinGamer.get_followers
      • CodinGamer.followers_ids -> CodinGamer.get_followers_ids
      • CodinGamer.following -> CodinGamer.get_followed
      • CodinGamer.following_ids -> CodinGamer.get_followed_ids
      • CodinGamer.clash_of_code_rank -> CodinGamer.get_clash_of_code_rank
    • Add more exceptions: LoginError regroups all the exceptions related to login: LoginRequired, EmailRequired, MalformedEmail, PasswordRequired, EmailNotLinked and IncorrectPassword. And NotFound regroups CodinGamerNotFound, ClashOfCodeNotFound, ChallengeNotFound and PuzzleNotFound.

    • Make all attributes of CodinGame models read-only.

    • Add ChallengeLeaderboard.has_leagues and PuzzleLeaderboard.has_leagues.

    • Add Notification._raw.

    • Change ClashOfCode.time_before_start and ClashOfCode.time_before_end from float to datetime.timedelta.

    • Remove argument type validation, not my fault if you can't read the docs.

    • Rewrite the way the client works to implement a class to manage the connection state and separate the Client that the user uses from the HTTP client that interacts with the API.

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io

    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Jun 19, 2021)

    Version 0.4

    Changelog

    • Add support for leaderboards in Client.get_global_leaderboard, Client.get_challenge_leaderboard and Client.get_puzzle_leaderboard. See docs.
    • Bug fixes

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io/en/latest/index.html

    Source code(tar.gz)
    Source code(zip)
  • v0.3.5(Dec 10, 2020)

    Version 0.3.5

    Changelog

    • Add support for ids in Client.get_codingamer.

      import codingame
      client = codingame.Client()
      codingamer = client.get_codingamer(3877165)
      print(codingamer.pseudo)
      
    • Add CodinGamer.followers_ids and CodinGamer.following_ids to get information without logging in.

      import codingame
      client = codingame.Client()
      codingamer = client.get_codingamer(3877165)
      print(codingamer.followers_ids)
      print(codingamer.following_ids)
      
    • Add CodinGamer.clash_of_code_rank to get the CodinGamer’s ranking in Clash of Codes.

      import codingame
      client = codingame.Client()
      codingamer = client.get_codingamer(3877165)
      print(codingamer.clash_of_code_rank)
      
    • Bug fixes

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io/en/latest/index.html

    Source code(tar.gz)
    Source code(zip)
  • v.0.3.4(Dec 1, 2020)

  • v0.3.3(Nov 6, 2020)

    Version 0.3.3

    Changelog

    Add support for usernames in Client.get_codingamer.

    import codingame
    client = codingame.Client()
    codingamer= client.get_codingamer("takos")
    print(codingamer.pseudo)
    

    Bug fixes

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io/en/latest/index.html

    Source code(tar.gz)
    Source code(zip)
  • v0.3.2(Sep 23, 2020)

    Version 0.3.2

    Changelog

    Add Client.get_pending_clash_of_code that returns a pending public Clash of Code.

    import codingame
    client = codingame.Client()
    clash_of_code = client.get_pending_clash_of_code()
    print(clash_of_code.join_url)
    

    Bug fixes

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io/en/latest/index.html

    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(Sep 20, 2020)

    Version 0.3.1

    Changelog

    Add Client.notifications that returns a generator of all the notifications. Note: you need to login for the notifications.

    import codingame
    client = codingame.Client("email", "password")
    notifications = [n for n in client.notifications]
    

    Bug fixes

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io/en/latest/index.html

    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Sep 20, 2020)

    Version 0.3.0

    Changelog

    Add login with Client:

    import codingame
    # like this
    client = codingame.Client()
    client.login("email", "password")
    # or like this
    client = codingame.Client("email", "password")
    # then you can get the loged in user with like this
    if client.logged_in:
        user = client.codingamer
    

    Add list of language ids accessible with Client().language_ids Add CodinGamer.followers and CodinGamer.following for the currently logged in CodinGamer Bug fixes

    Update

    Update the module by doing pip install codingame --upgrade

    Links

    PyPi: https://pypi.org/project/codingame Docs: https://codingame.readthedocs.io/en/latest/index.html

    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Sep 16, 2020)

  • v0.2.0(Sep 13, 2020)

    Version 0.2.0

    Changelog

    Add Client.get_clash_of_code() and data classes for it (ClashOfCode and Player)

    Update

    Update the module by doing pip install codingame --upgrade

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Sep 12, 2020)

Owner
Takos
Python developer and freelancer
Takos
tetrados is a tool to generate a density of states using the linear tetrahedron method from a band structure.

tetrados tetrados is a tool to generate a density of states using the linear tetrahedron method from a band structure. Currently, only VASP calculatio

Alex Ganose 1 Dec 21, 2021
Learning objective: Use React.js, Axios, and CSS to build a responsive YouTube clone app

Learning objective: Use React.js, Axios, and CSS to build a responsive YouTube clone app to search for YouTube videos, channels, playlists, and live events via wrapper around Google YouTube API.

Dillon 0 May 03, 2022
🔵Open many google dorks in a fasted way

Dorkinho 🔵 The author is not responsible for misuse of the tool, use it in good practices like Pentest and CTF OSINT challenges. Dorkinho is a script

SidHawks 2 May 02, 2022
Xbps-install wrapper written in Python that doesn't care about case sensitiveness and package versions

xbi Xbps-install wrapper written in Python that doesn't care about case sensitiveness and package versions. Description This Python script can be easi

Emanuele Sabato 5 Apr 11, 2022
python scripts and other files to generate induction encoder PCBs in Kicad

induction_encoder python scripts and other files to generate induction encoder PCBs in Kicad Targeting the Renesas IPS2200 encoder chips.

Taylor Alexander 8 Feb 16, 2022
Semester Project on Signal Processing @CS UCU 2021

Blur Detection with Haar Wavelet Transform Requirements Python3 opencv-python PyWavelets Install these using the following command: $ pip install -r r

ButynetsD 2 Oct 15, 2022
A repository of study materials related to Think Python 2nd Edition by Allen B. Downey. More information about the book can be found here: https://greenteapress.com/wp/think-python-2e/

Intro-To-Python This content is based on the book Think Python 2nd Edition by Allen B. Downey. More information about the book can be found here: http

Brent Eskridge 63 Jan 07, 2023
This is a working model for which I have used python.

Jarvis_voiceAssistance This is a working model for which I have used python. This model can: 1)Play a video or song on youtube. 2)Tell us time. 3)Tell

Hardik Jain 1 Jan 30, 2022
A python script to make leaderboards using a CSV with the runners name, IDs and Flag Emojis

SrcLbMaker A python script to make speedrun.com global leaderboards. Installation You need python 3.6 or higher. First, go to the folder where you wan

2 Jul 25, 2022
Runnable Python demo of ArtLine

artline-demo How to run? pip3 install -r requirements.txt python3 app.py How to use? Run the Flask app Open localhost:5000 in browser Select an image(

Jiang Wenjian 134 Jul 29, 2022
Catalogue CRUD Application

This Python program creates a relational SQL database hosted on the Snowflake platform, then opens a CRUD GUI to manipulate and view the data. In this application, it is used as a book catalogue. CUR

0 Dec 13, 2022
RecurrentArchitectures - See the accompanying blog post

Why this? What is the goal? The goal of this repository is to write all the recurrent architectures from scratch in tensorflow for learning purposes.

Debajyoti Datta 9 Feb 06, 2022
Telegram bot for Urban Dictionary.

Urban Dictionary Bot @TheUrbanDictBot A star ⭐ from you means a lot to us! Telegram bot for Urban Dictionary. Usage Deploy to Heroku Tap on above butt

Stark Bots 17 Nov 24, 2022
Birthday program - A program that lookups a birthday txt file and compares to the current date to check for birthdays

Birthday Program This is a program that lookups a birthday txt file and compares

Daquiver 4 Feb 02, 2022
NUM Alert - A work focus aid created for the Hack the Job hackathon

Contributors: Uladzislau Kaparykha, Amanda Hahn, Nicholas Waller Hackathon Team Name: N.U.M General Purpose: The general purpose of this program is to

Amanda Hahn 1 Jan 10, 2022
Translation patch for Hololive ERROR

Translation patch for Hololive ERROR How do I install the patch? Grab the Translation.zip file for the latest version from the releases page, and unzi

18 Jul 20, 2022
script to analyze EQ decay using python

pyq_decay script to analyze EQ decay using python PyQ Decay ver 1.0 A pythonic script to analyze EQ aftershock decay using method of Omori (1894), Mog

1 Nov 04, 2021
This directory gathers the tools developed by the Data Sourcing Working Group

BigScience Data Sourcing Code This directory gathers the tools developed by the Data Sourcing Working Group First Sourcing Sprint: October 2021 The co

BigScience Workshop 27 Nov 04, 2022
Change ACLs for QNAP LXD unprivileged container.

qnaplxdunpriv If Advanced Folder Permissions is enabled in QNAP NAS, unprivileged LXD containers won't start. qnaplxdunpriv changes ACLs of some Conta

1 Jan 10, 2022
Flight Reservation App With Python

Flight Reservation App With Python

victor-h. 1 Nov 21, 2021