Skip to content

Commit d564bac

Browse files
authored
Merge pull request #854 from bashtage/fix-853-freebsd-tests
TST: Run the IVJIVE docstring examples quietly under pytest -v
2 parents b7c5c17 + dcbaae3 commit d564bac

3 files changed

Lines changed: 81 additions & 9 deletions

File tree

‎README.md‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,47 @@ python -m pip install -r requirements.txt -r requirements-dev.txt
125125
python -m pip install -e . --no-build-isolation
126126
```
127127

128+
## Running the tests
129+
130+
The tests are installed with linearmodels. They need pytest 9 and xarray, and
131+
pytest-xdist to run in parallel.
132+
133+
```bash
134+
python -c "import linearmodels; linearmodels.test(['--skip-slow', '-n', 'auto'])"
135+
```
136+
137+
`--skip-slow` skips the slow tests and `--skip-examples` the example notebooks.
138+
139+
pytest loads every plugin that is installed in the environment, and the test
140+
configuration of linearmodels is strict, so that, for example, a marker that is
141+
not registered is an error. A plugin that uses such a marker makes tests fail
142+
with a message such as `'gpu' not found in markers configuration option`. To run
143+
the tests without the other plugins, turn off their automatic loading and load
144+
pytest-xdist explicitly. This works with `python -m pytest` too.
145+
146+
```bash
147+
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -c "import linearmodels; linearmodels.test(['-p', 'xdist', '-n', 'auto'])"
148+
```
149+
150+
When the tests run in several processes with pytest-xdist, limit the BLAS
151+
libraries to one thread in each process. Otherwise every process starts as many
152+
threads as there are cores, and excessive context switching makes the tests run
153+
very slow. This problem is particularly acute on machines with high CPU counts.
154+
155+
```bash
156+
export MKL_NUM_THREADS=1
157+
export OPENBLAS_NUM_THREADS=1
158+
export OMP_NUM_THREADS=1
159+
```
160+
161+
or, in PowerShell,
162+
163+
```powershell
164+
$env:MKL_NUM_THREADS = 1
165+
$env:OPENBLAS_NUM_THREADS = 1
166+
$env:OMP_NUM_THREADS = 1
167+
```
168+
128169
## Documentation
129170

130171
[Stable Documentation](https://bashtage.github.io/linearmodels/) is
@@ -173,6 +214,8 @@ Python, NumPy and the other dependencies.
173214
### Testing
174215

175216
- pytest (9.0+)
217+
- xarray (0.16+)
218+
- pytest-xdist (optional, to run the tests in parallel)
176219

177220
### Documentation
178221

‎linearmodels/tests/iv/test_new_feature_hardening.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ def run_docstring_examples(obj, name):
8888
failures = []
8989
with_examples = set()
9090
for test in finder.find(obj, name, globs={}):
91-
runner = doctest.DocTestRunner(optionflags=doctest.ELLIPSIS)
91+
# verbose=None, the default, is verbose when "-v" is in sys.argv, as it is in
92+
# "pytest -v", and the examples that pass are then written to out as well
93+
runner = doctest.DocTestRunner(verbose=False, optionflags=doctest.ELLIPSIS)
9294
with warnings.catch_warnings():
9395
warnings.simplefilter("ignore", MissingValueWarning)
9496
runner.run(test, out=failures.append)

‎linearmodels/tests/test_kernel_bandwidth_few_observations.py‎

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,29 @@ def system_equations(nobs, endogenous=False):
874874
}
875875

876876

877+
def gmm_equations(nobs):
878+
"""
879+
Two equations, each with one endogenous regressor and one instrument
880+
881+
IVSystemGMM inverts the covariance of the moment conditions, in the robust and
882+
the kernel weights. The equations of system_equations(nobs, True) are exactly
883+
identified, so that their 4 moment conditions sum to zero at the estimates and have
884+
rank nobs - 1 or less: their covariance is singular with 4 or fewer observations,
885+
and inverting it only works up to rounding (it raised "Singular matrix" on FreeBSD,
886+
#853). These equations have no constant and 2 moment conditions, whose covariance
887+
has full rank from 3 observations.
888+
"""
889+
first, second = iv_data(nobs, seed=11), iv_data(nobs, seed=111)
890+
return {
891+
f"eq{i}": {
892+
"dependent": data.y,
893+
"endog": data[["xn"]],
894+
"instruments": data[["z1"]],
895+
}
896+
for i, data in enumerate((first, second))
897+
}
898+
899+
877900
@pytest.mark.parametrize("kernel", CANONICAL)
878901
@pytest.mark.parametrize(("model", "endogenous"), [(SUR, False), (IV3SLS, True)])
879902
def test_system_models_raise_when_fit_with_too_few_observations(
@@ -914,7 +937,7 @@ def test_system_models_explicit_bandwidth_works_with_the_observations_that_raise
914937
def test_system_gmm_weights_raise_when_fit_with_too_few_observations(kernel):
915938
nobs = fewest_observations(kernel) - 1
916939
mod = IVSystemGMM(
917-
system_equations(nobs, True),
940+
gmm_equations(nobs),
918941
weight_type="kernel",
919942
kernel=kernel,
920943
optimal_bw=True,
@@ -923,20 +946,24 @@ def test_system_gmm_weights_raise_when_fit_with_too_few_observations(kernel):
923946
mod.fit()
924947

925948

926-
# The robust weights of the two equations need 4 observations before the covariance
927-
# gets to the bandwidth: the Bartlett kernel is reached with 4
928-
SYSTEM_GMM_COVARIANCE_FEW = [("parzen", 4), ("qs", 4), ("qs", 5)]
949+
# Every number of observations from 3, where the robust weights of gmm_equations can
950+
# be estimated, to one less than the kernel needs
951+
SYSTEM_GMM_COVARIANCE_FEW = [
952+
(kernel, nobs)
953+
for kernel in CANONICAL
954+
for nobs in range(3, fewest_observations(kernel))
955+
]
929956

930957

931958
@pytest.mark.parametrize(("kernel", "nobs"), SYSTEM_GMM_COVARIANCE_FEW)
932959
def test_system_gmm_covariance_raises_when_fit_with_too_few_observations(kernel, nobs):
933-
mod = IVSystemGMM(system_equations(nobs, True))
960+
mod = IVSystemGMM(gmm_equations(nobs))
934961
with pytest.raises(ValueError, match=re.escape(too_few_message(kernel, nobs))):
935962
mod.fit(cov_type="kernel", kernel=kernel)
936963

937964

938965
def test_system_gmm_default_bandwidth_raises_when_fit_with_too_few_observations():
939-
mod = IVSystemGMM(system_equations(3, True), weight_type="kernel")
966+
mod = IVSystemGMM(gmm_equations(3), weight_type="kernel")
940967
with pytest.warns(DefaultBandwidthWarning):
941968
with pytest.raises(ValueError, match=re.escape(too_few_message("bartlett", 3))):
942969
mod.fit()
@@ -945,7 +972,7 @@ def test_system_gmm_default_bandwidth_raises_when_fit_with_too_few_observations(
945972
@pytest.mark.parametrize("kernel", CANONICAL)
946973
def test_system_gmm_explicit_bandwidth_works_with_the_observations_that_raise(kernel):
947974
nobs = fewest_observations(kernel) - 1
948-
equations = system_equations(nobs, True)
975+
equations = gmm_equations(nobs)
949976
explicit = IVSystemGMM(
950977
equations, weight_type="kernel", kernel=kernel, bandwidth=1
951978
).fit()
@@ -959,7 +986,7 @@ def test_system_gmm_explicit_bandwidth_works_with_the_observations_that_raise(ke
959986
@pytest.mark.parametrize("kernel", CANONICAL)
960987
def test_system_gmm_with_the_fewest_observations(kernel):
961988
nobs = fewest_observations(kernel)
962-
equations = system_equations(nobs, True)
989+
equations = gmm_equations(nobs)
963990
res = IVSystemGMM(
964991
equations, weight_type="kernel", kernel=kernel, optimal_bw=True
965992
).fit(cov_type="kernel", kernel=kernel)

0 commit comments

Comments
 (0)