Skip to content

Commit 31e7033

Browse files
authored
Merge pull request #594 from bashtage/numpy-3
COMPAT: Add monkey patch for formulaic
2 parents 02633ad + 0382db7 commit 31e7033

24 files changed

+79
-40
lines changed

ci/azure_template_posix.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,8 @@ jobs:
152152
testRunTitle: 'Python $(python.version)'
153153
condition: succeededOrFailed()
154154

155-
- task: PublishCodeCoverageResults@1
155+
- task: PublishCodeCoverageResults@2
156156
inputs:
157-
codeCoverageTool: Cobertura
158157
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'
159158
condition: and(eq(variables['coverage'], 'true'), ne(variables['test.install'], 'true'))
160159

doc/source/conf.py

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import glob
1111
import hashlib
1212
import os
13-
from typing import Dict, List
1413

1514
from packaging.version import parse
1615

examples/system_formulas.ipynb

+3-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@
4646
"from collections import OrderedDict\n",
4747
"\n",
4848
"formula = OrderedDict()\n",
49-
"formula[\n",
50-
" \"benefits\"\n",
51-
"] = \"hrbens ~ educ + exper + expersq + union + south + nrtheast + nrthcen + male\"\n",
49+
"formula[\"benefits\"] = (\n",
50+
" \"hrbens ~ educ + exper + expersq + union + south + nrtheast + nrthcen + male\"\n",
51+
")\n",
5252
"formula[\"earnings\"] = \"hrearn ~ educ + exper + expersq + nrtheast + married + male\""
5353
]
5454
},

linearmodels/asset_pricing/covariance.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Covariance estimators for linear factor models
33
"""
4+
45
from __future__ import annotations
56

67
from numpy import empty, ndarray

linearmodels/asset_pricing/model.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Linear factor models for applications in asset pricing
33
"""
4+
45
from __future__ import annotations
56

67
from typing import Any, Callable, cast

linearmodels/asset_pricing/results.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Results for linear factor models
33
"""
4+
45
from __future__ import annotations
56

67
from linearmodels.compat.statsmodels import Summary

linearmodels/compat/formulaic.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
def monkey_patch_materializers():
2+
from formulaic.materializers.base import FormulaMaterializer
3+
from formulaic.materializers.pandas import PandasMaterializer
4+
5+
if "pandas.DataFrame" not in FormulaMaterializer.REGISTERED_INPUTS:
6+
FormulaMaterializer.REGISTERED_INPUTS["pandas.DataFrame"] = (
7+
FormulaMaterializer.REGISTERED_INPUTS["pandas.core.frame.DataFrame"]
8+
)
9+
if "pandas.DataFrame" not in PandasMaterializer.REGISTERED_INPUTS:
10+
PandasMaterializer.REGISTERED_INPUTS["pandas.DataFrame"] = (
11+
PandasMaterializer.REGISTERED_INPUTS["pandas.core.frame.DataFrame"]
12+
)

linearmodels/iv/_utility.py

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212

1313
from linearmodels.typing import Float64Array
1414

15+
from ..compat.formulaic import monkey_patch_materializers
16+
17+
# Monkey patch parsers if needed, remove once formulaic updated
18+
monkey_patch_materializers()
19+
1520
PARSING_ERROR = """
1621
Conversion of formula blocks to DataFrames failed.
1722
The formula blocks used for conversion were:

linearmodels/iv/absorbing.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ def lsmr_annihilate(
125125
return empty_like(y)
126126
use_cache = use_cache and x_hash is not None
127127
regressor_hash = x_hash if x_hash is not None else ""
128-
default_opts: dict[
129-
str, bool | float | str | ArrayLike | None | dict[str, Any]
130-
] = dict(atol=1e-8, btol=1e-8, show=False)
128+
default_opts: dict[str, bool | float | str | ArrayLike | None | dict[str, Any]] = (
129+
dict(atol=1e-8, btol=1e-8, show=False)
130+
)
131131
assert lsmr_options is not None
132132
default_opts.update(lsmr_options)
133133
resids = []
@@ -835,8 +835,9 @@ def _prepare_interactions(self) -> None:
835835
def _first_time_fit(
836836
self,
837837
use_cache: bool,
838-
absorb_options: None
839-
| (dict[str, bool | float | str | ArrayLike | None | dict[str, Any]]),
838+
absorb_options: None | (
839+
dict[str, bool | float | str | ArrayLike | None | dict[str, Any]]
840+
),
840841
method: str,
841842
) -> None:
842843
weights = (
@@ -947,8 +948,9 @@ def fit(
947948
cov_type: str = "robust",
948949
debiased: bool = False,
949950
method: str = "auto",
950-
absorb_options: None
951-
| (dict[str, bool | float | str | ArrayLike | None | dict[str, Any]]) = None,
951+
absorb_options: None | (
952+
dict[str, bool | float | str | ArrayLike | None | dict[str, Any]]
953+
) = None,
952954
use_cache: bool = True,
953955
lsmr_options: dict[str, float | bool] | None = None,
954956
**cov_config: Any,

linearmodels/iv/model.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Instrumental variable estimators
33
"""
4+
45
from __future__ import annotations
56

67
from typing import Any, TypeVar, Union, cast

linearmodels/iv/results.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Results containers and post-estimation diagnostics for IV models
33
"""
4+
45
from __future__ import annotations
56

67
from linearmodels.compat.statsmodels import Summary

linearmodels/panel/covariance.py

+4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class HomoskedasticCovariance:
7979
where df is ``extra_df`` and n-df is replace by n-df-k if ``debiased`` is
8080
``True``.
8181
"""
82+
8283
ALLOWED_KWARGS: tuple[str, ...] = tuple()
8384
DEFAULT_KERNEL = "newey-west"
8485

@@ -270,6 +271,7 @@ class ClusteredCovariance(HomoskedasticCovariance):
270271
where g is the number of distinct groups and n is the number of
271272
observations.
272273
"""
274+
273275
ALLOWED_KWARGS = ("clusters", "group_debias")
274276

275277
def __init__(
@@ -400,6 +402,7 @@ class DriscollKraay(HomoskedasticCovariance):
400402
where df is ``extra_df`` and n-df is replace by n-df-k if ``debiased`` is
401403
``True``. :math:`K(i, bw)` is the kernel weighting function.
402404
"""
405+
403406
ALLOWED_KWARGS = ("kernel", "bandwidth")
404407
# TODO: Test
405408

@@ -517,6 +520,7 @@ class ACCovariance(HomoskedasticCovariance):
517520
where df is ``extra_df`` and n-df is replace by n-df-k if ``debiased`` is
518521
``True``. :math:`K(i, bw)` is the kernel weighting function.
519522
"""
523+
520524
ALLOWED_KWARGS = ("kernel", "bandwidth")
521525
# TODO: Docstring
522526

linearmodels/panel/data.py

+8-11
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ def __init__(
254254
raise TypeError("Only ndarrays, DataFrames or DataArrays are " "supported")
255255
if convert_dummies:
256256
self._frame = expand_categoricals(self._frame, drop_first)
257-
self._frame = self._frame.astype(np.float64, copy=False)
257+
self._frame = self._frame.astype(np.float64)
258258

259259
time_index = Series(self.index.levels[1])
260260
if not (
@@ -519,32 +519,29 @@ def demean_pass(
519519
return PanelData(current)
520520

521521
@overload
522-
def demean(
522+
def demean( # noqa: E704
523523
self,
524524
group: Literal["entity", "time", "both"],
525525
*,
526526
return_panel: Literal[False],
527-
) -> Float64Array:
528-
...
527+
) -> Float64Array: ...
529528

530529
@overload
531-
def demean(
530+
def demean( # noqa: E704
532531
self,
533532
group: Literal["entity", "time", "both"] = ...,
534533
weights: PanelData | None = ...,
535534
return_panel: Literal[True] = ...,
536535
low_memory: bool = ...,
537-
) -> PanelData:
538-
...
536+
) -> PanelData: ...
539537

540538
@overload
541-
def demean(
539+
def demean( # noqa: E704
542540
self,
543541
group: Literal["entity", "time", "both"],
544542
weights: PanelData | None,
545543
return_panel: Literal[False],
546-
) -> Float64Array:
547-
...
544+
) -> Float64Array: ... # noqa: E704
548545

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

762759

763760
PanelDataLike = Union[PanelData, ArrayLike]

linearmodels/panel/model.py

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
from linearmodels.compat.formulaic import monkey_patch_materializers
4+
35
from collections.abc import Mapping
46
from typing import Any, NamedTuple, Union, cast
57

@@ -61,6 +63,9 @@
6163
NumericArray,
6264
)
6365

66+
# Monkey patch parsers if needed, remove once formulaic updated
67+
monkey_patch_materializers()
68+
6469
CovarianceEstimator = Union[
6570
ACCovariance,
6671
ClusteredCovariance,

linearmodels/shared/hypotheses.py

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
from linearmodels.compat.formulaic import monkey_patch_materializers
4+
35
from collections.abc import Mapping
46

57
from formulaic.utils.constraints import LinearConstraints
@@ -9,6 +11,9 @@
911

1012
from linearmodels.typing import ArrayLike
1113

14+
# Monkey patch parsers if needed, remove once formulaic updated
15+
monkey_patch_materializers()
16+
1217

1318
class WaldTestStatistic:
1419
"""

linearmodels/shared/utility.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@
2323

2424

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

29-
def __getitem__(self, __k: _KT) -> _VT_co:
30-
...
28+
def __getitem__(self, __k: _KT) -> _VT_co: ... # noqa: E704
3129

3230

3331
def _new_attr_dict_(*args: Iterable[tuple[Any, Any]]) -> AttrDict:

linearmodels/system/gmm.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Covariance and weight estimation for GMM IV estimators
33
"""
4+
45
from __future__ import annotations
56

67
from collections.abc import Sequence

linearmodels/system/model.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111
Systems of Simultaneous Equations in R. Journal of Statistical Software,
1212
23(4), 1 - 40. doi:http://dx.doi.org/10.18637/jss.v023.i04
1313
"""
14+
1415
from __future__ import annotations
1516

17+
from linearmodels.compat.formulaic import monkey_patch_materializers
18+
1619
from collections.abc import Mapping, Sequence
1720
from functools import reduce
1821
import textwrap
@@ -57,6 +60,9 @@
5760

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

63+
# Monkey patch parsers if needed, remove once formulaic updated
64+
monkey_patch_materializers()
65+
6066
UNKNOWN_EQ_TYPE = """
6167
Contents of each equation must be either a dictionary with keys "dependent"
6268
and "exog" or a 2-element tuple of he form (dependent, exog).
@@ -877,8 +883,7 @@ def _common_indiv_results(
877883
constant: bool,
878884
total_ss: float,
879885
*,
880-
weight_est: None
881-
| (
886+
weight_est: None | (
882887
HomoskedasticWeightMatrix | HeteroskedasticWeightMatrix | KernelWeightMatrix
883888
) = None,
884889
) -> AttrDict:

linearmodels/tests/iv/results/simulated-test-data.py

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
Will also test other configurations - small, covariance-estimators, constant
1313
1414
"""
15+
1516
import numpy as np
1617
from numpy.random import multivariate_normal, seed
1718
import pandas as pd

linearmodels/tests/system/results/execute-stata-3sls.py

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Important cases
33
44
"""
5+
56
import os
67
import subprocess
78

linearmodels/tests/system/results/execute-stata.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
2. Small sample adjustment
66
3. Constraints across equations
77
"""
8+
89
import os
910
import subprocess
1011

linearmodels/typing/__init__.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,6 @@
4848
np.ndarray[Any, np.dtype[np.floating[Any]]], # pragma: no cover
4949
] # pragma: no cover
5050
else:
51-
IntArray = (
52-
Float64Array
53-
) = Int64Array = Int32Array = BoolArray = AnyArray = NumericArray = np.ndarray
51+
IntArray = Float64Array = Int64Array = Int32Array = BoolArray = AnyArray = (
52+
NumericArray
53+
) = np.ndarray

linearmodels/typing/data.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
AnyArray = np.ndarray[Any, Any] # pragma: no cover
3030
Uint32Array = np.ndarray[Any, np.dtype[np.uint32]] # pragma: no cover
3131
else:
32-
Uint32Array = (
33-
IntArray
34-
) = Float64Array = Int64Array = Int32Array = BoolArray = AnyArray = NDArray
32+
Uint32Array = IntArray = Float64Array = Int64Array = Int32Array = BoolArray = (
33+
AnyArray
34+
) = NDArray
3535

3636
__all__ = [
3737
"Float64Array",

setup.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
from setuptools import Extension, find_namespace_packages, setup
22
from setuptools.dist import Distribution
3+
from setuptools.errors import CCompilerError, ExecError, PlatformError
34

4-
from distutils.errors import CCompilerError, DistutilsExecError, DistutilsPlatformError
55
import glob
66
import os
7-
from typing import Dict
87

98
try:
109
from Cython.Build import cythonize
@@ -136,8 +135,8 @@ def run_setup(binary: bool = True) -> None:
136135
run_setup(binary=build_binary)
137136
except (
138137
CCompilerError,
139-
DistutilsExecError,
140-
DistutilsPlatformError,
138+
ExecError,
139+
PlatformError,
141140
OSError,
142141
ValueError,
143142
ImportError,

0 commit comments

Comments
 (0)