modelflowib 2.77__tar.gz → 2.78__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.
- {modelflowib-2.77 → modelflowib-2.78}/PKG-INFO +1 -1
- {modelflowib-2.77 → modelflowib-2.78}/modelconstruct_estimation.py +64 -7
- {modelflowib-2.77 → modelflowib-2.78}/modelestimator_new.py +133 -1
- {modelflowib-2.77 → modelflowib-2.78}/modelflowib.egg-info/PKG-INFO +1 -1
- {modelflowib-2.77 → modelflowib-2.78}/modelhtml.py +22 -5
- {modelflowib-2.77 → modelflowib-2.78}/pyproject.toml +1 -1
- {modelflowib-2.77 → modelflowib-2.78}/README.md +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/license.md +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelBLfunk.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/model_Excel.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/model_cvx.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/model_dynare.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/model_financial_stability.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/model_latex.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/model_latex_class.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/model_parquet_mixin.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelclass.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelconstruct.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeldash.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeldashboot.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeldashsidebar.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeldekom.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeldiff.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeldisplay.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelestimation.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelflowib.egg-info/SOURCES.txt +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelflowib.egg-info/dependency_links.txt +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelflowib.egg-info/requires.txt +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelflowib.egg-info/top_level.txt +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelgrab.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelgrabgdx.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelgrabwf2.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelhelp.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelinvert.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeljupyter.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeljupytermagic.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelmacrograb.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelmanipulation.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelmf.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelnet.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelnewton.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelnormalize.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelpattern.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelreport.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelsolver_ng.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modeluserfunk.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelvis.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelwidget.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/modelwidget_input.py +0 -0
- {modelflowib-2.77 → modelflowib-2.78}/setup.cfg +0 -0
|
@@ -1781,15 +1781,34 @@ def _estimation_record_to_markdown(record: dict) -> str:
|
|
|
1781
1781
|
|
|
1782
1782
|
coefs = _estimator_coefficients_for_markdown(est)
|
|
1783
1783
|
if coefs:
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1784
|
+
try:
|
|
1785
|
+
tvals = est.tvalues.to_dict()
|
|
1786
|
+
except Exception:
|
|
1787
|
+
tvals = {}
|
|
1788
|
+
# NaN != NaN — only add the column when at least one t-stat exists.
|
|
1789
|
+
has_t = any(v == v for v in tvals.values())
|
|
1790
|
+
if has_t:
|
|
1791
|
+
lines.extend([
|
|
1792
|
+
"",
|
|
1793
|
+
"| Parameter | Estimate | t-stat |",
|
|
1794
|
+
"|:--|--:|--:|",
|
|
1795
|
+
])
|
|
1796
|
+
else:
|
|
1797
|
+
lines.extend([
|
|
1798
|
+
"",
|
|
1799
|
+
"| Parameter | Estimate |",
|
|
1800
|
+
"|:--|--:|",
|
|
1801
|
+
])
|
|
1789
1802
|
for key in sorted(coefs, key=lambda x: (str(x).split("__")[0], int(str(x).split("__")[-1]) if str(x).split("__")[-1].lstrip("-").isdigit() else str(x))):
|
|
1790
|
-
|
|
1791
|
-
f"| {_markdown_escape_cell(key)}
|
|
1803
|
+
row = (
|
|
1804
|
+
f"| {_markdown_escape_cell(key)} "
|
|
1805
|
+
f"| {_markdown_escape_cell(_markdown_format_number(coefs[key]))} |"
|
|
1792
1806
|
)
|
|
1807
|
+
if has_t:
|
|
1808
|
+
t = tvals.get(key)
|
|
1809
|
+
t_cell = f"{t:.3f}" if t is not None and t == t else ""
|
|
1810
|
+
row += f" {_markdown_escape_cell(t_cell)} |"
|
|
1811
|
+
lines.append(row)
|
|
1793
1812
|
|
|
1794
1813
|
return "\n".join(lines) + "\n"
|
|
1795
1814
|
|
|
@@ -2429,6 +2448,31 @@ class Makemodel(BaseExplode):
|
|
|
2429
2448
|
"""
|
|
2430
2449
|
return MakeModelReport(self, title=title, plot_format=plot_format, report_all=report_all)
|
|
2431
2450
|
|
|
2451
|
+
@property
|
|
2452
|
+
def tvalues(self):
|
|
2453
|
+
"""t-statistics for all estimated equations as a DataFrame.
|
|
2454
|
+
|
|
2455
|
+
Rows are parameter tokens (``C__1``, ``C__2``, ...), one column per
|
|
2456
|
+
estimated equation named by its endogenous variable. NaN where a
|
|
2457
|
+
parameter is not in that equation or the backend provides no
|
|
2458
|
+
t-statistic (fixed/derived parameters, failed covariance, EViews
|
|
2459
|
+
``NA`` rows).
|
|
2460
|
+
|
|
2461
|
+
Per-equation access: ``rec['estimator_object'].tvalues`` on the
|
|
2462
|
+
entries of :attr:`estimation_records`.
|
|
2463
|
+
"""
|
|
2464
|
+
import pandas as pd
|
|
2465
|
+
cols = {}
|
|
2466
|
+
for rec in self.estimation_records:
|
|
2467
|
+
est = rec.get('estimator_object')
|
|
2468
|
+
try:
|
|
2469
|
+
ser = est.tvalues
|
|
2470
|
+
except Exception:
|
|
2471
|
+
continue
|
|
2472
|
+
name = getattr(est, 'endo_var', '') or rec.get('frmlname', '')
|
|
2473
|
+
cols[name] = ser
|
|
2474
|
+
return pd.DataFrame(cols)
|
|
2475
|
+
|
|
2432
2476
|
@property
|
|
2433
2477
|
def markdown_with_estimation(self) -> str:
|
|
2434
2478
|
"""Original Markdown input with compact estimation tables inserted.
|
|
@@ -2816,6 +2860,19 @@ class Listmodels(BaseExplode):
|
|
|
2816
2860
|
"""
|
|
2817
2861
|
return MakeModelReport(self, title=title, plot_format=plot_format, report_all=report_all)
|
|
2818
2862
|
|
|
2863
|
+
@property
|
|
2864
|
+
def tvalues(self):
|
|
2865
|
+
"""t-statistics of all member Makemodels, combined column-wise.
|
|
2866
|
+
|
|
2867
|
+
See :attr:`Makemodel.tvalues` for the layout.
|
|
2868
|
+
"""
|
|
2869
|
+
import pandas as pd
|
|
2870
|
+
frames = [mex.tvalues for mex in self.makemodels]
|
|
2871
|
+
frames = [f for f in frames if not f.empty]
|
|
2872
|
+
if not frames:
|
|
2873
|
+
return pd.DataFrame()
|
|
2874
|
+
return pd.concat(frames, axis=1)
|
|
2875
|
+
|
|
2819
2876
|
@property
|
|
2820
2877
|
def markdown_with_estimation(self) -> str:
|
|
2821
2878
|
"""Concatenate member Makemodel markdown-with-estimation strings."""
|
|
@@ -99,6 +99,7 @@ from lmfit import Parameters, minimize
|
|
|
99
99
|
from matplotlib.gridspec import GridSpec
|
|
100
100
|
|
|
101
101
|
from modelclass import model
|
|
102
|
+
from modelmanipulation import check_syntax
|
|
102
103
|
import modelnormalize as nz
|
|
103
104
|
|
|
104
105
|
|
|
@@ -904,6 +905,13 @@ class Eq_parent:
|
|
|
904
905
|
raw = self.org_eq.upper()
|
|
905
906
|
eq_body, constraint_text = _split_st_clause(raw)
|
|
906
907
|
|
|
908
|
+
# 2a) Syntax-check the equation text BEFORE parameter-token
|
|
909
|
+
# normalization. Typos like ``C(1)2020`` (missing ``*D``) or a
|
|
910
|
+
# missing ``+`` between terms are clean SyntaxErrors here, but
|
|
911
|
+
# after normalization they can merge into single valid
|
|
912
|
+
# identifiers and slip through to give degenerate fits.
|
|
913
|
+
self._check_eq_syntax(eq_body)
|
|
914
|
+
|
|
907
915
|
# 2) Normalize parameter tokens in both equation body AND constraints
|
|
908
916
|
# so names align downstream (e.g. ``C(1)`` -> ``C__1``).
|
|
909
917
|
eq = _normalize_param_tokens(eq_body, self.est_param, self.param_names)
|
|
@@ -946,6 +954,7 @@ class Eq_parent:
|
|
|
946
954
|
# Subclasses that need a custom dataframe layout (e.g. mfcalc-built
|
|
947
955
|
# regressors for OLS) handle that themselves.
|
|
948
956
|
if self.input_df is not None:
|
|
957
|
+
self._check_unknown_variables()
|
|
949
958
|
self.eq_var_df = (
|
|
950
959
|
self.mdummy.insertModelVar(self.input_df)
|
|
951
960
|
.loc[:, self.varname_all]
|
|
@@ -953,7 +962,49 @@ class Eq_parent:
|
|
|
953
962
|
)
|
|
954
963
|
self.estimation_df = self.eq_var_df
|
|
955
964
|
|
|
956
|
-
|
|
965
|
+
@staticmethod
|
|
966
|
+
def _check_eq_syntax(eq_body: str) -> None:
|
|
967
|
+
"""Raise ``SyntaxError`` (with a pinpointed location) if the equation
|
|
968
|
+
text does not parse as Python expressions.
|
|
969
|
+
|
|
970
|
+
Each side of the first ``=`` is checked separately — the full
|
|
971
|
+
statement would be an invalid Python assignment whenever the LHS is
|
|
972
|
+
a transformation like ``DLOG(...)``. Whitespace is preserved, which
|
|
973
|
+
is what makes missing-operator typos detectable.
|
|
974
|
+
"""
|
|
975
|
+
checkable = eq_body.replace("@ABS(", "ABS(")
|
|
976
|
+
sides = [side.strip() for side in checkable.split("=", 1)]
|
|
977
|
+
check_syntax([side for side in sides if side])
|
|
978
|
+
|
|
979
|
+
def _check_unknown_variables(self) -> None:
|
|
980
|
+
"""Print a diagnosis and raise for variables with no data column.
|
|
981
|
+
|
|
982
|
+
Every variable in the equation that is not a parameter placeholder
|
|
983
|
+
(active prefix or ``param_names``) or a helper slot must exist in
|
|
984
|
+
``input_df``. Anything else would be inserted as an all-NaN column
|
|
985
|
+
by ``insertModelVar`` and silently degrade or break the fit —
|
|
986
|
+
typically a misspelled variable name or a forgotten ``param_names``
|
|
987
|
+
entry (``ALFA(1)`` with ``'alfa'`` not declared reads as a lead of
|
|
988
|
+
an unknown variable ALFA).
|
|
989
|
+
"""
|
|
990
|
+
helpers = {"ACTUAL", "FITTED", "RESIDUALS"}
|
|
991
|
+
known = set(self.input_df.columns) | set(self.c_params) | helpers
|
|
992
|
+
unknown = sorted(set(self.varname_all) - known)
|
|
993
|
+
if unknown:
|
|
994
|
+
# Print the diagnosis, then raise a bare SyntaxError — same
|
|
995
|
+
# style as check_syntax. IPython renders SyntaxError without
|
|
996
|
+
# the frame stack, so the notebook shows the message above
|
|
997
|
+
# instead of a long construction call stack.
|
|
998
|
+
print(
|
|
999
|
+
f"{type(self).__name__}({self.endo_var}): the equation "
|
|
1000
|
+
f"references variables with no column in input_df:\n"
|
|
1001
|
+
f" {unknown}\n"
|
|
1002
|
+
f"Equation: {self.org_eq_clean}\n"
|
|
1003
|
+
"Check for misspelled variable names or missing param_names "
|
|
1004
|
+
"entries — such variables would otherwise enter the "
|
|
1005
|
+
"estimation as all-NaN columns."
|
|
1006
|
+
)
|
|
1007
|
+
raise SyntaxError("Unknown variables in equation - see above") from None
|
|
957
1008
|
|
|
958
1009
|
@property
|
|
959
1010
|
def mdummy(self):
|
|
@@ -1079,6 +1130,10 @@ class EstimatorBackend(Eq_parent, ABC):
|
|
|
1079
1130
|
Default is a no-op. Override to reject equation forms the backend
|
|
1080
1131
|
cannot handle.
|
|
1081
1132
|
|
|
1133
|
+
:meth:`_tvalues_dict`
|
|
1134
|
+
Default returns ``{}`` (no t-statistics). Override to return
|
|
1135
|
+
``{<prefix>__n: t}`` so the :attr:`tvalues` Series is populated.
|
|
1136
|
+
|
|
1082
1137
|
Standard attributes set during ``__post_init__``
|
|
1083
1138
|
------------------------------------------------
|
|
1084
1139
|
regression_model : Any
|
|
@@ -1230,6 +1285,29 @@ class EstimatorBackend(Eq_parent, ABC):
|
|
|
1230
1285
|
break
|
|
1231
1286
|
return mapped
|
|
1232
1287
|
|
|
1288
|
+
# ---- t-statistics ------------------------------------------------------
|
|
1289
|
+
|
|
1290
|
+
def _tvalues_dict(self) -> Dict[str, float]:
|
|
1291
|
+
"""Backend-specific t-statistics keyed by ``{est_param}__n`` token.
|
|
1292
|
+
|
|
1293
|
+
Default: no t-statistics available. Backends override where the
|
|
1294
|
+
fitted result exposes (or allows computing) them.
|
|
1295
|
+
"""
|
|
1296
|
+
return {}
|
|
1297
|
+
|
|
1298
|
+
@cached_property
|
|
1299
|
+
def tvalues(self) -> pd.Series:
|
|
1300
|
+
"""t-statistics as a Series keyed like :attr:`coef_ser`.
|
|
1301
|
+
|
|
1302
|
+
Parameters without an available t-statistic (fixed, derived, or the
|
|
1303
|
+
backend could not provide one) are NaN.
|
|
1304
|
+
"""
|
|
1305
|
+
tvals = self._tvalues_dict()
|
|
1306
|
+
return pd.Series(
|
|
1307
|
+
{p: tvals.get(p, float("nan")) for p in self.c_params},
|
|
1308
|
+
name=self.caption, dtype=float,
|
|
1309
|
+
)
|
|
1310
|
+
|
|
1233
1311
|
# ---- A/F and residuals (computed once, cached) -------------------------
|
|
1234
1312
|
|
|
1235
1313
|
@cached_property
|
|
@@ -1486,6 +1564,13 @@ class Estimate_ols(EstimatorBackend):
|
|
|
1486
1564
|
"<caption><h3>OLS Regression Results</h3></caption>",
|
|
1487
1565
|
)
|
|
1488
1566
|
|
|
1567
|
+
def _tvalues_dict(self) -> Dict[str, float]:
|
|
1568
|
+
"""statsmodels exposes t-statistics directly, keyed by regressor
|
|
1569
|
+
column name — map those back to the canonical parameter tokens."""
|
|
1570
|
+
return self._map_statsmodels_params(
|
|
1571
|
+
self.regression_model.tvalues.to_dict()
|
|
1572
|
+
)
|
|
1573
|
+
|
|
1489
1574
|
# ---- override estimation_smpl: OLS reports its EFFECTIVE sample --------
|
|
1490
1575
|
|
|
1491
1576
|
@cached_property
|
|
@@ -1610,6 +1695,33 @@ class Estimate_nls_lmfit(EstimatorBackend):
|
|
|
1610
1695
|
"<h2>Fit Result</h2>", "<h3>NLS Regression Results</h3>"
|
|
1611
1696
|
)
|
|
1612
1697
|
|
|
1698
|
+
def _tvalues_dict(self) -> Dict[str, float]:
|
|
1699
|
+
"""lmfit provides standard errors (from the covariance matrix when
|
|
1700
|
+
``calc_covar=True``); t = value / stderr. Fixed parameters, derived
|
|
1701
|
+
(``expr``) parameters without propagated errors, and fits where the
|
|
1702
|
+
covariance could not be estimated have ``stderr`` None (or NaN) and
|
|
1703
|
+
are omitted (→ NaN in :attr:`tvalues`)."""
|
|
1704
|
+
res = self.regression_model
|
|
1705
|
+
out: Dict[str, float] = {}
|
|
1706
|
+
for name, p in res.params.items():
|
|
1707
|
+
# stderr is None when lmfit produced no uncertainties, and can
|
|
1708
|
+
# be NaN when the covariance matrix is ill-conditioned.
|
|
1709
|
+
if p.stderr and p.stderr == p.stderr:
|
|
1710
|
+
out[name] = p.value / p.stderr
|
|
1711
|
+
if not out and any(p.vary for p in res.params.values()):
|
|
1712
|
+
print(
|
|
1713
|
+
f"[{type(self).__name__}({self.endo_var})] WARNING: lmfit "
|
|
1714
|
+
f"produced no parameter uncertainties "
|
|
1715
|
+
f"(errorbars={getattr(res, 'errorbars', None)}), so no "
|
|
1716
|
+
"t-values are available. Common causes: singular or "
|
|
1717
|
+
"ill-conditioned Jacobian (collinear or huge-scale "
|
|
1718
|
+
"regressors), parameters stuck at a bound, or a fit that "
|
|
1719
|
+
"did not converge. Inspect "
|
|
1720
|
+
"est.regression_model.params.pretty_print() and "
|
|
1721
|
+
"est.regression_model.message."
|
|
1722
|
+
)
|
|
1723
|
+
return out
|
|
1724
|
+
|
|
1613
1725
|
|
|
1614
1726
|
# =============================================================================
|
|
1615
1727
|
# Estimate_nls_eviews — nonlinear least squares via EViews (py2eviews)
|
|
@@ -1702,6 +1814,26 @@ class Estimate_nls_eviews(EstimatorBackend):
|
|
|
1702
1814
|
def _render_summary_html(self) -> str:
|
|
1703
1815
|
return eviews_output_to_html(self.regression_model)
|
|
1704
1816
|
|
|
1817
|
+
def _tvalues_dict(self) -> Dict[str, float]:
|
|
1818
|
+
"""Parse the t-Statistic column from the EViews spool text.
|
|
1819
|
+
|
|
1820
|
+
Only the coefficient vector is read back from EViews numerically;
|
|
1821
|
+
the coefficient table (Coefficient, Std. Error, t-Statistic, Prob.)
|
|
1822
|
+
exists only as text in the spool. Rows where EViews prints ``NA``
|
|
1823
|
+
simply do not match and stay NaN in :attr:`tvalues`.
|
|
1824
|
+
"""
|
|
1825
|
+
if not isinstance(self.regression_model, str):
|
|
1826
|
+
return {}
|
|
1827
|
+
num = r"(-?[\d.]+(?:[eE][+-]?\d+)?)"
|
|
1828
|
+
out: Dict[str, float] = {}
|
|
1829
|
+
for m in re.finditer(
|
|
1830
|
+
rf"^\s*C\((\d+)\)\s+{num}\s+{num}\s+{num}",
|
|
1831
|
+
self.regression_model,
|
|
1832
|
+
flags=re.MULTILINE,
|
|
1833
|
+
):
|
|
1834
|
+
out[f"{self.est_param}__{m.group(1)}"] = float(m.group(4))
|
|
1835
|
+
return out
|
|
1836
|
+
|
|
1705
1837
|
|
|
1706
1838
|
# =============================================================================
|
|
1707
1839
|
# Estimate_nls — factory class dispatching on solver
|
|
@@ -118,6 +118,7 @@ def _mmr_md_to_html(
|
|
|
118
118
|
|
|
119
119
|
in_p = in_ul = in_ol = in_bll = in_fence = in_table = False
|
|
120
120
|
tbl_hdr_done = False
|
|
121
|
+
pending_est = False
|
|
121
122
|
|
|
122
123
|
def ep():
|
|
123
124
|
nonlocal in_p
|
|
@@ -148,9 +149,24 @@ def _mmr_md_to_html(
|
|
|
148
149
|
def end_all():
|
|
149
150
|
ep(); eul(); eol(); ebll(); etbl()
|
|
150
151
|
|
|
152
|
+
def flush_est():
|
|
153
|
+
# Emit the panel for the last estimated equation once all of its
|
|
154
|
+
# '>>' continuation lines have been rendered, so the equation is not
|
|
155
|
+
# split around its estimation output.
|
|
156
|
+
nonlocal pending_est, rec_i, panel_i
|
|
157
|
+
if pending_est:
|
|
158
|
+
pending_est = False
|
|
159
|
+
if rec_i < len(est_records):
|
|
160
|
+
ebll()
|
|
161
|
+
out.append(_mmr_est_panel(est_records[rec_i], panel_i, plot_format))
|
|
162
|
+
panel_i += 1; rec_i += 1
|
|
163
|
+
|
|
151
164
|
for raw in lines:
|
|
152
165
|
s = raw.strip()
|
|
153
166
|
|
|
167
|
+
if pending_est and not s.startswith('>>'):
|
|
168
|
+
flush_est()
|
|
169
|
+
|
|
154
170
|
# code fence (```)
|
|
155
171
|
if s.startswith('```'):
|
|
156
172
|
if in_fence:
|
|
@@ -192,20 +208,20 @@ def _mmr_md_to_html(
|
|
|
192
208
|
end_all()
|
|
193
209
|
out.append('<pre class="mmr-bll"><code>'); in_bll = True
|
|
194
210
|
out.append(_mmr_annotate_bll(content, var_desc))
|
|
211
|
+
# The estimator tag may sit on a continuation line.
|
|
212
|
+
if _mmr_has_estimator_tag(raw):
|
|
213
|
+
pending_est = True
|
|
195
214
|
continue
|
|
196
215
|
|
|
197
216
|
# BLL equation >
|
|
198
217
|
if s.startswith('>'):
|
|
199
218
|
content = s[1:].strip()
|
|
200
|
-
has_est = _mmr_has_estimator_tag(raw)
|
|
201
219
|
if not in_bll:
|
|
202
220
|
end_all()
|
|
203
221
|
out.append('<pre class="mmr-bll"><code>'); in_bll = True
|
|
204
222
|
out.append(_mmr_annotate_bll(content, var_desc))
|
|
205
|
-
if
|
|
206
|
-
|
|
207
|
-
out.append(_mmr_est_panel(est_records[rec_i], panel_i, plot_format))
|
|
208
|
-
panel_i += 1; rec_i += 1
|
|
223
|
+
if _mmr_has_estimator_tag(raw):
|
|
224
|
+
pending_est = True
|
|
209
225
|
continue
|
|
210
226
|
|
|
211
227
|
# markdown table row
|
|
@@ -262,6 +278,7 @@ def _mmr_md_to_html(
|
|
|
262
278
|
|
|
263
279
|
if in_fence:
|
|
264
280
|
out.append('</code></pre>')
|
|
281
|
+
flush_est()
|
|
265
282
|
end_all()
|
|
266
283
|
|
|
267
284
|
# leftover estimation records not matched to any source line
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "modelflowib" # PyPI distribution name
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.78" # OVERWRITTEN at build time from MF_VERSION
|
|
8
8
|
# (set_pyproject_version.py / make_pip.py -v)
|
|
9
9
|
description = "A tool to solve and manage dynamic economic and financial models"
|
|
10
10
|
readme = "README.md"
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|