Skip to content

Commit 367b4fe

Browse files
authored
Don’t accept warnings in tests (#116)
1 parent d2a493d commit 367b4fe

12 files changed

+69
-48
lines changed

.vscode/launch.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Python: Debug Tests",
6+
"type": "python",
7+
"request": "launch",
8+
"program": "${file}",
9+
"purpose": ["debug-test"],
10+
"console": "internalConsole",
11+
"justMyCode": false,
12+
},
13+
],
14+
}

README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Either use the converter manually …
7070
from rpy2.robjects import r
7171
from rpy2.robjects.conversion import localconverter
7272
73-
with localconverter(anndata2ri.full_converter()):
73+
with localconverter(anndata2ri.converter):
7474
adata = r('as(some_data, "SingleCellExperiment")')
7575
7676
… or activate it globally:

pyproject.toml

+1-14
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,7 @@ run = 'pytest -vv {args}'
6262
addopts = [
6363
'--import-mode=importlib',
6464
'-panndata2ri.test_utils',
65-
# TODO '-Werror',
66-
]
67-
filterwarnings = [
68-
# eventlet 0.24.1 imports dns.hash: https://github.com/eventlet/eventlet/pull/563
69-
'ignore::DeprecationWarning:dns.hash',
70-
# igraph 0.7.1post6 imports SafeConfigParser: https://github.com/igraph/python-igraph/pull/203
71-
'ignore::DeprecationWarning:igraph.configuration',
72-
# ipywidgets 7.4.2 imports ABCs from collections: https://github.com/jupyter-widgets/ipywidgets/pull/2395
73-
'ignore::DeprecationWarning:ipywidgets.widgets.widget_selection',
74-
# jinja2 2.10.1 imports ABCs from collections: https://github.com/pallets/jinja/pull/867
75-
'ignore::DeprecationWarning:jinja2.utils',
76-
'ignore::DeprecationWarning:jinja2.runtime',
77-
# rpy2 3.0.2 imports ABCs from collections: https://bitbucket.org/rpy2/rpy2/pull-requests/74/fix-deprecationwarning/diff
78-
'ignore::DeprecationWarning:rpy2.rinterface_lib.sexp',
65+
'-Werror',
7966
]
8067

8168
[tool.black]

src/anndata2ri/_conv.py

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

33
from typing import TYPE_CHECKING
4+
from warnings import warn
45

56
import numpy as np
67
import pandas as pd
78
from rpy2.robjects import conversion, numpy2ri, pandas2ri
8-
from rpy2.robjects.conversion import overlay_converter
99

1010
from . import scipy2ri
1111

@@ -18,14 +18,20 @@
1818

1919

2020
original_converter: conversion.Converter | None = None
21-
converter = conversion.Converter('original anndata conversion')
21+
converter = (
22+
conversion.Converter('original anndata conversion', template=conversion.get_conversion())
23+
+ numpy2ri.converter
24+
+ pandas2ri.converter
25+
+ scipy2ri.converter
26+
)
27+
2228

2329
_mat_converter = numpy2ri.converter + scipy2ri.converter
2430

2531

2632
def mat_py2rpy(obj: np.ndarray | spmatrix | pd.DataFrame) -> Sexp:
2733
if isinstance(obj, pd.DataFrame):
28-
numeric_cols = obj.dtypes <= np.number
34+
numeric_cols = obj.dtypes.map(lambda dt: np.issubdtype(dt, np.number))
2935
if not numeric_cols.all():
3036
non_num = numeric_cols.index[~numeric_cols]
3137
msg = f'DataFrame contains non-numeric columns {list(non_num)}'
@@ -37,18 +43,6 @@ def mat_py2rpy(obj: np.ndarray | spmatrix | pd.DataFrame) -> Sexp:
3743
mat_rpy2py: Callable[[Sexp], np.ndarray | spmatrix | Sexp] = _mat_converter.rpy2py
3844

3945

40-
def full_converter() -> conversion.Converter:
41-
pandas2ri.activate()
42-
new_converter = conversion.Converter('anndata conversion', template=conversion.get_conversion())
43-
pandas2ri.deactivate()
44-
45-
overlay_converter(scipy2ri.converter, new_converter)
46-
# overwrite the scipy2ri Sexp4 converter and add our others
47-
overlay_converter(converter, new_converter)
48-
49-
return new_converter
50-
51-
5246
def activate() -> None:
5347
r"""Activate conversion for supported objects.
5448
@@ -58,12 +52,19 @@ def activate() -> None:
5852
5953
Does nothing if this is the active converter.
6054
"""
55+
warn(
56+
'The global conversion available with activate() '
57+
'is deprecated and will be removed in the next major release. '
58+
'Use a local converter.',
59+
category=DeprecationWarning,
60+
stacklevel=2,
61+
)
6162
global original_converter # noqa: PLW0603
6263

6364
if original_converter is not None:
6465
return
6566

66-
new_converter = full_converter()
67+
new_converter = converter
6768
original_converter = conversion.get_conversion()
6869
conversion.set_conversion(new_converter)
6970

src/anndata2ri/_py2r.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from rpy2.robjects.vectors import ListVector
1212

1313
from . import _conv_name
14-
from ._conv import converter, full_converter, mat_py2rpy
14+
from ._conv import converter, mat_py2rpy
1515
from ._rpy2_ext import importr
1616

1717

@@ -77,7 +77,7 @@ def py2rpy_anndata(obj: AnnData) -> RS4:
7777
col_data = s4v.DataFrame(**col_args)
7878

7979
# Convert everything we know
80-
with localconverter(full_converter() + dict_converter):
80+
with localconverter(converter + dict_converter):
8181
metadata = ListVector(obj.uns.items())
8282

8383
rd_args = {_conv_name.scanpy2sce(k): mat_py2rpy(obj.obsm[k]) for k in obj.obsm}

src/anndata2ri/_r2py.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from rpy2.robjects.robject import RSlots
1111

1212
from . import _conv_name
13-
from ._conv import converter, full_converter, mat_rpy2py
13+
from ._conv import converter, mat_rpy2py
1414
from ._rpy2_ext import importr
1515
from .scipy2ri import supported_r_matrix_classes
1616
from .scipy2ri._r2py import rmat_to_spmat
@@ -122,8 +122,11 @@ def convert_mats(
122122

123123
obs = rpy2py_data_frame(col_data)
124124
var = rpy2py_data_frame(row_data)
125+
# To avoid ImplicitModificationWarning
126+
obs.index = obs.index.astype('string')
127+
var.index = var.index.astype('string')
125128
# The whole shebang: configured converter, numpy, pandas and ours
126-
with localconverter(full_converter()):
129+
with localconverter(converter):
127130
uns = dict(metadata.items())
128131

129132
return AnnData(exprs, obs, var, uns, obsm, layers=layers)

src/anndata2ri/scipy2ri/_conv.py

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

3+
from warnings import warn
4+
35
from rpy2.robjects import conversion, numpy2ri
46
from rpy2.robjects.conversion import overlay_converter
57

@@ -13,6 +15,13 @@ def activate() -> None:
1315
1416
Does nothing if this is the active conversion.
1517
"""
18+
warn(
19+
'The global conversion available with activate() '
20+
'is deprecated and will be removed in the next major release. '
21+
'Use a local converter.',
22+
category=DeprecationWarning,
23+
stacklevel=2,
24+
)
1625
global original_converter # noqa: PLW0603
1726

1827
if original_converter is not None:

src/anndata2ri/scipy2ri/_r2py.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def rmat_to_spmat(rmat: SexpS4) -> sparse.spmatrix:
5959
if supported_r_matrix_classes(types='n') & r_classes
6060
else slots['x']
6161
)
62-
dtype = np.bool_ if supported_r_matrix_classes(types=('n', 'l')) & r_classes else np.floating
62+
dtype = np.bool_ if supported_r_matrix_classes(types=('n', 'l')) & r_classes else np.float_
6363
return mat_cls((data, *coord_spec), shape=shape, dtype=dtype)
6464

6565
msg = 'Should have hit one of the branches'

src/anndata2ri/test_utils.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,21 @@ def deactivate(self) -> None:
3838

3939

4040
def _conversion_py2rpy_manual(conv_mod: ConversionModule, dataset: Any) -> Sexp: # noqa: ANN401
41-
return conv_mod.converter.py2rpy(dataset)
41+
converter = conv_mod.get_conversion() if hasattr(conv_mod, 'get_conversion') else conv_mod.converter
42+
return converter.py2rpy(dataset)
4243

4344

4445
def _conversion_py2rpy_local(conv_mod: ConversionModule, dataset: Any) -> Sexp: # noqa: ANN401
45-
with localconverter(conv_mod.converter):
46+
converter = conv_mod.get_conversion() if hasattr(conv_mod, 'get_conversion') else conv_mod.converter
47+
with localconverter(converter):
4648
globalenv['temp'] = dataset
4749
return globalenv['temp']
4850

4951

5052
def _conversion_py2rpy_activate(conv_mod: ConversionModule, dataset: Any) -> Sexp: # noqa: ANN401
5153
try:
52-
conv_mod.activate()
54+
with pytest.warns(DeprecationWarning, match=r'global conversion'):
55+
conv_mod.activate()
5356
globalenv['temp'] = dataset
5457
finally:
5558
conv_mod.deactivate()
@@ -70,19 +73,22 @@ def py2r(request: pytest.FixtureRequest) -> Py2R:
7073

7174

7275
def _conversion_rpy2py_manual(conv_mod: ConversionModule, dataset: Callable[[], Sexp]) -> Any: # noqa: ANN401
73-
return conv_mod.converter.rpy2py(dataset())
76+
converter = conv_mod.get_conversion() if hasattr(conv_mod, 'get_conversion') else conv_mod.converter
77+
return converter.rpy2py(dataset())
7478

7579

7680
def _conversion_rpy2py_local(conv_mod: ConversionModule, dataset: Callable[[], Sexp]) -> Any: # noqa: ANN401
7781
# Needs default_converter to e.g. call `as` on a SummarizedExperiment:
7882
# Calling a R function returning a S4 object requires py2rpy[RS4], py2rpy[str], …
79-
with localconverter(default_converter + conv_mod.converter):
83+
converter = conv_mod.get_conversion() if hasattr(conv_mod, 'get_conversion') else conv_mod.converter
84+
with localconverter(default_converter + converter):
8085
return dataset()
8186

8287

8388
def _conversion_rpy2py_activate(conv_mod: ConversionModule, dataset: Callable[[], Sexp]) -> Any: # noqa: ANN401
8489
try:
85-
conv_mod.activate()
90+
with pytest.warns(DeprecationWarning, match=r'global conversion'):
91+
conv_mod.activate()
8692
return dataset()
8793
finally:
8894
conv_mod.deactivate()

tests/test_py2rpy.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ def test_py2rpy2_numpy_pbmc68k() -> None:
7070
from scanpy.datasets import pbmc68k_reduced
7171

7272
try:
73-
anndata2ri.activate()
73+
with pytest.warns(DeprecationWarning, match=r'global conversion'):
74+
anndata2ri.activate()
7475
with catch_warnings(record=True) as logs:
7576
simplefilter('ignore', DeprecationWarning)
7677
globalenv['adata'] = pbmc68k_reduced()

tests/test_rpy2py.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def test_convert_empty_df_with_rows(r2py: R2Py) -> None:
8585
df = r('S4Vectors::DataFrame(a=1:10)[, -1]')
8686
assert df.slots['nrows'][0] == 10
8787

88-
df_py = r2py(anndata2ri, lambda: conversion.rpy2py(df))
88+
df_py = r2py(anndata2ri, lambda: conversion.get_conversion().rpy2py(df))
8989
assert isinstance(df_py, pd.DataFrame)
9090

9191

tests/test_scipy_rpy2py.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@
4949
coo_b2 = [[0, 0, 1], [0, 1, 0], [0, 0, 0]]
5050

5151
mats = [
52-
pytest.param((0, 0), sparse.csc_matrix, np.floating, csc_empty, dgc_empty, id='dgC_empty'),
53-
pytest.param((3, 2), sparse.csc_matrix, np.floating, csc_f, dgc, id='dgC'),
54-
pytest.param((2, 3), sparse.csr_matrix, np.floating, csr_f, dgr, id='dgR'),
55-
pytest.param((2, 3), sparse.coo_matrix, np.floating, coo_f, dgt, id='dgT'),
52+
pytest.param((0, 0), sparse.csc_matrix, np.float_, csc_empty, dgc_empty, id='dgC_empty'),
53+
pytest.param((3, 2), sparse.csc_matrix, np.float_, csc_f, dgc, id='dgC'),
54+
pytest.param((2, 3), sparse.csr_matrix, np.float_, csr_f, dgr, id='dgR'),
55+
pytest.param((2, 3), sparse.coo_matrix, np.float_, coo_f, dgt, id='dgT'),
5656
pytest.param((2, 3), sparse.csc_matrix, np.bool_, csc_b1, lgc, id='lgC'),
5757
pytest.param((3, 3), sparse.csr_matrix, np.bool_, csr_b1, lgr, id='lgR'),
5858
# pytest.param((?, ?), sparse.coo_matrix, np.bool_, coo_b1, lgt, id="lgT"),

0 commit comments

Comments
 (0)