owlplanner 2025.5.3__py3-none-any.whl → 2025.5.12__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/__init__.py +8 -6
- owlplanner/abcapi.py +14 -7
- owlplanner/config.py +7 -7
- owlplanner/plan.py +435 -829
- owlplanner/plotting/__init__.py +7 -0
- owlplanner/plotting/base.py +76 -0
- owlplanner/plotting/factory.py +32 -0
- owlplanner/plotting/matplotlib_backend.py +432 -0
- owlplanner/plotting/plotly_backend.py +980 -0
- owlplanner/rates.py +40 -68
- owlplanner/tax2025.py +2 -1
- owlplanner/timelists.py +3 -8
- owlplanner/version.py +1 -1
- {owlplanner-2025.5.3.dist-info → owlplanner-2025.5.12.dist-info}/METADATA +8 -5
- owlplanner-2025.5.12.dist-info/RECORD +22 -0
- owlplanner-2025.5.3.dist-info/RECORD +0 -17
- /owlplanner/{logging.py → mylogging.py} +0 -0
- {owlplanner-2025.5.3.dist-info → owlplanner-2025.5.12.dist-info}/WHEEL +0 -0
- {owlplanner-2025.5.3.dist-info → owlplanner-2025.5.12.dist-info}/licenses/LICENSE +0 -0
owlplanner/__init__.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
from owlplanner.plan import Plan
|
|
2
|
-
from owlplanner.plan import clone
|
|
3
|
-
from owlplanner.config import readConfig
|
|
4
|
-
from owlplanner.rates import getRatesDistributions
|
|
5
|
-
from owlplanner.
|
|
6
|
-
|
|
1
|
+
from owlplanner.plan import Plan # noqa: F401
|
|
2
|
+
from owlplanner.plan import clone # noqa: F401
|
|
3
|
+
from owlplanner.config import readConfig # noqa: F401
|
|
4
|
+
from owlplanner.rates import getRatesDistributions # noqa: F401
|
|
5
|
+
from owlplanner.version import __version__ # noqa: F401
|
|
6
|
+
|
|
7
|
+
# Make the package importable as 'owlplanner'
|
|
8
|
+
__all__ = ['Plan', 'clone', 'readConfig', 'getRatesDistributions', '__version__']
|
owlplanner/abcapi.py
CHANGED
|
@@ -43,14 +43,16 @@ class Row(object):
|
|
|
43
43
|
"""
|
|
44
44
|
Add an element at index ``ind`` of value ``val`` to the row.
|
|
45
45
|
"""
|
|
46
|
-
|
|
46
|
+
if not (0 <= ind < self.nvars):
|
|
47
|
+
raise ValueError(f"Index {ind} out of range.")
|
|
47
48
|
self.ind.append(ind)
|
|
48
49
|
self.val.append(val)
|
|
49
50
|
|
|
50
|
-
def addElemDic(self, rowDic=
|
|
51
|
+
def addElemDic(self, rowDic=None):
|
|
51
52
|
"""
|
|
52
53
|
Add elements at indices provided by a dictionary.
|
|
53
54
|
"""
|
|
55
|
+
rowDic = {} if rowDic is None else rowDic
|
|
54
56
|
for key in rowDic:
|
|
55
57
|
self.addElem(key, rowDic[key])
|
|
56
58
|
return self
|
|
@@ -73,11 +75,12 @@ class ConstraintMatrix(object):
|
|
|
73
75
|
self.ub = []
|
|
74
76
|
self.key = []
|
|
75
77
|
|
|
76
|
-
def newRow(self, rowDic=
|
|
78
|
+
def newRow(self, rowDic=None):
|
|
77
79
|
"""
|
|
78
80
|
Create a new row and populate its elements using the dictionary provided.
|
|
79
81
|
Return the row created.
|
|
80
82
|
"""
|
|
83
|
+
rowDic = {} if rowDic is None else rowDic
|
|
81
84
|
row = Row(self.nvars)
|
|
82
85
|
row.addElemDic(rowDic)
|
|
83
86
|
return row
|
|
@@ -157,7 +160,8 @@ class Bounds(object):
|
|
|
157
160
|
self.setBinary(ii)
|
|
158
161
|
|
|
159
162
|
def setBinary(self, ii):
|
|
160
|
-
|
|
163
|
+
if not (0 <= ii < self.nvars):
|
|
164
|
+
raise ValueError(f"Index {ii} out of range.")
|
|
161
165
|
self.ind.append(ii)
|
|
162
166
|
self.lb.append(0)
|
|
163
167
|
self.ub.append(1)
|
|
@@ -165,8 +169,10 @@ class Bounds(object):
|
|
|
165
169
|
self.integrality.append(ii)
|
|
166
170
|
|
|
167
171
|
def setRange(self, ii, lb, ub):
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
if not (0 <= ii < self.nvars):
|
|
173
|
+
raise ValueError(f"Index {ii} out of range.")
|
|
174
|
+
if lb > ub:
|
|
175
|
+
raise ValueError(f"Lower bound {lb} > upper bound {ub}.")
|
|
170
176
|
self.ind.append(ii)
|
|
171
177
|
self.lb.append(lb)
|
|
172
178
|
self.ub.append(ub)
|
|
@@ -219,7 +225,8 @@ class Objective(object):
|
|
|
219
225
|
self.val = []
|
|
220
226
|
|
|
221
227
|
def setElem(self, ind, val):
|
|
222
|
-
|
|
228
|
+
if not (0 <= ind < self.nvars):
|
|
229
|
+
raise ValueError(f"Index {ind} out of range.")
|
|
223
230
|
self.ind.append(ind)
|
|
224
231
|
self.val.append(val)
|
|
225
232
|
|
owlplanner/config.py
CHANGED
|
@@ -16,7 +16,7 @@ from datetime import date
|
|
|
16
16
|
import os
|
|
17
17
|
|
|
18
18
|
from owlplanner import plan
|
|
19
|
-
from owlplanner import
|
|
19
|
+
from owlplanner import mylogging as log
|
|
20
20
|
from owlplanner.rates import FROM, TO
|
|
21
21
|
|
|
22
22
|
|
|
@@ -122,13 +122,13 @@ def saveConfig(myplan, file, mylog):
|
|
|
122
122
|
with open(filename, "w") as casefile:
|
|
123
123
|
toml.dump(diconf, casefile, encoder=toml.TomlNumpyEncoder())
|
|
124
124
|
except Exception as e:
|
|
125
|
-
raise RuntimeError(f"Failed to save case file {filename}: {e}")
|
|
125
|
+
raise RuntimeError(f"Failed to save case file {filename}: {e}") from e
|
|
126
126
|
elif isinstance(file, StringIO):
|
|
127
127
|
try:
|
|
128
128
|
string = toml.dumps(diconf, encoder=toml.TomlNumpyEncoder())
|
|
129
129
|
file.write(string)
|
|
130
130
|
except Exception as e:
|
|
131
|
-
raise RuntimeError(f"Failed to save case to StringIO: {e}")
|
|
131
|
+
raise RuntimeError(f"Failed to save case to StringIO: {e}") from e
|
|
132
132
|
elif file is None:
|
|
133
133
|
pass
|
|
134
134
|
else:
|
|
@@ -143,7 +143,7 @@ def readConfig(file, *, verbose=True, logstreams=None, readContributions=True):
|
|
|
143
143
|
A new plan is created and returned.
|
|
144
144
|
Argument file can be a filename, a file, or a stringIO.
|
|
145
145
|
"""
|
|
146
|
-
mylog =
|
|
146
|
+
mylog = log.Logger(verbose, logstreams)
|
|
147
147
|
|
|
148
148
|
accountTypes = ["taxable", "tax-deferred", "tax-free"]
|
|
149
149
|
|
|
@@ -160,19 +160,19 @@ def readConfig(file, *, verbose=True, logstreams=None, readContributions=True):
|
|
|
160
160
|
with open(filename, "r") as f:
|
|
161
161
|
diconf = toml.load(f)
|
|
162
162
|
except Exception as e:
|
|
163
|
-
raise FileNotFoundError(f"File {filename} not found: {e}")
|
|
163
|
+
raise FileNotFoundError(f"File {filename} not found: {e}") from e
|
|
164
164
|
elif isinstance(file, BytesIO):
|
|
165
165
|
try:
|
|
166
166
|
string = file.getvalue().decode("utf-8")
|
|
167
167
|
diconf = toml.loads(string)
|
|
168
168
|
except Exception as e:
|
|
169
|
-
raise RuntimeError(f"Cannot read from BytesIO: {e}")
|
|
169
|
+
raise RuntimeError(f"Cannot read from BytesIO: {e}") from e
|
|
170
170
|
elif isinstance(file, StringIO):
|
|
171
171
|
try:
|
|
172
172
|
string = file.getvalue()
|
|
173
173
|
diconf = toml.loads(string)
|
|
174
174
|
except Exception as e:
|
|
175
|
-
raise RuntimeError(f"Cannot read from StringIO: {e}")
|
|
175
|
+
raise RuntimeError(f"Cannot read from StringIO: {e}") from e
|
|
176
176
|
else:
|
|
177
177
|
raise ValueError(f"Type {type(file)} not a valid type")
|
|
178
178
|
|