Skip to content

Commit 436623e

Browse files
authored
Merge pull request #510 from bashtage/enable-cow-support
MAINT: Enable copy-on-write support
2 parents d71681c + ed03ab6 commit 436623e

File tree

7 files changed

+28
-7
lines changed

7 files changed

+28
-7
lines changed

ci/azure_template_posix.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ jobs:
5959
python311_latest:
6060
python.version: '3.11'
6161
XXHASH: true
62+
python311_copy_on_write:
63+
python.version: '3.11'
64+
XXHASH: true
65+
LM_TEST_COPY_ON_WRITE: 1
6266
maxParallel: 10
6367

6468
steps:

linearmodels/conftest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
from __future__ import annotations
22

3+
import logging
4+
import os
5+
6+
import pandas as pd
37
import pytest
48

9+
logger = logging.getLogger(__name__)
10+
11+
12+
try:
13+
cow = bool(os.environ.get("LM_TEST_COPY_ON_WRITE", False))
14+
pd.options.mode.copy_on_write = cow
15+
logger.critical("Copy on Write Enabled!")
16+
except AttributeError:
17+
logger.critical("Copy on Write disabled")
18+
519

620
def pytest_configure(config):
721
# Minimal config to simplify running tests from lm.test()

linearmodels/iv/absorbing.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
ndarray,
2323
ones,
2424
ptp,
25+
require,
2526
sqrt,
2627
where,
2728
zeros,
@@ -702,7 +703,7 @@ def __init__(
702703
self._regressors_hash: tuple[tuple[str, ...], ...] | None = None
703704

704705
def _drop_missing(self) -> BoolArray:
705-
missing = self.dependent.isnull.to_numpy()
706+
missing = require(self.dependent.isnull.to_numpy(), requirements="W")
706707
missing |= self.exog.isnull.to_numpy()
707708
missing |= self._absorb_inter.cat.isnull().any(axis=1).to_numpy()
708709
missing |= self._absorb_inter.cont.isnull().any(axis=1).to_numpy()

linearmodels/panel/data.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def dataframe(self) -> DataFrame:
284284
@property
285285
def values2d(self) -> AnyArray:
286286
"""NumPy ndarray view of dataframe"""
287-
return np.asarray(self._frame)
287+
return np.require(self._frame, requirements="W")
288288

289289
@property
290290
def values3d(self) -> AnyArray:
@@ -502,7 +502,7 @@ def demean_pass(
502502

503503
exclude = np.ptp(np.asarray(self._frame), 0) == 0
504504
max_rmse = np.sqrt(np.asarray(self._frame).var(0).max())
505-
scale = np.asarray(self._frame.std())
505+
scale = np.require(self._frame.std(), requirements="W")
506506
exclude = exclude | (scale < 1e-14 * max_rmse)
507507
replacement = cast(Float64Array, np.maximum(scale, 1))
508508
scale[exclude] = replacement[exclude]

linearmodels/panel/model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2419,7 +2419,7 @@ def fit(
24192419
)
24202420
w_frame = w_frame.reindex(self.weights.index).dropna(how="any")
24212421
index = cast(MultiIndex, w_frame.index)
2422-
w = w_frame.to_numpy()
2422+
w = np.require(w_frame, requirements="W")
24232423

24242424
w /= w.mean()
24252425
root_w = cast(Float64Array, np.sqrt(w))

linearmodels/tests/panel/test_data.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,9 @@ def test_demean_against_dummy_regression(data):
295295

296296

297297
def test_demean_missing(mi_df):
298-
mi_df.values.flat[::13] = np.nan
298+
values = np.require(mi_df, requirements="W")
299+
values.flat[::13] = np.nan
300+
mi_df.loc[:, :] = values
299301
data = PanelData(mi_df)
300302
fe = data.demean("entity")
301303
expected = data.values3d.copy()

linearmodels/tests/panel/test_model.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ def test_absorbing_effect(data, intercept):
198198
nentity = len(x.index.levels[0])
199199
ntime = len(x.index.levels[1])
200200
temp = data.x.iloc[:, 0].copy()
201-
temp.values[:] = 1.0
202-
temp.values[: (ntime * (nentity // 2))] = 0
201+
temp.loc[:] = 1.0
202+
temp.iloc[: (ntime * (nentity // 2))] = 0
203203

204204
if intercept:
205205
x["Intercept"] = 1.0

0 commit comments

Comments
 (0)