sunholo 0.60.3__py3-none-any.whl → 0.60.4__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.
- sunholo/cli/chat_vac.py +44 -28
- sunholo/cli/cli.py +3 -9
- sunholo/cli/run_proxy.py +6 -5
- sunholo/database/alloydb.py +50 -0
- sunholo/streaming/langserve.py +2 -2
- {sunholo-0.60.3.dist-info → sunholo-0.60.4.dist-info}/METADATA +2 -2
- {sunholo-0.60.3.dist-info → sunholo-0.60.4.dist-info}/RECORD +11 -11
- {sunholo-0.60.3.dist-info → sunholo-0.60.4.dist-info}/LICENSE.txt +0 -0
- {sunholo-0.60.3.dist-info → sunholo-0.60.4.dist-info}/WHEEL +0 -0
- {sunholo-0.60.3.dist-info → sunholo-0.60.4.dist-info}/entry_points.txt +0 -0
- {sunholo-0.60.3.dist-info → sunholo-0.60.4.dist-info}/top_level.txt +0 -0
sunholo/cli/chat_vac.py
CHANGED
|
@@ -3,7 +3,7 @@ from ..streaming import generate_proxy_stream
|
|
|
3
3
|
from ..utils.user_ids import generate_user_id
|
|
4
4
|
from ..utils.config import load_config_key
|
|
5
5
|
|
|
6
|
-
from .run_proxy import clean_proxy_list, start_proxy
|
|
6
|
+
from .run_proxy import clean_proxy_list, start_proxy, stop_proxy
|
|
7
7
|
|
|
8
8
|
import uuid
|
|
9
9
|
|
|
@@ -15,14 +15,17 @@ from rich.panel import Panel
|
|
|
15
15
|
from rich.text import Text
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def get_service_url(
|
|
18
|
+
def get_service_url(vac_name, project, region):
|
|
19
|
+
agent_name = load_config_key("agent", vac_name, kind="vacConfig")
|
|
19
20
|
proxies = clean_proxy_list()
|
|
20
|
-
if
|
|
21
|
-
port = proxies[
|
|
22
|
-
|
|
21
|
+
if agent_name in proxies:
|
|
22
|
+
port = proxies[agent_name]['port']
|
|
23
|
+
url = f"http://127.0.0.1:{port}"
|
|
23
24
|
else:
|
|
24
|
-
print(f"No proxy found running for service: {
|
|
25
|
-
|
|
25
|
+
print(f"No proxy found running for service: {agent_name} required for {vac_name} - attempting to connect")
|
|
26
|
+
url = start_proxy(agent_name, region, project)
|
|
27
|
+
|
|
28
|
+
return url
|
|
26
29
|
|
|
27
30
|
def stream_chat_session(service_name, project, region):
|
|
28
31
|
|
|
@@ -36,8 +39,6 @@ def stream_chat_session(service_name, project, region):
|
|
|
36
39
|
console.print("[bold red]Exiting chat session.[/bold red]")
|
|
37
40
|
break
|
|
38
41
|
|
|
39
|
-
chat_history.append({"role": "Human", "content": user_input})
|
|
40
|
-
|
|
41
42
|
def stream_response():
|
|
42
43
|
generate = generate_proxy_stream(
|
|
43
44
|
send_to_qa,
|
|
@@ -83,15 +84,16 @@ def stream_chat_session(service_name, project, region):
|
|
|
83
84
|
console.print(token, end='')
|
|
84
85
|
vac_response += token
|
|
85
86
|
|
|
86
|
-
chat_history.append({"
|
|
87
|
+
chat_history.append({"name": "Human", "content": user_input})
|
|
88
|
+
chat_history.append({"name": "AI", "content": vac_response})
|
|
87
89
|
response_started = False
|
|
88
90
|
console.print()
|
|
89
91
|
console.rule()
|
|
90
92
|
|
|
91
93
|
def headless_mode(service_name, user_input, project, region, chat_history=None):
|
|
92
94
|
chat_history = chat_history or []
|
|
93
|
-
|
|
94
|
-
service_url = get_service_url(project, region)
|
|
95
|
+
|
|
96
|
+
service_url = get_service_url(service_name, project, region)
|
|
95
97
|
user_id = generate_user_id()
|
|
96
98
|
session_id = str(uuid.uuid4())
|
|
97
99
|
|
|
@@ -124,13 +126,17 @@ def headless_mode(service_name, user_input, project, region, chat_history=None):
|
|
|
124
126
|
for part in generate():
|
|
125
127
|
yield part
|
|
126
128
|
|
|
127
|
-
|
|
129
|
+
vac_response = ""
|
|
130
|
+
|
|
128
131
|
for token in stream_response():
|
|
129
132
|
if isinstance(token, bytes):
|
|
130
133
|
token = token.decode('utf-8')
|
|
131
134
|
print(token, end='', flush=True)
|
|
135
|
+
vac_response += token
|
|
132
136
|
|
|
133
|
-
|
|
137
|
+
if vac_response:
|
|
138
|
+
chat_history.append({"name": "Human", "content": user_input})
|
|
139
|
+
chat_history.append({"name": "AI", "content": vac_response})
|
|
134
140
|
print() # For new line after streaming ends
|
|
135
141
|
|
|
136
142
|
return chat_history
|
|
@@ -138,24 +144,34 @@ def headless_mode(service_name, user_input, project, region, chat_history=None):
|
|
|
138
144
|
|
|
139
145
|
def vac_command(args):
|
|
140
146
|
try:
|
|
141
|
-
service_url = get_service_url(args.
|
|
147
|
+
service_url = get_service_url(args.vac_name, args.project, args.region)
|
|
142
148
|
except ValueError as e:
|
|
143
|
-
console.print(f"[bold red]ERROR: Could not start {args.
|
|
149
|
+
console.print(f"[bold red]ERROR: Could not start {args.vac_name} proxy URL: {str(e)}[/bold red]")
|
|
144
150
|
return
|
|
145
151
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
print(
|
|
150
|
-
Panel(description or "Starting VAC chat session",
|
|
151
|
-
title=display_name or args.service_name,
|
|
152
|
-
subtitle=service_url)
|
|
153
|
-
)
|
|
154
|
-
|
|
152
|
+
agent_name = load_config_key("agent", args.vac_name, kind="vacConfig")
|
|
153
|
+
|
|
155
154
|
if args.headless:
|
|
156
|
-
headless_mode(args.
|
|
155
|
+
headless_mode(args.vac_name, args.user_input, args.project, args.region, args.chat_history)
|
|
156
|
+
stop_proxy(agent_name)
|
|
157
157
|
else:
|
|
158
|
-
|
|
158
|
+
display_name = load_config_key("display_name", vector_name=args.vac_name, kind="vacConfig")
|
|
159
|
+
description = load_config_key("description", vector_name=args.vac_name, kind="vacConfig")
|
|
160
|
+
|
|
161
|
+
if agent_name == "langserve":
|
|
162
|
+
subtitle = f"{service_url}/{args.vac_name}/playground/"
|
|
163
|
+
else:
|
|
164
|
+
subtitle = f"{agent_name} - {service_url}/vac/{args.vac_name}"
|
|
165
|
+
|
|
166
|
+
print(
|
|
167
|
+
Panel(description or "Starting VAC chat session",
|
|
168
|
+
title=display_name or args.vac_name,
|
|
169
|
+
subtitle=subtitle)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
stream_chat_session(args.vac_name, args.project, args.region)
|
|
173
|
+
stop_proxy(agent_name)
|
|
174
|
+
|
|
159
175
|
|
|
160
176
|
def setup_vac_subparser(subparsers):
|
|
161
177
|
"""
|
|
@@ -165,7 +181,7 @@ def setup_vac_subparser(subparsers):
|
|
|
165
181
|
subparsers: The subparsers object from argparse.ArgumentParser().
|
|
166
182
|
"""
|
|
167
183
|
vac_parser = subparsers.add_parser('vac', help='Interact with deployed VAC services.')
|
|
168
|
-
vac_parser.add_argument('
|
|
184
|
+
vac_parser.add_argument('vac_name', help='Name of the VAC service.')
|
|
169
185
|
vac_parser.add_argument('user_input', help='User input for the VAC service when in headless mode.', nargs='?', default=None)
|
|
170
186
|
vac_parser.add_argument('--headless', action='store_true', help='Run in headless mode.')
|
|
171
187
|
vac_parser.add_argument('--chat_history', help='Chat history for headless mode (as JSON string).', default=None)
|
sunholo/cli/cli.py
CHANGED
|
@@ -11,13 +11,7 @@ from ..utils.config import load_config_key
|
|
|
11
11
|
|
|
12
12
|
from ..logging import log
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
from rich.console import Console
|
|
16
|
-
from rich.prompt import Prompt
|
|
17
|
-
from rich.spinner import Spinner
|
|
18
|
-
from rich.panel import Panel
|
|
19
|
-
from rich.text import Text
|
|
20
|
-
console = Console()
|
|
14
|
+
|
|
21
15
|
|
|
22
16
|
def load_default_gcp_config():
|
|
23
17
|
gcp_config = load_config_key('gcp_config', 'global', kind="vacConfig")
|
|
@@ -67,8 +61,8 @@ def main(args=None):
|
|
|
67
61
|
args = parser.parse_args(args)
|
|
68
62
|
|
|
69
63
|
if args.debug:
|
|
70
|
-
log.setLevel(logging.
|
|
71
|
-
logging.getLogger().setLevel(logging.
|
|
64
|
+
log.setLevel(logging.DEBUG)
|
|
65
|
+
logging.getLogger().setLevel(logging.DEBUG)
|
|
72
66
|
else:
|
|
73
67
|
log.setLevel(logging.WARNING)
|
|
74
68
|
logging.getLogger().setLevel(logging.WARNING)
|
sunholo/cli/run_proxy.py
CHANGED
|
@@ -52,7 +52,7 @@ def check_gcloud():
|
|
|
52
52
|
# Check if gcloud is installed
|
|
53
53
|
result = subprocess.run(["gcloud", "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30)
|
|
54
54
|
if result.returncode != 0:
|
|
55
|
-
print("ERROR: gcloud is not installed or not found in PATH.")
|
|
55
|
+
print("[bold red]ERROR: gcloud is not installed or not found in PATH.[/bold red]")
|
|
56
56
|
return False
|
|
57
57
|
|
|
58
58
|
# Check if gcloud is authenticated
|
|
@@ -239,8 +239,9 @@ def list_proxies():
|
|
|
239
239
|
"""
|
|
240
240
|
Lists all running proxies.
|
|
241
241
|
"""
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
with console.status("[bold orange]Listing Proxies[/bold orange]", spinner="star"):
|
|
243
|
+
proxies = clean_proxy_list()
|
|
244
|
+
|
|
244
245
|
if not proxies:
|
|
245
246
|
print("No proxies currently running.")
|
|
246
247
|
else:
|
|
@@ -264,10 +265,10 @@ def setup_proxy_subparser(subparsers):
|
|
|
264
265
|
subparsers: The subparsers object from argparse.ArgumentParser().
|
|
265
266
|
"""
|
|
266
267
|
|
|
267
|
-
proxy_parser = subparsers.add_parser('proxy', help='Set up or stop a proxy to the Cloud Run
|
|
268
|
+
proxy_parser = subparsers.add_parser('proxy', help='Set up or stop a proxy to the VAC Cloud Run services')
|
|
268
269
|
proxy_subparsers = proxy_parser.add_subparsers(dest='proxy_command', required=True)
|
|
269
270
|
|
|
270
|
-
start_parser = proxy_subparsers.add_parser('start', help='Start the proxy to the Cloud Run service
|
|
271
|
+
start_parser = proxy_subparsers.add_parser('start', help='Start the proxy to the VAC Cloud Run service')
|
|
271
272
|
start_parser.add_argument('service_name', help='Name of the Cloud Run service.')
|
|
272
273
|
start_parser.add_argument('--port', type=int, help='Port to run the proxy on. Auto-assigns if not provided.')
|
|
273
274
|
start_parser.set_defaults(func=lambda args: start_proxy(args.service_name, args.region, args.project, args.port))
|
sunholo/database/alloydb.py
CHANGED
|
@@ -171,6 +171,56 @@ class AlloyDBClient:
|
|
|
171
171
|
|
|
172
172
|
return self.execute_sql(query)
|
|
173
173
|
|
|
174
|
+
def create_database(self, database_name):
|
|
175
|
+
self.execute_sql(f'CREATE DATABASE "{database_name}"')
|
|
176
|
+
|
|
177
|
+
def fetch_owners(self):
|
|
178
|
+
owners = self.execute_sql('SELECT table_schema, table_name, privilege_type FROM information_schema.table_privileges')
|
|
179
|
+
for row in owners:
|
|
180
|
+
print(f"Schema: {row[0]}, Table: {row[1]}, Privilege: {row[2]}")
|
|
181
|
+
return owners
|
|
182
|
+
|
|
183
|
+
def create_schema(self, schema_name="public"):
|
|
184
|
+
self.execute_sql(f'CREATE SCHEMA IF NOT EXISTS {schema_name};')
|
|
185
|
+
|
|
186
|
+
def grant_permissions(self, schema_name, users):
|
|
187
|
+
for user in users:
|
|
188
|
+
self.execute_sql(f'GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA {schema_name} TO "{user}";')
|
|
189
|
+
self.execute_sql(f'GRANT USAGE, CREATE ON SCHEMA {schema_name} TO "{user}";')
|
|
190
|
+
self.execute_sql(f'ALTER DEFAULT PRIVILEGES IN SCHEMA {schema_name} GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "{user}";')
|
|
191
|
+
self.execute_sql(f'GRANT USAGE ON SCHEMA information_schema TO "{user}";')
|
|
192
|
+
self.execute_sql(f'GRANT SELECT ON information_schema.columns TO "{user}";')
|
|
193
|
+
|
|
194
|
+
def create_docstore_tables(self, vector_names, users):
|
|
195
|
+
for vector_name in vector_names:
|
|
196
|
+
table_name = f"{vector_name}_docstore"
|
|
197
|
+
sql = f'''
|
|
198
|
+
CREATE TABLE IF NOT EXISTS "{table_name}"
|
|
199
|
+
(page_content TEXT, doc_id UUID, source TEXT, images_gsurls JSONB, chunk_metadata JSONB, langchain_metadata JSONB)
|
|
200
|
+
'''
|
|
201
|
+
self.execute_sql(sql)
|
|
202
|
+
|
|
203
|
+
for user in users:
|
|
204
|
+
self.execute_sql(f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "{table_name}" TO "{user}";')
|
|
205
|
+
|
|
206
|
+
vectorstore_id = f"{vector_name}_vectorstore_1536"
|
|
207
|
+
sql = f'''
|
|
208
|
+
CREATE TABLE IF NOT EXISTS "{vectorstore_id}" (
|
|
209
|
+
langchain_id UUID NOT NULL,
|
|
210
|
+
content TEXT NOT NULL,
|
|
211
|
+
embedding vector NOT NULL,
|
|
212
|
+
source TEXT,
|
|
213
|
+
langchain_metadata JSONB,
|
|
214
|
+
docstore_doc_id UUID,
|
|
215
|
+
eventTime TIMESTAMPTZ
|
|
216
|
+
);
|
|
217
|
+
'''
|
|
218
|
+
self.execute_sql(sql)
|
|
219
|
+
|
|
220
|
+
for user in users:
|
|
221
|
+
self.execute_sql(f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE {vectorstore_id} TO "{user}";')
|
|
222
|
+
|
|
223
|
+
|
|
174
224
|
alloydb_table_cache = {} # Our cache, initially empty # noqa: F841
|
|
175
225
|
def create_alloydb_table(vector_name, engine, type = "vectorstore", alloydb_config=None, username=None):
|
|
176
226
|
global alloydb_table_cache
|
sunholo/streaming/langserve.py
CHANGED
|
@@ -157,8 +157,8 @@ def parse_json_data(json_data: dict):
|
|
|
157
157
|
"""
|
|
158
158
|
try:
|
|
159
159
|
if isinstance(json_data, dict):
|
|
160
|
-
content = json_data.get('content')
|
|
161
|
-
if content:
|
|
160
|
+
content = json_data.get('content', None)
|
|
161
|
+
if content is not None: # content can be '' empty string
|
|
162
162
|
#log.debug(f'Yield content: {content}')
|
|
163
163
|
yield content
|
|
164
164
|
else:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sunholo
|
|
3
|
-
Version: 0.60.
|
|
3
|
+
Version: 0.60.4
|
|
4
4
|
Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
|
|
5
5
|
Home-page: https://github.com/sunholo-data/sunholo-py
|
|
6
|
-
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.60.
|
|
6
|
+
Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.60.4.tar.gz
|
|
7
7
|
Author: Holosun ApS
|
|
8
8
|
Author-email: multivac@sunholo.com
|
|
9
9
|
License: Apache License, Version 2.0
|
|
@@ -32,13 +32,13 @@ sunholo/chunker/pdfs.py,sha256=daCZ1xjn1YvxlifIyxskWNpLJLe-Q9D_Jq12MWx3tZo,2473
|
|
|
32
32
|
sunholo/chunker/publish.py,sha256=PoT8q3XJeFCg10WrLkYhuaaXIrGVkvUD3-R9IfoWoH4,2703
|
|
33
33
|
sunholo/chunker/splitter.py,sha256=FLkDhkePkg_zGQpFBK13Cznw575D-Rf9pcaCpc1HUxY,6726
|
|
34
34
|
sunholo/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
-
sunholo/cli/chat_vac.py,sha256=
|
|
36
|
-
sunholo/cli/cli.py,sha256=
|
|
35
|
+
sunholo/cli/chat_vac.py,sha256=038AkvGDEK5cBWqQTRrTQYCsa1FDWzZGHaHOyrS2lFE,6841
|
|
36
|
+
sunholo/cli/cli.py,sha256=LWA5OveHx3ocy9KD1XwAwosBFrTUwifArIbltYgpul4,2420
|
|
37
37
|
sunholo/cli/cli_init.py,sha256=JMZ9AX2cPDZ-_mv3adiv2ToFVNyRPtjk9Biszl1kiR0,2358
|
|
38
38
|
sunholo/cli/configs.py,sha256=QUM9DvKOdZmEQRM5uI3Nh887T0YDiSMr7O240zTLqws,4546
|
|
39
39
|
sunholo/cli/deploy.py,sha256=zxdwUsRTRMC8U5vyRv0JiKBLFn84Ug_Tc88-_h9hJSs,1609
|
|
40
40
|
sunholo/cli/merge_texts.py,sha256=U9vdMwKmcPoc6iPOWX5MKSxn49dNGbNzVLw8ui5PhEU,1823
|
|
41
|
-
sunholo/cli/run_proxy.py,sha256=
|
|
41
|
+
sunholo/cli/run_proxy.py,sha256=kYi3LnMdi27IqzA-k37WyT8AnFifn5ePP7jNK-8UmhE,9694
|
|
42
42
|
sunholo/cli/sun_rich.py,sha256=UpMqeJ0C8i0pkue1AHnnyyX0bFJ9zZeJ7HBR6yhuA8A,54
|
|
43
43
|
sunholo/components/__init__.py,sha256=RJGNEihwvRIiDScKis04RHJv4yZGI1UpXlOmuCptNZI,208
|
|
44
44
|
sunholo/components/llm.py,sha256=T4we3tGmqUj4tPwxQr9M6AXv_BALqZV_dRSvINan-oU,10374
|
|
@@ -46,7 +46,7 @@ sunholo/components/prompt.py,sha256=eZSghXkIlRzXiSrzgkG7e5ytUYq6R6LV-qjHU8jStig,
|
|
|
46
46
|
sunholo/components/retriever.py,sha256=_Lyt9RIgb2PD-rhV6oKAadiUs3ukT5uAYGW197tEskw,3755
|
|
47
47
|
sunholo/components/vectorstore.py,sha256=dzspqOBtuxSjCFxem5_50sqwUUjbZ4oBYERtCwxZR6E,5619
|
|
48
48
|
sunholo/database/__init__.py,sha256=Zz0Shcq-CtStf9rJGIYB_Ybzb8rY_Q9mfSj-nviM490,241
|
|
49
|
-
sunholo/database/alloydb.py,sha256=
|
|
49
|
+
sunholo/database/alloydb.py,sha256=0zRLyeC9nACzj3v36ET9NqLeuzdwBJ2bE09CzgVTTFM,17098
|
|
50
50
|
sunholo/database/database.py,sha256=doY05kG8BZBLL-arh4hq5ef1ouWOtGHqdsDc6M2YHgk,7345
|
|
51
51
|
sunholo/database/lancedb.py,sha256=WSrbY5mgyeXx6i7UBiz4YQ_i5UIYVYFo-vPGO72bQKY,707
|
|
52
52
|
sunholo/database/static_dbs.py,sha256=aOyU3AJ-Dzz3qSNjbuN2293cfYw5PhkcQuQxdwPMJ4w,435
|
|
@@ -83,7 +83,7 @@ sunholo/qna/parsers.py,sha256=mH_SIgN2yXzvcoQZt9ITkdJSw3jgZGuu0p8q_H-kdSM,2140
|
|
|
83
83
|
sunholo/qna/retry.py,sha256=gFgOf9AxrZMIO9OwOYu1EW7rhNhyfnw_o4XAsNLBOVQ,2021
|
|
84
84
|
sunholo/streaming/__init__.py,sha256=k8dBqhzyS1Oi6NfADtRtWfnPtU1FU2kQz-YxH9yrNeQ,197
|
|
85
85
|
sunholo/streaming/content_buffer.py,sha256=fWcg0oTf470M3U40VAChfmHmWRFgRD8VaT90jNfBCH0,6455
|
|
86
|
-
sunholo/streaming/langserve.py,sha256=
|
|
86
|
+
sunholo/streaming/langserve.py,sha256=4AeNt4FPv461s20_5q17Nx83cHjK7Dl3gVOcWAxMgOk,6350
|
|
87
87
|
sunholo/streaming/streaming.py,sha256=9z6pXINEopuL_Z1RnmgXAoZJum9dzyuOxqYtEYnjf8w,16405
|
|
88
88
|
sunholo/summarise/__init__.py,sha256=MZk3dblUMODcPb1crq4v-Z508NrFIpkSWNf9FIO8BcU,38
|
|
89
89
|
sunholo/summarise/summarise.py,sha256=C3HhjepTjUhUC8FLk4jMQIBvq1BcORniwuTFHjPVhVo,3784
|
|
@@ -96,9 +96,9 @@ sunholo/utils/parsers.py,sha256=OrHmASqIbI45atVOhiGodgLvnfrzkvVzyHnSvAXD89I,3841
|
|
|
96
96
|
sunholo/utils/user_ids.py,sha256=SQd5_H7FE7vcTZp9AQuQDWBXd4FEEd7TeVMQe1H4Ny8,292
|
|
97
97
|
sunholo/vertex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
98
98
|
sunholo/vertex/init_vertex.py,sha256=JDMUaBRdednzbKF-5p33qqLit2LMsvgvWW-NRz0AqO0,1801
|
|
99
|
-
sunholo-0.60.
|
|
100
|
-
sunholo-0.60.
|
|
101
|
-
sunholo-0.60.
|
|
102
|
-
sunholo-0.60.
|
|
103
|
-
sunholo-0.60.
|
|
104
|
-
sunholo-0.60.
|
|
99
|
+
sunholo-0.60.4.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
|
100
|
+
sunholo-0.60.4.dist-info/METADATA,sha256=nHPHNqcRw2WAX2guIAM0QXFVcQLx3FzlB024g-jfK4k,8057
|
|
101
|
+
sunholo-0.60.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
102
|
+
sunholo-0.60.4.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
|
103
|
+
sunholo-0.60.4.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
|
104
|
+
sunholo-0.60.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|