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
8 changes: 8 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[flake8]
# Leave at 99 for now
max-line-length = 99
ignore = E203,W503,BLK100
per-file-ignores =
linearmodels/panel/data.py: E704
linearmodels/shared/utility.py: F811, E704
linearmodels/panel/utility.py: F811
47 changes: 28 additions & 19 deletions ci/azure_template_posix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ parameters:

jobs:

- job: ${{ parameters.name }}Test
- job: ${{ parameters.name }}_Test
pool:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
python310_minimums:
python310_minimums_wheel:
python.version: '3.10'
NUMPY: 1.22.3
SCIPY: 1.8.0
PANDAS: 1.3.0
STATSMODELS: 0.13.1
XARRAY: 0.21.0
FORMULAIC: 1.0.2
test.install: true
python310_mid:
test.wheel: true
python310_mid_sdist:
python.version: '3.10'
NUMPY: 1.23.0
SCIPY: 1.9.0
Expand All @@ -34,24 +34,24 @@ jobs:
XARRAY: 2022.6.0
XXHASH: true
FORMULAIC: 1.0.2
test.install: true
python310_recent:
test.sdist: true
python310_recent_wheel:
python.version: '3.10'
NUMPY: 1.24.0
SCIPY: 1.12.0
PANDAS: 2.0.0
STATSMODELS: 0.14.0
XARRAY: 2023.4.0
FORMULAIC: 1.1.0
test.install: true
test.wheel: true
python310_latest:
python.version: '3.10'
FORMULAIC: 1.2.0
XXHASH: true
PYARROW: true
python310_no_cython:
python.version: '3.10'
LM_NO_BINARY: 1
BUILD_FLAGS: '-Csetup-args=-Dno-binary=true'
python311_latest:
python.version: '3.11'
XXHASH: true
Expand All @@ -64,6 +64,7 @@ jobs:
python.version: '3.13'
XXHASH: true
PYARROW: true
BUILD_FLAGS: '-Csetup-args=-Dcython-coverage=true'
python313_copy_on_write:
python.version: '3.12'
XXHASH: true
Expand All @@ -81,7 +82,7 @@ jobs:
displayName: 'Use Python $(python.version)'

- script: |
python -m pip install --upgrade pip setuptools>=61 wheel
python -m pip install --upgrade pip wheel build
python -m pip install -r requirements.txt
python -m pip install -r requirements-test.txt
python -m pip install -r requirements-dev.txt
Expand All @@ -102,18 +103,26 @@ jobs:
displayName: 'Check style and formatting'

- script: |
echo "Installing to site packages"
python -m pip wheel . --wheel-dir ./dist/ --no-build-isolation
echo "Installing to site packages (sdist)"
python -m build --sdist . -v
SDIST=$(ls -t ./dist/linearmodels-*.tar.gz | head -1)
pip install ${SDIST} -v
displayName: 'Install linearmodels (site-packages)'
condition: eq(variables['test.sdist'], 'true')

- script: |
echo "Installing to site packages (wheel)"
python -m pip wheel . --wheel-dir ./dist/
WHL=$(ls -t ./dist/linearmodels-*.whl | head -1)
pip install ${WHL}
pip install ${WHL} -v
displayName: 'Install linearmodels (site-packages)'
condition: eq(variables['test.install'], 'true')
condition: eq(variables['test.wheel'], 'true')

- script: |
echo python -m pip install -e . -v --no-build-isolation
python -m pip install -e . -v --no-build-isolation
echo python -m pip install --no-build-isolation -vv -e . ${FLAGS}
python -m pip install --no-build-isolation -vv -e . ${FLAGS}
displayName: 'Install linearmodels (editable)'
condition: ne(variables['test.install'], 'true')
condition: and(ne(variables['test.wheel'], 'true'), ne(variables['test.sdist'], 'true'))

- script: |
echo "Testing site packages"
Expand All @@ -122,17 +131,17 @@ jobs:
python -c "import linearmodels; linearmodels.test(['-n', 'auto', '--junitxml=../junit/test-results.xml'])"
popd
displayName: 'Run tests (site-packages)'
condition: and(eq(variables['test.install'], 'true'), ne(variables['pip.pre'], 'true'))
condition: or(eq(variables['test.wheel'], 'true'), eq(variables['test.sdist'], 'true'))

- script: |
echo "Testing editable install"
if [[ ${COVERAGE} == "true" ]]; then
export COVERAGE_OPTS="--cov-config .coveragerc --cov=linearmodels --cov-report xml:coverage.xml --cov-report term"
export COVERAGE_OPTS="--cov=linearmodels --cov-report xml:coverage.xml --cov-report term"
fi
echo pytest -m "${PYTEST_PATTERN}" --junitxml=junit/test-results.xml -n auto --durations=25 ${COVERAGE_OPTS} linearmodels/tests
pytest -m "${PYTEST_PATTERN}" --junitxml=junit/test-results.xml -n auto --durations=25 ${COVERAGE_OPTS} linearmodels/tests
displayName: 'Run tests (editable)'
condition: and(ne(variables['test.install'], 'true'), ne(variables['pip.pre'], 'true'))
condition: and(and(ne(variables['test.wheel'], 'true'), ne(variables['test.sdist'], 'true')), ne(variables['pip.pre'], 'true'))

- script: |
echo "Testing pip-pre"
Expand Down
9 changes: 3 additions & 6 deletions examples/system_examples.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@
"\n",
"cov = res.sigma\n",
"std = np.sqrt(np.diag(res.sigma)[:, None])\n",
"regions = [k for k in mod_data.keys()]\n",
"regions = list(mod_data.keys())\n",
"corr = pd.DataFrame(cov / (std @ std.T), columns=regions, index=regions)\n",
"\n",
"sns.heatmap(corr, vmax=0.8, square=True)\n",
Expand Down Expand Up @@ -257,9 +257,7 @@
"outputs": [],
"source": [
"# TODO: Implement method to compare across equations\n",
"params = []\n",
"for label in res.equation_labels:\n",
" params.append(res.equations[label].params)\n",
"params = [res.equations[label].params for label in res.equation_labels]\n",
"params = pd.concat(params, axis=1)\n",
"params.columns = res.equation_labels\n",
"params.T.style.format(\"{:0.3f}\")"
Expand Down Expand Up @@ -732,7 +730,6 @@
"outputs": [],
"source": [
"import statsmodels.api as sm\n",
"\n",
"from linearmodels.datasets import french\n",
"\n",
"data = french.load()\n",
Expand Down Expand Up @@ -779,7 +776,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
"version": "3.13.7"
},
"pycharm": {
"stem_cell": {
Expand Down
17 changes: 8 additions & 9 deletions examples/system_three-stage-ls.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
"metadata": {},
"outputs": [],
"source": [
"equations = dict(hours=hours, lwage=lwage)\n",
"equations = {\"hours\": hours, \"lwage\": lwage}\n",
"system_2sls = IV3SLS.from_formula(equations, data)\n",
"system_2sls_res = system_2sls.fit(method=\"ols\", cov_type=\"unadjusted\")\n",
"print(system_2sls_res)"
Expand All @@ -154,7 +154,6 @@
"metadata": {},
"outputs": [],
"source": [
"equations = dict(hours=hours, lwage=lwage)\n",
"system_3sls = IV3SLS.from_formula(equations, data)\n",
"system_3sls_res = system_3sls.fit(method=\"gls\", cov_type=\"unadjusted\")\n",
"print(system_3sls_res)"
Expand Down Expand Up @@ -196,7 +195,7 @@
" \"instruments\": data[[\"age\", \"kidslt6\", \"nwifeinc\"]],\n",
"}\n",
"\n",
"equations = dict(hours=hours, lwage=lwage)\n",
"equations = {\"hours\": hours, \"lwage\": lwage}\n",
"system_3sls = IV3SLS(equations)\n",
"system_3sls_res = system_3sls.fit(cov_type=\"unadjusted\")\n",
"print(system_3sls_res)"
Expand All @@ -223,10 +222,10 @@
"metadata": {},
"outputs": [],
"source": [
"equations = dict(\n",
" hours=\"hours ~ educ + age + kidslt6 + nwifeinc + [lwage ~ exper + expersq]\",\n",
" lwage=\"lwage ~ educ + exper + expersq + [hours ~ age + kidslt6 + nwifeinc]\",\n",
")\n",
"equations = {\n",
" \"hours\": \"hours ~ educ + age + kidslt6 + nwifeinc + [lwage ~ exper + expersq]\",\n",
" \"lwage\": \"lwage ~ educ + exper + expersq + [hours ~ age + kidslt6 + nwifeinc]\",\n",
"}\n",
"system_gmm = IVSystemGMM.from_formula(equations, data, weight_type=\"unadjusted\")\n",
"system_gmm_res = system_gmm.fit(cov_type=\"unadjusted\")\n",
"print(system_gmm_res)"
Expand Down Expand Up @@ -295,7 +294,7 @@
"in_sample = df.iloc[:-10000]\n",
"oos = df.iloc[-10000:]\n",
"mod = IV3SLS.from_formula(\n",
" dict(y1=\"y1 ~ x1 + [y2 ~ x2]\", y2=\"y2 ~ x2 + [y1 ~ x1]\"), data=df\n",
" {\"y1\": \"y1 ~ x1 + [y2 ~ x2]\", \"y2\": \"y2 ~ x2 + [y1 ~ x1]\"}, data=df\n",
")\n",
"res = mod.fit()\n",
"print(res)"
Expand Down Expand Up @@ -353,7 +352,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
"version": "3.13.7"
},
"pycharm": {
"stem_cell": {
Expand Down
Empty file added linearmodels/_build/__init__.py
Empty file.
88 changes: 88 additions & 0 deletions linearmodels/_build/git_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
from __future__ import annotations

import os
import setuptools_scm
from packaging.version import Version
from pathlib import Path

ROOT = Path(__file__).parent.parent.parent.absolute()


def get_version() -> tuple[str, tuple[int | str, ...]]:
_version = setuptools_scm.get_version(root=ROOT)
parsed_version = Version(_version)
version_fields: tuple[int | str, ...] = parsed_version.release
if parsed_version.epoch:
version_fields = (f"{parsed_version.epoch}!", *version_fields)
if parsed_version.pre is not None:
version_fields += (f"{parsed_version.pre[0]}{parsed_version.pre[1]}",)

if parsed_version.post is not None:
version_fields += (f"post{parsed_version.post}",)

if parsed_version.dev is not None:
version_fields += (f"dev{parsed_version.dev}",)

if parsed_version.local is not None:
version_fields += (parsed_version.local,)

return _version, version_fields


def write_version_file(
filename: str, version: str, version_fields: tuple[int | str, ...]
) -> None:
template = f"""# file generated by setuptools-scm
# don't change, don't track in version control

__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]

TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Tuple
from typing import Union

VERSION_TUPLE = Tuple[Union[int, str], ...]
else:
VERSION_TUPLE = object

version: str
__version__: str
__version_tuple__: VERSION_TUPLE
version_tuple: VERSION_TUPLE

__version__ = version = '{version}'
__version_tuple__ = version_tuple = {version_fields}
"""

with open(filename, "w") as f:
f.write(template)


if __name__ == "__main__":
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--write", help="Save version to this file")
parser.add_argument(
"--meson-dist",
help="Output path is relative to MESON_DIST_ROOT",
action="store_true",
)
args = parser.parse_args()

version, version_tuple = get_version()

if args.write:
outfile = args.write
if args.meson_dist:
outfile = os.path.join(os.environ.get("MESON_DIST_ROOT", ""), outfile)

# Print human readable output path
relpath = os.path.relpath(outfile)
if relpath.startswith("."):
relpath = outfile
write_version_file(relpath, version, version_tuple)
else:
print(version)
Loading
Loading