nkululeko 0.86.4__py3-none-any.whl → 0.86.6__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.
nkululeko/constants.py CHANGED
@@ -1,2 +1,2 @@
1
- VERSION="0.86.4"
1
+ VERSION="0.86.6"
2
2
  SAMPLING_RATE = 16000
@@ -59,6 +59,20 @@ class Dataset_CSV(Dataset):
59
59
  lambda x: root + "/" + audio_path + "/" + x
60
60
  )
61
61
  )
62
+ else: # absolute path is True
63
+ if audformat.index_type(df.index) == "segmented":
64
+ file_index = (
65
+ df.index.levels[0]
66
+ .map(lambda x: audio_path + "/" + x)
67
+ .values
68
+ )
69
+ df = df.set_index(df.index.set_levels(
70
+ file_index, level="file"))
71
+ else:
72
+ if not isinstance(df, pd.DataFrame):
73
+ df = pd.DataFrame(df)
74
+ df = df.set_index(df.index.to_series().apply(
75
+ lambda x: audio_path + "/" + x ))
62
76
 
63
77
  self.df = df
64
78
  self.db = None
nkululeko/experiment.py CHANGED
@@ -112,11 +112,11 @@ class Experiment:
112
112
  auto_labels = list(next(iter(self.datasets.values())).df[self.target].unique())
113
113
  if labels:
114
114
  self.labels = ast.literal_eval(labels)
115
- self.util.debug(f"Target labels (from config): {labels}")
115
+ self.util.debug(f"Using target labels (from config): {labels}")
116
116
  else:
117
117
  self.labels = auto_labels
118
118
  # print autolabel no matter it is specified or not
119
- self.util.debug(f"Target labels (from database): {auto_labels}")
119
+ self.util.debug(f"Labels (from database): {auto_labels}")
120
120
  glob_conf.set_labels(self.labels)
121
121
  self.util.debug(f"loaded databases {dbs}")
122
122
 
nkululeko/modelrunner.py CHANGED
@@ -30,6 +30,8 @@ class Modelrunner:
30
30
  # intialize a new model
31
31
  model_type = glob_conf.config["MODEL"]["type"]
32
32
  self._select_model(model_type)
33
+ self.best_performance = 0
34
+ self.best_epoch = 0
33
35
 
34
36
  def do_epochs(self):
35
37
  # initialze results
@@ -51,7 +53,8 @@ class Modelrunner:
51
53
  # epochs are handled by Huggingface API
52
54
  self.model.train()
53
55
  report = self.model.predict()
54
- # todo: findout the best epoch
56
+ # todo: findout the best epoch, no need
57
+ # since oad_best_model_at_end is given in training args
55
58
  epoch = epoch_num
56
59
  report.set_id(self.run, epoch)
57
60
  plot_name = self.util.get_plot_name() + f"_{self.run}_{epoch:03d}_cnf"
@@ -77,10 +80,15 @@ class Modelrunner:
77
80
  report.set_id(self.run, epoch)
78
81
  plot_name = self.util.get_plot_name() + f"_{self.run}_{epoch:03d}_cnf"
79
82
  reports.append(report)
83
+ test_score_metric = report.get_result().get_test_result()
80
84
  self.util.debug(
81
- f"run: {self.run} epoch: {epoch}: result: "
82
- f"{reports[-1].get_result().get_test_result()}"
85
+ f"run: {self.run} epoch: {epoch}: result: {test_score_metric}"
83
86
  )
87
+ # print(f"performance: {performance.split(' ')[1]}")
88
+ performance = float(test_score_metric.split(' ')[1])
89
+ if performance > self.best_performance:
90
+ self.best_performance = performance
91
+ self.best_epoch = epoch
84
92
  if plot_epochs:
85
93
  self.util.debug(f"plotting conf matrix to {plot_name}")
86
94
  report.plot_confmatrix(plot_name, epoch)
@@ -110,11 +118,14 @@ class Modelrunner:
110
118
  f"reached patience ({str(patience)}): early stopping"
111
119
  )
112
120
  break
121
+ # After training, report the best performance and epoch
122
+ best_report = reports[self.best_epoch]
123
+ # self.util.debug(f"Best score at epoch: {self.best_epoch}, UAR: {self.best_performance}") # move to reporter below
113
124
 
114
125
  if not plot_epochs:
115
126
  # Do at least one confusion matrix plot
116
127
  self.util.debug(f"plotting confusion matrix to {plot_name}")
117
- reports[-1].plot_confmatrix(plot_name, epoch)
128
+ best_report.plot_confmatrix(plot_name, self.best_epoch)
118
129
  return reports, epoch
119
130
 
120
131
  def _select_model(self, model_type):
@@ -7,10 +7,11 @@ from confidence_intervals import evaluate_with_conf_int
7
7
  import matplotlib.pyplot as plt
8
8
  import numpy as np
9
9
  from scipy.stats import pearsonr
10
- from sklearn.metrics import ConfusionMatrixDisplay
10
+ from sklearn.metrics import ConfusionMatrixDisplay, roc_curve
11
11
  from sklearn.metrics import classification_report
12
12
  from sklearn.metrics import confusion_matrix
13
13
  from sklearn.metrics import r2_score
14
+ from sklearn.metrics import roc_curve, auc, roc_auc_score
14
15
  from torch import is_tensor
15
16
 
16
17
  from audmetric import accuracy
@@ -121,7 +122,7 @@ class Reporter:
121
122
  self.truths = np.digitize(self.truths, bins) - 1
122
123
  self.preds = np.digitize(self.preds, bins) - 1
123
124
 
124
- def plot_confmatrix(self, plot_name, epoch):
125
+ def plot_confmatrix(self, plot_name, epoch=None):
125
126
  if not self.util.exp_is_classification():
126
127
  self.continuous_to_categorical()
127
128
  self._plot_confmat(self.truths, self.preds, plot_name, epoch)
@@ -155,9 +156,11 @@ class Reporter:
155
156
  pred = np.digitize(pred, bins) - 1
156
157
  self._plot_confmat(truth, pred.astype("int"), plot_name, 0)
157
158
 
158
- def _plot_confmat(self, truths, preds, plot_name, epoch):
159
+ def _plot_confmat(self, truths, preds, plot_name, epoch=None):
159
160
  # print(truths)
160
161
  # print(preds)
162
+ if epoch is None:
163
+ epoch = self.epoch
161
164
  fig_dir = self.util.get_path("fig_dir")
162
165
  labels = glob_conf.labels
163
166
  fig = plt.figure() # figsize=[5, 5]
@@ -224,7 +227,7 @@ class Reporter:
224
227
 
225
228
  res_dir = self.util.get_path("res_dir")
226
229
  rpt = (
227
- f"epoch: {epoch}, UAR: {uar_str}"
230
+ f"Best score at epoch: {epoch}, UAR: {uar_str}"
228
231
  + f", (+-{up_str}/{low_str}), ACC: {acc_str}"
229
232
  )
230
233
  # print(rpt)
@@ -236,7 +239,9 @@ class Reporter:
236
239
  def set_filename_add(self, my_string):
237
240
  self.filenameadd = f"_{my_string}"
238
241
 
239
- def print_results(self, epoch):
242
+ def print_results(self, epoch=None):
243
+ if epoch is None:
244
+ epoch = self.epoch
240
245
  """Print all evaluation values to text file."""
241
246
  res_dir = self.util.get_path("res_dir")
242
247
  file_name = f"{res_dir}{self.util.get_exp_name()}_{epoch}{self.filenameadd}.txt"
@@ -261,9 +266,18 @@ class Reporter:
261
266
  c_res = rpt[l]["f1-score"]
262
267
  c_ress[i] = float(f"{c_res:.3f}")
263
268
  self.util.debug(f"labels: {labels}")
264
- f1_per_class = f"result per class (F1 score): {c_ress}"
269
+ f1_per_class = (
270
+ f"result per class (F1 score): {c_ress} from epoch: {epoch}"
271
+ )
272
+ if len(np.unique(self.truths)) == 2:
273
+ fpr, tpr, _ = roc_curve(self.truths, self.preds)
274
+ auc_score = auc(fpr, tpr)
275
+ pauc_score = roc_auc_score(self.truths, self.preds, max_fpr=0.1)
276
+ auc_pauc = f"auc: {auc_score:.3f}, pauc: {pauc_score:.3f} from epoch: {epoch}"
277
+ self.util.debug(auc_pauc)
265
278
  self.util.debug(f1_per_class)
266
279
  rpt_str = f"{json.dumps(rpt)}\n{f1_per_class}"
280
+ # rpt_str += f"\n{auc_auc}"
267
281
  text_file.write(rpt_str)
268
282
  glob_conf.report.add_item(
269
283
  ReportItem(
nkululeko/runmanager.py CHANGED
@@ -63,8 +63,7 @@ class Runmanager:
63
63
  )
64
64
  self.reports, last_epoch = self.modelrunner.do_epochs()
65
65
  # wrap up the run
66
- plot_anim_progression = self.util.config_val(
67
- "PLOT", "anim_progression", 0)
66
+ plot_anim_progression = self.util.config_val("PLOT", "anim_progression", 0)
68
67
  if plot_anim_progression:
69
68
  plot_name_suggest = self.util.get_exp_name()
70
69
  plot_name = (
@@ -88,8 +87,7 @@ class Runmanager:
88
87
  + "_epoch_progression"
89
88
  )
90
89
  self.util.debug(f"plotting progression to {plot_name}")
91
- self.reports[-1].plot_epoch_progression(
92
- self.reports, plot_name)
90
+ self.reports[-1].plot_epoch_progression(self.reports, plot_name)
93
91
  # remember the best run
94
92
  best_report = self.get_best_result(self.reports)
95
93
  plot_best_model = self.util.config_val("PLOT", "best_model", False)
@@ -107,9 +105,10 @@ class Runmanager:
107
105
  )
108
106
  self.print_model(best_report, plot_name)
109
107
  # finally, print out the numbers for this run
110
- self.reports[-1].print_results(
111
- int(self.util.config_val("EXP", "epochs", 1))
112
- )
108
+ # self.reports[-1].print_results(
109
+ # int(self.util.config_val("EXP", "epochs", 1))
110
+ # )
111
+ best_report.print_results(best_report.epoch)
113
112
  self.best_results.append(best_report)
114
113
  self.last_epochs.append(last_epoch)
115
114
 
@@ -145,19 +144,19 @@ class Runmanager:
145
144
  )
146
145
  self.print_model(report, plot_name)
147
146
 
148
- def print_model(self, report, plot_name):
147
+ def print_model(self, reporter, plot_name):
149
148
  """Print a confusion matrix for a special report.
150
149
 
151
150
  Args:
152
151
  report: for which report (will be computed newly from model)
153
152
  plot_name: name of plot file
154
153
  """
155
- epoch = report.epoch
154
+ epoch = reporter.epoch
156
155
  # self.load_model(report)
157
156
  # report = self.model.predict()
158
157
  self.util.debug(f"plotting conf matrix to {plot_name}")
159
- report.plot_confmatrix(plot_name, epoch)
160
- report.print_results(epoch)
158
+ reporter.plot_confmatrix(plot_name)
159
+ reporter.print_results()
161
160
 
162
161
  def load_model(self, report):
163
162
  """Load a model from disk for a specific run and epoch and evaluate it.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nkululeko
3
- Version: 0.86.4
3
+ Version: 0.86.6
4
4
  Summary: Machine learning audio prediction experiments based on templates
5
5
  Home-page: https://github.com/felixbur/nkululeko
6
6
  Author: Felix Burkhardt
@@ -58,6 +58,8 @@ Requires-Dist: pylatex
58
58
  - [Hello World example](#hello-world-example)
59
59
  - [Features](#features)
60
60
  - [License](#license)
61
+ - [Contributing](#contributing)
62
+ - [Citing](#citing)
61
63
 
62
64
 
63
65
  ## Overview
@@ -65,7 +67,7 @@ A project to detect speaker characteristics by machine learning experiments with
65
67
 
66
68
  The idea is to have a framework (based on e.g. sklearn and torch) that can be used to rapidly and automatically analyse audio data and explore machine learning models based on that data.
67
69
 
68
- * NEW: Nkululeko now automatically generates PDF reports [sample for EmoDB](meta/images/emodb_report.pdf)
70
+ * NEW with nkululeko: [Finetune transformer-models](http://blog.syntheticspeech.de/2024/05/29/nkululeko-how-to-finetune-a-transformer-model/)
69
71
  * The latest features can be seen in [the ini-file](./ini_file.md) options that are used to control Nkululeko
70
72
  * Below is a [Hello World example](#helloworld) that should set you up fastly, also on [Google Colab](https://colab.research.google.com/drive/1GYNBd5cdZQ1QC3Jm58qoeMaJg3UuPhjw?usp=sharing#scrollTo=4G_SjuF9xeQf), and [with Kaggle](https://www.kaggle.com/felixburk/nkululeko-hello-world-example)
71
73
  * [Here's a blog post on how to set up nkululeko on your computer.](http://blog.syntheticspeech.de/2021/08/30/how-to-set-up-your-first-nkululeko-project/)
@@ -249,7 +251,7 @@ There's my [blog](http://blog.syntheticspeech.de/?s=nkululeko) with tutorials:
249
251
  * [Predict new labels for your data from public models and check bias](http://blog.syntheticspeech.de/2023/08/16/nkululeko-how-to-predict-labels-for-your-data-from-existing-models-and-check-them/)
250
252
  * [Resample](http://blog.syntheticspeech.de/2023/08/31/how-to-fix-different-sampling-rates-in-a-dataset-with-nkululeko/)
251
253
  * [Get some statistics on correlation and effect-size](http://blog.syntheticspeech.de/2023/09/05/nkululeko-get-some-statistics-on-correlation-and-effect-size/)
252
- * [Generate a latex / pdf report](http://blog.syntheticspeech.de/2023/09/26/nkululeko-generate-a-latex-pdf-report/)
254
+ * [Automatic generation of a latex / pdf report](http://blog.syntheticspeech.de/2023/09/26/nkululeko-generate-a-latex-pdf-report/)
253
255
  * [Inspect your data with Spotlight](http://blog.syntheticspeech.de/2023/10/31/nkululeko-inspect-your-data-with-spotlight/)
254
256
  * [Automatically stratify your split sets](http://blog.syntheticspeech.de/2023/11/07/nkululeko-automatically-stratify-your-split-sets/)
255
257
  * [re-name data column names](http://blog.syntheticspeech.de/2023/11/16/nkululeko-re-name-data-column-names/)
@@ -314,6 +316,12 @@ Here's [an animation that shows the progress of classification done with nkulule
314
316
 
315
317
  ## License
316
318
  Nkululeko can be used under the [MIT license](https://choosealicense.com/licenses/mit/)
319
+
320
+
321
+ ## Contributing
322
+ Contributions are welcome and encouraged. To learn more about how to contribute to nkululeko please refer to the [Contributing guidelines](./CONTRIBUTING.md)
323
+
324
+ ## Citing
317
325
  If you use it, please mention the Nkululeko paper
318
326
 
319
327
  F. Burkhardt, Johannes Wagner, Hagen Wierstorf, Florian Eyben and Björn Schuller: Nkululeko: A Tool For Rapid Speaker Characteristics Detection, Proc. Proc. LREC, 2022
@@ -335,6 +343,14 @@ F. Burkhardt, Johannes Wagner, Hagen Wierstorf, Florian Eyben and Björn Schulle
335
343
  Changelog
336
344
  =========
337
345
 
346
+ Version 0.86.6
347
+ --------------
348
+ * now best (not last) result is shown at end
349
+
350
+ Version 0.86.5
351
+ --------------
352
+ * fix audio path detection in data csv import
353
+
338
354
  Version 0.86.4
339
355
  --------------
340
356
  * add finetuning to the demo module
@@ -2,25 +2,25 @@ nkululeko/__init__.py,sha256=62f8HiEzJ8rG2QlTFJXUCMpvuH3fKI33DoJSj33mscc,63
2
2
  nkululeko/aug_train.py,sha256=YhuZnS_WVWnun9G-M6g5n6rbRxoVREz6Zh7k6qprFNQ,3194
3
3
  nkululeko/augment.py,sha256=4MG0apTAG5RgkuJrYEjGgDdbodZWi_HweSPNI1JJ5QA,3051
4
4
  nkululeko/cacheddataset.py,sha256=lIJ6hUo5LoxSrzXtWV8mzwO7wRtUETWnOQ4ws2XfL1E,969
5
- nkululeko/constants.py,sha256=QtEoU6iCjnUpcJT-FOh4bU4miJ_D0z26OpSub4oEY1c,39
5
+ nkululeko/constants.py,sha256=r-AT0ZtgRKUYQ1VxJ3nCCqbKQzOAQiOexnQFaojN3Z0,39
6
6
  nkululeko/demo.py,sha256=WSKr-W5uJ9DQfemK923g7Hd5V3kgAn03Er0JX1Pa45I,5142
7
7
  nkululeko/demo_feats.py,sha256=sAeGFojhEj9WEDFtG3SzPBmyYJWLF2rkbpp65m8Ujo4,2025
8
8
  nkululeko/demo_predictor.py,sha256=es56xbT8ifkS_vnrlb5NTZT54gNmeUtNlA4zVA_gnN8,4757
9
- nkululeko/experiment.py,sha256=huhHLQfnzxRJlQi2SY61XMWbC8xEWpe31yq9spBUk-4,31041
9
+ nkululeko/experiment.py,sha256=5nF-eDf8OCp6KRIU7KnryWL5SLJQUtr2BueHhEdcKw0,31040
10
10
  nkululeko/explore.py,sha256=lDzRoW_Taa5u4BBABZLD89BcQWnYlrftJR4jgt1yyj0,2609
11
11
  nkululeko/export.py,sha256=mHeEAAmtZuxdyebLlbSzPrHSi9OMgJHbk35d3DTxRBc,4632
12
12
  nkululeko/feature_extractor.py,sha256=8mssYKmo4LclVI-hiLmJEDZ0ZPyDavFG2YwtXcrGzwM,3976
13
13
  nkululeko/file_checker.py,sha256=LoLnL8aHpW-axMQ46qbqrManTs5otG9ShpEZuz9iRSk,3474
14
14
  nkululeko/filter_data.py,sha256=w-X2mhKdYr5DxDIz50E5yzO6Jmzk4jjDBoXsgOOVtcA,7222
15
15
  nkululeko/glob_conf.py,sha256=KL9YJQTHvTztxo1vr25qRRgaPnx4NTg0XrdbovKGMmw,525
16
- nkululeko/modelrunner.py,sha256=iCmfJxsS2UafcikjRdUqPQuqQMOYA-Ctr3et3HeNR3c,10452
16
+ nkululeko/modelrunner.py,sha256=OU35qwP94GxW_EtL4I2-RhqB-wxbjNvp8CIHNbtnt7Q,11155
17
17
  nkululeko/multidb.py,sha256=fG3VukEWP1vreVN4gB1IRXxwwg4jLftsSEYtu0o1f78,5634
18
18
  nkululeko/nkuluflag.py,sha256=PGWSmZz-PiiHLgcZJAoGOI_Y-sZDVI1ksB8p5r7riWM,3725
19
19
  nkululeko/nkululeko.py,sha256=Kn3s2E3yyH8cJ7z6lkMxrnqtCxTu7-qfe9Zr_ONTD5g,1968
20
20
  nkululeko/plots.py,sha256=C2mwQFK0Vxfl5ZM7CO87tULDoEf7G16ek0nU77bhOc4,23070
21
21
  nkululeko/predict.py,sha256=sF091sSSLnEWcISx9ZcULLie3tY5XeFsQJd6b3vrxFg,2409
22
22
  nkululeko/resample.py,sha256=2d9eao_0sLrGZ_KSl8OVKsPor3BkFrlmMhrpB9WelIs,4267
23
- nkululeko/runmanager.py,sha256=eTM1DNQKt1lxYhzt4vZyZluPXW9sWlIJHNQzex4lkJU,7624
23
+ nkululeko/runmanager.py,sha256=ul1fIxJln3LUd9N8QZOMyWdC3alcsvaygdJ-7B63FDQ,7645
24
24
  nkululeko/scaler.py,sha256=4nkIqoajkIkuTPK0Z02ifMN_awl6fP_i-GBYdoGYgGM,4101
25
25
  nkululeko/segment.py,sha256=YLKckX44tbvTb3LrdgYw9X4guzuF27sutl92z9DkpZU,4835
26
26
  nkululeko/syllable_nuclei.py,sha256=Sky-C__MeUDaxqHnDl2TGLLYOYvsahD35TUjWGeG31k,10047
@@ -46,7 +46,7 @@ nkululeko/autopredict/ap_valence.py,sha256=n-hctRKySzhmJtowuMOTUu0T_ld3uK5pnfOzW
46
46
  nkululeko/autopredict/estimate_snr.py,sha256=S-bpS0xFkwWc4Ch75UrjbS8y538lQ0U3g_iLRFXureY,5048
47
47
  nkululeko/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  nkululeko/data/dataset.py,sha256=JGzMD6HIvkFkYBekmbmslIKc5ADaCj06T-8gpqH_kFo,27650
49
- nkululeko/data/dataset_csv.py,sha256=vTnjIc2UdSJT7foL-ltE9MWrZTCg0nplwKdEtMPxt2o,3933
49
+ nkululeko/data/dataset_csv.py,sha256=dzOrbKB8t0UATAIYaKAOqHTogmYPBqskt6Hak7VjbSM,4537
50
50
  nkululeko/feat_extract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  nkululeko/feat_extract/feats_agender.py,sha256=Qm69G4kqAyTVVk7wwRgrXlNwGaDMGRYyKGpuf0vOEgM,3113
52
52
  nkululeko/feat_extract/feats_agender_agender.py,sha256=tgH2BnwcxpvuLmOkrMbVdBSX0Onfz2MG12FsddalRKI,3424
@@ -96,7 +96,7 @@ nkululeko/reporting/defines.py,sha256=IsY1YgKRMaABpylVKjBJgJ5bNCEbGCVA_E6pivraqS
96
96
  nkululeko/reporting/latex_writer.py,sha256=qiCRSmB4KOD_za4oHu5x-PhwjZohzfo8wecMOwlXZwc,1886
97
97
  nkululeko/reporting/report.py,sha256=W0rcigDdjBvxZQ3pZja_gvToILYvaZ1BFtnN2qFRfYI,1060
98
98
  nkululeko/reporting/report_item.py,sha256=siWeGNgo4bAE46YBMNcsdf3jTMTy76BO9Fi6DTvDig4,533
99
- nkululeko/reporting/reporter.py,sha256=4dXRwJ-CZ49NlF_kv9hfDjZT3bbWNNMyNpKEBLKs3Ew,13447
99
+ nkululeko/reporting/reporter.py,sha256=S9A62AxdMTEV-9XDUQNxdoevGLXBP52WiDmZ694QMV4,14161
100
100
  nkululeko/reporting/result.py,sha256=nSN5or-Py2GPRWHkWpGRh7UCi1W0er7WLEHz8fYLk-A,742
101
101
  nkululeko/segmenting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
102
102
  nkululeko/segmenting/seg_inaspeechsegmenter.py,sha256=pmLHuXsaqvcdYxB4PSW9l1mbQWZZBJFhi_CGabqydas,1947
@@ -105,8 +105,8 @@ nkululeko/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
105
  nkululeko/utils/files.py,sha256=UiGAtZRWYjHSvlmPaTMtzyNNGE6qaLaxQkybctS7iRM,4021
106
106
  nkululeko/utils/stats.py,sha256=1yUq0FTOyqkU8TwUocJRYdJaqMU5SlOBBRUun9STo2M,2829
107
107
  nkululeko/utils/util.py,sha256=ILpfNuaeq-hy1bUkRhVrzO2wG9z9Upaozs9EBoIaMG0,14123
108
- nkululeko-0.86.4.dist-info/LICENSE,sha256=0zGP5B_W35yAcGfHPS18Q2B8UhvLRY3dQq1MhpsJU_U,1076
109
- nkululeko-0.86.4.dist-info/METADATA,sha256=D1y8wrwDr0gLVdafV4E_GcER5yrt3IaKUdqJ8huMCwA,37480
110
- nkululeko-0.86.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
111
- nkululeko-0.86.4.dist-info/top_level.txt,sha256=DPFNNSHPjUeVKj44dVANAjuVGRCC3MusJ08lc2a8xFA,10
112
- nkululeko-0.86.4.dist-info/RECORD,,
108
+ nkululeko-0.86.6.dist-info/LICENSE,sha256=0zGP5B_W35yAcGfHPS18Q2B8UhvLRY3dQq1MhpsJU_U,1076
109
+ nkululeko-0.86.6.dist-info/METADATA,sha256=2aKLKe_0C1iMKL1tZc5aLiMxp8GocGdQpnAQL4Z9agA,37924
110
+ nkululeko-0.86.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
111
+ nkululeko-0.86.6.dist-info/top_level.txt,sha256=DPFNNSHPjUeVKj44dVANAjuVGRCC3MusJ08lc2a8xFA,10
112
+ nkululeko-0.86.6.dist-info/RECORD,,