Skip to content

Commit 90cb774

Browse files
authored
Merge pull request #887 from Kaggle/add-session-client
Add new client to retrieve exportable .ipynb of current session.
2 parents cdea271 + 2b0074e commit 90cb774

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.c
488488
ENV PYTHONUSERBASE "/root/.local"
489489
ADD patches/kaggle_gcp.py /root/.local/lib/python3.7/site-packages/kaggle_gcp.py
490490
ADD patches/kaggle_secrets.py /root/.local/lib/python3.7/site-packages/kaggle_secrets.py
491+
ADD patches/kaggle_session.py /root/.local/lib/python3.7/site-packages/kaggle_session.py
491492
ADD patches/kaggle_web_client.py /root/.local/lib/python3.7/site-packages/kaggle_web_client.py
492493
ADD patches/kaggle_datasets.py /root/.local/lib/python3.7/site-packages/kaggle_datasets.py
493494
ADD patches/log.py /root/.local/lib/python3.7/site-packages/log.py

patches/kaggle_session.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
This library adds support for retrieving data related to the current user session.
3+
"""
4+
5+
import os
6+
7+
from kaggle_web_client import KaggleWebClient
8+
9+
10+
class UserSessionClient():
11+
GET_SOURCE_ENDPOINT = '/requests/GetKernelRunSourceForCaipRequest'
12+
13+
def __init__(self):
14+
self.web_client = KaggleWebClient()
15+
16+
def get_exportable_ipynb(self):
17+
"""Fetch the .ipynb source of the current notebook session.
18+
19+
If Kaggle datasets are attached to the notebook, the source will
20+
include an additonnal cell with logic to download the datasets
21+
outside the Kaggle platform.
22+
"""
23+
request_body = {
24+
'UseDraft': True,
25+
}
26+
return self.web_client.make_post_request(request_body, self.GET_SOURCE_ENDPOINT)

tests/test_user_session.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import json
2+
import os
3+
import threading
4+
import unittest
5+
6+
from http.server import BaseHTTPRequestHandler, HTTPServer
7+
from test.support import EnvironmentVarGuard
8+
from urllib.parse import urlparse
9+
from kaggle_session import UserSessionClient
10+
from kaggle_web_client import (_KAGGLE_URL_BASE_ENV_VAR_NAME,
11+
_KAGGLE_USER_SECRETS_TOKEN_ENV_VAR_NAME,
12+
CredentialError, BackendError)
13+
14+
class UserSessionHTTPHandler(BaseHTTPRequestHandler):
15+
16+
def set_request(self):
17+
raise NotImplementedError()
18+
19+
def get_response(self):
20+
raise NotImplementedError()
21+
22+
def do_HEAD(s):
23+
s.send_response(200)
24+
25+
def do_POST(s):
26+
s.set_request()
27+
s.send_response(200)
28+
s.send_header("Content-type", "application/json")
29+
s.end_headers()
30+
s.wfile.write(json.dumps(s.get_response()).encode("utf-8"))
31+
32+
class TestUserSessionClient(unittest.TestCase):
33+
SERVER_ADDRESS = urlparse(os.getenv(_KAGGLE_URL_BASE_ENV_VAR_NAME, default="http://127.0.0.1:8001"))
34+
TEST_JWT = 'test-secrets-key'
35+
36+
def _test_client(self, client_func, expected_path, expected_body, source=None, success=True):
37+
_request = {}
38+
39+
class GetKernelRunSourceForCaipHandler(UserSessionHTTPHandler):
40+
def set_request(self):
41+
_request['path'] = self.path
42+
content_len = int(self.headers.get('Content-Length'))
43+
_request['body'] = json.loads(self.rfile.read(content_len))
44+
_request['headers'] = self.headers
45+
46+
def get_response(self):
47+
if success:
48+
return {'result': {'source': source}, 'wasSuccessful': 'true'}
49+
return {'wasSuccessful': 'false'}
50+
51+
env = EnvironmentVarGuard()
52+
env.set(_KAGGLE_USER_SECRETS_TOKEN_ENV_VAR_NAME, self.TEST_JWT)
53+
with env:
54+
with HTTPServer((self.SERVER_ADDRESS.hostname, self.SERVER_ADDRESS.port), GetKernelRunSourceForCaipHandler) as httpd:
55+
threading.Thread(target=httpd.serve_forever).start()
56+
57+
try:
58+
client_func()
59+
finally:
60+
httpd.shutdown()
61+
62+
path, headers, body = _request['path'], _request['headers'], _request['body']
63+
self.assertEqual(
64+
path,
65+
expected_path,
66+
msg="Fake server did not receive the right request from UserSessionClient.")
67+
self.assertEqual(
68+
body,
69+
expected_body,
70+
msg="Fake server did not receive the right body from UserSessionClient.")
71+
72+
def test_no_token_fails(self):
73+
env = EnvironmentVarGuard()
74+
env.unset(_KAGGLE_USER_SECRETS_TOKEN_ENV_VAR_NAME)
75+
with env:
76+
with self.assertRaises(CredentialError):
77+
client = UserSessionClient()
78+
79+
def test_get_exportable_ipynb_succeeds(self):
80+
source = "import foo"
81+
82+
def call_get_ipynb():
83+
client = UserSessionClient()
84+
response = client.get_exportable_ipynb()
85+
self.assertEqual(source, response['source'])
86+
87+
self._test_client(
88+
call_get_ipynb,
89+
'/requests/GetKernelRunSourceForCaipRequest',
90+
{'UseDraft': True},
91+
source=source,
92+
success=True)
93+
94+
def test_get_exportable_ipynb_fails(self):
95+
def call_get_ipynb():
96+
client = UserSessionClient()
97+
with self.assertRaises(BackendError):
98+
client.get_exportable_ipynb()
99+
100+
self._test_client(
101+
call_get_ipynb,
102+
'/requests/GetKernelRunSourceForCaipRequest',
103+
{'UseDraft': True},
104+
success=False)

0 commit comments

Comments
 (0)