ctftime-api 0.1.5__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/.github/workflows/codeql.yml +1 -1
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/.github/workflows/docs.yml +2 -2
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/.github/workflows/publish.yml +3 -3
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/.github/workflows/test.yml +1 -1
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/PKG-INFO +8 -11
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/ctftime_api/client.py +12 -14
- ctftime_api-0.2.0/ctftime_api/models/country.py +259 -0
- ctftime_api-0.2.0/ctftime_api/models/duration.py +12 -0
- ctftime_api-0.2.0/ctftime_api/models/event.py +53 -0
- ctftime_api-0.2.0/ctftime_api/models/rating.py +16 -0
- ctftime_api-0.2.0/ctftime_api/models/team.py +61 -0
- ctftime_api-0.2.0/ctftime_api/models/vote.py +16 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/pyproject.toml +10 -12
- ctftime_api-0.2.0/tests/__init__.py +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/tests/test_client.py +16 -15
- ctftime_api-0.2.0/uv.lock +1709 -0
- ctftime_api-0.1.5/ctftime_api/models/duration.py +0 -8
- ctftime_api-0.1.5/ctftime_api/models/event.py +0 -42
- ctftime_api-0.1.5/ctftime_api/models/rating.py +0 -12
- ctftime_api-0.1.5/ctftime_api/models/team.py +0 -50
- ctftime_api-0.1.5/ctftime_api/models/vote.py +0 -13
- ctftime_api-0.1.5/uv.lock +0 -1452
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/.github/dependabot.yml +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/.github/workflows/cleanup.yml +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/.gitignore +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/LICENSE +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/README.md +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/ctftime_api/__init__.py +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/ctftime_api/models/__init__.py +0 -0
- /ctftime_api-0.1.5/tests/__init__.py → /ctftime_api-0.2.0/ctftime_api/py.typed +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/api/client.md +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/api/models/duration.md +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/api/models/event.md +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/api/models/rating.md +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/api/models/team.md +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/api/models/vote.md +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/assets/fonts/inter/italic.woff2 +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/assets/fonts/inter/italic_ext.woff2 +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/assets/fonts/inter/normal.woff2 +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/assets/fonts/inter/normal_ext.woff2 +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/assets/fonts/jetbrains_mono/normal.woff2 +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/assets/fonts/jetbrains_mono/normal_ext.woff2 +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/index.md +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/docs/stylesheets/fonts.css +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/examples/test_methods/main.py +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/justfile +0 -0
- {ctftime_api-0.1.5 → ctftime_api-0.2.0}/mkdocs.yml +0 -0
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
23
|
- name: Checkout code
|
|
24
|
-
uses: actions/checkout@
|
|
24
|
+
uses: actions/checkout@v5
|
|
25
25
|
|
|
26
26
|
- name: Install uv
|
|
27
27
|
uses: astral-sh/setup-uv@v6
|
|
@@ -46,7 +46,7 @@ jobs:
|
|
|
46
46
|
- name: Upload docs
|
|
47
47
|
if: ${{ (github.event.inputs.upload || github.ref_type == 'tag') }}
|
|
48
48
|
id: deployment
|
|
49
|
-
uses: actions/upload-pages-artifact@
|
|
49
|
+
uses: actions/upload-pages-artifact@v4
|
|
50
50
|
with:
|
|
51
51
|
path: site/
|
|
52
52
|
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
|
|
28
28
|
steps:
|
|
29
29
|
- name: Checkout code
|
|
30
|
-
uses: actions/checkout@
|
|
30
|
+
uses: actions/checkout@v5
|
|
31
31
|
|
|
32
32
|
- name: Install uv
|
|
33
33
|
uses: astral-sh/setup-uv@v6
|
|
@@ -50,7 +50,7 @@ jobs:
|
|
|
50
50
|
- name: Sign build artifacts
|
|
51
51
|
id: sign
|
|
52
52
|
if: ${{ (github.event.inputs.upload || github.ref_type == 'tag') }}
|
|
53
|
-
uses: actions/attest-build-provenance@
|
|
53
|
+
uses: actions/attest-build-provenance@v3
|
|
54
54
|
with:
|
|
55
55
|
subject-path: "dist/*"
|
|
56
56
|
|
|
@@ -78,7 +78,7 @@ jobs:
|
|
|
78
78
|
steps:
|
|
79
79
|
- name: Retrieve release distributions
|
|
80
80
|
id: download
|
|
81
|
-
uses: actions/download-artifact@
|
|
81
|
+
uses: actions/download-artifact@v5
|
|
82
82
|
with:
|
|
83
83
|
name: release-dists
|
|
84
84
|
path: dist/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ctftime_api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: CTFTime API wrapper
|
|
5
5
|
Project-URL: repository, https://github.com/jotonedev/ctftime_api
|
|
6
6
|
Project-URL: documentation, https://jotonedev.github.io/ctftime_api/
|
|
@@ -20,16 +20,13 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Requires-Python: >=3.11
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist: h2<5.0.0,>=4.2.0; extra == 'speed'
|
|
31
|
-
Requires-Dist: uvloop<1.0.0,>=0.21.0; (sys_platform != 'win32') and extra == 'speed'
|
|
32
|
-
Requires-Dist: zstandard<0.24.0,>=0.23.0; extra == 'speed'
|
|
23
|
+
Requires-Dist: dataclasses-json==0.6.7
|
|
24
|
+
Requires-Dist: httpx[http2]<0.29.0,>=0.28.1
|
|
25
|
+
Requires-Dist: yarl>=1.20.1
|
|
26
|
+
Provides-Extra: brotli
|
|
27
|
+
Requires-Dist: httpx[brotli]; extra == 'brotli'
|
|
28
|
+
Provides-Extra: zstd
|
|
29
|
+
Requires-Dist: httpx[zstd]; extra == 'zstd'
|
|
33
30
|
Description-Content-Type: text/markdown
|
|
34
31
|
|
|
35
32
|
# ctftime_api
|
|
@@ -4,10 +4,10 @@ from typing import Any
|
|
|
4
4
|
|
|
5
5
|
import httpx
|
|
6
6
|
from httpx import URL, Timeout
|
|
7
|
-
from pydantic_extra_types.country import CountryAlpha2
|
|
8
7
|
|
|
8
|
+
from ctftime_api.models.country import CountryCode
|
|
9
9
|
from ctftime_api.models.event import Event, EventResult
|
|
10
|
-
from ctftime_api.models.team import
|
|
10
|
+
from ctftime_api.models.team import Team, TeamComplete, TeamRank
|
|
11
11
|
from ctftime_api.models.vote import Vote
|
|
12
12
|
|
|
13
13
|
__all__ = ["CTFTimeClient"]
|
|
@@ -65,10 +65,10 @@ class CTFTimeClient:
|
|
|
65
65
|
response: dict[str, list[dict]] = await self._get(url, params={"limit": limit})
|
|
66
66
|
teams = response.get(f"{year}", [])
|
|
67
67
|
|
|
68
|
-
return [TeamRank.
|
|
68
|
+
return [TeamRank.from_dict(team) for team in teams]
|
|
69
69
|
|
|
70
70
|
async def get_top_team_by_country(
|
|
71
|
-
self, country: str |
|
|
71
|
+
self, country: str | CountryCode
|
|
72
72
|
) -> list[TeamRank]:
|
|
73
73
|
"""
|
|
74
74
|
Get the top teams in the leaderboard for a specific country.
|
|
@@ -78,9 +78,7 @@ class CTFTimeClient:
|
|
|
78
78
|
:raise httpx.HTTPStatusError: If the response status code is not successful.
|
|
79
79
|
:raise ValueError: If the country is not a two-letter country code or a pycountry Country object.
|
|
80
80
|
"""
|
|
81
|
-
if isinstance(country,
|
|
82
|
-
country = country
|
|
83
|
-
elif isinstance(country, str):
|
|
81
|
+
if isinstance(country, str):
|
|
84
82
|
if len(country) != 2:
|
|
85
83
|
raise ValueError(
|
|
86
84
|
"Country must be a two-letter country code or a pycountry Country object."
|
|
@@ -89,7 +87,7 @@ class CTFTimeClient:
|
|
|
89
87
|
url = self._base_url.join("top-by-country/").join(f"{country}/")
|
|
90
88
|
teams: list[dict[str, Any]] = await self._get(url)
|
|
91
89
|
|
|
92
|
-
return [TeamRank.
|
|
90
|
+
return [TeamRank.from_dict(team) for team in teams]
|
|
93
91
|
|
|
94
92
|
async def get_events_information(
|
|
95
93
|
self, start: int | datetime, end: int | datetime, limit: int = 10
|
|
@@ -118,7 +116,7 @@ class CTFTimeClient:
|
|
|
118
116
|
url, params={"start": start, "finish": end, "limit": limit}
|
|
119
117
|
)
|
|
120
118
|
|
|
121
|
-
return [Event.
|
|
119
|
+
return [Event.from_dict(event) for event in events]
|
|
122
120
|
|
|
123
121
|
async def get_event_information(self, event_id: int) -> Event:
|
|
124
122
|
"""
|
|
@@ -130,7 +128,7 @@ class CTFTimeClient:
|
|
|
130
128
|
url = self._base_url.join(f"events/{event_id}/")
|
|
131
129
|
event: dict[str, Any] = await self._get(url)
|
|
132
130
|
|
|
133
|
-
return Event.
|
|
131
|
+
return Event.from_dict(event)
|
|
134
132
|
|
|
135
133
|
async def get_teams_information(
|
|
136
134
|
self, limit: int = 100, offset: int = 0
|
|
@@ -149,7 +147,7 @@ class CTFTimeClient:
|
|
|
149
147
|
)
|
|
150
148
|
teams: list[dict[str, Any]] = response.get("results", [])
|
|
151
149
|
|
|
152
|
-
return [Team.
|
|
150
|
+
return [Team.from_dict(team) for team in teams]
|
|
153
151
|
|
|
154
152
|
async def get_team_information(self, team_id: int) -> TeamComplete:
|
|
155
153
|
"""
|
|
@@ -161,7 +159,7 @@ class CTFTimeClient:
|
|
|
161
159
|
url = self._base_url.join(f"teams/{team_id}/")
|
|
162
160
|
team: dict[str, Any] = await self._get(url)
|
|
163
161
|
|
|
164
|
-
return TeamComplete.
|
|
162
|
+
return TeamComplete.from_dict(team)
|
|
165
163
|
|
|
166
164
|
async def get_event_results(
|
|
167
165
|
self, year: int | None = None
|
|
@@ -181,7 +179,7 @@ class CTFTimeClient:
|
|
|
181
179
|
event: dict[str, dict] = await self._get(url)
|
|
182
180
|
|
|
183
181
|
return {
|
|
184
|
-
int(ctf_id): EventResult(
|
|
182
|
+
int(ctf_id): EventResult.from_dict(result)
|
|
185
183
|
for ctf_id, result in event.items()
|
|
186
184
|
}
|
|
187
185
|
|
|
@@ -206,4 +204,4 @@ class CTFTimeClient:
|
|
|
206
204
|
url = self._base_url.join(f"votes/{year}/")
|
|
207
205
|
votes: list[dict] = await self._get(url, timeout=timeout)
|
|
208
206
|
|
|
209
|
-
return [Vote(
|
|
207
|
+
return [Vote.from_dict(vote) for vote in votes]
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
3
|
+
__all__ = ["CountryCode"]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CountryCode(StrEnum):
|
|
7
|
+
"""
|
|
8
|
+
An enum for ISO 3166-1 alpha-2 country codes.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
AFGHANISTAN = "AF"
|
|
12
|
+
ALAND_ISLANDS = "AX"
|
|
13
|
+
ALBANIA = "AL"
|
|
14
|
+
ALGERIA = "DZ"
|
|
15
|
+
AMERICAN_SAMOA = "AS"
|
|
16
|
+
ANDORRA = "AD"
|
|
17
|
+
ANGOLA = "AO"
|
|
18
|
+
ANGUILLA = "AI"
|
|
19
|
+
ANTARCTICA = "AQ"
|
|
20
|
+
ANTIGUA_AND_BARBUDA = "AG"
|
|
21
|
+
ARGENTINA = "AR"
|
|
22
|
+
ARMENIA = "AM"
|
|
23
|
+
ARUBA = "AW"
|
|
24
|
+
AUSTRALIA = "AU"
|
|
25
|
+
AUSTRIA = "AT"
|
|
26
|
+
AZERBAIJAN = "AZ"
|
|
27
|
+
BAHAMAS = "BS"
|
|
28
|
+
BAHRAIN = "BH"
|
|
29
|
+
BANGLADESH = "BD"
|
|
30
|
+
BARBADOS = "BB"
|
|
31
|
+
BELARUS = "BY"
|
|
32
|
+
BELGIUM = "BE"
|
|
33
|
+
BELIZE = "BZ"
|
|
34
|
+
BENIN = "BJ"
|
|
35
|
+
BERMUDA = "BM"
|
|
36
|
+
BHUTAN = "BT"
|
|
37
|
+
BOLIVIA_PLURINATIONAL_STATE_OF = "BO"
|
|
38
|
+
BONAIRE_SINT_EUSTATIUS_AND_SABA = "BQ"
|
|
39
|
+
BOSNIA_AND_HERZEGOVINA = "BA"
|
|
40
|
+
BOTSWANA = "BW"
|
|
41
|
+
BOUVET_ISLAND = "BV"
|
|
42
|
+
BRAZIL = "BR"
|
|
43
|
+
BRITISH_INDIAN_OCEAN_TERRITORY = "IO"
|
|
44
|
+
BRUNEI_DARUSSALAM = "BN"
|
|
45
|
+
BULGARIA = "BG"
|
|
46
|
+
BURKINA_FASO = "BF"
|
|
47
|
+
BURUNDI = "BI"
|
|
48
|
+
CABO_VERDE = "CV"
|
|
49
|
+
CAMBODIA = "KH"
|
|
50
|
+
CAMEROON = "CM"
|
|
51
|
+
CANADA = "CA"
|
|
52
|
+
CAYMAN_ISLANDS = "KY"
|
|
53
|
+
CENTRAL_AFRICAN_REPUBLIC = "CF"
|
|
54
|
+
CHAD = "TD"
|
|
55
|
+
CHILE = "CL"
|
|
56
|
+
CHINA = "CN"
|
|
57
|
+
CHRISTMAS_ISLAND = "CX"
|
|
58
|
+
COCOS_KEELING_ISLANDS = "CC"
|
|
59
|
+
COLOMBIA = "CO"
|
|
60
|
+
COMOROS = "KM"
|
|
61
|
+
CONGO_THE_DEMOCRATIC_REPUBLIC_OF_THE = "CD"
|
|
62
|
+
CONGO = "CG"
|
|
63
|
+
COOK_ISLANDS = "CK"
|
|
64
|
+
COSTA_RICA = "CR"
|
|
65
|
+
COTE_D_IVOIRE = "CI"
|
|
66
|
+
CROATIA = "HR"
|
|
67
|
+
CUBA = "CU"
|
|
68
|
+
CURACAO = "CW"
|
|
69
|
+
CYPRUS = "CY"
|
|
70
|
+
CZECHIA = "CZ"
|
|
71
|
+
DENMARK = "DK"
|
|
72
|
+
DJIBOUTI = "DJ"
|
|
73
|
+
DOMINICA = "DM"
|
|
74
|
+
DOMINICAN_REPUBLIC = "DO"
|
|
75
|
+
ECUADOR = "EC"
|
|
76
|
+
EGYPT = "EG"
|
|
77
|
+
EL_SALVADOR = "SV"
|
|
78
|
+
EQUATORIAL_GUINEA = "GQ"
|
|
79
|
+
ERITREA = "ER"
|
|
80
|
+
ESTONIA = "EE"
|
|
81
|
+
ESWATINI = "SZ"
|
|
82
|
+
ETHIOPIA = "ET"
|
|
83
|
+
FALKLAND_ISLANDS_MALVINAS = "FK"
|
|
84
|
+
FAROE_ISLANDS = "FO"
|
|
85
|
+
FIJI = "FJ"
|
|
86
|
+
FINLAND = "FI"
|
|
87
|
+
FRANCE = "FR"
|
|
88
|
+
FRENCH_GUIANA = "GF"
|
|
89
|
+
FRENCH_POLYNESIA = "PF"
|
|
90
|
+
FRENCH_SOUTHERN_TERRITORIES = "TF"
|
|
91
|
+
GABON = "GA"
|
|
92
|
+
GAMBIA = "GM"
|
|
93
|
+
GEORGIA = "GE"
|
|
94
|
+
GERMANY = "DE"
|
|
95
|
+
GHANA = "GH"
|
|
96
|
+
GIBRALTAR = "GI"
|
|
97
|
+
GREECE = "GR"
|
|
98
|
+
GREENLAND = "GL"
|
|
99
|
+
GRENADA = "GD"
|
|
100
|
+
GUADELOUPE = "GP"
|
|
101
|
+
GUAM = "GU"
|
|
102
|
+
GUATEMALA = "GT"
|
|
103
|
+
GUERNSEY = "GG"
|
|
104
|
+
GUINEA = "GN"
|
|
105
|
+
GUINEA_BISSAU = "GW"
|
|
106
|
+
GUYANA = "GY"
|
|
107
|
+
HAITI = "HT"
|
|
108
|
+
HEARD_ISLAND_AND_MCDONALD_ISLANDS = "HM"
|
|
109
|
+
HOLY_SEE = "VA"
|
|
110
|
+
HONDURAS = "HN"
|
|
111
|
+
HONG_KONG = "HK"
|
|
112
|
+
HUNGARY = "HU"
|
|
113
|
+
ICELAND = "IS"
|
|
114
|
+
INDIA = "IN"
|
|
115
|
+
INDONESIA = "ID"
|
|
116
|
+
IRAN_ISLAMIC_REPUBLIC_OF = "IR"
|
|
117
|
+
IRAQ = "IQ"
|
|
118
|
+
IRELAND = "IE"
|
|
119
|
+
ISLE_OF_MAN = "IM"
|
|
120
|
+
ISRAEL = "IL"
|
|
121
|
+
ITALY = "IT"
|
|
122
|
+
JAMAICA = "JM"
|
|
123
|
+
JAPAN = "JP"
|
|
124
|
+
JERSEY = "JE"
|
|
125
|
+
JORDAN = "JO"
|
|
126
|
+
KAZAKHSTAN = "KZ"
|
|
127
|
+
KENYA = "KE"
|
|
128
|
+
KIRIBATI = "KI"
|
|
129
|
+
KOREA_THE_DEMOCRATIC_PEOPLES_REPUBLIC_OF = "KP"
|
|
130
|
+
KOREA_THE_REPUBLIC_OF = "KR"
|
|
131
|
+
KUWAIT = "KW"
|
|
132
|
+
KYRGYZSTAN = "KG"
|
|
133
|
+
LAO_PEOPLES_DEMOCRATIC_REPUBLIC = "LA"
|
|
134
|
+
LATVIA = "LV"
|
|
135
|
+
LEBANON = "LB"
|
|
136
|
+
LESOTHO = "LS"
|
|
137
|
+
LIBERIA = "LR"
|
|
138
|
+
LIBYA = "LY"
|
|
139
|
+
LIECHTENSTEIN = "LI"
|
|
140
|
+
LITHUANIA = "LT"
|
|
141
|
+
LUXEMBOURG = "LU"
|
|
142
|
+
MACAO = "MO"
|
|
143
|
+
REPUBLIC_OF_NORTH_MACEDONIA = "MK"
|
|
144
|
+
MADAGASCAR = "MG"
|
|
145
|
+
MALAWI = "MW"
|
|
146
|
+
MALAYSIA = "MY"
|
|
147
|
+
MALDIVES = "MV"
|
|
148
|
+
MALI = "ML"
|
|
149
|
+
MALTA = "MT"
|
|
150
|
+
MARSHALL_ISLANDS = "MH"
|
|
151
|
+
MARTINIQUE = "MQ"
|
|
152
|
+
MAURITANIA = "MR"
|
|
153
|
+
MAURITIUS = "MU"
|
|
154
|
+
MAYOTTE = "YT"
|
|
155
|
+
MEXICO = "MX"
|
|
156
|
+
MICRONESIA_FEDERATED_STATES_OF = "FM"
|
|
157
|
+
MOLDOVA_THE_REPUBLIC_OF = "MD"
|
|
158
|
+
MONACO = "MC"
|
|
159
|
+
MONGOLIA = "MN"
|
|
160
|
+
MONTENEGRO = "ME"
|
|
161
|
+
MONTSERRAT = "MS"
|
|
162
|
+
MOROCCO = "MA"
|
|
163
|
+
MOZAMBIQUE = "MZ"
|
|
164
|
+
MYANMAR = "MM"
|
|
165
|
+
NAMIBIA = "NA"
|
|
166
|
+
NAURU = "NR"
|
|
167
|
+
NEPAL = "NP"
|
|
168
|
+
NETHERLANDS = "NL"
|
|
169
|
+
NEW_CALEDONIA = "NC"
|
|
170
|
+
NEW_ZEALAND = "NZ"
|
|
171
|
+
NICARAGUA = "NI"
|
|
172
|
+
NIGER = "NE"
|
|
173
|
+
NIGERIA = "NG"
|
|
174
|
+
NIUE = "NU"
|
|
175
|
+
NORFOLK_ISLAND = "NF"
|
|
176
|
+
NORTHERN_MARIANA_ISLANDS = "MP"
|
|
177
|
+
NORWAY = "NO"
|
|
178
|
+
OMAN = "OM"
|
|
179
|
+
PAKISTAN = "PK"
|
|
180
|
+
PALAU = "PW"
|
|
181
|
+
PALESTINE_STATE_OF = "PS"
|
|
182
|
+
PANAMA = "PA"
|
|
183
|
+
PAPUA_NEW_GUINEA = "PG"
|
|
184
|
+
PARAGUAY = "PY"
|
|
185
|
+
PERU = "PE"
|
|
186
|
+
PHILIPPINES = "PH"
|
|
187
|
+
PITCAIRN = "PN"
|
|
188
|
+
POLAND = "PL"
|
|
189
|
+
PORTUGAL = "PT"
|
|
190
|
+
PUERTO_RICO = "PR"
|
|
191
|
+
QATAR = "QA"
|
|
192
|
+
REUNION = "RE"
|
|
193
|
+
ROMANIA = "RO"
|
|
194
|
+
RUSSIAN_FEDERATION = "RU"
|
|
195
|
+
RWANDA = "RW"
|
|
196
|
+
SAINT_BARTHELEMY = "BL"
|
|
197
|
+
SAINT_HELENA_ASCENSION_AND_TRISTAN_DA_CUNHA = "SH"
|
|
198
|
+
SAINT_KITTS_AND_NEVIS = "KN"
|
|
199
|
+
SAINT_LUCIA = "LC"
|
|
200
|
+
SAINT_MARTIN_FRENCH_PART = "MF"
|
|
201
|
+
SAINT_PIERRE_AND_MIQUELON = "PM"
|
|
202
|
+
SAINT_VINCENT_AND_THE_GRENADINES = "VC"
|
|
203
|
+
SAMOA = "WS"
|
|
204
|
+
SAN_MARINO = "SM"
|
|
205
|
+
SAO_TOME_AND_PRINCIPE = "ST"
|
|
206
|
+
SAUDI_ARABIA = "SA"
|
|
207
|
+
SENEGAL = "SN"
|
|
208
|
+
SERBIA = "RS"
|
|
209
|
+
SEYCHELLES = "SC"
|
|
210
|
+
SIERRA_LEONE = "SL"
|
|
211
|
+
SINGAPORE = "SG"
|
|
212
|
+
SINT_MAARTEN_DUTCH_PART = "SX"
|
|
213
|
+
SLOVAKIA = "SK"
|
|
214
|
+
SLOVENIA = "SI"
|
|
215
|
+
SOLOMON_ISLANDS = "SB"
|
|
216
|
+
SOMALIA = "SO"
|
|
217
|
+
SOUTH_AFRICA = "ZA"
|
|
218
|
+
SOUTH_GEORGIA_AND_THE_SOUTH_SANDWICH_ISLANDS = "GS"
|
|
219
|
+
SOUTH_SUDAN = "SS"
|
|
220
|
+
SPAIN = "ES"
|
|
221
|
+
SRI_LANKA = "LK"
|
|
222
|
+
SUDAN = "SD"
|
|
223
|
+
SURINAME = "SR"
|
|
224
|
+
SVALBARD_AND_JAN_MAYEN = "SJ"
|
|
225
|
+
SWEDEN = "SE"
|
|
226
|
+
SWITZERLAND = "CH"
|
|
227
|
+
SYRIAN_ARAB_REPUBLIC = "SY"
|
|
228
|
+
TAIWAN_PROVINCE_OF_CHINA = "TW"
|
|
229
|
+
TAJIKISTAN = "TJ"
|
|
230
|
+
TANZANIA_UNITED_REPUBLIC_OF = "TZ"
|
|
231
|
+
THAILAND = "TH"
|
|
232
|
+
TIMOR_LESTE = "TL"
|
|
233
|
+
TOGO = "TG"
|
|
234
|
+
TOKELAU = "TK"
|
|
235
|
+
TONGA = "TO"
|
|
236
|
+
TRINIDAD_AND_TOBAGO = "TT"
|
|
237
|
+
TUNISIA = "TN"
|
|
238
|
+
TURKEY = "TR"
|
|
239
|
+
TURKMENISTAN = "TM"
|
|
240
|
+
TURKS_AND_CAICOS_ISLANDS = "TC"
|
|
241
|
+
TUVALU = "TV"
|
|
242
|
+
UGANDA = "UG"
|
|
243
|
+
UKRAINE = "UA"
|
|
244
|
+
UNITED_ARAB_EMIRATES = "AE"
|
|
245
|
+
UNITED_KINGDOM_OF_GREAT_BRITAIN_AND_NORTHERN_IRELAND = "GB"
|
|
246
|
+
UNITED_STATES_MINOR_OUTLYING_ISLANDS = "UM"
|
|
247
|
+
UNITED_STATES_OF_AMERICA = "US"
|
|
248
|
+
URUGUAY = "UY"
|
|
249
|
+
UZBEKISTAN = "UZ"
|
|
250
|
+
VANUATU = "VU"
|
|
251
|
+
VENEZUELA_BOLIVARIAN_REPUBLIC_OF = "VE"
|
|
252
|
+
VIET_NAM = "VN"
|
|
253
|
+
VIRGIN_ISLANDS_BRITISH = "VG"
|
|
254
|
+
VIRGIN_ISLANDS_US = "VI"
|
|
255
|
+
WALLIS_AND_FUTUNA = "WF"
|
|
256
|
+
WESTERN_SAHARA = "EH"
|
|
257
|
+
YEMEN = "YE"
|
|
258
|
+
ZAMBIA = "ZM"
|
|
259
|
+
ZIMBABWE = "ZW"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from dataclasses_json import DataClassJsonMixin, Undefined, dataclass_json
|
|
4
|
+
|
|
5
|
+
__all__ = ["Duration"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class Duration(DataClassJsonMixin):
|
|
11
|
+
hours: int
|
|
12
|
+
days: int
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
from dataclasses_json import DataClassJsonMixin, Undefined, dataclass_json
|
|
5
|
+
from yarl import URL
|
|
6
|
+
|
|
7
|
+
from .duration import Duration
|
|
8
|
+
from .team import BaseTeam, TeamResult
|
|
9
|
+
|
|
10
|
+
__all__ = ["Event", "EventResult"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class Event(DataClassJsonMixin):
|
|
16
|
+
"""Represents a CTF event."""
|
|
17
|
+
|
|
18
|
+
organizers: list[BaseTeam]
|
|
19
|
+
ctftime_url: URL
|
|
20
|
+
ctf_id: int
|
|
21
|
+
weight: float
|
|
22
|
+
duration: Duration
|
|
23
|
+
live_feed: str
|
|
24
|
+
logo: URL | str
|
|
25
|
+
id: int
|
|
26
|
+
title: str
|
|
27
|
+
participants: int
|
|
28
|
+
location: str
|
|
29
|
+
description: str
|
|
30
|
+
format: str
|
|
31
|
+
is_votable_now: bool
|
|
32
|
+
prizes: str
|
|
33
|
+
restrictions: str
|
|
34
|
+
url: URL | str
|
|
35
|
+
public_votable: bool
|
|
36
|
+
start: datetime | str
|
|
37
|
+
finish: datetime | str
|
|
38
|
+
|
|
39
|
+
def __post_init__(self):
|
|
40
|
+
if isinstance(self.start, str):
|
|
41
|
+
object.__setattr__(self, "start", datetime.fromisoformat(self.start))
|
|
42
|
+
if isinstance(self.finish, str):
|
|
43
|
+
object.__setattr__(self, "finish", datetime.fromisoformat(self.finish))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
47
|
+
@dataclass(frozen=True)
|
|
48
|
+
class EventResult(DataClassJsonMixin):
|
|
49
|
+
"""Represents a CTF event result."""
|
|
50
|
+
|
|
51
|
+
title: str
|
|
52
|
+
time: datetime
|
|
53
|
+
scores: list[TeamResult]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from dataclasses_json import DataClassJsonMixin, Undefined, dataclass_json
|
|
4
|
+
|
|
5
|
+
__all__ = ["Rating"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class Rating(DataClassJsonMixin):
|
|
11
|
+
"""Represents a CTF team rating."""
|
|
12
|
+
|
|
13
|
+
rating_place: int | None = None
|
|
14
|
+
organizer_points: float | None = None
|
|
15
|
+
rating_points: float | None = None
|
|
16
|
+
country_place: int | None = None
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
|
|
3
|
+
from dataclasses_json import DataClassJsonMixin, Undefined, config, dataclass_json
|
|
4
|
+
from yarl import URL
|
|
5
|
+
|
|
6
|
+
from .country import CountryCode
|
|
7
|
+
from .rating import Rating
|
|
8
|
+
|
|
9
|
+
__all__ = ["BaseTeam", "Team", "TeamRank", "TeamComplete", "TeamResult"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class BaseTeam(DataClassJsonMixin):
|
|
15
|
+
"""Represents a CTF team. Contains only the minimal information."""
|
|
16
|
+
|
|
17
|
+
team_id: int = field(metadata=config(field_name="id"))
|
|
18
|
+
team_name: str = field(metadata=config(field_name="name"))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class Team(BaseTeam):
|
|
24
|
+
"""Represents a CTF team"""
|
|
25
|
+
|
|
26
|
+
team_country: CountryCode | None = None
|
|
27
|
+
academic: bool = False
|
|
28
|
+
aliases: list[str] = field(default_factory=list)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class TeamRank(BaseTeam):
|
|
34
|
+
"""Represents a CTF team in the leaderboard"""
|
|
35
|
+
|
|
36
|
+
points: float
|
|
37
|
+
country_place: int | None = None
|
|
38
|
+
place: int | None = None
|
|
39
|
+
events: int | None = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
43
|
+
@dataclass(frozen=True)
|
|
44
|
+
class TeamResult(DataClassJsonMixin):
|
|
45
|
+
"""Represents a CTF team result"""
|
|
46
|
+
|
|
47
|
+
team_id: int
|
|
48
|
+
points: float
|
|
49
|
+
place: int
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class TeamComplete(Team):
|
|
55
|
+
"""Represents a CTF team with complete information"""
|
|
56
|
+
|
|
57
|
+
primary_alias: str | None = None
|
|
58
|
+
logo: URL | str | None = None
|
|
59
|
+
university: str | None = None
|
|
60
|
+
university_website: URL | str | None = None
|
|
61
|
+
rating: dict[int, Rating | None] = field(default_factory=dict)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
from dataclasses_json import DataClassJsonMixin, Undefined, dataclass_json
|
|
5
|
+
|
|
6
|
+
__all__ = ["Vote"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass_json(undefined=Undefined.EXCLUDE)
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class Vote(DataClassJsonMixin):
|
|
12
|
+
event_id: int
|
|
13
|
+
user_id: int
|
|
14
|
+
user_teams: list[int] # list of team IDs
|
|
15
|
+
weight: str
|
|
16
|
+
creation_date: datetime
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ctftime_api"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "CTFTime API wrapper"
|
|
5
5
|
authors = [{ name = "John Toniutti", email = "john.toniutti@gmail.com" }]
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -25,19 +25,17 @@ classifiers = [
|
|
|
25
25
|
"Typing :: Typed",
|
|
26
26
|
]
|
|
27
27
|
dependencies = [
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"pycountry (>=24.6.1,<25.0.0)",
|
|
28
|
+
"dataclasses-json==0.6.7",
|
|
29
|
+
"httpx[http2] (>=0.28.1,<0.29.0)",
|
|
30
|
+
"yarl>=1.20.1",
|
|
32
31
|
]
|
|
33
32
|
|
|
34
33
|
[project.optional-dependencies]
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"zstandard (>=0.23.0,<0.24.0)",
|
|
34
|
+
brotli = [
|
|
35
|
+
"httpx[brotli]",
|
|
36
|
+
]
|
|
37
|
+
zstd = [
|
|
38
|
+
"httpx[zstd]",
|
|
41
39
|
]
|
|
42
40
|
|
|
43
41
|
[project.urls]
|
|
@@ -49,7 +47,7 @@ dev = [
|
|
|
49
47
|
"ruff~=0.9",
|
|
50
48
|
"pytest~=8.3",
|
|
51
49
|
"pytest-cov~=6.1",
|
|
52
|
-
"pytest-asyncio
|
|
50
|
+
"pytest-asyncio>=0.24,<2.0",
|
|
53
51
|
"mypy~=1.11",
|
|
54
52
|
]
|
|
55
53
|
docs = [
|
|
File without changes
|