Skip to content

Commit

Permalink
COMPAT: Add monkey patch for formulaic
Browse files Browse the repository at this point in the history
  • Loading branch information
bashtage committed Apr 16, 2024
1 parent a8f8dee commit 224eaa0
Show file tree
Hide file tree
Showing 23 changed files with 78 additions and 38 deletions.
1 change: 0 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import glob
import hashlib
import os
from typing import Dict, List

from packaging.version import parse

Expand Down
6 changes: 3 additions & 3 deletions examples/system_formulas.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
"from collections import OrderedDict\n",
"\n",
"formula = OrderedDict()\n",
"formula[\n",
" \"benefits\"\n",
"] = \"hrbens ~ educ + exper + expersq + union + south + nrtheast + nrthcen + male\"\n",
"formula[\"benefits\"] = (\n",
" \"hrbens ~ educ + exper + expersq + union + south + nrtheast + nrthcen + male\"\n",
")\n",
"formula[\"earnings\"] = \"hrearn ~ educ + exper + expersq + nrtheast + married + male\""
]
},
Expand Down
1 change: 1 addition & 0 deletions linearmodels/asset_pricing/covariance.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Covariance estimators for linear factor models
"""

from __future__ import annotations

from numpy import empty, ndarray
Expand Down
1 change: 1 addition & 0 deletions linearmodels/asset_pricing/model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Linear factor models for applications in asset pricing
"""

from __future__ import annotations

from typing import Any, Callable, cast
Expand Down
1 change: 1 addition & 0 deletions linearmodels/asset_pricing/results.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Results for linear factor models
"""

from __future__ import annotations

from linearmodels.compat.statsmodels import Summary
Expand Down
12 changes: 12 additions & 0 deletions linearmodels/compat/formulaic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
def monkey_patch_materializers():
from formulaic.materializers.base import FormulaMaterializer
from formulaic.materializers.pandas import PandasMaterializer

if "pandas.DataFrame" not in FormulaMaterializer.REGISTERED_INPUTS:
FormulaMaterializer.REGISTERED_INPUTS["pandas.DataFrame"] = (
FormulaMaterializer.REGISTERED_INPUTS["pandas.core.frame.DataFrame"]
)
if "pandas.DataFrame" not in PandasMaterializer.REGISTERED_INPUTS:
PandasMaterializer.REGISTERED_INPUTS["pandas.DataFrame"] = (

Check warning on line 10 in linearmodels/compat/formulaic.py

View check run for this annotation

Codecov / codecov/patch

linearmodels/compat/formulaic.py#L10

Added line #L10 was not covered by tests
PandasMaterializer.REGISTERED_INPUTS["pandas.core.frame.DataFrame"]
)
5 changes: 5 additions & 0 deletions linearmodels/iv/_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

from linearmodels.typing import Float64Array

from ..compat.formulaic import monkey_patch_materializers

# Monkey patch parsers if needed, remove once formulaic updated
monkey_patch_materializers()

PARSING_ERROR = """
Conversion of formula blocks to DataFrames failed.
The formula blocks used for conversion were:
Expand Down
16 changes: 9 additions & 7 deletions linearmodels/iv/absorbing.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ def lsmr_annihilate(
return empty_like(y)
use_cache = use_cache and x_hash is not None
regressor_hash = x_hash if x_hash is not None else ""
default_opts: dict[
str, bool | float | str | ArrayLike | None | dict[str, Any]
] = dict(atol=1e-8, btol=1e-8, show=False)
default_opts: dict[str, bool | float | str | ArrayLike | None | dict[str, Any]] = (
dict(atol=1e-8, btol=1e-8, show=False)
)
assert lsmr_options is not None
default_opts.update(lsmr_options)
resids = []
Expand Down Expand Up @@ -835,8 +835,9 @@ def _prepare_interactions(self) -> None:
def _first_time_fit(
self,
use_cache: bool,
absorb_options: None
| (dict[str, bool | float | str | ArrayLike | None | dict[str, Any]]),
absorb_options: None | (
dict[str, bool | float | str | ArrayLike | None | dict[str, Any]]
),
method: str,
) -> None:
weights = (
Expand Down Expand Up @@ -947,8 +948,9 @@ def fit(
cov_type: str = "robust",
debiased: bool = False,
method: str = "auto",
absorb_options: None
| (dict[str, bool | float | str | ArrayLike | None | dict[str, Any]]) = None,
absorb_options: None | (
dict[str, bool | float | str | ArrayLike | None | dict[str, Any]]
) = None,
use_cache: bool = True,
lsmr_options: dict[str, float | bool] | None = None,
**cov_config: Any,
Expand Down
1 change: 1 addition & 0 deletions linearmodels/iv/model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Instrumental variable estimators
"""

from __future__ import annotations

from typing import Any, TypeVar, Union, cast
Expand Down
1 change: 1 addition & 0 deletions linearmodels/iv/results.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Results containers and post-estimation diagnostics for IV models
"""

from __future__ import annotations

from linearmodels.compat.statsmodels import Summary
Expand Down
4 changes: 4 additions & 0 deletions linearmodels/panel/covariance.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class HomoskedasticCovariance:
where df is ``extra_df`` and n-df is replace by n-df-k if ``debiased`` is
``True``.
"""

ALLOWED_KWARGS: tuple[str, ...] = tuple()
DEFAULT_KERNEL = "newey-west"

Expand Down Expand Up @@ -270,6 +271,7 @@ class ClusteredCovariance(HomoskedasticCovariance):
where g is the number of distinct groups and n is the number of
observations.
"""

ALLOWED_KWARGS = ("clusters", "group_debias")

def __init__(
Expand Down Expand Up @@ -400,6 +402,7 @@ class DriscollKraay(HomoskedasticCovariance):
where df is ``extra_df`` and n-df is replace by n-df-k if ``debiased`` is
``True``. :math:`K(i, bw)` is the kernel weighting function.
"""

ALLOWED_KWARGS = ("kernel", "bandwidth")
# TODO: Test

Expand Down Expand Up @@ -517,6 +520,7 @@ class ACCovariance(HomoskedasticCovariance):
where df is ``extra_df`` and n-df is replace by n-df-k if ``debiased`` is
``True``. :math:`K(i, bw)` is the kernel weighting function.
"""

ALLOWED_KWARGS = ("kernel", "bandwidth")
# TODO: Docstring

Expand Down
19 changes: 8 additions & 11 deletions linearmodels/panel/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def __init__(
raise TypeError("Only ndarrays, DataFrames or DataArrays are " "supported")
if convert_dummies:
self._frame = expand_categoricals(self._frame, drop_first)
self._frame = self._frame.astype(np.float64, copy=False)
self._frame = self._frame.astype(np.float64)

time_index = Series(self.index.levels[1])
if not (
Expand Down Expand Up @@ -519,32 +519,29 @@ def demean_pass(
return PanelData(current)

@overload
def demean(
def demean( # noqa: E704
self,
group: Literal["entity", "time", "both"],
*,
return_panel: Literal[False],
) -> Float64Array:
...
) -> Float64Array: ...

Check notice

Code scanning / CodeQL

Statement has no effect Note

This statement has no effect.

@overload
def demean(
def demean( # noqa: E704
self,
group: Literal["entity", "time", "both"] = ...,
weights: PanelData | None = ...,
return_panel: Literal[True] = ...,
low_memory: bool = ...,
) -> PanelData:
...
) -> PanelData: ...

Check notice

Code scanning / CodeQL

Statement has no effect Note

This statement has no effect.

@overload
def demean(
def demean( # noqa: E704
self,
group: Literal["entity", "time", "both"],
weights: PanelData | None,
return_panel: Literal[False],
) -> Float64Array:
...
) -> Float64Array: ... # noqa: E704

Check notice

Code scanning / CodeQL

Statement has no effect Note

This statement has no effect.

def demean(
self,
Expand Down Expand Up @@ -757,7 +754,7 @@ def dummies(self, group: str = "entity", drop_first: bool = False) -> DataFrame:
cols = self.entities if group == "entity" else self.time
# TODO: Incorrect typing in pandas-stubs not handling Hashable | None
dummy_cols = [c for c in cols if c in dummies]
return dummies[dummy_cols].astype(np.float64, copy=False) # type: ignore
return dummies[dummy_cols].astype(np.float64) # type: ignore


PanelDataLike = Union[PanelData, ArrayLike]
5 changes: 5 additions & 0 deletions linearmodels/panel/model.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

from linearmodels.compat.formulaic import monkey_patch_materializers

from collections.abc import Mapping
from typing import Any, NamedTuple, Union, cast

Expand Down Expand Up @@ -61,6 +63,9 @@
NumericArray,
)

# Monkey patch parsers if needed, remove once formulaic updated
monkey_patch_materializers()

CovarianceEstimator = Union[
ACCovariance,
ClusteredCovariance,
Expand Down
5 changes: 5 additions & 0 deletions linearmodels/shared/hypotheses.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

from linearmodels.compat.formulaic import monkey_patch_materializers

from collections.abc import Mapping

from formulaic.utils.constraints import LinearConstraints
Expand All @@ -9,6 +11,9 @@

from linearmodels.typing import ArrayLike

# Monkey patch parsers if needed, remove once formulaic updated
monkey_patch_materializers()


class WaldTestStatistic:
"""
Expand Down
6 changes: 2 additions & 4 deletions linearmodels/shared/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@


class SupportsKeysAndGetItem(Protocol[_KT, _VT_co]):
def keys(self) -> Iterable[_KT]:
...
def keys(self) -> Iterable[_KT]: ... # noqa: E704

Check notice

Code scanning / CodeQL

Statement has no effect Note

This statement has no effect.

def __getitem__(self, __k: _KT) -> _VT_co:
...
def __getitem__(self, __k: _KT) -> _VT_co: ... # noqa: E704

Check notice

Code scanning / CodeQL

Statement has no effect Note

This statement has no effect.


def _new_attr_dict_(*args: Iterable[tuple[Any, Any]]) -> AttrDict:
Expand Down
1 change: 1 addition & 0 deletions linearmodels/system/gmm.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Covariance and weight estimation for GMM IV estimators
"""

from __future__ import annotations

from collections.abc import Sequence
Expand Down
9 changes: 7 additions & 2 deletions linearmodels/system/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
Systems of Simultaneous Equations in R. Journal of Statistical Software,
23(4), 1 - 40. doi:http://dx.doi.org/10.18637/jss.v023.i04
"""

from __future__ import annotations

from linearmodels.compat.formulaic import monkey_patch_materializers

from collections.abc import Mapping, Sequence
from functools import reduce
import textwrap
Expand Down Expand Up @@ -57,6 +60,9 @@

__all__ = ["SUR", "IV3SLS", "IVSystemGMM", "LinearConstraint"]

# Monkey patch parsers if needed, remove once formulaic updated
monkey_patch_materializers()

UNKNOWN_EQ_TYPE = """
Contents of each equation must be either a dictionary with keys "dependent"
and "exog" or a 2-element tuple of he form (dependent, exog).
Expand Down Expand Up @@ -877,8 +883,7 @@ def _common_indiv_results(
constant: bool,
total_ss: float,
*,
weight_est: None
| (
weight_est: None | (
HomoskedasticWeightMatrix | HeteroskedasticWeightMatrix | KernelWeightMatrix
) = None,
) -> AttrDict:
Expand Down
1 change: 1 addition & 0 deletions linearmodels/tests/iv/results/simulated-test-data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
Will also test other configurations - small, covariance-estimators, constant
"""

import numpy as np
from numpy.random import multivariate_normal, seed
import pandas as pd
Expand Down
1 change: 1 addition & 0 deletions linearmodels/tests/system/results/execute-stata-3sls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Important cases
"""

import os
import subprocess

Expand Down
1 change: 1 addition & 0 deletions linearmodels/tests/system/results/execute-stata.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
2. Small sample adjustment
3. Constraints across equations
"""

import os
import subprocess

Expand Down
6 changes: 3 additions & 3 deletions linearmodels/typing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@
np.ndarray[Any, np.dtype[np.floating[Any]]], # pragma: no cover
] # pragma: no cover
else:
IntArray = (
Float64Array
) = Int64Array = Int32Array = BoolArray = AnyArray = NumericArray = np.ndarray
IntArray = Float64Array = Int64Array = Int32Array = BoolArray = AnyArray = (
NumericArray
) = np.ndarray
6 changes: 3 additions & 3 deletions linearmodels/typing/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
AnyArray = np.ndarray[Any, Any] # pragma: no cover
Uint32Array = np.ndarray[Any, np.dtype[np.uint32]] # pragma: no cover
else:
Uint32Array = (
IntArray
) = Float64Array = Int64Array = Int32Array = BoolArray = AnyArray = NDArray
Uint32Array = IntArray = Float64Array = Int64Array = Int32Array = BoolArray = (
AnyArray
) = NDArray

__all__ = [
"Float64Array",
Expand Down
7 changes: 3 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from setuptools import Extension, find_namespace_packages, setup
from setuptools.dist import Distribution
from setuptools.errors import CCompilerError, ExecError, PlatformError

from distutils.errors import CCompilerError, DistutilsExecError, DistutilsPlatformError
import glob
import os
from typing import Dict

try:
from Cython.Build import cythonize
Expand Down Expand Up @@ -136,8 +135,8 @@ def run_setup(binary: bool = True) -> None:
run_setup(binary=build_binary)
except (
CCompilerError,
DistutilsExecError,
DistutilsPlatformError,
ExecError,
PlatformError,
OSError,
ValueError,
ImportError,
Expand Down

0 comments on commit 224eaa0

Please sign in to comment.