engforge 0.3.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.
- engforge/__init__.py +26 -0
- engforge/_testing_components.py +864 -0
- engforge/analysis.py +257 -0
- engforge/attr_dynamics.py +222 -0
- engforge/attr_plotting.py +811 -0
- engforge/attr_signals.py +116 -0
- engforge/attr_slots.py +211 -0
- engforge/attr_solver.py +443 -0
- engforge/attributes.py +326 -0
- engforge/common.py +76 -0
- engforge/component_collections.py +276 -0
- engforge/components.py +55 -0
- engforge/configuration.py +673 -0
- engforge/dataframe.py +185 -0
- engforge/datastores/__init__.py +116 -0
- engforge/datastores/data.py +519 -0
- engforge/datastores/gdocs.py +2650 -0
- engforge/datastores/reporting.py +935 -0
- engforge/datastores/secrets.py +549 -0
- engforge/dynamics.py +662 -0
- engforge/eng/__init__.py +0 -0
- engforge/eng/costs.py +1459 -0
- engforge/eng/fluid_material.py +279 -0
- engforge/eng/geometry.py +1060 -0
- engforge/eng/pipes.py +1211 -0
- engforge/eng/prediction.py +366 -0
- engforge/eng/solid_materials.py +445 -0
- engforge/eng/structure.py +2228 -0
- engforge/eng/structure_beams.py +821 -0
- engforge/eng/thermodynamics.py +271 -0
- engforge/engforge_attributes.py +380 -0
- engforge/env_var.py +214 -0
- engforge/locations.py +18 -0
- engforge/logging.py +290 -0
- engforge/patterns.py +449 -0
- engforge/problem_context.py +2251 -0
- engforge/properties.py +501 -0
- engforge/reporting.py +595 -0
- engforge/solveable.py +964 -0
- engforge/solver.py +316 -0
- engforge/solver_utils.py +726 -0
- engforge/system.py +143 -0
- engforge/system_reference.py +299 -0
- engforge/tabulation.py +288 -0
- engforge/test/__init__.py +2 -0
- engforge/test/_pre_test_structures.py +221 -0
- engforge/test/report_testing.py +158 -0
- engforge/test/test_airfilter.py +91 -0
- engforge/test/test_analysis.py +3 -0
- engforge/test/test_comp_iter.py +196 -0
- engforge/test/test_composition.py +139 -0
- engforge/test/test_costs.py +338 -0
- engforge/test/test_dynamics.py +109 -0
- engforge/test/test_dynamics_spaces.py +39 -0
- engforge/test/test_four_bar.py +97 -0
- engforge/test/test_modules.py +72 -0
- engforge/test/test_performance.py +93 -0
- engforge/test/test_pipes.py +49 -0
- engforge/test/test_problem.py +411 -0
- engforge/test/test_problem_deepscoping.py +68 -0
- engforge/test/test_slider_crank.py +51 -0
- engforge/test/test_solver.py +343 -0
- engforge/test/test_tabulation.py +233 -0
- engforge/typing.py +92 -0
- engforge-0.3.0.dist-info/METADATA +392 -0
- engforge-0.3.0.dist-info/RECORD +69 -0
- engforge-0.3.0.dist-info/WHEEL +5 -0
- engforge-0.3.0.dist-info/licenses/LICENSE +7 -0
- engforge-0.3.0.dist-info/top_level.txt +1 -0
engforge/reporting.py
ADDED
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
"""The set of reporters define an interface to report plots or tables"""
|
|
2
|
+
|
|
3
|
+
from engforge.configuration import Configuration, forge
|
|
4
|
+
from engforge.typing import Options
|
|
5
|
+
from engforge.logging import LoggingMixin
|
|
6
|
+
import attrs
|
|
7
|
+
import abc
|
|
8
|
+
|
|
9
|
+
import os, pathlib
|
|
10
|
+
import datetime
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def path_exist_validator(inst, attr, value):
|
|
14
|
+
if not isinstance(value, str):
|
|
15
|
+
raise ValueError(f"{attr.name} isnt a string")
|
|
16
|
+
if not os.path.exists(value):
|
|
17
|
+
raise FileExistsError(f"{value} does not exist")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# BASE CLASSSES (PLOT + TABLE)
|
|
21
|
+
@attrs.define
|
|
22
|
+
class Reporter(LoggingMixin):
|
|
23
|
+
"""A mixin intended"""
|
|
24
|
+
|
|
25
|
+
name: str = attrs.field(default="reporter")
|
|
26
|
+
|
|
27
|
+
def check_config(self):
|
|
28
|
+
"""a test to see if the reporter should be used"""
|
|
29
|
+
return True
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def subclasses(cls, out=None):
|
|
33
|
+
"""get all reporters of this type"""
|
|
34
|
+
if out is None:
|
|
35
|
+
out = set()
|
|
36
|
+
|
|
37
|
+
for scls in cls.__subclasses__():
|
|
38
|
+
out.add(scls)
|
|
39
|
+
scls.subclasses(scls)
|
|
40
|
+
|
|
41
|
+
def upload(self, analysis: "Analysis"):
|
|
42
|
+
self.info(f"uploading {analysis.identity} to {self.identity}")
|
|
43
|
+
raise NotImplemented()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Functionality Mixins
|
|
47
|
+
@attrs.define
|
|
48
|
+
class TemporalReporterMixin(Reporter):
|
|
49
|
+
"""Provide single or periodic keys"""
|
|
50
|
+
|
|
51
|
+
# report_mode: Options("single", "daily", "monthly") #choose wisely
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def report_root(self):
|
|
55
|
+
raise NotImplemented()
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def date_key(self):
|
|
59
|
+
d = datetime.datetime.utcnow().date()
|
|
60
|
+
return f"{d.year}.{d.month:02}.{d.day:02}"
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def month_key(self):
|
|
64
|
+
d = datetime.datetime.utcnow().date()
|
|
65
|
+
return f"{d.year}.{d.month:02}"
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def report_root(self):
|
|
69
|
+
"""define your keys!"""
|
|
70
|
+
raise NotImplemented()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@attrs.define
|
|
74
|
+
class DiskReporterMixin(TemporalReporterMixin):
|
|
75
|
+
path: str = attrs.field(default=None, validator=path_exist_validator)
|
|
76
|
+
|
|
77
|
+
# whats our /report/<key> gonna be
|
|
78
|
+
report_mode = Options("single", "daily", "monthly")
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def report_root(self):
|
|
82
|
+
if self.report_mode == "single":
|
|
83
|
+
return self.path
|
|
84
|
+
elif self.report_mode == "daily":
|
|
85
|
+
return os.path.join(self.path, self.date_key)
|
|
86
|
+
elif self.report_mode == "monthly":
|
|
87
|
+
return os.path.join(self.path, self.month_key)
|
|
88
|
+
|
|
89
|
+
raise ValueError(f"options failed!")
|
|
90
|
+
|
|
91
|
+
def ensure_exists(self):
|
|
92
|
+
if not os.path.exists(self.report_root):
|
|
93
|
+
pth = pathlib.Path(self.report_root)
|
|
94
|
+
pth.mkdir(parents=True, exist_ok=True)
|
|
95
|
+
|
|
96
|
+
def ensure_path(self, file_path, is_dir=False):
|
|
97
|
+
pth = pathlib.Path(file_path)
|
|
98
|
+
diri = pth if is_dir else pth.parent
|
|
99
|
+
if not diri.exists():
|
|
100
|
+
diri.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Basic Reporter Types
|
|
104
|
+
@attrs.define
|
|
105
|
+
class TableReporter(Reporter):
|
|
106
|
+
"""A reporter to upload dataframes to a table store"""
|
|
107
|
+
|
|
108
|
+
name: str = attrs.field(default="table_reporter")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@attrs.define
|
|
112
|
+
class PlotReporter(Reporter):
|
|
113
|
+
"""A reporter to upload plots to a file store"""
|
|
114
|
+
|
|
115
|
+
name: str = attrs.field(default="plot_reporter")
|
|
116
|
+
|
|
117
|
+
# FIXME: make attrs work... layout class conflict
|
|
118
|
+
# ext = Options('png','jpg','gif')
|
|
119
|
+
# ext: str = attrs.field(default='png')
|
|
120
|
+
ext = "png"
|
|
121
|
+
|
|
122
|
+
# def upload(self, analysis):
|
|
123
|
+
# for figkey, fig in analysis.stored_plots.items():
|
|
124
|
+
# try:
|
|
125
|
+
# filname = os.path.join(self.report_root, f"{figkey}.{self.ext}")
|
|
126
|
+
# self.ensure_path(filname)
|
|
127
|
+
# self.info(f"saving {figkey} to {filname}")
|
|
128
|
+
# fig.savefig(filname)
|
|
129
|
+
#
|
|
130
|
+
# except Exception as e:
|
|
131
|
+
# self.error(e, f"issue showing {figkey}")
|
|
132
|
+
def upload(self, analyis):
|
|
133
|
+
raise NotImplemented(f"plot reporter subclass needs an upload method")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# Table Reporters
|
|
137
|
+
@attrs.define
|
|
138
|
+
class CSVReporter(TableReporter, DiskReporterMixin):
|
|
139
|
+
name: str = attrs.field(default="CSV")
|
|
140
|
+
|
|
141
|
+
def upload(self, analysis: "Analysis"):
|
|
142
|
+
self.info(f"uploading {analysis.identity} to {self.identity}")
|
|
143
|
+
self.ensure_exists()
|
|
144
|
+
|
|
145
|
+
system = analysis.system
|
|
146
|
+
|
|
147
|
+
# Make System Dataframe
|
|
148
|
+
af = os.path.join(self.report_root, f"system_{system.name}.csv")
|
|
149
|
+
self.ensure_path(af)
|
|
150
|
+
self.info(f"saving system to: {af}")
|
|
151
|
+
system.dataframe.to_csv(af)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# # Make Analysis Dataframe
|
|
155
|
+
# af = os.path.join(self.report_root, f"analysis_{analysis.name}.csv")
|
|
156
|
+
# self.ensure_path(af)
|
|
157
|
+
# self.info(f"saving analysis to: {af}")
|
|
158
|
+
# analysis.dataframe.to_csv(af)
|
|
159
|
+
#
|
|
160
|
+
# for ckey, comp in system.comp_references().items():
|
|
161
|
+
# af = os.path.join(self.report_root, f"{ckey}_{comp.name}.csv")
|
|
162
|
+
# self.ensure_path(af)
|
|
163
|
+
# self.info(f"saving {ckey} to: {af}")
|
|
164
|
+
# comp.dataframe.to_csv(af)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@attrs.define
|
|
168
|
+
class ExcelReporter(TableReporter, DiskReporterMixin):
|
|
169
|
+
name: str = attrs.field(default="EXCEL")
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@attrs.define
|
|
173
|
+
class GsheetsReporter(TableReporter, TemporalReporterMixin):
|
|
174
|
+
name: str = attrs.field(default="GSHEETS")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# @attrs.define
|
|
178
|
+
# class SQLReporter(TableReporter):
|
|
179
|
+
# name: str = attrs.field(default="SQL")
|
|
180
|
+
#
|
|
181
|
+
#
|
|
182
|
+
# @attrs.define
|
|
183
|
+
# class ArangoReporter(TableReporter):
|
|
184
|
+
# name: str = attrs.field(default="SQL")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# PLOT Reporters
|
|
188
|
+
@attrs.define
|
|
189
|
+
class DiskPlotReporter(PlotReporter, DiskReporterMixin):
|
|
190
|
+
name: str = attrs.field(default="DrivePlots")
|
|
191
|
+
|
|
192
|
+
def upload(self, analysis):
|
|
193
|
+
for figkey, fig in analysis.stored_plots.items():
|
|
194
|
+
try:
|
|
195
|
+
filname = os.path.join(self.report_root, f"{figkey}.{self.ext}")
|
|
196
|
+
self.ensure_path(filname)
|
|
197
|
+
self.info(f"saving {figkey} to {filname}")
|
|
198
|
+
fig.savefig(filname)
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
self.error(e, f"issue showing {figkey}")
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@attrs.define
|
|
205
|
+
class GdriveReporter(PlotReporter, TemporalReporterMixin):
|
|
206
|
+
name: str = attrs.field(default="Gdrive")
|
|
207
|
+
share_drive: str = attrs.field(
|
|
208
|
+
default=None, validator=attrs.validators.instance_of(str)
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# TODO: move to analysis
|
|
213
|
+
# def split_dataframe_by_colmum(self,df,max_columns=10):
|
|
214
|
+
# df_cols = list(df.columns)
|
|
215
|
+
# if len(df_cols) < max_columns:
|
|
216
|
+
# return [df]
|
|
217
|
+
#
|
|
218
|
+
# col_chunks = list(chunks(df_cols,max_columns))
|
|
219
|
+
# dat_chunks = [df[colck].copy() for colck in col_chunks]
|
|
220
|
+
#
|
|
221
|
+
# return dat_chunks
|
|
222
|
+
|
|
223
|
+
# def cleanup_dataframe(self,df,badwords=('min','max')):
|
|
224
|
+
# tl_df = self.static_dataframe
|
|
225
|
+
# to_drop = [cl for cl in tl_df.columns if any([bw in cl.lower() for bw in badwords])]
|
|
226
|
+
# out_df = tl_df.drop(columns=to_drop)
|
|
227
|
+
# return out_df
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# @solver_cached
|
|
231
|
+
# def variable_dataframe(self):
|
|
232
|
+
# vals = list(zip(*list((self.variable_data_dict.values()))))
|
|
233
|
+
# cols = list((self.variable_data_dict.keys()))
|
|
234
|
+
# if vals:
|
|
235
|
+
# return pandas.DataFrame(data = vals, columns=cols, copy = True)
|
|
236
|
+
# else:
|
|
237
|
+
# return None
|
|
238
|
+
#
|
|
239
|
+
# @solver_cached
|
|
240
|
+
# def static_dataframe(self):
|
|
241
|
+
# vals = [list((self.static_data_dict.values()))]
|
|
242
|
+
# cols = list((self.static_data_dict.keys()))
|
|
243
|
+
# if vals:
|
|
244
|
+
# return pandas.DataFrame(data = vals, columns=cols, copy = True)
|
|
245
|
+
# else:
|
|
246
|
+
# return None
|
|
247
|
+
|
|
248
|
+
# Clearance Methods
|
|
249
|
+
# table property internal variables
|
|
250
|
+
# __store_options = ('csv','excel','gsheets')#,'db','gsheets','excel','json')
|
|
251
|
+
# _store_types = None
|
|
252
|
+
# _store_level:int = -1
|
|
253
|
+
|
|
254
|
+
# @property
|
|
255
|
+
# def table_iterator(self):
|
|
256
|
+
# '''Checks data to see what type of table it is, type 1 is a single row
|
|
257
|
+
# whereas type 2 & 3 have several rows, but type 2 has some values that are singular
|
|
258
|
+
#
|
|
259
|
+
# iterates table_type,values,label'''
|
|
260
|
+
#
|
|
261
|
+
# if not self.TABLE:
|
|
262
|
+
# return 0,[],[]
|
|
263
|
+
# if len(self.TABLE) <= 1:
|
|
264
|
+
# yield 1,self.TABLE[1],self.data_label
|
|
265
|
+
# else:
|
|
266
|
+
# #wide outerloop over vars
|
|
267
|
+
# for label in set.union(*[set(tuple(row.keys())) for i,row in self.TABLE.items()]):
|
|
268
|
+
# #inner loop over data
|
|
269
|
+
# col = [row[label] if label in row else None for inx,row in self.TABLE.items()]
|
|
270
|
+
#
|
|
271
|
+
# if all([isinstance(cvar,TABLE_TYPES) for cvar in col]): #do a type check
|
|
272
|
+
# if len(set(col)) <= 1: #All Values Are Similar
|
|
273
|
+
# yield 2, col[0], label #Can assume that first value is equal to all
|
|
274
|
+
# else:
|
|
275
|
+
# yield 3, col, label
|
|
276
|
+
#
|
|
277
|
+
# def recursive_data_structure(self,levels_to_descend = -1, parent_level=0):
|
|
278
|
+
# '''Returns the static and variable data from each configuration to grab defined by the
|
|
279
|
+
# recursive commands input in this function
|
|
280
|
+
#
|
|
281
|
+
# data is stored like: output[level]=[{static,variable},{static,variable},...]'''
|
|
282
|
+
#
|
|
283
|
+
# output = {}
|
|
284
|
+
#
|
|
285
|
+
# for level,conf in self.go_through_configurations(0,levels_to_descend,parent_level):
|
|
286
|
+
# if level in output:
|
|
287
|
+
# output[level].append({'static':conf.static_dataframe,\
|
|
288
|
+
# 'variable':conf.variable_dataframe,'conf':conf})
|
|
289
|
+
# else:
|
|
290
|
+
# output[level] = [{'static':conf.static_dataframe,\
|
|
291
|
+
# 'variable':conf.variable_dataframe,\
|
|
292
|
+
# 'conf':conf}]
|
|
293
|
+
#
|
|
294
|
+
# return output
|
|
295
|
+
|
|
296
|
+
# Multi-Component Table Combination Methods
|
|
297
|
+
# @solver_cached
|
|
298
|
+
# def static_data_dict(self):
|
|
299
|
+
# '''returns key-value pairs in table that are single valued, all in type 1, some in type 2'''
|
|
300
|
+
#
|
|
301
|
+
# output = {}
|
|
302
|
+
# for tab_type,value,label in self.table_iterator:
|
|
303
|
+
# if tab_type == 1:
|
|
304
|
+
# return {l:v for l,v in zip(label,value)}
|
|
305
|
+
# elif tab_type == 2:
|
|
306
|
+
# output[label] = value
|
|
307
|
+
# return output
|
|
308
|
+
#
|
|
309
|
+
# @solver_cached
|
|
310
|
+
# def variable_data_dict(self):
|
|
311
|
+
# '''returns a dictionary of key value pairs where values list is not the same all of type 3 and some of type 2'''
|
|
312
|
+
# output = {}
|
|
313
|
+
# for tab_type,value,label in self.table_iterator:
|
|
314
|
+
# if tab_type == 3:
|
|
315
|
+
# output[label] = value
|
|
316
|
+
# return output
|
|
317
|
+
#
|
|
318
|
+
#
|
|
319
|
+
# #Multi-Component Table Lookups
|
|
320
|
+
# @solver_cached
|
|
321
|
+
# def toplevel_static(self):
|
|
322
|
+
# out_df = self.cleanup_dataframe( self.static_dataframe )
|
|
323
|
+
# df_list = self.split_dataframe_by_colmum(out_df,self.max_col_width_static)
|
|
324
|
+
#
|
|
325
|
+
# return {'conf':self,'dfs': df_list }
|
|
326
|
+
#
|
|
327
|
+
# @solver_cached
|
|
328
|
+
# def other_static_tables(self):
|
|
329
|
+
# rds = self.recursive_data_structure(self.store_level)
|
|
330
|
+
# output = []
|
|
331
|
+
# for index, components in rds.items():
|
|
332
|
+
# if index > 0:
|
|
333
|
+
# for comp in components:
|
|
334
|
+
# if comp['static'] is not None:
|
|
335
|
+
# df_list = self.split_dataframe_by_colmum(comp['static'],self.max_col_width_static)
|
|
336
|
+
# output.append({'conf':comp['conf'],'dfs': df_list})
|
|
337
|
+
# return output
|
|
338
|
+
#
|
|
339
|
+
# @solver_cached
|
|
340
|
+
# def variable_tables(self):
|
|
341
|
+
# '''Grabs all valid variable dataframes and puts them in a list'''
|
|
342
|
+
# rds = self.recursive_data_structure(self.store_level)
|
|
343
|
+
#
|
|
344
|
+
# output = []
|
|
345
|
+
# for index, components in rds.items():
|
|
346
|
+
# for comp in components:
|
|
347
|
+
# if comp['variable'] is not None:
|
|
348
|
+
# output.append({'conf':comp['conf'],'df':comp['variable']})
|
|
349
|
+
#
|
|
350
|
+
# return output
|
|
351
|
+
#
|
|
352
|
+
# @solver_cached
|
|
353
|
+
# def joined_dataframe(self):
|
|
354
|
+
# '''this is a high level data frame with all data that changes in the system'''
|
|
355
|
+
# if self.variable_tables:
|
|
356
|
+
# return pandas.concat([ vt['df'] for vt in list(reversed(self.variable_tables))],axis=1)
|
|
357
|
+
# else:
|
|
358
|
+
# return None
|
|
359
|
+
#
|
|
360
|
+
# @property
|
|
361
|
+
# def complete_dataframe(self):
|
|
362
|
+
# '''this is a high level data frame with all data in the system'''
|
|
363
|
+
#
|
|
364
|
+
# rds = self.recursive_data_structure()
|
|
365
|
+
# if rds:
|
|
366
|
+
# dataframes = []
|
|
367
|
+
# stat_dataframes = []
|
|
368
|
+
# for lvl, comps in rds.items():
|
|
369
|
+
# for comp in comps:
|
|
370
|
+
# df = comp['conf'].dataframe
|
|
371
|
+
# if not comp['conf'] is self:
|
|
372
|
+
# nm = comp['conf'].name.lower()
|
|
373
|
+
# if nm == 'default':
|
|
374
|
+
# nm = comp['conf'].__class__.__name__.lower()
|
|
375
|
+
# nm = nm.replace(' ','_')
|
|
376
|
+
# strv=f'{nm}_'
|
|
377
|
+
# strv+='{}'
|
|
378
|
+
# else:
|
|
379
|
+
# nm = ''
|
|
380
|
+
# strv='{}'
|
|
381
|
+
# df.rename(strv.format, axis=1, inplace=True)
|
|
382
|
+
#
|
|
383
|
+
# dataframes.append(df)
|
|
384
|
+
# return pandas.concat(dataframes,join='outer',axis=1)
|
|
385
|
+
#
|
|
386
|
+
# else:
|
|
387
|
+
# return None
|
|
388
|
+
|
|
389
|
+
# Saving & Data Acces Methods
|
|
390
|
+
# def get_field_from_table(self,field,check_type=None,check_value:Callable = None):
|
|
391
|
+
# '''Converts Pandas To Numpy Array By Key, also handles poorly formated fields
|
|
392
|
+
# :param check_type: use a type or tuple of types to validate if the field is of type table
|
|
393
|
+
# :param check_value: use a function to check each value to ensure its valid for return, check type take priority'''
|
|
394
|
+
# if self.joined_dataframe is None:
|
|
395
|
+
# return numpy.array([])
|
|
396
|
+
# elif field in self.joined_dataframe:
|
|
397
|
+
# table = self.joined_dataframe[field]
|
|
398
|
+
# elif field.title() in self.joined_dataframe:
|
|
399
|
+
# table = self.joined_dataframe[field.title()]
|
|
400
|
+
# else:
|
|
401
|
+
# raise Exception('No Field Named {}'.format(field))
|
|
402
|
+
#
|
|
403
|
+
# #Remove Infinity
|
|
404
|
+
# table = table.replace([numpy.inf, -numpy.inf], numpy.nan)
|
|
405
|
+
#
|
|
406
|
+
# if check_type is not None:
|
|
407
|
+
# if all([isinstance(v,check_type) for v in table]):
|
|
408
|
+
# return table.to_numpy(copy=True)
|
|
409
|
+
# return None
|
|
410
|
+
# elif check_value is not None:
|
|
411
|
+
# if all([check_value(v) for v in table]):
|
|
412
|
+
# return table.to_numpy(copy=True)
|
|
413
|
+
# return None
|
|
414
|
+
#
|
|
415
|
+
# return table.to_numpy(dtype=float,copy=True)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
# Save functionality
|
|
419
|
+
# TODO: get me outta hur
|
|
420
|
+
# def save_table(self,dataframe=None,filename=None,meta_tags=None,*args,**kwargs):
|
|
421
|
+
# '''Header method to save the config in many different formats
|
|
422
|
+
# :param meta_tags: a dictionary with headers being column names, and the value as the item to fill that column'''
|
|
423
|
+
# if dataframe is None:
|
|
424
|
+
# dataframe = self.dataframe
|
|
425
|
+
#
|
|
426
|
+
# self.info('saving gsheets...')
|
|
427
|
+
#
|
|
428
|
+
# if meta_tags is not None and type(meta_tags) is dict:
|
|
429
|
+
# for tag,value in meta_tags.items():
|
|
430
|
+
# dataframe[tag] = value
|
|
431
|
+
#
|
|
432
|
+
#
|
|
433
|
+
# for save_format in self.store_types:
|
|
434
|
+
# try:
|
|
435
|
+
# if save_format == 'csv':
|
|
436
|
+
# self.save_csv(dataframe,filename,*args,**kwargs)
|
|
437
|
+
# elif save_format == 'excel':
|
|
438
|
+
# self.save_excel(dataframe,filename,*args,**kwargs)
|
|
439
|
+
# elif save_format == 'gsheets':
|
|
440
|
+
# self.save_gsheets(dataframe,filename,*args,**kwargs)
|
|
441
|
+
# except Exception as e:
|
|
442
|
+
# self.error(e,'Issue Saving Tables:')
|
|
443
|
+
|
|
444
|
+
# def save_csv(self,dataframe,filename=None,*args,**kwargs):
|
|
445
|
+
# if self.TABLE:
|
|
446
|
+
# if filename is None:
|
|
447
|
+
# filename = '{}.csv'.format(self.filename)
|
|
448
|
+
# if type(filename) is str and not filename.endswith('.csv'):
|
|
449
|
+
# filename += '.csv'
|
|
450
|
+
# filepath = os.path.join(self.config_path_daily,filename)
|
|
451
|
+
# dataframe.to_csv(path_or_buf=filepath,index=False,*args,**kwargs)
|
|
452
|
+
#
|
|
453
|
+
# def save_excel(self,dataframe,filename=None,*args,**kwargs):
|
|
454
|
+
# if self.TABLE:
|
|
455
|
+
# if filename is None:
|
|
456
|
+
# filename = '{}.xlsx'.format(self.filename)
|
|
457
|
+
# if type(filename) is str and not filename.endswith('.xlsx'):
|
|
458
|
+
# filename += '.xlsx'
|
|
459
|
+
# filepath = os.path.join(self.config_path_daily,filename)
|
|
460
|
+
# dataframe.to_excel(path_or_buf=filepath,*args,**kwargs)
|
|
461
|
+
|
|
462
|
+
# @property
|
|
463
|
+
# def store_level(self):
|
|
464
|
+
# return self._store_level
|
|
465
|
+
#
|
|
466
|
+
# @store_level.setter
|
|
467
|
+
# def store_level(self,new_level:int):
|
|
468
|
+
# assert isinstance(new_level,(int))
|
|
469
|
+
# self._store_level = new_level
|
|
470
|
+
#
|
|
471
|
+
# @property
|
|
472
|
+
# def store_types(self):
|
|
473
|
+
# if self._store_types is None:
|
|
474
|
+
# self._store_types = [] #initalization
|
|
475
|
+
# return self._store_types
|
|
476
|
+
|
|
477
|
+
# @store_types.setter
|
|
478
|
+
# def store_types(self, new_type_or_list):
|
|
479
|
+
# '''If you add a list or iterable, and each value is a valid output option we will assign it
|
|
480
|
+
# otherwise if its a value in the valid options it will be added.
|
|
481
|
+
# '''
|
|
482
|
+
# if isinstance(new_type_or_list,(list,tuple)):
|
|
483
|
+
# assert all([val in self.__store_options for val in new_type_or_list])
|
|
484
|
+
# self._store_types = list(new_type_or_list)
|
|
485
|
+
#
|
|
486
|
+
# elif new_type_or_list in self.__store_options:
|
|
487
|
+
# self._store_types.append(new_type_or_list)
|
|
488
|
+
#
|
|
489
|
+
# else:
|
|
490
|
+
# self.warning('store types input not valid {}'.format(new_type_or_list))
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
# def save_to_worksheet(self,worksheet:'pygsheets.Worksheet'):
|
|
494
|
+
# '''Saves to a gsheets via pygsheets adds static and regular data'''
|
|
495
|
+
#
|
|
496
|
+
# title = self.identity.replace('_',' ').title()
|
|
497
|
+
#
|
|
498
|
+
# self.info('saving worksheet as {}'.format(title))
|
|
499
|
+
# wksh = worksheet
|
|
500
|
+
#
|
|
501
|
+
# wksh.clear()
|
|
502
|
+
#
|
|
503
|
+
# #Static data
|
|
504
|
+
# start = pygsheets.Address((2,2))
|
|
505
|
+
#
|
|
506
|
+
# tld = self.toplevel_static
|
|
507
|
+
# sdf = tld['dfs']
|
|
508
|
+
#
|
|
509
|
+
# cur_index = start + (1,0)
|
|
510
|
+
# for i,df in enumerate(sdf):
|
|
511
|
+
# self.debug('saving dataframe {}'.format(df))
|
|
512
|
+
# wksh.update_value(start.label,self.identity)
|
|
513
|
+
# wksh.cell(start.label).set_text_format('bold',True)
|
|
514
|
+
# wksh.set_dataframe(df,cur_index.label , extend=True)
|
|
515
|
+
# cur_index += (2,0)
|
|
516
|
+
#
|
|
517
|
+
# cur_index += (3,0)
|
|
518
|
+
#
|
|
519
|
+
# var_index = pygsheets.Address(cur_index.label)
|
|
520
|
+
#
|
|
521
|
+
# max_row = 0
|
|
522
|
+
#
|
|
523
|
+
# vrt = self.variable_tables
|
|
524
|
+
# self.info('saving {} other static tables'.format(len(vrt)))
|
|
525
|
+
#
|
|
526
|
+
# for dfpack in vrt:
|
|
527
|
+
# conf = dfpack['conf']
|
|
528
|
+
# df = dfpack['df']
|
|
529
|
+
# self.debug('saving dataframe {}'.format(df))
|
|
530
|
+
#
|
|
531
|
+
# (num_rows,num_cols) = df.shape
|
|
532
|
+
# max_row = max(max_row,num_rows)
|
|
533
|
+
#
|
|
534
|
+
# wksh.update_value((var_index-(1,0)).label,conf.classname)
|
|
535
|
+
# wksh.cell((var_index-(1,0)).label).set_text_format('bold',True)
|
|
536
|
+
#
|
|
537
|
+
# wksh.set_dataframe(df,start=var_index.label,extend=True)
|
|
538
|
+
#
|
|
539
|
+
# var_index += (0,num_cols)
|
|
540
|
+
#
|
|
541
|
+
# cur_index += (3+max_row,0)
|
|
542
|
+
#
|
|
543
|
+
# ost = self.other_static_tables
|
|
544
|
+
#
|
|
545
|
+
# self.info('saving {} other static tables'.format(len(ost)))
|
|
546
|
+
#
|
|
547
|
+
# for dfpack in ost:
|
|
548
|
+
# conf = dfpack['conf']
|
|
549
|
+
# sdf = dfpack['dfs']
|
|
550
|
+
#
|
|
551
|
+
# wksh.update_value((cur_index-(1,0)).label,conf.identity)
|
|
552
|
+
# wksh.cell((cur_index-(1,0)).label).set_text_format('bold',True)
|
|
553
|
+
#
|
|
554
|
+
# for i,df in enumerate(sdf):
|
|
555
|
+
#
|
|
556
|
+
# self.debug('saving {} dataframe {}'.format(conf.identity, df))
|
|
557
|
+
# wksh.set_dataframe(df,start=cur_index.label ,extend=True)
|
|
558
|
+
# cur_index += (2,0)
|
|
559
|
+
#
|
|
560
|
+
# cur_index += (3,0)
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
# def save_gsheets(self,dataframe,filename=None,index=False,*args,**kwargs):
|
|
564
|
+
# '''A function to save the table to google sheets
|
|
565
|
+
# :param filename: the filepath on google drive - be careful!
|
|
566
|
+
# '''
|
|
567
|
+
# with self.drive.context(filepath_root=self.local_sync_path, sync_root=self.cloud_sync_path) as gdrive:
|
|
568
|
+
# with gdrive.rate_limit_manager( self.save_gsheets,6,dataframe,filename=filename,*args,**kwargs) as tdrive:
|
|
569
|
+
#
|
|
570
|
+
# old_sleep = tdrive._sleep_time
|
|
571
|
+
# tdrive.reset_sleep_time( max(old_sleep,2.5) )
|
|
572
|
+
#
|
|
573
|
+
# gpath = tdrive.sync_path(self.local_sync_path)
|
|
574
|
+
# self.info(f'saving as gsheets in dir {self.local_sync_path} -> {gpath}')
|
|
575
|
+
# parent_id = gdrive.get_gpath_id(gpath)
|
|
576
|
+
# #TODO: delete old file if exists
|
|
577
|
+
# tdrive.sleep(2*(1+tdrive.time_fuzz*random.random()))
|
|
578
|
+
# if tdrive and tdrive.gsheets:
|
|
579
|
+
# sht = tdrive.gsheets.create(filename,folder=parent_id)
|
|
580
|
+
#
|
|
581
|
+
# tdrive.sleep(2*(1+tdrive.time_fuzz*random.random()))
|
|
582
|
+
# tdrive.cache_directory(parent_id)
|
|
583
|
+
#
|
|
584
|
+
# wk = sht.sheet1
|
|
585
|
+
#
|
|
586
|
+
# wk.rows = dataframe.shape[0]
|
|
587
|
+
# gdrive.sleep(2*(1+tdrive.time_fuzz*random.random()))
|
|
588
|
+
#
|
|
589
|
+
# wk.set_dataframe(dataframe,start='A1',fit=True)
|
|
590
|
+
# gdrive.sleep(2*(1+tdrive.time_fuzz*random.random()))
|
|
591
|
+
#
|
|
592
|
+
# #TODO: add in dataframe dict with schema sheename: {dataframe,**other_args}
|
|
593
|
+
# self.info('gsheet saved -> {}'.format(os.path.join(gpath,filename)))
|
|
594
|
+
#
|
|
595
|
+
# tdrive.reset_sleep_time( old_sleep )
|