owlplanner 2025.3.30__py3-none-any.whl → 2025.4.1__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.
- owlplanner/config.py +6 -0
- owlplanner/plan.py +19 -7
- owlplanner/version.py +1 -1
- {owlplanner-2025.3.30.dist-info → owlplanner-2025.4.1.dist-info}/METADATA +1 -1
- {owlplanner-2025.3.30.dist-info → owlplanner-2025.4.1.dist-info}/RECORD +7 -7
- {owlplanner-2025.3.30.dist-info → owlplanner-2025.4.1.dist-info}/WHEEL +0 -0
- {owlplanner-2025.3.30.dist-info → owlplanner-2025.4.1.dist-info}/licenses/LICENSE +0 -0
owlplanner/config.py
CHANGED
|
@@ -12,6 +12,7 @@ Disclaimer: This program comes with no guarantee. Use at your own risk.
|
|
|
12
12
|
import toml as toml
|
|
13
13
|
from io import StringIO, BytesIO
|
|
14
14
|
import numpy as np
|
|
15
|
+
from datetime import date
|
|
15
16
|
import os
|
|
16
17
|
|
|
17
18
|
from owlplanner import plan
|
|
@@ -302,6 +303,11 @@ def readConfig(file, *, verbose=True, logstreams=None, readContributions=True):
|
|
|
302
303
|
if name != "None" and name not in p.inames:
|
|
303
304
|
raise ValueError(f"Unknown name {name} for noRothConversions.")
|
|
304
305
|
|
|
306
|
+
# Rebase startRothConversions on year change.
|
|
307
|
+
thisyear = date.today().year
|
|
308
|
+
year = p.solverOptions.get("startRothConversions", thisyear)
|
|
309
|
+
diconf["Solver Options"]["startRothConversions"] = max(year, thisyear)
|
|
310
|
+
|
|
305
311
|
# Results.
|
|
306
312
|
p.setDefaultPlots(diconf["Results"]["Default plots"])
|
|
307
313
|
|
owlplanner/plan.py
CHANGED
|
@@ -1143,6 +1143,17 @@ class Plan(object):
|
|
|
1143
1143
|
# Should we adjust Roth conversion cap with inflation?
|
|
1144
1144
|
B.set0_Ub(_q2(Cx, i, n, Ni, Nn), rhsopt)
|
|
1145
1145
|
|
|
1146
|
+
# Process startRothConversions option.
|
|
1147
|
+
if "startRothConversions" in options:
|
|
1148
|
+
rhsopt = options["startRothConversions"]
|
|
1149
|
+
thisyear = date.today().year
|
|
1150
|
+
yearn = max(rhsopt - thisyear, 0)
|
|
1151
|
+
|
|
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
|
+
|
|
1146
1157
|
# Process noRothConversions option. Also valid when N_i == 1, why not?
|
|
1147
1158
|
if "noRothConversions" in options and options["noRothConversions"] != "None":
|
|
1148
1159
|
rhsopt = options["noRothConversions"]
|
|
@@ -1197,7 +1208,7 @@ class Plan(object):
|
|
|
1197
1208
|
# Account for time elapsed in the current year.
|
|
1198
1209
|
spending *= units * self.yearFracLeft
|
|
1199
1210
|
# self.mylog.vprint('Maximizing bequest with desired net spending of:', u.d(spending))
|
|
1200
|
-
# To allow slack in first year, Cg can be made Nn+1 and store basis in g[Nn].
|
|
1211
|
+
# To allow slack in first year, Cg can be made Nn+1 and store basis in g[Nn].
|
|
1201
1212
|
A.addNewRow({_q1(Cg, 0, Nn): 1}, spending, spending)
|
|
1202
1213
|
|
|
1203
1214
|
# Set initial balances through constraints.
|
|
@@ -1616,16 +1627,17 @@ class Plan(object):
|
|
|
1616
1627
|
knownObjectives = ["maxBequest", "maxSpending"]
|
|
1617
1628
|
knownSolvers = ["HiGHS", "MOSEK"]
|
|
1618
1629
|
knownOptions = [
|
|
1619
|
-
"units",
|
|
1620
|
-
"maxRothConversion",
|
|
1621
|
-
"netSpending",
|
|
1622
|
-
"spendingSlack",
|
|
1623
1630
|
"bequest",
|
|
1624
1631
|
"bigM",
|
|
1632
|
+
"maxRothConversion",
|
|
1633
|
+
"netSpending",
|
|
1625
1634
|
"noRothConversions",
|
|
1626
|
-
"withMedicare",
|
|
1627
|
-
"solver",
|
|
1628
1635
|
"previousMAGIs",
|
|
1636
|
+
"solver",
|
|
1637
|
+
"spendingSlack",
|
|
1638
|
+
"startRothConversions",
|
|
1639
|
+
"units",
|
|
1640
|
+
"withMedicare",
|
|
1629
1641
|
]
|
|
1630
1642
|
# We will modify options if required.
|
|
1631
1643
|
if options is None:
|
owlplanner/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2025.
|
|
1
|
+
__version__ = "2025.04.01"
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
owlplanner/__init__.py,sha256=QqrdT0Qks20osBTg7h0vJHAxpP9lL7DA99xb0nYbtw4,254
|
|
2
2
|
owlplanner/abcapi.py,sha256=LbzW_KcNy0IeHp42MUHwGu_H67B2h_e1_vu-c2ACTkQ,6646
|
|
3
|
-
owlplanner/config.py,sha256=
|
|
3
|
+
owlplanner/config.py,sha256=F6GS3n02VeFX0GCVeM4J7Ra0in4N632W6TZIXk7Yj2w,12519
|
|
4
4
|
owlplanner/logging.py,sha256=tYMw04O-XYSzjTj36fmKJGLcE1VkK6k6oJNeqtKXzuc,2530
|
|
5
|
-
owlplanner/plan.py,sha256=
|
|
5
|
+
owlplanner/plan.py,sha256=glDdZIwHrSBl73SrEvuueP6HhpZYJcdkIZUTyEMgufQ,117423
|
|
6
6
|
owlplanner/progress.py,sha256=8jlCvvtgDI89zXVNMBg1-lnEyhpPvKQS2X5oAIpoOVQ,384
|
|
7
7
|
owlplanner/rates.py,sha256=gJaoe-gJqWCQV5qVLlHp-Yn9TSJs-PJzeTbOwMCbqWs,15682
|
|
8
8
|
owlplanner/tax2025.py,sha256=HEXfL0HfwUvZOQRjivXO2jFeoVZ5m_yk_hoMiVi-hR0,7745
|
|
9
9
|
owlplanner/timelists.py,sha256=tYieZU67FT6TCcQQis36JaXGI7dT6NqD7RvdEjgJL4M,4026
|
|
10
10
|
owlplanner/utils.py,sha256=WpJgn79YZfH8UCkcmhd-AZlxlGuz1i1-UDBRXImsY6I,2485
|
|
11
|
-
owlplanner/version.py,sha256=
|
|
11
|
+
owlplanner/version.py,sha256=Kr7kuAxBy9BosIPj1QB_sXrE5p_ga2ZEalol7JPRHL0,28
|
|
12
12
|
owlplanner/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
owlplanner/data/rates.csv,sha256=6fxg56BVVORrj9wJlUGFdGXKvOX5r7CSca8uhUbbuIU,3734
|
|
14
|
-
owlplanner-2025.
|
|
15
|
-
owlplanner-2025.
|
|
16
|
-
owlplanner-2025.
|
|
17
|
-
owlplanner-2025.
|
|
14
|
+
owlplanner-2025.4.1.dist-info/METADATA,sha256=ncoHFUU3X9fTZ0ug2NJX3KAkA4958htE1AafkwkbuOg,53800
|
|
15
|
+
owlplanner-2025.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
16
|
+
owlplanner-2025.4.1.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
|
17
|
+
owlplanner-2025.4.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|