owlplanner 2025.5.5__tar.gz → 2025.5.15__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.
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/.devcontainer/devcontainer.json +1 -1
- owlplanner-2025.5.15/.streamlit/fullconfig.toml +330 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/PKG-INFO +10 -5
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/README.md +6 -4
- owlplanner-2025.5.15/docker/Dockerfile.build +24 -0
- owlplanner-2025.5.5/docker/Dockerfile → owlplanner-2025.5.15/docker/Dockerfile.run +6 -5
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docker/README.md +5 -1
- owlplanner-2025.5.15/docker/buildentrypoint.sh +12 -0
- owlplanner-2025.5.15/docker/runentrypoint.sh +17 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/notebooks/john+sally.ipynb +13 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/notebooks/kim+sam.ipynb +17 -5
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/notebooks/template.ipynb +956 -944
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/notebooks/tutorial_1.ipynb +15 -2
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/notebooks/tutorial_2.ipynb +389 -377
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/notebooks/tutorial_3.ipynb +422 -410
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/owlplanner.cmd +2 -2
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/owlplanner.sh +1 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/pyproject.toml +6 -3
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/requirements.txt +1 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/__init__.py +3 -1
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/config.py +2 -2
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/plan.py +139 -274
- owlplanner-2025.5.15/src/owlplanner/plotting/__init__.py +7 -0
- owlplanner-2025.5.15/src/owlplanner/plotting/base.py +76 -0
- owlplanner-2025.5.15/src/owlplanner/plotting/factory.py +32 -0
- owlplanner-2025.5.15/src/owlplanner/plotting/matplotlib_backend.py +432 -0
- owlplanner-2025.5.15/src/owlplanner/plotting/plotly_backend.py +980 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/rates.py +3 -14
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/timelists.py +2 -7
- owlplanner-2025.5.15/src/owlplanner/version.py +1 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/tests/test_logger.py +3 -3
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/About_Owl.py +2 -1
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Create_Case.py +3 -2
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Current_Assets.py +4 -3
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Documentation.py +38 -19
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Graphs.py +5 -3
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Historical_Range.py +3 -3
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Monte_Carlo.py +3 -3
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Optimization_Parameters.py +11 -11
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Output_Files.py +2 -2
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Quick_Start.py +1 -1
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Rates_Selection.py +27 -29
- owlplanner-2025.5.15/ui/Settings.py +29 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Wages_And_Contributions.py +2 -2
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/main.py +3 -4
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/owlbridge.py +91 -32
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/sskeys.py +12 -4
- owlplanner-2025.5.5/docker/fastentrypoint.sh +0 -9
- owlplanner-2025.5.5/src/owlplanner/plots.py +0 -296
- owlplanner-2025.5.5/src/owlplanner/version.py +0 -1
- owlplanner-2025.5.5/ui/Settings.py +0 -33
- owlplanner-2025.5.5/ui/plots.py +0 -20
- owlplanner-2025.5.5/ui/requirements.txt +0 -11
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/.flake8 +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/.gitattributes +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/.github/workflows/github-actions-runtests.yml +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/.gitignore +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/INSTALL.md +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/LICENSE +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/USER_GUIDE.md +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docker/docker-compose.yml +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/AD-taxDef.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/AD-taxFree.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/AD-taxable.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/Hist_Bequest.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/Hist_Spending.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/MC-tutorial2a.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/MC-tutorial2b.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/OwlUI.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/allocations.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/owl.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/profile.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/ratesCorrelations.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/ratesPlot.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/savingsPlot.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/sourcesPlot.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/spendingPlot.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/taxIncomePlot.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/images/taxesPlot.png +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/owl.pdf +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/docs/owl.tex +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/case_jack+jill.toml +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/case_joe.toml +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/case_john+sally.toml +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/case_jon+jane.toml +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/case_kim+sam-bequest.toml +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/case_kim+sam-spending.toml +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/jack+jill.xlsx +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/joe.xlsx +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/john+sally.xlsx +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/jon+jane.xlsx +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/examples/template.xlsx +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/pytest.ini +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/abcapi.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/data/__init__.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/data/rates.csv +0 -0
- /owlplanner-2025.5.5/src/owlplanner/logging.py → /owlplanner-2025.5.15/src/owlplanner/mylogging.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/progress.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/tax2025.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/src/owlplanner/utils.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/tests/test_regressions.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/tests/test_repro.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/tests/test_toml_cases.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/tests/test_ui_asset_allocation.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/tests/test_ui_compare_summaries.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/tests/test_ui_sskeys.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/tests/test_units.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Asset_Allocation.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Fixed_Income.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Logs.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/README.md +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/Worksheets.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/__init__.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/progress.py +0 -0
- {owlplanner-2025.5.5 → owlplanner-2025.5.15}/ui/tomlexamples.py +0 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
|
|
2
|
+
[global]
|
|
3
|
+
|
|
4
|
+
# By default, Streamlit displays a warning when a user sets both a widget
|
|
5
|
+
# default value in the function defining the widget and a widget value via
|
|
6
|
+
# the widget's key in `st.session_state`.
|
|
7
|
+
|
|
8
|
+
# If you'd like to turn off this warning, set this to True.
|
|
9
|
+
|
|
10
|
+
# Default: false
|
|
11
|
+
# disableWidgetStateDuplicationWarning = false
|
|
12
|
+
|
|
13
|
+
# If True, will show a warning when you run a Streamlit-enabled script
|
|
14
|
+
# via "python my_script.py".
|
|
15
|
+
|
|
16
|
+
# Default: true
|
|
17
|
+
# showWarningOnDirectExecution = true
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
[logger]
|
|
21
|
+
|
|
22
|
+
# Level of logging for Streamlit's internal logger: "error", "warning",
|
|
23
|
+
# "info", or "debug".
|
|
24
|
+
|
|
25
|
+
# Default: "info"
|
|
26
|
+
# level = "info"
|
|
27
|
+
|
|
28
|
+
# String format for logging messages. If logger.datetimeFormat is set,
|
|
29
|
+
# logger messages will default to `%(asctime)s.%(msecs)03d %(message)s`. See
|
|
30
|
+
# Python's documentation for available attributes:
|
|
31
|
+
# https://docs.python.org/3/library/logging.html#formatter-objects
|
|
32
|
+
|
|
33
|
+
# Default: "%(asctime)s %(message)s"
|
|
34
|
+
# messageFormat = "%(asctime)s %(message)s"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
[client]
|
|
38
|
+
|
|
39
|
+
# Controls whether uncaught app exceptions and deprecation warnings
|
|
40
|
+
# are displayed in the browser. This can be one of the following:
|
|
41
|
+
|
|
42
|
+
# - "full" : In the browser, Streamlit displays app deprecation
|
|
43
|
+
# warnings and exceptions, including exception types,
|
|
44
|
+
# exception messages, and associated tracebacks.
|
|
45
|
+
# - "stacktrace" : In the browser, Streamlit displays exceptions,
|
|
46
|
+
# including exception types, generic exception messages,
|
|
47
|
+
# and associated tracebacks. Deprecation warnings and
|
|
48
|
+
# full exception messages will only print to the
|
|
49
|
+
# console.
|
|
50
|
+
# - "type" : In the browser, Streamlit displays exception types and
|
|
51
|
+
# generic exception messages. Deprecation warnings, full
|
|
52
|
+
# exception messages, and associated tracebacks only
|
|
53
|
+
# print to the console.
|
|
54
|
+
# - "none" : In the browser, Streamlit displays generic exception
|
|
55
|
+
# messages. Deprecation warnings, full exception
|
|
56
|
+
# messages, associated tracebacks, and exception types
|
|
57
|
+
# will only print to the console.
|
|
58
|
+
# - True : This is deprecated. Streamlit displays "full"
|
|
59
|
+
# error details.
|
|
60
|
+
# - False : This is deprecated. Streamlit displays "stacktrace"
|
|
61
|
+
# error details.
|
|
62
|
+
|
|
63
|
+
# Default: [ "f", "u", "l", "l",]
|
|
64
|
+
# showErrorDetails = [ "f", "u", "l", "l",]
|
|
65
|
+
|
|
66
|
+
# Change the visibility of items in the toolbar, options menu,
|
|
67
|
+
# and settings dialog (top right of the app).
|
|
68
|
+
|
|
69
|
+
# Allowed values:
|
|
70
|
+
# - "auto" : Show the developer options if the app is accessed through
|
|
71
|
+
# localhost or through Streamlit Community Cloud as a developer.
|
|
72
|
+
# Hide them otherwise.
|
|
73
|
+
# - "developer" : Show the developer options.
|
|
74
|
+
# - "viewer" : Hide the developer options.
|
|
75
|
+
# - "minimal" : Show only options set externally (e.g. through
|
|
76
|
+
# Streamlit Community Cloud) or through st.set_page_config.
|
|
77
|
+
# If there are no options left, hide the menu.
|
|
78
|
+
|
|
79
|
+
# Default: "auto"
|
|
80
|
+
toolbarMode = "developer"
|
|
81
|
+
|
|
82
|
+
# Controls whether to display the default sidebar page navigation in a
|
|
83
|
+
# multi-page app. This only applies when app's pages are defined by the
|
|
84
|
+
# `pages/` directory.
|
|
85
|
+
|
|
86
|
+
# Default: true
|
|
87
|
+
# showSidebarNavigation = true
|
|
88
|
+
|
|
89
|
+
[runner]
|
|
90
|
+
|
|
91
|
+
# Allows you to type a variable or string by itself in a single line of
|
|
92
|
+
# Python code to write it to the app.
|
|
93
|
+
|
|
94
|
+
# Default: true
|
|
95
|
+
# magicEnabled = true
|
|
96
|
+
|
|
97
|
+
# Handle script rerun requests immediately, rather than waiting for script
|
|
98
|
+
# execution to reach a yield point. This makes Streamlit much more
|
|
99
|
+
# responsive to user interaction, but it can lead to race conditions in
|
|
100
|
+
# apps that mutate session_state data outside of explicit session_state
|
|
101
|
+
# assignment statements.
|
|
102
|
+
|
|
103
|
+
# Default: true
|
|
104
|
+
# fastReruns = true
|
|
105
|
+
|
|
106
|
+
# Raise an exception after adding unserializable data to Session State.
|
|
107
|
+
# Some execution environments may require serializing all data in Session
|
|
108
|
+
# State, so it may be useful to detect incompatibility during development,
|
|
109
|
+
# or when the execution environment will stop supporting it in the future.
|
|
110
|
+
|
|
111
|
+
# Default: false
|
|
112
|
+
# enforceSerializableSessionState = false
|
|
113
|
+
|
|
114
|
+
# Adjust how certain 'options' widgets like radio, selectbox, and
|
|
115
|
+
# multiselect coerce Enum members when the Enum class gets re-defined
|
|
116
|
+
# during a script re-run. For more information, check out the docs:
|
|
117
|
+
# https://docs.streamlit.io/develop/concepts/design/custom-classes#enums
|
|
118
|
+
|
|
119
|
+
# Allowed values:
|
|
120
|
+
# - "off": Disables Enum coercion.
|
|
121
|
+
# - "nameOnly": Enum classes can be coerced if their member names match.
|
|
122
|
+
# - "nameAndValue": Enum classes can be coerced if their member names AND
|
|
123
|
+
# member values match.
|
|
124
|
+
|
|
125
|
+
# Default: "nameOnly"
|
|
126
|
+
# enumCoercion = "nameOnly"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
[server]
|
|
130
|
+
|
|
131
|
+
# List of folders that should not be watched for changes.
|
|
132
|
+
|
|
133
|
+
# Relative paths will be taken as relative to the current working directory.
|
|
134
|
+
|
|
135
|
+
# Example: ['/home/user1/env', 'relative/path/to/folder']
|
|
136
|
+
|
|
137
|
+
# Default: []
|
|
138
|
+
# folderWatchBlacklist = []
|
|
139
|
+
|
|
140
|
+
# Change the type of file watcher used by Streamlit, or turn it off
|
|
141
|
+
# completely.
|
|
142
|
+
|
|
143
|
+
# Allowed values:
|
|
144
|
+
# - "auto" : Streamlit will attempt to use the watchdog module, and
|
|
145
|
+
# falls back to polling if watchdog is not available.
|
|
146
|
+
# - "watchdog" : Force Streamlit to use the watchdog module.
|
|
147
|
+
# - "poll" : Force Streamlit to always use polling.
|
|
148
|
+
# - "none" : Streamlit will not watch files.
|
|
149
|
+
|
|
150
|
+
# Default: "auto"
|
|
151
|
+
# fileWatcherType = "auto"
|
|
152
|
+
|
|
153
|
+
# Symmetric key used to produce signed cookies. If deploying on multiple
|
|
154
|
+
# replicas, this should be set to the same value across all replicas to ensure
|
|
155
|
+
# they all share the same secret.
|
|
156
|
+
|
|
157
|
+
# Default: randomly generated secret key.
|
|
158
|
+
# cookieSecret = "b87888855015f2bb50b408cb9d958bb52ea434cc6dacdf971c9e2b4997216925"
|
|
159
|
+
|
|
160
|
+
# If false, will attempt to open a browser window on start.
|
|
161
|
+
|
|
162
|
+
# Default: false unless (1) we are on a Linux box where DISPLAY is unset, or
|
|
163
|
+
# (2) we are running in the Streamlit Atom plugin.
|
|
164
|
+
# headless = false
|
|
165
|
+
|
|
166
|
+
# Automatically rerun script when the file is modified on disk.
|
|
167
|
+
|
|
168
|
+
# Default: false
|
|
169
|
+
# runOnSave = false
|
|
170
|
+
|
|
171
|
+
# The address where the server will listen for client and browser
|
|
172
|
+
# connections. Use this if you want to bind the server to a specific address.
|
|
173
|
+
# If set, the server will only be accessible from this address, and not from
|
|
174
|
+
# any aliases (like localhost).
|
|
175
|
+
|
|
176
|
+
# Default: (unset)
|
|
177
|
+
# address =
|
|
178
|
+
|
|
179
|
+
# The port where the server will listen for browser connections.
|
|
180
|
+
|
|
181
|
+
# Don't use port 3000 which is reserved for internal development.
|
|
182
|
+
|
|
183
|
+
# Default: 8501
|
|
184
|
+
# port = 8501
|
|
185
|
+
|
|
186
|
+
# The base path for the URL where Streamlit should be served from.
|
|
187
|
+
|
|
188
|
+
# Default: ""
|
|
189
|
+
# baseUrlPath = ""
|
|
190
|
+
|
|
191
|
+
# Enables support for Cross-Origin Resource Sharing (CORS) protection,
|
|
192
|
+
# for added security.
|
|
193
|
+
|
|
194
|
+
# If XSRF protection is enabled and CORS protection is disabled at the
|
|
195
|
+
# same time, Streamlit will enable them both instead.
|
|
196
|
+
|
|
197
|
+
# Default: true
|
|
198
|
+
# enableCORS = true
|
|
199
|
+
|
|
200
|
+
# Enables support for Cross-Site Request Forgery (XSRF) protection, for
|
|
201
|
+
# added security.
|
|
202
|
+
|
|
203
|
+
# If XSRF protection is enabled and CORS protection is disabled at the
|
|
204
|
+
# same time, Streamlit will enable them both instead.
|
|
205
|
+
|
|
206
|
+
# Default: true
|
|
207
|
+
# enableXsrfProtection = true
|
|
208
|
+
|
|
209
|
+
# Max size, in megabytes, for files uploaded with the file_uploader.
|
|
210
|
+
|
|
211
|
+
# Default: 200
|
|
212
|
+
# maxUploadSize = 200
|
|
213
|
+
|
|
214
|
+
# Max size, in megabytes, of messages that can be sent via the WebSocket
|
|
215
|
+
# connection.
|
|
216
|
+
|
|
217
|
+
# Default: 200
|
|
218
|
+
# maxMessageSize = 200
|
|
219
|
+
|
|
220
|
+
# Enables support for websocket compression.
|
|
221
|
+
|
|
222
|
+
# Default: false
|
|
223
|
+
# enableWebsocketCompression = false
|
|
224
|
+
|
|
225
|
+
# Enable serving files from a `static` directory in the running app's
|
|
226
|
+
# directory.
|
|
227
|
+
|
|
228
|
+
# Default: false
|
|
229
|
+
# enableStaticServing = false
|
|
230
|
+
|
|
231
|
+
# TTL in seconds for sessions whose websockets have been disconnected. The server
|
|
232
|
+
# may choose to clean up session state, uploaded files, etc for a given session
|
|
233
|
+
# with no active websocket connection at any point after this time has passed.
|
|
234
|
+
|
|
235
|
+
# Default: 120
|
|
236
|
+
# disconnectedSessionTTL = 120
|
|
237
|
+
|
|
238
|
+
# Server certificate file for connecting via HTTPS.
|
|
239
|
+
# Must be set at the same time as "server.sslKeyFile".
|
|
240
|
+
|
|
241
|
+
# ['DO NOT USE THIS OPTION IN A PRODUCTION ENVIRONMENT. It has not gone through security audits or performance tests. For the production environment, we recommend performing SSL termination by the load balancer or the reverse proxy.']
|
|
242
|
+
# sslCertFile =
|
|
243
|
+
|
|
244
|
+
# Cryptographic key file for connecting via HTTPS.
|
|
245
|
+
# Must be set at the same time as "server.sslCertFile".
|
|
246
|
+
|
|
247
|
+
# ['DO NOT USE THIS OPTION IN A PRODUCTION ENVIRONMENT. It has not gone through security audits or performance tests. For the production environment, we recommend performing SSL termination by the load balancer or the reverse proxy.']
|
|
248
|
+
# sslKeyFile =
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
[browser]
|
|
252
|
+
|
|
253
|
+
# Internet address where users should point their browsers in order to
|
|
254
|
+
# connect to the app. Can be IP address or DNS name and path.
|
|
255
|
+
|
|
256
|
+
# This is used to:
|
|
257
|
+
# - Set the correct URL for CORS and XSRF protection purposes.
|
|
258
|
+
# - Show the URL on the terminal
|
|
259
|
+
# - Open the browser
|
|
260
|
+
|
|
261
|
+
# Default: "localhost"
|
|
262
|
+
# serverAddress = "localhost"
|
|
263
|
+
|
|
264
|
+
# Whether to send usage statistics to Streamlit.
|
|
265
|
+
|
|
266
|
+
# Default: true
|
|
267
|
+
# gatherUsageStats = true
|
|
268
|
+
|
|
269
|
+
# Port where users should point their browsers in order to connect to the
|
|
270
|
+
# app.
|
|
271
|
+
|
|
272
|
+
# This is used to:
|
|
273
|
+
# - Set the correct URL for XSRF protection purposes.
|
|
274
|
+
# - Show the URL on the terminal (part of `streamlit run`).
|
|
275
|
+
# - Open the browser automatically (part of `streamlit run`).
|
|
276
|
+
|
|
277
|
+
# This option is for advanced use cases. To change the port of your app, use
|
|
278
|
+
# `server.Port` instead. Don't use port 3000 which is reserved for internal
|
|
279
|
+
# development.
|
|
280
|
+
|
|
281
|
+
# Default: whatever value is set in server.port.
|
|
282
|
+
# serverPort = 8501
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
[mapbox]
|
|
286
|
+
|
|
287
|
+
# Configure Streamlit to use a custom Mapbox
|
|
288
|
+
# token for elements like st.pydeck_chart and st.map.
|
|
289
|
+
# To get a token for yourself, create an account at
|
|
290
|
+
# https://mapbox.com. It's free (for moderate usage levels)!
|
|
291
|
+
|
|
292
|
+
# Default: ""
|
|
293
|
+
# token = ""
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
[theme]
|
|
297
|
+
|
|
298
|
+
# The preset Streamlit theme that your custom theme inherits from.
|
|
299
|
+
# One of "light" or "dark".
|
|
300
|
+
# base =
|
|
301
|
+
|
|
302
|
+
# Primary accent color for interactive elements.
|
|
303
|
+
# primaryColor =
|
|
304
|
+
|
|
305
|
+
# Background color for the main content area.
|
|
306
|
+
# backgroundColor =
|
|
307
|
+
|
|
308
|
+
# Background color used for the sidebar and most interactive widgets.
|
|
309
|
+
# secondaryBackgroundColor =
|
|
310
|
+
|
|
311
|
+
# Color used for almost all text.
|
|
312
|
+
# textColor =
|
|
313
|
+
|
|
314
|
+
# The font family for all text in the app, except code blocks. One of "sans serif",
|
|
315
|
+
# "serif", or "monospace".
|
|
316
|
+
# To use a custom font, it needs to be added via [theme.fontFaces].
|
|
317
|
+
# font =
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
[secrets]
|
|
321
|
+
|
|
322
|
+
# List of locations where secrets are searched. An entry can be a path to a
|
|
323
|
+
# TOML file or directory path where Kubernetes style secrets are saved.
|
|
324
|
+
# Order is important, import is first to last, so secrets in later files
|
|
325
|
+
# will take precedence over earlier ones.
|
|
326
|
+
|
|
327
|
+
# Default: [ "C:\\Users\\marti\\.streamlit\\secrets.toml", "C:\\Users\\marti\\Dropbox\\Retirement\\MyProject\\Owl\\.streamlit\\.streamlit\\secrets.toml",]
|
|
328
|
+
# files = [ "C:\\Users\\marti\\.streamlit\\secrets.toml", "C:\\Users\\marti\\Dropbox\\Retirement\\MyProject\\Owl\\.streamlit\\.streamlit\\secrets.toml",]
|
|
329
|
+
|
|
330
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: owlplanner
|
|
3
|
-
Version: 2025.5.
|
|
3
|
+
Version: 2025.5.15
|
|
4
4
|
Summary: Owl: Retirement planner with great wisdom
|
|
5
5
|
Project-URL: HomePage, https://github.com/mdlacasse/owl
|
|
6
6
|
Project-URL: Repository, https://github.com/mdlacasse/owl
|
|
@@ -693,8 +693,11 @@ Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
|
693
693
|
Requires-Python: >=3.8
|
|
694
694
|
Requires-Dist: matplotlib
|
|
695
695
|
Requires-Dist: numpy
|
|
696
|
+
Requires-Dist: odfpy
|
|
696
697
|
Requires-Dist: openpyxl
|
|
697
698
|
Requires-Dist: pandas
|
|
699
|
+
Requires-Dist: plotly
|
|
700
|
+
Requires-Dist: pulp
|
|
698
701
|
Requires-Dist: scipy
|
|
699
702
|
Requires-Dist: seaborn
|
|
700
703
|
Requires-Dist: streamlit
|
|
@@ -711,15 +714,17 @@ Description-Content-Type: text/markdown
|
|
|
711
714
|
-------------------------------------------------------------------------------------
|
|
712
715
|
|
|
713
716
|
### TL;DR
|
|
714
|
-
Owl is a retirement planning tool that uses a linear programming
|
|
715
|
-
to provide guidance on retirement decisions
|
|
717
|
+
Owl is a financial retirement planning tool that uses a linear programming
|
|
718
|
+
optimization algorithm to provide guidance on retirement decisions
|
|
719
|
+
such as contributions, withdrawals, Roth conversions, and more.
|
|
716
720
|
Users can select varying return rates to perform historical back testing,
|
|
717
721
|
stochastic rates for performing Monte Carlo analyses,
|
|
718
722
|
or fixed rates either derived from historical averages, or set by the user.
|
|
719
723
|
|
|
720
724
|
There are a few ways to run Owl:
|
|
721
725
|
|
|
722
|
-
- Run Owl directly on the Streamlit Community Server at
|
|
726
|
+
- Run Owl directly on the Streamlit Community Server at
|
|
727
|
+
[owlplanner.streamlit.app](https://owlplanner.streamlit.app).
|
|
723
728
|
|
|
724
729
|
- Run locally on your computer using a Docker image.
|
|
725
730
|
Follow these [instructions](docker/README.md) for this option.
|
|
@@ -729,7 +734,7 @@ Follow these [instructions](INSTALL.md) to install Owl from the source code and
|
|
|
729
734
|
|
|
730
735
|
-------------------------------------------------------------------------------------
|
|
731
736
|
## Overview
|
|
732
|
-
This package is a
|
|
737
|
+
This package is a modeling framework for exploring the sensitivity of retirement financial decisions.
|
|
733
738
|
Strictly speaking, it is not a planning tool, but more an environment for exploring *what if* scenarios.
|
|
734
739
|
It provides different realizations of a financial strategy through the rigorous
|
|
735
740
|
mathematical optimization of relevant decision variables. Two major objective goals can be set: either
|
|
@@ -8,15 +8,17 @@
|
|
|
8
8
|
-------------------------------------------------------------------------------------
|
|
9
9
|
|
|
10
10
|
### TL;DR
|
|
11
|
-
Owl is a retirement planning tool that uses a linear programming
|
|
12
|
-
to provide guidance on retirement decisions
|
|
11
|
+
Owl is a financial retirement planning tool that uses a linear programming
|
|
12
|
+
optimization algorithm to provide guidance on retirement decisions
|
|
13
|
+
such as contributions, withdrawals, Roth conversions, and more.
|
|
13
14
|
Users can select varying return rates to perform historical back testing,
|
|
14
15
|
stochastic rates for performing Monte Carlo analyses,
|
|
15
16
|
or fixed rates either derived from historical averages, or set by the user.
|
|
16
17
|
|
|
17
18
|
There are a few ways to run Owl:
|
|
18
19
|
|
|
19
|
-
- Run Owl directly on the Streamlit Community Server at
|
|
20
|
+
- Run Owl directly on the Streamlit Community Server at
|
|
21
|
+
[owlplanner.streamlit.app](https://owlplanner.streamlit.app).
|
|
20
22
|
|
|
21
23
|
- Run locally on your computer using a Docker image.
|
|
22
24
|
Follow these [instructions](docker/README.md) for this option.
|
|
@@ -26,7 +28,7 @@ Follow these [instructions](INSTALL.md) to install Owl from the source code and
|
|
|
26
28
|
|
|
27
29
|
-------------------------------------------------------------------------------------
|
|
28
30
|
## Overview
|
|
29
|
-
This package is a
|
|
31
|
+
This package is a modeling framework for exploring the sensitivity of retirement financial decisions.
|
|
30
32
|
Strictly speaking, it is not a planning tool, but more an environment for exploring *what if* scenarios.
|
|
31
33
|
It provides different realizations of a financial strategy through the rigorous
|
|
32
34
|
mathematical optimization of relevant decision variables. Two major objective goals can be set: either
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# docker/Dockerfile
|
|
2
|
+
|
|
3
|
+
FROM python:3.13-slim
|
|
4
|
+
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
|
|
7
|
+
RUN apt-get update; \
|
|
8
|
+
apt-get upgrade; \
|
|
9
|
+
apt-get install -y --no-install-recommends \
|
|
10
|
+
curl \
|
|
11
|
+
git \
|
|
12
|
+
; \
|
|
13
|
+
rm -rf /var/lib/apt/lists/*
|
|
14
|
+
|
|
15
|
+
COPY buildentrypoint.sh /usr/bin/entrypoint.sh
|
|
16
|
+
COPY runentrypoint.sh /usr/bin/runentrypoint.sh
|
|
17
|
+
|
|
18
|
+
RUN chmod 555 /usr/bin/entrypoint.sh /usr/bin/runentrypoint.sh
|
|
19
|
+
|
|
20
|
+
EXPOSE 8501
|
|
21
|
+
|
|
22
|
+
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
|
23
|
+
|
|
24
|
+
ENTRYPOINT ["/bin/bash", "/usr/bin/entrypoint.sh"]
|
|
@@ -12,20 +12,21 @@ RUN apt-get update; \
|
|
|
12
12
|
; \
|
|
13
13
|
rm -rf /var/lib/apt/lists/*
|
|
14
14
|
|
|
15
|
-
COPY
|
|
15
|
+
COPY runentrypoint.sh /usr/bin/entrypoint.sh
|
|
16
16
|
|
|
17
17
|
RUN chmod 555 /usr/bin/entrypoint.sh
|
|
18
18
|
|
|
19
19
|
# Build in the container for faster starts.
|
|
20
20
|
RUN python -m pip install --no-cache-dir --upgrade pip
|
|
21
21
|
|
|
22
|
-
RUN pip install --no-cache-dir build
|
|
22
|
+
# RUN pip install --no-cache-dir build
|
|
23
|
+
RUN rm -rf /app/owl
|
|
23
24
|
|
|
24
25
|
RUN git clone --depth 1 https://github.com/mdlacasse/Owl.git owl
|
|
25
26
|
|
|
26
|
-
RUN cd /app/owl && python -m
|
|
27
|
-
|
|
28
|
-
RUN cd /app/owl && pip install --no-cache-dir .
|
|
27
|
+
RUN cd /app/owl && python -m pip install -r requirements.txt
|
|
28
|
+
# RUN cd /app/owl && python -m build
|
|
29
|
+
# RUN cd /app/owl && pip install --no-cache-dir .
|
|
29
30
|
|
|
30
31
|
EXPOSE 8501
|
|
31
32
|
|
|
@@ -37,10 +37,14 @@ This approach requires cloning the Owl package from GitHub,
|
|
|
37
37
|
and having both Python and Docker installed on your computer.
|
|
38
38
|
|
|
39
39
|
##### Docker image
|
|
40
|
+
There are two images you can create. One builds Owl at run time, while
|
|
41
|
+
the other builds it statically in the image.
|
|
42
|
+
These two approaches trade startup time for image space
|
|
43
|
+
(~300 MB vs. 1.8 GB, ~22 vs. 200 sec).
|
|
40
44
|
First build the Docker image from the `docker` directory:
|
|
41
45
|
```shell
|
|
42
46
|
cd docker
|
|
43
|
-
docker build --no-cache -t owldocker .
|
|
47
|
+
docker build --no-cache -f Dockerfile.{build or run} -t owldocker .
|
|
44
48
|
```
|
|
45
49
|
|
|
46
50
|
#### Running the container
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#/bin/bash
|
|
2
|
+
|
|
3
|
+
# Build at run time for smaller image but slower starts.
|
|
4
|
+
rm -rf /app/owl
|
|
5
|
+
cd /app && git clone --depth 1 https://github.com/mdlacasse/Owl.git owl
|
|
6
|
+
|
|
7
|
+
export OWLDIR=/app/owl
|
|
8
|
+
|
|
9
|
+
python -m pip install --no-cache-dir --upgrade pip
|
|
10
|
+
cd ${OWLDIR} && python -m pip install -r requirements.txt
|
|
11
|
+
|
|
12
|
+
exec /usr/bin/runentrypoint.sh
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#/bin/bash
|
|
2
|
+
|
|
3
|
+
if ! [[ -v OWLDIR ]]; then
|
|
4
|
+
OWLDIR=/app/owl
|
|
5
|
+
fi
|
|
6
|
+
|
|
7
|
+
export PYTHONPATH=${OWLDIR}/src:${PYTHONPATH}
|
|
8
|
+
|
|
9
|
+
echo ""
|
|
10
|
+
echo "Owl is now running locally: Point your browser to http://localhost:8501"
|
|
11
|
+
|
|
12
|
+
if type -P streamlit >& /dev/null; then
|
|
13
|
+
streamlit run ${OWLDIR}/ui/main.py --server.port=8501 --server.address=0.0.0.0 --browser.gatherUsageStats=false
|
|
14
|
+
else
|
|
15
|
+
python3 -m streamlit run ${OWLDIR}/ui/main.py --server.port=8501 --server.address=0.0.0.0 --browser.gatherUsageStats=false
|
|
16
|
+
fi
|
|
17
|
+
|
|
@@ -14,6 +14,17 @@
|
|
|
14
14
|
"## John and Sally (a case from Eric Sajdak)"
|
|
15
15
|
]
|
|
16
16
|
},
|
|
17
|
+
{
|
|
18
|
+
"cell_type": "code",
|
|
19
|
+
"execution_count": null,
|
|
20
|
+
"id": "5cb2c2a1-6f77-41bf-a22d-42863c756eeb",
|
|
21
|
+
"metadata": {},
|
|
22
|
+
"outputs": [],
|
|
23
|
+
"source": [
|
|
24
|
+
"import sys\n",
|
|
25
|
+
"sys.path.insert(0, \"../src\")"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
17
28
|
{
|
|
18
29
|
"cell_type": "code",
|
|
19
30
|
"execution_count": null,
|
|
@@ -29,7 +40,9 @@
|
|
|
29
40
|
"source": [
|
|
30
41
|
"%%time\n",
|
|
31
42
|
"import owlplanner as owl\n",
|
|
43
|
+
"\n",
|
|
32
44
|
"plan = owl.Plan(['John', 'Sally'], [1962, 1962], [92, 92], 'john+sally')\n",
|
|
45
|
+
"# plan.setPlotBackend(\"plotly\")\n",
|
|
33
46
|
"plan.setAccountBalances(taxable=[200, 200], taxDeferred=[750, 750], taxFree=[50, 50])\n",
|
|
34
47
|
"# Unrealistic empty contributions and wages\n",
|
|
35
48
|
"plan.readContributions('../examples/john+sally.xlsx')\n",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"metadata": {},
|
|
16
16
|
"outputs": [],
|
|
17
17
|
"source": [
|
|
18
|
-
"import
|
|
18
|
+
"import sys\n",
|
|
19
|
+
"sys.path.insert(0, \"../src\")"
|
|
19
20
|
]
|
|
20
21
|
},
|
|
21
22
|
{
|
|
@@ -25,7 +26,9 @@
|
|
|
25
26
|
"metadata": {},
|
|
26
27
|
"outputs": [],
|
|
27
28
|
"source": [
|
|
28
|
-
"
|
|
29
|
+
"import owlplanner as owl\n",
|
|
30
|
+
"p = owl.Plan(['Kim', 'Sam'], [1966, 1967], [86, 89], 'kim+sam-spending', verbose=True)\n",
|
|
31
|
+
"# p.setPlotBackend(\"plotly\")"
|
|
29
32
|
]
|
|
30
33
|
},
|
|
31
34
|
{
|
|
@@ -81,7 +84,7 @@
|
|
|
81
84
|
"metadata": {},
|
|
82
85
|
"outputs": [],
|
|
83
86
|
"source": [
|
|
84
|
-
"p.readContributions('../examples/template.xlsx')"
|
|
87
|
+
"p.readContributions('../examples/template.xlsx');"
|
|
85
88
|
]
|
|
86
89
|
},
|
|
87
90
|
{
|
|
@@ -126,12 +129,21 @@
|
|
|
126
129
|
{
|
|
127
130
|
"cell_type": "code",
|
|
128
131
|
"execution_count": null,
|
|
129
|
-
"id": "
|
|
132
|
+
"id": "f2542fd7-f087-4597-b9c4-1c3b8fa2e452",
|
|
130
133
|
"metadata": {},
|
|
131
134
|
"outputs": [],
|
|
132
135
|
"source": [
|
|
133
136
|
"p.setDefaultPlots('today')\n",
|
|
134
|
-
"p.showNetSpending()
|
|
137
|
+
"p.showNetSpending()"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"cell_type": "code",
|
|
142
|
+
"execution_count": null,
|
|
143
|
+
"id": "525f22e2-d241-4fa8-bc95-82d758238326",
|
|
144
|
+
"metadata": {},
|
|
145
|
+
"outputs": [],
|
|
146
|
+
"source": [
|
|
135
147
|
"p.showGrossIncome()\n",
|
|
136
148
|
"p.showTaxes()\n",
|
|
137
149
|
"p.showSources()\n",
|