owlplanner 2025.4.1__tar.gz → 2025.4.2__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 (112) hide show
  1. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/.flake8 +1 -1
  2. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/PKG-INFO +1 -1
  3. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/pyproject.toml +1 -1
  4. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/plan.py +30 -28
  5. owlplanner-2025.4.2/src/owlplanner/version.py +1 -0
  6. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Documentation.py +2 -0
  7. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Optimization_Parameters.py +1 -1
  8. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/requirements.txt +1 -1
  9. owlplanner-2025.4.1/src/owlplanner/version.py +0 -1
  10. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/.devcontainer/devcontainer.json +0 -0
  11. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/.gitattributes +0 -0
  12. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/.github/workflows/github-actions-runtests.yml +0 -0
  13. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/.gitignore +0 -0
  14. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/INSTALL.md +0 -0
  15. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/LICENSE +0 -0
  16. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/Papers/FE00006821-Class-VI-Injection-Permit--Salient-Features-and-Regulatory-Challenges_Final.pdf +0 -0
  17. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/Papers/Kou-OptionPricingDouble-2004.pdf +0 -0
  18. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/Papers/Multi-Period Mean Expected-Shortfall Strategies Cut Your Losses and Ride Your Gains .pdf +0 -0
  19. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/Papers/Optimal Asset Allocation for Retirement Saving Deterministic Vs. Time Consistent Adaptive Strategies.pdf +0 -0
  20. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/Papers/Rule-based_strategies_for_dynamic_life_cycle_inves.pdf +0 -0
  21. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/Papers/bv_cvxbook.pdf +0 -0
  22. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/Papers/s10436-006-0062-y.pdf +0 -0
  23. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/README.md +0 -0
  24. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/USER_GUIDE.md +0 -0
  25. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docker/Dockerfile +0 -0
  26. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docker/README.md +0 -0
  27. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docker/docker-compose.yml +0 -0
  28. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docker/fastentrypoint.sh +0 -0
  29. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/AD-taxDef.png +0 -0
  30. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/AD-taxFree.png +0 -0
  31. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/AD-taxable.png +0 -0
  32. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/Hist_Bequest.png +0 -0
  33. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/Hist_Spending.png +0 -0
  34. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/MC-tutorial2a.png +0 -0
  35. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/MC-tutorial2b.png +0 -0
  36. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/OwlUI.png +0 -0
  37. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/allocations.png +0 -0
  38. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/owl.png +0 -0
  39. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/profile.png +0 -0
  40. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/ratesCorrelations.png +0 -0
  41. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/ratesPlot.png +0 -0
  42. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/savingsPlot.png +0 -0
  43. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/sourcesPlot.png +0 -0
  44. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/spendingPlot.png +0 -0
  45. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/taxIncomePlot.png +0 -0
  46. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/images/taxesPlot.png +0 -0
  47. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/owl.pdf +0 -0
  48. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/docs/owl.tex +0 -0
  49. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/case_jack+jill.toml +0 -0
  50. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/case_joe.toml +0 -0
  51. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/case_john+sally.toml +0 -0
  52. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/case_jon+jane.toml +0 -0
  53. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/case_kim+sam-bequest.toml +0 -0
  54. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/case_kim+sam-spending.toml +0 -0
  55. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/jack+jill.xlsx +0 -0
  56. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/joe.xlsx +0 -0
  57. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/john+sally.xlsx +0 -0
  58. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/jon+jane.xlsx +0 -0
  59. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/examples/template.xlsx +0 -0
  60. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/notebooks/john+sally.ipynb +0 -0
  61. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/notebooks/kim+sam.ipynb +0 -0
  62. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/notebooks/template.ipynb +0 -0
  63. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/notebooks/tutorial_1.ipynb +0 -0
  64. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/notebooks/tutorial_2.ipynb +0 -0
  65. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/notebooks/tutorial_3.ipynb +0 -0
  66. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/owlplanner.cmd +0 -0
  67. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/owlplanner.sh +0 -0
  68. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/requirements.txt +0 -0
  69. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/__init__.py +0 -0
  70. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/abcapi.py +0 -0
  71. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/config.py +0 -0
  72. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/data/__init__.py +0 -0
  73. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/data/rates.csv +0 -0
  74. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/logging.py +0 -0
  75. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/progress.py +0 -0
  76. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/rates.py +0 -0
  77. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/tax2025.py +0 -0
  78. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/timelists.py +0 -0
  79. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/src/owlplanner/utils.py +0 -0
  80. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/tests/test_logger.py +0 -0
  81. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/tests/test_regressions.py +0 -0
  82. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/tests/test_repro.py +0 -0
  83. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/tests/test_toml_cases.py +0 -0
  84. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/tests/test_units.py +0 -0
  85. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ttt.py +0 -0
  86. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ttt2.py +0 -0
  87. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ttt3.py +0 -0
  88. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/About_Owl.py +0 -0
  89. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Asset_Allocation.py +0 -0
  90. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Create_Case.py +0 -0
  91. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Current_Assets.py +0 -0
  92. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Fixed_Income.py +0 -0
  93. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Graphs.py +0 -0
  94. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Historical_Range.py +0 -0
  95. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Logs.py +0 -0
  96. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Monte_Carlo.py +0 -0
  97. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Output_Files.py +0 -0
  98. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Quick_Start.py +0 -0
  99. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/README.md +0 -0
  100. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Rates_Selection.py +0 -0
  101. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Settings.py +0 -0
  102. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Wages_And_Contributions.py +0 -0
  103. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/Worksheets.py +0 -0
  104. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/main+fonts.py +0 -0
  105. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/main.py +0 -0
  106. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/owlbridge.py +0 -0
  107. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/plots.py +0 -0
  108. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/progress.py +0 -0
  109. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/sskeys.py +0 -0
  110. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/sskeys.py.color +0 -0
  111. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/style.css +0 -0
  112. {owlplanner-2025.4.1 → owlplanner-2025.4.2}/ui/tomlexamples.py +0 -0
@@ -1,6 +1,6 @@
1
1
  [flake8]
2
2
  max-line-length = 120
3
- max-complexity = 60
3
+ max-complexity = 70
4
4
  # These checks violate PEP8 so let's ignore them
5
5
  extend-ignore = E203
6
6
  # extend-exclude = */site-packages/*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owlplanner
3
- Version: 2025.4.1
3
+ Version: 2025.4.2
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "owlplanner"
7
- version = "2025.04.01"
7
+ version = "2025.04.02"
8
8
  authors = [
9
9
  { name="Martin-D. Lacasse", email="martin.d.lacasse@gmail.com" },
10
10
  ]
@@ -1122,16 +1122,17 @@ class Plan(object):
1122
1122
  B.set0_Ub(_q1(Ce, n, Nn), self.sigmaBar_n[n])
1123
1123
 
1124
1124
  # Roth conversions equalities/inequalities.
1125
- if "maxRothConversion" in options:
1126
- if options["maxRothConversion"] == "file":
1127
- # self.mylog.vprint(f"Fixing Roth conversions to those from file {self.timeListsFileName}.")
1128
- for i in range(Ni):
1129
- for n in range(self.horizons[i]):
1130
- rhs = self.myRothX_in[i][n]
1131
- B.setRange(_q2(Cx, i, n, Ni, Nn), rhs, rhs)
1132
- else:
1125
+ # This condition supercedes everything else.
1126
+ if "maxRothConversion" in options and options["maxRothConversion"] == "file":
1127
+ # self.mylog.vprint(f"Fixing Roth conversions to those from file {self.timeListsFileName}.")
1128
+ for i in range(Ni):
1129
+ for n in range(self.horizons[i]):
1130
+ rhs = self.myRothX_in[i][n]
1131
+ B.setRange(_q2(Cx, i, n, Ni, Nn), rhs, rhs)
1132
+ else:
1133
+ if "maxRothConversion" in options:
1133
1134
  rhsopt = options["maxRothConversion"]
1134
- assert isinstance(rhsopt, (int, float)), "Specified maxConversion is not a number."
1135
+ assert isinstance(rhsopt, (int, float)), "Specified maxRothConversion is not a number."
1135
1136
  rhsopt *= units
1136
1137
  if rhsopt < 0:
1137
1138
  # self.mylog.vprint('Unlimited Roth conversions (<0)')
@@ -1143,27 +1144,28 @@ class Plan(object):
1143
1144
  # Should we adjust Roth conversion cap with inflation?
1144
1145
  B.set0_Ub(_q2(Cx, i, n, Ni, Nn), rhsopt)
1145
1146
 
1146
- # Process startRothConversions option.
1147
- if "startRothConversions" in options:
1148
- rhsopt = options["startRothConversions"]
1149
- thisyear = date.today().year
1150
- yearn = max(rhsopt - thisyear, 0)
1147
+ # Process startRothConversions option.
1148
+ if "startRothConversions" in options:
1149
+ rhsopt = options["startRothConversions"]
1150
+ assert isinstance(rhsopt, (int, float)), "Specified startRothConversions is not a number."
1151
+ thisyear = date.today().year
1152
+ yearn = max(rhsopt - thisyear, 0)
1151
1153
 
1152
- for i in range(Ni):
1153
- nstart = min(yearn, self.horizons[i])
1154
- for n in range(0, nstart):
1155
- B.set0_Ub(_q2(Cx, i, n, Ni, Nn), zero)
1156
-
1157
- # Process noRothConversions option. Also valid when N_i == 1, why not?
1158
- if "noRothConversions" in options and options["noRothConversions"] != "None":
1159
- rhsopt = options["noRothConversions"]
1160
- try:
1161
- i_x = self.inames.index(rhsopt)
1162
- except ValueError:
1163
- raise ValueError(f"Unknown individual {rhsopt} for noRothConversions:")
1154
+ for i in range(Ni):
1155
+ nstart = min(yearn, self.horizons[i])
1156
+ for n in range(0, nstart):
1157
+ B.set0_Ub(_q2(Cx, i, n, Ni, Nn), zero)
1158
+
1159
+ # Process noRothConversions option. Also valid when N_i == 1, why not?
1160
+ if "noRothConversions" in options and options["noRothConversions"] != "None":
1161
+ rhsopt = options["noRothConversions"]
1162
+ try:
1163
+ i_x = self.inames.index(rhsopt)
1164
+ except ValueError:
1165
+ raise ValueError(f"Unknown individual {rhsopt} for noRothConversions:")
1164
1166
 
1165
- for n in range(Nn):
1166
- B.set0_Ub(_q2(Cx, i_x, n, Ni, Nn), zero)
1167
+ for n in range(Nn):
1168
+ B.set0_Ub(_q2(Cx, i_x, n, Ni, Nn), zero)
1167
1169
 
1168
1170
  # Impose withdrawal limits on taxable and tax-exempt accounts.
1169
1171
  for i in range(Ni):
@@ -0,0 +1 @@
1
+ __version__ = "2025.04.02"
@@ -282,6 +282,8 @@ button is toggled, in which case Roth conversions will not be optimized,
282
282
  but will rather be performed according to
283
283
  the `Roth conv` column on the
284
284
  [Wages and Contributions](#wages-and-contributions) page.
285
+ A year from which Roth conversions can begin to be considered can also be selected: no Roth
286
+ conversions will be allowed before the year specified.
285
287
 
286
288
  Calculations of Medicare and IRMAA can be turned on or off. This will typically speed up
287
289
  the calculations by a factor of 2 to 3, which can be useful when running Monte Carlo simulations.
@@ -57,7 +57,7 @@ else:
57
57
  helpmsg = "Do not perform Roth conversions before that year."
58
58
  thisyear = date.today().year
59
59
  kz.initKey("startRothConversions", thisyear)
60
- ret = kz.getIntNum("Year to start Roth conversions", "startRothConversions", min_value=thisyear,
60
+ ret = kz.getIntNum("Year to start considering Roth conversions", "startRothConversions", min_value=thisyear,
61
61
  disabled=fromFile, help=helpmsg)
62
62
  if kz.getKey("status") == "married":
63
63
  iname1 = kz.getKey("iname1")
@@ -8,4 +8,4 @@ scipy
8
8
  streamlit
9
9
  toml
10
10
  # --extra-index-url https://test.pypi.org/simple
11
- owlplanner >= 2025.04.01
11
+ owlplanner >= 2025.04.02
@@ -1 +0,0 @@
1
- __version__ = "2025.04.01"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes