nkululeko 0.77.4__py3-none-any.whl → 0.77.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/aug_train.py CHANGED
@@ -11,15 +11,7 @@ import nkululeko.glob_conf as glob_conf
11
11
  from nkululeko.augment import doit as augment
12
12
 
13
13
 
14
- def main(src_dir):
15
- parser = argparse.ArgumentParser(description="Call the nkululeko framework.")
16
- parser.add_argument("--config", default="exp.ini", help="The base configuration")
17
- args = parser.parse_args()
18
- if args.config is not None:
19
- config_file = args.config
20
- else:
21
- config_file = f"{src_dir}/exp.ini"
22
-
14
+ def doit(config_file):
23
15
  # test if the configuration file exists
24
16
  if not os.path.isfile(config_file):
25
17
  print(f"ERROR: no such file: {config_file}")
@@ -87,6 +79,17 @@ def main(src_dir):
87
79
  print("DONE")
88
80
 
89
81
 
82
+ def main(src_dir):
83
+ parser = argparse.ArgumentParser(description="Call the nkululeko framework.")
84
+ parser.add_argument("--config", default="exp.ini", help="The base configuration")
85
+ args = parser.parse_args()
86
+ if args.config is not None:
87
+ config_file = args.config
88
+ else:
89
+ config_file = f"{src_dir}/exp.ini"
90
+ doit(config_file)
91
+
92
+
90
93
  if __name__ == "__main__":
91
94
  cwd = os.path.dirname(os.path.abspath(__file__))
92
95
  main(cwd) # use this if you want to state the config file path on command line
@@ -60,7 +60,15 @@ class Augmenter:
60
60
  audiofile.write(new_full_name, signal=sig_aug, sampling_rate=sr)
61
61
  index_map[f] = new_full_name
62
62
  df_ret = self.df.copy()
63
- file_index = df_ret.index.levels[0].map(lambda x: index_map[x]).values
64
- df_ret = df_ret.set_index(df_ret.index.set_levels(file_index, level="file"))
63
+
64
+ file_index = df_ret.index.to_series().map(lambda x: index_map[x[0]]).values
65
+ # workaround because i just couldn't get this easier...
66
+ arrays = [
67
+ file_index,
68
+ list(df_ret.index.get_level_values(1)),
69
+ list(df_ret.index.get_level_values(2)),
70
+ ]
71
+ new_index = pd.MultiIndex.from_arrays(arrays, names=("file", "start", "end"))
72
+ df_ret = df_ret.set_index(new_index)
65
73
 
66
74
  return df_ret
@@ -68,6 +68,15 @@ class Randomsplicer:
68
68
  index_map[f] = new_full_name
69
69
 
70
70
  df_ret = self.df.copy()
71
- file_index = df_ret.index.levels[0].map(lambda x: index_map[x]).values
72
- df_ret = df_ret.set_index(df_ret.index.set_levels(file_index, level="file"))
71
+
72
+ file_index = df_ret.index.to_series().map(lambda x: index_map[x[0]]).values
73
+ # workaround because i just couldn't get this easier...
74
+ arrays = [
75
+ file_index,
76
+ list(df_ret.index.get_level_values(1)),
77
+ list(df_ret.index.get_level_values(2)),
78
+ ]
79
+ new_index = pd.MultiIndex.from_arrays(arrays, names=("file", "start", "end"))
80
+ df_ret = df_ret.set_index(new_index)
81
+
73
82
  return df_ret
nkululeko/constants.py CHANGED
@@ -1,2 +1,2 @@
1
- VERSION="0.77.4"
1
+ VERSION="0.77.6"
2
2
  SAMPLING_RATE = 16000
nkululeko/experiment.py CHANGED
@@ -261,11 +261,11 @@ class Experiment:
261
261
  if type(test_cats) == np.ndarray:
262
262
  self.util.debug(f"Categories test (nd.array): {test_cats}")
263
263
  else:
264
- self.util.debug(f"Categories test (list): {test_cats.to_list()}")
264
+ self.util.debug(f"Categories test (list): {list(test_cats)}")
265
265
  if type(train_cats) == np.ndarray:
266
266
  self.util.debug(f"Categories train (nd.array): {train_cats}")
267
267
  else:
268
- self.util.debug(f"Categories train (list): {train_cats.to_list()}")
268
+ self.util.debug(f"Categories train (list): {list(train_cats)}")
269
269
 
270
270
  # encode the labels as numbers
271
271
  self.label_encoder = LabelEncoder()
@@ -7,7 +7,6 @@ from sklearn.tree import DecisionTreeClassifier
7
7
  from sklearn.linear_model import LinearRegression
8
8
  from sklearn.tree import DecisionTreeRegressor
9
9
  import matplotlib.pyplot as plt
10
- from xgboost import XGBClassifier, XGBRegressor
11
10
  from nkululeko.utils.util import Util
12
11
  from nkululeko.utils.stats import normalize
13
12
  from nkululeko.plots import Plots
@@ -126,6 +125,8 @@ class FeatureAnalyser:
126
125
  plots = Plots()
127
126
  plots.plot_tree(model, self.features)
128
127
  elif model_s == "xgb":
128
+ from xgboost import XGBClassifier
129
+
129
130
  model = XGBClassifier(enable_categorical=True, tree_method="hist")
130
131
  self.labels = self.labels.astype("category")
131
132
  result_importances[model_s] = self._get_importance(
@@ -171,6 +172,8 @@ class FeatureAnalyser:
171
172
  model, permutation
172
173
  )
173
174
  elif model_s == "xgr":
175
+ from xgboost import XGBClassifier
176
+
174
177
  model = XGBRegressor()
175
178
  result_importances[model_s] = self._get_importance(
176
179
  model, permutation
nkululeko/models/model.py CHANGED
@@ -137,11 +137,11 @@ class Model:
137
137
  groups=annos["fold"],
138
138
  ):
139
139
  train_x = feats.iloc[train_index].to_numpy()
140
- train_y = targets[train_index]
140
+ train_y = targets.iloc[train_index]
141
141
  self.clf.fit(train_x, train_y)
142
142
 
143
143
  truth_x = feats.iloc[test_index].to_numpy()
144
- truth_y = targets[test_index]
144
+ truth_y = targets.iloc[test_index]
145
145
  predict_y = self.clf.predict(truth_x)
146
146
  report = Reporter(truth_y.astype(float), predict_y, self.run, self.epoch)
147
147
  result = report.get_result().get_test_result()
@@ -113,7 +113,7 @@ class CNN_model(Model):
113
113
  img_path = self.df_feats.iloc[idx, 0]
114
114
  image = Image.open(img_path)
115
115
  # Get emotion label
116
- label = self.df_labels[self.target][idx]
116
+ label = self.df_labels[self.target].iloc[idx]
117
117
  if self.transform:
118
118
  image = self.transform(image)
119
119
  return image, label
@@ -115,7 +115,7 @@ class MLP_model(Model):
115
115
  def get_loader(self, df_x, df_y, shuffle):
116
116
  data = []
117
117
  for i in range(len(df_x)):
118
- data.append([df_x.values[i], df_y[self.target][i]])
118
+ data.append([df_x.values[i], df_y[self.target].iloc[i]])
119
119
  return torch.utils.data.DataLoader(
120
120
  data, shuffle=shuffle, batch_size=self.batch_size
121
121
  )
nkululeko/nkululeko.py CHANGED
@@ -9,15 +9,7 @@ from nkululeko.utils.util import Util
9
9
  from nkululeko.constants import VERSION
10
10
 
11
11
 
12
- def main(src_dir):
13
- parser = argparse.ArgumentParser(description="Call the nkululeko framework.")
14
- parser.add_argument("--config", default="exp.ini", help="The base configuration")
15
- args = parser.parse_args()
16
- if args.config is not None:
17
- config_file = args.config
18
- else:
19
- config_file = f"{src_dir}/exp.ini"
20
-
12
+ def doit(config_file):
21
13
  # test if the configuration file exists
22
14
  if not os.path.isfile(config_file):
23
15
  print(f"ERROR: no such file: {config_file}")
@@ -54,11 +46,22 @@ def main(src_dir):
54
46
  expr.init_runmanager()
55
47
 
56
48
  # run the experiment
57
- expr.run()
58
-
49
+ reports = expr.run()
50
+ result = reports[-1].result.test
59
51
  expr.store_report()
60
-
61
52
  print("DONE")
53
+ return result
54
+
55
+
56
+ def main(src_dir):
57
+ parser = argparse.ArgumentParser(description="Call the nkululeko framework.")
58
+ parser.add_argument("--config", default="exp.ini", help="The base configuration")
59
+ args = parser.parse_args()
60
+ if args.config is not None:
61
+ config_file = args.config
62
+ else:
63
+ config_file = f"{src_dir}/exp.ini"
64
+ doit(config_file)
62
65
 
63
66
 
64
67
  if __name__ == "__main__":
nkululeko/plots.py CHANGED
@@ -279,7 +279,7 @@ class Plots:
279
279
  res_pval = int(res_pval[1] * 1000) / 1000
280
280
  caption = f"{ylab} {df.shape[0]}. P-val chi2: {res_pval}"
281
281
  ax = (
282
- df.groupby(col1)[col2]
282
+ df.groupby(col1, observed=False)[col2]
283
283
  .value_counts()
284
284
  .unstack()
285
285
  .plot(kind="bar", stacked=True, title=caption, rot=0)
nkululeko/utils/util.py CHANGED
@@ -11,9 +11,24 @@ import audformat
11
11
 
12
12
  class Util:
13
13
  # a list of words that need not to be warned upon if default values are used
14
- stopvals = [False, "False", "classification", "png", "audio_path"]
14
+ stopvals = [
15
+ "all",
16
+ False,
17
+ "False",
18
+ "classification",
19
+ "png",
20
+ "audio_path",
21
+ "kde",
22
+ "pkl",
23
+ "eGeMAPSv02",
24
+ "functionals",
25
+ ]
15
26
 
16
27
  def __init__(self, caller=None, has_config=True):
28
+ if caller is not None:
29
+ self.caller = caller
30
+ else:
31
+ self.caller = ""
17
32
  if has_config:
18
33
  import nkululeko.glob_conf as glob_conf
19
34
 
@@ -25,10 +40,7 @@ class Util:
25
40
  self.error(f"no such file: {self.got_data_roots}")
26
41
  self.data_roots = configparser.ConfigParser()
27
42
  self.data_roots.read(self.got_data_roots)
28
- if caller is not None:
29
- self.caller = caller
30
- else:
31
- self.caller = ""
43
+ self.debug(f"getting data roots from {self.got_data_roots}")
32
44
 
33
45
  def get_path(self, entry):
34
46
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nkululeko
3
- Version: 0.77.4
3
+ Version: 0.77.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
@@ -19,6 +19,7 @@ Requires-Dist: audinterface
19
19
  Requires-Dist: audiofile
20
20
  Requires-Dist: audiomentations
21
21
  Requires-Dist: audonnx
22
+ Requires-Dist: cylimiter
22
23
  Requires-Dist: datasets
23
24
  Requires-Dist: imageio
24
25
  Requires-Dist: imbalanced-learn
@@ -188,6 +189,7 @@ Here is an overview of the interfaces:
188
189
  * **nkululeko.test**: predict a series of files with the current best model
189
190
  * **nkululeko.explore**: perform data exploration
190
191
  * **nkululeko.augment**: augment the current training data
192
+ * **nkululeko.aug_train**: augment the current training data and do a training including this data
191
193
  * **nkululeko.predict**: predict features like SNR, MOS, arousal/valence, age/gender, with DNN models
192
194
  * **nkululeko.segment**: segment a database based on VAD (voice activity detection)
193
195
  * **nkululeko.resample**: check on all sampling rates and change to 16kHz
@@ -309,6 +311,14 @@ F. Burkhardt, Johannes Wagner, Hagen Wierstorf, Florian Eyben and Björn Schulle
309
311
  Changelog
310
312
  =========
311
313
 
314
+ Version 0.77.6
315
+ --------------
316
+ * added functions to call modules with config file path directly
317
+
318
+ Version 0.77.5
319
+ --------------
320
+ * fixed augmentation bug for python version 10
321
+
312
322
  Version 0.77.4
313
323
  --------------
314
324
  * made traditional augmentations (audiomentation module) configurable
@@ -1,11 +1,11 @@
1
1
  nkululeko/__init__.py,sha256=62f8HiEzJ8rG2QlTFJXUCMpvuH3fKI33DoJSj33mscc,63
2
- nkululeko/aug_train.py,sha256=zlaGdWFyaFCpHZ8h_mqPVFcdaOPyK0iXgEkr6eIBqMQ,2976
2
+ nkululeko/aug_train.py,sha256=Z8AYr1E-zjRVrB7uRF_eKTvc0vYXVYGuy3BtzjSIL64,3022
3
3
  nkululeko/augment.py,sha256=sHWG4Jmb4BjnaaXXnRYMP7Jkk0qlaZ2ohsArP8uW_d8,3003
4
4
  nkululeko/cacheddataset.py,sha256=lIJ6hUo5LoxSrzXtWV8mzwO7wRtUETWnOQ4ws2XfL1E,969
5
- nkululeko/constants.py,sha256=rvUnKw3Xc-nto6fPV0AMxGXyhmvKh8-LgsanR3fMg-0,39
5
+ nkululeko/constants.py,sha256=p_G6aEcoN8S7E9aX4sOtHKmywY_uhLXbm6h0iJqfjuY,39
6
6
  nkululeko/demo.py,sha256=FFR8qHMCY8kKKRWDTa8xA7A8mWeYalRKYNtV5rjGg44,1915
7
7
  nkululeko/demo_predictor.py,sha256=j4ySWWcIxW7ZAIBH86m9BfRFokzrUNkRD6fpsvAQGTw,2629
8
- nkululeko/experiment.py,sha256=bDRTZTm3LvTxeMNmC1_xOIspLhrh1JwXJfiAxLJfIzE,28657
8
+ nkululeko/experiment.py,sha256=natQpQ_lETWoSea8rTM77g2G_xO_1KXNkES5eYU6GdM,28649
9
9
  nkululeko/explore.py,sha256=pfciOL66e0T4Bk0RTkwDyE6pK_baSUdjMo2Ybpst3L4,2202
10
10
  nkululeko/export.py,sha256=mHeEAAmtZuxdyebLlbSzPrHSi9OMgJHbk35d3DTxRBc,4632
11
11
  nkululeko/feature_extractor.py,sha256=tKv1b1-o7xNMgBavTR8VY8_H5HKoJEnnosS-KcjmOEU,7281
@@ -13,8 +13,8 @@ nkululeko/file_checker.py,sha256=LoLnL8aHpW-axMQ46qbqrManTs5otG9ShpEZuz9iRSk,347
13
13
  nkululeko/filter_data.py,sha256=w-X2mhKdYr5DxDIz50E5yzO6Jmzk4jjDBoXsgOOVtcA,7222
14
14
  nkululeko/glob_conf.py,sha256=6MZe83QCgHD_zB79Sl9m6UJQASwfqJlyb-1nqrQ_6Iw,381
15
15
  nkululeko/modelrunner.py,sha256=TQW08f72-GjBEIFTE3_8B8qMCWvTJUqJ1fveygmYnXI,9278
16
- nkululeko/nkululeko.py,sha256=MyjjbCg8qgLHHpvwJOEHBGNCDKf0GTv7gnXX27L56R4,1724
17
- nkululeko/plots.py,sha256=l-bxUoChkCIMsLPK4hMZyIWfuPNN_n-3g8Usc4sJ85A,21262
16
+ nkululeko/nkululeko.py,sha256=5EfguOjCMt3xDttBJOw-B9upwOHcrN4z3yGKZH5OtoU,1833
17
+ nkululeko/plots.py,sha256=Ci8brbxGXsCp1lnJdGkPUXoyWA6qUqUUwuxKOYEaqR8,21278
18
18
  nkululeko/predict.py,sha256=dRXX-sQVESa7cNi_56S6UkUOa_pV1g_K4xYtYVM1SJs,1876
19
19
  nkululeko/reporter.py,sha256=wrtWbU_UKDwhKQNMi7Q_Ix5N_UTzTagRwZikgUGk1c8,11606
20
20
  nkululeko/resample.py,sha256=C2S3aOTwlx5iYah_hs0JARHBC8Cq4Z5cH_mnDMb5RKk,2185
@@ -26,8 +26,8 @@ nkululeko/syllable_nuclei.py,sha256=Sky-C__MeUDaxqHnDl2TGLLYOYvsahD35TUjWGeG31k,
26
26
  nkululeko/test.py,sha256=cRtOn_d3Fh2kZmnT4nnQeGzZTRtpr5jRhowykOwunME,1421
27
27
  nkululeko/test_predictor.py,sha256=8eyHJ_YNIwR2OfICkqo7zF2f7UP8nL0nzCwC-8XnkZY,2409
28
28
  nkululeko/augmenting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- nkululeko/augmenting/augmenter.py,sha256=PxXYbpgopkdPSdd8dMr9iKDKvIA12Ty7hDrOtdpkm6M,2632
30
- nkululeko/augmenting/randomsplicer.py,sha256=OIBmfzyx1vhKl1cUQGlQw-CWZwsCV8XG9miITb41CT0,2395
29
+ nkululeko/augmenting/augmenter.py,sha256=XAt0dpmlnKxqyysqCgV3rcz-pRIvOz7rU7dmGDCVAzs,2905
30
+ nkululeko/augmenting/randomsplicer.py,sha256=Z5rxdKKUpuncLWuTS6xVfVKUeVbeiYU_dLRHQ5fcg4Y,2669
31
31
  nkululeko/augmenting/randomsplicing.py,sha256=ldym9vZNsZIU5BAAaJVaOmAgmVHNs4a5i5K3bW-WAQU,1791
32
32
  nkululeko/augmenting/resampler.py,sha256=cRrn27w_f2I6aN0CftlTuHT2edi7pTREh3Yc6BxhcGU,3335
33
33
  nkululeko/autopredict/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -48,7 +48,7 @@ nkululeko/data/dataset_csv.py,sha256=9ysujWHQnOHLWtJxGtvdpHE3c_sM_l9svFYWYCpamVs
48
48
  nkululeko/feat_extract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  nkululeko/feat_extract/feats_agender.py,sha256=sDfsvSC2zt1JLn5rmB7bdck1JmXIIol3oIwN90TossM,2867
50
50
  nkululeko/feat_extract/feats_agender_agender.py,sha256=UYATYWE-zCt9F1qA4xQbYZ2qM7DT2nwGxk7vSiyhit4,2953
51
- nkululeko/feat_extract/feats_analyser.py,sha256=82CCFTViP3XCEUS5Mku_0P358jEsm2-AIt5lAvlQQmY,11335
51
+ nkululeko/feat_extract/feats_analyser.py,sha256=nD2-7K4c0hFJvVCfmpsoU-SnePyb4m_JIPsf0uTzE0M,11397
52
52
  nkululeko/feat_extract/feats_audmodel.py,sha256=sZD8NBC3qId4ygzBvW5RvKVgCC1zxvO_cyFazYOEwCk,2901
53
53
  nkululeko/feat_extract/feats_audmodel_dim.py,sha256=z48s-FXokREnir_dNMl8fNI5PLCXzOhvmjgfCjTDjh8,2817
54
54
  nkululeko/feat_extract/feats_clap.py,sha256=v82mbjdjGDSKUUBggttw7jW0oka22fWAmfUf-4VmaDU,3379
@@ -72,14 +72,14 @@ nkululeko/losses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
72
72
  nkululeko/losses/loss_ccc.py,sha256=NOK0y0fxKUnU161B5geap6Fmn8QzoPl2MqtPiV8IuJE,976
73
73
  nkululeko/losses/loss_softf1loss.py,sha256=5gW-PuiqeAZcRgfwjueIOQtMokOjZWgQnVIv59HKTCo,1309
74
74
  nkululeko/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- nkululeko/models/model.py,sha256=7hrPyqWdgQ5TbQKZTcr-XwK83070IZdWy5Ek7FeeVpQ,11311
75
+ nkululeko/models/model.py,sha256=jg6t-0fXCPQv0cQZjyye4OZlkwf-iAN8HBikTHU1MBA,11321
76
76
  nkululeko/models/model_bayes.py,sha256=wI7-sCwibqXMCHviu349TYjgJXXNXym-Z6ZM83uxlFQ,378
77
- nkululeko/models/model_cnn.py,sha256=ObNSQpADBx3X5m31KPUw0U8q7ztAcc56uBVE2-QSjYo,9249
77
+ nkululeko/models/model_cnn.py,sha256=B02NPo6a_4SwLbnzd25drQZqUpC15ecXGrb1rXv5VOE,9254
78
78
  nkululeko/models/model_gmm.py,sha256=onovzGBeguwZ-upXtuDLaBw9sd6fDDQslVBOrz1Z8TE,645
79
79
  nkululeko/models/model_knn.py,sha256=5tGqiPo2JTw9VLmD-MXNZKFJ5RTLA6uv_blJDJ9lScA,573
80
80
  nkululeko/models/model_knn_reg.py,sha256=Fbuk6Ku6eyrbbMEk7rB5dwfhvQOMsdZk6HI_0T0gYPw,580
81
81
  nkululeko/models/model_lin_reg.py,sha256=NBTnY2ULuhUBt5ArYQwskZ2Vq4BBDGkqd9SYBFl7Ql4,392
82
- nkululeko/models/model_mlp.py,sha256=0Fm1wZd69HoNTrsi3MpS5cOm2Cd7wJALSxoUcr3ELak,8494
82
+ nkululeko/models/model_mlp.py,sha256=hgAy1WtTw1nUFxjOmfEDBzpe7IF2APsICIip_si6nv8,8499
83
83
  nkululeko/models/model_mlp_regression.py,sha256=nFJwch23tUTCxAlgi3YkT-6KSPPLAE7wFK2zF2gg3F4,9457
84
84
  nkululeko/models/model_svm.py,sha256=J1d8mf5T4QHtilkUTBkhegVB_0D2kRY0BiBGz-LUJmw,554
85
85
  nkululeko/models/model_svr.py,sha256=au5AtzjEpaY9_7Fz6CQoIZ3s6OAvLUxjAXuqHF9dRbk,514
@@ -98,9 +98,9 @@ nkululeko/segmenting/seg_silero.py,sha256=lLytS38KzARS17omwv8VBw-zz60RVSXGSvZ5Ev
98
98
  nkululeko/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
99
  nkululeko/utils/files.py,sha256=UiGAtZRWYjHSvlmPaTMtzyNNGE6qaLaxQkybctS7iRM,4021
100
100
  nkululeko/utils/stats.py,sha256=29otJpUp1VqbtDKmlLkPPzBmVfTFiHZ70rUdR4860rM,2788
101
- nkululeko/utils/util.py,sha256=icfzPBoBjrvcycrfVqLZ-m8nUp2-Kj6P00cs96ogqTo,11411
102
- nkululeko-0.77.4.dist-info/LICENSE,sha256=0zGP5B_W35yAcGfHPS18Q2B8UhvLRY3dQq1MhpsJU_U,1076
103
- nkululeko-0.77.4.dist-info/METADATA,sha256=tYGi3pYZWpWN1lahin-XjlACBNcziWNOWmbYvnQFUPg,30364
104
- nkululeko-0.77.4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
105
- nkululeko-0.77.4.dist-info/top_level.txt,sha256=DPFNNSHPjUeVKj44dVANAjuVGRCC3MusJ08lc2a8xFA,10
106
- nkululeko-0.77.4.dist-info/RECORD,,
101
+ nkululeko/utils/util.py,sha256=lpaM7_KnLjquFFtMPH6swdisF1kqSHBLpHh3CzgGtLw,11625
102
+ nkululeko-0.77.6.dist-info/LICENSE,sha256=0zGP5B_W35yAcGfHPS18Q2B8UhvLRY3dQq1MhpsJU_U,1076
103
+ nkululeko-0.77.6.dist-info/METADATA,sha256=jVeWsnVWyiRsVCYFxbyK_UYgqyLsDNNKTXg_XaQIK7A,30662
104
+ nkululeko-0.77.6.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
105
+ nkululeko-0.77.6.dist-info/top_level.txt,sha256=DPFNNSHPjUeVKj44dVANAjuVGRCC3MusJ08lc2a8xFA,10
106
+ nkululeko-0.77.6.dist-info/RECORD,,