konfai 1.0.7__py3-none-any.whl → 1.0.8__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 konfai might be problematic. Click here for more details.
- konfai/network/network.py +6 -11
- konfai/predictor.py +80 -38
- {konfai-1.0.7.dist-info → konfai-1.0.8.dist-info}/METADATA +5 -3
- {konfai-1.0.7.dist-info → konfai-1.0.8.dist-info}/RECORD +8 -8
- {konfai-1.0.7.dist-info → konfai-1.0.8.dist-info}/WHEEL +0 -0
- {konfai-1.0.7.dist-info → konfai-1.0.8.dist-info}/entry_points.txt +0 -0
- {konfai-1.0.7.dist-info → konfai-1.0.8.dist-info}/licenses/LICENSE +0 -0
- {konfai-1.0.7.dist-info → konfai-1.0.8.dist-info}/top_level.txt +0 -0
konfai/network/network.py
CHANGED
|
@@ -509,10 +509,10 @@ class Network(ModuleArgsDict, ABC):
|
|
|
509
509
|
results[name_function(self)] = function(self, *args, **kwargs)
|
|
510
510
|
return results
|
|
511
511
|
|
|
512
|
-
def _function_network(
|
|
512
|
+
def _function_network():
|
|
513
513
|
def _function_network_d(function : Callable):
|
|
514
514
|
def new_function(self : Self, *args, **kwargs) -> dict[str, object]:
|
|
515
|
-
return self._apply_network(lambda network: network.
|
|
515
|
+
return self._apply_network(lambda network: network.getName(), [], self.getName(), function, *args, **kwargs)
|
|
516
516
|
return new_function
|
|
517
517
|
return _function_network_d
|
|
518
518
|
|
|
@@ -547,7 +547,7 @@ class Network(ModuleArgsDict, ABC):
|
|
|
547
547
|
self._it = 0
|
|
548
548
|
self.outputsGroup : list[OutputsGroup]= []
|
|
549
549
|
|
|
550
|
-
@_function_network(
|
|
550
|
+
@_function_network()
|
|
551
551
|
def state_dict(self) -> dict[str, OrderedDict]:
|
|
552
552
|
destination = OrderedDict()
|
|
553
553
|
destination._metadata = OrderedDict()
|
|
@@ -618,13 +618,13 @@ class Network(ModuleArgsDict, ABC):
|
|
|
618
618
|
module.apply(fn)
|
|
619
619
|
fn(self)
|
|
620
620
|
|
|
621
|
-
@_function_network(
|
|
621
|
+
@_function_network()
|
|
622
622
|
def load(self, state_dict : dict[str, dict[str, torch.Tensor]], init: bool = True, ema : bool =False):
|
|
623
623
|
if init:
|
|
624
624
|
self.apply(partial(ModuleArgsDict.init_func, init_type=self.init_type, init_gain=self.init_gain))
|
|
625
625
|
name = "Model" + ("_EMA" if ema else "")
|
|
626
626
|
if name in state_dict:
|
|
627
|
-
model_state_dict_tmp = {k.split(".")[-1] : v for k, v in state_dict[name].items()}[self.
|
|
627
|
+
model_state_dict_tmp = {k.split(".")[-1] : v for k, v in state_dict[name].items()}[self.getName()]
|
|
628
628
|
map = self.getMap()
|
|
629
629
|
model_state_dict : OrderedDict[str, torch.Tensor] = OrderedDict()
|
|
630
630
|
|
|
@@ -806,8 +806,6 @@ class Network(ModuleArgsDict, ABC):
|
|
|
806
806
|
|
|
807
807
|
if not len(layers_name):
|
|
808
808
|
break
|
|
809
|
-
|
|
810
|
-
|
|
811
809
|
|
|
812
810
|
def init_outputsGroup(self):
|
|
813
811
|
metric_tmp = {network.measure : network.measure.outputsCriterions.keys() for network in self.getNetworks().values() if network.measure}
|
|
@@ -906,15 +904,12 @@ class Network(ModuleArgsDict, ABC):
|
|
|
906
904
|
return module
|
|
907
905
|
|
|
908
906
|
def getName(self) -> str:
|
|
909
|
-
return self.
|
|
907
|
+
return self.name
|
|
910
908
|
|
|
911
909
|
def setName(self, name: str) -> Self:
|
|
912
910
|
self.name = name
|
|
913
911
|
return self
|
|
914
912
|
|
|
915
|
-
def _getName(self) -> str:
|
|
916
|
-
return self.name
|
|
917
|
-
|
|
918
913
|
def setState(self, state: NetState):
|
|
919
914
|
for module in self.modules():
|
|
920
915
|
if isinstance(module, ModuleArgsDict):
|
konfai/predictor.py
CHANGED
|
@@ -22,6 +22,8 @@ import torch.distributed as dist
|
|
|
22
22
|
from torch.nn.parallel import DistributedDataParallel as DDP
|
|
23
23
|
from torch.utils.data import DataLoader
|
|
24
24
|
import importlib
|
|
25
|
+
import copy
|
|
26
|
+
from collections import defaultdict
|
|
25
27
|
|
|
26
28
|
class OutDataset(Dataset, NeedDevice, ABC):
|
|
27
29
|
|
|
@@ -152,7 +154,7 @@ class OutSameAsGroupDataset(OutDataset):
|
|
|
152
154
|
if self.redution == "mean":
|
|
153
155
|
result = torch.mean(result.float(), dim=0).to(dtype)
|
|
154
156
|
elif self.redution == "median":
|
|
155
|
-
result, _ = torch.median(result.float(), dim=0)
|
|
157
|
+
result, _ = torch.median(result.float(), dim=0)
|
|
156
158
|
else:
|
|
157
159
|
raise NameError("Reduction method does not exist (mean, median)")
|
|
158
160
|
for transform in self.final_transforms:
|
|
@@ -199,19 +201,19 @@ class OutDatasetLoader():
|
|
|
199
201
|
|
|
200
202
|
class _Predictor():
|
|
201
203
|
|
|
202
|
-
def __init__(self, world_size: int, global_rank: int, local_rank: int, predict_path: str, data_log: Union[list[str], None], outsDataset: dict[str, OutDataset],
|
|
204
|
+
def __init__(self, world_size: int, global_rank: int, local_rank: int, predict_path: str, data_log: Union[list[str], None], outsDataset: dict[str, OutDataset], modelComposite: DDP, dataloader_prediction: DataLoader) -> None:
|
|
203
205
|
self.world_size = world_size
|
|
204
206
|
self.global_rank = global_rank
|
|
205
207
|
self.local_rank = local_rank
|
|
206
208
|
|
|
207
|
-
self.
|
|
209
|
+
self.modelComposite = modelComposite
|
|
208
210
|
self.dataloader_prediction = dataloader_prediction
|
|
209
211
|
self.outsDataset = outsDataset
|
|
210
212
|
|
|
211
213
|
|
|
212
214
|
self.it = 0
|
|
213
215
|
|
|
214
|
-
self.device = self.
|
|
216
|
+
self.device = self.modelComposite.device
|
|
215
217
|
self.dataset: DatasetIter = self.dataloader_prediction.dataset
|
|
216
218
|
patch_size, overlap = self.dataset.getPatchConfig()
|
|
217
219
|
for outDataset in self.outsDataset.values():
|
|
@@ -220,7 +222,7 @@ class _Predictor():
|
|
|
220
222
|
if data_log is not None:
|
|
221
223
|
for data in data_log:
|
|
222
224
|
self.data_log[data.split("/")[0].replace(":", ".")] = (DataLog.__getitem__(data.split("/")[1]).value[0], int(data.split("/")[2]))
|
|
223
|
-
self.tb = SummaryWriter(log_dir = predict_path+"Metric/") if len([network for network in self.
|
|
225
|
+
self.tb = SummaryWriter(log_dir = predict_path+"Metric/") if len([network for network in self.modelComposite.module.getNetworks().values() if network.measure is not None]) or len(self.data_log) else None
|
|
224
226
|
|
|
225
227
|
def __enter__(self):
|
|
226
228
|
return self
|
|
@@ -234,15 +236,15 @@ class _Predictor():
|
|
|
234
236
|
|
|
235
237
|
@torch.no_grad()
|
|
236
238
|
def run(self):
|
|
237
|
-
self.
|
|
238
|
-
self.
|
|
239
|
-
desc = lambda : "Prediction : {}".format(description(self.
|
|
239
|
+
self.modelComposite.eval()
|
|
240
|
+
self.modelComposite.module.setState(NetState.PREDICTION)
|
|
241
|
+
desc = lambda : "Prediction : {}".format(description(self.modelComposite))
|
|
240
242
|
self.dataloader_prediction.dataset.load()
|
|
241
243
|
with tqdm.tqdm(iterable = enumerate(self.dataloader_prediction), leave=False, desc = desc(), total=len(self.dataloader_prediction), disable=self.global_rank != 0 and "DL_API_CLUSTER" not in os.environ) as batch_iter:
|
|
242
244
|
dist.barrier()
|
|
243
245
|
for it, data_dict in batch_iter:
|
|
244
246
|
input = self.getInput(data_dict)
|
|
245
|
-
for name, output in self.
|
|
247
|
+
for name, output in self.modelComposite(input, list(self.outsDataset.keys())):
|
|
246
248
|
self._predict_log(data_dict)
|
|
247
249
|
outDataset = self.outsDataset[name]
|
|
248
250
|
for i, (index, patch_augmentation, patch_index) in enumerate([(int(index), int(patch_augmentation), int(patch_index)) for index, patch_augmentation, patch_index in zip(list(data_dict.values())[0][1], list(data_dict.values())[0][2], list(data_dict.values())[0][3])]):
|
|
@@ -254,7 +256,7 @@ class _Predictor():
|
|
|
254
256
|
self.it += 1
|
|
255
257
|
|
|
256
258
|
def _predict_log(self, data_dict : dict[str, tuple[torch.Tensor, int, int, int]]):
|
|
257
|
-
measures = DistributedObject.getMeasure(self.world_size, self.global_rank, self.local_rank, {"" : self.
|
|
259
|
+
measures = DistributedObject.getMeasure(self.world_size, self.global_rank, self.local_rank, {"" : self.modelComposite.module}, 1)
|
|
258
260
|
|
|
259
261
|
if self.global_rank == 0:
|
|
260
262
|
images_log = []
|
|
@@ -265,20 +267,56 @@ class _Predictor():
|
|
|
265
267
|
else:
|
|
266
268
|
images_log.append(name.replace(":", "."))
|
|
267
269
|
|
|
268
|
-
for name, network in self.
|
|
270
|
+
for name, network in self.modelComposite.module.getNetworks().items():
|
|
269
271
|
if network.measure is not None:
|
|
270
272
|
self.tb.add_scalars("Prediction/{}/Loss".format(name), {k : v[1] for k, v in measures["{}{}".format(name, "")][0].items()}, self.it)
|
|
271
273
|
self.tb.add_scalars("Prediction/{}/Metric".format(name), {k : v[1] for k, v in measures["{}{}".format(name, "")][1].items()}, self.it)
|
|
272
274
|
if len(images_log):
|
|
273
275
|
for name, layer, _ in self.model.module.get_layers([v.to(0) for k, v in self.getInput(data_dict).items() if k[1]], images_log):
|
|
274
276
|
self.data_log[name][0](self.tb, "Prediction/{}".format(name), layer[:self.data_log[name][1]].detach().cpu().numpy(), self.it)
|
|
277
|
+
|
|
278
|
+
class ModelComposite(Network):
|
|
279
|
+
|
|
280
|
+
def __init__(self, model: Network, nb_models: int, method: str):
|
|
281
|
+
super().__init__(model.in_channels, model.optimizer, model.schedulers, model.outputsCriterionsLoader, model.patch, model.nb_batch_per_step, model.init_type, model.init_gain, model.dim)
|
|
282
|
+
self.method = method
|
|
283
|
+
for i in range(nb_models):
|
|
284
|
+
self.add_module("Model_{}".format(i), copy.deepcopy(model), in_branch=[0], out_branch=["output_{}".format(i)])
|
|
285
|
+
|
|
286
|
+
def load(self, state_dicts : list[dict[str, dict[str, torch.Tensor]]]):
|
|
287
|
+
for i, state_dict in enumerate(state_dicts):
|
|
288
|
+
self["Model_{}".format(i)].load(state_dict, init=False)
|
|
289
|
+
self["Model_{}".format(i)].setName("{}_{}".format(self["Model_{}".format(i)].getName(), i))
|
|
290
|
+
|
|
291
|
+
def forward(self, data_dict: dict[tuple[str, bool], torch.Tensor], output_layers: list[str] = []) -> list[tuple[str, torch.Tensor]]:
|
|
292
|
+
result = {}
|
|
293
|
+
for name, module in self.items():
|
|
294
|
+
result[name] = module(data_dict, output_layers)
|
|
275
295
|
|
|
296
|
+
aggregated = defaultdict(list)
|
|
297
|
+
for module_outputs in result.values():
|
|
298
|
+
for key, tensor in module_outputs:
|
|
299
|
+
aggregated[key].append(tensor)
|
|
300
|
+
|
|
301
|
+
final_outputs = []
|
|
302
|
+
for key, tensors in aggregated.items():
|
|
303
|
+
stacked = torch.stack(tensors, dim=0)
|
|
304
|
+
if self.method == 'mean':
|
|
305
|
+
agg = torch.mean(stacked, dim=0)
|
|
306
|
+
elif self.method == 'median':
|
|
307
|
+
agg = torch.median(stacked, dim=0).values
|
|
308
|
+
final_outputs.append((key, agg))
|
|
309
|
+
|
|
310
|
+
return final_outputs
|
|
311
|
+
|
|
312
|
+
|
|
276
313
|
class Predictor(DistributedObject):
|
|
277
314
|
|
|
278
315
|
@config("Predictor")
|
|
279
316
|
def __init__(self,
|
|
280
317
|
model: ModelLoader = ModelLoader(),
|
|
281
318
|
dataset: DataPrediction = DataPrediction(),
|
|
319
|
+
combine: str = "mean",
|
|
282
320
|
train_name: str = "name",
|
|
283
321
|
manual_seed : Union[int, None] = None,
|
|
284
322
|
gpu_checkpoints: Union[list[str], None] = None,
|
|
@@ -289,6 +327,7 @@ class Predictor(DistributedObject):
|
|
|
289
327
|
super().__init__(train_name)
|
|
290
328
|
self.manual_seed = manual_seed
|
|
291
329
|
self.dataset = dataset
|
|
330
|
+
self.combine = combine
|
|
292
331
|
|
|
293
332
|
self.model = model.getModel(train=False)
|
|
294
333
|
self.it = 0
|
|
@@ -305,28 +344,31 @@ class Predictor(DistributedObject):
|
|
|
305
344
|
|
|
306
345
|
self.gpu_checkpoints = gpu_checkpoints
|
|
307
346
|
|
|
308
|
-
def _load(self) -> dict[str, dict[str, torch.Tensor]]:
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
name = MODEL()
|
|
347
|
+
def _load(self) -> list[dict[str, dict[str, torch.Tensor]]]:
|
|
348
|
+
model_paths = MODEL().split(":")
|
|
349
|
+
state_dicts = []
|
|
350
|
+
for model_path in model_paths:
|
|
351
|
+
if model_path.startswith("https://"):
|
|
352
|
+
try:
|
|
353
|
+
state_dicts.append(torch.hub.load_state_dict_from_url(url=model_path, map_location="cpu", check_hash=True))
|
|
354
|
+
except:
|
|
355
|
+
raise Exception("Model : {} does not exist !".format(model_path))
|
|
318
356
|
else:
|
|
319
|
-
if
|
|
320
|
-
path =
|
|
321
|
-
name =
|
|
357
|
+
if model_path != "":
|
|
358
|
+
path = ""
|
|
359
|
+
name = model_path
|
|
322
360
|
else:
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
361
|
+
if self.name.endswith(".pt"):
|
|
362
|
+
path = MODELS_DIRECTORY()+"/".join(self.name.split("/")[:-1])+"/StateDict/"
|
|
363
|
+
name = self.name.split("/")[-1]
|
|
364
|
+
else:
|
|
365
|
+
path = MODELS_DIRECTORY()+self.name+"/StateDict/"
|
|
366
|
+
name = sorted(os.listdir(path))[-1]
|
|
367
|
+
if os.path.exists(path+name):
|
|
368
|
+
state_dicts.append(torch.load(path+name, weights_only=False))
|
|
369
|
+
else:
|
|
370
|
+
raise Exception("Model : {} does not exist !".format(path+name))
|
|
371
|
+
return state_dicts
|
|
330
372
|
|
|
331
373
|
def setup(self, world_size: int):
|
|
332
374
|
for dataset_filename in self.datasets_filename:
|
|
@@ -345,11 +387,11 @@ class Predictor(DistributedObject):
|
|
|
345
387
|
self.model.init(autocast=False, state = State.PREDICTION)
|
|
346
388
|
self.model.init_outputsGroup()
|
|
347
389
|
self.model._compute_channels_trace(self.model, self.model.in_channels, None, self.gpu_checkpoints)
|
|
348
|
-
self.
|
|
349
|
-
|
|
350
|
-
if len(list(self.outsDataset.keys())) == 0 and len([network for network in self.model.getNetworks().values() if network.measure is not None]) == 0:
|
|
351
|
-
exit(0)
|
|
390
|
+
self.modelComposite = ModelComposite(self.model, len(MODEL().split(":")), self.combine)
|
|
391
|
+
self.modelComposite.load(self._load())
|
|
352
392
|
|
|
393
|
+
if len(list(self.outsDataset.keys())) == 0 and len([network for network in self.modelComposite.getNetworks().values() if network.measure is not None]) == 0:
|
|
394
|
+
exit(0)
|
|
353
395
|
|
|
354
396
|
self.size = (len(self.gpu_checkpoints)+1 if self.gpu_checkpoints else 1)
|
|
355
397
|
self.dataloader = self.dataset.getData(world_size//self.size)
|
|
@@ -358,9 +400,9 @@ class Predictor(DistributedObject):
|
|
|
358
400
|
|
|
359
401
|
|
|
360
402
|
def run_process(self, world_size: int, global_rank: int, local_rank: int, dataloaders: list[DataLoader]):
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
with _Predictor(world_size, global_rank, local_rank, self.predict_path, self.images_log, self.outsDataset,
|
|
403
|
+
modelComposite = Network.to(self.modelComposite, local_rank*self.size)
|
|
404
|
+
modelComposite = DDP(modelComposite, static_graph=True) if torch.cuda.is_available() else CPU_Model(modelComposite)
|
|
405
|
+
with _Predictor(world_size, global_rank, local_rank, self.predict_path, self.images_log, self.outsDataset, modelComposite, *dataloaders) as p:
|
|
364
406
|
p.run()
|
|
365
407
|
|
|
366
408
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: konfai
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.8
|
|
4
4
|
Summary: Modular and configurable Deep Learning framework with YAML and PyTorch
|
|
5
5
|
Author-email: Valentin Boussot <boussot.v@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -31,9 +31,11 @@ Provides-Extra: plot
|
|
|
31
31
|
Requires-Dist: matplotlib; extra == "plot"
|
|
32
32
|
Dynamic: license-file
|
|
33
33
|
|
|
34
|
+
[](https://github.com/vboussot/KonfAI/blob/main/LICENSE)
|
|
35
|
+
[](https://pypi.org/project/konfai/)
|
|
34
36
|
|
|
35
37
|
# 🧠 KonfAI
|
|
36
|
-
<img src="https://raw.githubusercontent.com/vboussot/KonfAI/main/logo.png" alt="KonfAI Logo" width="
|
|
38
|
+
<img src="https://raw.githubusercontent.com/vboussot/KonfAI/main/logo.png" alt="KonfAI Logo" width="250" align="right"/>
|
|
37
39
|
|
|
38
40
|
**KonfAI** is a modular and highly configurable deep learning framework built on PyTorch, driven entirely by YAML configuration files.
|
|
39
41
|
|
|
@@ -54,7 +56,7 @@ It is designed to support complex medical imaging workflows, flexible model arch
|
|
|
54
56
|
|
|
55
57
|
## 🚀 Installation
|
|
56
58
|
|
|
57
|
-
### From PyPI
|
|
59
|
+
### From PyPI
|
|
58
60
|
|
|
59
61
|
Install KonfAI from PyPI:
|
|
60
62
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
konfai/__init__.py,sha256=jXMTNml38eX6FSq9d3C_gJVgRLTKHPBUXqOLC7Pqkuo,828
|
|
2
2
|
konfai/evaluator.py,sha256=WLJ_hEwY2smB6F2KBLCVH_j13WVe3biuETSg2_NTXdk,7396
|
|
3
3
|
konfai/main.py,sha256=RDPi55Q6Klf-zenMTCHOwucEx-LNsVCcCmYea528JRw,2193
|
|
4
|
-
konfai/predictor.py,sha256
|
|
4
|
+
konfai/predictor.py,sha256=xbc7B5rXEI8D5upNpKa6hGgMFkkAbKqUHgAekS862Hg,22347
|
|
5
5
|
konfai/trainer.py,sha256=x4Sni2JBOPgcSnpRwHHIQFB7cc0-cZ4L8X9pwZQt0qs,16866
|
|
6
6
|
konfai/data/HDF5.py,sha256=Amexa4zMfsamo0odxHgKBwWlR7WquhGnAmFFVETcpQw,14355
|
|
7
7
|
konfai/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -24,16 +24,16 @@ konfai/models/segmentation/NestedUNet.py,sha256=GnAwQYHzivHN1qouifJyneh9nOFHSloG
|
|
|
24
24
|
konfai/models/segmentation/UNet.py,sha256=Icd_YddkHpExRxyvhoBTsd4McVkaBOF4Y3L_NrNA6Gs,4214
|
|
25
25
|
konfai/network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
26
|
konfai/network/blocks.py,sha256=EN1JN929zzV0FfecgFnVvv8u-WwENFRxloOpfCBkqeU,13529
|
|
27
|
-
konfai/network/network.py,sha256=
|
|
27
|
+
konfai/network/network.py,sha256=AX_r8ZyUJfR0h2XyMGbUKDsWHDHPeOxUGtQQvkuLmeE,45640
|
|
28
28
|
konfai/utils/ITK.py,sha256=OxTieDNNYHGkn7zxJsAG-6ecRG1VYMvn1dlBbBe1DOs,13955
|
|
29
29
|
konfai/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
30
30
|
konfai/utils/config.py,sha256=tzIkNUA88EXGpkH-GUFA-BehxC47wAuDbu0M0kWfUIY,9887
|
|
31
31
|
konfai/utils/dataset.py,sha256=DTAt8AEsAkDWM8ZtiXPUQfS5DQBqdYmXuw2sjOTIYV4,35517
|
|
32
32
|
konfai/utils/registration.py,sha256=v1srEBOcgDnHrx0YtsK6bcj0yCMH7wNeaQ3wC7gEvOw,8898
|
|
33
33
|
konfai/utils/utils.py,sha256=hRxqq1cOXewFG417kYQZUGzKqaCK14GNQqjFdRBIVGs,20186
|
|
34
|
-
konfai-1.0.
|
|
35
|
-
konfai-1.0.
|
|
36
|
-
konfai-1.0.
|
|
37
|
-
konfai-1.0.
|
|
38
|
-
konfai-1.0.
|
|
39
|
-
konfai-1.0.
|
|
34
|
+
konfai-1.0.8.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
35
|
+
konfai-1.0.8.dist-info/METADATA,sha256=Z64230_Rnhc7tKFybl8fL8l-O1sf4aGeQoN9F8llMEA,2515
|
|
36
|
+
konfai-1.0.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
37
|
+
konfai-1.0.8.dist-info/entry_points.txt,sha256=fG82HRN5-g39ACSOCtij_I3N6EHxfYnMR0D7TI_8pW8,81
|
|
38
|
+
konfai-1.0.8.dist-info/top_level.txt,sha256=xF470dkIlFoFqTZEOlRehKJr4WU_8OKGXrJqYm9vWKs,7
|
|
39
|
+
konfai-1.0.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|