scverse / scanpy

Single-cell analysis in Python. Scales to >1M cells.
https://scanpy.readthedocs.io
BSD 3-Clause "New" or "Revised" License
1.9k stars 597 forks source link

sc.tl.ingest does not work with Python 3.10 #2191

Closed HarryHung closed 4 days ago

HarryHung commented 2 years ago

Minimal code sample

RecursionError when using sc.tl.ingest with Python 3.10. Downgrading to Python 3.8 or 3.9 fixes the issue.

Recreate by just running scanpy's own Integrating data using ingest and BBKNN tutorial.

image

---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
Input In [6], in <cell line: 1>()
----> 1 sc.tl.ingest(adata, adata_ref, obs='louvain')

File ~/miniconda3/envs/test/lib/python3.10/site-packages/scanpy/tools/_ingest.py:133, in ingest(adata, adata_ref, obs, embedding_method, labeling_method, neighbors_key, inplace, **kwargs)
    130     ing.map_embedding(method)
    132 if obs is not None:
--> 133     ing.neighbors(**kwargs)
    134     for i, col in enumerate(obs):
    135         ing.map_labels(col, labeling_method[i])

File ~/miniconda3/envs/test/lib/python3.10/site-packages/scanpy/tools/_ingest.py:472, in Ingest.neighbors(self, k, queue_size, epsilon, random_state)
    469 if self._use_pynndescent:
    470     self._nnd_idx.search_rng_state = rng_state
--> 472     self._indices, self._distances = self._nnd_idx.query(test, k, epsilon)
    474 else:
    475     from umap.utils import deheap_sort

File ~/miniconda3/envs/test/lib/python3.10/site-packages/pynndescent/pynndescent_.py:1595, in NNDescent.query(self, query_data, k, epsilon)
   1564 """Query the training graph_data for the k nearest neighbors
   1565 
   1566 Parameters
   (...)
   1592     training graph_data.
   1593 """
   1594 if not hasattr(self, "_search_graph"):
-> 1595     self._init_search_graph()
   1597 if not self._is_sparse:
   1598     # Standard case
   1599     if not hasattr(self, "_search_function"):

File ~/miniconda3/envs/test/lib/python3.10/site-packages/pynndescent/pynndescent_.py:967, in NNDescent._init_search_graph(self)
    961     self._search_forest = [
    962         convert_tree_format(tree, self._raw_data.shape[0])
    963         for tree in rp_forest
    964     ]
    965 else:
    966     # convert the best trees into a search forest
--> 967     tree_scores = [
    968         score_linked_tree(tree, self._neighbor_graph[0])
    969         for tree in self._rp_forest
    970     ]
    971     if self.verbose:
    972         print(ts(), "Worst tree score: {:.8f}".format(np.min(tree_scores)))

File ~/miniconda3/envs/test/lib/python3.10/site-packages/pynndescent/pynndescent_.py:968, in <listcomp>(.0)
    961     self._search_forest = [
    962         convert_tree_format(tree, self._raw_data.shape[0])
    963         for tree in rp_forest
    964     ]
    965 else:
    966     # convert the best trees into a search forest
    967     tree_scores = [
--> 968         score_linked_tree(tree, self._neighbor_graph[0])
    969         for tree in self._rp_forest
    970     ]
    971     if self.verbose:
    972         print(ts(), "Worst tree score: {:.8f}".format(np.min(tree_scores)))

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/dispatcher.py:487, in _DispatcherBase._compile_for_args(self, *args, **kws)
    485             e.patch_message('\n'.join((str(e).rstrip(), help_msg)))
    486     # ignore the FULL_TRACEBACKS config, this needs reporting!
--> 487     raise e
    488 finally:
    489     self._types_active_call = []

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/dispatcher.py:420, in _DispatcherBase._compile_for_args(self, *args, **kws)
    418 return_val = None
    419 try:
--> 420     return_val = self.compile(tuple(argtypes))
    421 except errors.ForceLiteralArg as e:
    422     # Received request for compiler re-entry with the list of arguments
    423     # indicated by e.requested_args.
    424     # First, check if any of these args are already Literal-ized
    425     already_lit_pos = [i for i in e.requested_args
    426                        if isinstance(args[i], types.Literal)]

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/dispatcher.py:965, in Dispatcher.compile(self, sig)
    963 with ev.trigger_event("numba:compile", data=ev_details):
    964     try:
--> 965         cres = self._compiler.compile(args, return_type)
    966     except errors.ForceLiteralArg as e:
    967         def folded(args, kws):

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/dispatcher.py:125, in _FunctionCompiler.compile(self, args, return_type)
    124 def compile(self, args, return_type):
--> 125     status, retval = self._compile_cached(args, return_type)
    126     if status:
    127         return retval

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/dispatcher.py:139, in _FunctionCompiler._compile_cached(self, args, return_type)
    136     pass
    138 try:
--> 139     retval = self._compile_core(args, return_type)
    140 except errors.TypingError as e:
    141     self._failed_cache[key] = e

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/dispatcher.py:152, in _FunctionCompiler._compile_core(self, args, return_type)
    149 flags = self._customize_flags(flags)
    151 impl = self._get_implementation(args, {})
--> 152 cres = compiler.compile_extra(self.targetdescr.typing_context,
    153                               self.targetdescr.target_context,
    154                               impl,
    155                               args=args, return_type=return_type,
    156                               flags=flags, locals=self.locals,
    157                               pipeline_class=self.pipeline_class)
    158 # Check typing error if object mode is used
    159 if cres.typing_error is not None and not flags.enable_pyobject:

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler.py:693, in compile_extra(typingctx, targetctx, func, args, return_type, flags, locals, library, pipeline_class)
    669 """Compiler entry point
    670 
    671 Parameter
   (...)
    689     compiler pipeline
    690 """
    691 pipeline = pipeline_class(typingctx, targetctx, library,
    692                           args, return_type, flags, locals)
--> 693 return pipeline.compile_extra(func)

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler.py:429, in CompilerBase.compile_extra(self, func)
    427 self.state.lifted = ()
    428 self.state.lifted_from = None
--> 429 return self._compile_bytecode()

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler.py:497, in CompilerBase._compile_bytecode(self)
    493 """
    494 Populate and run pipeline for bytecode input
    495 """
    496 assert self.state.func_ir is None
--> 497 return self._compile_core()

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler.py:476, in CompilerBase._compile_core(self)
    474         self.state.status.fail_reason = e
    475         if is_final_pipeline:
--> 476             raise e
    477 else:
    478     raise CompilerError("All available pipelines exhausted")

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler.py:463, in CompilerBase._compile_core(self)
    461 res = None
    462 try:
--> 463     pm.run(self.state)
    464     if self.state.cr is not None:
    465         break

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler_machinery.py:353, in PassManager.run(self, state)
    350 msg = "Failed in %s mode pipeline (step: %s)" % \
    351     (self.pipeline_name, pass_desc)
    352 patched_exception = self._patch_error(msg, e)
--> 353 raise patched_exception

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler_machinery.py:341, in PassManager.run(self, state)
    339 pass_inst = _pass_registry.get(pss).pass_inst
    340 if isinstance(pass_inst, CompilerPass):
--> 341     self._runPass(idx, pass_inst, state)
    342 else:
    343     raise BaseException("Legacy pass in use")

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler_lock.py:35, in _CompilerLock.__call__.<locals>._acquire_compile_lock(*args, **kwargs)
     32 @functools.wraps(func)
     33 def _acquire_compile_lock(*args, **kwargs):
     34     with self:
---> 35         return func(*args, **kwargs)

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler_machinery.py:296, in PassManager._runPass(self, index, pss, internal_state)
    294     mutated |= check(pss.run_initialization, internal_state)
    295 with SimpleTimer() as pass_time:
--> 296     mutated |= check(pss.run_pass, internal_state)
    297 with SimpleTimer() as finalize_time:
    298     mutated |= check(pss.run_finalizer, internal_state)

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/compiler_machinery.py:269, in PassManager._runPass.<locals>.check(func, compiler_state)
    268 def check(func, compiler_state):
--> 269     mangled = func(compiler_state)
    270     if mangled not in (True, False):
    271         msg = ("CompilerPass implementations should return True/False. "
    272                "CompilerPass with name '%s' did not.")

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/core/typed_passes.py:306, in ParforPass.run_pass(self, state)
    295 assert state.func_ir
    296 parfor_pass = _parfor_ParforPass(state.func_ir,
    297                                  state.typemap,
    298                                  state.calltypes,
   (...)
    304                                  state.metadata,
    305                                  state.parfor_diagnostics)
--> 306 parfor_pass.run()
    308 # check the parfor pass worked and warn if it didn't
    309 has_parfor = False

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/parfors/parfor.py:2926, in ParforPass.run(self)
   2924 # Validate reduction in parfors.
   2925 for p in parfors:
-> 2926     get_parfor_reductions(self.func_ir, p, p.params, self.calltypes)
   2928 # Validate parameters:
   2929 for p in parfors:

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/parfors/parfor.py:3549, in get_parfor_reductions(func_ir, parfor, parfor_params, calltypes, reductions, reduce_varnames, param_uses, param_nodes, var_to_param)
   3547 if param_name in used_vars and param_name not in reduce_varnames:
   3548     param_nodes[param].reverse()
-> 3549     reduce_nodes = get_reduce_nodes(param, param_nodes[param], func_ir)
   3550     # Certain kinds of ill-formed Python (like potentially undefined
   3551     # variables) in combination with SSA can make things look like
   3552     # reductions except that they don't have reduction operators.
   3553     # If we get to this point but don't find a reduction operator
   3554     # then assume it is this situation and just don't treat this
   3555     # variable as a reduction.
   3556     if reduce_nodes is not None:

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/parfors/parfor.py:3637, in get_reduce_nodes(reduction_node, nodes, func_ir)
   3635 defs[lhs.name] = rhs
   3636 if isinstance(rhs, ir.Var) and rhs.name in defs:
-> 3637     rhs = lookup(rhs)
   3638 if isinstance(rhs, ir.Expr):
   3639     in_vars = set(lookup(v, True).name for v in rhs.list_vars())

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/parfors/parfor.py:3627, in get_reduce_nodes.<locals>.lookup(var, varonly)
   3625 val = defs.get(var.name, None)
   3626 if isinstance(val, ir.Var):
-> 3627     return lookup(val)
   3628 else:
   3629     return var if (varonly or val is None) else val

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/parfors/parfor.py:3627, in get_reduce_nodes.<locals>.lookup(var, varonly)
   3625 val = defs.get(var.name, None)
   3626 if isinstance(val, ir.Var):
-> 3627     return lookup(val)
   3628 else:
   3629     return var if (varonly or val is None) else val

    [... skipping similar frames: get_reduce_nodes.<locals>.lookup at line 3627 (2946 times)]

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/parfors/parfor.py:3627, in get_reduce_nodes.<locals>.lookup(var, varonly)
   3625 val = defs.get(var.name, None)
   3626 if isinstance(val, ir.Var):
-> 3627     return lookup(val)
   3628 else:
   3629     return var if (varonly or val is None) else val

File ~/miniconda3/envs/test/lib/python3.10/site-packages/numba/parfors/parfor.py:3625, in get_reduce_nodes.<locals>.lookup(var, varonly)
   3624 def lookup(var, varonly=True):
-> 3625     val = defs.get(var.name, None)
   3626     if isinstance(val, ir.Var):
   3627         return lookup(val)

RecursionError: Failed in nopython mode pipeline (step: convert to parfors)
maximum recursion depth exceeded while calling a Python object

Versions

----- anndata 0.8.0 scanpy 1.8.2 sinfo 0.3.1 ----- PIL 9.0.1 anndata 0.8.0 asttokens NA backcall 0.2.0 beta_ufunc NA binom_ufunc NA cffi 1.15.0 colorama 0.4.4 cycler 0.10.0 cython_runtime NA dateutil 2.8.2 debugpy 1.5.1 decorator 5.1.1 defusedxml 0.7.1 entrypoints 0.4 executing 0.8.3 h5py 3.6.0 hypergeom_ufunc NA igraph 0.9.9 ipykernel 6.9.1 ipython_genutils 0.2.0 ipywidgets 7.7.0 jedi 0.18.1 joblib 1.1.0 kiwisolver 1.4.0 leidenalg 0.8.9 llvmlite 0.38.0 matplotlib 3.4.3 matplotlib_inline NA mpl_toolkits NA natsort 8.1.0 nbinom_ufunc NA numba 0.55.1 numexpr 2.8.0 numpy 1.21.5 packaging 21.3 pandas 1.4.1 parso 0.8.3 pexpect 4.8.0 pickleshare 0.7.5 pkg_resources NA prompt_toolkit 3.0.27 ptyprocess 0.7.0 pure_eval 0.2.2 pycparser 2.21 pydev_ipython NA pydevconsole NA pydevd 2.6.0 pydevd_concurrency_analyser NA pydevd_file_utils NA pydevd_plugins NA pydevd_tracing NA pygments 2.11.2 pynndescent 0.5.6 pyparsing 3.0.7 pytz 2022.1 scanpy 1.8.2 scipy 1.8.0 seaborn 0.11.2 setuptools 60.10.0 sinfo 0.3.1 six 1.16.0 sklearn 1.0.2 sphinxcontrib NA stack_data 0.2.0 statsmodels 0.13.2 tables 3.7.0 texttable 1.6.4 threadpoolctl 3.1.0 tornado 6.1 tqdm 4.63.1 traitlets 5.1.1 typing_extensions NA umap 0.5.2 wcwidth 0.2.5 zmq 22.3.0 ----- IPython 8.1.1 jupyter_client 7.1.2 jupyter_core 4.9.2 notebook 6.4.10 ----- Python 3.10.4 | packaged by conda-forge | (main, Mar 24 2022, 17:38:57) [GCC 10.3.0] Linux-5.10.102.1-microsoft-standard-WSL2-x86_64-with-glibc2.31 8 logical CPU cores, x86_64 ----- Session information updated at 2022-03-24 22:07
flying-sheep commented 4 days ago

We’re testing ingest with 3.12 and soon drop support for 3.9, so this should definitely be working.

I just ran the tutorial and it works fine: https://github.com/scverse/scanpy-tutorials/pull/139