kaggle 1.7.4.2__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.
Files changed (114) hide show
  1. kaggle/__init__.py +10 -6
  2. kaggle/api/kaggle_api.py +574 -585
  3. kaggle/api/kaggle_api_extended.py +5251 -4738
  4. kaggle/cli.py +1335 -1585
  5. kaggle/models/api_blob_type.py +3 -3
  6. kaggle/models/dataset_column.py +129 -129
  7. kaggle/models/dataset_new_request.py +130 -72
  8. kaggle/models/dataset_new_version_request.py +88 -56
  9. kaggle/models/dataset_update_settings_request.py +93 -59
  10. kaggle/models/kaggle_models_extended.py +169 -172
  11. kaggle/models/kernel_push_request.py +152 -100
  12. kaggle/models/model_instance_new_version_request.py +30 -30
  13. kaggle/models/model_instance_update_request.py +171 -71
  14. kaggle/models/model_new_instance_request.py +223 -88
  15. kaggle/models/model_new_request.py +61 -46
  16. kaggle/models/model_update_request.py +66 -48
  17. kaggle/models/start_blob_upload_request.py +146 -138
  18. kaggle/models/start_blob_upload_response.py +83 -78
  19. kaggle/models/upload_file.py +92 -96
  20. kaggle/test/test_authenticate.py +23 -23
  21. {kaggle-1.7.4.2.dist-info → kaggle-1.8.0.dist-info}/METADATA +11 -15
  22. kaggle-1.8.0.dist-info/RECORD +148 -0
  23. kagglesdk/__init__.py +5 -1
  24. kagglesdk/benchmarks/services/__init__.py +0 -0
  25. kagglesdk/benchmarks/services/benchmarks_api_service.py +19 -0
  26. kagglesdk/benchmarks/types/__init__.py +0 -0
  27. kagglesdk/benchmarks/types/benchmark_types.py +307 -0
  28. kagglesdk/benchmarks/types/benchmarks_api_service.py +243 -0
  29. kagglesdk/blobs/services/blob_api_service.py +1 -1
  30. kagglesdk/blobs/types/blob_api_service.py +2 -2
  31. kagglesdk/common/services/__init__.py +0 -0
  32. kagglesdk/common/services/operations_service.py +46 -0
  33. kagglesdk/common/types/file_download.py +1 -1
  34. kagglesdk/common/types/http_redirect.py +1 -1
  35. kagglesdk/common/types/operations.py +194 -0
  36. kagglesdk/common/types/operations_service.py +48 -0
  37. kagglesdk/community/__init__.py +0 -0
  38. kagglesdk/community/types/__init__.py +0 -0
  39. kagglesdk/community/types/content_enums.py +44 -0
  40. kagglesdk/community/types/organization.py +410 -0
  41. kagglesdk/competitions/services/competition_api_service.py +49 -12
  42. kagglesdk/competitions/types/competition.py +14 -0
  43. kagglesdk/competitions/types/competition_api_service.py +1639 -1275
  44. kagglesdk/competitions/types/search_competitions.py +28 -0
  45. kagglesdk/datasets/databundles/__init__.py +0 -0
  46. kagglesdk/datasets/databundles/types/__init__.py +0 -0
  47. kagglesdk/datasets/databundles/types/databundle_api_types.py +540 -0
  48. kagglesdk/datasets/services/dataset_api_service.py +39 -14
  49. kagglesdk/datasets/types/dataset_api_service.py +567 -297
  50. kagglesdk/datasets/types/dataset_enums.py +21 -0
  51. kagglesdk/datasets/types/dataset_service.py +145 -0
  52. kagglesdk/datasets/types/dataset_types.py +74 -74
  53. kagglesdk/datasets/types/search_datasets.py +6 -0
  54. kagglesdk/discussions/__init__.py +0 -0
  55. kagglesdk/discussions/types/__init__.py +0 -0
  56. kagglesdk/discussions/types/search_discussions.py +43 -0
  57. kagglesdk/discussions/types/writeup_enums.py +11 -0
  58. kagglesdk/education/services/education_api_service.py +1 -1
  59. kagglesdk/education/types/education_api_service.py +1 -1
  60. kagglesdk/kaggle_client.py +55 -20
  61. kagglesdk/kaggle_creds.py +148 -0
  62. kagglesdk/kaggle_env.py +89 -27
  63. kagglesdk/kaggle_http_client.py +235 -290
  64. kagglesdk/kaggle_oauth.py +200 -0
  65. kagglesdk/kaggle_object.py +298 -250
  66. kagglesdk/kernels/services/kernels_api_service.py +46 -9
  67. kagglesdk/kernels/types/kernels_api_service.py +658 -158
  68. kagglesdk/kernels/types/kernels_enums.py +6 -0
  69. kagglesdk/kernels/types/search_kernels.py +6 -0
  70. kagglesdk/licenses/__init__.py +0 -0
  71. kagglesdk/licenses/types/__init__.py +0 -0
  72. kagglesdk/licenses/types/licenses_types.py +182 -0
  73. kagglesdk/models/services/model_api_service.py +46 -21
  74. kagglesdk/models/types/model_api_service.py +1018 -652
  75. kagglesdk/models/types/model_enums.py +8 -0
  76. kagglesdk/models/types/model_service.py +71 -71
  77. kagglesdk/models/types/model_types.py +1057 -5
  78. kagglesdk/models/types/search_models.py +8 -0
  79. kagglesdk/search/__init__.py +0 -0
  80. kagglesdk/search/services/__init__.py +0 -0
  81. kagglesdk/search/services/search_api_service.py +19 -0
  82. kagglesdk/search/types/__init__.py +0 -0
  83. kagglesdk/search/types/search_api_service.py +2435 -0
  84. kagglesdk/search/types/search_content_shared.py +50 -0
  85. kagglesdk/search/types/search_enums.py +45 -0
  86. kagglesdk/search/types/search_service.py +303 -0
  87. kagglesdk/security/__init__.py +0 -0
  88. kagglesdk/security/services/__init__.py +0 -0
  89. kagglesdk/security/services/iam_service.py +31 -0
  90. kagglesdk/security/services/oauth_service.py +58 -0
  91. kagglesdk/security/types/__init__.py +0 -0
  92. kagglesdk/security/types/authentication.py +171 -0
  93. kagglesdk/security/types/iam_service.py +496 -0
  94. kagglesdk/security/types/oauth_service.py +1181 -0
  95. kagglesdk/security/types/roles.py +8 -0
  96. kagglesdk/security/types/security_types.py +159 -0
  97. kagglesdk/test/__init__.py +0 -0
  98. kagglesdk/test/test_client.py +20 -24
  99. kagglesdk/users/services/__init__.py +0 -0
  100. kagglesdk/users/services/account_service.py +31 -0
  101. kagglesdk/users/services/group_api_service.py +31 -0
  102. kagglesdk/users/types/account_service.py +345 -0
  103. kagglesdk/users/types/group_api_service.py +315 -0
  104. kagglesdk/users/types/group_types.py +165 -0
  105. kagglesdk/users/types/groups_enum.py +8 -0
  106. kagglesdk/users/types/progression_service.py +9 -0
  107. kagglesdk/users/types/search_users.py +23 -0
  108. kagglesdk/users/types/user_avatar.py +226 -0
  109. kaggle/configuration.py +0 -206
  110. kaggle-1.7.4.2.dist-info/RECORD +0 -89
  111. {kaggle-1.7.4.2.dist-info → kaggle-1.8.0.dist-info}/WHEEL +0 -0
  112. {kaggle-1.7.4.2.dist-info → kaggle-1.8.0.dist-info}/entry_points.txt +0 -0
  113. {kaggle-1.7.4.2.dist-info → kaggle-1.8.0.dist-info}/licenses/LICENSE.txt +0 -0
  114. {kaggle/test → kagglesdk/benchmarks}/__init__.py +0 -0
@@ -4,11 +4,17 @@ import json
4
4
  import os
5
5
  import urllib.parse
6
6
  from io import BytesIO
7
+ from pathlib import Path
7
8
 
8
9
  import requests
9
10
  from urllib3.fields import RequestField
10
11
 
11
- from kagglesdk.kaggle_env import get_endpoint, get_env, KaggleEnv
12
+ from kagglesdk.kaggle_env import (
13
+ get_endpoint,
14
+ get_env,
15
+ get_access_token_from_env,
16
+ KaggleEnv,
17
+ )
12
18
  from kagglesdk.kaggle_object import KaggleObject
13
19
  from typing import Type
14
20
 
@@ -17,300 +23,239 @@ from typing import Type
17
23
  # auth handling. The new client requires KAGGLE_API_TOKEN, so it is not
18
24
  # currently usable by the CLI.
19
25
 
20
- # TODO: Extend kapigen to add a boolean to these requests indicating that they use forms.
21
- REQUESTS_REQUIRING_FORMS = ['ApiUploadDatasetFileRequest', 'ApiCreateSubmissionRequest', 'ApiCreateCodeSubmissionRequest', 'ApiStartSubmissionUploadRequest', 'ApiUploadModelFileRequest']
22
26
 
23
27
  def _headers_to_str(headers):
24
- return '\n'.join(f'{k}: {v}' for k, v in headers.items())
28
+ return "\n".join(f"{k}: {v}" for k, v in headers.items())
25
29
 
26
30
 
27
31
  def _get_apikey_creds():
28
- apikey_filename = os.path.expanduser('~/.kaggle/kaggle.json')
29
- if not os.path.exists(apikey_filename):
30
- return None
31
-
32
- kaggle_json = None
33
- with open(apikey_filename) as apikey_file:
34
- kaggle_json = apikey_file.read()
35
-
36
- if not kaggle_json or not kaggle_json.strip():
37
- return None
38
-
39
- api_key_data = json.loads(kaggle_json)
40
- username = api_key_data['username']
41
- api_key = api_key_data['key']
42
- return username, api_key
43
-
44
-
45
- def clean_data(data):
46
- if isinstance(data, dict):
47
- return {to_lower_camel_case(k): clean_data(v) for k, v in data.items() if v is not None}
48
- if isinstance(data, list):
49
- return [clean_data(v) for v in data if v is not None]
50
- if data is True:
51
- return 'true'
52
- if data is False:
53
- return 'false'
54
- return data
55
-
56
- def find_words(source, left='{', right='}'):
57
- words = []
58
- split_str = source.split(left)
59
-
60
- for s in split_str[1:]:
61
- split_s = s.split(right)
62
- if len(split_s) > 1:
63
- words.append(split_s[0])
64
-
65
- return words
66
-
67
- def to_camel_case(snake_str):
68
- return "".join(x.capitalize() for x in snake_str.lower().split("_"))
69
-
70
- def to_lower_camel_case(snake_str):
71
- # https://stackoverflow.com/questions/19053707/converting-snake-case-to-lower-camel-case-lowercamelcase
72
- # We capitalize the first letter of each component except the first one
73
- # with the 'capitalize' method and join them together.
74
- camel_string = to_camel_case(snake_str)
75
- return snake_str[0].lower() + camel_string[1:]
32
+ apikey_filename = os.path.expanduser("~/.kaggle/kaggle.json")
33
+ if not os.path.exists(apikey_filename):
34
+ return None
35
+
36
+ kaggle_json = None
37
+ with open(apikey_filename) as apikey_file:
38
+ kaggle_json = apikey_file.read()
39
+
40
+ if not kaggle_json or not kaggle_json.strip():
41
+ return None
42
+
43
+ api_key_data = json.loads(kaggle_json)
44
+ username = api_key_data["username"]
45
+ api_key = api_key_data["key"]
46
+ return username, api_key
47
+
76
48
 
77
49
  class KaggleHttpClient(object):
78
- _xsrf_cookie_name = 'XSRF-TOKEN'
79
- _csrf_cookie_name = "CSRF-TOKEN"
80
- _xsrf_cookies = (_xsrf_cookie_name, _csrf_cookie_name)
81
- _xsrf_header_name = 'X-XSRF-TOKEN'
82
-
83
- def __init__(self,
84
- env: KaggleEnv = None,
85
- verbose: bool = False,
86
- renew_iap_token=None,
87
- username=None,
88
- password=None):
89
- self._env = env or get_env()
90
- self._signed_in = None
91
- self._endpoint = get_endpoint(self._env)
92
- self._verbose = verbose
93
- self._session = None
94
- self._username = username
95
- self._password = password
96
-
97
- def call(self, service_name: str, request_name: str, request: KaggleObject,
98
- response_type: Type[KaggleObject]):
99
- self._init_session()
100
- http_request = self._prepare_request(service_name, request_name, request)
101
-
102
- http_response = self._session.send(http_request)
103
-
104
- response = self._prepare_response(response_type, http_response)
105
- return response
106
-
107
- def _prepare_request(self, service_name: str, request_name: str,
108
- request: KaggleObject):
109
- request_url = self._get_request_url(request)
110
- method = request.method()
111
- data= ''
112
- if method == 'GET':
113
- data = request.__class__.to_dict(request, ignore_defaults=False)
114
- if request.endpoint_path():
115
- words = find_words(request.endpoint_path())
116
- list(map(data.pop, [to_lower_camel_case(w) for w in words]))
117
- if len(data) == 0:
118
- data = None
119
- if data:
120
- request_url = f'{request_url}?{urllib.parse.urlencode(clean_data(data))}'
121
- data = ''
122
- self._session.headers.update({
123
- 'Accept': 'application/json',
124
- 'Content-Type': 'text/plain',
125
- })
126
- elif method == 'POST':
127
- data = request.to_field_map(request, ignore_defaults=True)
128
- if isinstance(data, dict):
129
- fields = request.body_fields()
130
- if fields is not None:
131
- if fields != '*':
132
- data = data[fields]
133
- data = clean_data(data)
134
- if self.requires_form(request):
135
- data, content_type = self.make_form(data)
50
+ _xsrf_cookie_name = "XSRF-TOKEN"
51
+ _csrf_cookie_name = "CSRF-TOKEN"
52
+ _xsrf_cookies = (_xsrf_cookie_name, _csrf_cookie_name)
53
+ _xsrf_header_name = "X-XSRF-TOKEN"
54
+
55
+ def __init__(
56
+ self,
57
+ env: KaggleEnv = None,
58
+ verbose: bool = False,
59
+ username: str = None,
60
+ password: str = None,
61
+ api_token: str = None,
62
+ ):
63
+ self._env = env or get_env()
64
+ self._signed_in = None
65
+ self._endpoint = get_endpoint(self._env)
66
+ self._verbose = verbose
67
+ self._session = None
68
+ self._username = username
69
+ self._password = password
70
+ self._api_token = api_token
71
+
72
+ def call(
73
+ self,
74
+ service_name: str,
75
+ request_name: str,
76
+ request: KaggleObject,
77
+ response_type: Type[KaggleObject],
78
+ ):
79
+ self._init_session()
80
+ http_request = self._prepare_request(service_name, request_name, request)
81
+
82
+ # Merge environment settings into session
83
+ settings = self._session.merge_environment_settings(http_request.url, {}, None, None, None)
84
+ http_response = self._session.send(http_request, **settings)
85
+
86
+ response = self._prepare_response(response_type, http_response)
87
+ return response
88
+
89
+ def _prepare_request(self, service_name: str, request_name: str, request: KaggleObject):
90
+ request_url = self._get_request_url(service_name, request_name)
91
+ http_request = requests.Request(
92
+ method="POST",
93
+ url=request_url,
94
+ json=request.__class__.to_dict(request),
95
+ headers=self._session.headers,
96
+ auth=self._session.auth,
97
+ )
98
+ prepared_request = http_request.prepare()
99
+ self._print_request(prepared_request)
100
+ return prepared_request
101
+
102
+ def _prepare_response(self, response_type, http_response):
103
+ """Extract the kaggle response and raise an exception if it is an error."""
104
+ self._print_response(http_response)
105
+ try:
106
+ if "application/json" in http_response.headers["Content-Type"]:
107
+ resp = http_response.json()
108
+ if "code" in resp and resp["code"] >= 400:
109
+ raise requests.exceptions.HTTPError(resp["message"], response=http_response)
110
+ except KeyError:
111
+ pass
112
+ http_response.raise_for_status()
113
+ if response_type is None: # Method doesn't have a return type
114
+ return None
115
+ return response_type.prepare_from(http_response)
116
+
117
+ def _print_request(self, request):
118
+ if not self._verbose:
119
+ return
120
+ self._print("---------------------Request----------------------")
121
+ self._print(f"{request.method} {request.url}\n{_headers_to_str(request.headers)}\n\n{request.body}")
122
+ self._print("--------------------------------------------------")
123
+
124
+ def _print_response(self, response, body=True):
125
+ if not self._verbose:
126
+ return
127
+ self._print("---------------------Response---------------------")
128
+ self._print(f"{response.status_code}\n{_headers_to_str(response.headers)}")
129
+ if body:
130
+ self._print(f"\n{response.text}")
131
+ self._print("--------------------------------------------------")
132
+
133
+ def _print(self, message: str):
134
+ if self._verbose:
135
+ print(message)
136
+
137
+ def __enter__(self):
138
+ self._init_session()
139
+ return self
140
+
141
+ def __exit__(self, exc_type, exc_value, tb):
142
+ if self._session is not None:
143
+ self._session.close()
144
+
145
+ def _init_session(self):
146
+ if self._session is not None:
147
+ return self._session
148
+
149
+ self._session = requests.Session()
150
+ self._session.headers.update({"User-Agent": "kaggle-api/v1.8.0", "Content-Type": "application/json"}) # Was: V2
151
+
152
+ iap_token = self._get_iap_token_if_required()
153
+ if iap_token is not None:
154
+ self._session.headers.update(
155
+ {
156
+ # https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_proxy-authorization_header
157
+ "Proxy-Authorization": f"Bearer {iap_token}",
158
+ }
159
+ )
160
+
161
+ self._try_fill_auth()
162
+ # self._fill_xsrf_token(iap_token) # TODO Make this align with original handler.
163
+
164
+ def _get_iap_token_if_required(self):
165
+ if self._env not in (KaggleEnv.STAGING, KaggleEnv.ADMIN):
166
+ return None
167
+ iap_token = os.getenv("KAGGLE_IAP_TOKEN")
168
+ if iap_token is None:
169
+ raise Exception(f'Must set KAGGLE_IAP_TOKEN to access "{self._endpoint}"')
170
+ return iap_token
171
+
172
+ def _fill_xsrf_token(self, iap_token):
173
+ initial_get_request = requests.Request(
174
+ method="GET",
175
+ url=self._endpoint,
176
+ headers=self._session.headers,
177
+ auth=self._session.auth,
178
+ )
179
+ prepared_request = initial_get_request.prepare()
180
+ self._print_request(prepared_request)
181
+
182
+ http_response = self._session.send(prepared_request)
183
+
184
+ self._print_response(http_response, body=False)
185
+ if iap_token is not None and http_response.status_code in (401, 403):
186
+ raise requests.exceptions.HTTPError("IAP token invalid or expired")
187
+ http_response.raise_for_status()
188
+
189
+ self._session.headers.update(
190
+ {
191
+ KaggleHttpClient._xsrf_header_name: self._session.cookies[KaggleHttpClient._xsrf_cookie_name],
192
+ }
193
+ )
194
+
195
+ def build_start_oauth_url(
196
+ self,
197
+ client_id: str,
198
+ redirect_uri: str,
199
+ scope: list[str],
200
+ state: str,
201
+ code_challenge: str,
202
+ ) -> str:
203
+ params = {
204
+ "response_type": "code",
205
+ "client_id": client_id,
206
+ "redirect_uri": redirect_uri,
207
+ "scope": " ".join(scope),
208
+ "state": state,
209
+ "code_challenge": code_challenge,
210
+ "code_challenge_method": "S256",
211
+ "response_type": "code",
212
+ "response_mode": "query",
213
+ }
214
+ auth_url = f"{self.get_non_api_endpoint()}/api/v1/oauth2/authorize"
215
+ query_string = urllib.parse.urlencode(params, quote_via=urllib.parse.quote_plus)
216
+ return f"{auth_url}?{query_string}"
217
+
218
+ def get_oauth_default_redirect_url(self) -> str:
219
+ return f"{self.get_non_api_endpoint()}/account/api/oauth/token"
220
+
221
+ def get_non_api_endpoint(self) -> str:
222
+ return "https://www.kaggle.com" if self._env == KaggleEnv.PROD else self._endpoint
223
+
224
+ class BearerAuth(requests.auth.AuthBase):
225
+
226
+ def __init__(self, token):
227
+ self.token = token
228
+
229
+ def __call__(self, r):
230
+ r.headers["Authorization"] = f"Bearer {self.token}"
231
+ return r
232
+
233
+ def _try_fill_auth(self):
234
+ if self._signed_in is not None:
235
+ return
236
+
237
+ if self._api_token is None:
238
+ (api_token, _) = get_access_token_from_env()
239
+ self._api_token = api_token
240
+
241
+ if self._api_token is not None:
242
+ self._session.auth = KaggleHttpClient.BearerAuth(self._api_token)
243
+ self._signed_in = True
244
+ return
245
+
246
+ if self._username and self._password:
247
+ apikey_creds = self._username, self._password
136
248
  else:
137
- content_type = 'application/json'
138
- data = json.dumps(data)
139
- self._session.headers.update({
140
- 'Accept': 'application/json',
141
- 'Content-Type': content_type,
142
- })
143
- http_request = requests.Request(
144
- method=method,
145
- url=request_url,
146
- data=data,
147
- headers=self._session.headers,
148
- # cookies=self._get_xsrf_cookies(),
149
- auth=self._session.auth)
150
- prepared_request = http_request.prepare()
151
- self._print_request(prepared_request)
152
- return prepared_request
153
-
154
- def _get_xsrf_cookies(self):
155
- cookies = requests.cookies.RequestsCookieJar()
156
- for cookie in self._session.cookies:
157
- if cookie.name in KaggleHttpClient._xsrf_cookies:
158
- cookies[cookie.name] = cookie.value
159
- return cookies
160
-
161
- def _prepare_response(self, response_type, http_response):
162
- self._print_response(http_response)
163
- http_response.raise_for_status()
164
- if 'application/json' in http_response.headers['Content-Type']:
165
- resp = http_response.json()
166
- if 'code' in resp and resp['code'] >= 400:
167
- raise requests.exceptions.HTTPError(
168
- resp['message'], response=http_response)
169
- if response_type is None: # Method doesn't have a return type
170
- return None
171
- return response_type.prepare_from(http_response)
172
-
173
- def _print_request(self, request):
174
- if not self._verbose:
175
- return
176
- self._print('---------------------Request----------------------')
177
- self._print(
178
- f'{request.method} {request.url}\n{_headers_to_str(request.headers)}\n\n{request.body}'
179
- )
180
- self._print('--------------------------------------------------')
181
-
182
- def _print_response(self, response, body=True):
183
- if not self._verbose:
184
- return
185
- self._print('---------------------Response---------------------')
186
- self._print(f'{response.status_code}\n{_headers_to_str(response.headers)}')
187
- if body:
188
- self._print(f'\n{response.text}')
189
- self._print('--------------------------------------------------')
190
-
191
- def _print(self, message: str):
192
- if self._verbose:
193
- print(message)
194
-
195
- def __enter__(self):
196
- self._init_session()
197
- return self
198
-
199
- def __exit__(self, exc_type, exc_value, tb):
200
- if self._session is not None:
201
- self._session.close()
202
-
203
- def _init_session(self):
204
- if self._session is not None:
205
- return self._session
206
-
207
- self._session = requests.Session()
208
- self._session.headers.update({
209
- 'User-Agent': 'kaggle-api/v1.7.0', # Was: V2
210
- 'Content-Type': 'application/x-www-form-urlencoded', # Was: /json
211
- })
212
-
213
- iap_token = self._get_iap_token_if_required()
214
- if iap_token is not None:
215
- self._session.headers.update({
216
- # https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_proxy-authorization_header
217
- 'Proxy-Authorization': f'Bearer {iap_token}',
218
- })
219
-
220
- self._try_fill_auth()
221
- # self._fill_xsrf_token(iap_token) # TODO Make this align with original handler.
222
-
223
- def _get_iap_token_if_required(self):
224
- if self._env not in (KaggleEnv.STAGING, KaggleEnv.ADMIN):
225
- return None
226
- iap_token = os.getenv('KAGGLE_IAP_TOKEN')
227
- if iap_token is None:
228
- raise Exception(f'Must set KAGGLE_IAP_TOKEN to access "{self._endpoint}"')
229
- return iap_token
230
-
231
- def _fill_xsrf_token(self, iap_token):
232
- initial_get_request = requests.Request(
233
- method='GET',
234
- url=self._endpoint,
235
- headers=self._session.headers,
236
- auth=self._session.auth)
237
- prepared_request = initial_get_request.prepare()
238
- self._print_request(prepared_request)
239
-
240
- http_response = self._session.send(prepared_request)
241
-
242
- self._print_response(http_response, body=False)
243
- if iap_token is not None and http_response.status_code in (401, 403):
244
- raise requests.exceptions.HTTPError('IAP token invalid or expired')
245
- http_response.raise_for_status()
246
-
247
- self._session.headers.update({
248
- KaggleHttpClient._xsrf_header_name:
249
- self._session.cookies[KaggleHttpClient._xsrf_cookie_name],
250
- })
251
-
252
- class BearerAuth(requests.auth.AuthBase):
253
-
254
- def __init__(self, token):
255
- self.token = token
256
-
257
- def __call__(self, r):
258
- r.headers["Authorization"] = f"Bearer {self.token}"
259
- return r
260
-
261
- def _try_fill_auth(self):
262
- if self._signed_in is not None:
263
- return
264
-
265
- api_token = os.getenv('KAGGLE_API_TOKEN')
266
- if api_token is not None:
267
- self._session.auth = KaggleHttpClient.BearerAuth(api_token)
268
- self._signed_in = True
269
- return
270
-
271
- if self._username and self._password:
272
- apikey_creds = self._username, self._password
273
- else:
274
- apikey_creds = _get_apikey_creds()
275
- if apikey_creds is not None:
276
- self._session.auth = apikey_creds
277
- self._signed_in = True
278
- return
279
-
280
- self._signed_in = False
281
-
282
- def _get_request_url(self, request):
283
- return f'{self._endpoint}{request.endpoint()}'
284
-
285
- @staticmethod
286
- def make_form(fields):
287
- body = BytesIO()
288
- boundary = binascii.hexlify(os.urandom(16)).decode()
289
- writer = codecs.lookup("utf-8")[3]
290
-
291
- for field in fields.items():
292
- field = RequestField.from_tuples(*field)
293
- body.write(f"--{boundary}\r\n".encode("latin-1"))
294
-
295
- writer(body).write(field.render_headers())
296
- data = field.data
297
-
298
- if isinstance(data, int):
299
- data = str(data)
300
-
301
- if isinstance(data, str):
302
- writer(body).write(data)
303
- else:
304
- body.write(data)
305
-
306
- body.write(b"\r\n")
307
-
308
- body.write(f"--{boundary}--\r\n".encode("latin-1"))
309
-
310
- content_type = f"multipart/form-data; boundary={boundary}"
311
-
312
- return body.getvalue(), content_type
313
-
314
- @staticmethod
315
- def requires_form(request):
316
- return type(request).__name__ in REQUESTS_REQUIRING_FORMS
249
+ apikey_creds = _get_apikey_creds()
250
+ if apikey_creds is not None:
251
+ self._session.auth = apikey_creds
252
+ self._signed_in = True
253
+ return
254
+
255
+ self._signed_in = False
256
+
257
+ def _get_request_url(self, service_name: str, request_name: str):
258
+ # On prod, API endpoints are served under https://api.kaggle.com/v1,
259
+ # but on staging/admin/local, they are served under http://localhost/api/v1.
260
+ base_url = self._endpoint if self._env == KaggleEnv.PROD else f"{self._endpoint}/api"
261
+ return f"{base_url}/v1/{service_name}/{request_name}"