malevich-coretools 0.3.9__py3-none-any.whl → 0.3.11__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 malevich-coretools might be problematic. Click here for more details.

@@ -111,7 +111,7 @@ class UserApp(BaseModel):
111
111
  image: JsonImage
112
112
  platform: str
113
113
  platformSettings: Optional[str] = None
114
- extraCollectionsFrom: Optional[Dict[str, Alias.Id]] = None
114
+ extraCollectionsFrom: Optional[Dict[str, List[Alias.Id]]] = None
115
115
 
116
116
 
117
117
  class UserTask(BaseModel):
@@ -170,6 +170,7 @@ class UnscheduleOperation(BaseModel):
170
170
  class Restrictions(BaseModel):
171
171
  honestScale: bool = True
172
172
  singlePod: bool = False
173
+ smartAppsReuse: bool = False
173
174
 
174
175
 
175
176
  class MainTask(BaseModel):
@@ -217,7 +218,7 @@ class ResultIds(BaseModel):
217
218
 
218
219
 
219
220
  class FilesDirs(BaseModel):
220
- files: List[str]
221
+ files: Dict[str, int]
221
222
  directories: List[str]
222
223
 
223
224
 
@@ -522,3 +523,51 @@ class BatchResponse(BaseModel):
522
523
 
523
524
  class BatchResponses(BaseModel):
524
525
  data: List[BatchResponse]
526
+
527
+
528
+ class UserLimits(BaseModel):
529
+ # set by superuser
530
+ appMemoryRequest: int # in Mi
531
+ appMemoryLimit: int # in Mi
532
+ appCpuRequest: int # in m
533
+ appCpuLimit: int # in m
534
+ appStorageRequest: int # in Mi
535
+ appStorageLimit: int # in Mi
536
+ assetsLimit: int # in Mi, if < 0 - unlimited
537
+ allowCommonGpu: int # ignore if exist access key
538
+ gpuDiskMax: int # ignore if exist access key
539
+
540
+ # set by user
541
+ defaultMemoryRequest: int # in Mi
542
+ defaultMemoryLimit: int # in Mi
543
+ defaultCpuRequest: int # in m
544
+ defaultCpuLimit: int # in m
545
+ defaultStorageRequest: int # in Mi
546
+ defaultStorageLimit: int # in Mi
547
+ defaultGpuDisk: int
548
+
549
+
550
+ class BasePlatformSettings(BaseModel):
551
+ memoryRequest: Optional[int]
552
+ memoryLimit: Optional[int]
553
+ cpuRequest: Optional[int]
554
+ cpuLimit: Optional[int]
555
+ storageRequest: Optional[int]
556
+ storageLimit: Optional[int]
557
+
558
+
559
+ class Limits(BasePlatformSettings):
560
+ gpuDisk: Optional[int]
561
+
562
+
563
+ class LimitsScope(BaseModel): # for superuser/admin
564
+ login: str
565
+ appMemoryRequest: Optional[int]
566
+ appMemoryLimit: Optional[int]
567
+ appCpuRequest: Optional[int]
568
+ appCpuLimit: Optional[int]
569
+ appStorageRequest: Optional[int]
570
+ appStorageLimit: Optional[int]
571
+ assetsLimit: Optional[int]
572
+ allowCommonGpu: Optional[bool]
573
+ gpuDiskMax: Optional[int]
@@ -643,6 +643,18 @@ def post_manager_app_pause(data: AppManage, wait: bool, *args, **kwargs) -> Alia
643
643
  return send_to_core_modify(MANAGER_APP_PAUSE(wait), data, *args, **kwargs)
644
644
 
645
645
 
646
+ def get_limits(*args, **kwargs) -> UserLimits:
647
+ return model_from_json(send_to_core_get(LIMITS(True), *args, **kwargs), UserLimits)
648
+
649
+
650
+ def post_limits(data: Limits, wait: bool, *args, **kwargs) -> Alias.Info:
651
+ return send_to_core_modify(LIMITS(wait), data, *args, **kwargs)
652
+
653
+
654
+ def post_user_limits(data: LimitsScope, wait: bool, *args, **kwargs) -> Alias.Info:
655
+ return send_to_core_modify(LIMITS_USER(wait), data, *args, **kwargs)
656
+
657
+
646
658
  async def kafka_send(data: KafkaMsg, *args, **kwargs) -> Union[Alias.Info, KafkaMsg]:
647
659
  result = await send_to_core_post_async(KAFKA_SEND, data, *args, **kwargs)
648
660
  try:
@@ -8,6 +8,7 @@ from malevich_coretools.abstract.abstract import (
8
8
  DEFAULT_MSG_URL,
9
9
  Alias,
10
10
  AppSettings,
11
+ BasePlatformSettings,
11
12
  Cfg,
12
13
  DocsDataCollection,
13
14
  EndpointOverride,
@@ -163,10 +164,12 @@ def create_task_policy(
163
164
  def create_restrictions(
164
165
  honest_scale: bool = True,
165
166
  single_pod: bool = False,
167
+ smart_apps_reuse: bool = False,
166
168
  ) -> Restrictions:
167
169
  return Restrictions(
168
170
  honestScale=honest_scale,
169
171
  singlePod=single_pod,
172
+ smartAppsReuse=smart_apps_reuse,
170
173
  )
171
174
 
172
175
 
@@ -269,3 +272,21 @@ def create_cfg_struct(
269
272
  app_cfg_extension=app_cfg_extension_fixed,
270
273
  email=email,
271
274
  )
275
+
276
+
277
+ def base_settings(
278
+ memory_request: Optional[int] = None,
279
+ memory_limit: Optional[int] = None,
280
+ cpu_request: Optional[int] = None,
281
+ cpu_limit: Optional[int] = None,
282
+ storage_request: Optional[int] = None,
283
+ storage_limit: Optional[int] = None,
284
+ ) -> str:
285
+ return BasePlatformSettings(
286
+ memoryRequest=memory_request,
287
+ memoryLimit=memory_limit,
288
+ cpuRequest=cpu_request,
289
+ cpuLimit=cpu_limit,
290
+ storageRequest=storage_request,
291
+ storageLimit=storage_limit,
292
+ ).model_dump_json()
@@ -33,9 +33,9 @@ def with_key_values(url: str, key_values: Dict[str, Optional[str]]) -> str:
33
33
  return url
34
34
 
35
35
  ## DocsController
36
- DOCS_MAIN = f"{API_VERSION}/docs/"
37
- DOCS = lambda wait: with_wait(DOCS_MAIN, wait)
38
- DOCS_ID = lambda id, wait: with_wait(f"{DOCS_MAIN}{id}", wait)
36
+ DOCS_MAIN = f"{API_VERSION}/docs"
37
+ DOCS = lambda wait: with_wait(f"{DOCS_MAIN}/", wait)
38
+ DOCS_ID = lambda id, wait: with_wait(f"{DOCS_MAIN}/{id}", wait)
39
39
 
40
40
  ## CollectionsController
41
41
  COLLECTIONS_MAIN = f"{API_VERSION}/collections"
@@ -170,6 +170,11 @@ MANAGER_APP_STOP = lambda wait: with_wait(f"{MANAGER_MAIN}/app/stop", wait)
170
170
  MANAGER_APP_RESUME = lambda wait: with_wait(f"{MANAGER_MAIN}/app/resume", wait)
171
171
  MANAGER_APP_PAUSE = lambda wait: with_wait(f"{MANAGER_MAIN}/app/pause", wait)
172
172
 
173
+ ## LimitsController
174
+ LIMITS_MAIN = f"{API_VERSION}/limits"
175
+ LIMITS = lambda wait: with_wait(f"{LIMITS_MAIN}/", wait)
176
+ LIMITS_USER = lambda wait: with_wait(f"{LIMITS_MAIN}/user", wait)
177
+
173
178
  ### Kafka
174
179
  KAFKA_SEND = f"{MANAGER_MAIN}/kafkaMsg"
175
180
 
@@ -0,0 +1,51 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ class VastPlatformQuery(BaseModel):
5
+ bw_nvlink: float | None = Field(default=None, description="Bandwidth NVLink")
6
+ compute_cap: int | None = Field(default=None, description="CUDA compute capability * 100 (ie: 650 for 6.5, 700 for 7.0)")
7
+ cpu_cores: int | None = Field(default=None, description="Number of virtual CPU cores")
8
+ cpu_cores_effective: float | None = Field(default=None, description="Effective number of CPU cores")
9
+ cpu_ram: float | None = Field(default=None, description="System RAM in gigabytes")
10
+ cuda_vers: float | None = Field(default=None, description="Machine max supported CUDA version (based on driver version)")
11
+ datacenter: bool | None = Field(default=None, description="Show only datacenter offers")
12
+ direct_port_count: int | None = Field(default=None, description="Open ports on host's router")
13
+ disk_bw: float | None = Field(default=None, description="Disk read bandwidth, in MB/s")
14
+ disk_space: float | None = Field(default=None, description="Disk storage space, in GB")
15
+ dlperf: float | None = Field(default=None, description="DL-perf score")
16
+ dlperf_usd: float | None = Field(default=None, description="DL-perf/$")
17
+ dph: float | None = Field(default=None, description="$/hour rental cost")
18
+ driver_version: str | None = Field(default=None, description="Machine's NVIDIA driver version as 3 digit string ex. '535.86.05'")
19
+ duration: float | None = Field(default=None, description="Max rental duration in days")
20
+ external: bool | None = Field(default=False, description="Show external offers in addition to datacenter offers")
21
+ flops_usd: float | None = Field(default=None, description="TFLOPs/$")
22
+ geolocation: str | None = Field(default=None, description="Two letter country code. Works with operators =, !=, in, not in (e.g. geolocation not in [XV,XZ])")
23
+ gpu_mem_bw: float | None = Field(default=None, description="GPU memory bandwidth in GB/s")
24
+ gpu_name: str | None = Field(default=None, description="GPU model name (no quotes, replace spaces with underscores, ie: RTX_3090 rather than 'RTX 3090')")
25
+ gpu_ram: float | None = Field(default=None, description="GPU RAM in GB")
26
+ gpu_frac: float | None = Field(default=None, description="Ratio of GPUs in the offer to GPUs in the system")
27
+ gpu_display_active: bool | None = Field(default=None, description="True if the GPU has a display attached")
28
+ has_avx: bool | None = Field(default=None, description="CPU supports AVX instruction set")
29
+ id: int | None = Field(default=None, description="Instance unique ID")
30
+ inet_down: float | None = Field(default=None, description="Internet download speed in Mb/s")
31
+ inet_down_cost: float | None = Field(default=None, description="Internet download bandwidth cost in $/GB")
32
+ inet_up: float | None = Field(default=None, description="Internet upload speed in Mb/s")
33
+ inet_up_cost: float | None = Field(default=None, description="Internet upload bandwidth cost in $/GB")
34
+ machine_id: int | None = Field(default=None, description="Machine ID of instance")
35
+ min_bid: float | None = Field(default=None, description="Current minimum bid price in $/hr for interruptible")
36
+ num_gpus: int | None = Field(default=None, description="# of GPUs")
37
+ pci_gen: float | None = Field(default=None, description="PCIE generation")
38
+ pcie_bw: float | None = Field(default=None, description="PCIE bandwidth")
39
+ reliability: float | None = Field(default=None, description="Machine reliability score")
40
+ rentable: bool | None = Field(default=True, description="Is the instance currently rentable")
41
+ rented: bool | None = Field(default=False, description="Allow/disallow duplicates and potential conflicts with existing stopped instances")
42
+ storage_cost: float | None = Field(default=None, description="Storage cost in $/GB/month")
43
+ static_ip: bool | None = Field(default=None, description="Is the IP address static/stable")
44
+ total_flops: float | None = Field(default=None, description="Total TFLOPs from all GPUs")
45
+ verified: bool | None = Field(default=True, description="Is the machine verified")
46
+
47
+
48
+ class VastPlatformSettings(BaseModel):
49
+ instance_id: int | None = None
50
+ advanced_query_settings: VastPlatformQuery | None = Field(default=None, description="Configure search settings to find GPU instances on-demand")
51
+ disk_size: int | None = Field(default=None, description="Disk storage space, in GB")
@@ -15,6 +15,7 @@ from malevich_coretools.batch import ( # noqa: F401
15
15
  DefferOperation,
16
16
  )
17
17
  from malevich_coretools.funcs.helpers import ( # noqa: F401
18
+ base_settings,
18
19
  create_app_settings,
19
20
  create_cfg_struct,
20
21
  create_endpoint_override,
@@ -1562,7 +1563,7 @@ def create_app(
1562
1563
  image_auth: Optional[AUTH] = None,
1563
1564
  platform: str = "base",
1564
1565
  platform_settings: Optional[str] = None,
1565
- extra_collections_from: Optional[Dict[str, str]] = None,
1566
+ extra_collections_from: Optional[Dict[str, Union[List[str], str]]] = None,
1566
1567
  wait: bool = True,
1567
1568
  *,
1568
1569
  use_system_auth: bool = True,
@@ -1585,6 +1586,10 @@ def create_app(
1585
1586
  if Config.WITH_WARNINGS and (image_user is None or image_token is None):
1586
1587
  Config.logger.warning("image_auth not set")
1587
1588
  json_image = JsonImage(ref=image_ref, user=image_user, token=image_token)
1589
+ if extra_collections_from is not None:
1590
+ for k, v in extra_collections_from.items():
1591
+ if isinstance(v, str):
1592
+ extra_collections_from[k] = [v]
1588
1593
  data = UserApp(
1589
1594
  appId=app_id,
1590
1595
  inputId=input_id,
@@ -1612,7 +1617,7 @@ def update_app(
1612
1617
  image_auth: Optional[AUTH] = None,
1613
1618
  platform: str = "base",
1614
1619
  platform_settings: Optional[str] = None,
1615
- extra_collections_from: Optional[Dict[str, str]] = None,
1620
+ extra_collections_from: Optional[Dict[str, Union[List[str], str]]] = None,
1616
1621
  wait: bool = True,
1617
1622
  *,
1618
1623
  use_system_auth: bool = True,
@@ -1634,6 +1639,10 @@ def update_app(
1634
1639
  if Config.WITH_WARNINGS and (image_user is None or image_token is None):
1635
1640
  Config.logger.warning("image_auth not set")
1636
1641
  json_image = JsonImage(ref=image_ref, user=image_user, token=image_token)
1642
+ if extra_collections_from is not None:
1643
+ for k, v in extra_collections_from.items():
1644
+ if isinstance(v, str):
1645
+ extra_collections_from[k] = [v]
1637
1646
  data = UserApp(
1638
1647
  appId=app_id,
1639
1648
  inputId=input_id,
@@ -1932,7 +1941,7 @@ def __fix_cfg(cfg: Union[Dict[str, Any], Alias.Json, Cfg]) -> str:
1932
1941
  for app_setting in cfg.app_settings:
1933
1942
  if isinstance(app_setting.saveCollectionsName, str):
1934
1943
  app_setting.saveCollectionsName = [app_setting.saveCollectionsName]
1935
- cfg_json = cfg.json()
1944
+ cfg_json = cfg.model_dump_json()
1936
1945
  else:
1937
1946
  if isinstance(cfg, Alias.Json):
1938
1947
  cfg = json.loads(cfg)
@@ -2771,6 +2780,76 @@ def app_pause(
2771
2780
  )
2772
2781
 
2773
2782
 
2783
+ # Limits
2784
+
2785
+
2786
+ def get_user_limits(
2787
+ *,
2788
+ auth: Optional[AUTH] = None,
2789
+ conn_url: Optional[str] = None,
2790
+ batcher: Optional[Batcher] = None,
2791
+ ) -> UserLimits:
2792
+ """return limits for user"""
2793
+ if batcher is None:
2794
+ batcher = Config.BATCHER
2795
+ if batcher is not None:
2796
+ return batcher.add("getLimits", result_model=UserLimits)
2797
+ return f.get_limits(auth=auth, conn_url=conn_url)
2798
+
2799
+
2800
+ def update_user_limits(
2801
+ memory_request: Optional[int] = None,
2802
+ memory_limit: Optional[int] = None,
2803
+ cpu_request: Optional[int] = None,
2804
+ cpu_limit: Optional[int] = None,
2805
+ storage_request: Optional[int] = None,
2806
+ storage_limit: Optional[int] = None,
2807
+ gpu_disk: Optional[int] = None,
2808
+ wait: bool = True,
2809
+ *,
2810
+ auth: Optional[AUTH] = None,
2811
+ conn_url: Optional[str] = None,
2812
+ batcher: Optional[Batcher] = None,
2813
+ ) -> Alias.Info:
2814
+ """update limits for user"""
2815
+ if batcher is None:
2816
+ batcher = Config.BATCHER
2817
+ data = Limits(memoryRequest=memory_request, memoryLimit=memory_limit, cpuRequest=cpu_request, cpuLimit=cpu_limit, storageRequest=storage_request, storageLimit=storage_limit, gpuDisk=gpu_disk)
2818
+ if batcher is not None:
2819
+ return batcher.add("postLimits", data=data)
2820
+ return f.post_limits(
2821
+ data, wait=wait, auth=auth, conn_url=conn_url
2822
+ )
2823
+
2824
+
2825
+ def update_user_limits_scope(
2826
+ login: str,
2827
+ app_memory_request: Optional[int] = None,
2828
+ app_memory_limit: Optional[int] = None,
2829
+ app_cpu_request: Optional[int] = None,
2830
+ app_cpu_limit: Optional[int] = None,
2831
+ app_storage_request: Optional[int] = None,
2832
+ app_storage_limit: Optional[int] = None,
2833
+ assets_limit: Optional[int] = None,
2834
+ allow_common_gpu: Optional[bool] = None,
2835
+ gpu_disk_max: Optional[int] = None,
2836
+ wait: bool = True,
2837
+ *,
2838
+ auth: Optional[AUTH] = None,
2839
+ conn_url: Optional[str] = None,
2840
+ batcher: Optional[Batcher] = None,
2841
+ ) -> Alias.Info:
2842
+ """update limits scope for user, for superuser/admin"""
2843
+ if batcher is None:
2844
+ batcher = Config.BATCHER
2845
+ data = LimitsScope(login=login, appMemoryRequest=app_memory_request, appMemoryLimit=app_memory_limit, appCpuRequest=app_cpu_request, appCpuLimit=app_cpu_limit, appStorageRequest=app_storage_request, appStorageLimit=app_storage_limit, assetsLimit=assets_limit, allowCommonGpu=allow_common_gpu, gpuDiskMax=gpu_disk_max)
2846
+ if batcher is not None:
2847
+ return batcher.add("postUserLimits", data=data)
2848
+ return f.post_user_limits(
2849
+ data, wait=wait, auth=auth, conn_url=conn_url
2850
+ )
2851
+
2852
+
2774
2853
  # kafka
2775
2854
 
2776
2855
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: malevich-coretools
3
- Version: 0.3.9
3
+ Version: 0.3.11
4
4
  Author: Andrew Pogrebnoj
5
5
  Author-email: andrew@onjulius.co
6
6
  License-File: LICENSE
@@ -1,7 +1,7 @@
1
1
  malevich_coretools/__init__.py,sha256=DJtPESxkCZD2SbTZTrR_x0TKDQ4MJpmBqGw5YpKYidM,134
2
- malevich_coretools/utils.py,sha256=YPNYwhGTZTGWSPLX1vOMTTugSoQsU4CEiW6-rDLKa2I,93382
2
+ malevich_coretools/utils.py,sha256=H0edeBCNTwZsjSRI0jNcKptKxIqwUlLZgG9ebHDLq3o,96326
3
3
  malevich_coretools/abstract/__init__.py,sha256=ZWtP4gFLpNVFXzlMKXEK4iMnUqqMg07pL8yKGSJd6QI,38
4
- malevich_coretools/abstract/abstract.py,sha256=lMUDKf_GwExy8xLoOkotPSbVaPFT1LjYleJ3pNYw7xU,11762
4
+ malevich_coretools/abstract/abstract.py,sha256=n-n_ZjrhtIb4dGqjYUP6GJq2496Ug0ef95h7OGDlFj4,13229
5
5
  malevich_coretools/abstract/statuses.py,sha256=9ISSw_evsylBshLXoU44TCoFOrZm4bXIxyAFFDqdUWc,333
6
6
  malevich_coretools/admin/__init__.py,sha256=zdIcHs3T_NZ8HYWts-O7OpBEWHIu779QDZMGF5HRCLg,35
7
7
  malevich_coretools/admin/utils.py,sha256=68fbVsZ-Rmi4YMiOirr6_i03ruT-ts7xSuUntb7JdHs,3015
@@ -9,17 +9,18 @@ malevich_coretools/batch/__init__.py,sha256=co0xKwCGgHMk-r4Q62U6vUFhRdYsUMIfnx9I
9
9
  malevich_coretools/batch/utils.py,sha256=cqX34sfh85dCwLv7qprxatzhYxxj7LqZwjhlmk_3GXQ,7705
10
10
  malevich_coretools/funcs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  malevich_coretools/funcs/checks.py,sha256=Q5pRtRevQrGv_-SMbn2GgYnulhclDLBXdRtbw2QOYKU,223
12
- malevich_coretools/funcs/funcs.py,sha256=NM8TqdcnZ1bQrDejxEf-4aeL56JuG7oZ-I_DF-K3L5o,33904
13
- malevich_coretools/funcs/helpers.py,sha256=4Rin3TMfbZ6t0LUs7iltmdccmNTRoNOJlVkrurSFIH4,9202
12
+ malevich_coretools/funcs/funcs.py,sha256=AwlbVr8WBT4VSUk28w2CDr5eYbn6ktXuZQpYJQ85jVI,34344
13
+ malevich_coretools/funcs/helpers.py,sha256=CZYza0uQ68ywcfeUE9rP7q0VjsfnLtBp4z0qQZbIkjY,9843
14
14
  malevich_coretools/secondary/__init__.py,sha256=048HqvG36_1WdDVZK_RuECmaf14Iq2fviUysG1inlaE,78
15
15
  malevich_coretools/secondary/config.py,sha256=hRlSJuPQnhKyt1wmOAJX_XmcliaO0fPGbW94AE_Mazs,463
16
- malevich_coretools/secondary/const.py,sha256=TAbJxCQSFhe5zokGh8137mN33tGRFapFcldoynD94Jo,11435
16
+ malevich_coretools/secondary/const.py,sha256=eO_LGpAfJVEmj7PJQq6lovC8WZ-XoO_ynGAnpMggV7M,11623
17
17
  malevich_coretools/secondary/helpers.py,sha256=t-W9g9t0O1EaAX8UOb1wxXFAMawbtDotDH47t0GdjG4,6142
18
18
  malevich_coretools/secondary/kafka_utils.py,sha256=SIUnBFyfwsquN6MAUrEkKCw-1l7979Znl7OTQSX2UKo,989
19
19
  malevich_coretools/tools/__init__.py,sha256=jDxlCa5Dr6Y43qlI7JwsRAlBkKmFeTHTEnjNUvu-0iw,46
20
+ malevich_coretools/tools/abstract.py,sha256=B1RW1FeNHrQ6r1k-cQZ4k4noCRXkIGt-JUwVoXEDkAg,4466
20
21
  malevich_coretools/tools/vast.py,sha256=63tvy70qQV9vnK0eWytlgjBGSnfA7l3kSIDgACBbMMs,12893
21
- malevich_coretools-0.3.9.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
22
- malevich_coretools-0.3.9.dist-info/METADATA,sha256=GBI_0sYncVRBFQLsNUJtWZ0CVoHyz5sC4jULbW6Wq6M,264
23
- malevich_coretools-0.3.9.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
24
- malevich_coretools-0.3.9.dist-info/top_level.txt,sha256=wDX3s1Tso0otBPNrFRfXqyNpm48W4Bp5v6JfbITO2Z8,19
25
- malevich_coretools-0.3.9.dist-info/RECORD,,
22
+ malevich_coretools-0.3.11.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
23
+ malevich_coretools-0.3.11.dist-info/METADATA,sha256=rcSq6VtokUHEhlmGW9C46m9CWzvOv2tHH94cHbEnh2c,265
24
+ malevich_coretools-0.3.11.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
25
+ malevich_coretools-0.3.11.dist-info/top_level.txt,sha256=wDX3s1Tso0otBPNrFRfXqyNpm48W4Bp5v6JfbITO2Z8,19
26
+ malevich_coretools-0.3.11.dist-info/RECORD,,