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
Google Scholar App Using Python

Google Scholar App Watch the tutorial video How to build a Google Scholar App | Streamlit #30 Demo Launch the web app: Reproducing this web app To rec

Chanin Nantasenamat 4 Jun 05, 2022
A redesign of our previous Python World Cup, aiming to simulate the 2022 World Cup all the way from the qualifiers

A redesign of our previous Python World Cup, aiming to simulate the 2022 World Cup all the way from the qualifiers. This new version is designed to be more compact and more efficient and will reflect

Sam Counsell 1 Jan 07, 2022
A collection of design patterns and idioms in Python (With tests!).

Python Patterns Help the project financially: Donate: https://smartlegion.github.io/donate/ Yandex Money: https://yoomoney.ru/to/4100115206129186 PayP

5 Sep 12, 2021
Cairo-math-64x61 - Fixed point 64.61 math library for Cairo / Starknet

Cairo Math 64x61 A fixed point 64.61 math library for Cairo & Starknet Signed 64

Influence 63 Dec 05, 2022
frida-based ceserver. iOS analysis is possible with Cheat Engine.

frida-ceserver frida-based ceserver. iOS analysis is possible with Cheat Engine. Original by Dark Byte. Usage Install frida on iOS. python main.py Cyd

KenjiroIchise 89 Jan 08, 2023
Python project setup, updater, and launcher

pyLaunch Python project setup, updater, and launcher Purpose: Increase project productivity and provide features easily. Once installed as a git submo

DAAV, LLC 1 Jan 07, 2022
A multi-platform fuzzer for poking at userland binaries and servers

litefuzz A multi-platform fuzzer for poking at userland binaries and servers litefuzz intro why how it works what it does what it doesn't do support p

52 Nov 18, 2022
flake8 plugin which forbids match statements (PEP 634)

flake8-match flake8 plugin which forbids match statements (PEP 634)

Anthony Sottile 25 Nov 01, 2022
LSO, also known as Linux Swap Operator, is a software with both GUI and terminal versions that you can manage the Swap area for Linux operating systems.

LSO - Linux Swap Operator Türkçe - LSO Nedir? LSO, diğer adıyla Linux Swap Operator Linux işletim sistemleri için Swap alanını yönetebileceğiniz hem G

Eren İnce 4 Feb 09, 2022
Security-related flags and options for C compilers

Getting the maximum of your C compiler, for security

135 Nov 11, 2022
An alternative app for core Armoury Crate functions.

NoROG DISCLAIMER: Use at your own risk. This is alpha-quality software. It has not been extensively tested, though I personally run it daily on my lap

12 Nov 29, 2022
Number calculator application.

Number calculator application.

Michael J Bailey 3 Oct 08, 2021
Multiperiod Reports by Month/Quarter/Year in Beancount.

Multiperiod Reports by Month/Quarter/Year in Beancount. Plotting income and expenses over time. Treemap plot of expenses.

Altynbek Isabekov 16 Aug 13, 2022
Helper to organize your windows on your desktop.

The script of positionsing windows on the screen. How does it work? Select your window to move/res

Andrii D. 1 Jul 09, 2021
For Tok-k passages that have passed through the Bi-Encoder Retrival, ReRank is performed using CrossEncoder.

Cross-Encoder-with-Bi-Encoder For Tok-k passages that have passed through the Bi-Encoder Retrival, ReRank is performed using CrossEncoder. Data Data u

7 Feb 09, 2022
Low-level Python CFFI Bindings for Argon2

Low-level Python CFFI Bindings for Argon2 argon2-cffi-bindings provides low-level CFFI bindings to the Argon2 password hashing algorithm including a v

Hynek Schlawack 4 Dec 15, 2022
Sync SiYuanNote & Yuque.

SiyuanYuque Sync SiYuanNote & Yuque. Install Use pip to install. pip install SiyuanYuque Execute like this: python -m SiyuanYuque Remember to create a

Clouder 23 Nov 25, 2022
Fastest python library for making asynchronous group requests.

FGrequests: Fastest Asynchronous Group Requests Installation Install using pip: pip install fgrequests Documentation Pretty easy to use. import fgrequ

Farid Chowdhury 14 Nov 22, 2022
A collection of full-stack resources for programmers.

A collection of full-stack resources for programmers.

Charles-Axel Dein 22.3k Dec 30, 2022
Paprika is a python library that reduces boilerplate. Heavily inspired by Project Lombok.

Image courtesy of Anna Quaglia (Photographer) Paprika Paprika is a python library that reduces boilerplate. It is heavily inspired by Project Lombok.

Rayan Hatout 55 Dec 26, 2022