sapiopycommons 2025.10.2a773__py3-none-any.whl → 2025.10.9a776__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 sapiopycommons might be problematic. Click here for more details.
- sapiopycommons/ai/{tool_service_base.py → agent_service_base.py} +127 -127
- sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.py +41 -0
- sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.pyi +35 -0
- sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2_grpc.py +24 -0
- sapiopycommons/ai/protoapi/plan/script/script_pb2.py +17 -15
- sapiopycommons/ai/protoapi/plan/script/script_pb2.pyi +10 -4
- sapiopycommons/ai/protoapi/plan/tool/tool_pb2.py +29 -27
- sapiopycommons/ai/protoapi/plan/tool/tool_pb2.pyi +14 -6
- sapiopycommons/ai/request_validation.py +40 -21
- sapiopycommons/ai/server.py +11 -11
- sapiopycommons/ai/test_client.py +26 -23
- sapiopycommons/files/temp_files.py +1 -1
- {sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/METADATA +1 -1
- {sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/RECORD +16 -13
- {sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/WHEEL +0 -0
- {sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/licenses/LICENSE +0 -0
sapiopycommons/ai/server.py
CHANGED
|
@@ -12,7 +12,7 @@ from sapiopycommons.ai.protoapi.plan.converter.converter_pb2_grpc import add_Con
|
|
|
12
12
|
from sapiopycommons.ai.protoapi.plan.script.script_pb2_grpc import add_ScriptServiceServicer_to_server, \
|
|
13
13
|
ScriptServiceServicer
|
|
14
14
|
from sapiopycommons.ai.protoapi.plan.tool.tool_pb2_grpc import add_ToolServiceServicer_to_server, ToolServiceServicer
|
|
15
|
-
from sapiopycommons.ai.
|
|
15
|
+
from sapiopycommons.ai.agent_service_base import AgentServiceBase
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class SapioGrpcServer:
|
|
@@ -24,7 +24,7 @@ class SapioGrpcServer:
|
|
|
24
24
|
debug_mode: bool
|
|
25
25
|
_converter_services: list[ConverterServiceServicer]
|
|
26
26
|
_script_services: list[ScriptServiceServicer]
|
|
27
|
-
|
|
27
|
+
_agent_services: list[ToolServiceServicer]
|
|
28
28
|
|
|
29
29
|
@staticmethod
|
|
30
30
|
def args_parser() -> ArgumentParser:
|
|
@@ -68,7 +68,7 @@ class SapioGrpcServer:
|
|
|
68
68
|
print("Debug mode is enabled.")
|
|
69
69
|
self._converter_services = []
|
|
70
70
|
self._script_services = []
|
|
71
|
-
self.
|
|
71
|
+
self._agent_services = []
|
|
72
72
|
|
|
73
73
|
def update_message_size(self, message_mb_size: int) -> None:
|
|
74
74
|
"""
|
|
@@ -97,22 +97,22 @@ class SapioGrpcServer:
|
|
|
97
97
|
"""
|
|
98
98
|
self._script_services.append(service)
|
|
99
99
|
|
|
100
|
-
def
|
|
100
|
+
def add_agent_service(self, service: AgentServiceBase) -> None:
|
|
101
101
|
"""
|
|
102
|
-
Add
|
|
102
|
+
Add an agent service to the gRPC server.
|
|
103
103
|
|
|
104
|
-
:param service: The
|
|
104
|
+
:param service: The agent service to register with the server.
|
|
105
105
|
"""
|
|
106
106
|
service.debug_mode = self.debug_mode
|
|
107
|
-
self.
|
|
107
|
+
self._agent_services.append(service)
|
|
108
108
|
|
|
109
109
|
def start(self) -> None:
|
|
110
110
|
"""
|
|
111
111
|
Start the gRPC server for the provided servicers.
|
|
112
112
|
"""
|
|
113
|
-
if not (self._converter_services or self._script_services or self.
|
|
113
|
+
if not (self._converter_services or self._script_services or self._agent_services):
|
|
114
114
|
raise ValueError("No services have been added to the server. Use add_converter_service, add_script_service,"
|
|
115
|
-
"or
|
|
115
|
+
"or add_agent_service to register a service before starting the server.")
|
|
116
116
|
|
|
117
117
|
async def serve():
|
|
118
118
|
server = grpc.aio.server(options=self.options)
|
|
@@ -123,8 +123,8 @@ class SapioGrpcServer:
|
|
|
123
123
|
for service in self._script_services:
|
|
124
124
|
print(f"Registering Script service: {service.__class__.__name__}")
|
|
125
125
|
add_ScriptServiceServicer_to_server(service, server)
|
|
126
|
-
for service in self.
|
|
127
|
-
print(f"Registering
|
|
126
|
+
for service in self._agent_services:
|
|
127
|
+
print(f"Registering Agent service: {service.__class__.__name__}")
|
|
128
128
|
add_ToolServiceServicer_to_server(service, server)
|
|
129
129
|
|
|
130
130
|
from grpc_health.v1 import health_pb2, health_pb2_grpc
|
sapiopycommons/ai/test_client.py
CHANGED
|
@@ -33,27 +33,27 @@ class ContainerType(Enum):
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
# FR-47422: Created class.
|
|
36
|
-
class
|
|
36
|
+
class AgentOutput:
|
|
37
37
|
"""
|
|
38
|
-
A class for holding the output of a TestClient that calls
|
|
39
|
-
printed to show the output of the
|
|
38
|
+
A class for holding the output of a TestClient that calls an AgentService. AgentOutput objects an be
|
|
39
|
+
printed to show the output of the agent in a human-readable format.
|
|
40
40
|
"""
|
|
41
|
-
|
|
41
|
+
agent_name: str
|
|
42
42
|
|
|
43
43
|
status: str
|
|
44
44
|
message: str
|
|
45
45
|
|
|
46
46
|
binary_output: list[list[bytes]]
|
|
47
47
|
csv_output: list[list[dict[str, Any]]]
|
|
48
|
-
json_output: list[list[Any]]
|
|
48
|
+
json_output: list[list[dict[str, Any]]]
|
|
49
49
|
text_output: list[list[str]]
|
|
50
50
|
|
|
51
51
|
new_records: list[dict[str, FieldValue]]
|
|
52
52
|
|
|
53
53
|
logs: list[str]
|
|
54
54
|
|
|
55
|
-
def __init__(self,
|
|
56
|
-
self.
|
|
55
|
+
def __init__(self, agent_name: str):
|
|
56
|
+
self.agent_name = agent_name
|
|
57
57
|
self.binary_output = []
|
|
58
58
|
self.csv_output = []
|
|
59
59
|
self.json_output = []
|
|
@@ -65,20 +65,20 @@ class ToolOutput:
|
|
|
65
65
|
return self.status == "Success"
|
|
66
66
|
|
|
67
67
|
def __str__(self):
|
|
68
|
-
ret_val: str = f"{self.
|
|
68
|
+
ret_val: str = f"{self.agent_name} Output:\n"
|
|
69
69
|
ret_val += f"\tStatus: {self.status}\n"
|
|
70
70
|
ret_val += f"\tMessage: {self.message}\n"
|
|
71
71
|
ret_val += "-" * 25 + "\n"
|
|
72
72
|
|
|
73
73
|
if self.status == "Success":
|
|
74
|
-
ret_val += f"Binary Output: {sum(len(x) for x in self.binary_output)} item(s) across {len(self.binary_output)}
|
|
74
|
+
ret_val += f"Binary Output: {sum(len(x) for x in self.binary_output)} item(s) across {len(self.binary_output)} output(s)\n"
|
|
75
75
|
for i, output in enumerate(self.binary_output, start=1):
|
|
76
76
|
output: list[bytes]
|
|
77
77
|
ret_val += f"\tBinary Output {i}:\n"
|
|
78
78
|
for binary in output:
|
|
79
79
|
ret_val += f"\t\t{len(binary)} byte(s): {binary[:50]}...\n"
|
|
80
80
|
|
|
81
|
-
ret_val += f"CSV Output: {sum(len(x) for x in self.csv_output)} item(s) across {len(self.csv_output)}
|
|
81
|
+
ret_val += f"CSV Output: {sum(len(x) for x in self.csv_output)} item(s) across {len(self.csv_output)} output(s)\n"
|
|
82
82
|
for i, output in enumerate(self.csv_output, start=1):
|
|
83
83
|
output: list[dict[str, Any]]
|
|
84
84
|
ret_val += f"\tCSV Output {i}:\n"
|
|
@@ -86,7 +86,7 @@ class ToolOutput:
|
|
|
86
86
|
for j, csv_row in enumerate(output):
|
|
87
87
|
ret_val += f"\t\t{j}: {', '.join(f'{v}' for k, v in csv_row.items())}\n"
|
|
88
88
|
|
|
89
|
-
ret_val += f"JSON Output: {sum(len(x) for x in self.json_output)} item(s) across {len(self.json_output)}
|
|
89
|
+
ret_val += f"JSON Output: {sum(len(x) for x in self.json_output)} item(s) across {len(self.json_output)} output(s)\n"
|
|
90
90
|
for i, output in enumerate(self.json_output, start=1):
|
|
91
91
|
output: list[Any]
|
|
92
92
|
ret_val += f"\tJSON Output {i}:\n"
|
|
@@ -94,7 +94,7 @@ class ToolOutput:
|
|
|
94
94
|
ret_val += f"\t\t"
|
|
95
95
|
ret_val += json.dumps(json_obj, indent=2).replace("\n", "\n\t\t") + "\n"
|
|
96
96
|
|
|
97
|
-
ret_val += f"Text Output: {sum(len(x) for x in self.text_output)} item(s) across {len(self.text_output)}
|
|
97
|
+
ret_val += f"Text Output: {sum(len(x) for x in self.text_output)} item(s) across {len(self.text_output)} output(s)\n"
|
|
98
98
|
for i, output in enumerate(self.text_output, start=1):
|
|
99
99
|
output: list[str]
|
|
100
100
|
ret_val += f"\tText Output {i}:\n"
|
|
@@ -113,7 +113,7 @@ class ToolOutput:
|
|
|
113
113
|
|
|
114
114
|
class TestClient:
|
|
115
115
|
"""
|
|
116
|
-
A client for testing
|
|
116
|
+
A client for testing an AgentService.
|
|
117
117
|
"""
|
|
118
118
|
grpc_server_url: str
|
|
119
119
|
options: list[tuple[str, Any]] | None
|
|
@@ -236,6 +236,7 @@ class TestClient:
|
|
|
236
236
|
"""
|
|
237
237
|
Helper method for adding inputs to the next request.
|
|
238
238
|
"""
|
|
239
|
+
container: StepItemContainerPbo | None = None
|
|
239
240
|
match container_type:
|
|
240
241
|
# The content type doesn't matter when we're just testing.
|
|
241
242
|
case ContainerType.BINARY:
|
|
@@ -246,27 +247,29 @@ class TestClient:
|
|
|
246
247
|
container = StepItemContainerPbo(content_type=ContentTypePbo(), json_container=items)
|
|
247
248
|
case ContainerType.TEXT:
|
|
248
249
|
container = StepItemContainerPbo(content_type=ContentTypePbo(), text_container=items)
|
|
250
|
+
case _:
|
|
251
|
+
raise ValueError(f"Unsupported container type: {container_type}")
|
|
249
252
|
self._request_inputs.append(container)
|
|
250
253
|
|
|
251
254
|
def get_service_details(self) -> ToolDetailsResponsePbo:
|
|
252
255
|
"""
|
|
253
|
-
Get the details of the
|
|
256
|
+
Get the details of the agents from the server.
|
|
254
257
|
|
|
255
|
-
:return: A ToolDetailsResponsePbo object containing the details of the
|
|
258
|
+
:return: A ToolDetailsResponsePbo object containing the details of the agent service.
|
|
256
259
|
"""
|
|
257
260
|
with grpc.insecure_channel(self.grpc_server_url, options=self.options) as channel:
|
|
258
261
|
stub = ToolServiceStub(channel)
|
|
259
262
|
return stub.GetToolDetails(ToolDetailsRequestPbo(sapio_conn_info=self.connection))
|
|
260
263
|
|
|
261
|
-
def
|
|
264
|
+
def call_agent(self, agent_name: str, is_verbose: bool = True, is_dry_run: bool = False) -> AgentOutput:
|
|
262
265
|
"""
|
|
263
|
-
Send the request to the
|
|
266
|
+
Send the request to the agent service for a particular agent name. This will send all the inputs that have been
|
|
264
267
|
added using the add_X_input functions.
|
|
265
268
|
|
|
266
|
-
:param
|
|
267
|
-
:param is_verbose: If True, the
|
|
268
|
-
:param is_dry_run: If True, the
|
|
269
|
-
:return:
|
|
269
|
+
:param agent_name: The name of the agent to call on the server.
|
|
270
|
+
:param is_verbose: If True, the agent will log verbosely.
|
|
271
|
+
:param is_dry_run: If True, the agent will not be executed, but the request will be validated.
|
|
272
|
+
:return: An AgentOutput object containing the results of the agent service call.
|
|
270
273
|
"""
|
|
271
274
|
with grpc.insecure_channel(self.grpc_server_url, options=self.options) as channel:
|
|
272
275
|
stub = ToolServiceStub(channel)
|
|
@@ -274,7 +277,7 @@ class TestClient:
|
|
|
274
277
|
response: ProcessStepResponsePbo = stub.ProcessData(
|
|
275
278
|
ProcessStepRequestPbo(
|
|
276
279
|
sapio_user=self.connection,
|
|
277
|
-
tool_name=
|
|
280
|
+
tool_name=agent_name,
|
|
278
281
|
config_field_values=self._config_fields,
|
|
279
282
|
dry_run=is_dry_run,
|
|
280
283
|
verbose_logging=is_verbose,
|
|
@@ -285,7 +288,7 @@ class TestClient:
|
|
|
285
288
|
)
|
|
286
289
|
)
|
|
287
290
|
|
|
288
|
-
results =
|
|
291
|
+
results = AgentOutput(agent_name)
|
|
289
292
|
|
|
290
293
|
match response.status:
|
|
291
294
|
case ProcessStepResponseStatusPbo.SUCCESS:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: sapiopycommons
|
|
3
|
-
Version: 2025.10.
|
|
3
|
+
Version: 2025.10.9a776
|
|
4
4
|
Summary: Official Sapio Python API Utilities Package
|
|
5
5
|
Project-URL: Homepage, https://github.com/sapiosciences
|
|
6
6
|
Author-email: Jonathan Steck <jsteck@sapiosciences.com>, Yechen Qiao <yqiao@sapiosciences.com>
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
sapiopycommons/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
sapiopycommons/ai/agent_service_base.py,sha256=52_QRjbMi6XYHC3oakX3mO5TOh6w8hieTbxzfKbFZWw,54600
|
|
3
4
|
sapiopycommons/ai/converter_service_base.py,sha256=HiUXmwqv1STgyQeF9_eTFXzjIFXp5-NJ7sEhMpV3aAU,6351
|
|
4
5
|
sapiopycommons/ai/protobuf_utils.py,sha256=cBjbxoFAwU02kNUxEce95WnMU2CMuDD-qFaeWgvQJMQ,24599
|
|
5
|
-
sapiopycommons/ai/request_validation.py,sha256=
|
|
6
|
-
sapiopycommons/ai/server.py,sha256=
|
|
7
|
-
sapiopycommons/ai/test_client.py,sha256=
|
|
8
|
-
sapiopycommons/ai/
|
|
6
|
+
sapiopycommons/ai/request_validation.py,sha256=TD2EUi_G5cy1OOVK1AmY2SQc3PEoAKGWs2pT8Qnp2Oo,25092
|
|
7
|
+
sapiopycommons/ai/server.py,sha256=gutSskn_Fenq1uz0DDMvjx4QVFiKt2WVEP3-01a69eU,6384
|
|
8
|
+
sapiopycommons/ai/test_client.py,sha256=C35Z9m4wCQhWPsX_p59VD8eAHP1OkZoJjnUVIdxSmZA,16546
|
|
9
|
+
sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.py,sha256=mEonoj6Iq-AyvO4m3YsPYu85aZfD1E0a0cL8B9yPfEo,2481
|
|
10
|
+
sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.pyi,sha256=sfExq8fFwIwFxCpV50ytdxW5ePNBjJBr_80_trq_JQw,1658
|
|
11
|
+
sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2_grpc.py,sha256=TNS1CB_QGBSa1YU9sYR_hF-pmBwv2GpxjaNQoM_r9iU,948
|
|
9
12
|
sapiopycommons/ai/protoapi/fielddefinitions/fields_pb2.py,sha256=8tKXwLXcqFGdQHHSEBSi6Fd7dcaCFoOqmhjzqhenb_M,2372
|
|
10
13
|
sapiopycommons/ai/protoapi/fielddefinitions/fields_pb2.pyi,sha256=FwtXmNAf7iYGEFm4kbqb04v77jNHbZg18ZmEDhle_bU,1444
|
|
11
14
|
sapiopycommons/ai/protoapi/fielddefinitions/fields_pb2_grpc.py,sha256=uO25bcnfGqXpP4ggUur54Nr73Wj-DGWftExzLNcxdHI,931
|
|
@@ -24,14 +27,14 @@ sapiopycommons/ai/protoapi/plan/converter/converter_pb2_grpc.py,sha256=6T5FCmT_v
|
|
|
24
27
|
sapiopycommons/ai/protoapi/plan/item/item_container_pb2.py,sha256=VIXmIw8-9jtH7peJZ16BEmGDfaVjjxTKhmlfcHWT82M,3863
|
|
25
28
|
sapiopycommons/ai/protoapi/plan/item/item_container_pb2.pyi,sha256=bbPNQDwfFDd7_S7yU99Co1O7sRhxjle-RM0_nK8jgjc,4246
|
|
26
29
|
sapiopycommons/ai/protoapi/plan/item/item_container_pb2_grpc.py,sha256=1NzBWBUINC0Rk-NGYZ-97BVKvVUxcn_I44IjQO2h-nQ,932
|
|
27
|
-
sapiopycommons/ai/protoapi/plan/script/script_pb2.py,sha256=
|
|
28
|
-
sapiopycommons/ai/protoapi/plan/script/script_pb2.pyi,sha256=
|
|
30
|
+
sapiopycommons/ai/protoapi/plan/script/script_pb2.py,sha256=4TN7NlJEENAVqwfymoEDj5hhHYxHLdrHdpRUVgzVG8A,5621
|
|
31
|
+
sapiopycommons/ai/protoapi/plan/script/script_pb2.pyi,sha256=l250ak1sOfm7Ue-PyBQC-7j7-p4DeBxltnOzwDsQIYc,6870
|
|
29
32
|
sapiopycommons/ai/protoapi/plan/script/script_pb2_grpc.py,sha256=ginPYpsiI6U6dB6gfWHJM8LWjSHUgcqz_gR7Dmdsyck,6864
|
|
30
33
|
sapiopycommons/ai/protoapi/plan/tool/entry_pb2.py,sha256=yNyyyVvz94ewjGaHw3t0pUP-KH7ACg5hLC0QzrsFPis,2130
|
|
31
34
|
sapiopycommons/ai/protoapi/plan/tool/entry_pb2.pyi,sha256=2vI0WSy0KGFHDewMSRyX5rUkmmmSaMBLvFO7txqA6Ug,2354
|
|
32
35
|
sapiopycommons/ai/protoapi/plan/tool/entry_pb2_grpc.py,sha256=i24BfJEt7LtyROxHVEyS9RLYqLZKPvyJMKRFZj6NUTg,923
|
|
33
|
-
sapiopycommons/ai/protoapi/plan/tool/tool_pb2.py,sha256=
|
|
34
|
-
sapiopycommons/ai/protoapi/plan/tool/tool_pb2.pyi,sha256=
|
|
36
|
+
sapiopycommons/ai/protoapi/plan/tool/tool_pb2.py,sha256=aLD5j60lWUxhHW8b1AoUOClLOjFPjEMmM1KrY337-gI,9095
|
|
37
|
+
sapiopycommons/ai/protoapi/plan/tool/tool_pb2.pyi,sha256=HGNou2THKPk8o9G_ZPvbGXDb6cBnv8L1R_l10i9ceHI,18441
|
|
35
38
|
sapiopycommons/ai/protoapi/plan/tool/tool_pb2_grpc.py,sha256=CLSGEgSpN4D6wcE-P_5lzb2Nttjr4XjumxGUrZQSip0,6915
|
|
36
39
|
sapiopycommons/ai/protoapi/session/sapio_conn_info_pb2.py,sha256=MhWzTyJz3xZgpdW8_LCVKuzKXT0cv6iHMRB-UNCUNzM,2094
|
|
37
40
|
sapiopycommons/ai/protoapi/session/sapio_conn_info_pb2.pyi,sha256=vLYA8Tkzq2AwgVadoUp5vAg4HgGlgga0kzeS3e_XkCQ,1621
|
|
@@ -69,7 +72,7 @@ sapiopycommons/files/file_text_converter.py,sha256=Gaj_divTiKXWd6flDOgrxNXpcn9fD
|
|
|
69
72
|
sapiopycommons/files/file_util.py,sha256=WBA3FYG8R2HtfxjWSzQhZKW6_1s6JSxTo9lk3SeNDu8,37140
|
|
70
73
|
sapiopycommons/files/file_validator.py,sha256=ryg22-93csmRO_Pv0ZpWphNkB74xWZnHyJ23K56qLj0,28761
|
|
71
74
|
sapiopycommons/files/file_writer.py,sha256=hACVl0duCjP28gJ1NPljkjagNCLod0ygUlPbvUmRDNM,17605
|
|
72
|
-
sapiopycommons/files/temp_files.py,sha256=
|
|
75
|
+
sapiopycommons/files/temp_files.py,sha256=s2sGvn9uh2dTI8AVAQJWOf6RAZ0xZs7DSccCi4AGmlw,3175
|
|
73
76
|
sapiopycommons/flowcyto/flow_cyto.py,sha256=B6DFquLi-gcWfJWyP4vYfwTXXJKl6O9W5-k8FzkM0Oo,2610
|
|
74
77
|
sapiopycommons/flowcyto/flowcyto_data.py,sha256=mYKFuLbtpJ-EsQxLGtu4tNHVlygTxKixgJxJqD68F58,2596
|
|
75
78
|
sapiopycommons/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -102,7 +105,7 @@ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
102
105
|
sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
|
|
103
106
|
sapiopycommons/webhook/webhook_handlers.py,sha256=7o_wXOruhT9auNh8OfhJAh4WhhiPKij67FMBSpGPICc,39939
|
|
104
107
|
sapiopycommons/webhook/webservice_handlers.py,sha256=cvW6Mk_110BzYqkbk63Kg7jWrltBCDALOlkJRu8h4VQ,14300
|
|
105
|
-
sapiopycommons-2025.10.
|
|
106
|
-
sapiopycommons-2025.10.
|
|
107
|
-
sapiopycommons-2025.10.
|
|
108
|
-
sapiopycommons-2025.10.
|
|
108
|
+
sapiopycommons-2025.10.9a776.dist-info/METADATA,sha256=5yZk5DAAW1IHX_9fduVcHOOjludn5fBGykcvM0i4uE4,3142
|
|
109
|
+
sapiopycommons-2025.10.9a776.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
110
|
+
sapiopycommons-2025.10.9a776.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
111
|
+
sapiopycommons-2025.10.9a776.dist-info/RECORD,,
|
|
File without changes
|
{sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|