chromaquant 0.4.0__py3-none-any.whl → 0.5.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.
Files changed (63) hide show
  1. chromaquant/__init__.py +9 -2
  2. chromaquant/data/__init__.py +14 -0
  3. chromaquant/data/breakdown.py +430 -0
  4. chromaquant/data/dataset.py +195 -0
  5. chromaquant/data/table.py +412 -0
  6. chromaquant/data/value.py +215 -0
  7. chromaquant/formula/__init__.py +13 -0
  8. chromaquant/formula/base_formulas.py +168 -0
  9. chromaquant/formula/formula.py +507 -0
  10. chromaquant/import_local_packages.py +55 -0
  11. chromaquant/logging_and_handling.py +76 -0
  12. chromaquant/match/__init__.py +13 -0
  13. chromaquant/match/match.py +184 -0
  14. chromaquant/match/match_config.py +296 -0
  15. chromaquant/match/match_tools.py +154 -0
  16. chromaquant/{Quant → results}/__init__.py +2 -2
  17. chromaquant/results/reporting_tools.py +190 -0
  18. chromaquant/results/results.py +250 -0
  19. chromaquant/utils/__init__.py +14 -0
  20. chromaquant/utils/categories.py +127 -0
  21. chromaquant/utils/chemical_formulas.py +104 -0
  22. chromaquant/utils/dataframe_processing.py +222 -0
  23. chromaquant/utils/file_tools.py +100 -0
  24. chromaquant/utils/formula_tools.py +119 -0
  25. chromaquant-0.5.0.dist-info/METADATA +61 -0
  26. chromaquant-0.5.0.dist-info/RECORD +29 -0
  27. {chromaquant-0.4.0.dist-info → chromaquant-0.5.0.dist-info}/WHEEL +1 -1
  28. {chromaquant-0.4.0.dist-info → chromaquant-0.5.0.dist-info}/licenses/LICENSE.txt +1 -1
  29. chromaquant-0.5.0.dist-info/licenses/LICENSES_bundled.txt +251 -0
  30. chromaquant/Handle/__init__.py +0 -13
  31. chromaquant/Handle/fileChecks.py +0 -172
  32. chromaquant/Handle/handleDirectories.py +0 -89
  33. chromaquant/Hydro/__init__.py +0 -12
  34. chromaquant/Hydro/hydroMain.py +0 -496
  35. chromaquant/Manual/HydroUI.py +0 -418
  36. chromaquant/Manual/QuantUPP.py +0 -373
  37. chromaquant/Manual/Quantification.py +0 -1305
  38. chromaquant/Manual/__init__.py +0 -10
  39. chromaquant/Manual/duplicateMatch.py +0 -211
  40. chromaquant/Manual/fpm_match.py +0 -798
  41. chromaquant/Manual/label-type.py +0 -179
  42. chromaquant/Match/AutoFpmMatch.py +0 -1133
  43. chromaquant/Match/MatchSub/__init__.py +0 -13
  44. chromaquant/Match/MatchSub/matchTools.py +0 -282
  45. chromaquant/Match/MatchSub/peakTools.py +0 -259
  46. chromaquant/Match/__init__.py +0 -13
  47. chromaquant/Match/matchMain.py +0 -233
  48. chromaquant/Quant/AutoQuantification.py +0 -1329
  49. chromaquant/Quant/QuantSub/__init__.py +0 -15
  50. chromaquant/Quant/QuantSub/gasFID.py +0 -241
  51. chromaquant/Quant/QuantSub/gasTCD.py +0 -425
  52. chromaquant/Quant/QuantSub/liquidFID.py +0 -310
  53. chromaquant/Quant/QuantSub/parseTools.py +0 -162
  54. chromaquant/Quant/quantMain.py +0 -417
  55. chromaquant/UAPP/__init__.py +0 -12
  56. chromaquant/UAPP/uappMain.py +0 -427
  57. chromaquant/__main__.py +0 -526
  58. chromaquant/oldui.py +0 -492
  59. chromaquant/properties.json +0 -4
  60. chromaquant-0.4.0.dist-info/METADATA +0 -189
  61. chromaquant-0.4.0.dist-info/RECORD +0 -38
  62. chromaquant-0.4.0.dist-info/entry_points.txt +0 -2
  63. chromaquant-0.4.0.dist-info/licenses/LICENSES_bundled.txt +0 -1035
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ COPYRIGHT STATEMENT:
5
+
6
+ ChromaQuant – A quantification software for complex gas chromatographic data
7
+
8
+ Copyright (c) 2026, by Julia Hancock
9
+ Affiliation: Dr. Julie Elaine Rorrer
10
+ URL: https://www.rorrerlab.com/
11
+
12
+ License: BSD 3-Clause License
13
+
14
+ ---
15
+
16
+ COLLECTION OF SIMPLE FORMULAS
17
+
18
+ Julia Hancock
19
+ Started 1-23-2026
20
+
21
+ """
22
+
23
+ from .formula import Formula
24
+
25
+ """ FUNCTIONS """
26
+
27
+
28
+ # Create formula using formula string and (optionally) pointer
29
+ def CREATE_FORMULA_FROM_STRING(formula_string: str,
30
+ key_pointer: str = '',
31
+ table_pointer: str = ''):
32
+
33
+ # Create Formula
34
+ formula = Formula(formula_string, key_pointer, table_pointer)
35
+
36
+ return formula
37
+
38
+
39
+ # Create formula by wrapping existing formula in stated Excel formula
40
+ def WRAP_FORMULA_STRING(inner_formula_string: str,
41
+ wrapping_formula_string: str):
42
+
43
+ # Get a new formula string
44
+ formula_string = \
45
+ f'={wrapping_formula_string}({inner_formula_string})'
46
+
47
+ return formula_string
48
+
49
+
50
+ # Wrap existing formula in IFERROR()
51
+ def FORMULA_IF_ERROR(formula: Formula):
52
+
53
+ # Get the formula string
54
+ formula_string = formula.formula_string
55
+
56
+ # If there is an equals sign at the beginning...
57
+ if formula_string[0] == '=':
58
+ # Remove the equals sign
59
+ formula_string = formula_string[1:]
60
+
61
+ # Otherwise, pass
62
+ else:
63
+ pass
64
+
65
+ # Wrap the formula string in IFERROR()
66
+ formula_string = '=IFERROR(' + formula_string + ', "")'
67
+
68
+ # Set the formula string in Formula again
69
+ formula.formula_string = formula_string
70
+
71
+ return formula
72
+
73
+
74
+ # Create formula for binary operations
75
+ def FORMULA_BINARY_OPERATION(left_hand_side: str,
76
+ right_hand_side: str,
77
+ operator: str,
78
+ key_pointer: str = '',
79
+ table_pointer: str = ''):
80
+
81
+ # Get a list of sides
82
+ side_list = [left_hand_side, right_hand_side]
83
+
84
+ # For each passed side of the operator...
85
+ for i in range(len(side_list)):
86
+
87
+ # If the side starts with equals...
88
+ if side_list[i][0] == '=':
89
+ # Remove the equals sign
90
+ side_list[i] = side_list[i][1:]
91
+
92
+ # Otherwise, pass
93
+ else:
94
+ pass
95
+
96
+ # Get a formula string
97
+ formula_string = f'=({side_list[0]}{operator}{side_list[1]})'
98
+
99
+ # Get a Formula instance using CREATE_FORMULA_FROM_STRING
100
+ formula = CREATE_FORMULA_FROM_STRING(formula_string,
101
+ key_pointer,
102
+ table_pointer)
103
+
104
+ return formula
105
+
106
+
107
+ # Create formula for binary addition
108
+ def FORMULA_ADDITION(left_hand_side: str,
109
+ right_hand_side: str,
110
+ key_pointer: str = '',
111
+ table_pointer: str = ''):
112
+
113
+ # Get a Formula instance using FORMULA_BINARY_OPERATION
114
+ formula = FORMULA_BINARY_OPERATION(left_hand_side,
115
+ right_hand_side,
116
+ '+',
117
+ key_pointer,
118
+ table_pointer)
119
+
120
+ return formula
121
+
122
+
123
+ # Create formula for binary subtraction
124
+ def FORMULA_SUBTRACTION(left_hand_side: str,
125
+ right_hand_side: str,
126
+ key_pointer: str = '',
127
+ table_pointer: str = ''):
128
+
129
+ # Get a Formula instance using FORMULA_BINARY_OPERATION
130
+ formula = FORMULA_BINARY_OPERATION(left_hand_side,
131
+ right_hand_side,
132
+ '-',
133
+ key_pointer,
134
+ table_pointer)
135
+
136
+ return formula
137
+
138
+
139
+ # Create formula for binary multiplication
140
+ def FORMULA_MULTIPLICATION(left_hand_side: str,
141
+ right_hand_side: str,
142
+ key_pointer: str = '',
143
+ table_pointer: str = ''):
144
+
145
+ # Get a Formula instance using FORMULA_BINARY_OPERATION
146
+ formula = FORMULA_BINARY_OPERATION(left_hand_side,
147
+ right_hand_side,
148
+ '*',
149
+ key_pointer,
150
+ table_pointer)
151
+
152
+ return formula
153
+
154
+
155
+ # Create formula for binary division
156
+ def FORMULA_DIVISION(left_hand_side: str,
157
+ right_hand_side: str,
158
+ key_pointer: str = '',
159
+ table_pointer: str = ''):
160
+
161
+ # Get a Formula instance using FORMULA_BINARY_OPERATION
162
+ formula = FORMULA_BINARY_OPERATION(left_hand_side,
163
+ right_hand_side,
164
+ '/',
165
+ key_pointer,
166
+ table_pointer)
167
+
168
+ return formula
@@ -0,0 +1,507 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ COPYRIGHT STATEMENT:
5
+
6
+ ChromaQuant – A quantification software for complex gas chromatographic data
7
+
8
+ Copyright (c) 2026, by Julia Hancock
9
+ Affiliation: Dr. Julie Elaine Rorrer
10
+ URL: https://www.rorrerlab.com/
11
+
12
+ License: BSD 3-Clause License
13
+
14
+ ---
15
+
16
+ CLASS DEFINITION FOR FORMULA
17
+
18
+ Julia Hancock
19
+ Started 1-07-2026
20
+
21
+ """
22
+
23
+ import logging
24
+ import re
25
+ from typing import Any
26
+ from ..logging_and_handling import setup_logger, setup_error_logging
27
+
28
+ """ LOGGING AND HANDLING """
29
+
30
+ # Create a logger
31
+ logger = logging.getLogger(__name__)
32
+
33
+ # Format the logger
34
+ logger = setup_logger(logger)
35
+
36
+ # Get an error logging decorator
37
+ error_logging = setup_error_logging(logger)
38
+
39
+ """ CLASSES """
40
+
41
+
42
+ # Define the formula class
43
+ class Formula:
44
+
45
+ """ SPECIAL METHODS """
46
+ # Initialize class
47
+ def __init__(self,
48
+ formula: str = '',
49
+ key_pointer: str = '',
50
+ table_pointer: str = ''):
51
+ """__init__ summary
52
+
53
+ Parameters
54
+ ----------
55
+ formula : str
56
+ Passed formula with or without inserts and pointers
57
+ pointer: dict
58
+ Dictionary with key and (optionally) table name where
59
+ the formula will be located
60
+
61
+ """
62
+
63
+ # Extract the formula if passed
64
+ if formula != '':
65
+ self._formula = formula
66
+ self.get_formula_cell_inserts()
67
+
68
+ # Otherwise set to a default value
69
+ else:
70
+ self._formula = None
71
+
72
+ # Add passed pointers, even if blank
73
+ self.point_to(key_pointer, table_pointer)
74
+
75
+ # Object representation method, allows for direct access to formula
76
+ def __repr__(self):
77
+ # Return formula string
78
+ return self._formula
79
+
80
+ """ PROPERTIES """
81
+ # Formula properties
82
+ # Formula getter
83
+ @property
84
+ def formula_string(self):
85
+ return self._formula
86
+
87
+ # Formula setter
88
+ @formula_string.setter
89
+ def formula_string(self, value):
90
+ self._formula = value
91
+ self.get_formula_cell_inserts()
92
+
93
+ # Formula deleter
94
+ @formula_string.deleter
95
+ def formula_string(self):
96
+ del self._formula
97
+ del self.insert_list
98
+
99
+ """ METHODS """
100
+ # Method to set formula pointer values
101
+ @error_logging
102
+ def point_to(self,
103
+ key_or_column_id: str,
104
+ table_id: str = ''):
105
+
106
+ # Set the key pointer
107
+ self.key_pointer = key_or_column_id
108
+
109
+ # Set the table pointer
110
+ self.table_pointer = table_id
111
+
112
+ return None
113
+
114
+ # Method to get cases in a formula where cells need to be inserted
115
+ @error_logging
116
+ def get_formula_cell_inserts(self):
117
+
118
+ # Initialize a list to contain parsed pipe contents
119
+ insert_list = []
120
+
121
+ # If the formula contains at least one pipe character...
122
+ if '|' in self._formula:
123
+
124
+ # Get the number of pipes in the formula
125
+ pipe_count = self._formula.count('|')
126
+
127
+ # If the number of pipes is divisible by two...
128
+ if pipe_count % 2 == 0:
129
+
130
+ # Get a list of every substring within pipes
131
+ insert_list = [{'start': match.start(),
132
+ 'end': match.end(),
133
+ 'raw': match.group(),
134
+ 'pipe': [],
135
+ 'pointers': {}}
136
+ for match in re.finditer(r'\|(.*?)\|',
137
+ self._formula)]
138
+
139
+ # For each pipe substring...
140
+ for i in range(len(insert_list)):
141
+
142
+ # Split each substring if it contains commas
143
+ insert_list[i]['pipe'] = \
144
+ insert_list[i]['raw'].split(',')
145
+
146
+ # For each newly-split substring...
147
+ for j in range(len(insert_list[i]['pipe'])):
148
+
149
+ # If the substring contains one colon...
150
+ if insert_list[i]['pipe'][j].count(':') == 1:
151
+
152
+ # Split the substring by that colon
153
+ key_value_list = \
154
+ insert_list[i]['pipe'][j].split(':')
155
+
156
+ # Strip the key and value of pipes and whitespace
157
+ key_value_list = \
158
+ [k.strip('|').strip() for k in key_value_list]
159
+
160
+ # Add the key-value pair to the pointers dictionary
161
+ insert_list[i]['pointers'][key_value_list[0]] = \
162
+ key_value_list[1]
163
+
164
+ # Otherwise, raise error
165
+ else:
166
+ raise ValueError('At least one pointer contains an'
167
+ ' unexpected number of colons')
168
+
169
+ # Remove the pipe key-value pairs
170
+ del insert_list[i]['pipe']
171
+
172
+ # Otherwise, raise an error
173
+ else:
174
+ raise ValueError('Formula contains at least'
175
+ 'one hanging pipe delimeter:'
176
+ f' "{self._formula}"')
177
+
178
+ # Otherwise, pass
179
+ else:
180
+ pass
181
+
182
+ # Save the insert list to a class attribute
183
+ self.insert_list = insert_list
184
+
185
+ return None
186
+
187
+ # Method to replace formula inserts with references
188
+ @error_logging
189
+ def insert_references(self,
190
+ dataset_references: dict[str, dict[Any]]):
191
+
192
+ # Get a dataset references attribute
193
+ self.dataset_references = dataset_references
194
+
195
+ # If the insert list is not None (i.e., there are inserts)...
196
+ if self.insert_list is not None:
197
+
198
+ # If function was passed a table to output to...
199
+ if self.table_pointer != '' and self.key_pointer != '':
200
+
201
+ # Get the list of referenced formulas
202
+ self.referenced_formulas = \
203
+ self.process_table_formula_inserts()
204
+
205
+ # Otherwise, if the function was passed a value to output to...
206
+ elif self.key_pointer != '':
207
+
208
+ # Get the list of referenced formulas
209
+ self.referenced_formulas = \
210
+ self.process_value_formula_inserts()
211
+
212
+ # Otherwise, raise an error
213
+ else:
214
+ raise ValueError('Passed output pointers do not'
215
+ ' point to either a value or table')
216
+
217
+ return None
218
+
219
+ # Method to process table formula inserts
220
+ @error_logging
221
+ def process_table_formula_inserts(self):
222
+ """
223
+ process_table_formula_inserts
224
+
225
+ Parameters
226
+ ----------
227
+ None
228
+
229
+ Returns
230
+ -------
231
+ new_formula : list or str
232
+ New formula or list of new formulas.
233
+
234
+ Raises
235
+ ------
236
+ ValueError
237
+ 'Insert list contains non-key or non-table elements'
238
+ ValueError
239
+ 'Formula missing necessary keys'
240
+ ValueError
241
+ 'Passed output pointers do not point to either a value or table'
242
+ """
243
+
244
+ # Try...
245
+ try:
246
+
247
+ # Get the table length
248
+ # NOTE: USES THE LENGTH FROM THE FIRST COLUMN IN THE TABLE
249
+ output_table_length = \
250
+ self.dataset_references[
251
+ self.table_pointer
252
+ ][
253
+ next(iter(self.table_pointer[self.table_pointer]))
254
+ ]['length']
255
+
256
+ # If length is less than one, set to five
257
+ if output_table_length < 1:
258
+ output_table_length = 5
259
+
260
+ # Otherwise, pass
261
+ else:
262
+ pass
263
+
264
+ # If can't get the length, set to five
265
+ except Exception:
266
+ # logger.info('Formula output pointer indicates empty column.')
267
+ output_table_length = 5
268
+
269
+ # If there is at least one table among inserts...
270
+ if any('table' in insert.get('pointers', {})
271
+ and 'key' in insert.get('pointers', {})
272
+ for insert in self.insert_list):
273
+
274
+ # Get the length of the longest named table
275
+ max_table_length = max(
276
+ [self.dataset_references[
277
+ insert['pointers']['table']
278
+ ][
279
+ insert['pointers']['key']
280
+ ]['length']
281
+ for insert in self.insert_list
282
+ if 'table' in insert.get('pointers', {})]
283
+ )
284
+
285
+ # If the max_table_length is greater than 1, set
286
+ # the output_table_length to the max_table_length
287
+ if max_table_length > 1:
288
+ output_table_length = max_table_length
289
+
290
+ # Otherwise, pass
291
+ else:
292
+ pass
293
+
294
+ # Initialize a new formula list
295
+ new_formula = \
296
+ [self._formula for i in range(output_table_length)]
297
+
298
+ # For every insert...
299
+ for insert in self.insert_list:
300
+
301
+ # If the insert has a table and key pointer...
302
+ if 'table' in insert['pointers'] \
303
+ and 'key' in insert['pointers']:
304
+
305
+ # Get the insert's table and key pointers
306
+ table_id = insert['pointers']['table']
307
+ column_name = insert['pointers']['key']
308
+
309
+ # Get the current table reference
310
+ table_ref = self.dataset_references[table_id]
311
+
312
+ # If the insert has range pointer equal to true...
313
+ if 'range' in insert['pointers'] and \
314
+ insert['pointers']['range'].capitalize() \
315
+ == 'True':
316
+
317
+ # Get a range substring for each
318
+ # new entry in the output table
319
+ insert['reference'] = \
320
+ table_ref[column_name]['range']
321
+
322
+ # Replace the insert's raw substring
323
+ # for every formula in the new formula list
324
+ new_formula = \
325
+ [self.replace_insert(one_formula,
326
+ insert['raw'],
327
+ insert['reference'])
328
+ for one_formula in new_formula]
329
+
330
+ # Otherwise...
331
+ else:
332
+
333
+ # Get the column letter
334
+ column_letter = \
335
+ table_ref[column_name]['column_letter']
336
+ # Get the column sheet
337
+ column_sheet = \
338
+ table_ref[column_name]['sheet']
339
+
340
+ # Get the start and end rows
341
+ start_row = \
342
+ table_ref[column_name]['start_row']
343
+ end_row = \
344
+ table_ref[column_name]['end_row']
345
+
346
+ # Get a list of insert references for each
347
+ # row iterated over, adjusted to ignore header
348
+ insert['reference'] = \
349
+ [
350
+ f"'{column_sheet}'!"
351
+ f"${column_letter}${row}"
352
+ for row in
353
+ range(start_row, end_row + 1)
354
+ ]
355
+
356
+ # Replace the insert's raw substring
357
+ # for every formula in the new formula list
358
+ new_formula = \
359
+ [self.replace_insert(new_formula[i],
360
+ insert['raw'],
361
+ insert['reference'][i]
362
+ )
363
+ for i in range(output_table_length)]
364
+
365
+ # Otherwise, if the insert has a key pointer...
366
+ elif 'key' in insert['pointers']:
367
+
368
+ # Get the key pointer
369
+ key_id = insert['pointers']['key']
370
+
371
+ # Get the value's data reference string
372
+ insert['reference'] = \
373
+ self.dataset_references[key_id]['data_cell']
374
+
375
+ # Replace the insert's raw substring
376
+ # for every formula in the new formula list
377
+ new_formula = \
378
+ [self.replace_insert(one_formula,
379
+ insert['raw'],
380
+ insert['reference'])
381
+ for one_formula in new_formula]
382
+
383
+ # Otherwise, raise an error
384
+ else:
385
+ raise ValueError('Insert list contains '
386
+ 'non-key or non-table elements')
387
+
388
+ # Otherwise, if there are only values among inserts...
389
+ elif all('key' in insert.get('pointers', {})
390
+ for insert in self.insert_list):
391
+
392
+ # Initialize a new formula list
393
+ new_formula = \
394
+ [self._formula for i in range(output_table_length)]
395
+
396
+ # Initialize a string formula to use in iterations
397
+ iterate_formula = self._formula
398
+
399
+ # For every insert...
400
+ for insert in self.insert_list:
401
+
402
+ # Get the key pointer
403
+ key_id = insert['pointers']['key']
404
+
405
+ # Get the value's reference string
406
+ insert['reference'] = \
407
+ self.dataset_references[key_id]['data_cell']
408
+
409
+ # Replace insert substring with value's reference
410
+ iterate_formula = \
411
+ self.replace_insert(iterate_formula,
412
+ insert['raw'],
413
+ insert['reference'])
414
+
415
+ # Set the new formula list to be iterate_formula for
416
+ # every entry in the output_table's column
417
+ new_formula = [iterate_formula
418
+ for row in range(output_table_length)]
419
+
420
+ # Otherwise, raise an exception
421
+ else:
422
+ raise ValueError(
423
+ 'Insert list contains non-key or non-table elements'
424
+ )
425
+
426
+ return new_formula
427
+
428
+ # Method to process value formula inserts
429
+ @error_logging
430
+ def process_value_formula_inserts(self):
431
+ """
432
+ process_value_formula_inserts
433
+
434
+ Parameters
435
+ ----------
436
+ None
437
+
438
+ Returns
439
+ -------
440
+ new_formula : str
441
+ New formula.
442
+
443
+ Raises
444
+ ------
445
+ ValueError
446
+ 'Formula missing necessary keys'
447
+ """
448
+
449
+ # Initialize a new formula
450
+ new_formula = self._formula
451
+
452
+ # For every insert...
453
+ for insert in self.insert_list:
454
+
455
+ # If the insert has a table and key pointer...
456
+ if 'table' in insert['pointers'] \
457
+ and 'key' in insert['pointers']:
458
+
459
+ # Get the insert's table and key pointers
460
+ table_id = insert['pointers']['table']
461
+ column_name = insert['pointers']['key']
462
+
463
+ # Get the table reference
464
+ table_ref = self.dataset_references[table_id]
465
+
466
+ # Get a range substring and save to insert['reference']
467
+ insert['reference'] = \
468
+ table_ref[column_name]['range']
469
+
470
+ # Replace pointer substring with range substring
471
+ new_formula = \
472
+ new_formula.replace(
473
+ insert['raw'],
474
+ insert['reference'])
475
+
476
+ # Otherwise, if insert has a key pointer...
477
+ elif 'key' in insert['pointers']:
478
+
479
+ # Get the key pointer
480
+ key_id = insert['pointers']['key']
481
+
482
+ # Get the value's reference string
483
+ insert['reference'] = \
484
+ self.dataset_references[key_id]['data_cell']
485
+
486
+ # Replace insert substring with value's reference
487
+ new_formula = \
488
+ self.replace_insert(new_formula,
489
+ insert['raw'],
490
+ insert['reference'])
491
+
492
+ # Otherwise, raise an error
493
+ else:
494
+ raise ValueError('Formula missing necessary keys')
495
+
496
+ return new_formula
497
+
498
+ """ STATIC METHODS """
499
+ # Method to replace formula raw insert with reference
500
+ @staticmethod
501
+ def replace_insert(formula, raw, reference):
502
+
503
+ # Replace pointer substring with value's reference
504
+ new_formula = \
505
+ formula.replace(raw, reference)
506
+
507
+ return new_formula