small-fish-gui 1.5.0__py3-none-any.whl → 1.6.0__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.
- small_fish_gui/__init__.py +1 -1
- small_fish_gui/__main__.py +3 -3
- small_fish_gui/gui/prompts.py +10 -6
- small_fish_gui/pipeline/_colocalisation.py +9 -0
- small_fish_gui/pipeline/_napari_wrapper.py +7 -11
- small_fish_gui/pipeline/actions.py +30 -1
- small_fish_gui/pipeline/detection.py +10 -2
- small_fish_gui/pipeline/main.py +5 -1
- {small_fish_gui-1.5.0.dist-info → small_fish_gui-1.6.0.dist-info}/METADATA +1 -1
- {small_fish_gui-1.5.0.dist-info → small_fish_gui-1.6.0.dist-info}/RECORD +12 -12
- {small_fish_gui-1.5.0.dist-info → small_fish_gui-1.6.0.dist-info}/WHEEL +0 -0
- {small_fish_gui-1.5.0.dist-info → small_fish_gui-1.6.0.dist-info}/licenses/LICENSE +0 -0
small_fish_gui/__init__.py
CHANGED
small_fish_gui/__main__.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import sys, subprocess
|
|
2
2
|
import PySimpleGUI as sg
|
|
3
3
|
|
|
4
|
+
from small_fish_gui import __version__
|
|
5
|
+
|
|
4
6
|
def main():
|
|
5
7
|
import small_fish_gui.pipeline.main
|
|
6
8
|
|
|
@@ -10,9 +12,7 @@ def is_last_version() :
|
|
|
10
12
|
latest_version = latest_version[:latest_version.find(')')]
|
|
11
13
|
latest_version = latest_version.replace(' ','').split(',')[-1]
|
|
12
14
|
|
|
13
|
-
current_version =
|
|
14
|
-
current_version = current_version[current_version.find('Version:')+8:]
|
|
15
|
-
current_version = current_version[:current_version.find('\\n')].replace(' ','')
|
|
15
|
+
current_version = __version__
|
|
16
16
|
|
|
17
17
|
return current_version == latest_version
|
|
18
18
|
|
small_fish_gui/gui/prompts.py
CHANGED
|
@@ -280,7 +280,7 @@ def _warning_popup(warning:str) :
|
|
|
280
280
|
|
|
281
281
|
def _sumup_df(results: pd.DataFrame) :
|
|
282
282
|
|
|
283
|
-
COLUMNS = ['acquisition_id','threshold', 'spot_number', 'cell_number', 'filename', 'channel to compute']
|
|
283
|
+
COLUMNS = ['acquisition_id','name','threshold', 'spot_number', 'cell_number', 'filename', 'channel to compute']
|
|
284
284
|
|
|
285
285
|
if len(results) > 0 :
|
|
286
286
|
if 'channel to compute' not in results : results['channel to compute'] = np.NaN
|
|
@@ -303,7 +303,7 @@ def hub_prompt(fov_results, do_segmentation=False) :
|
|
|
303
303
|
[sg.Text('RESULTS', font= 'bold 13')],
|
|
304
304
|
[sg.Table(values= list(sumup_df.values), headings= list(sumup_df.columns), row_height=20, num_rows= 5, vertical_scroll_only=False, key= "result_table"), segmentation_object],
|
|
305
305
|
[sg.Button('Add detection'), sg.Button('Compute colocalisation'), sg.Button('Batch detection')],
|
|
306
|
-
[sg.Button('Save results', button_color= 'green'), sg.Button('Delete acquisitions',button_color= 'gray'), sg.Button('Reset segmentation',button_color= 'gray'), sg.Button('Reset results',button_color= 'gray')]
|
|
306
|
+
[sg.Button('Rename acquisition', button_color= 'green'), sg.Button('Save results', button_color= 'green'), sg.Button('Delete acquisitions',button_color= 'gray'), sg.Button('Reset segmentation',button_color= 'gray'), sg.Button('Reset results',button_color= 'gray')]
|
|
307
307
|
# [sg.Button('Save results', button_color= 'green'), sg.Button('Reset results',button_color= 'gray')]
|
|
308
308
|
]
|
|
309
309
|
|
|
@@ -318,16 +318,20 @@ def hub_prompt(fov_results, do_segmentation=False) :
|
|
|
318
318
|
return event, values
|
|
319
319
|
|
|
320
320
|
def coloc_prompt() :
|
|
321
|
-
layout = [
|
|
322
|
-
[parameters_layout(['colocalisation distance'], header= 'Colocalisation', default_values= 0)]
|
|
323
|
-
]
|
|
324
|
-
|
|
321
|
+
layout = parameters_layout(['colocalisation distance'], unit= 'nm', header= 'Colocalisation', default_values= 0)
|
|
325
322
|
event, values = prompt_with_help(layout)
|
|
326
323
|
|
|
327
324
|
if event == 'Ok' :
|
|
328
325
|
return values['colocalisation distance']
|
|
329
326
|
else : return False
|
|
330
327
|
|
|
328
|
+
def rename_prompt() :
|
|
329
|
+
layout = parameters_layout(['name'], header= "Rename acquisitions", size=12)
|
|
330
|
+
event, values = prompt_with_help(layout)
|
|
331
|
+
if event == 'Ok' :
|
|
332
|
+
return values['name']
|
|
333
|
+
else : return False
|
|
334
|
+
|
|
331
335
|
def ask_detection_confirmation(used_threshold) :
|
|
332
336
|
layout = [
|
|
333
337
|
[sg.Text("Proceed with current detection ?", font= 'bold 10')],
|
|
@@ -263,4 +263,13 @@ def launch_colocalisation(result_tables, result_dataframe, colocalisation_distan
|
|
|
263
263
|
'fraction_spots1_coloc_cluster2' : [fraction_spots1_coloc_cluster2],
|
|
264
264
|
})
|
|
265
265
|
|
|
266
|
+
coloc_df['fraction_spots1_coloc_free2'] = coloc_df['fraction_spots1_coloc_spots2'] - coloc_df['fraction_spots1_coloc_cluster2']
|
|
267
|
+
coloc_df['fraction_spots2_coloc_free1'] = coloc_df['fraction_spots2_coloc_spots1'] - coloc_df['fraction_spots2_coloc_cluster1']
|
|
268
|
+
|
|
269
|
+
#Add names
|
|
270
|
+
coloc_df_col = list(coloc_df.columns)
|
|
271
|
+
coloc_df['name1'] = acquisition1.at['name']
|
|
272
|
+
coloc_df['name2'] = acquisition2.at['name']
|
|
273
|
+
coloc_df = coloc_df.loc[:,['name1','name2'] + coloc_df_col]
|
|
274
|
+
|
|
266
275
|
return coloc_df
|
|
@@ -13,7 +13,7 @@ from ._colocalisation import spots_multicolocalisation
|
|
|
13
13
|
|
|
14
14
|
def _update_clusters(new_clusters: np.ndarray, spots: np.ndarray, voxel_size, cluster_size, min_spot_number, shape) :
|
|
15
15
|
if len(new_clusters) == 0 : return new_clusters
|
|
16
|
-
if len(spots) == 0 : return
|
|
16
|
+
if len(spots) == 0 : return np.empty(shape=(0,2+len(voxel_size)))
|
|
17
17
|
|
|
18
18
|
if len(new_clusters[0]) in [2,3] :
|
|
19
19
|
new_clusters = np.concatenate([
|
|
@@ -25,13 +25,10 @@ def _update_clusters(new_clusters: np.ndarray, spots: np.ndarray, voxel_size, cl
|
|
|
25
25
|
assert len(new_clusters[0]) == 4 or len(new_clusters[0]) == 5, "Wrong number of coordinates for clusters should not happen."
|
|
26
26
|
|
|
27
27
|
# Update spots clusters
|
|
28
|
-
|
|
29
|
-
new_clusters[:,-2] = spots_multicolocalisation(new_clusters[:,:3], spots, radius_nm= cluster_size, voxel_size=voxel_size, image_shape=shape)
|
|
30
|
-
elif len(voxel_size) == 2 :
|
|
31
|
-
new_clusters[:,-2] = spots_multicolocalisation(new_clusters[:,:2], spots, radius_nm= cluster_size, voxel_size=voxel_size, image_shape=shape)
|
|
28
|
+
new_clusters[:,-2] = spots_multicolocalisation(new_clusters[:,:-2], spots, radius_nm= cluster_size, voxel_size=voxel_size, image_shape=shape)
|
|
32
29
|
|
|
33
30
|
# delete too small clusters
|
|
34
|
-
|
|
31
|
+
new_clusters = np.delete(new_clusters, new_clusters[:,-2] < min_spot_number, 0)
|
|
35
32
|
|
|
36
33
|
return new_clusters
|
|
37
34
|
|
|
@@ -98,9 +95,8 @@ def correct_spots(image, spots, voxel_size= (1,1,1), clusters= None, cluster_siz
|
|
|
98
95
|
new_spots = np.array(Viewer.layers['single spots'].data, dtype= int)
|
|
99
96
|
|
|
100
97
|
if type(clusters) != type(None) :
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
new_clusters = _update_clusters(new_clusters, new_spots, voxel_size=voxel_size, cluster_size=cluster_size, min_spot_number=min_spot_number, shape=image.shape)
|
|
98
|
+
new_clusters = np.array(Viewer.layers['foci'].data, dtype= int)
|
|
99
|
+
new_clusters = _update_clusters(new_clusters, new_spots, voxel_size=voxel_size, cluster_size=cluster_size, min_spot_number=min_spot_number, shape=image.shape)
|
|
104
100
|
else : new_clusters = None
|
|
105
101
|
|
|
106
102
|
return new_spots, new_clusters
|
|
@@ -152,9 +148,9 @@ def show_segmentation(
|
|
|
152
148
|
Viewer.show(block=False)
|
|
153
149
|
napari.run()
|
|
154
150
|
|
|
155
|
-
|
|
156
151
|
new_nuc_label = Viewer.layers['nucleus_label'].data
|
|
157
|
-
if
|
|
152
|
+
if 'cytoplasm_label' in Viewer.layers :
|
|
153
|
+
new_cyto_label = Viewer.layers['cytoplasm_label'].data
|
|
158
154
|
else : new_cyto_label = new_nuc_label
|
|
159
155
|
|
|
160
156
|
return new_nuc_label, new_cyto_label
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
This submodule groups all the possible actions of the user in the main windows. It is the start of each action the user can do.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from ..gui.prompts import output_image_prompt, ask_detection_confirmation, ask_cancel_detection
|
|
5
|
+
from ..gui.prompts import output_image_prompt, ask_detection_confirmation, ask_cancel_detection, rename_prompt
|
|
6
6
|
from ..interface.output import write_results
|
|
7
7
|
from ._preprocess import map_channels, prepare_image_detection, reorder_shape, reorder_image_stack
|
|
8
8
|
from .detection import ask_input_parameters, initiate_detection, launch_detection, launch_features_computation, get_nucleus_signal
|
|
@@ -177,3 +177,32 @@ def delete_acquisitions(selected_acquisitions : pd.DataFrame,
|
|
|
177
177
|
result_df = result_df.drop(result_drop_idx, axis=0)
|
|
178
178
|
|
|
179
179
|
return result_df, cell_result_df, coloc_df
|
|
180
|
+
|
|
181
|
+
def rename_acquisitions(
|
|
182
|
+
selected_acquisitions : pd.DataFrame,
|
|
183
|
+
result_df : pd.DataFrame,
|
|
184
|
+
cell_result_df : pd.DataFrame,
|
|
185
|
+
coloc_df : pd.DataFrame
|
|
186
|
+
) :
|
|
187
|
+
|
|
188
|
+
if len(result_df) == 0 :
|
|
189
|
+
sg.popup("No acquisition to rename.")
|
|
190
|
+
return result_df, cell_result_df, coloc_df
|
|
191
|
+
|
|
192
|
+
if len(selected_acquisitions) == 0 :
|
|
193
|
+
sg.popup("Please select the acquisitions you would like to rename.")
|
|
194
|
+
|
|
195
|
+
else :
|
|
196
|
+
name = rename_prompt()
|
|
197
|
+
print("entered : ",name)
|
|
198
|
+
if not name : return result_df, cell_result_df, coloc_df #User didn't put a name or canceled
|
|
199
|
+
name : str = name.replace(' ','_')
|
|
200
|
+
acquisition_ids = list(result_df.iloc[list(selected_acquisitions)]['acquisition_id'])
|
|
201
|
+
|
|
202
|
+
result_df.loc[result_df['acquisition_id'].isin(acquisition_ids),['name']] = name
|
|
203
|
+
if len(cell_result_df) > 0 : cell_result_df.loc[cell_result_df['acquisition_id'].isin(acquisition_ids),['name']] = name
|
|
204
|
+
if len(coloc_df) > 0 :
|
|
205
|
+
coloc_df.loc[coloc_df['acquisition_id_1'].isin(acquisition_ids), ['name1']] = name
|
|
206
|
+
coloc_df.loc[coloc_df['acquisition_id_2'].isin(acquisition_ids), ['name2']] = name
|
|
207
|
+
|
|
208
|
+
return result_df, cell_result_df, coloc_df
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Contains code to handle detection as well as bigfish wrappers related to spot detection.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
from ._preprocess import ParameterInputError
|
|
5
6
|
from ._preprocess import check_integrity, convert_parameters_types
|
|
6
7
|
from ._signaltonoise import compute_snr_spots
|
|
@@ -575,8 +576,6 @@ def launch_cell_extraction(acquisition_id, spots, clusters, image, nucleus_signa
|
|
|
575
576
|
|
|
576
577
|
return result_frame
|
|
577
578
|
|
|
578
|
-
|
|
579
|
-
|
|
580
579
|
@add_default_loading
|
|
581
580
|
def launch_clustering(spots, user_parameters):
|
|
582
581
|
|
|
@@ -694,6 +693,15 @@ def launch_features_computation(acquisition_id, image, nucleus_signal, spots, cl
|
|
|
694
693
|
frame_results['threshold'] = user_parameters['threshold']
|
|
695
694
|
|
|
696
695
|
frame_results = pd.DataFrame(columns= frame_results.keys(), data= (frame_results.values(),))
|
|
696
|
+
|
|
697
|
+
#Adding name column
|
|
698
|
+
result_col = list(frame_results.columns)
|
|
699
|
+
cell_result_col = list(cell_result_dframe.columns)
|
|
700
|
+
name = "acquisition_{0}".format(acquisition_id)
|
|
701
|
+
frame_results['name'] = name
|
|
702
|
+
cell_result_dframe['name'] = name
|
|
703
|
+
frame_results = frame_results.loc[:,['name'] + result_col]
|
|
704
|
+
cell_result_dframe = cell_result_dframe.loc[:,['name'] + cell_result_col]
|
|
697
705
|
|
|
698
706
|
return frame_results, cell_result_dframe
|
|
699
707
|
|
small_fish_gui/pipeline/main.py
CHANGED
|
@@ -5,7 +5,7 @@ This script is called when software starts; it is the main loop.
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
import PySimpleGUI as sg
|
|
7
7
|
from ..gui import hub_prompt
|
|
8
|
-
from .actions import add_detection, save_results, compute_colocalisation, delete_acquisitions
|
|
8
|
+
from .actions import add_detection, save_results, compute_colocalisation, delete_acquisitions, rename_acquisitions
|
|
9
9
|
from ._preprocess import clean_unused_parameters_cache
|
|
10
10
|
from ..batch import batch_promp
|
|
11
11
|
|
|
@@ -84,6 +84,10 @@ while True : #Break this loop to close small_fish
|
|
|
84
84
|
preset=user_parameters,
|
|
85
85
|
)
|
|
86
86
|
|
|
87
|
+
elif event == "Rename acquisition" :
|
|
88
|
+
selected_acquisitions = values.setdefault('result_table', []) #Contains the lines selected by the user on the sum-up array.
|
|
89
|
+
result_df, cell_result_df, coloc_df = rename_acquisitions(selected_acquisitions, result_df, cell_result_df, coloc_df)
|
|
90
|
+
|
|
87
91
|
else :
|
|
88
92
|
break
|
|
89
93
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: small_fish_gui
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0
|
|
4
4
|
Summary: Small Fish is a python application for the analysis of smFish images. It provides a ready to use graphical interface to combine famous python packages for cell analysis without any need for coding.
|
|
5
5
|
Project-URL: Homepage, https://github.com/2Echoes/small_fish
|
|
6
6
|
Project-URL: Issues, https://github.com/2Echoes/small_fish/issues
|
|
@@ -2,8 +2,8 @@ small_fish_gui/.readthedocs.yaml,sha256=r2T0e_In8X8l0_ZwgPvuoWQ9c0PE9bSpFzV2W6Ez
|
|
|
2
2
|
small_fish_gui/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
|
|
3
3
|
small_fish_gui/README.md,sha256=4RpEXKZW5vH6sUWeZb88yr1TLLPi20PqOk7KdA9O9Hk,4234
|
|
4
4
|
small_fish_gui/Segmentation example.jpg,sha256=opfiSbjmfF6z8kBs08sg_FNR2Om0AcMPU5sSwSLHdoQ,215038
|
|
5
|
-
small_fish_gui/__init__.py,sha256=
|
|
6
|
-
small_fish_gui/__main__.py,sha256=
|
|
5
|
+
small_fish_gui/__init__.py,sha256=5p-W0XXzvadf_q5TZCbYLXaSLIBLOBlhwt7rTtg760w,1941
|
|
6
|
+
small_fish_gui/__main__.py,sha256=jjFNnf-l4jCJI16epq2KOaKmgtUAe9lSNdPj5fpxrDk,1143
|
|
7
7
|
small_fish_gui/napari_detection_example.png,sha256=l5EZlrbXemLiGqb5inSVsD6Kko1Opz528-go-fBfrw8,977350
|
|
8
8
|
small_fish_gui/requirements.txt,sha256=9OMfUAnLdHevq6w_fVoDmVmkSMJeFofkOK_86_fu9C0,321
|
|
9
9
|
small_fish_gui/utils.py,sha256=LM6QW2ono_LIRv7JXIIq7ZxxbDXqBtZ5uR9gjKJfwM8,1903
|
|
@@ -26,7 +26,7 @@ small_fish_gui/gui/general_help_screenshot.png,sha256=X4E6Td5f04K-pBUPDaBJRAE3D5
|
|
|
26
26
|
small_fish_gui/gui/help_module.py,sha256=PmgkkDs7bZ2-po83A_PK9uldQcHjehYmqre21nYb6DQ,9600
|
|
27
27
|
small_fish_gui/gui/layout.py,sha256=oB8Kg6s0rCA8yB4WM8JQY8BpjoPiBqTGb6YoOKDqEA8,13855
|
|
28
28
|
small_fish_gui/gui/mapping_help_screenshot.png,sha256=HcuRh5TYciUogUasza5vZ_QSshaiHsskQK23mh9vQS8,34735
|
|
29
|
-
small_fish_gui/gui/prompts.py,sha256=
|
|
29
|
+
small_fish_gui/gui/prompts.py,sha256=rdO2X_whpBgMzCrysFoJEUWfZwbC7mZOp_DYctftNT0,13634
|
|
30
30
|
small_fish_gui/gui/segmentation_help_screenshot.png,sha256=rbSgIydT0gZtfMh1qk4mdMbEIyCaakvHmxa2eOrLwO0,118944
|
|
31
31
|
small_fish_gui/interface/__init__.py,sha256=PB86R4Y9kV80aGZ-vP0ZW2KeaCwGbBbCtFCmbN2yl28,275
|
|
32
32
|
small_fish_gui/interface/image.py,sha256=X1L7S5svxUwdoDcI3QM1PbN-c4Nz5w30hixq3IgqSn8,1130
|
|
@@ -34,19 +34,19 @@ small_fish_gui/interface/output.py,sha256=5jC37tobgXgsiVJYx3RWaES09I-YFmbXKk65lH
|
|
|
34
34
|
small_fish_gui/interface/parameters.py,sha256=lUugD-4W2TZyJF3TH1q70TlktEYhhPtcPCrvxm5Dk50,36
|
|
35
35
|
small_fish_gui/interface/testing.py,sha256=MY5-GcPOUHagcrwR8A7QOjAmjZIDVC8Wz3NibLe3KQw,321
|
|
36
36
|
small_fish_gui/pipeline/__init__.py,sha256=_Ey20GG8fJtqZvixbXNNYX6wTWMnCUArmARPqsNEhuQ,743
|
|
37
|
-
small_fish_gui/pipeline/_colocalisation.py,sha256=
|
|
37
|
+
small_fish_gui/pipeline/_colocalisation.py,sha256=pWyObNoACWNW04OYzKf7bgq2OezWpEWh7Vl5DShTI1A,10118
|
|
38
38
|
small_fish_gui/pipeline/_custom_errors.py,sha256=tQ-AUhgzIFpK30AZiQQrtHCHyGVRDdAoIjzL0Fk-1pA,43
|
|
39
|
-
small_fish_gui/pipeline/_napari_wrapper.py,sha256=
|
|
39
|
+
small_fish_gui/pipeline/_napari_wrapper.py,sha256=Yjpo-uXQxLfLESsWr4kIBZgQNVXJtcTFcrsvS9sk4No,7832
|
|
40
40
|
small_fish_gui/pipeline/_preprocess.py,sha256=ddocTXwc0vYq2VGUbWYaN9eUiHPyfiCuBpYQ2p6rQ8g,13084
|
|
41
41
|
small_fish_gui/pipeline/_segmentation.py,sha256=gcanidUOC9nULF6UffWLFmfIup-EOMxeckBz7Xldp3I,18852
|
|
42
42
|
small_fish_gui/pipeline/_signaltonoise.py,sha256=7A9t7xu7zghI6cr201Ldm-LjJ5NOuP56VSeJ8KIzcUo,8497
|
|
43
|
-
small_fish_gui/pipeline/actions.py,sha256=
|
|
44
|
-
small_fish_gui/pipeline/detection.py,sha256=
|
|
45
|
-
small_fish_gui/pipeline/main.py,sha256=
|
|
43
|
+
small_fish_gui/pipeline/actions.py,sha256=YGW7IFwtRksf0nktl5C2uVLP-Z-7vVznIBxIdJGZJZw,9447
|
|
44
|
+
small_fish_gui/pipeline/detection.py,sha256=rnA0qMqr0dNUAUPd1ANYZ7dyfllsDQrihO_gjEpenvA,34817
|
|
45
|
+
small_fish_gui/pipeline/main.py,sha256=7iBHO8xNEvdONaUo78jkShBkHFuwgGryMoI4YwP4coI,3817
|
|
46
46
|
small_fish_gui/pipeline/spots.py,sha256=yHvqf1eD25UltELpzcouYXhLkxiXI_mOL1ANSzXK5pw,1907
|
|
47
47
|
small_fish_gui/pipeline/test.py,sha256=w4ZMGDmUDXxVgWTlZ2TKw19W8q5gcE9gLMKe0SWnRrw,2827
|
|
48
48
|
small_fish_gui/pipeline/utils.py,sha256=run6qtqCAe_mFnE3o1CnmF1xBBmK3ydgc8-jOV9P-_w,448
|
|
49
|
-
small_fish_gui-1.
|
|
50
|
-
small_fish_gui-1.
|
|
51
|
-
small_fish_gui-1.
|
|
52
|
-
small_fish_gui-1.
|
|
49
|
+
small_fish_gui-1.6.0.dist-info/METADATA,sha256=lNNHwO008d4nmzHaYpeNKi9DFptJ56O0GxfmxWiRxI4,2567
|
|
50
|
+
small_fish_gui-1.6.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
51
|
+
small_fish_gui-1.6.0.dist-info/licenses/LICENSE,sha256=-iFy8VGBYs5VsHglKpk4D-hxqQ2jMJaqmfq_ulIzDks,1303
|
|
52
|
+
small_fish_gui-1.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|