Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to python 3.9 #1125

Merged
merged 6 commits into from Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .azure-pipelines.yml
Expand Up @@ -16,8 +16,8 @@ jobs:
Python3.11:
python.version: "3.11"
RUN_COVERAGE: yes
Python3.8:
python.version: "3.8"
Python3.9:
python.version: "3.9"
PreRelease:
python.version: "3.11"
PRERELEASE_DEPENDENCIES: yes
Expand Down
9 changes: 6 additions & 3 deletions anndata/__init__.py
@@ -1,4 +1,5 @@
"""Annotated multivariate observation data."""
from __future__ import annotations

try: # See https://github.com/maresb/hatch-vcs-footgun-example
from setuptools_scm import get_version
Expand Down Expand Up @@ -34,12 +35,14 @@
read_zarr,
)
from ._warnings import (
ExperimentalFeatureWarning,
ImplicitModificationWarning,
OldFormatWarning,
WriteWarning,
ImplicitModificationWarning,
ExperimentalFeatureWarning,
)
from . import experimental

# Experimental needs to be imported last
from . import experimental # isort: skip


def read(*args, **kwargs):
Expand Down
11 changes: 7 additions & 4 deletions anndata/_core/access.py
@@ -1,13 +1,16 @@
from __future__ import annotations

from functools import reduce
from typing import NamedTuple, Tuple
from typing import TYPE_CHECKING, NamedTuple

from . import anndata
if TYPE_CHECKING:
from anndata import AnnData


class ElementRef(NamedTuple):
parent: "anndata.AnnData"
parent: AnnData
attrname: str
keys: Tuple[str, ...] = ()
keys: tuple[str, ...] = ()

def __str__(self) -> str:
return f".{self.attrname}" + "".join(map(lambda x: f"['{x}']", self.keys))
Expand Down
70 changes: 40 additions & 30 deletions anndata/_core/aligned_mapping.py
@@ -1,26 +1,36 @@
from __future__ import annotations

import warnings
from abc import ABC, abstractmethod
from collections import abc as cabc
from collections.abc import Iterator, Mapping, Sequence
from copy import copy
from typing import Union, Optional, Type, ClassVar, TypeVar # Special types
from typing import Iterator, Mapping, Sequence # ABCs
from typing import Tuple, List, Dict # Generic base types
import warnings
from typing import (
TYPE_CHECKING,
ClassVar,
TypeVar,
Union,
)

import numpy as np
import pandas as pd
from scipy.sparse import spmatrix

from ..utils import deprecated, ensure_df_homogeneous, dim_len
from . import raw, anndata
from .views import as_view, view_update
from anndata._warnings import ExperimentalFeatureWarning, ImplicitModificationWarning
from anndata.compat import AwkArray

from ..utils import deprecated, dim_len, ensure_df_homogeneous
from .access import ElementRef
from .index import _subset
from anndata.compat import AwkArray
from anndata._warnings import ExperimentalFeatureWarning, ImplicitModificationWarning
from .views import as_view, view_update

if TYPE_CHECKING:
from .anndata import AnnData
from .raw import Raw


OneDIdx = Union[Sequence[int], Sequence[bool], slice]
TwoDIdx = Tuple[OneDIdx, OneDIdx]
TwoDIdx = tuple[OneDIdx, OneDIdx]

I = TypeVar("I", OneDIdx, TwoDIdx, covariant=True)
# TODO: pd.DataFrame only allowed in AxisArrays?
Expand All @@ -36,16 +46,16 @@ class AlignedMapping(cabc.MutableMapping, ABC):
_allow_df: ClassVar[bool]
"""If this mapping supports heterogeneous DataFrames"""

_view_class: ClassVar[Type["AlignedViewMixin"]]
_view_class: ClassVar[type[AlignedViewMixin]]
"""The view class for this aligned mapping."""

_actual_class: ClassVar[Type["AlignedActualMixin"]]
_actual_class: ClassVar[type[AlignedActualMixin]]
"""The actual class (which has it’s own data) for this aligned mapping."""

def __repr__(self):
return f"{type(self).__name__} with keys: {', '.join(self.keys())}"

def _ipython_key_completions_(self) -> List[str]:
def _ipython_key_completions_(self) -> list[str]:
return list(self.keys())

def _validate_value(self, val: V, key: str) -> V:
Expand Down Expand Up @@ -94,7 +104,7 @@ def attrname(self) -> str:

@property
@abstractmethod
def axes(self) -> Tuple[int, ...]:
def axes(self) -> tuple[int, ...]:
"""Which axes of the parent is this aligned to?"""
pass

Expand All @@ -104,7 +114,7 @@ def is_view(self) -> bool:
pass

@property
def parent(self) -> Union["anndata.AnnData", "raw.Raw"]:
def parent(self) -> AnnData | Raw:
return self._parent

def copy(self):
Expand All @@ -117,7 +127,7 @@ def copy(self):
d[k] = v.copy()
return d

def _view(self, parent: "anndata.AnnData", subset_idx: I):
def _view(self, parent: AnnData, subset_idx: I):
"""Returns a subset copy-on-write view of the object."""
return self._view_class(self, parent, subset_idx)

Expand All @@ -127,7 +137,7 @@ def as_dict(self) -> dict:


class AlignedViewMixin:
parent: "anndata.AnnData"
parent: AnnData
"""Reference to parent AnnData view"""

attrname: str
Expand Down Expand Up @@ -177,7 +187,7 @@ def __len__(self) -> int:


class AlignedActualMixin:
_data: Dict[str, V]
_data: dict[str, V]
"""Underlying mapping to the data"""

is_view = False
Expand Down Expand Up @@ -216,7 +226,7 @@ def attrname(self) -> str:
return f"{self.dim}m"

@property
def axes(self) -> Tuple[int]:
def axes(self) -> tuple[int]:
"""Axes of the parent this is aligned to"""
return (self._axis,)

Expand All @@ -225,7 +235,7 @@ def dim(self) -> str:
"""Name of the dimension this aligned to."""
return self._dimnames[self._axis]

def flipped(self) -> "AxisArraysBase":
def flipped(self) -> AxisArraysBase:
"""Transpose."""
new = self.copy()
new.dimension = abs(self._axis - 1)
Expand Down Expand Up @@ -265,9 +275,9 @@ def dim_names(self) -> pd.Index:
class AxisArrays(AlignedActualMixin, AxisArraysBase):
def __init__(
self,
parent: Union["anndata.AnnData", "raw.Raw"],
parent: AnnData | Raw,
axis: int,
vals: Union[Mapping, AxisArraysBase, None] = None,
vals: Mapping | AxisArraysBase | None = None,
):
self._parent = parent
if axis not in (0, 1):
Expand All @@ -282,7 +292,7 @@ class AxisArraysView(AlignedViewMixin, AxisArraysBase):
def __init__(
self,
parent_mapping: AxisArraysBase,
parent_view: "anndata.AnnData",
parent_view: AnnData,
subset_idx: OneDIdx,
):
self.parent_mapping = parent_mapping
Expand All @@ -306,15 +316,15 @@ class LayersBase(AlignedMapping):
axes = (0, 1)

# TODO: I thought I had a more elegant solution to overriding this...
def copy(self) -> "Layers":
def copy(self) -> Layers:
d = self._actual_class(self.parent)
for k, v in self.items():
d[k] = v.copy()
return d


class Layers(AlignedActualMixin, LayersBase):
def __init__(self, parent: "anndata.AnnData", vals: Optional[Mapping] = None):
def __init__(self, parent: AnnData, vals: Mapping | None = None):
self._parent = parent
self._data = dict()
if vals is not None:
Expand All @@ -325,7 +335,7 @@ class LayersView(AlignedViewMixin, LayersBase):
def __init__(
self,
parent_mapping: LayersBase,
parent_view: "anndata.AnnData",
parent_view: AnnData,
subset_idx: TwoDIdx,
):
self.parent_mapping = parent_mapping
Expand All @@ -351,7 +361,7 @@ def attrname(self) -> str:
return f"{self.dim}p"

@property
def axes(self) -> Tuple[int, int]:
def axes(self) -> tuple[int, int]:
"""Axes of the parent this is aligned to"""
return self._axis, self._axis

Expand All @@ -364,9 +374,9 @@ def dim(self) -> str:
class PairwiseArrays(AlignedActualMixin, PairwiseArraysBase):
def __init__(
self,
parent: "anndata.AnnData",
parent: AnnData,
axis: int,
vals: Optional[Mapping] = None,
vals: Mapping | None = None,
):
self._parent = parent
if axis not in (0, 1):
Expand All @@ -381,7 +391,7 @@ class PairwiseArraysView(AlignedViewMixin, PairwiseArraysBase):
def __init__(
self,
parent_mapping: PairwiseArraysBase,
parent_view: "anndata.AnnData",
parent_view: AnnData,
subset_idx: OneDIdx,
):
self.parent_mapping = parent_mapping
Expand Down