sarapy 0.4.5__py3-none-any.whl → 0.4.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.
@@ -4,7 +4,6 @@ import numpy as np
4
4
  # from sarapy.mlProcessors import PlantinFMCreator
5
5
  from sarapy.mlProcessors import PlantinClassifier
6
6
 
7
-
8
7
  class OpsProcessor():
9
8
  """Clase para procesar las operaciones de los operarios. La información se toma de la base de datos
10
9
  hostórica y se procesa para obtener un array con las operaciones clasificadas para cada operario.
@@ -39,7 +38,7 @@ class OpsProcessor():
39
38
  self._classifiedOperations = np.array([]) ##array con las operaciones clasificadas
40
39
  self._last_row_db = 0 ##indicador de la última fila de los datos extraidos de la base de datos histórica
41
40
 
42
- def processOperations(self, newSample):
41
+ def processOperations(self, data):
43
42
  """Método para procesar las operaciones de los operarios.
44
43
 
45
44
  Se toma una nueva muestra y se procesa la información para clasificar las operaciones considerando el
@@ -47,20 +46,25 @@ class OpsProcessor():
47
46
  Se retorna un array con las clasificaciones concatenadas, manteniendo el orden de las operaciones por operario.
48
47
 
49
48
  Args:
50
- - newSample: lista con los datos (numpy.array de strings) de una muestra de operaciones.
51
- La forma de cada dato dentro de la lista newSample es (n,6). Las columnas de newSample son,
49
+ data: Es una lista de diccionario. Cada diccionario tiene los siguientes keys.
52
50
 
53
- - 0: op_number
54
- - 1: id_oprr
55
- - 2: tlm_spbb
56
- - 3: date_oprc
57
- - 4: lat
58
- - 5: lon
59
- - 6: precision
51
+ id_db, ID_NPDB, TLM_SPBB, date_oprc, latitud, longitud, precision
52
+
53
+ Ejemplo:
54
+
55
+ {"id_db":"1", "ID_NPDB":"XXAA123",
56
+ "TLM_SPBB": "1010001000010010101100010110000111101101001100000000000000000000",
57
+ "date_oprc":"2024-02-17 12:33:20",
58
+ "Latitud":"-32.145564789", "Longitud":"-55.145564789", "Precision": "0.25"}
59
+
60
+ Returns:
61
+ Lista de diccionarios con las clasificaciones. Cada diccionario tiene la forma
62
+ {"id_db": 10, "tag_seedling": 1, "tag_fertilizer": 1}
60
63
  """
61
64
 
62
65
  ##chqueo que newSample no esté vacío
63
- if len(newSample) != 0:
66
+ if len(data) != 0:
67
+ newSample = self.transformInputData(data)
64
68
  #Si tenemos nuevas operaciones, actualizamos el diccionario de operaciones
65
69
  self.updateOperationsDict(newSample) #actualizamos diccionario interno de la clase
66
70
  plantinClassifications = self.classifyForPlantin() #clasificamos las operaciones para plantín
@@ -79,12 +83,12 @@ class OpsProcessor():
79
83
  - newSample: lista con los datos (numpy.array de strings) de las operaciones.
80
84
  La forma de cada dato dentro de la lista newSample es (n,6). Las columnas de newSample son,
81
85
 
82
- - 0: op_number
83
- - 1: id_oprr
84
- - 2: tlm_spbb
86
+ - 0: id_db
87
+ - 1: ID_NPDP
88
+ - 2: TLM_SPBB
85
89
  - 3: date_oprc
86
- - 4: lat
87
- - 5: lon
90
+ - 4: latitud
91
+ - 5: longitud
88
92
  - 6: precision
89
93
 
90
94
  Returns:
@@ -93,36 +97,36 @@ class OpsProcessor():
93
97
  DE MANERA CORRECTA O HUBO ALGÚN PROBLEMA Y ASÍ VER QUÉ HACER EN EL MAIN
94
98
  """
95
99
 
96
- id_oprrs_w_newOperations = np.unique(newSample[:,1]) ##identificadores de operarios con nuevas operaciones en la muestra
100
+ ID_NPDPs_w_newOperations = np.unique(newSample[:,1]) ##identificadores de operarios con nuevas operaciones en la muestra
97
101
 
98
- ##chqueo si estos id_oprrs ya están en el diccionario, sino los agrego
99
- for id_oprr in id_oprrs_w_newOperations:
100
- if id_oprr not in self._operationsDict:
102
+ ##chqueo si estos ID_NPDPs ya están en el diccionario, sino los agrego
103
+ for ID_NPDP in ID_NPDPs_w_newOperations:
104
+ if ID_NPDP not in self._operationsDict:
101
105
  #El diccionario contiene la siguiente información:
102
- #sample_ops: np.array con las columnas de tlm_spbb, date_oprc, lat, lon, precision
103
- #last_oprc: np.array de la última operación con las columnas de tlm_spbb, date_oprc, lat, lon, precision
106
+ #sample_ops: np.array con las columnas de TLM_SPBB, date_oprc, lat, lon, precision
107
+ #last_oprc: np.array de la última operación con las columnas de TLM_SPBB, date_oprc, lat, lon, precision
104
108
  #first_day_op_classified: booleano para saber si es la primera operación del día fue clasificada
105
- self._operationsDict[id_oprr] = {"sample_ops": None,
109
+ self._operationsDict[ID_NPDP] = {"sample_ops": None,
106
110
  "last_oprc": None,
107
111
  "first_day_op_classified": False,
108
112
  "new_sample": False,
109
113
  "ops_numbers": None} #inicio del diccionario anidado para el nuevo operario
110
114
 
111
115
  ##actualizo el diccionario con las operaciones nuevas para aquellos operarios que correspondan
112
- for id_oprr in id_oprrs_w_newOperations:
113
- sample_ops = newSample[newSample[:,1] == id_oprr][:,2:] #me quedo con las columnas de tlm_spbb, date_oprc, lat, lon, precision
114
- ops_numbers = newSample[newSample[:,1] == id_oprr][:,0]
116
+ for ID_NPDP in ID_NPDPs_w_newOperations:
117
+ sample_ops = newSample[newSample[:,1] == ID_NPDP][:,2:] #me quedo con las columnas de TLM_SPBB, date_oprc, lat, lon, precision
118
+ ops_numbers = newSample[newSample[:,1] == ID_NPDP][:,0]
115
119
  ##actualizo el diccionario
116
- self._operationsDict[id_oprr]["sample_ops"] = sample_ops
117
- self._operationsDict[id_oprr]["ops_numbers"] = ops_numbers
120
+ self._operationsDict[ID_NPDP]["sample_ops"] = sample_ops
121
+ self._operationsDict[ID_NPDP]["ops_numbers"] = ops_numbers
118
122
  ##chequeo si tenemos última operación, si es así, asignamos dicha operación en la primera fila de sample_ops
119
- last_op = self._operationsDict[id_oprr]["last_oprc"]
123
+ last_op = self._operationsDict[ID_NPDP]["last_oprc"]
120
124
  ###si last_op es not None y last_op no está vacía, entonces concatenamos last_op con sample_ops
121
125
  if last_op is not None and last_op.size != 0:
122
- self._operationsDict[id_oprr]["sample_ops"] = np.vstack((last_op, sample_ops))
126
+ self._operationsDict[ID_NPDP]["sample_ops"] = np.vstack((last_op, sample_ops))
123
127
 
124
- self.updateNewSamplesValues(id_oprrs_w_newOperations) #actualizo el estado de 'new_sample' en el diccionario de operaciones
125
- self.updateLastOperations(id_oprrs_w_newOperations) #actualizo la última operación de una muestra de operaciones en el diccionario de operaciones
128
+ self.updateNewSamplesValues(ID_NPDPs_w_newOperations) #actualizo el estado de 'new_sample' en el diccionario de operaciones
129
+ self.updateLastOperations(ID_NPDPs_w_newOperations) #actualizo la última operación de una muestra de operaciones en el diccionario de operaciones
126
130
 
127
131
  def classifyForPlantin(self):
128
132
  """Método para clasificar las operaciones para plantín.
@@ -135,91 +139,135 @@ class OpsProcessor():
135
139
  ##creamos/reiniciamos el array con las clasificaciones de las operaciones para plantín
136
140
  plantinClassifications = None
137
141
 
138
- ##me quedo con los id_oprrs que tengan _operationsDict[id_oprr]["new_sample"] iguales a True
139
- ops_with_new_sample = [id_oprr for id_oprr in self.operationsDict.keys() if self.operationsDict[id_oprr]["new_sample"]]
142
+ ##me quedo con los ID_NPDPs que tengan _operationsDict[ID_NPDP]["new_sample"] iguales a True
143
+ ops_with_new_sample = [ID_NPDP for ID_NPDP in self.operationsDict.keys() if self.operationsDict[ID_NPDP]["new_sample"]]
140
144
 
141
- for id_oprr in ops_with_new_sample:#self.operationsDict.keys():
145
+ for ID_NPDP in ops_with_new_sample:#self.operationsDict.keys():
142
146
  ##clasificamos las operaciones para plantín
143
- operations = self.operationsDict[id_oprr]["sample_ops"]
147
+ operations = self.operationsDict[ID_NPDP]["sample_ops"]
144
148
  classified_ops = self._plantin_classifier.classify(operations)
145
149
 
146
150
  ##chequeo si first_day_op_classified es True, si es así, no se considera la primera fila de las classified_ops
147
- if self.operationsDict[id_oprr]["first_day_op_classified"]:
151
+ if self.operationsDict[ID_NPDP]["first_day_op_classified"]:
148
152
  classified_ops = classified_ops[1:]
149
153
 
150
154
  # plantinClassifications = np.vstack((plantinClassifications, classified_ops)) if plantinClassifications is not None else classified_ops
151
155
  plantinClassifications = np.concatenate((plantinClassifications, classified_ops)) if plantinClassifications is not None else classified_ops
152
156
 
153
- self.operationsDict[id_oprr]["first_day_op_classified"] = True
157
+ self.operationsDict[ID_NPDP]["first_day_op_classified"] = True
154
158
 
155
159
  return plantinClassifications
156
160
 
157
- def updateLastOperations(self, id_oprrs_w_newOperations):
161
+ def updateLastOperations(self, ID_NPDPs_w_newOperations):
158
162
  """Método para actualizar la última operación de una muestra de operaciones en el diccionario de operaciones
159
163
 
160
164
  Args:
161
165
  - newSample: lista con los datos (numpy.array de strings) de las operaciones.
162
166
  La forma de cada dato dentro de la lista newSample es (n,6). Las columnas de newSample son,
163
167
 
164
- - 0: op_number
165
- - 1: id_oprr
166
- - 2: tlm_spbb
168
+ - 0: id_db
169
+ - 1: ID_NPDP
170
+ - 2: TLM_SPBB
167
171
  - 3: date_oprc
168
- - 4: lat
169
- - 5: lon
172
+ - 4: latitud
173
+ - 5: longitud
170
174
  - 6: precision
171
175
  """
172
176
 
173
- for id_oprr in id_oprrs_w_newOperations:
174
- self._operationsDict[id_oprr]["last_oprc"] = self._operationsDict[id_oprr]["sample_ops"][-1]
177
+ for ID_NPDP in ID_NPDPs_w_newOperations:
178
+ self._operationsDict[ID_NPDP]["last_oprc"] = self._operationsDict[ID_NPDP]["sample_ops"][-1]
175
179
 
176
180
  def updateOperationsNumbers(self, new_ops_numbers):
177
181
  """Método para actualizar los números de operaciones en el diccionario de operaciones.
178
182
 
179
183
  Args:
180
- - new_ops_numbers: array de la forma (n,2) con los números de operaciones en la primer columna y los id_oprrs en la segunda.
184
+ - new_ops_numbers: array de la forma (n,2) con los números de operaciones en la primer columna y los ID_NPDPs en la segunda.
181
185
  """
182
- id_oprrs_w_newOperations = np.unique(new_ops_numbers[:,1]) ##identificadores de operarios con nuevas operaciones en la muestra
186
+ ID_NPDPs_w_newOperations = np.unique(new_ops_numbers[:,1]) ##identificadores de operarios con nuevas operaciones en la muestra
183
187
  opsNumbersList = np.array([]) ##array con los números de operaciones
184
188
 
185
- for id_oprr in id_oprrs_w_newOperations:
186
- opsNumbersList = np.append(opsNumbersList, self.operationsDict[id_oprr]["ops_numbers"].flatten())
189
+ for ID_NPDP in ID_NPDPs_w_newOperations:
190
+ opsNumbersList = np.append(opsNumbersList, self.operationsDict[ID_NPDP]["ops_numbers"].flatten())
187
191
 
188
192
  return opsNumbersList
189
193
 
190
- def updateNewSamplesValues(self, id_oprrs_w_newOperations):
194
+ def updateNewSamplesValues(self, ID_NPDPs_w_newOperations):
191
195
  """Método para actualizar el estado de 'new_sample' del diccionario de operaciones.
192
196
 
193
197
  Args:
194
- - id_oprrs_w_newOperations: lista con los id_oprrs que tienen nuevas operaciones.
198
+ - ID_NPDPs_w_newOperations: lista con los ID_NPDPs que tienen nuevas operaciones.
195
199
  """
196
200
 
197
201
  ##recorro el diccionario de operaciones y actualizo el estado de 'new_sample' a
198
- ##True para los id_oprrs que tienen nuevas operaciones y a False para los que no tienen nuevas operaciones
199
- for id_oprr in self.operationsDict.keys():
200
- if id_oprr in id_oprrs_w_newOperations:
201
- self._operationsDict[id_oprr]["new_sample"] = True
202
+ ##True para los ID_NPDPs que tienen nuevas operaciones y a False para los que no tienen nuevas operaciones
203
+ for ID_NPDP in self.operationsDict.keys():
204
+ if ID_NPDP in ID_NPDPs_w_newOperations:
205
+ self._operationsDict[ID_NPDP]["new_sample"] = True
202
206
  else:
203
- self._operationsDict[id_oprr]["new_sample"] = False
207
+ self._operationsDict[ID_NPDP]["new_sample"] = False
204
208
 
205
209
  def resetAllNewSamplesValues(self):
206
210
  """Método para resetar todos los valores de new_sample en el diccionario de operaciones.
207
211
  """
208
212
 
209
- for id_oprr in self.operationsDict.keys():
210
- self._operationsDict[id_oprr]["new_sample"] = False
213
+ for ID_NPDP in self.operationsDict.keys():
214
+ self._operationsDict[ID_NPDP]["new_sample"] = False
211
215
 
212
216
  def getActualOperationsNumbers(self):
213
217
  """Método para obtener los números de operaciones desde el diccionario de operaciones para aquellos operarios que
214
218
  tienen nuevas operaciones en la muestra."""
215
219
 
216
220
  opsNumbersList = np.array([])
217
- for id_oprr in self.operationsDict.keys():
218
- if self.operationsDict[id_oprr]["new_sample"]:
219
- opsNumbersList = np.append(opsNumbersList, self.operationsDict[id_oprr]["ops_numbers"].flatten())
221
+ for ID_NPDP in self.operationsDict.keys():
222
+ if self.operationsDict[ID_NPDP]["new_sample"]:
223
+ opsNumbersList = np.append(opsNumbersList, self.operationsDict[ID_NPDP]["ops_numbers"].flatten())
220
224
 
221
225
  return opsNumbersList
226
+
227
+ def updateFirstDayOp(self):
228
+ """Método para actualizar el indicador de si es la primera operación del día para cada operario en el diccionario de operaciones.
229
+ """
222
230
 
231
+ for ID_NPDP in self.operationsDict.keys():
232
+ self._operationsDict[ID_NPDP]["first_day_op_classified"] = False
233
+
234
+ def transformInputData(self, data):
235
+ """Función para transformar los datos de entrada que llegan del decoder
236
+
237
+ Args:
238
+ data: Es una lista de diccionario. Cada diccionario tiene los siguientes keys.
239
+
240
+ id_db, ID_NPDB, TLM_SPBB, date_oprc, latitud, longitud, precision
241
+
242
+ Ejemplo:
243
+
244
+ {"id_db":"1", "ID_NPDB":"XXAA123",
245
+ "TLM_SPBB": "1010001000010010101100010110000111101101001100000000000000000000",
246
+ "date_oprc":"2024-02-17 12:33:20",
247
+ "Latitud":"-32.145564789", "Longitud":"-55.145564789", "Precision": "0.25"}
248
+
249
+ Returns:
250
+ Retorna un array de strings con la siguiente estructura
251
+ - 0: id_db
252
+ - 1: ID_NPDP
253
+ - 2: TLM_SPBB
254
+ - 3: date_oprc
255
+ - 4: latitud
256
+ - 5: longitud
257
+ - 6: precision
258
+ """
259
+
260
+ ##convierto list_of_dics a un array de strings
261
+ newSample = np.array([[d["id_db"],
262
+ d["ID_NPDB"],
263
+ d["TLM_SPBB"],
264
+ d["date_oprc"],
265
+ d["Latitud"],
266
+ d["Longitud"],
267
+ d["precision"]] for d in data])
268
+
269
+ return newSample
270
+
223
271
  def cleanSamplesOperations(self):
224
272
  """Método para limpiar las operaciones de un operario en el diccionario de operaciones.
225
273
 
@@ -227,25 +275,18 @@ class OpsProcessor():
227
275
  - newSample: lista con los datos (numpy.array de strings) de las operaciones.
228
276
  La forma de cada dato dentro de la lista newSample es (n,6). Las columnas de newSample son,
229
277
 
230
- - 0: op_number
231
- - 1: id_oprr
232
- - 2: tlm_spbb
278
+ - 0: id_db
279
+ - 1: ID_NPDP
280
+ - 2: TLM_SPBB
233
281
  - 3: date_oprc
234
- - 4: lat
235
- - 5: lon
282
+ - 4: latitud
283
+ - 5: longitud
236
284
  - 6: precision
237
285
  """
238
286
 
239
- for id_oprr in self.operationsDict.keys():
240
- self._operationsDict[id_oprr]["sample_ops"] = None
241
-
242
- def updateFirstDayOp(self):
243
- """Método para actualizar el indicador de si es la primera operación del día para cada operario en el diccionario de operaciones.
244
- """
245
-
246
- for id_oprr in self.operationsDict.keys():
247
- self._operationsDict[id_oprr]["first_day_op_classified"] = False
248
-
287
+ for ID_NPDP in self.operationsDict.keys():
288
+ self._operationsDict[ID_NPDP]["sample_ops"] = None
289
+
249
290
  @property
250
291
  def operationsDict(self):
251
292
  return self._operationsDict
@@ -256,35 +297,16 @@ if __name__ == "__main__":
256
297
  import pandas as pd
257
298
  import numpy as np
258
299
  import os
259
- path = os.path.join(os.getcwd(), "examples\\volcado_17112023_NODE_processed.csv")
300
+ path = os.path.join(os.getcwd(), "examples\\volcado_17112023_NODE_processed_modified.csv")
260
301
  data_df = pd.read_csv(path, sep=";", )
261
302
  raw_data = data_df.to_numpy().astype(str)
262
-
263
- ##seed de numpy en 42
264
- np.random.seed(42)
265
-
266
- size = data_df[data_df["id_oprr"] == 1].shape[0]
267
- data_df.loc[data_df["id_oprr"] == 1, "id_dataBase"] = range(1,size+1)
268
- size = data_df[data_df["id_oprr"] == 2].shape[0]
269
- data_df.loc[data_df["id_oprr"] == 2, "id_dataBase"] = range(1,size+1)
270
- ##tomo raw_data y obtengo muestras de entre 7 a 15 filas una detrás de la otra. El valor de entre 7 y 15 es aleatorio.
271
- samples = []
272
- index = 0
273
- while True:
274
- random_value = np.random.randint(8, 15)
275
- if index + random_value < len(raw_data):
276
- samples.append(raw_data[index:index+random_value])
277
- else:
278
- break
279
- index += random_value
303
+
304
+ ##tomo los valos de data_df y formo una lista de diccionarios por cada fila
305
+ samples = data_df.to_dict(orient="records")
280
306
 
281
307
  # from sarapy.dataProcessing import OpsProcessor
282
308
  op = OpsProcessor(classifier_file="examples\\pip_lda_imp.pkl", imputeDistances = False)
283
-
284
309
  op.operationsDict
285
310
 
286
311
  ##procesamos una muestra
287
- print(op.processOperations(samples[10]))
288
- print(op.processOperations(np.array([])))
289
- print(op.processOperations(samples[11]))
290
- # data_df.loc[data_df["id_oprr"] == 1].head(15)
312
+ print(op.processOperations(samples))
sarapy/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  ## Version of the package
2
- __version__ = "0.4.5"
2
+ __version__ = "0.4.6"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sarapy
3
- Version: 0.4.5
3
+ Version: 0.4.6
4
4
  Home-page: https://github.com/lucasbaldezzari/sarapy
5
5
  Author: Lucas Baldezzari
6
6
  Author-email: Lucas Baldezzari <lmbaldezzari@gmail.com>
@@ -18,6 +18,10 @@ Requires-Dist: geopy
18
18
 
19
19
  Library for processing SARAPICO project metadata of _AMG_.
20
20
 
21
+ #### Version 0.4.6
22
+
23
+ - Se agrega función OpsProcessor.transformInputData() para convertir la lista de diccionarios entregadas por el decoder a un array de strings necesarios para procesar y clasificar los datos.
24
+
21
25
  #### Version 0.4.5
22
26
 
23
27
  - Se modifica clase PlantinClassifier para que ahora tome un clasificador y lo use para clasificar operaciones.
@@ -1,7 +1,7 @@
1
1
  sarapy/__init__.py,sha256=aVoywqGSscYYDycLaYJnz08dlQabl9gH0h4Q5KtHM9o,74
2
- sarapy/version.py,sha256=KuF2_9QeYiY1yBG2nnCohYHev5noJChe7yA4NSKV9oI,51
2
+ sarapy/version.py,sha256=-ICsoFiOIdQXw8uAPX7Lbso9HPap3-v8C1PrZR2OSIk,51
3
3
  sarapy/dataProcessing/GeoProcessor.py,sha256=YeNFHZ5sArnSLDxz009SJzgdWuMPgvJPkqtwcivk87A,4654
4
- sarapy/dataProcessing/OpsProcessor.py,sha256=O927-r0JvXyh397mAoowfQE0cxEoFug9OIxDiFDsuN8,14340
4
+ sarapy/dataProcessing/OpsProcessor.py,sha256=Ol_eVjWIqouoehwDT2MSJw8hy0T4Hvz2g0T-wryFpfs,15354
5
5
  sarapy/dataProcessing/TLMSensorDataProcessor.py,sha256=FbYKl0HMqBj6s2Uwu-MlYt1-QRWf-2rk0AdJTN3eE9w,23817
6
6
  sarapy/dataProcessing/TimeSeriesProcessor.py,sha256=QPvg9vyPSWjVl020zbebqvlM9JnL1uEAuACRsfZweAg,5497
7
7
  sarapy/dataProcessing/__init__.py,sha256=Kqs5sFtq6RMEa3KLJFbsGRoYsIxHL1UUGMuplyCyQFk,200
@@ -11,7 +11,7 @@ sarapy/mlProcessors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
11
11
  sarapy/preprocessing/DistancesImputer.py,sha256=NvbVAh5m0yFxVgDbEFnEX7RSG13qLjO7i2gqjDAWsf4,9106
12
12
  sarapy/preprocessing/FertilizerImputer.py,sha256=zK6ONAilwPHvj-bC7yxnQYOkDBCCkWh6__57vYK9anM,1490
13
13
  sarapy/preprocessing/__init__.py,sha256=Wg_Csy8Xiz8BN8A4-T7iPwcL_ol5ApEx6YtybItKB8M,100
14
- sarapy-0.4.5.dist-info/METADATA,sha256=DBScbd2NSkGpigcjAPNsnsaukTcB39urVx7rTxgoJcI,1567
15
- sarapy-0.4.5.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
16
- sarapy-0.4.5.dist-info/top_level.txt,sha256=4mUGZXfX2Fw47fpY6MQkaJeuOs_8tbjLkkNp34DJWiA,7
17
- sarapy-0.4.5.dist-info/RECORD,,
14
+ sarapy-0.4.6.dist-info/METADATA,sha256=8urLZKvvFMsuWBhJ9R_tC-S8a3x-7bTBhz_Psg6f3_4,1784
15
+ sarapy-0.4.6.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
16
+ sarapy-0.4.6.dist-info/top_level.txt,sha256=4mUGZXfX2Fw47fpY6MQkaJeuOs_8tbjLkkNp34DJWiA,7
17
+ sarapy-0.4.6.dist-info/RECORD,,
File without changes