From f18ce20383be85f0d6ebc3483fd1ce9c961b971b Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Thu, 2 Jul 2026 07:10:03 +0000 Subject: [PATCH 1/9] enable loc setting on partial triangles --- chainladder/core/slice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chainladder/core/slice.py b/chainladder/core/slice.py index 96a477995..b6ed5c279 100644 --- a/chainladder/core/slice.py +++ b/chainladder/core/slice.py @@ -367,7 +367,7 @@ def index_key(self, key: _LabelKey) -> np.ndarray: # Case scalar, locate position in first level of index. else: idx = np.where(self.obj.kdims[:, 0]==key)[0] - return idx + return _LocBase._contig_slice(idx) def other_key( self, @@ -402,7 +402,7 @@ def other_key( if type(key) in [slice, list]: return obj_idx.loc[key].values if not hasattr(key, '__iter__') or type(key) is str: - return np.array([obj_idx.loc[key]]) + return _LocBase._contig_slice(np.array([obj_idx.loc[key]])) else: raise AttributeError("Unable to slice.") From a7178504f2ec8af11d93b9de1e1e59b956b5eead Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Thu, 2 Jul 2026 07:36:58 +0000 Subject: [PATCH 2/9] fixing --- chainladder/core/slice.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/chainladder/core/slice.py b/chainladder/core/slice.py index b6ed5c279..fd0712455 100644 --- a/chainladder/core/slice.py +++ b/chainladder/core/slice.py @@ -367,7 +367,7 @@ def index_key(self, key: _LabelKey) -> np.ndarray: # Case scalar, locate position in first level of index. else: idx = np.where(self.obj.kdims[:, 0]==key)[0] - return _LocBase._contig_slice(idx) + return idx def other_key( self, @@ -402,7 +402,7 @@ def other_key( if type(key) in [slice, list]: return obj_idx.loc[key].values if not hasattr(key, '__iter__') or type(key) is str: - return _LocBase._contig_slice(np.array([obj_idx.loc[key]])) + return np.array([obj_idx.loc[key]]) else: raise AttributeError("Unable to slice.") @@ -431,7 +431,9 @@ def key_to_slice(self, key: _LabelKey) -> tuple[_AxisKey, _AxisKey, _AxisKey, _A return out def __setitem__(self, key: _LabelKey, values: int | float | TriangleSlicer) -> None: - super().__setitem__(cast(tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey], self.key_to_slice(key)), values) + raw_slice = self.key_to_slice(key) + contig_slice = [_LocBase._contig_slice(x) for x in raw_slice] + super().__setitem__(cast(tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey], contig_slice), values) class Ilocation(_LocBase): """ From 1187a52f705e95e04d9ef626a61c0b0cc6a430bf Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Fri, 10 Jul 2026 05:44:46 +0000 Subject: [PATCH 3/9] adding test --- chainladder/core/tests/test_slicing.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/chainladder/core/tests/test_slicing.py b/chainladder/core/tests/test_slicing.py index c4c2f5efb..b54ed49b2 100644 --- a/chainladder/core/tests/test_slicing.py +++ b/chainladder/core/tests/test_slicing.py @@ -273,7 +273,29 @@ def test_loc_setitem_triangle_value(clrd: Triangle) -> None: tri.loc["Aegis Grp", "comauto"] = sub * 2 assert tri.loc["Aegis Grp", "comauto"] == sub * 2 +def test_loc_setitem_partial_triangles(raa: Triangle) -> None: + """ + Use Triangle.loc to set a few origin or develop period via a TriangleSlicer. + + Parameters + ---------- + raa: Triangle + The raa sample data set fixture. + Returns + ------- + None + + """ + raa2 = raa * 2 + raa_new = raa.copy() + raa_new.loc[:,:,:,:60] = raa2.loc[:,:,:,:60] + raa_new.loc[:,:,:,72:] = raa2.loc[:,:,:,72:] + assert raa_new == raa2 + raa_new = raa.copy() + raa_new.loc[:,:,:'1984',:] = raa2.loc[:,:,:'1984',:] + raa_new.loc[:,:,'1985':,:] = raa2.loc[:,:,'1985':,:] + assert raa_new == raa2 def test_invalid_iloc_sparse_assignment(prism) -> None: """ From de661e2dc296ff4dcb4a8a763d35982178af0ece Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Thu, 9 Jul 2026 22:49:13 -0700 Subject: [PATCH 4/9] Loc setter (#1102) * enable loc setting on partial triangles * fixing * adding test --- chainladder/core/slice.py | 4 +++- chainladder/core/tests/test_slicing.py | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/chainladder/core/slice.py b/chainladder/core/slice.py index 96a477995..fd0712455 100644 --- a/chainladder/core/slice.py +++ b/chainladder/core/slice.py @@ -431,7 +431,9 @@ def key_to_slice(self, key: _LabelKey) -> tuple[_AxisKey, _AxisKey, _AxisKey, _A return out def __setitem__(self, key: _LabelKey, values: int | float | TriangleSlicer) -> None: - super().__setitem__(cast(tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey], self.key_to_slice(key)), values) + raw_slice = self.key_to_slice(key) + contig_slice = [_LocBase._contig_slice(x) for x in raw_slice] + super().__setitem__(cast(tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey], contig_slice), values) class Ilocation(_LocBase): """ diff --git a/chainladder/core/tests/test_slicing.py b/chainladder/core/tests/test_slicing.py index c4c2f5efb..b54ed49b2 100644 --- a/chainladder/core/tests/test_slicing.py +++ b/chainladder/core/tests/test_slicing.py @@ -273,7 +273,29 @@ def test_loc_setitem_triangle_value(clrd: Triangle) -> None: tri.loc["Aegis Grp", "comauto"] = sub * 2 assert tri.loc["Aegis Grp", "comauto"] == sub * 2 +def test_loc_setitem_partial_triangles(raa: Triangle) -> None: + """ + Use Triangle.loc to set a few origin or develop period via a TriangleSlicer. + + Parameters + ---------- + raa: Triangle + The raa sample data set fixture. + Returns + ------- + None + + """ + raa2 = raa * 2 + raa_new = raa.copy() + raa_new.loc[:,:,:,:60] = raa2.loc[:,:,:,:60] + raa_new.loc[:,:,:,72:] = raa2.loc[:,:,:,72:] + assert raa_new == raa2 + raa_new = raa.copy() + raa_new.loc[:,:,:'1984',:] = raa2.loc[:,:,:'1984',:] + raa_new.loc[:,:,'1985':,:] = raa2.loc[:,:,'1985':,:] + assert raa_new == raa2 def test_invalid_iloc_sparse_assignment(prism) -> None: """ From c5d6f2b6820718385b43a703b564ac3e94af385d Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sat, 1 Aug 2026 08:29:32 +0000 Subject: [PATCH 5/9] more comment and docstrings; adding non-contig support --- chainladder/core/slice.py | 25 ++++++- chainladder/core/tests/test_slicing.py | 94 ++++++++++++++++++++++++-- 2 files changed, 111 insertions(+), 8 deletions(-) diff --git a/chainladder/core/slice.py b/chainladder/core/slice.py index fd0712455..02fc00233 100644 --- a/chainladder/core/slice.py +++ b/chainladder/core/slice.py @@ -154,7 +154,14 @@ def __setitem__( key = tuple( [slice(item, item + 1) if isinstance(item, int) else item for item in key] ) - cast(np.ndarray, cast(object, self.obj.values)).__setitem__(self._normalize_index(key), values) + norm_key = self._normalize_index(key) + if type(norm_key[2]) != slice or type(norm_key[3]) != slice: + raise ValueError("Setting while fancy indexing on origin/development is not supported.") + if type(norm_key[0]) is slice or type(norm_key[1]) is slice: + cast(np.ndarray, cast(object, self.obj.values)).__setitem__(norm_key, values) + else: + #the getter uses arr[idx,:][:,idx] to get the Cartesian product, using np.ix_ on the setter to match + cast(np.ndarray, cast(object, self.obj.values)).__setitem__(np.ix_(norm_key[0], norm_key[1])+(norm_key[2], norm_key[3]), values) def _normalize_index(self, key: IndexExpression) -> tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey]: """ @@ -431,7 +438,23 @@ def key_to_slice(self, key: _LabelKey) -> tuple[_AxisKey, _AxisKey, _AxisKey, _A return out def __setitem__(self, key: _LabelKey, values: int | float | TriangleSlicer) -> None: + """ + Supports the .loc[] for setting Triangle values. Only supported for numpy backend. + + Parameters + ---------- + key: _LabelKey + Indicates the location of the Triangle you want to set values for. + values: int | float | TriangleSlicer + The value(s) you want to assign to the slice of the Triangle. + + Returns + ------- + None + + """ raw_slice = self.key_to_slice(key) + # _LocBase expects key to be contiguous if possible contig_slice = [_LocBase._contig_slice(x) for x in raw_slice] super().__setitem__(cast(tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey], contig_slice), values) diff --git a/chainladder/core/tests/test_slicing.py b/chainladder/core/tests/test_slicing.py index b54ed49b2..c016455b9 100644 --- a/chainladder/core/tests/test_slicing.py +++ b/chainladder/core/tests/test_slicing.py @@ -289,13 +289,16 @@ def test_loc_setitem_partial_triangles(raa: Triangle) -> None: """ raa2 = raa * 2 raa_new = raa.copy() - raa_new.loc[:,:,:,:60] = raa2.loc[:,:,:,:60] - raa_new.loc[:,:,:,72:] = raa2.loc[:,:,:,72:] - assert raa_new == raa2 - raa_new = raa.copy() - raa_new.loc[:,:,:'1984',:] = raa2.loc[:,:,:'1984',:] - raa_new.loc[:,:,'1985':,:] = raa2.loc[:,:,'1985':,:] - assert raa_new == raa2 + if raa_new.array_backend == "sparse": + pytest.skip("Test is specific to the numpy backend.") + else: + raa_new.loc[:,:,:,:60] = raa2.loc[:,:,:,:60] + raa_new.loc[:,:,:,72:] = raa2.loc[:,:,:,72:] + assert raa_new == raa2 + raa_new = raa.copy() + raa_new.loc[:,:,:'1984',:] = raa2.loc[:,:,:'1984',:] + raa_new.loc[:,:,'1985':,:] = raa2.loc[:,:,'1985':,:] + assert raa_new == raa2 def test_invalid_iloc_sparse_assignment(prism) -> None: """ @@ -350,6 +353,25 @@ def test_get_idx_fancy_origin_raises(raa: Triangle) -> None: with pytest.raises(ValueError, match="Fancy indexing on origin/development is not supported"): _= raa.iloc[0, 0, [0, 1, 5], :] +def test_set_fancy_origin_raises(raa: Triangle) -> None: + """ + Attempt setting with fancy indexing on origin axis, raise an error. + + Parameters + ---------- + raa: Triangle + The raa sample data set fixture. + + Returns + ------- + None + + """ + if raa.array_backend == "sparse": + pytest.skip("Test is specific to the numpy backend.") + else: + with pytest.raises(ValueError, match="Setting while fancy indexing on origin/development is not supported."): + raa.iloc[0, 0, [0, 1, 5], :] = raa.iloc[0, 0, :3, :] def test_get_idx_fancy_development_raises(raa: Triangle) -> None: """ @@ -368,6 +390,25 @@ def test_get_idx_fancy_development_raises(raa: Triangle) -> None: with pytest.raises(ValueError, match="Fancy indexing on origin/development is not supported"): _= raa.iloc[0, 0, :, [0, 1, 5]] +def test_set_fancy_development_raises(raa: Triangle) -> None: + """ + Attempt setting with fancy indexing on development axis, raise an error. + + Parameters + ---------- + raa: Triangle + The raa sample data set fixture. + + Returns + ------- + None + + """ + if raa.array_backend == "sparse": + pytest.skip("Test is specific to the numpy backend.") + else: + with pytest.raises(ValueError, match="Setting while fancy indexing on origin/development is not supported."): + raa.iloc[0, 0, :, [0, 1, 5]] = raa.iloc[0, 0, :, :3] def test_get_idx_non_contiguous_index_and_columns(clrd: Triangle) -> None: """ @@ -393,6 +434,45 @@ def test_get_idx_non_contiguous_index_and_columns(clrd: Triangle) -> None: assert result.index.values.tolist() == expected_index assert result.columns.tolist() == ['IncurLoss', 'CumPaidLoss', 'EarnedPremNet'] +def test_setting_non_contiguous_index_and_columns(clrd: Triangle) -> None: + """ + Set lists of non-contiguous indexes and column through Triangle.loc. Check the values + of the index and columns returned. + + Parameters + ---------- + clrd: Triangle + The clrd sample data set fixture. + + Returns + ------- + None + + """ + if clrd.array_backend == "sparse": + pytest.skip("Test is specific to the numpy backend.") + else: + dest_index = [ + ['Adriatic Ins Co', 'othliab'], + ['Adriatic Ins Co', 'ppauto'], + ['Agency Ins Co Of MD Inc', 'ppauto'], + ] + val_index = [ + ['Adriatic Ins Co', 'ppauto'], + ['Aegis Grp', 'comauto'], + ['Agency Ins Co Of MD Inc', 'ppauto'], + ] + dest_col = ['CumPaidLoss', 'BulkLoss', 'EarnedPremNet'] + val_col = ['IncurLoss', 'CumPaidLoss', 'EarnedPremNet'] + clrd_copy = clrd.copy() + clrd_copy.loc[dest_index] = clrd.loc[val_index] + assert clrd_copy.loc[dest_index] == clrd.loc[val_index] + clrd_copy = clrd.copy() + clrd_copy.loc[:,dest_col] = clrd.loc[:,val_col] + assert clrd_copy.loc[:,dest_col] == clrd.loc[:,val_col] + clrd_copy = clrd.copy() + clrd_copy.loc[dest_index,dest_col] = clrd.loc[val_index,val_col] + assert clrd_copy.loc[dest_index,dest_col] == clrd.loc[val_index,val_col] def test_sparse_at_iat1(prism): t = prism.copy() From 4618748f81e202b47e5463512f04641e5357577e Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sat, 1 Aug 2026 17:23:44 +0000 Subject: [PATCH 6/9] generalizing across iloc --- chainladder/core/slice.py | 13 ++++--- chainladder/core/tests/test_slicing.py | 48 +++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/chainladder/core/slice.py b/chainladder/core/slice.py index 02fc00233..212fbf030 100644 --- a/chainladder/core/slice.py +++ b/chainladder/core/slice.py @@ -150,11 +150,13 @@ def __setitem__( raise ValueError('Setting values with sparse backend requires .at or .iat') if isinstance(values, TriangleSlicer): values = values.values + # attempt to make keys contig + contig_key = tuple([_LocBase._contig_slice(x) for x in key]) # Create a slice for any key elements that are integers, otherwise preserve the slice or array. - key = tuple( - [slice(item, item + 1) if isinstance(item, int) else item for item in key] + tuple_key = tuple( + [slice(item, item + 1) if isinstance(item, int) else item for item in contig_key] ) - norm_key = self._normalize_index(key) + norm_key = self._normalize_index(tuple_key) if type(norm_key[2]) != slice or type(norm_key[3]) != slice: raise ValueError("Setting while fancy indexing on origin/development is not supported.") if type(norm_key[0]) is slice or type(norm_key[1]) is slice: @@ -453,10 +455,7 @@ def __setitem__(self, key: _LabelKey, values: int | float | TriangleSlicer) -> N None """ - raw_slice = self.key_to_slice(key) - # _LocBase expects key to be contiguous if possible - contig_slice = [_LocBase._contig_slice(x) for x in raw_slice] - super().__setitem__(cast(tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey], contig_slice), values) + super().__setitem__(cast(tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey], self.key_to_slice(key)), values) class Ilocation(_LocBase): """ diff --git a/chainladder/core/tests/test_slicing.py b/chainladder/core/tests/test_slicing.py index c016455b9..02c7f2738 100644 --- a/chainladder/core/tests/test_slicing.py +++ b/chainladder/core/tests/test_slicing.py @@ -367,11 +367,15 @@ def test_set_fancy_origin_raises(raa: Triangle) -> None: None """ + raa_copy = raa.copy() if raa.array_backend == "sparse": pytest.skip("Test is specific to the numpy backend.") else: with pytest.raises(ValueError, match="Setting while fancy indexing on origin/development is not supported."): - raa.iloc[0, 0, [0, 1, 5], :] = raa.iloc[0, 0, :3, :] + raa_copy.iloc[0, 0, [0, 1, 5], :] = raa.iloc[0, 0, :3, :] + with pytest.raises(ValueError, match="Setting while fancy indexing on origin/development is not supported."): + raa_copy.loc['Total', 'values', ['1983', '1984', '1986'], :] = raa.iloc[0, 0, :3, :] + def test_get_idx_fancy_development_raises(raa: Triangle) -> None: """ @@ -404,11 +408,15 @@ def test_set_fancy_development_raises(raa: Triangle) -> None: None """ + raa_copy = raa.copy() if raa.array_backend == "sparse": pytest.skip("Test is specific to the numpy backend.") else: with pytest.raises(ValueError, match="Setting while fancy indexing on origin/development is not supported."): - raa.iloc[0, 0, :, [0, 1, 5]] = raa.iloc[0, 0, :, :3] + raa_copy.iloc[0, 0, :, [0, 1, 5]] = raa.iloc[0, 0, :, :3] + with pytest.raises(ValueError, match="Setting while fancy indexing on origin/development is not supported."): + raa_copy.loc['Total', 'values', :, [12, 24, 48]] = raa.iloc[0, 0, :, :3] + def test_get_idx_non_contiguous_index_and_columns(clrd: Triangle) -> None: """ @@ -434,10 +442,10 @@ def test_get_idx_non_contiguous_index_and_columns(clrd: Triangle) -> None: assert result.index.values.tolist() == expected_index assert result.columns.tolist() == ['IncurLoss', 'CumPaidLoss', 'EarnedPremNet'] -def test_setting_non_contiguous_index_and_columns(clrd: Triangle) -> None: +def test_loc_setting_non_contiguous_index_and_columns(clrd: Triangle) -> None: """ Set lists of non-contiguous indexes and column through Triangle.loc. Check the values - of the index and columns returned. + of the assigned triangles. Parameters ---------- @@ -474,6 +482,38 @@ def test_setting_non_contiguous_index_and_columns(clrd: Triangle) -> None: clrd_copy.loc[dest_index,dest_col] = clrd.loc[val_index,val_col] assert clrd_copy.loc[dest_index,dest_col] == clrd.loc[val_index,val_col] +def test_iloc_setting_non_contiguous_index_and_columns(clrd: Triangle) -> None: + """ + Set lists of non-contiguous indexes and column through Triangle.iloc. Check the values + of the assigned triangles. + + Parameters + ---------- + clrd: Triangle + The clrd sample data set fixture. + + Returns + ------- + None + + """ + if clrd.array_backend == "sparse": + pytest.skip("Test is specific to the numpy backend.") + else: + dest_index = [0,1,5] + val_index = [1,4,6] + dest_col = [2,3,5] + val_col = [1,2,4] + clrd_copy = clrd.copy() + clrd_copy.iloc[dest_index] = clrd.iloc[val_index] + assert clrd_copy.iloc[dest_index] == clrd.iloc[val_index] + clrd_copy = clrd.copy() + clrd_copy.iloc[:,dest_col] = clrd.iloc[:,val_col] + assert clrd_copy.iloc[:,dest_col] == clrd.iloc[:,val_col] + clrd_copy = clrd.copy() + clrd_copy.iloc[dest_index,dest_col] = clrd.iloc[val_index,val_col] + assert clrd_copy.iloc[dest_index,dest_col] == clrd.iloc[val_index,val_col] + def test_sparse_at_iat1(prism): t = prism.copy() t.iat[0, 0, 0, 0] = 5.0 From ff1f162872a899364e349edf0f9b66442b30ffa4 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Sat, 1 Aug 2026 14:35:33 -0700 Subject: [PATCH 7/9] Update slice.py --- chainladder/core/slice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chainladder/core/slice.py b/chainladder/core/slice.py index 212fbf030..3364fe13d 100644 --- a/chainladder/core/slice.py +++ b/chainladder/core/slice.py @@ -191,7 +191,7 @@ def _normalize_index(self, key: IndexExpression) -> tuple[_AxisKey, _AxisKey, _A start: int | None= i.start if i.start > 0 else None stop: int | None = i.stop if i.stop > -1 else None stop: int | None = None if stop == self.obj.shape[n] else stop - step: int | None = None if start is None and stop is None else i.step + step: int | None = None if start is None and stop is None and (i.step == 1) else i.step l.append(slice(start, stop, step)) else: l.append(i) From 06a42069e0a3853ac05e0111f7aeb145002e02ba Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 12 Aug 2026 12:45:26 -0700 Subject: [PATCH 8/9] Update slice.py --- chainladder/core/slice.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/chainladder/core/slice.py b/chainladder/core/slice.py index 2644fa7d7..a5e65ac0b 100644 --- a/chainladder/core/slice.py +++ b/chainladder/core/slice.py @@ -67,7 +67,7 @@ def get_idx(self, idx: tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey]) -> Triangl c_idx: slice | np.ndarray = _LocBase._contig_slice(idx[1]) o_idx: slice | np.ndarray = _LocBase._contig_slice(idx[2]) d_idx: slice | np.ndarray = _LocBase._contig_slice(idx[3]) - if type(o_idx) != slice or type(d_idx) != slice: + if type(o_idx) is not slice or type(d_idx) is not slice: raise ValueError("Fancy indexing on origin/development is not supported.") if type(i_idx) is slice or type(c_idx) is slice: obj.values = obj.values[i_idx, c_idx, o_idx, d_idx] @@ -157,7 +157,7 @@ def __setitem__( [slice(item, item + 1) if isinstance(item, int) else item for item in contig_key] ) norm_key = self._normalize_index(tuple_key) - if type(norm_key[2]) != slice or type(norm_key[3]) != slice: + if type(norm_key[2]) is not slice or type(norm_key[3]) is not slice: raise ValueError("Setting while fancy indexing on origin/development is not supported.") if type(norm_key[0]) is slice or type(norm_key[1]) is slice: cast(np.ndarray, cast(object, self.obj.values)).__setitem__(norm_key, values) @@ -183,7 +183,7 @@ def _normalize_index(self, key: IndexExpression) -> tuple[_AxisKey, _AxisKey, _A """ # Apply sparse normalization, fills out the rest of the dimensions using the shape of the Triangle. key: tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey] = _slicing.normalize_index(key, self.obj.shape) - l = [] + key_list = [] # Preserve start/stop/step boundaries if the user has specified them, otherwise replace them with None. # None indicates "go-to-boundary" for the slice. for n, i in enumerate(key): @@ -192,10 +192,10 @@ def _normalize_index(self, key: IndexExpression) -> tuple[_AxisKey, _AxisKey, _A stop: int | None = i.stop if i.stop > -1 else None stop: int | None = None if stop == self.obj.shape[n] else stop step: int | None = None if start is None and stop is None and (i.step == 1) else i.step - l.append(slice(start, stop, step)) + key_list.append(slice(start, stop, step)) else: - l.append(i) - key = tuple(l) + key_list.append(i) + key = tuple(key_list) return key def _sparse_setitem( @@ -228,7 +228,7 @@ def _sparse_setitem( (arr.coords[3] == key[3])) # If it does, index the location and assign the value directly. if check.max(): - data_index = np.where(check == True)[0][0] + data_index = np.where(check)[0][0] arr.data[data_index] = values # Otherwise, create a new sparse array with the updated coordinates and data. else: @@ -780,7 +780,7 @@ def _check_index(self, key: IndexExpression) -> tuple[int, int, int, int]: """ idx = self._normalize_index(key) types = {type(i) for i in idx} - if len(types) > 1 or list(types)[0] != int: + if len(types) > 1 or list(types)[0] is not int: raise ValueError('iAt based indexing can only have integer indexers') return cast("tuple[int, int, int, int]", idx) From 38765f11af3e645854ebf7bc54aa2ba2d1b643e8 Mon Sep 17 00:00:00 2001 From: henrydingliu <106109320+henrydingliu@users.noreply.github.com> Date: Wed, 12 Aug 2026 13:02:47 -0700 Subject: [PATCH 9/9] Update slice.py --- chainladder/core/slice.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/chainladder/core/slice.py b/chainladder/core/slice.py index a5e65ac0b..519969988 100644 --- a/chainladder/core/slice.py +++ b/chainladder/core/slice.py @@ -163,7 +163,10 @@ def __setitem__( cast(np.ndarray, cast(object, self.obj.values)).__setitem__(norm_key, values) else: #the getter uses arr[idx,:][:,idx] to get the Cartesian product, using np.ix_ on the setter to match - cast(np.ndarray, cast(object, self.obj.values)).__setitem__(np.ix_(norm_key[0], norm_key[1])+(norm_key[2], norm_key[3]), values) + cast(np.ndarray, cast(object, self.obj.values)).__setitem__( + np.ix_(norm_key[0], norm_key[1]) + (norm_key[2], norm_key[3]), + values + ) def _normalize_index(self, key: IndexExpression) -> tuple[_AxisKey, _AxisKey, _AxisKey, _AxisKey]: """ @@ -478,7 +481,10 @@ class TriangleSlicer: def __getitem__(self: TriangleProtocol, key: pd.Series | np.ndarray | list[str]) -> Triangle: ... @overload def __getitem__(self: TriangleProtocol, key: str | int) -> Triangle | pd.Series: ... - def __getitem__(self: TriangleProtocol, key: pd.Series | np.ndarray | str | list[str] | int) -> Triangle | pd.Series: + def __getitem__( + self: TriangleProtocol, + key: pd.Series | np.ndarray | str | list[str] | int + ) -> Triangle | pd.Series: """ Boolean Slicer functionality.