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
Find the remote website version based on a git repository

versionshaker Versionshaker is a tool to find a remote website version based on a git repository This tool will help you to find the website version o

Orange Cyberdefense 110 Oct 23, 2022
Simple dotfile pre-processor with a per-file configuration

ix (eeks) Simple dotfile pre-processor with a per-file configuration Summary (TL;DR) ix.py is all you need config is an ini file. files to be processe

Poly 12 Dec 16, 2021
An implementation of Ray Tracing in One Weekend using Taichi

又一个Taichi语言的Ray Tracer 背景简介 这个Ray Tracer基本上是照搬了Peter Shirley的第一本小书Ray Tracing in One Weekend,在我写的时候参考的是Version 3.2.3这个版本。应该比其他中文博客删改了不少内容。果然Peter Shir

张皓 30 Nov 21, 2022
Open-source data observability for modern data teams

Use cases Monitor your data warehouse in minutes: Data anomalies monitoring as dbt tests Data lineage made simple, reliable, and automated dbt operati

889 Jan 01, 2023
[Cython] Vs [Python] Which one is Faster ?

[Cython] Vs [Python] ? Attractive Contrast :) Mission : Which one is Faster ? Comparing of Execution runtime for [Selection_sort] with Time Complexity

baqer marani 1 Dec 05, 2021
A common, beautiful interface to tabular data, no matter the format

rows No matter in which format your tabular data is: rows will import it, automatically detect types and give you high-level Python objects so you can

Álvaro Justen 834 Jan 03, 2023
Provides guideline on how to configure pre-commit hooks in your own python project

Pre-commit Configuration Guide The main aim of this repository is to act as a guide on how to configure the pre-commit hooks in your existing python p

Faraz Ahmed Khan 2 Mar 31, 2022
Simple Python script I use to manage and build my Reflux themes.

Simple Python script I use to manage and build my Reflux themes. Built for personal use, but anyone can easily fork and tweak to suit thier needs.

Ire 3 Jan 25, 2022
Node editor view image node

A Blender addon to quickly view images from image nodes in Blender's image viewer.

5 Nov 27, 2022
A numbers check python package

A numbers check python package

Fayas Noushad 3 Nov 28, 2021
PyPI package for scaffolding out code for decision tree models that can learn to find relationships between the attributes of an object.

Decision Tree Writer This package allows you to train a binary classification decision tree on a list of labeled dictionaries or class instances, and

2 Apr 23, 2022
Hopefully the the next-generation backend server of bgm.tv

Hopefully the the next-generation backend server of bgm.tv

Bangumi 475 Jan 01, 2023
A web project to control the daily life budget planing

Budget Planning - API In this repo there's only the API and Back-End of the this project. Install and run the project # install virtualenv --python=py

Leonardo Da Vinci 1 Oct 24, 2021
Home Assistant integration for spanish electrical data providers (e.g., datadis)

homeassistant-edata Esta integración para Home Assistant te permite seguir de un vistazo tus consumos y máximas potencias alcanzadas. Para ello, se ap

VMG 163 Jan 05, 2023
Get a list of content on your Netflix My List that is expiring in the next month or two.

Netflix My List Expiring Movies Annoyed at Netflix for taking away your movies? Now you don't have to be! Installation instructions Install selenium C

24 Aug 06, 2022
A maubot plugin to invite users to Matrix rooms according to LDAP groups

LDAP Inviter Bot This is a maubot plugin that invites users to Matrix rooms according to their membership in LDAP groups.

David Mehren 14 Dec 09, 2022
Repls goes to sleep due to inactivity, but to keep it awake, simply host a webserver and ping it.

Repls goes to sleep due to inactivity, but to keep it awake, simply host a webserver and ping it. This repo will help you make a webserver with a bit of console controls.

2 Mar 01, 2022
Utility to play with ADCS, allows to request tickets and collect information about related objects

certi Utility to play with ADCS, allows to request tickets and collect information about related objects. Basically, it's the impacket copy of Certify

Eloy 185 Dec 29, 2022
Automation in socks label validation

This is a project for socks card label validation where the socks card is validated comparing with the correct socks card whose coordinates are stored in the database. When the test socks card is com

1 Jan 19, 2022
A bot to use in a pump & dump event

A bot to use in a pump & dump event on Binance.com. Please note the bot is in heavy devleopment currently so be aware of errors. If you experience err

Freddie Jonas 189 Dec 24, 2022