kaggle 1.7.4.5__py3-none-any.whl → 1.8.0__py3-none-any.whl
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.
- kaggle/__init__.py +10 -6
- kaggle/api/kaggle_api.py +574 -598
- kaggle/api/kaggle_api_extended.py +5251 -4769
- kaggle/cli.py +1335 -1585
- kaggle/models/api_blob_type.py +3 -3
- kaggle/models/dataset_column.py +165 -174
- kaggle/models/dataset_new_request.py +83 -41
- kaggle/models/dataset_new_version_request.py +32 -25
- kaggle/models/dataset_update_settings_request.py +35 -27
- kaggle/models/kaggle_models_extended.py +169 -172
- kaggle/models/kernel_push_request.py +66 -49
- kaggle/models/model_instance_new_version_request.py +10 -18
- kaggle/models/model_instance_update_request.py +103 -34
- kaggle/models/model_new_instance_request.py +138 -41
- kaggle/models/model_new_request.py +35 -27
- kaggle/models/model_update_request.py +32 -25
- kaggle/models/start_blob_upload_request.py +192 -195
- kaggle/models/start_blob_upload_response.py +98 -98
- kaggle/models/upload_file.py +114 -120
- kaggle/test/test_authenticate.py +23 -23
- {kaggle-1.7.4.5.dist-info → kaggle-1.8.0.dist-info}/METADATA +11 -15
- kaggle-1.8.0.dist-info/RECORD +148 -0
- kagglesdk/__init__.py +5 -1
- kagglesdk/benchmarks/services/__init__.py +0 -0
- kagglesdk/benchmarks/services/benchmarks_api_service.py +19 -0
- kagglesdk/benchmarks/types/__init__.py +0 -0
- kagglesdk/benchmarks/types/benchmark_types.py +307 -0
- kagglesdk/benchmarks/types/benchmarks_api_service.py +243 -0
- kagglesdk/blobs/services/blob_api_service.py +1 -1
- kagglesdk/blobs/types/blob_api_service.py +2 -2
- kagglesdk/common/services/__init__.py +0 -0
- kagglesdk/common/services/operations_service.py +46 -0
- kagglesdk/common/types/file_download.py +1 -1
- kagglesdk/common/types/http_redirect.py +1 -1
- kagglesdk/common/types/operations.py +194 -0
- kagglesdk/common/types/operations_service.py +48 -0
- kagglesdk/community/__init__.py +0 -0
- kagglesdk/community/types/__init__.py +0 -0
- kagglesdk/community/types/content_enums.py +44 -0
- kagglesdk/community/types/organization.py +410 -0
- kagglesdk/competitions/services/competition_api_service.py +49 -12
- kagglesdk/competitions/types/competition.py +14 -0
- kagglesdk/competitions/types/competition_api_service.py +1639 -1275
- kagglesdk/competitions/types/search_competitions.py +28 -0
- kagglesdk/datasets/databundles/__init__.py +0 -0
- kagglesdk/datasets/databundles/types/__init__.py +0 -0
- kagglesdk/datasets/databundles/types/databundle_api_types.py +540 -0
- kagglesdk/datasets/services/dataset_api_service.py +39 -14
- kagglesdk/datasets/types/dataset_api_service.py +554 -300
- kagglesdk/datasets/types/dataset_enums.py +21 -0
- kagglesdk/datasets/types/dataset_service.py +145 -0
- kagglesdk/datasets/types/dataset_types.py +74 -74
- kagglesdk/datasets/types/search_datasets.py +6 -0
- kagglesdk/discussions/__init__.py +0 -0
- kagglesdk/discussions/types/__init__.py +0 -0
- kagglesdk/discussions/types/search_discussions.py +43 -0
- kagglesdk/discussions/types/writeup_enums.py +11 -0
- kagglesdk/education/services/education_api_service.py +1 -1
- kagglesdk/education/types/education_api_service.py +1 -1
- kagglesdk/kaggle_client.py +46 -23
- kagglesdk/kaggle_creds.py +148 -0
- kagglesdk/kaggle_env.py +89 -25
- kagglesdk/kaggle_http_client.py +216 -306
- kagglesdk/kaggle_oauth.py +200 -0
- kagglesdk/kaggle_object.py +286 -293
- kagglesdk/kernels/services/kernels_api_service.py +46 -9
- kagglesdk/kernels/types/kernels_api_service.py +635 -159
- kagglesdk/kernels/types/kernels_enums.py +6 -0
- kagglesdk/kernels/types/search_kernels.py +6 -0
- kagglesdk/licenses/__init__.py +0 -0
- kagglesdk/licenses/types/__init__.py +0 -0
- kagglesdk/licenses/types/licenses_types.py +182 -0
- kagglesdk/models/services/model_api_service.py +41 -17
- kagglesdk/models/types/model_api_service.py +987 -637
- kagglesdk/models/types/model_enums.py +8 -0
- kagglesdk/models/types/model_service.py +71 -71
- kagglesdk/models/types/model_types.py +1057 -5
- kagglesdk/models/types/search_models.py +8 -0
- kagglesdk/search/__init__.py +0 -0
- kagglesdk/search/services/__init__.py +0 -0
- kagglesdk/search/services/search_api_service.py +19 -0
- kagglesdk/search/types/__init__.py +0 -0
- kagglesdk/search/types/search_api_service.py +2435 -0
- kagglesdk/search/types/search_content_shared.py +50 -0
- kagglesdk/search/types/search_enums.py +45 -0
- kagglesdk/search/types/search_service.py +303 -0
- kagglesdk/security/services/iam_service.py +31 -0
- kagglesdk/security/services/oauth_service.py +27 -1
- kagglesdk/security/types/authentication.py +63 -63
- kagglesdk/security/types/iam_service.py +496 -0
- kagglesdk/security/types/oauth_service.py +797 -10
- kagglesdk/security/types/roles.py +8 -0
- kagglesdk/security/types/security_types.py +159 -0
- kagglesdk/test/__init__.py +0 -0
- kagglesdk/test/test_client.py +20 -22
- kagglesdk/users/services/account_service.py +13 -1
- kagglesdk/users/services/group_api_service.py +31 -0
- kagglesdk/users/types/account_service.py +169 -28
- kagglesdk/users/types/group_api_service.py +315 -0
- kagglesdk/users/types/group_types.py +165 -0
- kagglesdk/users/types/groups_enum.py +8 -0
- kagglesdk/users/types/progression_service.py +9 -0
- kagglesdk/users/types/search_users.py +23 -0
- kagglesdk/users/types/user_avatar.py +226 -0
- kaggle/configuration.py +0 -206
- kaggle-1.7.4.5.dist-info/RECORD +0 -98
- {kaggle-1.7.4.5.dist-info → kaggle-1.8.0.dist-info}/WHEEL +0 -0
- {kaggle-1.7.4.5.dist-info → kaggle-1.8.0.dist-info}/entry_points.txt +0 -0
- {kaggle-1.7.4.5.dist-info → kaggle-1.8.0.dist-info}/licenses/LICENSE.txt +0 -0
- {kaggle/test → kagglesdk/benchmarks}/__init__.py +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import hashlib
|
|
3
|
+
import http.server
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import platform
|
|
7
|
+
import random
|
|
8
|
+
import secrets
|
|
9
|
+
import socketserver
|
|
10
|
+
import uuid
|
|
11
|
+
import urllib.parse
|
|
12
|
+
import webbrowser
|
|
13
|
+
from datetime import datetime, timedelta, timezone
|
|
14
|
+
from kagglesdk.kaggle_client import KaggleClient
|
|
15
|
+
from kagglesdk.kaggle_creds import KaggleCredentials
|
|
16
|
+
from kagglesdk.security.types.oauth_service import ExchangeOAuthTokenRequest
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class KaggleOAuth:
|
|
20
|
+
OAUTH_CLIENT_ID = "kagglesdk"
|
|
21
|
+
|
|
22
|
+
def __init__(self, client: KaggleClient):
|
|
23
|
+
self._client = client
|
|
24
|
+
self._http_client = client.http_client()
|
|
25
|
+
self._server_running = False
|
|
26
|
+
self._creds = None
|
|
27
|
+
self._logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
class OAuthState:
|
|
30
|
+
def __init__(self):
|
|
31
|
+
self.state = str(uuid.uuid4())
|
|
32
|
+
self.code_verifier = KaggleOAuth.OAuthState._generate_code_verifier()
|
|
33
|
+
self.code_challenge = KaggleOAuth.OAuthState._generate_code_challenge(self.code_verifier)
|
|
34
|
+
|
|
35
|
+
def _generate_state(length: int = 32):
|
|
36
|
+
return secrets.token_urlsafe(length)
|
|
37
|
+
|
|
38
|
+
def _generate_code_verifier(length: int = 64) -> str:
|
|
39
|
+
if not 42 <= length <= 128:
|
|
40
|
+
raise ValueError("Code verifier length must be between 42 and 128 characters.")
|
|
41
|
+
return secrets.token_urlsafe(length)
|
|
42
|
+
|
|
43
|
+
def _generate_code_challenge(code_verifier: str) -> str:
|
|
44
|
+
code_verifier_bytes = code_verifier.encode("utf-8")
|
|
45
|
+
code_challenge_bytes = hashlib.sha256(code_verifier_bytes).digest()
|
|
46
|
+
code_challenge_base64 = base64.urlsafe_b64encode(code_challenge_bytes).decode("utf-8")
|
|
47
|
+
return code_challenge_base64
|
|
48
|
+
|
|
49
|
+
class OAuthCallbackHandler(http.server.BaseHTTPRequestHandler):
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
*args,
|
|
53
|
+
oauth: "KaggleOAuth" = None,
|
|
54
|
+
oauth_state: "KaggleOAuth.OAuthState" = None,
|
|
55
|
+
on_success=None,
|
|
56
|
+
logger=None,
|
|
57
|
+
**kwargs,
|
|
58
|
+
):
|
|
59
|
+
self._oauth = oauth
|
|
60
|
+
self._oauth_state = oauth_state
|
|
61
|
+
self._on_success = on_success
|
|
62
|
+
self._logger = logger
|
|
63
|
+
super().__init__(*args, **kwargs)
|
|
64
|
+
|
|
65
|
+
def do_GET(self):
|
|
66
|
+
if self.path == "/favicon.ico":
|
|
67
|
+
return
|
|
68
|
+
try:
|
|
69
|
+
self._handle_oauth_callback()
|
|
70
|
+
finally:
|
|
71
|
+
self._stop_server()
|
|
72
|
+
|
|
73
|
+
def _handle_oauth_callback(self):
|
|
74
|
+
parsed_url = urllib.parse.urlparse(self.path)
|
|
75
|
+
query_params = urllib.parse.parse_qs(parsed_url.query)
|
|
76
|
+
if "code" in query_params and "state" in query_params:
|
|
77
|
+
code = query_params["code"][0]
|
|
78
|
+
state = query_params["state"][0]
|
|
79
|
+
self._logger.debug(f"\nReceived OAuth Callback:")
|
|
80
|
+
self._logger.debug(f" code : {code}")
|
|
81
|
+
self._logger.debug(f" state: {state}")
|
|
82
|
+
if state == self._oauth_state.state:
|
|
83
|
+
self.send_response(200)
|
|
84
|
+
self.send_header("Content-type", "text/html")
|
|
85
|
+
self.end_headers()
|
|
86
|
+
self.wfile.write(
|
|
87
|
+
b"<html><body><h1>Authentication Successful!</h1><p>You can close this window.</p></body></html>"
|
|
88
|
+
)
|
|
89
|
+
self._on_success(code)
|
|
90
|
+
else:
|
|
91
|
+
self._logger.error(f"Invalid state! Expected: {self._oauth_state.state}, Received: {state}")
|
|
92
|
+
self.send_response(400)
|
|
93
|
+
self.send_header("Content-type", "text/html")
|
|
94
|
+
self.end_headers()
|
|
95
|
+
self.wfile.write(b"<html><body><h1>Authentication Failed!</h1></body></html>")
|
|
96
|
+
else:
|
|
97
|
+
self._logger.debug(f"\nReceived Invalid OAuth Callback: {self.path}")
|
|
98
|
+
self.send_response(400)
|
|
99
|
+
self.send_header("Content-type", "text/html")
|
|
100
|
+
self.end_headers()
|
|
101
|
+
self.wfile.write(
|
|
102
|
+
b"<html><body><h1>Authentication Failed!</h1><p>Invalid callback parameters.</p></body></html>"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def _stop_server(self):
|
|
106
|
+
self._oauth.stop_server()
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def _can_open_browser():
|
|
110
|
+
if platform.system() in ["Windows", "Darwin"]:
|
|
111
|
+
return True # Assume GUI on Windows/Mac
|
|
112
|
+
|
|
113
|
+
if "DISPLAY" in os.environ and os.environ["DISPLAY"] != "":
|
|
114
|
+
return True # X11 display available
|
|
115
|
+
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
def _exchange_oauth_token(self, code: str, scopes: list[str], oauth_state: "KaggleOAuth.OAuthState"):
|
|
119
|
+
request = ExchangeOAuthTokenRequest()
|
|
120
|
+
request.code = code
|
|
121
|
+
request.code_verifier = oauth_state.code_verifier
|
|
122
|
+
request.grant_type = "authorization_code"
|
|
123
|
+
|
|
124
|
+
response = self._client.security.oauth_client.exchange_oauth_token(request)
|
|
125
|
+
self._creds = KaggleCredentials(
|
|
126
|
+
client=self._client,
|
|
127
|
+
refresh_token=response.refreshToken,
|
|
128
|
+
access_token=response.accessToken,
|
|
129
|
+
access_token_expiration=datetime.now(timezone.utc) + timedelta(seconds=response.expires_in),
|
|
130
|
+
username=response.username,
|
|
131
|
+
scopes=scopes,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def _run_oauth_flow(self, scopes: list[str], no_launch_browser: bool) -> KaggleCredentials:
|
|
135
|
+
use_browser = not no_launch_browser and KaggleOAuth._can_open_browser()
|
|
136
|
+
redirect_uri = self._http_client.get_oauth_default_redirect_url()
|
|
137
|
+
if use_browser:
|
|
138
|
+
port = random.randint(8000, 9000)
|
|
139
|
+
redirect_uri = f"http://localhost:{port}"
|
|
140
|
+
self._logger.debug(f"Will listen for the callback at: {redirect_uri}")
|
|
141
|
+
|
|
142
|
+
oauth_state = KaggleOAuth.OAuthState()
|
|
143
|
+
oauth_start_url = self._http_client.build_start_oauth_url(
|
|
144
|
+
client_id=KaggleOAuth.OAUTH_CLIENT_ID,
|
|
145
|
+
redirect_uri=redirect_uri,
|
|
146
|
+
scope=scopes,
|
|
147
|
+
state=oauth_state.state,
|
|
148
|
+
code_challenge=oauth_state.code_challenge,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if use_browser:
|
|
152
|
+
webbrowser.open(oauth_start_url)
|
|
153
|
+
print("Your browser has been opened to visit:")
|
|
154
|
+
print(f" {oauth_start_url}\n\n")
|
|
155
|
+
|
|
156
|
+
def exchange_oauth_token(code: str):
|
|
157
|
+
self._exchange_oauth_token(code, scopes, oauth_state)
|
|
158
|
+
|
|
159
|
+
def handler_factory(*args, **kwargs):
|
|
160
|
+
return KaggleOAuth.OAuthCallbackHandler(
|
|
161
|
+
*args,
|
|
162
|
+
oauth=self,
|
|
163
|
+
oauth_state=oauth_state,
|
|
164
|
+
on_success=exchange_oauth_token,
|
|
165
|
+
logger=self._logger,
|
|
166
|
+
**kwargs,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
self._server_running = True
|
|
170
|
+
with socketserver.TCPServer(("127.0.0.1", port), handler_factory) as httpd:
|
|
171
|
+
self._logger.debug(f"Listening for callback on port {port}...")
|
|
172
|
+
while self._server_running:
|
|
173
|
+
httpd.handle_request()
|
|
174
|
+
self._logger.debug("OAuth flow completed (or server stopped).")
|
|
175
|
+
else:
|
|
176
|
+
print("\nGo to the following link in your browser, and complete the sign-in prompts at Kaggle:\n")
|
|
177
|
+
print(f" {oauth_start_url}")
|
|
178
|
+
print(
|
|
179
|
+
"\nOnce finished, enter the verification code provided in your browser: ",
|
|
180
|
+
end="",
|
|
181
|
+
)
|
|
182
|
+
code = input()
|
|
183
|
+
self._exchange_oauth_token(code, scopes, oauth_state)
|
|
184
|
+
|
|
185
|
+
return self._creds
|
|
186
|
+
|
|
187
|
+
def stop_server(self):
|
|
188
|
+
self._server_running = False
|
|
189
|
+
|
|
190
|
+
def _ensure_creds_valid(self, creds: KaggleCredentials):
|
|
191
|
+
if not creds:
|
|
192
|
+
raise Exception("Authentication failed.")
|
|
193
|
+
return creds.introspect()
|
|
194
|
+
|
|
195
|
+
def authenticate(self, scopes: list[str], no_launch_browser: bool = False) -> KaggleCredentials:
|
|
196
|
+
creds = self._run_oauth_flow(scopes, no_launch_browser)
|
|
197
|
+
username = self._ensure_creds_valid(creds)
|
|
198
|
+
creds.save()
|
|
199
|
+
print(f"\nYou are now logged in as [{username}]\n")
|
|
200
|
+
return creds
|