Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,47 @@ python -m pip install -r requirements.txt -r requirements-dev.txt
python -m pip install -e . --no-build-isolation
```

## Running the tests

The tests are installed with linearmodels. They need pytest 9 and xarray, and
pytest-xdist to run in parallel.

```bash
python -c "import linearmodels; linearmodels.test(['--skip-slow', '-n', 'auto'])"
```

`--skip-slow` skips the slow tests and `--skip-examples` the example notebooks.

pytest loads every plugin that is installed in the environment, and the test
configuration of linearmodels is strict, so that, for example, a marker that is
not registered is an error. A plugin that uses such a marker makes tests fail
with a message such as `'gpu' not found in markers configuration option`. To run
the tests without the other plugins, turn off their automatic loading and load
pytest-xdist explicitly. This works with `python -m pytest` too.

```bash
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -c "import linearmodels; linearmodels.test(['-p', 'xdist', '-n', 'auto'])"
```

When the tests run in several processes with pytest-xdist, limit the BLAS
libraries to one thread in each process. Otherwise every process starts as many
threads as there are cores, and excessive context switching makes the tests run
very slow. This problem is particularly acute on machines with high CPU counts.

```bash
export MKL_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
export OMP_NUM_THREADS=1
```

or, in PowerShell,

```powershell
$env:MKL_NUM_THREADS = 1
$env:OPENBLAS_NUM_THREADS = 1
$env:OMP_NUM_THREADS = 1
```

## Documentation

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

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

### Documentation

Expand Down
4 changes: 3 additions & 1 deletion linearmodels/tests/iv/test_new_feature_hardening.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ def run_docstring_examples(obj, name):
failures = []
with_examples = set()
for test in finder.find(obj, name, globs={}):
runner = doctest.DocTestRunner(optionflags=doctest.ELLIPSIS)
# verbose=None, the default, is verbose when "-v" is in sys.argv, as it is in
# "pytest -v", and the examples that pass are then written to out as well
runner = doctest.DocTestRunner(verbose=False, optionflags=doctest.ELLIPSIS)
with warnings.catch_warnings():
warnings.simplefilter("ignore", MissingValueWarning)
runner.run(test, out=failures.append)
Expand Down
43 changes: 35 additions & 8 deletions linearmodels/tests/test_kernel_bandwidth_few_observations.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,29 @@ def system_equations(nobs, endogenous=False):
}


def gmm_equations(nobs):
"""
Two equations, each with one endogenous regressor and one instrument

IVSystemGMM inverts the covariance of the moment conditions, in the robust and
the kernel weights. The equations of system_equations(nobs, True) are exactly
identified, so that their 4 moment conditions sum to zero at the estimates and have
rank nobs - 1 or less: their covariance is singular with 4 or fewer observations,
and inverting it only works up to rounding (it raised "Singular matrix" on FreeBSD,
#853). These equations have no constant and 2 moment conditions, whose covariance
has full rank from 3 observations.
"""
first, second = iv_data(nobs, seed=11), iv_data(nobs, seed=111)
return {
f"eq{i}": {
"dependent": data.y,
"endog": data[["xn"]],
"instruments": data[["z1"]],
}
for i, data in enumerate((first, second))
}


@pytest.mark.parametrize("kernel", CANONICAL)
@pytest.mark.parametrize(("model", "endogenous"), [(SUR, False), (IV3SLS, True)])
def test_system_models_raise_when_fit_with_too_few_observations(
Expand Down Expand Up @@ -914,7 +937,7 @@ def test_system_models_explicit_bandwidth_works_with_the_observations_that_raise
def test_system_gmm_weights_raise_when_fit_with_too_few_observations(kernel):
nobs = fewest_observations(kernel) - 1
mod = IVSystemGMM(
system_equations(nobs, True),
gmm_equations(nobs),
weight_type="kernel",
kernel=kernel,
optimal_bw=True,
Expand All @@ -923,20 +946,24 @@ def test_system_gmm_weights_raise_when_fit_with_too_few_observations(kernel):
mod.fit()


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


@pytest.mark.parametrize(("kernel", "nobs"), SYSTEM_GMM_COVARIANCE_FEW)
def test_system_gmm_covariance_raises_when_fit_with_too_few_observations(kernel, nobs):
mod = IVSystemGMM(system_equations(nobs, True))
mod = IVSystemGMM(gmm_equations(nobs))
with pytest.raises(ValueError, match=re.escape(too_few_message(kernel, nobs))):
mod.fit(cov_type="kernel", kernel=kernel)


def test_system_gmm_default_bandwidth_raises_when_fit_with_too_few_observations():
mod = IVSystemGMM(system_equations(3, True), weight_type="kernel")
mod = IVSystemGMM(gmm_equations(3), weight_type="kernel")
with pytest.warns(DefaultBandwidthWarning):
with pytest.raises(ValueError, match=re.escape(too_few_message("bartlett", 3))):
mod.fit()
Expand All @@ -945,7 +972,7 @@ def test_system_gmm_default_bandwidth_raises_when_fit_with_too_few_observations(
@pytest.mark.parametrize("kernel", CANONICAL)
def test_system_gmm_explicit_bandwidth_works_with_the_observations_that_raise(kernel):
nobs = fewest_observations(kernel) - 1
equations = system_equations(nobs, True)
equations = gmm_equations(nobs)
explicit = IVSystemGMM(
equations, weight_type="kernel", kernel=kernel, bandwidth=1
).fit()
Expand All @@ -959,7 +986,7 @@ def test_system_gmm_explicit_bandwidth_works_with_the_observations_that_raise(ke
@pytest.mark.parametrize("kernel", CANONICAL)
def test_system_gmm_with_the_fewest_observations(kernel):
nobs = fewest_observations(kernel)
equations = system_equations(nobs, True)
equations = gmm_equations(nobs)
res = IVSystemGMM(
equations, weight_type="kernel", kernel=kernel, optimal_bw=True
).fit(cov_type="kernel", kernel=kernel)
Expand Down
Loading