Repository: statsmodels/statsmodels

Issue:
TST: test failures, mainly pandas 2.0
pandas index testing int32 versus int64 only on Windows

FAILED statsmodels/tsa/tests/test_deterministic.py::test_range_casting - Asse...
FAILED statsmodels/formula/tests/test_formula.py::test_patsy_missing_data - A...
FAILED statsmodels/formula/tests/test_formula.py::test_formula_predict_series

It looks like the pandas testing asserts are too picky

```
>       assert_attr_equal("dtype", left, right, obj=obj)
E       AssertionError: DataFrame.index are different
E       
E       Attribute "dtype" are different
E       [left]:  int32
E       [right]: int64
```

```
>       assert_attr_equal("dtype", left, right, obj=obj)
E       AssertionError: Series.index are different
E       
E       Attribute "dtype" are different
E       [left]:  int64
E       [right]: int32
```

https://dev.azure.com/statsmodels/statsmodels-testing/_build/results?buildId=5078&view=logs&j=ebc56dac-6f4d-5150-6aa3-fbf780873fe8&t=035ec20e-5b65-57c3-c467-de7ec870fc7c&l=891


Those errors are messy
The formula failures are patsy creating an int32 index in predict when exog in predict is dict or recarray, i.e. patsy needs to create an index because it's not in the exog.
So statsmodels does not choose any of the int dtypes of the index. Plus it's not consistent across machines because those only fail on Windows.
:(

The assert function is in our `testing` and delegates to the specific pandas assert function.
We need options for our assert function, so we can skip specific parts, i.e. add kwargs to forward to the pandas functions.




Discussion:
linux and mac only fail with #8775

pre-testing has additional failures:

FAILED statsmodels/distributions/tests/test_tools.py::test_bernstein_1d - Ass...
FAILED statsmodels/iolib/tests/test_table.py::TestSimpleTable::test_regression_with_tuples
FAILED statsmodels/stats/tests/test_descriptivestats.py::test_extension_types
FAILED statsmodels/tools/tests/test_rootfinding.py::test_brentq_expanding - K...

and the

FAILED statsmodels/regression/tests/test_recursive_ls.py::test_glm_constrained
FAILED statsmodels/regression/tests/test_recursive_ls.py::test_constraints_stata
FAILED statsmodels/regression/tests/test_recursive_ls.py::test_multiple_constraints

```

2023-04-06T12:49:33.6336610Z ______________________________ test_bernstein_1d _______________________________
2023-04-06T12:49:33.6337235Z [gw0] linux -- Python 3.11.2 /opt/hostedtoolcache/Python/3.11.2/x64/bin/python
2023-04-06T12:49:33.6337493Z 
2023-04-06T12:49:33.6337781Z     def test_bernstein_1d():
2023-04-06T12:49:33.6338069Z         k = 5
2023-04-06T12:49:33.6338358Z         xg1 = np.arange(k) / (k - 1)
2023-04-06T12:49:33.6338669Z         xg2 = np.arange(2 * k) / (2 * k - 1)
2023-04-06T12:49:33.6338988Z         # verify linear coefficients are mapped to themselves
2023-04-06T12:49:33.6339331Z         res_bp = dt._eval_bernstein_1d(xg2, xg1)
2023-04-06T12:49:33.6339641Z         assert_allclose(res_bp, xg2, atol=1e-12)
2023-04-06T12:49:33.6339928Z     
2023-04-06T12:49:33.6340230Z         res_bp = dt._eval_bernstein_1d(xg2, xg1, method="beta")
2023-04-06T12:49:33.6340563Z >       assert_allclose(res_bp, xg2, atol=1e-12)
2023-04-06T12:49:33.6340785Z 
2023-04-06T12:49:33.6341098Z statsmodels/distributions/tests/test_tools.py:131: 
2023-04-06T12:49:33.6341441Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
2023-04-06T12:49:33.6341669Z 
2023-04-06T12:49:33.6342049Z args = (<function assert_allclose.<locals>.compare at 0x7f7d31809c60>, array([0.        , 0.11111111, 0.22222222, 0.33333333,... , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
2023-04-06T12:49:33.6342473Z        0.55555556, 0.66666667, 0.77777778, 0.88888889, 1.        ]))
2023-04-06T12:49:33.6342952Z kwds = {'equal_nan': True, 'err_msg': '', 'header': 'Not equal to tolerance rtol=1e-07, atol=1e-12', 'verbose': True}
2023-04-06T12:49:33.6343354Z 
2023-04-06T12:49:33.6343626Z     @wraps(func)
2023-04-06T12:49:33.6343910Z     def inner(*args, **kwds):
2023-04-06T12:49:33.6344210Z         with self._recreate_cm():
2023-04-06T12:49:33.6344514Z >           return func(*args, **kwds)
2023-04-06T12:49:33.6344808Z E           AssertionError: 
2023-04-06T12:49:33.6345180Z E           Not equal to tolerance rtol=1e-07, atol=1e-12
2023-04-06T12:49:33.6345488Z E           
2023-04-06T12:49:33.6345781Z E           Mismatched elements: 1 / 10 (10%)
2023-04-06T12:49:33.6346087Z E           Max absolute difference: 1.
2023-04-06T12:49:33.6346381Z E           Max relative difference: 1.
2023-04-06T12:49:33.6346710Z E            x: array([0.      , 0.111111, 0.222222, 0.333333, 0.444444, 0.555556,
2023-04-06T12:49:33.6347054Z E                  0.666667, 0.777778, 0.888889, 0.      ])
2023-04-06T12:49:33.6347392Z E            y: array([0.      , 0.111111, 0.222222, 0.333333, 0.444444, 0.555556,
2023-04-06T12:49:33.6348174Z E                  0.666667, 0.777778, 0.888889, 1.      ])
2023-04-06T12:49:33.6348409Z 
2023-04-06T12:49:33.6348732Z /opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/contextlib.py:81: AssertionError



2023-04-06T12:49:33.6349110Z _________________ TestSimpleTable.test_regression_with_tuples __________________
2023-04-06T12:49:33.6349568Z [gw1] linux -- Python 3.11.2 /opt/hostedtoolcache/Python/3.11.2/x64/bin/python
2023-04-06T12:49:33.6349827Z 
2023-04-06T12:49:33.6350141Z self = <statsmodels.iolib.tests.test_table.TestSimpleTable object at 0x7f95189b7210>
2023-04-06T12:49:33.6350393Z 
2023-04-06T12:49:33.6350674Z     def test_regression_with_tuples(self):
2023-04-06T12:49:33.6350986Z         i = pandas.Series([1, 2, 3, 4] * 10, name="i")
2023-04-06T12:49:33.6351497Z         y = pandas.Series([1, 2, 3, 4, 5] * 8, name="y")
2023-04-06T12:49:33.6351835Z         x = pandas.Series([1, 2, 3, 4, 5, 6, 7, 8] * 5, name="x")
2023-04-06T12:49:33.6352144Z     
2023-04-06T12:49:33.6352422Z         df = pandas.DataFrame(index=i.index)
2023-04-06T12:49:33.6352725Z         df = df.join(i)
2023-04-06T12:49:33.6353016Z         endo = df.join(y)
2023-04-06T12:49:33.6353303Z         exo = df.join(x)
2023-04-06T12:49:33.6353594Z         endo_groups = endo.groupby("i")
2023-04-06T12:49:33.6353901Z         exo_groups = exo.groupby("i")
2023-04-06T12:49:33.6354208Z         exo_df = exo_groups.agg([np.sum, np.max])
2023-04-06T12:49:33.6354530Z         endo_df = endo_groups.agg([np.sum, np.max])
2023-04-06T12:49:33.6354843Z         reg = OLS(exo_df[[("x", "sum")]], endo_df).fit()
2023-04-06T12:49:33.6355147Z         interesting_lines = []
2023-04-06T12:49:33.6355434Z         import warnings
2023-04-06T12:49:33.6355729Z         with warnings.catch_warnings():
2023-04-06T12:49:33.6356040Z             # Catch ominormal warning, not interesting here
2023-04-06T12:49:33.6356362Z             warnings.simplefilter("ignore")
2023-04-06T12:49:33.6356681Z             for line in str(reg.summary()).splitlines():
2023-04-06T12:49:33.6356987Z                 if "_" in line:
2023-04-06T12:49:33.6357368Z                     interesting_lines.append(line[:38])
2023-04-06T12:49:33.6357695Z     
2023-04-06T12:49:33.6357985Z         desired = ["Dep. Variable:                  x_sum ",
2023-04-06T12:49:33.6358300Z                    "y_sum          1.4595      0.209      ",
2023-04-06T12:49:33.6358605Z                    "y_amax         0.2432      0.035      "]
2023-04-06T12:49:33.6358874Z     
2023-04-06T12:49:33.6359427Z >       assert_equal(sorted(desired), sorted(interesting_lines))
2023-04-06T12:49:33.6359748Z E       AssertionError: 
2023-04-06T12:49:33.6360038Z E       Items are not equal:
2023-04-06T12:49:33.6360311Z E       item=1
2023-04-06T12:49:33.6360582Z E       
2023-04-06T12:49:33.6360966Z E        ACTUAL: 'y_amax         0.2432      0.035      '
2023-04-06T12:49:33.6361356Z E        DESIRED: 'y_max          0.2432      0.035      '
2023-04-06T12:49:33.6361587Z 
2023-04-06T12:49:33.6361891Z statsmodels/iolib/tests/test_table.py:226: AssertionError



2023-04-06T12:49:34.5941820Z _____________________________ test_extension_types _____________________________
2023-04-06T12:49:34.5942401Z [gw0] linux -- Python 3.11.2 /opt/hostedtoolcache/Python/3.11.2/x64/bin/python
2023-04-06T12:49:34.5942582Z 
2023-04-06T12:49:34.5942799Z df =            a  b     c     d
2023-04-06T12:49:34.5943018Z 0   1.764052  0   NaN  <NA>
2023-04-06T12:49:34.5943227Z 1   0.400157  1   1.0     1
2023-04-06T12:49:34.5943454Z 2   0.978738  2   NaN  <NA>
2023-04-06T12:49:34.5943663Z 3   2....  NaN  <NA>
2023-04-06T12:49:34.5943874Z 97  1.785870  7  97.0    97
2023-04-06T12:49:34.5944090Z 98  0.126912  8   NaN  <NA>
2023-04-06T12:49:34.5944304Z 99  0.401989  9  99.0    99
2023-04-06T12:49:34.5944442Z 
2023-04-06T12:49:34.5944638Z [100 rows x 4 columns]
2023-04-06T12:49:34.5944787Z 
2023-04-06T12:49:34.5945158Z     @pytest.mark.skipif(not hasattr(pd, "NA"), reason="Must support NA")
2023-04-06T12:49:34.5945424Z     def test_extension_types(df):
2023-04-06T12:49:34.5945664Z         df["c"] = pd.Series(np.arange(100.0))
2023-04-06T12:49:34.5945928Z         df["d"] = pd.Series(np.arange(100), dtype=pd.Int64Dtype())
2023-04-06T12:49:34.5946198Z         df.loc[df.index[::2], "c"] = np.nan
2023-04-06T12:49:34.5946444Z         df.loc[df.index[::2], "d"] = pd.NA
2023-04-06T12:49:34.5946684Z         res = Description(df)
2023-04-06T12:49:34.5946930Z >       np.testing.assert_allclose(res.frame.c, res.frame.d)
2023-04-06T12:49:34.5947098Z 
2023-04-06T12:49:34.5947599Z statsmodels/stats/tests/test_descriptivestats.py:170: 
2023-04-06T12:49:34.5947875Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
2023-04-06T12:49:34.5948167Z pandas/_libs/properties.pyx:36: in pandas._libs.properties.CachedProperty.__get__
2023-04-06T12:49:34.5948420Z     ???
2023-04-06T12:49:34.5948660Z statsmodels/stats/descriptivestats.py:361: in frame
2023-04-06T12:49:34.5948914Z     numeric = self.numeric
2023-04-06T12:49:34.5949178Z pandas/_libs/properties.pyx:36: in pandas._libs.properties.CachedProperty.__get__
2023-04-06T12:49:34.5949432Z     ???
2023-04-06T12:49:34.5949669Z statsmodels/stats/descriptivestats.py:406: in numeric
2023-04-06T12:49:34.5949916Z     mode_values = df.apply(_mode).T
2023-04-06T12:49:34.5950331Z /opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/site-packages/pandas/core/frame.py:9770: in apply
2023-04-06T12:49:34.5950751Z     return op.apply().__finalize__(self, method="apply")
2023-04-06T12:49:34.5951154Z /opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/site-packages/pandas/core/apply.py:693: in apply
2023-04-06T12:49:34.5951437Z     return self.apply_standard()
2023-04-06T12:49:34.5951831Z /opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/site-packages/pandas/core/apply.py:813: in apply_standard
2023-04-06T12:49:34.5952320Z     results, res_index = self.apply_series_generator()
2023-04-06T12:49:34.5952746Z /opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/site-packages/pandas/core/apply.py:829: in apply_series_generator
2023-04-06T12:49:34.5953032Z     results[i] = self.f(v)
2023-04-06T12:49:34.5953286Z statsmodels/stats/descriptivestats.py:398: in _mode
2023-04-06T12:49:34.5953557Z     mode_res = stats.mode(ser.dropna(), keepdims=True)
2023-04-06T12:49:34.5953995Z /opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/site-packages/scipy/stats/_axis_nan_policy.py:521: in axis_nan_policy_wrapper
2023-04-06T12:49:34.5954317Z     res = hypotest_fun_out(*samples, **kwds)
2023-04-06T12:49:34.5954579Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
2023-04-06T12:49:34.5954740Z 
2023-04-06T12:49:34.5954973Z a = array([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35,
2023-04-06T12:49:34.5955250Z        37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69,
2023-04-06T12:49:34.5955526Z        71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99],
2023-04-06T12:49:34.5955758Z       dtype=object)
2023-04-06T12:49:34.5956061Z axis = 0, nan_policy = 'propagate', keepdims = False
2023-04-06T12:49:34.5956224Z 
2023-04-06T12:49:34.5956542Z     @_axis_nan_policy_factory(_mode_result, override={'vectorization': True,
2023-04-06T12:49:34.5956881Z                                                       'nan_propagation': False})
2023-04-06T12:49:34.5957213Z     def mode(a, axis=0, nan_policy='propagate', keepdims=False):
2023-04-06T12:49:34.5957493Z         r"""Return an array of the modal (most common) value in the passed array.
2023-04-06T12:49:34.5957733Z     
2023-04-06T12:49:34.5957971Z         If there is more than one such value, only one is returned.
2023-04-06T12:49:34.5958295Z         The bin-count for the modal bins is also returned.
2023-04-06T12:49:34.5958527Z     
2023-04-06T12:49:34.5958784Z         Parameters
2023-04-06T12:49:34.5959030Z         ----------
2023-04-06T12:49:34.5959231Z         a : array_like
2023-04-06T12:49:34.5959531Z             n-dimensional array of which to find mode(s).
2023-04-06T12:49:34.5959779Z         axis : int or None, optional
2023-04-06T12:49:34.5960032Z             Axis along which to operate. Default is 0. If None, compute over
2023-04-06T12:49:34.5960280Z             the whole array `a`.
2023-04-06T12:49:34.5960587Z         nan_policy : {'propagate', 'raise', 'omit'}, optional
2023-04-06T12:49:34.5960851Z             Defines how to handle when input contains nan.
2023-04-06T12:49:34.5961185Z             The following options are available (default is 'propagate'):
2023-04-06T12:49:34.5961421Z     
2023-04-06T12:49:34.5961794Z               * 'propagate': treats nan as it would treat any other value
2023-04-06T12:49:34.5962093Z               * 'raise': throws an error
2023-04-06T12:49:34.5962411Z               * 'omit': performs the calculations ignoring nan values
2023-04-06T12:49:34.5962658Z         keepdims : bool, optional
2023-04-06T12:49:34.5962918Z             If set to ``False``, the `axis` over which the statistic is taken
2023-04-06T12:49:34.5963189Z             is consumed (eliminated from the output array). If set to ``True``,
2023-04-06T12:49:34.5963468Z             the `axis` is retained with size one, and the result will broadcast
2023-04-06T12:49:34.5963724Z             correctly against the input array.
2023-04-06T12:49:34.5963937Z     
2023-04-06T12:49:34.5964121Z         Returns
2023-04-06T12:49:34.5964362Z         -------
2023-04-06T12:49:34.5964627Z         mode : ndarray
2023-04-06T12:49:34.5964842Z             Array of modal values.
2023-04-06T12:49:34.5965063Z         count : ndarray
2023-04-06T12:49:34.5965531Z             Array of counts for each mode.
2023-04-06T12:49:34.5965742Z     
2023-04-06T12:49:34.5965941Z         Notes
2023-04-06T12:49:34.5966168Z         -----
2023-04-06T12:49:34.5966391Z         The mode  is calculated using `numpy.unique`.
2023-04-06T12:49:34.5966741Z         In NumPy versions 1.21 and after, all NaNs - even those with different
2023-04-06T12:49:34.5967108Z         binary representations - are treated as equivalent and counted as separate
2023-04-06T12:49:34.5967377Z         instances of the same value.
2023-04-06T12:49:34.5967585Z     
2023-04-06T12:49:34.5967830Z         By convention, the mode of an empty array is NaN, and the associated count
2023-04-06T12:49:34.5968078Z         is zero.
2023-04-06T12:49:34.5968278Z     
2023-04-06T12:49:34.5968465Z         Examples
2023-04-06T12:49:34.5968706Z         --------
2023-04-06T12:49:34.5968920Z         >>> import numpy as np
2023-04-06T12:49:34.5969142Z         >>> a = np.array([[3, 0, 3, 7],
2023-04-06T12:49:34.5969371Z         ...               [3, 2, 6, 2],
2023-04-06T12:49:34.5969587Z         ...               [1, 7, 2, 8],
2023-04-06T12:49:34.5969791Z         ...               [3, 0, 6, 1],
2023-04-06T12:49:34.5970005Z         ...               [3, 2, 5, 5]])
2023-04-06T12:49:34.5970227Z         >>> from scipy import stats
2023-04-06T12:49:34.5970457Z         >>> stats.mode(a, keepdims=True)
2023-04-06T12:49:34.5970707Z         ModeResult(mode=array([[3, 0, 6, 1]]), count=array([[4, 2, 2, 1]]))
2023-04-06T12:49:34.5970943Z     
2023-04-06T12:49:34.5971159Z         To get mode of whole array, specify ``axis=None``:
2023-04-06T12:49:34.5971375Z     
2023-04-06T12:49:34.5971642Z         >>> stats.mode(a, axis=None, keepdims=True)
2023-04-06T12:49:34.5971887Z         ModeResult(mode=[[3]], count=[[5]])
2023-04-06T12:49:34.5972128Z         >>> stats.mode(a, axis=None, keepdims=False)
2023-04-06T12:49:34.5972364Z         ModeResult(mode=3, count=5)
2023-04-06T12:49:34.5972574Z     
2023-04-06T12:49:34.5972768Z         """  # noqa: E501
2023-04-06T12:49:34.5973020Z         # `axis`, `nan_policy`, and `keepdims` are handled by `_axis_nan_policy`
2023-04-06T12:49:34.5973259Z     
2023-04-06T12:49:34.5973453Z         if a.size == 0:
2023-04-06T12:49:34.5973679Z             return ModeResult(np.nan, np.int64(0))
2023-04-06T12:49:34.5973903Z     
2023-04-06T12:49:34.5974122Z         vals, cnts = np.unique(a, return_counts=True)
2023-04-06T12:49:34.5974376Z         modes, counts = vals[cnts.argmax()], cnts.max()
2023-04-06T12:49:34.5974625Z >       return ModeResult(modes[()], counts[()])
2023-04-06T12:49:34.5975235Z E       TypeError: 'int' object is not subscriptable
2023-04-06T12:49:34.5975400Z 
2023-04-06T12:49:34.5975772Z /opt/hostedtoolcache/Python/3.11.2/x64/lib/python3.11/site-packages/scipy/stats/_stats_py.py:584: TypeError



2023-04-06T12:49:34.5976113Z ____________________________ test_brentq_expanding _____________________________
2023-04-06T12:49:34.5976493Z [gw1] linux -- Python 3.11.2 /opt/hostedtoolcache/Python/3.11.2/x64/bin/python
2023-04-06T12:49:34.5976762Z 
2023-04-06T12:49:34.5976970Z     def test_brentq_expanding():
2023-04-06T12:49:34.5977180Z         cases = [
2023-04-06T12:49:34.5977384Z             (0, {}),
2023-04-06T12:49:34.5977587Z             (50, {}),
2023-04-06T12:49:34.5977831Z             (-50, {}),
2023-04-06T12:49:34.5978119Z             (500000, dict(low=10000)),
2023-04-06T12:49:34.5978407Z             (-50000, dict(upp=-1000)),
2023-04-06T12:49:34.5978650Z             (500000, dict(low=300000, upp=700000)),
2023-04-06T12:49:34.5978955Z             (-50000, dict(low= -70000, upp=-1000))
2023-04-06T12:49:34.5979178Z             ]
2023-04-06T12:49:34.5979372Z     
2023-04-06T12:49:34.5979564Z         funcs = [(func, None),
2023-04-06T12:49:34.5979783Z                  (func, True),
2023-04-06T12:49:34.5979994Z                  (funcn, None),
2023-04-06T12:49:34.5980267Z                  (funcn, False)]
2023-04-06T12:49:34.5980468Z     
2023-04-06T12:49:34.5980667Z         for f, inc in funcs:
2023-04-06T12:49:34.5980883Z             for a, kwds in cases:
2023-04-06T12:49:34.5981172Z                 kw = {'increasing':inc}
2023-04-06T12:49:34.5981406Z                 kw.update(kwds)
2023-04-06T12:49:34.5981639Z                 res = brentq_expanding(f, args=(a,), **kwds)
2023-04-06T12:49:34.5981967Z                 #print '%10d'%a, ['dec', 'inc'][f is func], res - a
2023-04-06T12:49:34.5982221Z                 assert_allclose(res, a, rtol=1e-5)
2023-04-06T12:49:34.5982433Z     
2023-04-06T12:49:34.5982634Z         # wrong sign for start bounds
2023-04-06T12:49:34.5982888Z         # does not raise yet during development TODO: activate this
2023-04-06T12:49:34.5983163Z         # it kind of works in some cases, but not correctly or in a useful way
2023-04-06T12:49:34.5983559Z         #assert_raises(ValueError, brentq_expanding, func, args=(-500,), start_upp=-1000)
2023-04-06T12:49:34.5983866Z         #assert_raises(ValueError, brentq_expanding, func, args=(500,), start_low=1000)
2023-04-06T12:49:34.5984121Z     
2023-04-06T12:49:34.5984348Z         # low upp given, but does not bound root, leave brentq exception
2023-04-06T12:49:34.5984664Z         # ValueError: f(a) and f(b) must have different signs
2023-04-06T12:49:34.5985044Z         assert_raises(ValueError, brentq_expanding, funcn, args=(-50000,), low= -40000, upp=-10000)
2023-04-06T12:49:34.5985299Z     
2023-04-06T12:49:34.5985514Z         # max_it too low to find root bounds
2023-04-06T12:49:34.5985758Z         # ValueError: f(a) and f(b) must have different signs
2023-04-06T12:49:34.5986123Z         assert_raises(ValueError, brentq_expanding, func, args=(-50000,), max_it=2)
2023-04-06T12:49:34.5986372Z     
2023-04-06T12:49:34.5986572Z         # maxiter_bq too low
2023-04-06T12:49:34.5986805Z         # RuntimeError: Failed to converge after 3 iterations.
2023-04-06T12:49:34.5987181Z         assert_raises(RuntimeError, brentq_expanding, func, args=(-50000,), maxiter_bq=3)
2023-04-06T12:49:34.5987432Z     
2023-04-06T12:49:34.5987665Z         # cannot determine whether increasing, all 4 low trial points return nan
2023-04-06T12:49:34.5988027Z         assert_raises(ValueError, brentq_expanding, func_nan, args=(-20, 0.6))
2023-04-06T12:49:34.5988273Z     
2023-04-06T12:49:34.5988474Z         # test for full_output
2023-04-06T12:49:34.5988675Z         a = 500
2023-04-06T12:49:34.5988916Z         val, info = brentq_expanding(func, args=(a,), full_output=True)
2023-04-06T12:49:34.5989172Z         assert_allclose(val, a, rtol=1e-5)
2023-04-06T12:49:34.5989495Z         info1 = {'iterations': 63, 'start_bounds': (-1, 1),
2023-04-06T12:49:34.5989829Z                  'brentq_bounds': (100, 1000), 'flag': 'converged',
2023-04-06T12:49:34.5990190Z                  'function_calls': 64, 'iterations_expand': 3, 'converged': True}
2023-04-06T12:49:34.5990431Z     
2023-04-06T12:49:34.5990652Z         # adjustments for scipy 0.8.0 with changed convergence criteria
2023-04-06T12:49:34.5990988Z >       assert_array_less(info.__dict__['iterations'], 70)
2023-04-06T12:49:34.5991396Z E       KeyError: 'iterations'
2023-04-06T12:49:34.5991545Z 
2023-04-06T12:49:34.5991775Z statsmodels/tools/tests/test_rootfinding.py:86: KeyError
```



brentq test failure is because scipy RooResults as empty `__dict__` in `main` version.

test_extension_types error also seems to be because of a recent change in scipy.stats.mode

test_regression_with_tuples
seems that pandas has switched the label for groupby agg np.max from "amax" to "max"
(I'm not quite sure what that OLS in the unit test is supposed to do, it seems to have exog and endog reversed, but it can be just a misnaming.)
unit test needs fixing, e.g. explicitly rename column names if "amax"

bernstein test_bernstein_1d test failure is unclear
most likely some problems at upper bound of the unit interval in bernstein polynomials.

scipy.stats.beta_gen switch to boost pdf already 3 years ago, so that shouldn't be it.
I also don't find a recent scipy issue or pull that might have changed corner cases for beta.

I'm giving up on this for now.
The code looks pretty simple, but I don't see anything that might have changed for evaluating at `1`, dropping results value from 1 to 0.
I don't see any floating point noise that might cause this.
Although the code catches RuntimeWarnings, but I don't have an example to produce those.

It looks like the 2-d and n-d code still works. And evaluating at points < 1 is still correct also for 1d bernstein.
**correction** 2-d and n-d only have the "binom" version and not the failing `beta` version. binom is the default method.

I don't remember the details well enough. The corner cases might have a degenerate kernel distribution
.

Resolving patch:
diff --git a/statsmodels/tools/rootfinding.py b/statsmodels/tools/rootfinding.py
--- a/statsmodels/tools/rootfinding.py
+++ b/statsmodels/tools/rootfinding.py
@@ -13,6 +13,8 @@
 import numpy as np
 from scipy import optimize
 
+from statsmodels.tools.testing import Holder
+
 DEBUG = False
 
 
@@ -202,11 +204,19 @@ def brentq_expanding(func, low=None, upp=None, args=(), xtol=1e-5,
                           full_output=full_output)
     if full_output:
         val = res[0]
-        info = res[1]
-        info.iterations_expand = n_it
-        info.start_bounds = (sl, su)
-        info.brentq_bounds = (left, right)
-        info.increasing = increasing
+        info = Holder(
+            # from brentq
+            root=res[1].root,
+            iterations=res[1].iterations,
+            function_calls=res[1].function_calls,
+            converged=res[1].converged,
+            flag=res[1].flag,
+            # ours:
+            iterations_expand=n_it,
+            start_bounds=(sl, su),
+            brentq_bounds=(left, right),
+            increasing=increasing,
+            )
         return val, info
     else:
         return res


Test patch:
diff --git a/statsmodels/formula/tests/test_formula.py b/statsmodels/formula/tests/test_formula.py
--- a/statsmodels/formula/tests/test_formula.py
+++ b/statsmodels/formula/tests/test_formula.py
@@ -161,7 +161,7 @@ def test_formula_predict_series():
 
     result = results.predict({"x": [1, 2, 3]})
     expected = pd.Series([1., 2., 3.], index=[0, 1, 2])
-    assert_series_equal(result, expected)
+    assert_series_equal(result, expected, check_index_type=False)
 
 
 def test_patsy_lazy_dict():
@@ -210,7 +210,7 @@ def test_patsy_missing_data():
         assert 'ValueWarning' in repr(w[-1].message)
         assert 'nan values have been dropped' in repr(w[-1].message)
     # Frist record will be dropped in both cases
-    assert_equal(res.fittedvalues, res2)
+    assert_equal(res.fittedvalues, res2, check_index_type=False)
 
 
 def test_predict_nondataframe():
diff --git a/statsmodels/iolib/tests/test_table.py b/statsmodels/iolib/tests/test_table.py
--- a/statsmodels/iolib/tests/test_table.py
+++ b/statsmodels/iolib/tests/test_table.py
@@ -1,4 +1,4 @@
-import numpy as np
+
 from numpy.testing import assert_equal
 from statsmodels.iolib.table import SimpleTable, default_txt_fmt
 from statsmodels.iolib.table import default_latex_fmt
@@ -207,8 +207,8 @@ def test_regression_with_tuples(self):
         exo = df.join(x)
         endo_groups = endo.groupby("i")
         exo_groups = exo.groupby("i")
-        exo_df = exo_groups.agg([np.sum, np.max])
-        endo_df = endo_groups.agg([np.sum, np.max])
+        exo_df = exo_groups.agg(['sum', 'max'])
+        endo_df = endo_groups.agg(['sum', 'max'])
         reg = OLS(exo_df[[("x", "sum")]], endo_df).fit()
         interesting_lines = []
         import warnings
@@ -221,7 +221,7 @@ def test_regression_with_tuples(self):
 
         desired = ["Dep. Variable:                  x_sum ",
                    "y_sum          1.4595      0.209      ",
-                   "y_amax         0.2432      0.035      "]
+                   "y_max          0.2432      0.035      "]
 
         assert_equal(sorted(desired), sorted(interesting_lines))
 
diff --git a/statsmodels/tools/tests/test_rootfinding.py b/statsmodels/tools/tests/test_rootfinding.py
--- a/statsmodels/tools/tests/test_rootfinding.py
+++ b/statsmodels/tools/tests/test_rootfinding.py
@@ -80,14 +80,14 @@ def test_brentq_expanding():
     assert_allclose(val, a, rtol=1e-5)
     info1 = {'iterations': 63, 'start_bounds': (-1, 1),
              'brentq_bounds': (100, 1000), 'flag': 'converged',
-             'function_calls': 64, 'iterations_expand': 3, 'converged': True}
+             'function_calls': 64, 'iterations_expand': 3, 'converged': True,
+             }
 
-    # adjustments for scipy 0.8.0 with changed convergence criteria
-    assert_array_less(info.__dict__['iterations'], 70)
-    assert_array_less(info.__dict__['function_calls'], 70)
+    assert_array_less(info.iterations, 70)
+    assert_array_less(info.function_calls, 70)
     for k in info1:
         if k in ['iterations', 'function_calls']:
             continue
-        assert_equal(info1[k], info.__dict__[k])
+        assert_equal(info1[k], getattr(info, k))
 
     assert_allclose(info.root, a, rtol=1e-5)
diff --git a/statsmodels/tsa/tests/test_deterministic.py b/statsmodels/tsa/tests/test_deterministic.py
--- a/statsmodels/tsa/tests/test_deterministic.py
+++ b/statsmodels/tsa/tests/test_deterministic.py
@@ -571,7 +571,7 @@ def test_range_index_basic():
 
 
 def test_range_casting():
-    idx = np.arange(120)
+    idx = np.arange(120).astype(np.int64)
     dp = DeterministicProcess(
         idx, constant=True, order=1, seasonal=True, period=12
     )