From ecf50e72a7161ea4bbd0fdbc23603ed0bd5d910c Mon Sep 17 00:00:00 2001 From: Gene Dan Date: Wed, 8 Jul 2026 11:09:42 -0500 Subject: [PATCH 01/17] FIX: Fix doctest. --- .github/workflows/pytest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 266dcbf4..65cffdf1 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -76,4 +76,4 @@ jobs: - name: Install dependencies run: uv sync --extra docs - name: Run doctests - run: uv run --directory docs jb build . --builder=custom --custom-builder=doctest + run: uv run --directory docs sphinx-build -b doctest . _build/doctest From c3e839eb9237209c38d1206962b660373126f207 Mon Sep 17 00:00:00 2001 From: Gene Dan Date: Wed, 8 Jul 2026 11:44:19 -0500 Subject: [PATCH 02/17] FIX: Fix doctest. --- .github/workflows/pytest.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 65cffdf1..459ec988 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -75,5 +75,11 @@ jobs: python-version: "3.12" - name: Install dependencies run: uv sync --extra docs + - name: Generate autosummary stubs + # sphinx-build decides which documents the doctest builder will test + # *before* the autosummary extension has generated library/generated/*.rst + # (those files are gitignored, so they don't exist on a fresh checkout). + # Without this, every class/method docstring page is silently skipped. + run: uv run --directory docs sphinx-autogen -o library/generated library/api.md - name: Run doctests run: uv run --directory docs sphinx-build -b doctest . _build/doctest From c0c9c57381cb1c22c2a3997619f0bdc15713b5b8 Mon Sep 17 00:00:00 2001 From: Gene Dan Date: Wed, 8 Jul 2026 11:59:23 -0500 Subject: [PATCH 03/17] FIX: Fix doctest. --- .github/workflows/pytest.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 459ec988..392cdb6f 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -76,10 +76,6 @@ jobs: - name: Install dependencies run: uv sync --extra docs - name: Generate autosummary stubs - # sphinx-build decides which documents the doctest builder will test - # *before* the autosummary extension has generated library/generated/*.rst - # (those files are gitignored, so they don't exist on a fresh checkout). - # Without this, every class/method docstring page is silently skipped. run: uv run --directory docs sphinx-autogen -o library/generated library/api.md - name: Run doctests - run: uv run --directory docs sphinx-build -b doctest . _build/doctest + run: uv run --directory docs jb build . --builder=custom --custom-builder=doctest From 7f5ae19520b2918b685efd255126c32ef35e99f4 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:07:20 -0700 Subject: [PATCH 04/17] Update common.py --- chainladder/core/common.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/chainladder/core/common.py b/chainladder/core/common.py index 77f84d51..5b0dae75 100644 --- a/chainladder/core/common.py +++ b/chainladder/core/common.py @@ -174,6 +174,17 @@ def pipe(self, func, *args, **kwargs): >>> import chainladder as cl >>> raa = cl.load_sample('raa') >>> raa.pipe(lambda tri: tri.loc[..., 48:]) + 48 60 72 84 96 108 120 + 1981 11805.0 13539.0 16181.0 18009.0 18608.0 18662.0 18834.0 + 1982 10666.0 13782.0 15599.0 15496.0 16169.0 16704.0 NaN + 1983 16141.0 18735.0 22214.0 22863.0 23466.0 NaN NaN + 1984 21266.0 23425.0 26083.0 27067.0 NaN NaN NaN + 1985 22169.0 25955.0 26180.0 NaN NaN NaN NaN + 1986 12935.0 15852.0 NaN NaN NaN NaN NaN + 1987 12314.0 NaN NaN NaN NaN NaN NaN + 1988 NaN NaN NaN NaN NaN NaN NaN + 1989 NaN NaN NaN NaN NaN NaN NaN + 1990 NaN NaN NaN NaN NaN NaN NaN """ return func(self, *args, **kwargs) From a8494e1b9c0ae03f920475e2f5434c24673b8984 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:11:58 -0700 Subject: [PATCH 05/17] Update bornferg.py --- chainladder/methods/bornferg.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chainladder/methods/bornferg.py b/chainladder/methods/bornferg.py index 695a6f49..236b6244 100644 --- a/chainladder/methods/bornferg.py +++ b/chainladder/methods/bornferg.py @@ -123,6 +123,7 @@ def fit(self, X, y=None, sample_weight=None): Fit returns the estimator itself, with ``ultimate_`` populated. .. testsetup:: + import chainladder as cl .. testcode:: @@ -160,6 +161,7 @@ def predict(self, X, sample_weight=None): current Triangle and a refreshed apriori. .. testsetup:: + import chainladder as cl .. testcode:: From b185c518b99d560ec16a866fe15f04f9245bedb8 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:14:26 -0700 Subject: [PATCH 06/17] Update clark.py --- chainladder/development/clark.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chainladder/development/clark.py b/chainladder/development/clark.py index 6a39e3ad..2589f36d 100644 --- a/chainladder/development/clark.py +++ b/chainladder/development/clark.py @@ -142,7 +142,7 @@ class ClarkLDF(DevelopmentBase): 775 CumPaidLoss - LOB + LOB comauto 1.082 medmal 1.889 othliab 1.468 @@ -150,12 +150,12 @@ class ClarkLDF(DevelopmentBase): prodliab 1.441 wkcomp 1.107 CumPaidLoss - LOB + LOB comauto 20.481 - medmal 35.128 - othliab 37.745 + medmal 35.130 + othliab 37.746 ppauto 10.023 - prodliab 64.352 + prodliab 64.347 wkcomp 20.111 """ From 66347faa6a19e8a0060a49ba303d5c3d86d8539d Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:16:35 -0700 Subject: [PATCH 07/17] Update capecod.py --- chainladder/methods/capecod.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainladder/methods/capecod.py b/chainladder/methods/capecod.py index 4175e2ae..1470104d 100644 --- a/chainladder/methods/capecod.py +++ b/chainladder/methods/capecod.py @@ -218,7 +218,7 @@ def fit(self, X, y=None, sample_weight=None): exposure = cl.Chainladder().fit(tr).ultimate_ * 0 + 20000 print(cl.CapeCod(trend=0.05).fit(tr, sample_weight=exposure)) - .. testoutput: + .. testoutput:: CapeCod(trend=0.05) """ From 7edf2490e2ca375737b7bb531d64108065ced573 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:18:50 -0700 Subject: [PATCH 08/17] Update benktander.py --- chainladder/methods/benktander.py | 1 + 1 file changed, 1 insertion(+) diff --git a/chainladder/methods/benktander.py b/chainladder/methods/benktander.py index a83536dd..78b40ff5 100644 --- a/chainladder/methods/benktander.py +++ b/chainladder/methods/benktander.py @@ -218,6 +218,7 @@ def predict(self, X, sample_weight=None): current Triangle and a refreshed apriori. .. testsetup:: + import chainladder as cl .. testcode:: From 8078da9e15fbe68aa9c517741d3bb191eddeacec Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:19:36 -0700 Subject: [PATCH 09/17] Update chainladder.py --- chainladder/methods/chainladder.py | 1 + 1 file changed, 1 insertion(+) diff --git a/chainladder/methods/chainladder.py b/chainladder/methods/chainladder.py index 893933f3..d945242a 100644 --- a/chainladder/methods/chainladder.py +++ b/chainladder/methods/chainladder.py @@ -124,6 +124,7 @@ def fit(self, X, y=None, sample_weight=None): attribute access. .. testsetup:: + import chainladder as cl .. testcode:: From bfb6b36f3431eb5773ff2ff0767c8542dc15e039 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:24:40 -0700 Subject: [PATCH 10/17] Update chainladder.py --- chainladder/methods/chainladder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainladder/methods/chainladder.py b/chainladder/methods/chainladder.py index d945242a..2ab4ca61 100644 --- a/chainladder/methods/chainladder.py +++ b/chainladder/methods/chainladder.py @@ -130,7 +130,7 @@ def fit(self, X, y=None, sample_weight=None): .. testcode:: tr = cl.load_sample('ukmotor') - cl.Chainladder().fit(tr) + print(cl.Chainladder().fit(tr)) .. testoutput:: From 7ca0a66050d6e027857e127a302e8c5549ba456d Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:36:57 -0700 Subject: [PATCH 11/17] Update bornferg.py --- chainladder/methods/bornferg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainladder/methods/bornferg.py b/chainladder/methods/bornferg.py index 236b6244..3165cd72 100644 --- a/chainladder/methods/bornferg.py +++ b/chainladder/methods/bornferg.py @@ -176,7 +176,7 @@ def predict(self, X, sample_weight=None): print(model.predict(tr, sample_weight=apriori).ultimate_) - .. testoutput + .. testoutput:: 2261 2007 12690.000000 From 327cbd1d5028eaf08ac81677ddf96d8cfb246e1f Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:18:33 -0700 Subject: [PATCH 12/17] Update bornferg.py --- chainladder/methods/bornferg.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/chainladder/methods/bornferg.py b/chainladder/methods/bornferg.py index 3165cd72..1528c4bb 100644 --- a/chainladder/methods/bornferg.py +++ b/chainladder/methods/bornferg.py @@ -53,9 +53,7 @@ class BornhuetterFerguson(Benktander): raa = cl.load_sample("raa") premium = raa.latest_diagonal * 0 + 40_000 # zero out and add 40,000 to each origin - - ibnr = cl.BornhuetterFerguson(apriori=0.7).fit(X=raa, sample_weight=premium).ibnr_ - print(ibnr) + cl.BornhuetterFerguson(apriori=0.7).fit(X=raa, sample_weight=premium).ibnr_ .. testoutput:: @@ -77,9 +75,7 @@ class BornhuetterFerguson(Benktander): raa = cl.load_sample("raa") premium = raa.latest_diagonal * 0 + 40_000 * 0.7 # premium is modified by 70% - - ibnr = cl.BornhuetterFerguson().fit(X=raa, sample_weight=premium).ibnr_ - print(ibnr) + cl.BornhuetterFerguson().fit(X=raa, sample_weight=premium).ibnr_ .. testoutput:: @@ -130,7 +126,7 @@ def fit(self, X, y=None, sample_weight=None): tr = cl.load_sample('ukmotor') apriori = cl.Chainladder().fit(tr).ultimate_ * 0 + 14000 - print(cl.BornhuetterFerguson(apriori=1.0).fit(tr, sample_weight=apriori)) + cl.BornhuetterFerguson(apriori=1.0).fit(tr, sample_weight=apriori) .. testoutput:: @@ -173,8 +169,7 @@ def predict(self, X, sample_weight=None): model = cl.BornhuetterFerguson(apriori=1.0).fit( tr_prior, sample_weight=apriori_prior ) - - print(model.predict(tr, sample_weight=apriori).ultimate_) + model.predict(tr, sample_weight=apriori).ultimate_ .. testoutput:: From bf9a4f4882cf806b5d264a4864ef1447bf6ca22f Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:20:44 -0700 Subject: [PATCH 13/17] Update benktander.py --- chainladder/methods/benktander.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/chainladder/methods/benktander.py b/chainladder/methods/benktander.py index 78b40ff5..3803a983 100644 --- a/chainladder/methods/benktander.py +++ b/chainladder/methods/benktander.py @@ -52,9 +52,7 @@ class Benktander(MethodBase): .. testcode:: xyz = cl.load_sample("xyz") - - ibnr = cl.Benktander().fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal).ibnr_ - print(ibnr) + cl.Benktander().fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal).ibnr_ .. testoutput:: @@ -76,7 +74,6 @@ class Benktander(MethodBase): .. testcode:: xyz = cl.load_sample("xyz") - bk_ibnr = ( cl.Benktander(n_iters=1) .fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal) @@ -87,7 +84,7 @@ class Benktander(MethodBase): .fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal) .ibnr_ ) - print(bk_ibnr - bf_ibnr) + bk_ibnr - bf_ibnr .. testoutput:: @@ -109,10 +106,9 @@ class Benktander(MethodBase): .. testcode:: xyz = cl.load_sample("xyz") - bk_ibnr = cl.Benktander(n_iters=1000).fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal).ibnr_ cl_ibnr = cl.Chainladder().fit(xyz["Paid"]).ibnr_ - print(bk_ibnr - cl_ibnr) + bk_ibnr - cl_ibnr .. testoutput:: @@ -165,13 +161,11 @@ def fit(self, X, y=None, sample_weight=None): .. testcode:: xyz = cl.load_sample("xyz") - - ultimate = ( + ( cl.Benktander(apriori=1, n_iters=2) .fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal) .ultimate_ ) - print(ultimate) .. testoutput:: @@ -230,8 +224,7 @@ def predict(self, X, sample_weight=None): model = cl.Benktander(apriori=1.0, n_iters=2).fit( tr_prior, sample_weight=apriori_prior ) - - print(model.predict(tr, sample_weight=apriori).ultimate_) + model.predict(tr, sample_weight=apriori).ultimate_ .. testoutput:: From 0275df8af62f5bc69b09d2690c95ac939d905fe8 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:32:41 -0700 Subject: [PATCH 14/17] Update benktander.py --- chainladder/methods/benktander.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/chainladder/methods/benktander.py b/chainladder/methods/benktander.py index 3803a983..bcf84390 100644 --- a/chainladder/methods/benktander.py +++ b/chainladder/methods/benktander.py @@ -52,7 +52,8 @@ class Benktander(MethodBase): .. testcode:: xyz = cl.load_sample("xyz") - cl.Benktander().fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal).ibnr_ + ibnr = cl.Benktander().fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal).ibnr_ + print(ibnr) .. testoutput:: @@ -84,7 +85,7 @@ class Benktander(MethodBase): .fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal) .ibnr_ ) - bk_ibnr - bf_ibnr + print(bk_ibnr - bf_ibnr) .. testoutput:: @@ -108,7 +109,7 @@ class Benktander(MethodBase): xyz = cl.load_sample("xyz") bk_ibnr = cl.Benktander(n_iters=1000).fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal).ibnr_ cl_ibnr = cl.Chainladder().fit(xyz["Paid"]).ibnr_ - bk_ibnr - cl_ibnr + print(bk_ibnr - cl_ibnr) .. testoutput:: @@ -161,11 +162,12 @@ def fit(self, X, y=None, sample_weight=None): .. testcode:: xyz = cl.load_sample("xyz") - ( + ultimate = ( cl.Benktander(apriori=1, n_iters=2) .fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal) .ultimate_ ) + print(ultimate) .. testoutput:: @@ -224,7 +226,8 @@ def predict(self, X, sample_weight=None): model = cl.Benktander(apriori=1.0, n_iters=2).fit( tr_prior, sample_weight=apriori_prior ) - model.predict(tr, sample_weight=apriori).ultimate_ + ultimate = model.predict(tr, sample_weight=apriori).ultimate_ + print(ultimate) .. testoutput:: From 5f8207dc8dcf16c4496de5a5dd1b45b7c763affa Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:49:39 -0700 Subject: [PATCH 15/17] Update clark.py --- chainladder/development/clark.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/chainladder/development/clark.py b/chainladder/development/clark.py index 2589f36d..413e5420 100644 --- a/chainladder/development/clark.py +++ b/chainladder/development/clark.py @@ -134,8 +134,8 @@ class ClarkLDF(DevelopmentBase): clrd = cl.load_sample("clrd")[["CumPaidLoss"]] print(len(clrd.index)) m = cl.ClarkLDF(groupby="LOB").fit(clrd) - print(m.omega_.round(3)) - print(m.theta_.round(3)) + print(m.omega_.round(2)) + print(m.theta_.round(2)) .. testoutput:: :options: +NORMALIZE_WHITESPACE @@ -143,20 +143,20 @@ class ClarkLDF(DevelopmentBase): 775 CumPaidLoss LOB - comauto 1.082 - medmal 1.889 - othliab 1.468 - ppauto 1.149 - prodliab 1.441 - wkcomp 1.107 + comauto 1.08 + medmal 1.89 + othliab 1.47 + ppauto 1.15 + prodliab 1.44 + wkcomp 1.11 CumPaidLoss LOB - comauto 20.481 - medmal 35.130 - othliab 37.746 - ppauto 10.023 - prodliab 64.347 - wkcomp 20.111 + comauto 20.48 + medmal 35.13 + othliab 37.75 + ppauto 10.02 + prodliab 64.35 + wkcomp 20.11 """ From 7c6072cc3565032cdb83e359202afc3379fd01ff Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:52:29 -0700 Subject: [PATCH 16/17] Update bornferg.py --- chainladder/methods/bornferg.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/chainladder/methods/bornferg.py b/chainladder/methods/bornferg.py index 1528c4bb..ee968b2e 100644 --- a/chainladder/methods/bornferg.py +++ b/chainladder/methods/bornferg.py @@ -53,7 +53,8 @@ class BornhuetterFerguson(Benktander): raa = cl.load_sample("raa") premium = raa.latest_diagonal * 0 + 40_000 # zero out and add 40,000 to each origin - cl.BornhuetterFerguson(apriori=0.7).fit(X=raa, sample_weight=premium).ibnr_ + ibnr = cl.BornhuetterFerguson(apriori=0.7).fit(X=raa, sample_weight=premium).ibnr_ + print(ibnr) .. testoutput:: @@ -75,7 +76,8 @@ class BornhuetterFerguson(Benktander): raa = cl.load_sample("raa") premium = raa.latest_diagonal * 0 + 40_000 * 0.7 # premium is modified by 70% - cl.BornhuetterFerguson().fit(X=raa, sample_weight=premium).ibnr_ + ibnr = cl.BornhuetterFerguson().fit(X=raa, sample_weight=premium).ibnr_ + print(ibnr) .. testoutput:: @@ -126,7 +128,8 @@ def fit(self, X, y=None, sample_weight=None): tr = cl.load_sample('ukmotor') apriori = cl.Chainladder().fit(tr).ultimate_ * 0 + 14000 - cl.BornhuetterFerguson(apriori=1.0).fit(tr, sample_weight=apriori) + model = cl.BornhuetterFerguson(apriori=1.0).fit(tr, sample_weight=apriori) + print(model) .. testoutput:: @@ -169,7 +172,8 @@ def predict(self, X, sample_weight=None): model = cl.BornhuetterFerguson(apriori=1.0).fit( tr_prior, sample_weight=apriori_prior ) - model.predict(tr, sample_weight=apriori).ultimate_ + ultimate = model.predict(tr, sample_weight=apriori).ultimate_ + print(ultimate) .. testoutput:: From a568e33ca004a744156c802850841813cfe5afd9 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Thu, 9 Jul 2026 22:15:17 -0700 Subject: [PATCH 17/17] Update pytest.yml --- .github/workflows/pytest.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 392cdb6f..266dcbf4 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -75,7 +75,5 @@ jobs: python-version: "3.12" - name: Install dependencies run: uv sync --extra docs - - name: Generate autosummary stubs - run: uv run --directory docs sphinx-autogen -o library/generated library/api.md - name: Run doctests run: uv run --directory docs jb build . --builder=custom --custom-builder=doctest