engforge 0.3.0__tar.gz

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 (75) hide show
  1. engforge-0.3.0/LICENSE +7 -0
  2. engforge-0.3.0/PKG-INFO +392 -0
  3. engforge-0.3.0/README.md +316 -0
  4. engforge-0.3.0/engforge/__init__.py +26 -0
  5. engforge-0.3.0/engforge/_testing_components.py +864 -0
  6. engforge-0.3.0/engforge/analysis.py +257 -0
  7. engforge-0.3.0/engforge/attr_dynamics.py +222 -0
  8. engforge-0.3.0/engforge/attr_plotting.py +811 -0
  9. engforge-0.3.0/engforge/attr_signals.py +116 -0
  10. engforge-0.3.0/engforge/attr_slots.py +211 -0
  11. engforge-0.3.0/engforge/attr_solver.py +443 -0
  12. engforge-0.3.0/engforge/attributes.py +326 -0
  13. engforge-0.3.0/engforge/common.py +76 -0
  14. engforge-0.3.0/engforge/component_collections.py +276 -0
  15. engforge-0.3.0/engforge/components.py +55 -0
  16. engforge-0.3.0/engforge/configuration.py +673 -0
  17. engforge-0.3.0/engforge/dataframe.py +185 -0
  18. engforge-0.3.0/engforge/datastores/__init__.py +116 -0
  19. engforge-0.3.0/engforge/datastores/data.py +519 -0
  20. engforge-0.3.0/engforge/datastores/gdocs.py +2650 -0
  21. engforge-0.3.0/engforge/datastores/reporting.py +935 -0
  22. engforge-0.3.0/engforge/datastores/secrets.py +549 -0
  23. engforge-0.3.0/engforge/dynamics.py +662 -0
  24. engforge-0.3.0/engforge/eng/__init__.py +0 -0
  25. engforge-0.3.0/engforge/eng/costs.py +1459 -0
  26. engforge-0.3.0/engforge/eng/fluid_material.py +279 -0
  27. engforge-0.3.0/engforge/eng/geometry.py +1060 -0
  28. engforge-0.3.0/engforge/eng/pipes.py +1211 -0
  29. engforge-0.3.0/engforge/eng/prediction.py +366 -0
  30. engforge-0.3.0/engforge/eng/solid_materials.py +445 -0
  31. engforge-0.3.0/engforge/eng/structure.py +2228 -0
  32. engforge-0.3.0/engforge/eng/structure_beams.py +821 -0
  33. engforge-0.3.0/engforge/eng/thermodynamics.py +271 -0
  34. engforge-0.3.0/engforge/engforge_attributes.py +380 -0
  35. engforge-0.3.0/engforge/env_var.py +214 -0
  36. engforge-0.3.0/engforge/locations.py +18 -0
  37. engforge-0.3.0/engforge/logging.py +290 -0
  38. engforge-0.3.0/engforge/patterns.py +449 -0
  39. engforge-0.3.0/engforge/problem_context.py +2251 -0
  40. engforge-0.3.0/engforge/properties.py +501 -0
  41. engforge-0.3.0/engforge/reporting.py +595 -0
  42. engforge-0.3.0/engforge/solveable.py +964 -0
  43. engforge-0.3.0/engforge/solver.py +316 -0
  44. engforge-0.3.0/engforge/solver_utils.py +726 -0
  45. engforge-0.3.0/engforge/system.py +143 -0
  46. engforge-0.3.0/engforge/system_reference.py +299 -0
  47. engforge-0.3.0/engforge/tabulation.py +288 -0
  48. engforge-0.3.0/engforge/test/__init__.py +2 -0
  49. engforge-0.3.0/engforge/test/_pre_test_structures.py +221 -0
  50. engforge-0.3.0/engforge/test/report_testing.py +158 -0
  51. engforge-0.3.0/engforge/test/test_airfilter.py +91 -0
  52. engforge-0.3.0/engforge/test/test_analysis.py +3 -0
  53. engforge-0.3.0/engforge/test/test_comp_iter.py +196 -0
  54. engforge-0.3.0/engforge/test/test_composition.py +139 -0
  55. engforge-0.3.0/engforge/test/test_costs.py +338 -0
  56. engforge-0.3.0/engforge/test/test_dynamics.py +109 -0
  57. engforge-0.3.0/engforge/test/test_dynamics_spaces.py +39 -0
  58. engforge-0.3.0/engforge/test/test_four_bar.py +97 -0
  59. engforge-0.3.0/engforge/test/test_modules.py +72 -0
  60. engforge-0.3.0/engforge/test/test_performance.py +93 -0
  61. engforge-0.3.0/engforge/test/test_pipes.py +49 -0
  62. engforge-0.3.0/engforge/test/test_problem.py +411 -0
  63. engforge-0.3.0/engforge/test/test_problem_deepscoping.py +68 -0
  64. engforge-0.3.0/engforge/test/test_slider_crank.py +51 -0
  65. engforge-0.3.0/engforge/test/test_solver.py +343 -0
  66. engforge-0.3.0/engforge/test/test_tabulation.py +233 -0
  67. engforge-0.3.0/engforge/typing.py +92 -0
  68. engforge-0.3.0/engforge.egg-info/PKG-INFO +392 -0
  69. engforge-0.3.0/engforge.egg-info/SOURCES.txt +74 -0
  70. engforge-0.3.0/engforge.egg-info/dependency_links.txt +1 -0
  71. engforge-0.3.0/engforge.egg-info/not-zip-safe +1 -0
  72. engforge-0.3.0/engforge.egg-info/requires.txt +65 -0
  73. engforge-0.3.0/engforge.egg-info/top_level.txt +1 -0
  74. engforge-0.3.0/pyproject.toml +123 -0
  75. engforge-0.3.0/setup.cfg +9 -0
engforge-0.3.0/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright 2023 Ottermatics LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,392 @@
1
+ Metadata-Version: 2.4
2
+ Name: engforge
3
+ Version: 0.3.0
4
+ Summary: The Engineer's Framework
5
+ Author-email: Kevin Russell <olly@ottermatics.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Ottermatics/engforge
8
+ Project-URL: Repository, https://github.com/Ottermatics/engforge
9
+ Project-URL: Documentation, https://ottermatics.github.io/engforge/
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: attrs~=23.2.0
20
+ Requires-Dist: arrow
21
+ Requires-Dist: deepdiff>=6.3.1
22
+ Requires-Dist: numpy==1.24.3
23
+ Requires-Dist: scipy
24
+ Requires-Dist: matplotlib~=3.8.1
25
+ Requires-Dist: jupyter
26
+ Requires-Dist: pandas
27
+ Requires-Dist: scikit-learn~=1.3.2
28
+ Requires-Dist: seaborn
29
+ Requires-Dist: tabulate
30
+ Requires-Dist: networkx-query==1.0.1
31
+ Requires-Dist: networkx>=2.5.1
32
+ Requires-Dist: black~=24.8.0
33
+ Requires-Dist: randomname~=0.2.1
34
+ Requires-Dist: termcolor
35
+ Requires-Dist: pyee
36
+ Requires-Dist: methodtools~=0.4.7
37
+ Requires-Dist: tomli>=1.2.0; python_version < "3.11"
38
+ Provides-Extra: dev
39
+ Requires-Dist: wheel; extra == "dev"
40
+ Requires-Dist: jinja2>=2.11.3; extra == "dev"
41
+ Requires-Dist: sphinx>=3.2.1; extra == "dev"
42
+ Requires-Dist: recommonmark>=0.6.0; extra == "dev"
43
+ Requires-Dist: sphinx-rtd-theme>=1.0.0; extra == "dev"
44
+ Provides-Extra: eng
45
+ Requires-Dist: control; extra == "eng"
46
+ Requires-Dist: fluids; extra == "eng"
47
+ Requires-Dist: CoolProp; extra == "eng"
48
+ Requires-Dist: sectionproperties~=3.1.2; extra == "eng"
49
+ Requires-Dist: PyniteFEA>=1.2.0; extra == "eng"
50
+ Provides-Extra: database
51
+ Requires-Dist: SQLAlchemy~=1.3.17; extra == "database"
52
+ Requires-Dist: SQLAlchemy-Utils; extra == "database"
53
+ Requires-Dist: psycopg2-binary; extra == "database"
54
+ Requires-Dist: diskcache>=5.6.1; extra == "database"
55
+ Requires-Dist: sqlalchemy-batch-inserts; extra == "database"
56
+ Provides-Extra: google
57
+ Requires-Dist: expiringdict~=1.2.2; extra == "google"
58
+ Requires-Dist: pygsheets==2.0.4; extra == "google"
59
+ Requires-Dist: pydrive2==1.8.1; extra == "google"
60
+ Provides-Extra: cloud
61
+ Requires-Dist: boto3; extra == "cloud"
62
+ Provides-Extra: distributed
63
+ Requires-Dist: ray[default]~=2.35.0; extra == "distributed"
64
+ Requires-Dist: ray[tune]~=2.35.0; extra == "distributed"
65
+ Provides-Extra: docs
66
+ Requires-Dist: sphinx>=7.0.0; extra == "docs"
67
+ Requires-Dist: sphinx-rtd-theme; extra == "docs"
68
+ Requires-Dist: pydata-sphinx-theme; extra == "docs"
69
+ Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
70
+ Requires-Dist: myst-parser; extra == "docs"
71
+ Requires-Dist: sphinx_autodoc_typehints; extra == "docs"
72
+ Requires-Dist: toml~=0.10.2; extra == "docs"
73
+ Provides-Extra: all
74
+ Requires-Dist: engforge[cloud,database,dev,distributed,docs,eng,google]; extra == "all"
75
+ Dynamic: license-file
76
+
77
+ [![build](https://github.com/Ottermatics/engforge/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/Ottermatics/engforge/actions/workflows/build.yml)
78
+ [![docs](https://github.com/Ottermatics/engforge/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/Ottermatics/engforge/actions/workflows/docs.yml)
79
+ # EngForge
80
+ A library to tabulate information from complex systems with various ways to store data and act as glue code for complex systems & engineering problems.
81
+
82
+ ### Installation
83
+ ```bash
84
+ pip install git+https://github.com/Ottermatics/engforge.git
85
+ ```
86
+
87
+ ### Core Functions
88
+ 1. Tabulation Of Complex Systems
89
+ 2. Modular Post Processing (dataframes)
90
+ 3. Exploratory Analysis (ipython + functions / docs)
91
+ 4. Workflows for core engineering problemes (structures + cost, thermal+fluids solve)
92
+
93
+ ### MVP Features (WIP)
94
+ 1. Tabulation, use `attrs.field` and `system_property` to capture `y=f(x)` where `fields` are the state from which `system_property` derives results [Done]
95
+ 2. Dynamic Programing ensures work is only done when new data is available with `cached_system_property`. [Done]
96
+ 3. Quick Calculation provided by direct cached references to attribues and properties [Done]
97
+ 4. Solver based on `NPSS` strategy of balances and integrators [Done]
98
+ 5. Reporting to google sheets, csv and excel.
99
+
100
+ ### Systems & Analysis
101
+ Systems record data from components, and can execute a solver via the `run(**parameter_iterables)` command. Via a system's run command its state and internal component's & systems state can be altered in an outer product fashion, ie all combinations of inputs will be run. At the start of a run the systems & its components state is recorded and reset by default using `Ref` instances so that way multiple systems can use the same component. Its possible reference loops may occcur so its generally preferred to create components per system, however for coupled systems this is often desireable to converge on a solution.
102
+
103
+ By default the system calls a `default_solver()` method in its `execute()` function. A solver aims to drive its dependent parameter to zero by changing the independent parameters to zero, however it may adjust multiple parameters to meet multiple targets in more complex applications. For custom System behavior or to invoke custom solvers this method may be overriden.
104
+
105
+ To use the default solver & constraints
106
+ ```python
107
+ @forge
108
+ SolverSystem(System):
109
+ sol2 = Solver.define("dep", "indep")
110
+ sol2.add_constraint("max", limit_max) #indep should never go above this value (or function)
111
+ sol2.add_constraint("min", 0) #indep should never go below zero
112
+ ```
113
+
114
+ `Analysis` is a pluggable way to provide different output and calculation from the same system and interacts with plot and table reporters.
115
+
116
+ ### Components, Signals & Slots
117
+ Component are able to be mounted into multiple Systems via `SLOTS.define( ComponentType )`. A Component's properties can be updated via `SIGNALS` in the Systems's solver in the `pre_execute` and/or the `post_execute` functions via `SIGNAL.define(target, source, mode)` where mode can be `pre`,`post` or `both` to update before the `System.execute()` method.
118
+
119
+ Iterable Components may be defined on a System via `SLOT.define_iterable( <ComponentIter>, wide=True/False)` to choose how the system should iterate over the component, `wide` mode provides all the component `attributes` and `properties` in the same row whereas the `narrow` mode will iterate over each combination of component as though it was input into `system.run()`
120
+
121
+ ### Example Engineering Problems:
122
+ These problems demonstrate functionality
123
+
124
+ #### Air Filter
125
+ run a throttle sweep with filter loss characteristic and fan afinity law based pressure based off of a design point.
126
+ ```python
127
+ from engforge.analysis import Analysis
128
+ from engforge.reporting import CSVReporter,DiskPlotReporter
129
+ from engforge.properties import system_property
130
+ from engforge import *
131
+ import numpy as np
132
+ import os,pathlib
133
+ import attrs
134
+
135
+ @forge
136
+ class Fan(Component):
137
+
138
+ n_frac:float = field(default=1)
139
+ dp_design:float= field(default=100)
140
+ w_design:float = field(default=2)
141
+
142
+
143
+ @system_property
144
+ def dP_fan(self) -> float:
145
+ return self.dp_design*(self.n_frac*self.w_design)**2.0
146
+
147
+ @forge
148
+ class Filter(Component):
149
+
150
+ w:float = field(default=0)
151
+ k_loss:float = field(default=50)
152
+
153
+ @system_property
154
+ def dP_filter(self) -> float:
155
+ return self.k_loss*self.w
156
+
157
+ @forge
158
+ class Airfilter(System):
159
+
160
+ throttle:float = field(default=1)
161
+ w:float = field(default=1)
162
+ k_parasitic:float = field(default=0.1)
163
+
164
+ fan: Fan = Slot.define(Fan)
165
+ filt: Filter = Slot.define(Filter)
166
+
167
+ set_fan_n = Signal.define('fan.n_frac','throttle',mode='both')
168
+ set_filter_w = Signal.define('filt.w','w',mode='both')
169
+
170
+ flow_var = Solver.declare_var('w',combos='flow')
171
+ flow_var.add_var_constraint(0,'min',combos='flow')
172
+
173
+ pr_eq = Solver.constraint_equality('sum_dP',0,combos='flow')
174
+
175
+
176
+ flow_curve = Plot.define(
177
+ "throttle", "w", kind="lineplot", title="Flow Curve"
178
+ )
179
+
180
+ @system_property
181
+ def dP_parasitic(self) -> float:
182
+ return self.k_parasitic * self.w**2.0
183
+
184
+ @system_property
185
+ def sum_dP(self) -> float:
186
+ return self.fan.dP_fan - self.dP_parasitic - self.filt.dP_filter
187
+
188
+
189
+ #Run the system
190
+ from matplotlib.pylab import *
191
+
192
+
193
+
194
+ fan = Fan()
195
+ filt = Filter()
196
+ af = Airfilter(fan=fan,filt=filt)
197
+
198
+ change_all_log_levels(af,20) #info
199
+
200
+ af.run(throttle=list(np.arange(0.1,1.1,0.1)),combos='*')
201
+
202
+ df = af.dataframe
203
+
204
+ fig,(ax,ax2) = subplots(2,1)
205
+ ax.plot(df.throttle*100,df.w,'k--',label='flow')
206
+ ax2.plot(df.throttle*100,df.filt_dp_filter,label='filter')
207
+ ax2.plot(df.throttle*100,df.dp_parasitic,label='parasitic')
208
+ ax2.plot(df.throttle*100,df.fan_dp_fan,label='fan')
209
+ ax.legend(loc='upper right')
210
+ ax.set_title('flow')
211
+ ax.grid()
212
+ ax2.legend()
213
+ ax2.grid()
214
+ ax2.set_title(f'pressure')
215
+ ax2.set_xlabel(f'throttle%')
216
+ ```
217
+
218
+ ##### Results
219
+ ![air_filter_calc.png](media/air_filter_calc.png)
220
+
221
+
222
+ #### Spring Mass Damper
223
+ ##### Overview
224
+ Test case results in accurate resonance frequency calculation
225
+ ```python
226
+
227
+ @forge
228
+ class SpringMass(System):
229
+
230
+ k: float = attrs.field(default=50)
231
+ m: float = attrs.field(default=1)
232
+ g: float = attrs.field(default=9.81)
233
+ u: float = attrs.field(default=0.3)
234
+
235
+ a: float = attrs.field(default=0)
236
+ x: float = attrs.field(default=0.0)
237
+ v: float = attrs.field(default=0.0)
238
+
239
+ wo_f: float = attrs.field(default=1.0)
240
+ Fa: float = attrs.field(default=10.0)
241
+
242
+ x_neutral: float = attrs.field(default=0.5)
243
+
244
+ res =Solver.constraint_equality("sumF")
245
+ var_a = Solver.declare_var("a",combos='a',active=False)
246
+ var_b = Solver.declare_var("u",combos='u',active=False)
247
+ var_b.add_var_constraint(0.0,kind="min")
248
+ var_b.add_var_constraint(1.0,kind="max")
249
+
250
+ vtx = Time.integrate("v", "accl")
251
+ xtx = Time.integrate("x", "v")
252
+ xtx.add_var_constraint(0,kind="min")
253
+
254
+ #FIXME: implement trace testing
255
+ #pos = Trace.define(y="x", y2=["v", "a"])
256
+
257
+ @system_property
258
+ def dx(self) -> float:
259
+ return self.x_neutral - self.x
260
+
261
+ @system_property
262
+ def Fspring(self) -> float:
263
+ return self.k * self.dx
264
+
265
+ @system_property
266
+ def Fgrav(self) -> float:
267
+ return self.g * self.m
268
+
269
+ @system_property
270
+ def Faccel(self) -> float:
271
+ return self.a * self.m
272
+
273
+ @system_property
274
+ def Ffric(self) -> float:
275
+ return self.u * self.v
276
+
277
+ @system_property
278
+ def sumF(self) -> float:
279
+ return self.Fspring - self.Fgrav - self.Faccel - self.Ffric + self.Fext
280
+
281
+ @system_property
282
+ def Fext(self) -> float:
283
+ return self.Fa * np.cos( self.time * self.wo_f )
284
+
285
+ @system_property
286
+ def accl(self) -> float:
287
+ return self.sumF / self.m
288
+
289
+
290
+ #Run The System, Compare damping `u`=0 & 0.1
291
+ sm = SpringMass(x=0.0)
292
+ sm.sim(dt=0.01,endtime=10,u=[0.0,0.1],combos='*',slv_vars='*')
293
+
294
+ df = sm.dataframe
295
+ df.groupby('run_id').plot('time','x')
296
+ ```
297
+
298
+ ##### Results Damping Off
299
+ ![olib_spring_mass_clac.png](media/olib_spring_mass_clac.png)
300
+
301
+ ##### Results - Damping On
302
+ <img src="media/olib_spring_mass_clac_damp 1.png" />
303
+
304
+
305
+ ## Reporting & Analysis
306
+ `Analysis` is capable of tabulation as a `Component` or `System` and wraps a top level `System` and will save data for each system interval. `Analysis` stores several reporters for tables and plots that may be used to store results in multiple locations.
307
+
308
+ Reporting is supported for tables via dataframes in CSV,Excel and Gsheets (WIP).
309
+
310
+ For plots reporting is supported in disk storage.
311
+
312
+ ```python
313
+
314
+ from engforge.analysis import Analysis
315
+ from engforge.reporting import CSVReporter,DiskPlotReporter
316
+ from engforge.properties import system_property
317
+ import numpy as np
318
+ import os,pathlib
319
+
320
+ this_dir = str(pathlib.Path(__file__).parent)
321
+ this_dir = os.path.join(this_dir,'airfilter_report')
322
+ if not os.path.exists(this_dir):
323
+ os.path.mkdir(this_dir)
324
+
325
+ csv = CSVReporter(path=this_dir,report_mode='daily')
326
+ csv_latest = CSVReporter(path=this_dir,report_mode='single')
327
+
328
+ plots = DiskPlotReporter(path=this_dir,report_mode='monthly')
329
+ plots_latest = DiskPlotReporter(path=this_dir,report_mode='single')
330
+
331
+
332
+ @forge
333
+ class AirfilterAnalysis(Analysis):
334
+ """Does post processing on a system"""
335
+
336
+ efficiency = attrs.field(defualt=0.95)
337
+
338
+ @system_property
339
+ def clean_air_delivery_rate(self) -> float:
340
+ return self.system.w*self.efficiency
341
+
342
+ def post_process(self,*run_args,**run_kwargs):
343
+ pass
344
+ #TODO: something custom!
345
+
346
+ #Air Filter as before
347
+ fan = Fan()
348
+ filt = Filter()
349
+ af = Airfilter(fan=fan,filt=filt)
350
+
351
+ #Make The Analysis
352
+ sa = AirfilterAnalysis(
353
+ system = af,
354
+ table_reporters = [csv,csv_latest],
355
+ plot_reporters = [plots,plots_latest]
356
+ )
357
+
358
+ #Run the analysis! Input passed to system
359
+ sa.run(throttle=list(np.arange(0.1,1.1,0.1)),combos='*')
360
+
361
+
362
+ #CSV's & Plots available in ./airfilter_report!
363
+ ```
364
+
365
+
366
+
367
+
368
+ ## Documentation:
369
+ https://ottermatics.github.io/engforge/
370
+
371
+ ### DataStores
372
+ Datastores are a work in progress feature to provide a zero configuration library for storage of tabulated data and report generated artifacts. No garuntee is provided as to their stability yet.
373
+ Requirements for datasources are attempted upon access of `engforge.datastores` and entering of a `CONFIRM` prompt.
374
+
375
+ ### Environmental Variables
376
+ To allow a write-once implement anywhere interface `EnvVariable` is provided for both open (the default) and secret variables. Allowance for type conversion, and defaults are provided.
377
+
378
+ The current variable slots in memory are listed by `EnvVariable.print_env_vars()`
379
+ ```bash
380
+ FORGE_DB_HOST |SECRETS[FORGE_DB_HOST] = localhost
381
+ FORGE_DB_NAME |SECRETS[FORGE_DB_NAME] =
382
+ FORGE_DB_PASS |SECRETS[FORGE_DB_PASS] = postgres
383
+ FORGE_DB_PORT |SECRETS[FORGE_DB_PORT] = 5432
384
+ FORGE_DB_USER |SECRETS[FORGE_DB_USER] = postgres
385
+ FORGE_HOSTNAME |SECRETS[FORGE_HOSTNAME] = <your-machine>
386
+ FORGE_REPORT_PATH |SECRETS[FORGE_REPORT_PATH] =
387
+ FORGE_SLACK_LOG_WEBHOOK |SECRETS[FORGE_SLACK_LOG_WEBHOOK] =
388
+ SEABORN_CONTEXT |SECRETS[SEABORN_CONTEXT] = paper
389
+ SEABORN_PALETTE |SECRETS[SEABORN_PALETTE] = deep
390
+ SEABORN_THEME |SECRETS[SEABORN_THEME] = darkgrid
391
+ ```
392
+