inspect-ai 0.3.78__py3-none-any.whl → 0.3.80__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.
@@ -1,5 +1,6 @@
1
1
  import "bootstrap-icons/font/bootstrap-icons.css";
2
2
  import "bootstrap/dist/css/bootstrap.css";
3
+ import JSON5 from "json5";
3
4
 
4
5
  import "prismjs";
5
6
  import "prismjs/components/prism-bash";
@@ -748,7 +749,7 @@ export const App: FC<AppProps> = ({
748
749
 
749
750
  const embeddedState = document.getElementById("logview-state");
750
751
  if (embeddedState) {
751
- const state = JSON.parse(embeddedState.textContent || "");
752
+ const state = JSON5.parse(embeddedState.textContent || "");
752
753
  onMessage({ data: state });
753
754
  } else {
754
755
  const result = await load();
@@ -1,3 +1,4 @@
1
+ import JSON5 from "json5";
1
2
  import { dirname } from "../utils/path";
2
3
  import { getVscodeApi } from "../utils/vscode";
3
4
  import browserApi from "./api-browser";
@@ -22,7 +23,7 @@ const resolveApi = (): ClientAPI => {
22
23
  // Read the contents
23
24
  const context = scriptEl.textContent;
24
25
  if (context !== null) {
25
- const data = JSON.parse(context);
26
+ const data = JSON5.parse(context);
26
27
  if (data.log_dir || data.log_file) {
27
28
  const log_dir = data.log_dir || dirname(data.log_file);
28
29
  const api = simpleHttpApi(log_dir, data.log_file);
@@ -1,3 +1,4 @@
1
+ import JSON5 from "json5";
1
2
  import { ApplicationIcons } from "../appearance/icons";
2
3
 
3
4
  import { ANSIDisplay } from "../components/AnsiDisplay";
@@ -91,7 +92,7 @@ const contentRenderers: Record<string, ContentRenderer> = {
91
92
  return false;
92
93
  },
93
94
  render: (_id, entry) => {
94
- const obj = JSON.parse(entry.value);
95
+ const obj = JSON5.parse(entry.value);
95
96
  return { rendered: <JSONPanel data={obj as Record<string, unknown>} /> };
96
97
  },
97
98
  },
@@ -34,7 +34,7 @@ self.onmessage = function (e) {
34
34
  const decoder = new TextDecoder();
35
35
  const text = decoder.decode(encodedText);
36
36
  try {
37
- const result = JSON.parse(text);
37
+ const result = JSON5.parse(text);
38
38
  postMessage({ success: true, result });
39
39
  } catch (err) {
40
40
  postMessage({ success: false, error: err.message });
@@ -70,8 +70,6 @@ from inspect_ai.model import (
70
70
  TopLogprob,
71
71
  )
72
72
  from inspect_ai.model._model_call import ModelCall
73
- from inspect_ai.model._providers.util import model_base_url
74
- from inspect_ai.model._providers.util.hooks import HttpHooks, urllib3_hooks
75
73
  from inspect_ai.tool import (
76
74
  ToolCall,
77
75
  ToolChoice,
@@ -81,6 +79,9 @@ from inspect_ai.tool import (
81
79
  ToolParams,
82
80
  )
83
81
 
82
+ from .util import model_base_url
83
+ from .util.hooks import HttpHooks, HttpxHooks
84
+
84
85
  logger = getLogger(__name__)
85
86
 
86
87
 
@@ -177,15 +178,10 @@ class GoogleGenAIAPI(ModelAPI):
177
178
  self.api_key = os.environ.get(GOOGLE_API_KEY, None)
178
179
 
179
180
  # custom base_url
180
- base_url = model_base_url(base_url, "GOOGLE_BASE_URL")
181
+ self.base_url = model_base_url(self.base_url, "GOOGLE_BASE_URL")
181
182
 
182
- # create client
183
- self.client = Client(
184
- vertexai=self.is_vertex(),
185
- api_key=self.api_key,
186
- http_options={"base_url": base_url},
187
- **model_args,
188
- )
183
+ # save model args
184
+ self.model_args = model_args
189
185
 
190
186
  @override
191
187
  async def close(self) -> None:
@@ -202,11 +198,20 @@ class GoogleGenAIAPI(ModelAPI):
202
198
  tool_choice: ToolChoice,
203
199
  config: GenerateConfig,
204
200
  ) -> ModelOutput | tuple[ModelOutput | Exception, ModelCall]:
205
- # generate request_id
206
- request_id = urllib3_hooks().start_request()
201
+ # create client
202
+ client = Client(
203
+ vertexai=self.is_vertex(),
204
+ api_key=self.api_key,
205
+ http_options={"base_url": self.base_url},
206
+ **self.model_args,
207
+ )
208
+
209
+ # create hooks and allocate request
210
+ http_hooks = HttpxHooks(client._api_client._async_httpx_client)
211
+ request_id = http_hooks.start_request()
207
212
 
208
213
  # Create google-genai types.
209
- gemini_contents = await as_chat_messages(self.client, input)
214
+ gemini_contents = await as_chat_messages(client, input)
210
215
  gemini_tools = chat_tools(tools) if len(tools) > 0 else None
211
216
  gemini_tool_config = chat_tool_config(tool_choice) if len(tools) > 0 else None
212
217
  parameters = GenerateContentConfig(
@@ -222,9 +227,7 @@ class GoogleGenAIAPI(ModelAPI):
222
227
  safety_settings=safety_settings_to_list(self.safety_settings),
223
228
  tools=gemini_tools,
224
229
  tool_config=gemini_tool_config,
225
- system_instruction=await extract_system_message_as_parts(
226
- self.client, input
227
- ),
230
+ system_instruction=await extract_system_message_as_parts(client, input),
228
231
  )
229
232
  if config.response_schema is not None:
230
233
  parameters.response_mime_type = "application/json"
@@ -242,11 +245,11 @@ class GoogleGenAIAPI(ModelAPI):
242
245
  tools=gemini_tools,
243
246
  tool_config=gemini_tool_config,
244
247
  response=response,
245
- time=urllib3_hooks().end_request(request_id),
248
+ time=http_hooks.end_request(request_id),
246
249
  )
247
250
 
248
251
  try:
249
- response = await self.client.aio.models.generate_content(
252
+ response = await client.aio.models.generate_content(
250
253
  model=self.model_name,
251
254
  contents=gemini_contents,
252
255
  config=parameters,
@@ -264,26 +267,8 @@ class GoogleGenAIAPI(ModelAPI):
264
267
 
265
268
  @override
266
269
  def should_retry(self, ex: Exception) -> bool:
267
- import requests # type: ignore
268
-
269
- # standard http errors
270
- if (
271
- isinstance(ex, APIError)
272
- and isinstance(ex.status, str)
273
- and ex.status.isdigit()
274
- ):
275
- return is_retryable_http_status(int(ex.status))
276
-
277
- # low-level requests exceptions
278
- elif isinstance(ex, requests.exceptions.RequestException):
279
- return isinstance(
280
- ex,
281
- (
282
- requests.exceptions.ConnectionError
283
- | requests.exceptions.ConnectTimeout
284
- | requests.exceptions.ChunkedEncodingError
285
- ),
286
- )
270
+ if isinstance(ex, APIError) and ex.code is not None:
271
+ return is_retryable_http_status(ex.code)
287
272
  else:
288
273
  return False
289
274
 
@@ -283,10 +283,9 @@ def mistral_function(tool: ToolInfo) -> MistralFunction:
283
283
  return MistralFunction(
284
284
  name=tool.name,
285
285
  description=tool.description,
286
- parameters={
287
- k: v.model_dump(exclude={"additionalProperties"}, exclude_none=True)
288
- for k, v in tool.parameters.properties.items()
289
- },
286
+ parameters=tool.parameters.model_dump(
287
+ exclude={"additionalProperties"}, exclude_none=True
288
+ ),
290
289
  )
291
290
 
292
291
 
@@ -94,11 +94,7 @@ def vertex() -> type[ModelAPI]:
94
94
  def google() -> type[ModelAPI]:
95
95
  FEATURE = "Google API"
96
96
  PACKAGE = "google-genai"
97
- MIN_VERSION = "1.2.0"
98
-
99
- # workaround log spam
100
- # https://github.com/ray-project/ray/issues/24917
101
- os.environ["GRPC_ENABLE_FORK_SUPPORT"] = "0"
97
+ MIN_VERSION = "1.8.0"
102
98
 
103
99
  # verify we have the package
104
100
  try:
@@ -148,7 +144,7 @@ def cf() -> type[ModelAPI]:
148
144
  def mistral() -> type[ModelAPI]:
149
145
  FEATURE = "Mistral API"
150
146
  PACKAGE = "mistralai"
151
- MIN_VERSION = "1.5.1"
147
+ MIN_VERSION = "1.6.0"
152
148
 
153
149
  # verify we have the package
154
150
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: inspect_ai
3
- Version: 0.3.78
3
+ Version: 0.3.80
4
4
  Summary: Framework for large language model evaluations
5
5
  Author: UK AI Security Institute
6
6
  License: MIT License
@@ -50,7 +50,7 @@ inspect_ai/_eval/evalset.py,sha256=HGrz0LkTMsBbYDPZEMVnZCmFi_pYegZtSoqRVYbRDiE,2
50
50
  inspect_ai/_eval/list.py,sha256=VbZ-2EI6MqrXvCN7VTz21TQSoU5K5_Q0hqhxmj5A_m0,3744
51
51
  inspect_ai/_eval/loader.py,sha256=yOj8HqYBFQntx0_GY4Wxqm6jivlT4N4WiQ1T8J9uRVA,23606
52
52
  inspect_ai/_eval/registry.py,sha256=9Q-Re9uZagQ2nw-W7hA6zhrmCQFmo3KcxncTcG24EG8,5315
53
- inspect_ai/_eval/run.py,sha256=9TtOp1vc18KclxstjvWhEL5VtcLBL3SRbRwsoRXaah8,19179
53
+ inspect_ai/_eval/run.py,sha256=7Cepcyd5KaMcoUQybRifTtFEOLBBvmszhJdH_-yzb3E,19315
54
54
  inspect_ai/_eval/score.py,sha256=qf9T8XwUmfE6A8QK1-D-jUbNlLETVM-HXhucPWZ0Ro0,9591
55
55
  inspect_ai/_eval/task/__init__.py,sha256=6FvojMW3yo36L7xDacppCHDxt6A8_tzj_ftg5bQ6eNk,199
56
56
  inspect_ai/_eval/task/constants.py,sha256=quAKMw-4-3xKd1T_KwXCZvHYoKRXt1ZGuaHbBcWJwnA,72
@@ -144,8 +144,8 @@ inspect_ai/_view/www/.vscode/settings.json,sha256=g5hrVnMaYxM06JpiJD2EuE2xjcbF6x
144
144
  inspect_ai/_view/www/dist/index.html,sha256=gpdu6SR-SOH9EWx15cCWHzujMZujnZR5tRlEfROJg2A,997
145
145
  inspect_ai/_view/www/dist/assets/favicon.svg,sha256=b9AHYZaO2zBzeKH6G4PwXZMGGW_UxY0omKHam-c9MAs,1508
146
146
  inspect_ai/_view/www/dist/assets/index.css,sha256=V0HHB6ss9UdKAlLKTmyHoYAZrstD6nvb-UhnWInyhQQ,895546
147
- inspect_ai/_view/www/dist/assets/index.js,sha256=-dI_BWa2w7TMj1_inAgHQmG4qq44oG_X2JM70W7DygY,2748559
148
- inspect_ai/_view/www/src/App.tsx,sha256=rhiZKs-f1y9amyX_OLay7aL4OXaQ_o0gNd04M3pZVuk,28852
147
+ inspect_ai/_view/www/dist/assets/index.js,sha256=VOFdGjZJ1tIRN494HFu_9wY6jghQP5lswgZLvppnwxw,2748550
148
+ inspect_ai/_view/www/src/App.tsx,sha256=Biposnrrx3ZZXLiLJXTCJGQge66C9BE8mfn4W4QJyF4,28880
149
149
  inspect_ai/_view/www/src/AppErrorBoundary.tsx,sha256=RyhZWbIMZj1QeUOUUXh9hUFvq6LoDEoHuTY0giswmL0,1169
150
150
  inspect_ai/_view/www/src/constants.ts,sha256=aLncMT1XjKzyphLF_jkXPZicsCJXMsBXcDomAC4EaIY,1228
151
151
  inspect_ai/_view/www/src/index.tsx,sha256=WOnrMIxwi4xRcUnOyPDHCbA6cGpi5VUGeSHlcZp3v4o,3455
@@ -155,7 +155,7 @@ inspect_ai/_view/www/src/api/api-http.ts,sha256=BWgMOn0l4YL12HcoQRFSJPZ9QLTV4j3z
155
155
  inspect_ai/_view/www/src/api/api-shared.ts,sha256=F0qCU97BN8p4DjsdK62hwoRSlcJUahCY--WyacbMRz0,1524
156
156
  inspect_ai/_view/www/src/api/api-vscode.ts,sha256=1GzxZ5Os_l2mjPkfhSe7qKDPlGFSDMh5DjTA0vONVts,2324
157
157
  inspect_ai/_view/www/src/api/client-api.ts,sha256=bSHmXBp9i4NxBQn_BlTF_DyBlhR4sNPueHJEbC8nlOI,8202
158
- inspect_ai/_view/www/src/api/index.ts,sha256=A-nWwvyWc5uf7ebNmxdnDXMj4fuyYzhZHgIGsmyRlJw,1737
158
+ inspect_ai/_view/www/src/api/index.ts,sha256=8ZnvEspFRo9n0oWpWEw_FeGXmEbep36QlrvX4dgRPnA,1765
159
159
  inspect_ai/_view/www/src/api/jsonrpc.ts,sha256=XDyp8ruONzjng1vuiSv8EU7eJhST-4K2ox0IBkCmBfc,5662
160
160
  inspect_ai/_view/www/src/api/types.ts,sha256=fKO0-xwnQr2CEIvOH6umBknuVEJ_2NR3zXUapsk1x88,3086
161
161
  inspect_ai/_view/www/src/appearance/colors.ts,sha256=nkVEfmgLb8vTOF1o0YNu0SWNwmSMAbPKFwg4OTZDK_M,217
@@ -212,7 +212,7 @@ inspect_ai/_view/www/src/metadata/MetaDataView.module.css,sha256=-8AWTfZEMm7PEtS
212
212
  inspect_ai/_view/www/src/metadata/MetaDataView.tsx,sha256=JUfhXUzxDDzy240YZOMs2Zr9AXiWLUgUDU6puEin_G0,2243
213
213
  inspect_ai/_view/www/src/metadata/MetadataGrid.module.css,sha256=jHCm0DLEMzjpQGFIRZiJEej3LsliFKIe3qxPOPnSWH0,221
214
214
  inspect_ai/_view/www/src/metadata/RenderedContent.module.css,sha256=Ji5KWs-f7J2g-OqZ41Rxr0DAOkHHTDL-w7KAjgWxeVo,134
215
- inspect_ai/_view/www/src/metadata/RenderedContent.tsx,sha256=B0DohyaqZoJduAYbq1oQKTG--vGBxVZROb9douEPR_I,6909
215
+ inspect_ai/_view/www/src/metadata/RenderedContent.tsx,sha256=FTWVKM-TGN5GMSMijp56B2LbT9f2Oc9O9LoxeG15M8s,6937
216
216
  inspect_ai/_view/www/src/metadata/types.ts,sha256=Ss21MoobQ3SS1D3sbgQp_ab0ef4nD0MtTebUSllTWKs,345
217
217
  inspect_ai/_view/www/src/plan/DatasetDetailView.module.css,sha256=FxQ9APykN8fb9JPADCIeO6wq7F9YEmRll8P04Ay3k0o,32
218
218
  inspect_ai/_view/www/src/plan/DatasetDetailView.tsx,sha256=J-m35hVN4Sruw5CtuZUJQjASwD-rtJmXJP8SJynmcCU,933
@@ -361,7 +361,7 @@ inspect_ai/_view/www/src/utils/format.ts,sha256=AD7bQMaluuuP_VK_ST3ZJTst7gWPFxiW
361
361
  inspect_ai/_view/www/src/utils/git.ts,sha256=2hEC8kRq0NjEEwEmbi9vKy1COJ7NDNURq7PKxcs-7Tc,261
362
362
  inspect_ai/_view/www/src/utils/html.ts,sha256=BAiToeaO6DVHrofhNrhi0_bTbUumr8wmpkOGJe4Pd34,212
363
363
  inspect_ai/_view/www/src/utils/http.ts,sha256=bHOv920oFymmUJqDMjSaDRCAel3uvRBZFcDMirToKMg,388
364
- inspect_ai/_view/www/src/utils/json-worker.ts,sha256=LIVuPff2JrGkkjwrdlfNsSZUNpJTtEre6jGlJSwoztg,43454
364
+ inspect_ai/_view/www/src/utils/json-worker.ts,sha256=0eYPlkHkqu4JztHovMccTHa7ha8J84Dam9FEv0Js8Qk,43455
365
365
  inspect_ai/_view/www/src/utils/json.ts,sha256=tD4qnoHPB4bky08gHLgtaAMEcYvplqAQtg-173pwYp0,495
366
366
  inspect_ai/_view/www/src/utils/path.ts,sha256=rEGEqZVSjuOJ8NcOWGM7fzXrnQ28FGwHG_RVRAA8cWg,700
367
367
  inspect_ai/_view/www/src/utils/print.ts,sha256=KAJ4eAQwGql1qy7Ps5wDgPYSn4qrLzP0djFlS5As2U0,2693
@@ -469,12 +469,12 @@ inspect_ai/model/_providers/azureai.py,sha256=tDWuePLhnZBcpHLVzX7J3Wx8VRPhW8tmtj
469
469
  inspect_ai/model/_providers/bedrock.py,sha256=mLeMW2JkG4lF0VQGEdku73ZL00EBy-hEvEcyCdjDUDo,24153
470
470
  inspect_ai/model/_providers/cloudflare.py,sha256=0e0HPas21cVC8N9mNJlZnSZyIt6FUB9lTIAqPXJDrtE,4586
471
471
  inspect_ai/model/_providers/goodfire.py,sha256=EzebC1woEjIXfHLP_ixpMR6G1hC-LxbSUxiilq1c-Is,8868
472
- inspect_ai/model/_providers/google.py,sha256=YkgeFxVh9hMWoqiHe39wgt02eNTogMxmlYX6goYWyo0,28697
472
+ inspect_ai/model/_providers/google.py,sha256=HpTn7FXF4Lx34-RigFm2xW0yBTQfzPBDOhcTum69vBo,28207
473
473
  inspect_ai/model/_providers/grok.py,sha256=dS88ueXiD-kHAFr0jCoTpTGLGa2VsUlB_TFP8L_2lBM,995
474
474
  inspect_ai/model/_providers/groq.py,sha256=Fr4fy8NmqllmUW7jhnQ3W94zGlxyr276qaGFS_iDI3Q,11189
475
475
  inspect_ai/model/_providers/hf.py,sha256=EZRiiRSzIoRCdFYKj3Otn5ebsROdjzx5YSQ6CzqOJxk,17969
476
476
  inspect_ai/model/_providers/llama_cpp_python.py,sha256=i2I56Damgb8VDhMuPxPca24fVhlajDHzxCTYFnT41uI,702
477
- inspect_ai/model/_providers/mistral.py,sha256=TPJIB0AytktnFwwAlvg6Mz2hXarJK8m0G6ggJw5Cbqg,17774
477
+ inspect_ai/model/_providers/mistral.py,sha256=jrGZUhH6zJvzSz7ZBKa7JoggMXzWIpq1qDW_paRKk_w,17724
478
478
  inspect_ai/model/_providers/mockllm.py,sha256=gL9f-f5TOdE4a0GVENr3cOIIp2kv8zVXWPZ608rouGk,2440
479
479
  inspect_ai/model/_providers/none.py,sha256=6qLbZpHSoEZaaxFO7luieFjqig2Ju8Fu00DlRngAry8,935
480
480
  inspect_ai/model/_providers/ollama.py,sha256=mBPSxaEkiH_RnlHKqOyFBlXObQhc2dfjL-rCKrea5u8,675
@@ -482,7 +482,7 @@ inspect_ai/model/_providers/openai.py,sha256=Qg0MM2OftmzzZ8aio-hvg3GZv77-PyuuY0u
482
482
  inspect_ai/model/_providers/openai_o1.py,sha256=wURSSI7aCBxbZONQBaEOYPrQleBExL2c2uSIdJXLi1U,12763
483
483
  inspect_ai/model/_providers/openai_responses.py,sha256=9mVdfcKgIULv6YpwCFKFUj63JVi7szvBzHczj12ZdOc,6096
484
484
  inspect_ai/model/_providers/openrouter.py,sha256=pDimDmm_4FzS4GZx0n9z8z717mQf3IQlgEy30huzpc4,4730
485
- inspect_ai/model/_providers/providers.py,sha256=TdRXKzNQmeWZyTaAWkalmxVylRHkft0O8LqGJ054EiI,6508
485
+ inspect_ai/model/_providers/providers.py,sha256=cOXH7P7_mFs0UGQ3VBtXXSbGpQ0YlX1daM9wD98YeBI,6378
486
486
  inspect_ai/model/_providers/together.py,sha256=Hwg-5jlFR3K61Epp_NnmDR5lX-bHZ2QT77GjM9dQOKY,9461
487
487
  inspect_ai/model/_providers/vertex.py,sha256=3PX3pVvzydA-IczZaEAeqQeiTtimBa3a6t418GAtjhY,17235
488
488
  inspect_ai/model/_providers/vllm.py,sha256=KNEjdu-oeCXH-vhpMeF1Pmnf8-mkLpQ5pbyFJMlaT9c,14172
@@ -627,9 +627,9 @@ inspect_ai/util/_sandbox/docker/internal.py,sha256=c8X8TLrBPOvsfnq5TkMlb_bzTALyc
627
627
  inspect_ai/util/_sandbox/docker/prereqs.py,sha256=0j6_OauBBnVlpBleADcZavIAAQZy4WewVjbRn9c0stg,3355
628
628
  inspect_ai/util/_sandbox/docker/service.py,sha256=hhHIWH1VDFLwehdGd19aUBD_VKfDO3GCPxpw1HSwVQk,2437
629
629
  inspect_ai/util/_sandbox/docker/util.py,sha256=EeInihCNXgUWxaqZ4dNOJd719kXL2_jr63QCoXn68vA,3154
630
- inspect_ai-0.3.78.dist-info/licenses/LICENSE,sha256=xZPCr8gTiFIerrA_DRpLAbw-UUftnLFsHxKeW-NTtq8,1081
631
- inspect_ai-0.3.78.dist-info/METADATA,sha256=NNzcpeDyLChQBQ9aFqlE2iVcY-sod8sd5B72_pI2qq8,4997
632
- inspect_ai-0.3.78.dist-info/WHEEL,sha256=DK49LOLCYiurdXXOXwGJm6U4DkHkg4lcxjhqwRa0CP4,91
633
- inspect_ai-0.3.78.dist-info/entry_points.txt,sha256=WGGLmzTzDWLzYfiyovSY6oEKuf-gqzSDNOb5V-hk3fM,54
634
- inspect_ai-0.3.78.dist-info/top_level.txt,sha256=Tp3za30CHXJEKLk8xLe9qGsW4pBzJpEIOMHOHNCXiVo,11
635
- inspect_ai-0.3.78.dist-info/RECORD,,
630
+ inspect_ai-0.3.80.dist-info/licenses/LICENSE,sha256=xZPCr8gTiFIerrA_DRpLAbw-UUftnLFsHxKeW-NTtq8,1081
631
+ inspect_ai-0.3.80.dist-info/METADATA,sha256=ir05BvBkasBJahUTZEdiALpHw3BQMfx8A4oYr3Cd2wc,4997
632
+ inspect_ai-0.3.80.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
633
+ inspect_ai-0.3.80.dist-info/entry_points.txt,sha256=WGGLmzTzDWLzYfiyovSY6oEKuf-gqzSDNOb5V-hk3fM,54
634
+ inspect_ai-0.3.80.dist-info/top_level.txt,sha256=Tp3za30CHXJEKLk8xLe9qGsW4pBzJpEIOMHOHNCXiVo,11
635
+ inspect_ai-0.3.80.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.0.2)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5