internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: scverse/scanpy

Issue:
Report pynndescent version in sc.logging.print_header
Hi,

Thank you for the great tool. I think this is not a bug. 

Recently I upgraded some packages and found my results were different from the previous runs. I figured out that it is caused by different versions of `pynndescent` (0.4.7 vs 0.5.1), which is recommended to use in UMAP. So I think `pynndescent` should be included in the output of `sc.logging.print_header()`.

#### Versions

<details>

-----
anndata     0.7.5
scanpy      1.6.1
sinfo       0.3.1
-----
PIL                 8.1.0
anndata             0.7.5
constants           NA
cycler              0.10.0
cython_runtime      NA
dateutil            2.8.1
get_version         2.1
h5py                3.1.0
highs_wrapper       NA
igraph              0.8.3
joblib              1.0.0
kiwisolver          1.3.1
legacy_api_wrap     1.2
leidenalg           0.8.3
llvmlite            0.35.0
louvain             0.7.0
matplotlib          3.3.3
mpl_toolkits        NA
natsort             7.1.1
numba               0.52.0
numexpr             2.7.2
numpy               1.19.5
packaging           20.8
pandas              1.2.1
pkg_resources       NA
pynndescent         0.5.1
pyparsing           2.4.7
pytz                2020.5
scanpy              1.6.1
scipy               1.6.0
setuptools_scm      NA
sinfo               0.3.1
six                 1.15.0
sklearn             0.24.1
statsmodels         0.12.1
tables              3.6.1
texttable           1.6.3
umap                0.4.6
-----
Python 3.8.5 (default, Sep  4 2020, 07:30:14) [GCC 7.3.0]
Linux-3.10.0-1160.11.1.el7.x86_64-x86_64-with-glibc2.10
40 logical CPU cores, x86_64

</details>



Discussion:
I would definitely recommend using the `sc.logging.print_versions` function for a more complete listing of dependencies, which does include `pynndescent`. That said, I'm not against adding it to the more compact version.

Resolving patch:
diff --git a/scanpy/logging.py b/scanpy/logging.py
--- a/scanpy/logging.py
+++ b/scanpy/logging.py
@@ -131,6 +131,7 @@ def format(self, record: logging.LogRecord):
     ('igraph', 'python-igraph'),
     'louvain',
     'leidenalg',
+    'pynndescent',
 ]
 
 


Test patch:
Repository: scverse/scanpy

Issue:
Failing to detect ipython
- [x] I have checked that this issue has not already been reported.
- [x] I have confirmed this bug exists on the latest version of scanpy.
- [x] (optional) I have confirmed this bug exists on the master branch of scanpy.

---

Initially reported by @VolkerBergen in #1477.

From within ipython:

```python
from scanpy._settings import ScanpyConfig
ScanpyConfig._is_run_from_ipython()
# False
getattr(__builtins__, "__IPYTHON__")
# True
```

I'm not sure if/ how this ever worked, [since `__builtins__` is supposed to be a `dict` unless you're in the `__main__` namespace](https://docs.python.org/3/reference/executionmodel.html#builtins-and-restricted-execution). We can probably replace this with:

```python
import builtins
getattr(builtins, "__IPYTHON__", False)
```


Discussion:

Resolving patch:
diff --git a/scanpy/_settings.py b/scanpy/_settings.py
--- a/scanpy/_settings.py
+++ b/scanpy/_settings.py
@@ -470,8 +470,9 @@ def set_figure_params(
     @staticmethod
     def _is_run_from_ipython():
         """Determines whether we're currently in IPython."""
-        # https://stackoverflow.com/questions/40638507/testing-for-presence-of-ipython
-        return hasattr(__builtins__, "__IPYTHON__")
+        import builtins
+
+        return getattr(builtins, "__IPYTHON__", False)
 
     def __str__(self) -> str:
         return '\n'.join(


Test patch:
Repository: scverse/scanpy

Issue:
Numpy aliases of builtin types deprecated
## Description

Just a minor `numpy` deprecation: As of `numpy==1.20`, aliases of builtin types (`np.float`, `np.int`, ...) are deprecated and should be replaced by the builtin Python counterparts.


Discussion:

Resolving patch:
diff --git a/scanpy/metrics/_metrics.py b/scanpy/metrics/_metrics.py
--- a/scanpy/metrics/_metrics.py
+++ b/scanpy/metrics/_metrics.py
@@ -4,7 +4,7 @@
 from typing import Optional, Sequence, Union
 
 import pandas as pd
-from pandas.api.types import is_categorical
+from pandas.api.types import is_categorical_dtype
 from natsort import natsorted
 import numpy as np
 
@@ -75,11 +75,11 @@ def confusion_matrix(
     )
 
     # Filter
-    if is_categorical(orig):
+    if is_categorical_dtype(orig):
         orig_idx = pd.Series(orig).cat.categories
     else:
         orig_idx = natsorted(pd.unique(orig))
-    if is_categorical(new):
+    if is_categorical_dtype(new):
         new_idx = pd.Series(new).cat.categories
     else:
         new_idx = natsorted(pd.unique(new))
diff --git a/scanpy/preprocessing/_simple.py b/scanpy/preprocessing/_simple.py
--- a/scanpy/preprocessing/_simple.py
+++ b/scanpy/preprocessing/_simple.py
@@ -344,13 +344,11 @@ def log1p_array(X, *, base: Optional[Number] = None, copy: bool = False):
     # X = check_array(X, dtype=(np.float64, np.float32), ensure_2d=False, copy=copy)
     if copy:
         if not np.issubdtype(X.dtype, np.floating):
-            X = X.astype(np.floating)
+            X = X.astype(float)
         else:
             X = X.copy()
-    elif not (
-        np.issubdtype(X.dtype, np.floating) or np.issubdtype(X.dtype, np.complex)
-    ):
-        X = X.astype(np.floating)
+    elif not (np.issubdtype(X.dtype, np.floating) or np.issubdtype(X.dtype, complex)):
+        X = X.astype(float)
     np.log1p(X, out=X)
     if base is not None:
         np.divide(X, np.log(base), out=X)


Test patch:
diff --git a/scanpy/tests/test_clustering.py b/scanpy/tests/test_clustering.py
--- a/scanpy/tests/test_clustering.py
+++ b/scanpy/tests/test_clustering.py
@@ -41,7 +41,7 @@ def test_clustering_subset(adata_neighbors, clustering, key):
 
         # Original category's cells assigned only to new categories
         nonzero_cat = cat_counts[cat_counts > 0].index
-        common_cat = nonzero_cat & adata_neighbors.obs[key].cat.categories
+        common_cat = nonzero_cat.intersection(adata_neighbors.obs[key].cat.categories)
         assert len(common_cat) == 0
Repository: scverse/scanpy

Issue:
Increase visibility of ecosystem page
As discussed at last meeting

- [ ] Document process for adding entries (note this on top of ecosystem page)
- [ ] Link from external
- [ ] Clarify goals/ differences b/w ecosystem and external


Discussion:

Resolving patch:
diff --git a/scanpy/external/__init__.py b/scanpy/external/__init__.py
--- a/scanpy/external/__init__.py
+++ b/scanpy/external/__init__.py
@@ -14,12 +14,15 @@
 External API
 ============
 
+.. note::
+   More tools that integrate well with scanpy and anndata can be found on the :doc:`ecosystem page <../ecosystem>`.
 
 Import Scanpy's wrappers to external tools as::
 
    import scanpy.external as sce
 
-If you'd like to see your tool included here, please open a `pull request <https://github.com/theislab/scanpy>`_!
+If you'd like to include a tool here, consider making a pull request (:doc:`instructions <../dev/external-tools>`).
+If the tool already uses `scanpy` or `anndata`, it may fit better in the :doc:`ecosystem page <../ecosystem>`.
 
 Preprocessing: PP
 ------------------


Test patch:
Repository: scverse/scanpy

Issue:
Pandas 1.3.0 compatibility 
We have some failing tests due to a couple bugs introduced in pandas 1.3.0:

* https://github.com/pandas-dev/pandas/issues/42380

I think this one is small in scope. Has problems when `df.agg` is called, when all columns are categorical and index is non-unique. Definitely a bug in pandas, and I don't think we do this much. Switching to `df.apply` works around the problem.

* https://github.com/pandas-dev/pandas/issues/42376

Assignment of single columns `np.matrix` to dataframe columns no longer works as if the matrix were a 1d array. I think this is a bug since it's an undocumented behaviour change. Fixes are pretty easy, since we can just wrap occurrences with `np.ravel`, however I wouldn't be surprised if there were many places in the codebase that this happened.

I would be good if these didn't happen.


Discussion:

Resolving patch:
diff --git a/scanpy/plotting/_anndata.py b/scanpy/plotting/_anndata.py
--- a/scanpy/plotting/_anndata.py
+++ b/scanpy/plotting/_anndata.py
@@ -1938,7 +1938,7 @@ def _prepare_dataframe(
         categorical.name = groupby[0]
     else:
         # join the groupby values  using "_" to make a new 'category'
-        categorical = obs_tidy[groupby].agg('_'.join, axis=1).astype('category')
+        categorical = obs_tidy[groupby].apply('_'.join, axis=1).astype('category')
         categorical.name = "_".join(groupby)
 
         # preserve category order
diff --git a/scanpy/preprocessing/_qc.py b/scanpy/preprocessing/_qc.py
--- a/scanpy/preprocessing/_qc.py
+++ b/scanpy/preprocessing/_qc.py
@@ -106,7 +106,7 @@ def describe_obs(
         obs_metrics[f"log1p_n_{var_type}_by_{expr_type}"] = np.log1p(
             obs_metrics[f"n_{var_type}_by_{expr_type}"]
         )
-    obs_metrics[f"total_{expr_type}"] = X.sum(axis=1)
+    obs_metrics[f"total_{expr_type}"] = np.ravel(X.sum(axis=1))
     if log1p:
         obs_metrics[f"log1p_total_{expr_type}"] = np.log1p(
             obs_metrics[f"total_{expr_type}"]
@@ -119,8 +119,8 @@ def describe_obs(
                 proportions[:, i] * 100
             )
     for qc_var in qc_vars:
-        obs_metrics[f"total_{expr_type}_{qc_var}"] = X[:, adata.var[qc_var].values].sum(
-            axis=1
+        obs_metrics[f"total_{expr_type}_{qc_var}"] = np.ravel(
+            X[:, adata.var[qc_var].values].sum(axis=1)
         )
         if log1p:
             obs_metrics[f"log1p_total_{expr_type}_{qc_var}"] = np.log1p(


Test patch:
Repository: scverse/scanpy

Issue:
Pass delimiter in `scanpy.read` to `read_csv`
<!-- What kind of feature would you like to request? -->
- [x] Additional function parameters / changed functionality / changed defaults?
- [ ] New analysis tool: A simple analysis tool you have been using and are missing in `sc.tools`?
- [ ] New plotting function: A kind of plot you would like to seein `sc.pl`?
- [ ] External tools: Do you know an existing package that should go into `sc.external.*`?
- [ ] Other?

<!-- Please describe your wishes below: -->

## Description

ATM, the argument `delimiter` in `scvelo.readwrite.py::read` is not passed to `read_csv`. For more flexibility when reading from CSV files, it would be good to do so.


Discussion:

Resolving patch:
diff --git a/scanpy/readwrite.py b/scanpy/readwrite.py
--- a/scanpy/readwrite.py
+++ b/scanpy/readwrite.py
@@ -750,7 +750,11 @@ def _read(
     elif ext in {'mtx', 'mtx.gz'}:
         adata = read_mtx(filename)
     elif ext == 'csv':
-        adata = read_csv(filename, first_column_names=first_column_names)
+        if delimiter is None:
+            delimiter = ','
+        adata = read_csv(
+            filename, first_column_names=first_column_names, delimiter=delimiter
+        )
     elif ext in {'txt', 'tab', 'data', 'tsv'}:
         if ext == 'data':
             logg.hint(


Test patch:
Repository: scverse/scanpy

Issue:
small spelling mistake
In the file scanpy/_utils/__init__.py on master branch, line 412 says:
"Revieved a view of an AnnData. Making a copy."
probably meaning "received"


Discussion:
Thanks for the heads up! Would you be willing to file a quick pull request?

(Could do it myself, but happy to bring in new contributors)

Resolving patch:
diff --git a/scanpy/_utils/__init__.py b/scanpy/_utils/__init__.py
--- a/scanpy/_utils/__init__.py
+++ b/scanpy/_utils/__init__.py
@@ -409,7 +409,7 @@ def sanitize_anndata(adata):
 def view_to_actual(adata):
     if adata.is_view:
         warnings.warn(
-            "Revieved a view of an AnnData. Making a copy.",
+            "Received a view of an AnnData. Making a copy.",
             stacklevel=2,
         )
         adata._init_as_actual(adata.copy())


Test patch:
Repository: scverse/scanpy

Issue:
Use session_info instead of sinfo
[`sinfo` has been replaced](https://pypi.org/project/sinfo/) with [`session_info`](https://gitlab.com/joelostblom/session_info), which is definitely a better name. We should switch over to using this.

I think we'll be calling it like: `import session_info; session_info.show(dependencies=True, html=False, **extra_kwargs)`


Discussion:

Resolving patch:
diff --git a/scanpy/logging.py b/scanpy/logging.py
--- a/scanpy/logging.py
+++ b/scanpy/logging.py
@@ -1,15 +1,14 @@
 """Logging and Profiling
 """
-import io
 import logging
 import sys
 from functools import update_wrapper, partial
-from logging import CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET
+from logging import CRITICAL, ERROR, WARNING, INFO, DEBUG
 from datetime import datetime, timedelta, timezone
-from typing import Optional
+from typing import Optional, IO
+import warnings
 
 import anndata.logging
-from sinfo import sinfo
 
 
 HINT = (INFO + DEBUG) // 2
@@ -159,28 +158,37 @@ def print_header(*, file=None):
     )
 
 
-def print_versions(*, file=None):
-    """Print print versions of imported packages"""
-    if file is None:  # Inform people about the behavior change
-        warning('If you miss a compact list, please try `print_header`!')
-    stdout = sys.stdout
-    try:
-        buf = sys.stdout = io.StringIO()
-        sinfo(
+def print_versions(*, file: Optional[IO[str]] = None):
+    """\
+    Print versions of imported packages, OS, and jupyter environment.
+
+    For more options (including rich output) use `session_info.show` directly.
+    """
+    import session_info
+
+    if file is not None:
+        from contextlib import redirect_stdout
+
+        warnings.warn(
+            "Passing argument 'file' to print_versions is deprecated, and will be "
+            "removed in a future version.",
+            FutureWarning,
+        )
+        with redirect_stdout(file):
+            print_versions()
+    else:
+        session_info.show(
             dependencies=True,
+            html=False,
             excludes=[
                 'builtins',
                 'stdlib_list',
                 'importlib_metadata',
                 # Special module present if test coverage being calculated
-                # https://gitlab.com/joelostblom/sinfo/-/issues/10
+                # https://gitlab.com/joelostblom/session_info/-/issues/10
                 "$coverage",
             ],
         )
-    finally:
-        sys.stdout = stdout
-    output = buf.getvalue()
-    print(output, file=file)
 
 
 def print_version_and_date(*, file=None):


Test patch:
Repository: scverse/scanpy

Issue:
`TypeError: metaclass conflict`: matplotlib v3.7.0 is incompatible with scanpy
- [x] I have checked that this issue has not already been reported.
- [x] I have confirmed this bug exists on the latest version of scanpy.
- [x] **Updated:** I have confirmed this bug exists on the master branch of scanpy.

### Minimal code sample

Start from a fresh venv. (Tested on Python 3.9.2 on Debian Bullseye.)

```
(new-venv) $ pip install scanpy==1.9.1
```

Then from within that venv:

```python
import scanpy
```

```pytb
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../site-packages/scanpy/__init__.py", line 16, in <module>
    from . import plotting as pl
  File ".../site-packages/scanpy/plotting/__init__.py", line 1, in <module>
    from ._anndata import (
  File ".../site-packages/scanpy/plotting/_anndata.py", line 28, in <module>
    from . import _utils
  File ".../site-packages/scanpy/plotting/_utils.py", line 35, in <module>
    class _AxesSubplot(Axes, axes.SubplotBase, ABC):
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
```

### Versions

You can't get to `scanpy.logging.print_versions()` on account of the crash.


Discussion:
To users: you can work around this in your environments by installing the previous version of matplotlib, for example with:

```
$ pip install 'matplotlib<3.7'
```

and/or adding a similar version specification to your `pyproject.toml`/`setup.py`/equivalent file, like https://github.com/single-cell-data/TileDB-SOMA/commit/0bc97e893edd2ab6b8dc7d76635a079ae7f91516.

Resolving patch:
diff --git a/scanpy/plotting/_utils.py b/scanpy/plotting/_utils.py
--- a/scanpy/plotting/_utils.py
+++ b/scanpy/plotting/_utils.py
@@ -32,7 +32,7 @@
 VBound = Union[str, float, Callable[[Sequence[float]], float]]
 
 
-class _AxesSubplot(Axes, axes.SubplotBase, ABC):
+class _AxesSubplot(Axes, axes.SubplotBase):
     """Intersection between Axes and SubplotBase: Has methods of both"""
 
 


Test patch:
Repository: scverse/scanpy

Issue:
Improve settings documentation
### What kind of feature would you like to request?

Other?

### Please describe your wishes

Hello Scanpy team!

In scanpy api documentation I see [some settings](https://scanpy.readthedocs.io/en/stable/generated/scanpy._settings.ScanpyConfig.html#scanpy._settings.ScanpyConfig), however I don't understand how we are supposed to use n_job and max_memory settings. I would like scanpy to use whatever is available. How can I do that?



Discussion:
Think that for `n_job` it's generally `-1` to use all cores and concerning the `max_memory` I vaguely remember that the setting isn't really used so you can ignore it.
We might want to document that a bit better. I fatfingered.

Resolving patch:
diff --git a/scanpy/_settings.py b/scanpy/_settings.py
--- a/scanpy/_settings.py
+++ b/scanpy/_settings.py
@@ -303,9 +303,9 @@ def cache_compression(self, cache_compression: Optional[str]):
     @property
     def max_memory(self) -> Union[int, float]:
         """\
-        Maximal memory usage in Gigabyte.
+        Maximum memory usage in Gigabyte.
 
-        Is currently not well respected....
+        Is currently not well respected…
         """
         return self._max_memory
 
@@ -318,6 +318,10 @@ def max_memory(self, max_memory: Union[int, float]):
     def n_jobs(self) -> int:
         """\
         Default number of jobs/ CPUs to use for parallel computing.
+
+        Set to `-1` in order to use all available cores.
+        Not all algorithms support special behavior for numbers < `-1`,
+        so make sure to leave this setting as >= `-1`.
         """
         return self._n_jobs
 


Test patch:
Repository: scverse/scanpy

Issue:
Fix reference links in MyST docs
Links to references in docs are broken. I think we should probably switch over to [sphinxcontrib-bibtex](https://sphinxcontrib-bibtex.readthedocs.io/en/latest/) as recommended by [executable books](https://jupyterbook.org/content/citations.html).


Discussion:
Now, to go from some custom reference formatting scheme to bibtex 😭
doc changes that weren’t backported make it hard to fix this in 1.9.4, so it’ll have to wait for 1.10.0
Actually they aren’t broken in rST at all, only MyST:

https://scanpy.readthedocs.io/en/latest/generated/scanpy.tl.pca.html

![grafik](https://github.com/scverse/scanpy/assets/291575/f1c05c40-7152-4777-8847-fe77e615c346)

Resolving patch:
diff --git a/docs/extensions/cite.py b/docs/extensions/cite.py
new file mode 100644
--- /dev/null
+++ b/docs/extensions/cite.py
@@ -0,0 +1,33 @@
+"""Override MyST’s cite role with one that works."""
+
+from __future__ import annotations
+
+from types import MappingProxyType
+from typing import TYPE_CHECKING
+
+from docutils import nodes, utils
+
+if TYPE_CHECKING:
+    from typing import Any
+    from collections.abc import Mapping, Sequence
+
+    from sphinx.application import Sphinx
+    from docutils.parsers.rst.states import Inliner
+
+
+def cite_role(
+    name: str,
+    rawsource: str,
+    text: str,
+    lineno: int,
+    inliner: Inliner,
+    options: Mapping[str, Any] = MappingProxyType({}),
+    content: Sequence[str] = (),
+) -> tuple[list[nodes.Node], list[nodes.system_message]]:
+    key = utils.unescape(text)
+    node = nodes.citation_reference(f'[{key}]_', key)
+    return [node], []
+
+
+def setup(app: Sphinx):
+    app.add_role('cite', cite_role, override=True)


Test patch:
Repository: scverse/scanpy

Issue:
sc.datasets.blobs should get a random_state parameter
We should make the `random_state` of `make_blobs` available through our `blobs` function. This would make it easier to generate random data for testing. 


Discussion:

Resolving patch:
diff --git a/scanpy/datasets/_datasets.py b/scanpy/datasets/_datasets.py
--- a/scanpy/datasets/_datasets.py
+++ b/scanpy/datasets/_datasets.py
@@ -10,6 +10,7 @@
 from .._settings import settings
 from ..readwrite import read, read_visium
 from ._utils import check_datasetdir_exists, filter_oldformatwarning
+from .._utils import AnyRandom
 
 HERE = Path(__file__).parent
 
@@ -19,6 +20,7 @@ def blobs(
     n_centers: int = 5,
     cluster_std: float = 1.0,
     n_observations: int = 640,
+    random_state: AnyRandom = 0,
 ) -> ad.AnnData:
     """\
     Gaussian Blobs.
@@ -34,6 +36,8 @@ def blobs(
     n_observations
         Number of observations. By default, this is the same observation number
         as in :func:`scanpy.datasets.krumsiek11`.
+    random_state
+        Determines random number generation for dataset creation.
 
     Returns
     -------
@@ -47,7 +51,7 @@ def blobs(
         n_features=n_variables,
         centers=n_centers,
         cluster_std=cluster_std,
-        random_state=0,
+        random_state=random_state,
     )
     return ad.AnnData(X, obs=dict(blobs=y.astype(str)))
 


Test patch:
Repository: scverse/scanpy

Issue:
The compatibility with SpaceRanger v2.0 or later of `read_visium` function
### Please make sure these conditions are met

- [X] I have checked that this issue has not already been reported.
- [X] I have confirmed this bug exists on the latest version of scanpy.
- [X] (optional) I have confirmed this bug exists on the master branch of scanpy.

### What happened?

When reading the `tissue_positions.csv` file generated by SpaceRanger v2.0 or later, `read_visium` reads the header from the second row (with `header=1`), while it should read from the first row instead (with `header=0`).

### Minimal code sample

```python
positions = pd.read_csv(
            files['tissue_positions_file'],
            header=0 if tissue_positions_file.name == "tissue_positions.csv" else None,
            index_col=0,
        )
```


### Error output

_No response_

### Versions

<details>

```
anndata     0.10.2
scanpy      1.10.0.dev157+g9b7f6032
```

</details>



Discussion:

Resolving patch:
diff --git a/scanpy/readwrite.py b/scanpy/readwrite.py
--- a/scanpy/readwrite.py
+++ b/scanpy/readwrite.py
@@ -460,7 +460,7 @@ def read_visium(
         # read coordinates
         positions = pd.read_csv(
             files["tissue_positions_file"],
-            header=1 if tissue_positions_file.name == "tissue_positions.csv" else None,
+            header=0 if tissue_positions_file.name == "tissue_positions.csv" else None,
             index_col=0,
         )
         positions.columns = [


Test patch: