malevich-coretools 0.3.67__py3-none-any.whl → 0.3.68__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.

@@ -1,3 +1,4 @@
1
+ from .dm_utils import * # noqa: F403
1
2
  from .secondary import logs_streaming # noqa: F401
2
3
  from .tools import vast_settings # noqa: F401
3
4
  from .utils import * # noqa: F403
@@ -0,0 +1,233 @@
1
+ from typing import (
2
+ Any,
3
+ AsyncIterable,
4
+ Coroutine,
5
+ Iterable,
6
+ List,
7
+ Literal,
8
+ Optional,
9
+ Union,
10
+ overload,
11
+ )
12
+
13
+ import malevich_coretools.funcs.dm_funcs as f
14
+
15
+
16
+ @overload
17
+ def dm_stream(
18
+ operation_id: str,
19
+ run_id: str,
20
+ bind_id: str,
21
+ *,
22
+ conn_url: Optional[str] = None,
23
+ is_async: Literal[False] = False,
24
+ ) -> Iterable:
25
+ pass
26
+
27
+
28
+ @overload
29
+ def dm_stream(
30
+ operation_id: str,
31
+ run_id: str,
32
+ bind_id: str,
33
+ *,
34
+ conn_url: Optional[str] = None,
35
+ is_async: Literal[True],
36
+ ) -> Coroutine[Any, Any, AsyncIterable]:
37
+ pass
38
+
39
+
40
+ def dm_stream(
41
+ operation_id: str,
42
+ run_id: str,
43
+ bind_id: str,
44
+ *,
45
+ conn_url: Optional[str] = None,
46
+ is_async: bool = False,
47
+ ) -> Union[Iterable, Coroutine[Any, Any, AsyncIterable]]:
48
+ if is_async:
49
+ return f.dm_stream_async(operation_id, run_id, bind_id, conn_url=conn_url)
50
+ return f.dm_stream(operation_id, run_id, bind_id, conn_url=conn_url)
51
+
52
+
53
+ @overload
54
+ def dm_continue(
55
+ operation_id: str,
56
+ run_id: str,
57
+ id: str,
58
+ data: Any,
59
+ *,
60
+ conn_url: Optional[str] = None,
61
+ is_async: Literal[False] = False,
62
+ ) -> None:
63
+ pass
64
+
65
+
66
+ @overload
67
+ def dm_continue(
68
+ operation_id: str,
69
+ run_id: str,
70
+ id: str,
71
+ data: Any,
72
+ *,
73
+ conn_url: Optional[str] = None,
74
+ is_async: Literal[True],
75
+ ) -> Coroutine[Any, Any, None]:
76
+ pass
77
+
78
+
79
+ def dm_continue(
80
+ operation_id: str,
81
+ run_id: str,
82
+ id: str,
83
+ data: Any,
84
+ *,
85
+ conn_url: Optional[str] = None,
86
+ is_async: bool = False,
87
+ ) -> Union[None, Coroutine[Any, Any, None]]:
88
+ if is_async:
89
+ return f.dm_continue_async(operation_id, run_id, id, data, conn_url=conn_url)
90
+ return f.dm_continue(operation_id, run_id, id, data, conn_url=conn_url)
91
+
92
+
93
+ @overload
94
+ def dm_state(
95
+ operation_id: str,
96
+ run_id: str,
97
+ bind_id: str,
98
+ key: Optional[str] = None,
99
+ index: Optional[int] = None,
100
+ *,
101
+ conn_url: Optional[str] = None,
102
+ is_async: Literal[False] = False,
103
+ ) -> Any:
104
+ pass
105
+
106
+
107
+ @overload
108
+ def dm_state(
109
+ operation_id: str,
110
+ run_id: str,
111
+ bind_id: str,
112
+ key: Optional[str] = None,
113
+ index: Optional[int] = None,
114
+ *,
115
+ conn_url: Optional[str] = None,
116
+ is_async: Literal[True],
117
+ ) -> Coroutine[Any, Any, Any]:
118
+ pass
119
+
120
+
121
+ def dm_state(
122
+ operation_id: str,
123
+ run_id: str,
124
+ bind_id: str,
125
+ key: Optional[str] = None,
126
+ index: Optional[int] = None,
127
+ *,
128
+ conn_url: Optional[str] = None,
129
+ is_async: bool = False,
130
+ ) -> Union[Any, Coroutine[Any, Any, Any]]:
131
+ if is_async:
132
+ return f.dm_state_async(operation_id, run_id, bind_id, key, index, conn_url=conn_url)
133
+ return f.dm_state(operation_id, run_id, bind_id, key, index, conn_url=conn_url)
134
+
135
+
136
+ @overload
137
+ def dm_journal_list(
138
+ operation_id: str,
139
+ run_id: str,
140
+ *,
141
+ conn_url: Optional[str] = None,
142
+ is_async: Literal[False] = False,
143
+ ) -> List[str]:
144
+ pass
145
+
146
+
147
+ @overload
148
+ def dm_journal_list(
149
+ operation_id: str,
150
+ run_id: str,
151
+ *,
152
+ conn_url: Optional[str] = None,
153
+ is_async: Literal[True],
154
+ ) -> Coroutine[Any, Any, List[str]]:
155
+ pass
156
+
157
+
158
+ def dm_journal_list(
159
+ operation_id: str,
160
+ run_id: str,
161
+ *,
162
+ conn_url: Optional[str] = None,
163
+ is_async: bool = False,
164
+ ) -> Union[List[str], Coroutine[Any, Any, List[str]]]:
165
+ if is_async:
166
+ return f.dm_journal_list_async(operation_id, run_id, conn_url=conn_url)
167
+ return f.dm_journal_list(operation_id, run_id, conn_url=conn_url)
168
+
169
+
170
+ @overload
171
+ def dm_journal(
172
+ operation_id: str,
173
+ run_id: str,
174
+ key: str,
175
+ is_stream: Literal[False] = False,
176
+ *,
177
+ conn_url: Optional[str] = None,
178
+ is_async: Literal[False] = False,
179
+ ) -> Any:
180
+ pass
181
+
182
+
183
+ @overload
184
+ def dm_journal(
185
+ operation_id: str,
186
+ run_id: str,
187
+ key: str,
188
+ is_stream: Literal[False] = False,
189
+ *,
190
+ conn_url: Optional[str] = None,
191
+ is_async: Literal[True],
192
+ ) -> Coroutine[Any, Any, Any]:
193
+ pass
194
+
195
+
196
+ @overload
197
+ def dm_journal(
198
+ operation_id: str,
199
+ run_id: str,
200
+ key: str,
201
+ is_stream: Literal[True],
202
+ *,
203
+ conn_url: Optional[str] = None,
204
+ is_async: Literal[False] = False,
205
+ ) -> Iterable:
206
+ pass
207
+
208
+
209
+ @overload
210
+ def dm_journal(
211
+ operation_id: str,
212
+ run_id: str,
213
+ key: str,
214
+ is_stream: Literal[True],
215
+ *,
216
+ conn_url: Optional[str] = None,
217
+ is_async: Literal[True],
218
+ ) -> Coroutine[Any, Any, AsyncIterable]:
219
+ pass
220
+
221
+
222
+ def dm_journal(
223
+ operation_id: str,
224
+ run_id: str,
225
+ key: str,
226
+ is_stream: bool = False,
227
+ *,
228
+ conn_url: Optional[str] = None,
229
+ is_async: bool = False,
230
+ ) -> Union[Any, Iterable, Coroutine[Any, Any, Union[Any, AsyncIterable]]]:
231
+ if is_async:
232
+ return f.dm_journal_async(operation_id, run_id, key, is_stream, conn_url=conn_url)
233
+ return f.dm_journal(operation_id, run_id, key, is_stream, conn_url=conn_url)
@@ -0,0 +1,162 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, AsyncIterable, Iterable, List, Optional, Union
3
+
4
+ import aiohttp
5
+ import requests
6
+ from requests.models import Response
7
+
8
+ from malevich_coretools.secondary import Config
9
+ from malevich_coretools.secondary.const import * # noqa: F403
10
+
11
+
12
+ def dm_stream(operation_id: str, run_id: str, bind_id: str, conn_url: Optional[str]=None) -> Iterable:
13
+ return send_to_dm_stream(DM_STREAM(operation_id, run_id, bind_id), conn_url=conn_url)
14
+
15
+
16
+ async def dm_stream_async(operation_id: str, run_id: str, bind_id: str, conn_url: Optional[str]=None) -> AsyncIterable:
17
+ return await send_to_dm_stream_async(DM_STREAM(operation_id, run_id, bind_id), conn_url=conn_url)
18
+
19
+
20
+ def dm_continue(operation_id: str, run_id: str, id: str, data: Any, conn_url: Optional[str]=None) -> None:
21
+ return send_to_dm_post(DM_CONTINUE(operation_id, run_id, id), data, conn_url=conn_url)
22
+
23
+
24
+ async def dm_continue_async(operation_id: str, run_id: str, id: str, data: Any, conn_url: Optional[str]=None) -> None:
25
+ return await send_to_dm_post_async(DM_CONTINUE(operation_id, run_id, id), data, conn_url=conn_url)
26
+
27
+
28
+ def dm_state(operation_id: str, run_id: str, bind_id: str, key: Optional[str] = None, index: Optional[int] = None, conn_url: Optional[str]=None) -> Any:
29
+ return send_to_dm_get(DM_STATE(operation_id, run_id, bind_id, key, index), conn_url=conn_url)
30
+
31
+
32
+ async def dm_state_async(operation_id: str, run_id: str, bind_id: str, key: Optional[str] = None, index: Optional[int] = None, conn_url: Optional[str]=None) -> Any:
33
+ return await send_to_dm_get_async(DM_STATE(operation_id, run_id, bind_id, key, index), conn_url=conn_url)
34
+
35
+
36
+ def dm_journal_list(operation_id: str, run_id: str, conn_url: Optional[str]=None) -> List[str]:
37
+ return send_to_dm_get(DM_JOURNAL_LIST(operation_id, run_id), is_text=False, conn_url=conn_url)
38
+
39
+
40
+ async def dm_journal_list_async(operation_id: str, run_id: str, conn_url: Optional[str]=None) -> List[str]:
41
+ return await send_to_dm_get_async(DM_JOURNAL_LIST(operation_id, run_id), is_text=False, conn_url=conn_url)
42
+
43
+
44
+ def dm_journal(operation_id: str, run_id: str, key: str, is_stream: bool, conn_url: Optional[str]=None) -> Union[Any, Iterable]:
45
+ if is_stream:
46
+ return send_to_dm_stream(DM_JOURNAL(operation_id, run_id, key, is_stream), conn_url=conn_url)
47
+ return send_to_dm_get(DM_JOURNAL(operation_id, run_id, key, is_stream), conn_url=conn_url)
48
+
49
+
50
+ async def dm_journal_async(operation_id: str, run_id: str, key: str, is_stream: bool, conn_url: Optional[str]=None) -> Union[Any, AsyncIterable]:
51
+ if is_stream:
52
+ return await send_to_dm_stream_async(DM_JOURNAL(operation_id, run_id, key, is_stream), conn_url=conn_url)
53
+ return await send_to_dm_get_async(DM_JOURNAL(operation_id, run_id, key, is_stream), conn_url=conn_url)
54
+
55
+
56
+ #
57
+
58
+ def __check_response(path: str, response: Response): # noqa: ANN202
59
+ if response.status_code >= 400:
60
+ text = response.text
61
+ msg = f"failed: {text}" if len(text) > 0 else "failed"
62
+ Config.logger.error(f"{path} {msg}")
63
+
64
+ if response.reason is not None and len(response.reason) == 0:
65
+ response.reason = text
66
+ response.raise_for_status()
67
+
68
+
69
+ async def __async_check_response(response: aiohttp.ClientResponse, path: Optional[str] = None): # noqa: ANN202
70
+ if not response.ok:
71
+ text = await response.text()
72
+ if path is not None:
73
+ msg = f"failed: {text}" if len(text) > 0 else "failed"
74
+ Config.logger.error(f"{path} {msg}")
75
+ else:
76
+ Config.logger.error(text)
77
+
78
+ if response.reason is not None and len(response.reason) == 0:
79
+ response.reason = text
80
+ response.raise_for_status()
81
+
82
+
83
+ def send_to_dm_get(path: str, is_text: bool=True, conn_url: Optional[str]=None) -> Optional[Union[str, bytes]]:
84
+ host = Config.DM_HOST_PORT if conn_url is None else conn_url
85
+ assert host is not None, "dm host port not set"
86
+ response = requests.get(f"{host}{path}", headers=HEADERS)
87
+ __check_response(f"{host}{path}", response)
88
+ if response.status_code == HTTPStatus.NO_CONTENT:
89
+ return None
90
+ if is_text is True:
91
+ return response.text
92
+ elif is_text is False:
93
+ return response.json()
94
+ else:
95
+ return response.content
96
+
97
+
98
+ async def send_to_dm_get_async(path: str, is_text: bool=True, conn_url: Optional[str]=None, async_session = None) -> Optional[Union[str, bytes]]:
99
+ host = Config.DM_HOST_PORT if conn_url is None else conn_url
100
+ assert host is not None, "dm host port not set"
101
+ async with async_session or aiohttp.ClientSession(connector=aiohttp.TCPConnector(verify_ssl=False), timeout=aiohttp.ClientTimeout(total=None)) as session:
102
+ async with session.get(f"{host}{path}", headers=HEADERS) as response:
103
+ await __async_check_response(response, f"{host}{path}")
104
+ if response.status == HTTPStatus.NO_CONTENT:
105
+ return None
106
+ if is_text is True:
107
+ return await response.text()
108
+ elif is_text is False:
109
+ return await response.json()
110
+ else:
111
+ return await response.read()
112
+
113
+
114
+ def send_to_dm_post(path: str, operation: Optional[Any] = None, conn_url: Optional[str]=None) -> Optional[str]: # noqa: ANN401
115
+ host = Config.DM_HOST_PORT if conn_url is None else conn_url
116
+ assert host is not None, "dm host port not set"
117
+ response = requests.post(f"{host}{path}", data=operation, headers=HEADERS)
118
+ __check_response(f"{host}{path}", response)
119
+ if response.status_code == HTTPStatus.NO_CONTENT:
120
+ return None
121
+ return response.text
122
+
123
+
124
+ async def send_to_dm_post_async(path: str, operation: Optional[Any] = None, conn_url: Optional[str]=None, async_session=None) -> str: # noqa: ANN401
125
+ host = Config.DM_HOST_PORT if conn_url is None else conn_url
126
+ assert host is not None, "dm host port not set"
127
+ async with async_session or aiohttp.ClientSession(connector=aiohttp.TCPConnector(verify_ssl=False), timeout=aiohttp.ClientTimeout(total=None)) as session:
128
+ async with session.post(f"{host}{path}", data=operation, headers=HEADERS) as response:
129
+ await __async_check_response(response, f"{host}{path}")
130
+ if response.status == HTTPStatus.NO_CONTENT:
131
+ return None
132
+ return response.text()
133
+
134
+
135
+ def send_to_dm_stream(path: str, conn_url: Optional[str]=None) -> Iterable:
136
+ host = Config.DM_HOST_PORT if conn_url is None else conn_url
137
+ assert host is not None, "dm host port not set"
138
+
139
+ def stream_generator() -> None:
140
+ with requests.get(f"{host}{path}", headers=HEADERS, stream=True) as response:
141
+ __check_response(f"{host}{path}", response)
142
+ if response.status_code == HTTPStatus.NO_CONTENT:
143
+ return
144
+ for chunk in response.iter_content(chunk_size=4096):
145
+ if chunk:
146
+ yield chunk.decode("utf-8", errors="ignore")
147
+ return stream_generator()
148
+
149
+
150
+ async def send_to_dm_stream_async(path: str, conn_url: Optional[str]=None, async_session = None) -> AsyncIterable:
151
+ host = Config.DM_HOST_PORT if conn_url is None else conn_url
152
+ assert host is not None, "dm host port not set"
153
+
154
+ async def stream_generator() -> None:
155
+ async with async_session or aiohttp.ClientSession(connector=aiohttp.TCPConnector(verify_ssl=False), timeout=aiohttp.ClientTimeout(total=None)) as session:
156
+ async with session.get(f"{host}{path}", headers=HEADERS) as response:
157
+ await __async_check_response(response, f"{host}{path}")
158
+ if response.status == HTTPStatus.NO_CONTENT:
159
+ return
160
+ async for chunk in response.content.iter_any():
161
+ yield chunk.decode("utf-8", errors="ignore")
162
+ return stream_generator()
@@ -8,6 +8,7 @@ class Config:
8
8
  TOKEN = os.environ.get("GITLAB_ACCESS_TOKEN") # FIXME
9
9
 
10
10
  HOST_PORT = None
11
+ DM_HOST_PORT = None
11
12
  KAFKA_HOST_PORT = None
12
13
  CORE_USERNAME = None
13
14
  CORE_PASSWORD = None
@@ -239,3 +239,10 @@ KAFKA_SEND = f"{MANAGER_MAIN}/kafkaMsg"
239
239
  ## BatchController
240
240
  BATCH_MAIN = f"{API_VERSION}/batch"
241
241
  BATCH = BATCH_MAIN
242
+
243
+ ##### DM
244
+ DM_STREAM = lambda operationId, runId, bindId : f"stream/{operationId}/{runId}/{bindId}"
245
+ DM_CONTINUE = lambda operationId, runId, id: f"continue/{operationId}/{runId}/{id}"
246
+ DM_STATE = lambda operationId, runId, bindId, key, index : with_key_values(f"state/{operationId}/{runId}/{bindId}", {"key": key, "index": index})
247
+ DM_JOURNAL_LIST = lambda operationId, runId : f"journal/{operationId}/{runId}"
248
+ DM_JOURNAL = lambda operationId, runId, key, stream : with_key_values(f"journal/{operationId}/{runId}/{key}", {"stream": stream})
@@ -47,15 +47,24 @@ def set_host_port(host_port: str) -> None:
47
47
  Config.HOST_PORT = host_port
48
48
 
49
49
 
50
+ def set_dm_host_port(host_port: str) -> None:
51
+ """update host and port for malevich-dm, example: `http://localhost:8000/` """
52
+ assert len(host_port) > 0, "empty host port"
53
+ host_port = host_port if host_port[-1] == "/" else f"{host_port}/"
54
+ Config.DM_HOST_PORT = host_port
55
+
56
+
50
57
  def set_kafka_host_port(host_port: str) -> None:
51
58
  """update kafka host and port for malevich-kafka, example: `localhost:9092` """
52
59
  assert len(host_port) > 0, "empty host port"
53
60
  Config.KAFKA_HOST_PORT = host_port
54
61
 
55
62
 
56
- def set_conn_url(conn_url: str) -> None:
63
+ def set_conn_url(conn_url: str, dm_url: Optional[str] = None) -> None:
57
64
  """analogue set_host_port; update `conn_url` for malevich-core, example: `http://localhost:8080/` """
58
65
  set_host_port(conn_url)
66
+ if dm_url is not None:
67
+ set_dm_host_port(dm_url)
59
68
 
60
69
 
61
70
  def set_verbose(verbose: bool) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: malevich-coretools
3
- Version: 0.3.67
3
+ Version: 0.3.68
4
4
  Author: Andrew Pogrebnoj
5
5
  Author-email: andrew@onjulius.co
6
6
  License-File: LICENSE
@@ -1,5 +1,6 @@
1
- malevich_coretools/__init__.py,sha256=DJtPESxkCZD2SbTZTrR_x0TKDQ4MJpmBqGw5YpKYidM,134
2
- malevich_coretools/utils.py,sha256=o_uH_HJKs4od0ExFmG4LMwZ1pH4V6_90QYxn_sgVyC8,276863
1
+ malevich_coretools/__init__.py,sha256=0WUBUhATgnU3tctwv0AxzvRr0zRlW6V5INQljBCLRzo,172
2
+ malevich_coretools/dm_utils.py,sha256=WvjtqVaAiwahej-oMnB5JJKFiAcTRiyNStDu0WpifHs,4775
3
+ malevich_coretools/utils.py,sha256=imtU54FZ1poleLROQ-b20rynXlCEudYK0B_tnjKWoS0,277240
3
4
  malevich_coretools/abstract/__init__.py,sha256=6vQ08c8HPYyT_pPkKlc-EwQKE8xG3HTEo2p_GiI5rik,142
4
5
  malevich_coretools/abstract/abstract.py,sha256=SSmGmn2U4hBV3-e1Fxi1SsfgddB4TTE4_VFRR6VMP7g,17732
5
6
  malevich_coretools/abstract/operations.py,sha256=cWlo2xzW-rzkTInzpDjBYeL68KfLYqSpZJRzCQ4OzjA,3070
@@ -11,18 +12,19 @@ malevich_coretools/batch/__init__.py,sha256=taxyZl8YOZd2EBd3leN6slzMkejUtjQ64Na3
11
12
  malevich_coretools/batch/utils.py,sha256=FRmCYU-zr-RjgT1Mo3CUNcB2mW1t_gKCJazcMx6aIW4,7719
12
13
  malevich_coretools/funcs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
14
  malevich_coretools/funcs/checks.py,sha256=Q5pRtRevQrGv_-SMbn2GgYnulhclDLBXdRtbw2QOYKU,223
15
+ malevich_coretools/funcs/dm_funcs.py,sha256=Z0oSzMb9x6N2yANbIICz6erF9fJ5drg3Zheh-_VTPx4,7812
14
16
  malevich_coretools/funcs/funcs.py,sha256=JcRnt-wiOBOz-xt463Jv5ma8DmXXnR3R_5ALXWZAoZY,85988
15
17
  malevich_coretools/funcs/helpers.py,sha256=nYbUdtAuSSa9VMr7Oy2y0yvEMLv9EI1jzGq6eynuNLU,13573
16
18
  malevich_coretools/secondary/__init__.py,sha256=048HqvG36_1WdDVZK_RuECmaf14Iq2fviUysG1inlaE,78
17
- malevich_coretools/secondary/config.py,sha256=hRlSJuPQnhKyt1wmOAJX_XmcliaO0fPGbW94AE_Mazs,463
18
- malevich_coretools/secondary/const.py,sha256=rZ8d2tmBmiDEk5zhLKMe6mZRnwMvFrquJeK0RlTNzWw,15386
19
+ malevich_coretools/secondary/config.py,sha256=cjqKiWLm6m1kArOq4DWOHaNxKT_kHP9WUyHVkYe3UeI,487
20
+ malevich_coretools/secondary/const.py,sha256=yS--jwK01b98f2heACJfbPzCE2rItyPSX2PFIoQIy6M,15924
19
21
  malevich_coretools/secondary/helpers.py,sha256=V5xNv-Rt4SNkthTcNnMtYPjiYfoHmwUR8ApU8qFmzT0,7986
20
22
  malevich_coretools/secondary/kafka_utils.py,sha256=SIUnBFyfwsquN6MAUrEkKCw-1l7979Znl7OTQSX2UKo,989
21
23
  malevich_coretools/tools/__init__.py,sha256=jDxlCa5Dr6Y43qlI7JwsRAlBkKmFeTHTEnjNUvu-0iw,46
22
24
  malevich_coretools/tools/abstract.py,sha256=B1RW1FeNHrQ6r1k-cQZ4k4noCRXkIGt-JUwVoXEDkAg,4466
23
25
  malevich_coretools/tools/vast.py,sha256=63tvy70qQV9vnK0eWytlgjBGSnfA7l3kSIDgACBbMMs,12893
24
- malevich_coretools-0.3.67.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
25
- malevich_coretools-0.3.67.dist-info/METADATA,sha256=NyxNf6rMc1Q-bscMz5eHBbtm1hhdtbfdRAjY4FHg47k,347
26
- malevich_coretools-0.3.67.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- malevich_coretools-0.3.67.dist-info/top_level.txt,sha256=wDX3s1Tso0otBPNrFRfXqyNpm48W4Bp5v6JfbITO2Z8,19
28
- malevich_coretools-0.3.67.dist-info/RECORD,,
26
+ malevich_coretools-0.3.68.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
27
+ malevich_coretools-0.3.68.dist-info/METADATA,sha256=gaBdEDfWy1DOC6l_7GlMOiIMOP_ntOBjn7yMhYmbccg,347
28
+ malevich_coretools-0.3.68.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
+ malevich_coretools-0.3.68.dist-info/top_level.txt,sha256=wDX3s1Tso0otBPNrFRfXqyNpm48W4Bp5v6JfbITO2Z8,19
30
+ malevich_coretools-0.3.68.dist-info/RECORD,,