kleinkram 0.0.112__py3-none-any.whl → 0.0.114__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.
Potentially problematic release.
This version of kleinkram might be problematic. Click here for more details.
- kleinkram/auth.py +7 -4
- kleinkram/helper.py +4 -4
- kleinkram/main.py +177 -78
- {kleinkram-0.0.112.dist-info → kleinkram-0.0.114.dist-info}/METADATA +1 -1
- kleinkram-0.0.114.dist-info/RECORD +10 -0
- kleinkram-0.0.112.dist-info/RECORD +0 -10
- {kleinkram-0.0.112.dist-info → kleinkram-0.0.114.dist-info}/WHEEL +0 -0
- {kleinkram-0.0.112.dist-info → kleinkram-0.0.114.dist-info}/entry_points.txt +0 -0
- {kleinkram-0.0.112.dist-info → kleinkram-0.0.114.dist-info}/licenses/LICENSE +0 -0
kleinkram/auth.py
CHANGED
|
@@ -63,7 +63,6 @@ class OAuthCallbackHandler(BaseHTTPRequestHandler):
|
|
|
63
63
|
if self.path.startswith("/cli/callback"):
|
|
64
64
|
query = urllib.parse.urlparse(self.path).query
|
|
65
65
|
params = urllib.parse.parse_qs(query)
|
|
66
|
-
print(params)
|
|
67
66
|
self.server.tokens = {
|
|
68
67
|
AUTH_TOKEN: params.get(AUTH_TOKEN)[0],
|
|
69
68
|
REFRESH_TOKEN: params.get(REFRESH_TOKEN)[0],
|
|
@@ -108,10 +107,9 @@ class AuthenticatedClient(httpx.Client):
|
|
|
108
107
|
if not refresh_token:
|
|
109
108
|
print("No refresh token found. Please login again.")
|
|
110
109
|
raise Exception("No refresh token found.")
|
|
111
|
-
|
|
110
|
+
self.cookies.set(REFRESH_TOKEN, refresh_token,)
|
|
112
111
|
response = self.post(
|
|
113
112
|
"/auth/refresh-token",
|
|
114
|
-
json={REFRESH_TOKEN: refresh_token},
|
|
115
113
|
)
|
|
116
114
|
response.raise_for_status()
|
|
117
115
|
new_access_token = response.cookies.get(AUTH_TOKEN)
|
|
@@ -132,7 +130,7 @@ class AuthenticatedClient(httpx.Client):
|
|
|
132
130
|
if response.status_code == 401:
|
|
133
131
|
print("Token expired, refreshing token...")
|
|
134
132
|
self.refresh_token()
|
|
135
|
-
response = super().request(method, url, *args, **kwargs)
|
|
133
|
+
response = super().request(method, self.tokenfile.endpoint + url, *args, **kwargs)
|
|
136
134
|
return response
|
|
137
135
|
|
|
138
136
|
|
|
@@ -163,3 +161,8 @@ def endpoint(endpoint: Annotated[str, typer.Argument()]):
|
|
|
163
161
|
tokenfile = TokenFile()
|
|
164
162
|
tokenfile.endpoint = endpoint
|
|
165
163
|
tokenfile.writeToFile()
|
|
164
|
+
|
|
165
|
+
def setCliKey(key: Annotated[str, typer.Argument()]):
|
|
166
|
+
tokenfile = TokenFile()
|
|
167
|
+
tokenfile.tokens[tokenfile.endpoint][CLI_KEY] = key
|
|
168
|
+
tokenfile.writeToFile()
|
kleinkram/helper.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import fnmatch
|
|
2
|
-
import math
|
|
3
1
|
import os
|
|
4
2
|
import threading
|
|
5
3
|
import glob
|
|
@@ -45,7 +43,9 @@ def uploadFiles(files: Dict[str, str], paths: Dict[str, str], nrThreads: int):
|
|
|
45
43
|
def uploadFile(_queue: queue.Queue, paths: Dict[str, str], pbar: tqdm):
|
|
46
44
|
while True:
|
|
47
45
|
try:
|
|
48
|
-
filename,
|
|
46
|
+
filename, info = _queue.get(timeout=3)
|
|
47
|
+
url = info["url"]
|
|
48
|
+
uuid = info["uuid"]
|
|
49
49
|
filepath = paths[filename]
|
|
50
50
|
headers = {"Content-Type": "application/octet-stream"}
|
|
51
51
|
with open(filepath, "rb") as f:
|
|
@@ -54,7 +54,7 @@ def uploadFile(_queue: queue.Queue, paths: Dict[str, str], pbar: tqdm):
|
|
|
54
54
|
response = cli.put(url, content=f, headers=headers)
|
|
55
55
|
if response.status_code == 200:
|
|
56
56
|
pbar.update(100) # Update progress for each file
|
|
57
|
-
client.post("/queue/confirmUpload", json={"
|
|
57
|
+
client.post("/queue/confirmUpload", json={"uuid": uuid})
|
|
58
58
|
else:
|
|
59
59
|
print(f"Failed to upload {filename}. HTTP status: {response.status_code}")
|
|
60
60
|
_queue.task_done()
|
kleinkram/main.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
1
2
|
import os
|
|
2
3
|
|
|
3
4
|
import httpx
|
|
@@ -9,34 +10,40 @@ from rich.table import Table
|
|
|
9
10
|
|
|
10
11
|
from .helper import uploadFiles, expand_and_match
|
|
11
12
|
|
|
12
|
-
from .auth import login, client, endpoint
|
|
13
|
+
from .auth import login, client, endpoint, setCliKey
|
|
13
14
|
|
|
14
15
|
app = typer.Typer()
|
|
15
16
|
projects = typer.Typer(name="projects")
|
|
16
|
-
|
|
17
|
+
missions = typer.Typer(name="missions")
|
|
17
18
|
files = typer.Typer(name="files")
|
|
18
19
|
topics = typer.Typer(name="topics")
|
|
19
20
|
queue = typer.Typer(name="queue")
|
|
20
21
|
user = typer.Typer(name="users")
|
|
22
|
+
tagtypes = typer.Typer(name="tagtypes")
|
|
23
|
+
tag = typer.Typer(name="tag")
|
|
24
|
+
|
|
21
25
|
|
|
22
26
|
app.add_typer(projects)
|
|
23
|
-
app.add_typer(
|
|
27
|
+
app.add_typer(missions)
|
|
24
28
|
app.add_typer(topics)
|
|
25
29
|
app.add_typer(files)
|
|
26
30
|
app.add_typer(queue)
|
|
27
31
|
app.add_typer(user)
|
|
32
|
+
app.add_typer(tagtypes)
|
|
33
|
+
app.add_typer(tag)
|
|
28
34
|
app.command()(login)
|
|
29
35
|
app.command()(endpoint)
|
|
36
|
+
app.command()(setCliKey)
|
|
30
37
|
|
|
31
38
|
|
|
32
39
|
@files.command("list")
|
|
33
40
|
def list_files(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
project: Annotated[str, typer.Option()] = None,
|
|
42
|
+
mission: Annotated[str, typer.Option()] = None,
|
|
43
|
+
topics: Annotated[List[str], typer.Option()] = None,
|
|
37
44
|
):
|
|
38
45
|
"""
|
|
39
|
-
List all files with optional filters for project,
|
|
46
|
+
List all files with optional filters for project, mission, or topics.
|
|
40
47
|
"""
|
|
41
48
|
try:
|
|
42
49
|
url = f"/file/filteredByNames"
|
|
@@ -44,36 +51,36 @@ def list_files(
|
|
|
44
51
|
url,
|
|
45
52
|
params={
|
|
46
53
|
"projectName": project,
|
|
47
|
-
"
|
|
54
|
+
"missionName": mission,
|
|
48
55
|
"topics": topics,
|
|
49
56
|
},
|
|
50
57
|
)
|
|
51
58
|
response.raise_for_status()
|
|
52
59
|
data = response.json()
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
missions_by_project_uuid = {}
|
|
61
|
+
files_by_mission_uuid = {}
|
|
55
62
|
for file in data:
|
|
56
|
-
|
|
57
|
-
project_uuid = file["
|
|
58
|
-
if project_uuid not in
|
|
59
|
-
|
|
60
|
-
if
|
|
61
|
-
|
|
62
|
-
if
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
print("Files by
|
|
67
|
-
for project_uuid,
|
|
68
|
-
first_file =
|
|
69
|
-
print(f"* {first_file['
|
|
70
|
-
for
|
|
71
|
-
print(f" - {
|
|
72
|
-
for file in
|
|
63
|
+
mission_uuid = file["mission"]["uuid"]
|
|
64
|
+
project_uuid = file["mission"]["project"]["uuid"]
|
|
65
|
+
if project_uuid not in missions_by_project_uuid:
|
|
66
|
+
missions_by_project_uuid[project_uuid] = []
|
|
67
|
+
if mission_uuid not in missions_by_project_uuid[project_uuid]:
|
|
68
|
+
missions_by_project_uuid[project_uuid].append(mission_uuid)
|
|
69
|
+
if mission_uuid not in files_by_mission_uuid:
|
|
70
|
+
files_by_mission_uuid[mission_uuid] = []
|
|
71
|
+
files_by_mission_uuid[mission_uuid].append(file)
|
|
72
|
+
|
|
73
|
+
print("Files by mission & Project:")
|
|
74
|
+
for project_uuid, missions in missions_by_project_uuid.items():
|
|
75
|
+
first_file = files_by_mission_uuid[missions[0]][0]
|
|
76
|
+
print(f"* {first_file['mission']['project']['name']}")
|
|
77
|
+
for mission in missions:
|
|
78
|
+
print(f" - {files_by_mission_uuid[mission][0]['mission']['name']}")
|
|
79
|
+
for file in files_by_mission_uuid[mission]:
|
|
73
80
|
print(f" - '{file['filename']}'")
|
|
74
81
|
|
|
75
82
|
except httpx.HTTPError as e:
|
|
76
|
-
print(f"Failed to fetch
|
|
83
|
+
print(f"Failed to fetch missions: {e}")
|
|
77
84
|
|
|
78
85
|
|
|
79
86
|
@projects.command("list")
|
|
@@ -93,15 +100,16 @@ def list_projects():
|
|
|
93
100
|
print(f"Failed to fetch projects: {e}")
|
|
94
101
|
|
|
95
102
|
|
|
96
|
-
@
|
|
97
|
-
def
|
|
98
|
-
|
|
103
|
+
@missions.command("list")
|
|
104
|
+
def list_missions(
|
|
105
|
+
project: Annotated[str, typer.Option()] = None,
|
|
106
|
+
verbose: Annotated[bool, typer.Option()] = False,
|
|
99
107
|
):
|
|
100
108
|
"""
|
|
101
|
-
List all
|
|
109
|
+
List all missions with optional filter for project.
|
|
102
110
|
"""
|
|
103
111
|
try:
|
|
104
|
-
url = "/
|
|
112
|
+
url = "/mission"
|
|
105
113
|
if project:
|
|
106
114
|
url += f"/filteredByProjectName/{project}"
|
|
107
115
|
else:
|
|
@@ -109,45 +117,58 @@ def list_runs(
|
|
|
109
117
|
response = client.get(url)
|
|
110
118
|
response.raise_for_status()
|
|
111
119
|
data = response.json()
|
|
112
|
-
|
|
113
|
-
for
|
|
114
|
-
project_uuid =
|
|
115
|
-
if project_uuid not in
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
print("
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
missions_by_project_uuid = {}
|
|
121
|
+
for mission in data:
|
|
122
|
+
project_uuid = mission["project"]["uuid"]
|
|
123
|
+
if project_uuid not in missions_by_project_uuid:
|
|
124
|
+
missions_by_project_uuid[project_uuid] = []
|
|
125
|
+
missions_by_project_uuid[project_uuid].append(mission)
|
|
126
|
+
|
|
127
|
+
print("missions by Project:")
|
|
128
|
+
if not verbose:
|
|
129
|
+
for project_uuid, missions in missions_by_project_uuid.items():
|
|
130
|
+
print(f"* {missions_by_project_uuid[project_uuid][0]['project']['name']}")
|
|
131
|
+
for mission in missions:
|
|
132
|
+
print(f" - {mission['name']}")
|
|
133
|
+
else:
|
|
134
|
+
table = Table("UUID", "name", "project", "creator", "createdAt")
|
|
135
|
+
for project_uuid, missions in missions_by_project_uuid.items():
|
|
136
|
+
for mission in missions:
|
|
137
|
+
table.add_row(
|
|
138
|
+
mission["uuid"],
|
|
139
|
+
mission["name"],
|
|
140
|
+
mission["project"]["name"],
|
|
141
|
+
mission["creator"]["name"],
|
|
142
|
+
mission["createdAt"],
|
|
143
|
+
)
|
|
144
|
+
print(table)
|
|
124
145
|
|
|
125
146
|
except httpx.HTTPError as e:
|
|
126
|
-
print(f"Failed to fetch
|
|
147
|
+
print(f"Failed to fetch missions: {e}")
|
|
127
148
|
|
|
128
149
|
|
|
129
|
-
@
|
|
130
|
-
def
|
|
131
|
-
|
|
150
|
+
@missions.command("byUUID")
|
|
151
|
+
def mission_by_uuid(
|
|
152
|
+
uuid: Annotated[str, typer.Argument()],
|
|
132
153
|
):
|
|
133
154
|
try:
|
|
134
|
-
url = "/
|
|
155
|
+
url = "/mission/byUUID"
|
|
135
156
|
response = client.get(url, params={"uuid": uuid})
|
|
136
157
|
response.raise_for_status()
|
|
137
158
|
data = response.json()
|
|
138
|
-
print(f"
|
|
159
|
+
print(f"mission: {data['name']}")
|
|
139
160
|
print(f"Creator: {data['creator']['name']}")
|
|
140
161
|
table = Table("Filename", "Size", "date")
|
|
141
162
|
for file in data["files"]:
|
|
142
163
|
table.add_row(file["filename"], f"{file['size']}", file["date"])
|
|
143
164
|
except httpx.HTTPError as e:
|
|
144
|
-
print(f"Failed to fetch
|
|
165
|
+
print(f"Failed to fetch missions: {e}")
|
|
145
166
|
|
|
146
167
|
|
|
147
168
|
@topics.command("list")
|
|
148
169
|
def topics(
|
|
149
|
-
|
|
150
|
-
|
|
170
|
+
file: Annotated[str, typer.Option()] = None,
|
|
171
|
+
full: Annotated[bool, typer.Option()] = False,
|
|
151
172
|
):
|
|
152
173
|
try:
|
|
153
174
|
url = "/file/byName"
|
|
@@ -187,12 +208,12 @@ def create_project(name: Annotated[str, typer.Option()]):
|
|
|
187
208
|
|
|
188
209
|
@app.command("upload")
|
|
189
210
|
def upload(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
211
|
+
path: Annotated[str, typer.Option(prompt=True)],
|
|
212
|
+
project: Annotated[str, typer.Option(prompt=True)],
|
|
213
|
+
mission: Annotated[str, typer.Option(prompt=True)],
|
|
193
214
|
):
|
|
194
215
|
files = expand_and_match(path)
|
|
195
|
-
filenames = list(map(lambda x: x.split("/")[-1], files))
|
|
216
|
+
filenames = list(map(lambda x: x.split("/")[-1], filter(lambda x: not os.path.isdir(x),files)))
|
|
196
217
|
filepaths = {}
|
|
197
218
|
for path in files:
|
|
198
219
|
if not os.path.isdir(path):
|
|
@@ -209,31 +230,32 @@ def upload(
|
|
|
209
230
|
print(f"Project not found: {project}")
|
|
210
231
|
return
|
|
211
232
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if
|
|
216
|
-
|
|
217
|
-
if
|
|
233
|
+
get_mission_url = "/mission/byName"
|
|
234
|
+
mission_response = client.get(get_mission_url, params={"name": mission})
|
|
235
|
+
mission_response.raise_for_status()
|
|
236
|
+
if mission_response.content:
|
|
237
|
+
mission_json = mission_response.json()
|
|
238
|
+
if mission_json["uuid"]:
|
|
218
239
|
print(
|
|
219
|
-
f"
|
|
240
|
+
f"mission: {mission_json['uuid']} already exists. Delete it or select another name."
|
|
220
241
|
)
|
|
221
242
|
return
|
|
222
243
|
print(f"Something failed, should not happen")
|
|
223
244
|
return
|
|
224
245
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
246
|
+
create_mission_url = "/mission/create"
|
|
247
|
+
new_mission = client.post(
|
|
248
|
+
create_mission_url, json={"name": mission, "projectUUID": project_json["uuid"]}
|
|
228
249
|
)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
print(f"Created
|
|
250
|
+
new_mission.raise_for_status()
|
|
251
|
+
new_mission_data = new_mission.json()
|
|
252
|
+
print(f"Created mission: {new_mission_data['name']}")
|
|
232
253
|
|
|
233
254
|
get_presigned_url = "/queue/createPreSignedURLS"
|
|
255
|
+
|
|
234
256
|
response_2 = client.post(
|
|
235
257
|
get_presigned_url,
|
|
236
|
-
json={"filenames": filenames, "
|
|
258
|
+
json={"filenames": filenames, "missionUUID": new_mission_data["uuid"]},
|
|
237
259
|
)
|
|
238
260
|
response_2.raise_for_status()
|
|
239
261
|
presigned_urls = response_2.json()
|
|
@@ -260,6 +282,31 @@ def clear_queue():
|
|
|
260
282
|
print("Operation cancelled.")
|
|
261
283
|
|
|
262
284
|
|
|
285
|
+
@queue.command("list")
|
|
286
|
+
def list_queue():
|
|
287
|
+
"""List current Queue entities"""
|
|
288
|
+
try:
|
|
289
|
+
url = "/queue/active"
|
|
290
|
+
startDate = datetime.now().date() - timedelta(days=1)
|
|
291
|
+
response = client.get(url, params={"startDate": startDate})
|
|
292
|
+
response.raise_for_status()
|
|
293
|
+
data = response.json()
|
|
294
|
+
table = Table("UUID", "filename", "mission", "state", "origin", "createdAt")
|
|
295
|
+
for topic in data:
|
|
296
|
+
table.add_row(
|
|
297
|
+
topic["uuid"],
|
|
298
|
+
topic["filename"],
|
|
299
|
+
topic["mission"]["name"],
|
|
300
|
+
topic["state"],
|
|
301
|
+
topic["location"],
|
|
302
|
+
topic["createdAt"],
|
|
303
|
+
)
|
|
304
|
+
print(table)
|
|
305
|
+
|
|
306
|
+
except httpx.HTTPError as e:
|
|
307
|
+
print(e)
|
|
308
|
+
|
|
309
|
+
|
|
263
310
|
@files.command("clear")
|
|
264
311
|
def clear_queue():
|
|
265
312
|
"""Clear queue"""
|
|
@@ -289,7 +336,7 @@ def wipe():
|
|
|
289
336
|
response_queue = client.delete("/queue/clear")
|
|
290
337
|
response_file = client.delete("/file/clear")
|
|
291
338
|
response_analysis = client.delete("/analysis/clear")
|
|
292
|
-
|
|
339
|
+
response_mission = client.delete("/mission/clear")
|
|
293
340
|
response_project = client.delete("/project/clear")
|
|
294
341
|
|
|
295
342
|
if response_queue.status_code >= 400:
|
|
@@ -301,9 +348,9 @@ def wipe():
|
|
|
301
348
|
elif response_analysis.status_code >= 400:
|
|
302
349
|
print("Failed to clear analysis.")
|
|
303
350
|
print(response_analysis.text)
|
|
304
|
-
elif
|
|
305
|
-
print("Failed to clear
|
|
306
|
-
print(
|
|
351
|
+
elif response_mission.status_code >= 400:
|
|
352
|
+
print("Failed to clear missions.")
|
|
353
|
+
print(response_mission.text)
|
|
307
354
|
elif response_project.status_code >= 400:
|
|
308
355
|
print("Failed to clear projects.")
|
|
309
356
|
print(response_project.text)
|
|
@@ -355,15 +402,67 @@ def demote(email: Annotated[str, typer.Option()]):
|
|
|
355
402
|
|
|
356
403
|
@files.command("download")
|
|
357
404
|
def download(
|
|
358
|
-
|
|
405
|
+
missionuuid: Annotated[str, typer.Argument()],
|
|
359
406
|
):
|
|
360
407
|
try:
|
|
361
|
-
response = client.get("/file/downloadWithToken", params={"uuid":
|
|
408
|
+
response = client.get("/file/downloadWithToken", params={"uuid": missionuuid})
|
|
362
409
|
response.raise_for_status()
|
|
363
410
|
print(response.json())
|
|
364
411
|
except:
|
|
365
412
|
print("Failed to download file")
|
|
366
413
|
|
|
414
|
+
@missions.command('tag')
|
|
415
|
+
def addTag(
|
|
416
|
+
missionuuid: Annotated[str, typer.Argument()],
|
|
417
|
+
tagtypeuuid: Annotated[str, typer.Argument()],
|
|
418
|
+
value: Annotated[str, typer.Argument()],
|
|
419
|
+
):
|
|
420
|
+
try:
|
|
421
|
+
response = client.post("/tag/addTag", json={"mission": missionuuid, "tagType": tagtypeuuid, "value": value})
|
|
422
|
+
if response.status_code < 400:
|
|
423
|
+
print("Tagged mission")
|
|
424
|
+
else:
|
|
425
|
+
print(response.json())
|
|
426
|
+
print("Failed to tag mission")
|
|
427
|
+
except:
|
|
428
|
+
print("Failed to tag mission"
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
@tagtypes.command('list')
|
|
432
|
+
def tagTypes(
|
|
433
|
+
verbose: Annotated[bool, typer.Option()] = False,
|
|
434
|
+
):
|
|
435
|
+
try:
|
|
436
|
+
response = client.get("/tag/all")
|
|
437
|
+
response.raise_for_status()
|
|
438
|
+
data = response.json()
|
|
439
|
+
if verbose:
|
|
440
|
+
table = Table("UUID","Name", "Datatype")
|
|
441
|
+
for tagtype in data:
|
|
442
|
+
table.add_row(tagtype["uuid"], tagtype["name"], tagtype["datatype"])
|
|
443
|
+
else:
|
|
444
|
+
table = Table("Name", "Datatype")
|
|
445
|
+
for tagtype in data:
|
|
446
|
+
table.add_row(tagtype["name"], tagtype["datatype"])
|
|
447
|
+
print(table)
|
|
448
|
+
except:
|
|
449
|
+
print("Failed to fetch tagtypes")
|
|
450
|
+
|
|
451
|
+
@tag.command('delete')
|
|
452
|
+
def deleteTag(
|
|
453
|
+
taguuid: Annotated[str, typer.Argument()],
|
|
454
|
+
):
|
|
455
|
+
try:
|
|
456
|
+
response = client.delete("/tag/deleteTag", params={"uuid": taguuid})
|
|
457
|
+
if response.status_code < 400:
|
|
458
|
+
print("Deleted tag")
|
|
459
|
+
else:
|
|
460
|
+
print(response)
|
|
461
|
+
print("Failed to delete tag")
|
|
462
|
+
except:
|
|
463
|
+
print("Failed to delete tag"
|
|
464
|
+
)
|
|
465
|
+
|
|
367
466
|
|
|
368
467
|
if __name__ == "__main__":
|
|
369
468
|
app()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
kleinkram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
kleinkram/auth.py,sha256=IpAmvmjzDj_x6M3TNqcxNGGRn6LJaQS_Iay2MOWoJGs,5242
|
|
3
|
+
kleinkram/consts.py,sha256=8kCOeSdMqEyB89hT55w5yd1fksUwbj52a2nYkZTZI_0,88
|
|
4
|
+
kleinkram/helper.py,sha256=mP6AohHWU8kckAi1Oevgs0gfGPH1Qzkp0f7jiQF9u5I,2198
|
|
5
|
+
kleinkram/main.py,sha256=7TKP6RPbhtQCydE4aQtGP0GbwoaOLr1A6iK1NXTZmXQ,15068
|
|
6
|
+
kleinkram-0.0.114.dist-info/METADATA,sha256=XJ5EvSh72UWukdtV4flnEJJXPBu0faOM14IW20YxL7c,733
|
|
7
|
+
kleinkram-0.0.114.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
8
|
+
kleinkram-0.0.114.dist-info/entry_points.txt,sha256=RHXtRzcreVHImatgjhQwZQ6GdJThElYjHEWcR1BPXUI,45
|
|
9
|
+
kleinkram-0.0.114.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
|
10
|
+
kleinkram-0.0.114.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
kleinkram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
kleinkram/auth.py,sha256=Roe7UF9TI4-X0_Dy3UaO4R2yHVqRKu4AOJJfWpj1CBQ,5069
|
|
3
|
-
kleinkram/consts.py,sha256=8kCOeSdMqEyB89hT55w5yd1fksUwbj52a2nYkZTZI_0,88
|
|
4
|
-
kleinkram/helper.py,sha256=86KNbLmzWLFb9zn41VNL3_BK64pNU74ae8uVNsjDYHQ,2170
|
|
5
|
-
kleinkram/main.py,sha256=JAOKtNksVLWAVOxJc2OxBzB8NZpFLLp1NUZdN6GLk_o,11466
|
|
6
|
-
kleinkram-0.0.112.dist-info/METADATA,sha256=mKs8k7FJUX0GLzPPFwjNM8Rajy2zMeSUs90hoUqnEYo,733
|
|
7
|
-
kleinkram-0.0.112.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
8
|
-
kleinkram-0.0.112.dist-info/entry_points.txt,sha256=RHXtRzcreVHImatgjhQwZQ6GdJThElYjHEWcR1BPXUI,45
|
|
9
|
-
kleinkram-0.0.112.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
|
10
|
-
kleinkram-0.0.112.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|