glidepath 0.2.0__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.
Files changed (93) hide show
  1. glidepath/__init__.py +3 -0
  2. glidepath/app/__init__.py +364 -0
  3. glidepath/app/backtest.py +281 -0
  4. glidepath/app/charts.py +759 -0
  5. glidepath/app/copy.py +174 -0
  6. glidepath/app/display.py +148 -0
  7. glidepath/app/drawdown.py +436 -0
  8. glidepath/app/example.py +66 -0
  9. glidepath/app/exports.py +487 -0
  10. glidepath/app/files.py +249 -0
  11. glidepath/app/firstrun.py +114 -0
  12. glidepath/app/forms.py +1750 -0
  13. glidepath/app/inspector.py +506 -0
  14. glidepath/app/labels.py +66 -0
  15. glidepath/app/montecarlo.py +399 -0
  16. glidepath/app/plan.py +354 -0
  17. glidepath/app/retirement.py +446 -0
  18. glidepath/app/scenarios.py +831 -0
  19. glidepath/app/shell.py +185 -0
  20. glidepath/app/tables.py +138 -0
  21. glidepath/core/__init__.py +390 -0
  22. glidepath/core/annuities.py +240 -0
  23. glidepath/core/backtest.py +514 -0
  24. glidepath/core/comparison.py +278 -0
  25. glidepath/core/config.py +82 -0
  26. glidepath/core/contributions.py +337 -0
  27. glidepath/core/engine.py +2811 -0
  28. glidepath/core/entities.py +264 -0
  29. glidepath/core/glide.py +289 -0
  30. glidepath/core/investments.py +175 -0
  31. glidepath/core/money.py +107 -0
  32. glidepath/core/montecarlo.py +609 -0
  33. glidepath/core/pensions.py +298 -0
  34. glidepath/core/periods.py +367 -0
  35. glidepath/core/provenance.py +271 -0
  36. glidepath/core/randomness.py +128 -0
  37. glidepath/core/region.py +46 -0
  38. glidepath/core/reporting.py +231 -0
  39. glidepath/core/results.py +504 -0
  40. glidepath/core/retirement.py +291 -0
  41. glidepath/core/returns.py +312 -0
  42. glidepath/core/scenarios.py +579 -0
  43. glidepath/core/state_pension.py +264 -0
  44. glidepath/core/tax.py +139 -0
  45. glidepath/core/withdrawals.py +461 -0
  46. glidepath/core/wrappers.py +278 -0
  47. glidepath/gui/__init__.py +6 -0
  48. glidepath/gui/assets/icon_128.png +0 -0
  49. glidepath/gui/assets/icon_16.png +0 -0
  50. glidepath/gui/assets/icon_24.png +0 -0
  51. glidepath/gui/assets/icon_256.png +0 -0
  52. glidepath/gui/assets/icon_32.png +0 -0
  53. glidepath/gui/assets/icon_48.png +0 -0
  54. glidepath/gui/assets/icon_64.png +0 -0
  55. glidepath/gui/assets/wordmark.png +0 -0
  56. glidepath/gui/charts.py +829 -0
  57. glidepath/gui/forms.py +359 -0
  58. glidepath/gui/inspector.py +186 -0
  59. glidepath/gui/main.py +51 -0
  60. glidepath/gui/scenarios.py +402 -0
  61. glidepath/gui/style.py +376 -0
  62. glidepath/gui/tableview.py +67 -0
  63. glidepath/gui/widgets.py +989 -0
  64. glidepath/persistence/__init__.py +48 -0
  65. glidepath/persistence/assumptions.py +112 -0
  66. glidepath/persistence/decode.py +747 -0
  67. glidepath/persistence/document.py +101 -0
  68. glidepath/persistence/encode.py +433 -0
  69. glidepath/persistence/migrations.py +158 -0
  70. glidepath/persistence/values.py +298 -0
  71. glidepath/py.typed +0 -0
  72. glidepath/regions/__init__.py +7 -0
  73. glidepath/regions/uk/__init__.py +189 -0
  74. glidepath/regions/uk/ages.py +156 -0
  75. glidepath/regions/uk/contributions.py +717 -0
  76. glidepath/regions/uk/data/age_rules.toml +78 -0
  77. glidepath/regions/uk/data/assumptions_default.toml +170 -0
  78. glidepath/regions/uk/data/returns_history.toml +150 -0
  79. glidepath/regions/uk/data/tax_year_2026_27.toml +98 -0
  80. glidepath/regions/uk/extension.py +479 -0
  81. glidepath/regions/uk/loader.py +704 -0
  82. glidepath/regions/uk/region.py +160 -0
  83. glidepath/regions/uk/schema.py +563 -0
  84. glidepath/regions/uk/state_pension.py +129 -0
  85. glidepath/regions/uk/tax.py +466 -0
  86. glidepath/regions/uk/wrappers.py +283 -0
  87. glidepath/regions/uk/years.py +92 -0
  88. glidepath-0.2.0.dist-info/METADATA +189 -0
  89. glidepath-0.2.0.dist-info/RECORD +93 -0
  90. glidepath-0.2.0.dist-info/WHEEL +4 -0
  91. glidepath-0.2.0.dist-info/entry_points.txt +3 -0
  92. glidepath-0.2.0.dist-info/licenses/LICENSE +21 -0
  93. glidepath-0.2.0.dist-info/licenses/LICENSE-DATA +28 -0
glidepath/app/shell.py ADDED
@@ -0,0 +1,185 @@
1
+ """Shell view models: everything a UI shell renders, as plain data (§4.7).
2
+
3
+ Shells (PySide6 today, possibly web later) bind these to widgets and
4
+ forward user actions back; they add no copy or formatting of their own.
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+ from importlib import metadata
9
+ from typing import TYPE_CHECKING
10
+
11
+ from glidepath.app.copy import (
12
+ ABOUT_TITLE,
13
+ APP_NAME,
14
+ DISCLAIMER_ACCEPT_LABEL,
15
+ DISCLAIMER_BODY,
16
+ DISCLAIMER_DECLINE_LABEL,
17
+ DISCLAIMER_TITLE,
18
+ HELP_GUIDE_INTRO,
19
+ HELP_GUIDE_SECTIONS,
20
+ HELP_GUIDE_TITLE,
21
+ HELP_MENU_LABEL,
22
+ )
23
+ from glidepath.app.exports import (
24
+ CASH_FLOW_FILE_FILTER,
25
+ CASH_FLOW_FILE_SUFFIX,
26
+ EXPORT_CASH_FLOW_DIALOG_TITLE,
27
+ EXPORT_CASH_FLOW_LABEL,
28
+ EXPORT_REPORT_DIALOG_TITLE,
29
+ EXPORT_REPORT_LABEL,
30
+ REPORT_FILE_FILTER,
31
+ REPORT_FILE_SUFFIX,
32
+ )
33
+ from glidepath.app.files import (
34
+ FILE_MENU_LABEL,
35
+ OPEN_DIALOG_TITLE,
36
+ OPEN_PLAN_LABEL,
37
+ PLAN_FILE_FILTER,
38
+ PLAN_FILE_SUFFIX,
39
+ QUIT_LABEL,
40
+ SAVE_DIALOG_TITLE,
41
+ SAVE_PLAN_AS_LABEL,
42
+ SAVE_PLAN_LABEL,
43
+ )
44
+ from glidepath.app.forms import FactsFormViewModel, build_facts_form_view_model
45
+
46
+ if TYPE_CHECKING:
47
+ from glidepath.app.firstrun import FirstRunState
48
+
49
+
50
+ @dataclass(frozen=True)
51
+ class FileMenuViewModel:
52
+ """The File menu: open, save, and export the plan (§4.5, 9.19)."""
53
+
54
+ menu_label: str
55
+ open_label: str
56
+ save_label: str
57
+ save_as_label: str
58
+ open_dialog_title: str
59
+ save_dialog_title: str
60
+ file_filter: str
61
+ file_suffix: str
62
+ export_cash_flow_label: str
63
+ export_cash_flow_dialog_title: str
64
+ export_cash_flow_filter: str
65
+ export_cash_flow_suffix: str
66
+ export_report_label: str
67
+ export_report_dialog_title: str
68
+ export_report_filter: str
69
+ export_report_suffix: str
70
+ quit_label: str
71
+
72
+
73
+ @dataclass(frozen=True)
74
+ class DisclaimerViewModel:
75
+ """The first-run disclaimer screen (§1 product requirement)."""
76
+
77
+ title: str
78
+ body: str
79
+ accept_label: str
80
+ decline_label: str
81
+
82
+
83
+ @dataclass(frozen=True)
84
+ class AboutViewModel:
85
+ """The About screen; repeats the disclaimer (§1 product requirement)."""
86
+
87
+ title: str
88
+ body: str
89
+
90
+
91
+ @dataclass(frozen=True)
92
+ class HelpSectionViewModel:
93
+ """One titled passage of the how-to-use guide."""
94
+
95
+ heading: str
96
+ body: str
97
+
98
+
99
+ @dataclass(frozen=True)
100
+ class HelpGuideViewModel:
101
+ """The how-to-use guide: what each part of the shell is for."""
102
+
103
+ title: str
104
+ intro: str
105
+ sections: tuple[HelpSectionViewModel, ...]
106
+
107
+
108
+ @dataclass(frozen=True)
109
+ class ShellViewModel:
110
+ """Top-level application shell."""
111
+
112
+ window_title: str
113
+ file_menu: FileMenuViewModel
114
+ help_menu_label: str
115
+ facts_tab_label: str
116
+ charts_tab_label: str
117
+ scenarios_tab_label: str
118
+ inspector_tab_label: str
119
+ disclaimer: DisclaimerViewModel
120
+ about: AboutViewModel
121
+ help_guide: HelpGuideViewModel
122
+ facts_form: FactsFormViewModel
123
+
124
+
125
+ def _installed_version() -> str:
126
+ """The installed distribution version, or a placeholder outside an install."""
127
+ try:
128
+ return metadata.version(APP_NAME)
129
+ except metadata.PackageNotFoundError:
130
+ return "unknown"
131
+
132
+
133
+ def build_shell_view_model() -> ShellViewModel:
134
+ """Assemble the shell view model from canonical copy and metadata."""
135
+ return ShellViewModel(
136
+ window_title=APP_NAME,
137
+ file_menu=FileMenuViewModel(
138
+ menu_label=FILE_MENU_LABEL,
139
+ open_label=OPEN_PLAN_LABEL,
140
+ save_label=SAVE_PLAN_LABEL,
141
+ save_as_label=SAVE_PLAN_AS_LABEL,
142
+ open_dialog_title=OPEN_DIALOG_TITLE,
143
+ save_dialog_title=SAVE_DIALOG_TITLE,
144
+ file_filter=PLAN_FILE_FILTER,
145
+ file_suffix=PLAN_FILE_SUFFIX,
146
+ export_cash_flow_label=EXPORT_CASH_FLOW_LABEL,
147
+ export_cash_flow_dialog_title=EXPORT_CASH_FLOW_DIALOG_TITLE,
148
+ export_cash_flow_filter=CASH_FLOW_FILE_FILTER,
149
+ export_cash_flow_suffix=CASH_FLOW_FILE_SUFFIX,
150
+ export_report_label=EXPORT_REPORT_LABEL,
151
+ export_report_dialog_title=EXPORT_REPORT_DIALOG_TITLE,
152
+ export_report_filter=REPORT_FILE_FILTER,
153
+ export_report_suffix=REPORT_FILE_SUFFIX,
154
+ quit_label=QUIT_LABEL,
155
+ ),
156
+ help_menu_label=HELP_MENU_LABEL,
157
+ facts_tab_label="Facts",
158
+ charts_tab_label="Charts",
159
+ scenarios_tab_label="Scenarios",
160
+ inspector_tab_label="Stated vs assumed",
161
+ disclaimer=DisclaimerViewModel(
162
+ title=DISCLAIMER_TITLE,
163
+ body=DISCLAIMER_BODY,
164
+ accept_label=DISCLAIMER_ACCEPT_LABEL,
165
+ decline_label=DISCLAIMER_DECLINE_LABEL,
166
+ ),
167
+ about=AboutViewModel(
168
+ title=ABOUT_TITLE,
169
+ body=f"{APP_NAME} {_installed_version()}\n\n{DISCLAIMER_BODY}",
170
+ ),
171
+ help_guide=HelpGuideViewModel(
172
+ title=HELP_GUIDE_TITLE,
173
+ intro=HELP_GUIDE_INTRO,
174
+ sections=tuple(
175
+ HelpSectionViewModel(heading=heading, body=body)
176
+ for heading, body in HELP_GUIDE_SECTIONS
177
+ ),
178
+ ),
179
+ facts_form=build_facts_form_view_model(),
180
+ )
181
+
182
+
183
+ def should_show_disclaimer(state: FirstRunState) -> bool:
184
+ """The disclaimer shows on every run until an acknowledgement is recorded."""
185
+ return state.disclaimer_acknowledged_on is None
@@ -0,0 +1,138 @@
1
+ """Text form for table-valued assumption overrides (planning §1, issue #70/#71).
2
+
3
+ Structured defaults are edited as plain text — one ``key = value``
4
+ line per figure, dotted keys for nested tables — so every shipped
5
+ default is overridable in place without a bespoke editor per table
6
+ shape. Serialising and parsing are exact inverses over the value
7
+ shapes the catalogue holds (planning §7): ``Decimal`` and ``int``
8
+ figures, string tags, and nested tables. Content validation is not
9
+ this module's job — the per-key policy parsers vet a parsed table
10
+ before it can reach the assumption set (:mod:`glidepath.app.plan`).
11
+ """
12
+
13
+ import re
14
+ from collections.abc import Mapping
15
+ from decimal import Decimal, InvalidOperation
16
+ from typing import TYPE_CHECKING
17
+
18
+ if TYPE_CHECKING:
19
+ from glidepath.regions.uk import AssumptionValue
20
+
21
+ _INT_PATTERN = re.compile(r"[+-]?\d+")
22
+
23
+
24
+ def table_edit_text(value: Mapping[str, object]) -> str:
25
+ """The table as editable text: one ``key = value`` line per figure.
26
+
27
+ Nested tables flatten to dotted keys, so the text round-trips
28
+ through :func:`parse_table_text` for every shipped table shape.
29
+ """
30
+ lines: list[str] = []
31
+ _serialise(lines, value, prefix="")
32
+ return "\n".join(lines)
33
+
34
+
35
+ def _serialise(lines: list[str], table: Mapping[str, object], prefix: str) -> None:
36
+ """Append one dotted-key line per leaf of ``table`` to ``lines``."""
37
+ for key, entry in table.items():
38
+ path = f"{prefix}{key}"
39
+ if isinstance(entry, Mapping):
40
+ _serialise(lines, entry, f"{path}.")
41
+ else:
42
+ lines.append(f"{path} = {_leaf_text(entry)}")
43
+
44
+
45
+ def _leaf_text(entry: object) -> str:
46
+ """One leaf value as text that re-parses to an equal figure.
47
+
48
+ An integral ``Decimal`` (e.g. a hand-edited plan's ``1``) would
49
+ otherwise serialise to bare-integer text and re-parse as ``int``,
50
+ which the policy parsers reject — so it gains a fractional digit,
51
+ keeping numeric equality.
52
+ """
53
+ text = str(entry)
54
+ if isinstance(entry, Decimal) and _INT_PATTERN.fullmatch(text):
55
+ return f"{text}.0"
56
+ return text
57
+
58
+
59
+ def parse_table_text(text: str) -> dict[str, AssumptionValue]:
60
+ """Parse ``key = value`` lines back into a nested table.
61
+
62
+ Whole numbers parse as ``int``, other numerics as ``Decimal``, and
63
+ anything else as a string tag — the same convention the catalogue's
64
+ TOML loader applies, so a serialised default parses back exactly.
65
+ Blank lines are ignored.
66
+
67
+ Raises:
68
+ ValueError: On a line without ``=``, a missing value, an empty
69
+ key segment, or a duplicate/conflicting key path.
70
+ """
71
+ table: dict[str, AssumptionValue] = {}
72
+ for line in text.splitlines():
73
+ stripped = line.strip()
74
+ if not stripped:
75
+ continue
76
+ key_text, separator, value_text = stripped.partition("=")
77
+ if not separator:
78
+ msg = f"line {stripped!r}: expected 'key = value'"
79
+ raise ValueError(msg)
80
+ raw_value = value_text.strip()
81
+ if not raw_value:
82
+ msg = f"line {stripped!r}: missing value"
83
+ raise ValueError(msg)
84
+ path = [segment.strip() for segment in key_text.strip().split(".")]
85
+ if not all(path):
86
+ msg = f"line {stripped!r}: empty key"
87
+ raise ValueError(msg)
88
+ _assign(table, path, _parsed_scalar(raw_value))
89
+ return table
90
+
91
+
92
+ def _assign(
93
+ table: dict[str, AssumptionValue], path: list[str], value: AssumptionValue
94
+ ) -> None:
95
+ """Set ``value`` at the dotted ``path`` in ``table``, refusing conflicts.
96
+
97
+ Raises:
98
+ ValueError: If the path duplicates an earlier line or mixes a
99
+ figure with a nested table at the same key.
100
+ """
101
+ node = table
102
+ for depth, segment in enumerate(path[:-1], start=1):
103
+ child = node.setdefault(segment, {})
104
+ if not isinstance(child, dict):
105
+ # A user-text conflict, not a Python typing error, so the
106
+ # message must travel the ValueError rejection channel.
107
+ msg = f"key {'.'.join(path[:depth])!r} holds both a value and a table"
108
+ raise ValueError(msg) # noqa: TRY004
109
+ node = child
110
+ leaf = path[-1]
111
+ if leaf in node:
112
+ msg = f"duplicate key {'.'.join(path)!r}"
113
+ raise ValueError(msg)
114
+ node[leaf] = value
115
+
116
+
117
+ def _parsed_scalar(raw: str) -> AssumptionValue:
118
+ """The typed value one line's text denotes.
119
+
120
+ Non-finite numerics (``Infinity``, ``NaN``) fall through as string
121
+ tags — the policy parsers reject them by type, so they can never
122
+ enter a table as figures.
123
+ """
124
+ if _INT_PATTERN.fullmatch(raw):
125
+ return int(raw)
126
+ try:
127
+ value = Decimal(raw)
128
+ except InvalidOperation:
129
+ return raw
130
+ if not value.is_finite():
131
+ return raw
132
+ return value
133
+
134
+
135
+ __all__ = [
136
+ "parse_table_text",
137
+ "table_edit_text",
138
+ ]
@@ -0,0 +1,390 @@
1
+ """Region-agnostic core primitives (roadmap Phase 1).
2
+
3
+ The core defines value types, calendars, provenance kinds and entities.
4
+ It never imports region code (planning §4.2) — enforced by a guard test —
5
+ and never contains policy figures, which live in region data files.
6
+ """
7
+
8
+ from glidepath.core.annuities import (
9
+ AnnuityBasis,
10
+ AnnuityPurchase,
11
+ AnnuityRateTable,
12
+ AnnuityType,
13
+ annuity_base_rate_key,
14
+ annuity_start_date,
15
+ )
16
+ from glidepath.core.backtest import (
17
+ BacktestResult,
18
+ HistoricalSeries,
19
+ HistoricalWindowModel,
20
+ HistoricalYear,
21
+ WindowOutcome,
22
+ historical_window_factory,
23
+ run_windows,
24
+ )
25
+ from glidepath.core.comparison import (
26
+ BASE_RUN_NAME,
27
+ ComparisonRow,
28
+ PeriodMetrics,
29
+ ScenarioComparison,
30
+ ScenarioPeriodEntry,
31
+ compare_scenario_results,
32
+ run_scenarios,
33
+ )
34
+ from glidepath.core.config import EngineError, RunConfig, RunMode
35
+ from glidepath.core.contributions import (
36
+ AnnualAllowanceFunding,
37
+ AnnualAllowanceMeasurement,
38
+ AnnualAllowanceOutcome,
39
+ ContributionRuleset,
40
+ ContributionSchedule,
41
+ DbArrangementInput,
42
+ MemberContributionOutcome,
43
+ MemberContributionRequest,
44
+ SchemeInput,
45
+ SchemePayment,
46
+ )
47
+ from glidepath.core.engine import run
48
+ from glidepath.core.entities import (
49
+ EntityId,
50
+ Household,
51
+ Person,
52
+ PlannedOutflow,
53
+ Sex,
54
+ SpendingPlan,
55
+ TaxResidencyId,
56
+ new_entity_id,
57
+ validate_household_v1,
58
+ )
59
+ from glidepath.core.glide import (
60
+ GlidePathConfig,
61
+ GlidePathPoint,
62
+ LifeStage,
63
+ glide_path_from_shape,
64
+ years_to_target_retirement,
65
+ )
66
+ from glidepath.core.investments import (
67
+ AssetAllocation,
68
+ AssetReturns,
69
+ FeesAndGrowthOutcome,
70
+ FeeSchedule,
71
+ apply_fees_and_growth,
72
+ period_fee,
73
+ )
74
+ from glidepath.core.money import Money, Rate
75
+ from glidepath.core.montecarlo import (
76
+ MonteCarloResult,
77
+ PathOutcome,
78
+ PathParallelism,
79
+ SustainableIncomeSearch,
80
+ run_paths,
81
+ sustainable_income,
82
+ )
83
+ from glidepath.core.pensions import (
84
+ DBActiveMembership,
85
+ DBPension,
86
+ FactorTable,
87
+ RevaluationBasis,
88
+ RevaluationReference,
89
+ db_early_late_factor,
90
+ db_service_end_date,
91
+ db_start_date,
92
+ db_taken_age,
93
+ revaluation_factor_for_months,
94
+ )
95
+ from glidepath.core.periods import (
96
+ AgeRules,
97
+ AnnualCalendar,
98
+ FiscalCalendar,
99
+ Period,
100
+ add_months,
101
+ age_on,
102
+ birthday_in_year,
103
+ date_age_attained,
104
+ entitlement_active_fraction,
105
+ is_age_attained_by_period_start,
106
+ period_active_fraction,
107
+ prorata_fraction,
108
+ service_active_fraction,
109
+ whole_months_between,
110
+ )
111
+ from glidepath.core.provenance import (
112
+ Assumption,
113
+ AssumptionKey,
114
+ AssumptionReadRecorder,
115
+ AssumptionSet,
116
+ Decision,
117
+ Fact,
118
+ Provenance,
119
+ TrackedAssumptions,
120
+ decimal_assumption_value,
121
+ int_assumption_value,
122
+ mapping_assumption_value,
123
+ )
124
+ from glidepath.core.randomness import (
125
+ RandomSource,
126
+ SeededRandomSource,
127
+ derive_seed,
128
+ )
129
+ from glidepath.core.region import Region
130
+ from glidepath.core.reporting import (
131
+ PeriodReportRow,
132
+ ProjectionReport,
133
+ ReportBasis,
134
+ WrapperReportBalance,
135
+ build_report,
136
+ )
137
+ from glidepath.core.results import (
138
+ BalanceRollForward,
139
+ LabelledDecision,
140
+ LabelledFact,
141
+ PeriodSnapshot,
142
+ PersonPeriodResult,
143
+ ProjectionResult,
144
+ RunProvenance,
145
+ WrapperPeriodResult,
146
+ collect_plan_decisions,
147
+ collect_plan_facts,
148
+ )
149
+ from glidepath.core.retirement import (
150
+ RetirementAgeSearch,
151
+ earliest_retirement_age,
152
+ sustainable_income_at_age,
153
+ )
154
+ from glidepath.core.returns import (
155
+ DeterministicReturnModel,
156
+ PeriodReturns,
157
+ ReturnModel,
158
+ ReturnModelFactory,
159
+ StochasticReturnModel,
160
+ cholesky_lower,
161
+ nominal_rate,
162
+ )
163
+ from glidepath.core.scenarios import (
164
+ AppliedOverride,
165
+ AssumptionTarget,
166
+ DecisionTarget,
167
+ DecisionTargetInfo,
168
+ Override,
169
+ OverrideTarget,
170
+ Scenario,
171
+ ScenarioError,
172
+ ScenarioResolution,
173
+ decision_target_catalogue,
174
+ is_scenario_valid,
175
+ resolve_scenario,
176
+ scenario_orphans,
177
+ )
178
+ from glidepath.core.state_pension import (
179
+ StatePensionEntitlement,
180
+ StatePensionRecord,
181
+ StatePensionScheme,
182
+ StatePensionUprating,
183
+ UpratingRule,
184
+ deferral_months,
185
+ )
186
+ from glidepath.core.tax import TaxInput, TaxLine, TaxResult, TaxSystem
187
+ from glidepath.core.withdrawals import (
188
+ FixedPercentWithdrawalStrategy,
189
+ FixedRealWithdrawalStrategy,
190
+ GrossDraw,
191
+ GrossWithdrawalPlan,
192
+ GuardrailsWithdrawalStrategy,
193
+ NaturalYieldWithdrawalStrategy,
194
+ NetWithdrawalPlan,
195
+ TaxFreeCashStrategy,
196
+ WithdrawalPlan,
197
+ WithdrawalSource,
198
+ WithdrawalSourceId,
199
+ WithdrawalState,
200
+ WithdrawalStrategy,
201
+ tax_aware_order,
202
+ )
203
+ from glidepath.core.wrappers import (
204
+ ContributionCap,
205
+ ContributionTaxTreatment,
206
+ ContributionTerms,
207
+ GrowthTaxTreatment,
208
+ ReliefMechanic,
209
+ WithdrawalTaxTreatment,
210
+ Wrapper,
211
+ WrapperKindId,
212
+ WrapperRuleset,
213
+ WrapperTaxTreatment,
214
+ )
215
+
216
+ __all__ = [
217
+ "BASE_RUN_NAME",
218
+ "AgeRules",
219
+ "AnnualAllowanceFunding",
220
+ "AnnualAllowanceMeasurement",
221
+ "AnnualAllowanceOutcome",
222
+ "AnnualCalendar",
223
+ "AnnuityBasis",
224
+ "AnnuityPurchase",
225
+ "AnnuityRateTable",
226
+ "AnnuityType",
227
+ "AppliedOverride",
228
+ "AssetAllocation",
229
+ "AssetReturns",
230
+ "Assumption",
231
+ "AssumptionKey",
232
+ "AssumptionReadRecorder",
233
+ "AssumptionSet",
234
+ "AssumptionTarget",
235
+ "BacktestResult",
236
+ "BalanceRollForward",
237
+ "ComparisonRow",
238
+ "ContributionCap",
239
+ "ContributionRuleset",
240
+ "ContributionSchedule",
241
+ "ContributionTaxTreatment",
242
+ "ContributionTerms",
243
+ "DBActiveMembership",
244
+ "DBPension",
245
+ "DbArrangementInput",
246
+ "Decision",
247
+ "DecisionTarget",
248
+ "DecisionTargetInfo",
249
+ "DeterministicReturnModel",
250
+ "EngineError",
251
+ "EntityId",
252
+ "Fact",
253
+ "FactorTable",
254
+ "FeeSchedule",
255
+ "FeesAndGrowthOutcome",
256
+ "FiscalCalendar",
257
+ "FixedPercentWithdrawalStrategy",
258
+ "FixedRealWithdrawalStrategy",
259
+ "GlidePathConfig",
260
+ "GlidePathPoint",
261
+ "GrossDraw",
262
+ "GrossWithdrawalPlan",
263
+ "GrowthTaxTreatment",
264
+ "GuardrailsWithdrawalStrategy",
265
+ "HistoricalSeries",
266
+ "HistoricalWindowModel",
267
+ "HistoricalYear",
268
+ "Household",
269
+ "LabelledDecision",
270
+ "LabelledFact",
271
+ "LifeStage",
272
+ "MemberContributionOutcome",
273
+ "MemberContributionRequest",
274
+ "Money",
275
+ "MonteCarloResult",
276
+ "NaturalYieldWithdrawalStrategy",
277
+ "NetWithdrawalPlan",
278
+ "Override",
279
+ "OverrideTarget",
280
+ "PathOutcome",
281
+ "PathParallelism",
282
+ "Period",
283
+ "PeriodMetrics",
284
+ "PeriodReportRow",
285
+ "PeriodReturns",
286
+ "PeriodSnapshot",
287
+ "Person",
288
+ "PersonPeriodResult",
289
+ "PlannedOutflow",
290
+ "ProjectionReport",
291
+ "ProjectionResult",
292
+ "Provenance",
293
+ "RandomSource",
294
+ "Rate",
295
+ "Region",
296
+ "ReliefMechanic",
297
+ "ReportBasis",
298
+ "RetirementAgeSearch",
299
+ "ReturnModel",
300
+ "ReturnModelFactory",
301
+ "RevaluationBasis",
302
+ "RevaluationReference",
303
+ "RunConfig",
304
+ "RunMode",
305
+ "RunProvenance",
306
+ "Scenario",
307
+ "ScenarioComparison",
308
+ "ScenarioError",
309
+ "ScenarioPeriodEntry",
310
+ "ScenarioResolution",
311
+ "SchemeInput",
312
+ "SchemePayment",
313
+ "SeededRandomSource",
314
+ "Sex",
315
+ "SpendingPlan",
316
+ "StatePensionEntitlement",
317
+ "StatePensionRecord",
318
+ "StatePensionScheme",
319
+ "StatePensionUprating",
320
+ "StochasticReturnModel",
321
+ "SustainableIncomeSearch",
322
+ "TaxFreeCashStrategy",
323
+ "TaxInput",
324
+ "TaxLine",
325
+ "TaxResidencyId",
326
+ "TaxResult",
327
+ "TaxSystem",
328
+ "TrackedAssumptions",
329
+ "UpratingRule",
330
+ "WindowOutcome",
331
+ "WithdrawalPlan",
332
+ "WithdrawalSource",
333
+ "WithdrawalSourceId",
334
+ "WithdrawalState",
335
+ "WithdrawalStrategy",
336
+ "WithdrawalTaxTreatment",
337
+ "Wrapper",
338
+ "WrapperKindId",
339
+ "WrapperPeriodResult",
340
+ "WrapperReportBalance",
341
+ "WrapperRuleset",
342
+ "WrapperTaxTreatment",
343
+ "add_months",
344
+ "age_on",
345
+ "annuity_base_rate_key",
346
+ "annuity_start_date",
347
+ "apply_fees_and_growth",
348
+ "birthday_in_year",
349
+ "build_report",
350
+ "cholesky_lower",
351
+ "collect_plan_decisions",
352
+ "collect_plan_facts",
353
+ "compare_scenario_results",
354
+ "date_age_attained",
355
+ "db_early_late_factor",
356
+ "db_service_end_date",
357
+ "db_start_date",
358
+ "db_taken_age",
359
+ "decimal_assumption_value",
360
+ "decision_target_catalogue",
361
+ "deferral_months",
362
+ "derive_seed",
363
+ "earliest_retirement_age",
364
+ "entitlement_active_fraction",
365
+ "glide_path_from_shape",
366
+ "historical_window_factory",
367
+ "int_assumption_value",
368
+ "is_age_attained_by_period_start",
369
+ "is_scenario_valid",
370
+ "mapping_assumption_value",
371
+ "new_entity_id",
372
+ "nominal_rate",
373
+ "period_active_fraction",
374
+ "period_fee",
375
+ "prorata_fraction",
376
+ "resolve_scenario",
377
+ "revaluation_factor_for_months",
378
+ "run",
379
+ "run_paths",
380
+ "run_scenarios",
381
+ "run_windows",
382
+ "scenario_orphans",
383
+ "service_active_fraction",
384
+ "sustainable_income",
385
+ "sustainable_income_at_age",
386
+ "tax_aware_order",
387
+ "validate_household_v1",
388
+ "whole_months_between",
389
+ "years_to_target_retirement",
390
+ ]