Skip to content

Commit 1a2159b

Browse files
authored
2.0.0 version (#6)
* Rewrote comments * Added link to wiki from README * Now using POST requests to avoid 413 HTTP error * Creating Release on the tag * Updated LICENSE * Added task rating to get_tags methods * Edited setup.py * Changed LICENSE to GPLv3 * Fixed version parsing * Now all methods return objects * Added LICENSE head * Updated README * Updated Python version * Added checking for code style workflow * Rewrote gitignore, added dependencies * Updated README * Sorted imports in tests * Added information about types and methods
1 parent 1b53aac commit 1a2159b

14 files changed

+1817
-68
lines changed

.github/workflows/codestyle.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Check code style
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
build:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v2
16+
- name: Set up Python
17+
uses: actions/setup-python@v2
18+
with:
19+
python-version: "3.9"
20+
- name: Install dependencies
21+
run: |
22+
python -m pip install --upgrade pip
23+
pip install -r requirements.txt
24+
- name: Lint with black
25+
run: |
26+
pip install black
27+
black .

.github/workflows/publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ jobs:
1111
runs-on: ubuntu-latest
1212
steps:
1313
- uses: actions/checkout@master
14-
- name: Set up Python 3.8
14+
- name: Set up Python 3.9
1515
uses: actions/setup-python@v1
1616
with:
17-
python-version: 3.8
17+
python-version: 3.9
1818
- name: Install twine
1919
run: >-
2020
pip install twine

.gitignore

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
dist/
2-
build/
3-
CodeforcesApiPy.egg-info
4-
tests/conf.py
5-
.pylintrc
6-
__pycache__/
1+
/*
2+
3+
!/.gitignore
4+
!/setup.py
5+
!/setup.cfg
6+
!/LICENSE
7+
!/*.md
8+
!/requirements.txt
9+
!tests/
10+
tests/*
11+
!tests/main.py
12+
!tests/conf.py.template
13+
!/codeforces_api
14+
!/.github

LICENSE

Lines changed: 674 additions & 21 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Codeforces API
66
[![Publish to PyPI and TestPyPI](https://github.com/VadVergasov/CodeforcesApiPy/workflows/Publish%20to%20PyPI%20and%20TestPyPI/badge.svg?branch=master)](https://pypi.org/project/CodeforcesApiPy/)
77
[![Generate wiki](https://github.com/VadVergasov/CodeforcesApiPy/workflows/Generate%20wiki/badge.svg?branch=master)](https://github.com/VadVergasov/CodeforcesApiPy/wiki)
88
[![Downloads](https://static.pepy.tech/personalized-badge/codeforcesapipy?period=total&units=international_system&left_color=black&right_color=blue&left_text=Total%20downloads)](https://pepy.tech/project/codeforcesapipy)
9+
![Codestyle](https://img.shields.io/badge/code%20style-black-000000.svg)
910
==========
1011

1112
Installing
@@ -31,14 +32,30 @@ Using
3132
```python
3233
import codeforces_api
3334

34-
cf_api = codeforces_api.CodeforcesApi(api_key, secret) #Authorized access to api.
35-
anonim_cf_api = codeforces_api.CodeforcesApi() #Unauthorized access to api.
35+
cf_api = codeforces_api.CodeforcesApi(api_key, secret) # Authorized access to api.
36+
anonim_cf_api = codeforces_api.CodeforcesApi() # Unauthorized access to api.
3637

37-
parser = codeforces_api.CodeforcesParser() #Create parser.
38+
parser = codeforces_api.CodeforcesParser() # Create parser.
3839
```
3940

41+
Types
42+
-------
43+
44+
All types are defined in types.py. They are all completely in line with the [Codeforces API's definition of the types](https://codeforces.com/apiHelp/objects)
45+
46+
Methods
47+
-------
48+
49+
All [API methods](https://codeforces.com/apiHelp/methods) are located in the CodeforcesAPI class. They are renamed to follow common Python naming conventions. E.g. `contest.hacks` is renamed to `contest_hacks` and `user.actions` to `user_actions`.
50+
51+
Transferring to 2 version
52+
--------
53+
54+
In the second version, all objects are represented as a class, so if you want to get a handle of the user you need to do like this: user.handle. You can read about all fields on [Codeforces API objects](https://codeforces.com/apiHelp/objects).
55+
4056
Wiki
4157
--------
58+
4259
Here is link to the [wiki](https://github.com/VadVergasov/CodeforcesApiPy/wiki) for more details.
4360

4461
Examples

codeforces_api/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
"""
22
Importing all classes from modules
3+
Copyright (C) 2021 Vadim Vergasov
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program. If not, see <https://www.gnu.org/licenses/>.
316
"""
417
__all__ = ["CodeforcesApi", "CodeforcesApiRequestMaker", "CodeforcesParser"]
518
from codeforces_api.api_requests import CodeforcesApi
619
from codeforces_api.api_request_maker import CodeforcesApiRequestMaker
720
from codeforces_api.parse_methods import CodeforcesParser
21+
from codeforces_api.types import *

codeforces_api/api_request_maker.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
"""
22
Class for generating request URLs, which includes working with random, unpacking parameters, calculating hashes.
3+
Copyright (C) 2021 Vadim Vergasov
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program. If not, see <https://www.gnu.org/licenses/>.
316
"""
417
import random
518
import time

codeforces_api/api_requests.py

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
11
"""
22
The main class for the API requests.
3+
Copyright (C) 2021 Vadim Vergasov
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program. If not, see <https://www.gnu.org/licenses/>.
316
"""
417
import requests
518

619
from codeforces_api.api_request_maker import CodeforcesApiRequestMaker
20+
from codeforces_api.types import *
721

822

923
class CodeforcesApi(CodeforcesApiRequestMaker):
@@ -43,18 +57,21 @@ def blog_entry_comments(self, blog_entry_id):
4357
4458
Returns parsed response from codeforces.com.
4559
"""
46-
return self._make_request(
47-
"blogEntry.comments", **{"blogEntryId": str(blog_entry_id)}
48-
)
60+
return [
61+
Comment.de_json(comment)
62+
for comment in self._make_request(
63+
"blogEntry.comments", **{"blogEntryId": str(blog_entry_id)}
64+
)
65+
]
4966

5067
def blog_entry_view(self, blog_entry_id):
5168
"""
5269
Get blogEntry.view for blog, blog_entry_id required.
5370
5471
Returns parsed response from codeforces.com.
5572
"""
56-
return self._make_request(
57-
"blogEntry.view", **{"blogEntryId": str(blog_entry_id)}
73+
return BlogEntry.de_json(
74+
self._make_request("blogEntry.view", **{"blogEntryId": str(blog_entry_id)})
5875
)
5976

6077
def contest_hacks(self, contest_id):
@@ -63,25 +80,38 @@ def contest_hacks(self, contest_id):
6380
6481
Returns parsed response from codeforces.com.
6582
"""
66-
return self._make_request("contest.hacks", **{"contestId": str(contest_id)})
83+
return [
84+
Hack.de_json(hack)
85+
for hack in self._make_request(
86+
"contest.hacks", **{"contestId": str(contest_id)}
87+
)
88+
]
6789

6890
def contest_list(self, gym=False):
6991
"""
7092
Get all contests you can get all gym by gym parameter.
7193
7294
Returns parsed response from codeforces.com
7395
"""
74-
return self._make_request("contest.list", **{"gym": str(gym).lower()})
96+
return [
97+
Contest.de_json(contest)
98+
for contest in self._make_request(
99+
"contest.list", **{"gym": str(gym).lower()}
100+
)
101+
]
75102

76103
def contest_rating_changes(self, contest_id):
77104
"""
78105
Get contest.ratingChanges for the contest, contest_id required.
79106
80107
Returns parsed response from codeforces.com.
81108
"""
82-
return self._make_request(
83-
"contest.ratingChanges", **{"contestId": str(contest_id)}
84-
)
109+
return [
110+
RatingChange.de_json(rating_change)
111+
for rating_change in self._make_request(
112+
"contest.ratingChanges", **{"contestId": str(contest_id)}
113+
)
114+
]
85115

86116
def contest_standings(
87117
self,
@@ -131,7 +161,17 @@ def contest_standings(
131161
parameters["handles"] = handles_str
132162
if room != -1:
133163
parameters["room"] = str(room)
134-
return self._make_request("contest.standings", **parameters)
164+
response = self._make_request("contest.standings", **parameters)
165+
result = {
166+
"contest": Contest.de_json(response["contest"]),
167+
"problems": [],
168+
"rows": [],
169+
}
170+
for problem in response["problems"]:
171+
result["problems"].append(Problem.de_json(problem))
172+
for row in response["rows"]:
173+
result["rows"].append(RanklistRow.de_json(row))
174+
return result
135175

136176
def contest_status(self, contest_id, handle="", start=-1, count=-1):
137177
"""
@@ -154,7 +194,10 @@ def contest_status(self, contest_id, handle="", start=-1, count=-1):
154194
parameters["start"] = str(start)
155195
if count != -1:
156196
parameters["count"] = str(count)
157-
return self._make_request("contest.status", **parameters)
197+
return [
198+
Submission.de_json(submission)
199+
for submission in self._make_request("contest.status", **parameters)
200+
]
158201

159202
def problemset_problems(self, tags=[""], problemset_name=""):
160203
"""
@@ -173,7 +216,15 @@ def problemset_problems(self, tags=[""], problemset_name=""):
173216
parameters["tags"] = tags
174217
if problemset_name != "":
175218
parameters["problemsetName"] = problemset_name
176-
return self._make_request("problemset.problems", **parameters)
219+
result = {"problems": [], "problem_statistics": []}
220+
response = self._make_request("problemset.problems", **parameters)
221+
for problem in response["problems"]:
222+
result["problems"].append(Problem.de_json(problem))
223+
for problem_statistic in response["problemStatistics"]:
224+
result["problem_statistics"].append(
225+
ProblemStatistic.de_json(problem_statistic)
226+
)
227+
return result
177228

178229
def problemset_recent_status(self, count, problemset_name=""):
179230
"""
@@ -194,7 +245,12 @@ def problemset_recent_status(self, count, problemset_name=""):
194245
}
195246
if problemset_name != "":
196247
parameters["problemsetName"] = problemset_name
197-
return self._make_request("problemset.recentStatus", **parameters)
248+
return [
249+
Submission.de_json(submission)
250+
for submission in self._make_request(
251+
"problemset.recentStatus", **parameters
252+
)
253+
]
198254

199255
def recent_actions(self, max_count=100):
200256
"""
@@ -208,7 +264,12 @@ def recent_actions(self, max_count=100):
208264
"""
209265
if max_count > 100:
210266
raise OverflowError("Max_count should be less or equal to 1000")
211-
return self._make_request("recentActions", **{"maxCount": str(max_count)})
267+
return [
268+
RecentAction.de_json(recent_action)
269+
for recent_action in self._make_request(
270+
"recentActions", **{"maxCount": str(max_count)}
271+
)
272+
]
212273

213274
def user_blog_entries(self, handle):
214275
"""
@@ -220,7 +281,12 @@ def user_blog_entries(self, handle):
220281
"""
221282
if handle == "":
222283
raise TypeError("Handle should not be empty")
223-
return self._make_request("user.blogEntries", **{"handle": str(handle)})
284+
return [
285+
BlogEntry.de_json(blog_entry)
286+
for blog_entry in self._make_request(
287+
"user.blogEntries", **{"handle": str(handle)}
288+
)
289+
]
224290

225291
def user_friends(self, only_online=False):
226292
"""
@@ -253,7 +319,10 @@ def user_info(self, handles):
253319
handles_str = ""
254320
for handle in handles:
255321
handles_str += str(handle) + ";"
256-
return self._make_request("user.info", **{"handles": handles_str})
322+
return [
323+
User.de_json(user)
324+
for user in self._make_request("user.info", **{"handles": handles_str})
325+
]
257326

258327
def user_rated_list(self, active_only=False):
259328
"""
@@ -263,9 +332,12 @@ def user_rated_list(self, active_only=False):
263332
264333
Returns parsed response from codeforces.com.
265334
"""
266-
return self._make_request(
267-
"user.ratedList", **{"activeOnly": str(active_only).lower()}
268-
)
335+
return [
336+
User.de_json(user)
337+
for user in self._make_request(
338+
"user.ratedList", **{"activeOnly": str(active_only).lower()}
339+
)
340+
]
269341

270342
def user_rating(self, handle):
271343
"""
@@ -275,7 +347,12 @@ def user_rating(self, handle):
275347
276348
Returns parsed response from codeforces.com.
277349
"""
278-
return self._make_request("user.rating", **{"handle": str(handle)})
350+
return [
351+
RatingChange.de_json(rating_change)
352+
for rating_change in self._make_request(
353+
"user.rating", **{"handle": str(handle)}
354+
)
355+
]
279356

280357
def user_status(self, handle, start=-1, count=-1):
281358
"""
@@ -296,4 +373,8 @@ def user_status(self, handle, start=-1, count=-1):
296373
parameters["from"] = str(start)
297374
if count != -1:
298375
parameters["count"] = str(count)
299-
return self._make_request("user.status", **parameters)
376+
return [
377+
Submission.de_json(submission)
378+
for submission in self._make_request("user.status", **parameters)
379+
]
380+

0 commit comments

Comments
 (0)