diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3f91485..6525805 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.15.6 + rev: v0.16.0 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/setup.py b/setup.py index 53ff92a..0154199 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ if __name__ == "__main__": try: setup(use_scm_version={"version_scheme": "no-guess-dev"}) - except: # noqa + except: print( "\n\nAn error occurred while building the project, " "please ensure you have the most updated version of setuptools, " diff --git a/src/compressed_lists/__init__.py b/src/compressed_lists/__init__.py index 46b8676..8bcf8e2 100644 --- a/src/compressed_lists/__init__.py +++ b/src/compressed_lists/__init__.py @@ -15,12 +15,12 @@ finally: del version, PackageNotFoundError -from .partition import Partitioning from .base import CompressedList -from .integer_list import CompressedIntegerList -from .string_list import CompressedStringList, CompressedCharacterList +from .biocframe_list import CompressedSplitBiocFrameList from .bool_list import CompressedBooleanList from .float_list import CompressedFloatList +from .integer_list import CompressedIntegerList from .numpy_list import CompressedNumpyList -from .biocframe_list import CompressedSplitBiocFrameList +from .partition import Partitioning from .split_generic import splitAsCompressedList +from .string_list import CompressedCharacterList, CompressedStringList diff --git a/src/compressed_lists/base.py b/src/compressed_lists/base.py index 53aa35c..861d214 100644 --- a/src/compressed_lists/base.py +++ b/src/compressed_lists/base.py @@ -1,11 +1,12 @@ from __future__ import annotations -from typing import Any, Callable, Dict, Iterator, List, Optional, Sequence, Union +from collections.abc import Callable, Iterator, Sequence +from typing import Any from warnings import warn import biocutils as ut -from biocframe import BiocFrame import numpy as np +from biocframe import BiocFrame from .partition import Partitioning @@ -59,8 +60,8 @@ def __init__( unlist_data: Any, partitioning: Partitioning, element_type: Any = None, - element_metadata: Optional[BiocFrame] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, + element_metadata: BiocFrame | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, _validate: bool = True, ): """Initialize a CompressedList. @@ -205,8 +206,8 @@ def __str__(self) -> str: output += f"partitioning: {ut.print_truncated_list(self._partitioning)}\n" - output += f"element_metadata({str(len(self._element_metadata))} rows): {ut.print_truncated_list(list(self._element_metadata.get_column_names()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" - output += f"metadata({str(len(self._metadata))}): {ut.print_truncated_list(list(self._metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"element_metadata({len(self._element_metadata)!s} rows): {ut.print_truncated_list(list(self._element_metadata.get_column_names()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"metadata({len(self._metadata)!s}): {ut.print_truncated_list(list(self._metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" return output @@ -240,7 +241,7 @@ def paritioning(self) -> Partitioning: ######>> names <<###### ####################### - def get_names(self) -> Optional[ut.Names]: + def get_names(self) -> ut.Names | None: """Get the names of list elements.""" return self._partitioning.get_names() @@ -264,7 +265,7 @@ def set_names(self, names: Sequence[str], in_place: bool = False) -> CompressedL return output @property - def names(self) -> Optional[ut.Names]: + def names(self) -> ut.Names | None: """Alias for :py:attr:`~get_names`.""" return self._partitioning.get_names() @@ -379,7 +380,7 @@ def element_metadata(self, element_metadata: BiocFrame): ######>> accessors <<##### ########################## - def __getitem__(self, key: Union[int, str, slice]) -> Any: + def __getitem__(self, key: int | str | slice) -> Any: """Get an element or slice of elements from the list. Args: @@ -458,8 +459,8 @@ def extract_range(self, start: int, end: int) -> Any: def from_list( cls, lst: Any, - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, + names: ut.Names | Sequence[str] | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, ) -> CompressedList: """Create a CompressedList from a regular list. @@ -496,7 +497,7 @@ def from_list( ######>> coercions <<###### ########################### - def to_list(self) -> List[List[Any]]: + def to_list(self) -> list[list[Any]]: """Convert to a regular Python list. Returns: @@ -511,7 +512,7 @@ def to_list(self) -> List[List[Any]]: return result - def as_list(self) -> List[List[Any]]: + def as_list(self) -> list[list[Any]]: """Alias to :py:meth:`~to_list`""" return self.to_list() diff --git a/src/compressed_lists/biocframe_list.py b/src/compressed_lists/biocframe_list.py index 58e8873..d5b8eff 100644 --- a/src/compressed_lists/biocframe_list.py +++ b/src/compressed_lists/biocframe_list.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import Any, Dict, List, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any import biocutils as ut from biocframe import BiocFrame @@ -23,8 +24,8 @@ def __init__( self, unlist_data: BiocFrame, partitioning: Partitioning, - element_metadata: Optional[dict] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, + element_metadata: dict | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, **kwargs, ): """Initialize a CompressedSplitBiocFrameList. @@ -55,9 +56,9 @@ def __init__( @classmethod def from_list( cls, - lst: List[BiocFrame], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + lst: list[BiocFrame], + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> CompressedSplitBiocFrameList: """Create a `CompressedSplitBiocFrameList` from a regular list. @@ -82,7 +83,7 @@ def from_list( partitioning = Partitioning.from_list(lst, names) return cls(unlist_data, partitioning, metadata=metadata) - def __getitem__(self, key: Union[int, str, slice]): + def __getitem__(self, key: int | str | slice): """Override to handle column extraction using `splitAsCompressedList`.""" if isinstance(key, str): column_data = self._unlist_data.get_column(key) @@ -154,8 +155,8 @@ def __str__(self) -> str: output += f"partitioning: {ut.print_truncated_list(self._partitioning)}\n" - output += f"element_metadata({str(len(self._element_metadata))} rows): {ut.print_truncated_list(list(self._element_metadata.get_column_names()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" - output += f"metadata({str(len(self._metadata))}): {ut.print_truncated_list(list(self._metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"element_metadata({len(self._element_metadata)!s} rows): {ut.print_truncated_list(list(self._element_metadata.get_column_names()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" + output += f"metadata({len(self._metadata)!s}): {ut.print_truncated_list(list(self._metadata.keys()), sep=' ', include_brackets=False, transform=lambda y: y)}\n" return output @@ -179,9 +180,9 @@ def empty(cls, n: int): @splitAsCompressedList.register def _( data: BiocFrame, - groups_or_partitions: Union[list, Partitioning], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + groups_or_partitions: list | Partitioning, + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> CompressedSplitBiocFrameList: """Handle lists of BiocFrame objects.""" diff --git a/src/compressed_lists/bool_list.py b/src/compressed_lists/bool_list.py index df21979..2dcc2b7 100644 --- a/src/compressed_lists/bool_list.py +++ b/src/compressed_lists/bool_list.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any from warnings import warn import biocutils as ut @@ -19,8 +20,8 @@ def __init__( self, unlist_data: ut.BooleanList, partitioning: Partitioning, - element_metadata: Optional[dict] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, + element_metadata: dict | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, **kwargs, ): """Initialize a CompressedBooleanList. @@ -57,9 +58,9 @@ def __init__( @splitAsCompressedList.register def _( data: ut.BooleanList, - groups_or_partitions: Union[list, Partitioning], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + groups_or_partitions: list | Partitioning, + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> CompressedBooleanList: """Handle lists of booleans.""" diff --git a/src/compressed_lists/float_list.py b/src/compressed_lists/float_list.py index 3172a16..ad20297 100644 --- a/src/compressed_lists/float_list.py +++ b/src/compressed_lists/float_list.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any from warnings import warn import biocutils as ut @@ -19,8 +20,8 @@ def __init__( self, unlist_data: ut.FloatList, partitioning: Partitioning, - element_metadata: Optional[dict] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, + element_metadata: dict | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, **kwargs, ): """Initialize a CompressedFloatList. @@ -57,9 +58,9 @@ def __init__( @splitAsCompressedList.register def _( data: ut.FloatList, - groups_or_partitions: Union[list, Partitioning], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + groups_or_partitions: list | Partitioning, + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> CompressedFloatList: """Handle lists of floats.""" diff --git a/src/compressed_lists/integer_list.py b/src/compressed_lists/integer_list.py index f2586d2..d0dbb4e 100644 --- a/src/compressed_lists/integer_list.py +++ b/src/compressed_lists/integer_list.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any from warnings import warn import biocutils as ut @@ -19,8 +20,8 @@ def __init__( self, unlist_data: ut.IntegerList, partitioning: Partitioning, - element_metadata: Optional[dict] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, + element_metadata: dict | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, **kwargs, ): """Initialize a CompressedIntegerList. @@ -57,9 +58,9 @@ def __init__( @splitAsCompressedList.register def _( data: ut.IntegerList, - groups_or_partitions: Union[list, Partitioning], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + groups_or_partitions: list | Partitioning, + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> CompressedIntegerList: """Handle lists of integers.""" diff --git a/src/compressed_lists/numpy_list.py b/src/compressed_lists/numpy_list.py index bba2a3a..2b571a5 100644 --- a/src/compressed_lists/numpy_list.py +++ b/src/compressed_lists/numpy_list.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import Any, Dict, List, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any from warnings import warn import biocutils as ut @@ -22,8 +23,8 @@ def __init__( self, unlist_data: np.ndarray, partitioning: Partitioning, - element_metadata: Optional[dict] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, + element_metadata: dict | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, **kwargs, ): """Initialize a CompressedNumpyList. @@ -62,9 +63,9 @@ def __init__( @classmethod def from_list( cls, - lst: List[np.ndarray], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + lst: list[np.ndarray], + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> CompressedNumpyList: """ Create a `CompressedNumpyList` from a list of NumPy vectors. @@ -95,9 +96,9 @@ def from_list( @splitAsCompressedList.register def _( data: np.ndarray, - groups_or_partitions: Union[list, Partitioning], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + groups_or_partitions: list | Partitioning, + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> CompressedNumpyList: """Handle NumPy arrays.""" diff --git a/src/compressed_lists/partition.py b/src/compressed_lists/partition.py index 231814f..c569c33 100644 --- a/src/compressed_lists/partition.py +++ b/src/compressed_lists/partition.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import List, Optional, Sequence, Union +from collections.abc import Sequence from warnings import warn import biocutils as ut @@ -26,9 +26,7 @@ class Partitioning: It keeps track of where each element begins and ends in the unlisted data. """ - def __init__( - self, ends: Sequence[int], names: Optional[Union[ut.Names, Sequence[str]]] = None, _validate: bool = True - ): + def __init__(self, ends: Sequence[int], names: ut.Names | Sequence[str] | None = None, _validate: bool = True): """Initialize a Partitioning object. Args: @@ -56,9 +54,7 @@ def __init__( _validate_names(names, len(ends)) @classmethod - def from_lengths( - cls, lengths: Sequence[int], names: Optional[Union[ut.Names, Sequence[str]]] = None - ) -> Partitioning: + def from_lengths(cls, lengths: Sequence[int], names: ut.Names | Sequence[str] | None = None) -> Partitioning: """Create a Partitioning from a sequence of lengths. Args: @@ -75,7 +71,7 @@ def from_lengths( return cls(ends, names) @classmethod - def from_list(cls, lst: List, names: Optional[Union[ut.Names, Sequence[str]]] = None) -> Partitioning: + def from_list(cls, lst: list, names: ut.Names | Sequence[str] | None = None) -> Partitioning: """Create a Partitioning from a list by using the lengths of each element. Args: @@ -198,7 +194,7 @@ def get_partition_range(self, i: int) -> tuple: raise IndexError(f"Partition index {i} out of range.") return (self._starts[i], self._ends[i]) - def __getitem__(self, key: Union[int, slice]) -> Union[tuple, List[tuple]]: + def __getitem__(self, key: int | slice) -> tuple | list[tuple]: """Get partition range(s) by index or slice. Args: @@ -220,11 +216,11 @@ def __getitem__(self, key: Union[int, slice]) -> Union[tuple, List[tuple]]: ######>> names <<##### ###################### - def get_names(self) -> Optional[ut.Names]: + def get_names(self) -> ut.Names | None: """Return the names of each partition.""" return self._names - def set_names(self, names: Optional[Union[ut.Names, Sequence[str]]], in_place: bool = False) -> Partitioning: + def set_names(self, names: ut.Names | Sequence[str] | None, in_place: bool = False) -> Partitioning: """Set the names of list elements. Args: @@ -250,12 +246,12 @@ def set_names(self, names: Optional[Union[ut.Names, Sequence[str]]], in_place: b return output @property - def names(self) -> Optional[ut.Names]: + def names(self) -> ut.Names | None: """Alias for :py:attr:`~get_names`, provided for back-compatibility.""" return self.get_names() @names.setter - def names(self, names: Optional[Union[ut.Names, Sequence[str]]]): + def names(self, names: ut.Names | Sequence[str] | None): """Alias for :py:meth:`~set_names` with ``in_place = True``. As this mutates the original object, a warning is raised. diff --git a/src/compressed_lists/split_generic.py b/src/compressed_lists/split_generic.py index af44359..1647972 100644 --- a/src/compressed_lists/split_generic.py +++ b/src/compressed_lists/split_generic.py @@ -1,6 +1,7 @@ from collections import defaultdict +from collections.abc import Sequence from functools import singledispatch -from typing import Any, List, Optional, Sequence, Tuple, Union +from typing import Any import biocutils as ut import numpy as np @@ -13,8 +14,8 @@ def groups_to_partition( - data: Any, groups: list, names: Optional[Union[ut.Names, Sequence[str]]] = None -) -> Tuple[List[Any], Partitioning]: + data: Any, groups: list, names: ut.Names | Sequence[str] | None = None +) -> tuple[list[Any], Partitioning]: """Convert group membership vector to partitioned data and Partitioning object. Args: @@ -60,9 +61,9 @@ def groups_to_partition( @singledispatch def splitAsCompressedList( data: Any, - groups_or_partitions: Union[list, Partitioning], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + groups_or_partitions: list | Partitioning, + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> Any: """Generic function to split data into an appropriate `CompressedList` subclass. diff --git a/src/compressed_lists/string_list.py b/src/compressed_lists/string_list.py index 54892d0..39f1168 100644 --- a/src/compressed_lists/string_list.py +++ b/src/compressed_lists/string_list.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any from warnings import warn import biocutils as ut @@ -19,8 +20,8 @@ def __init__( self, unlist_data: ut.StringList, partitioning: Partitioning, - element_metadata: Optional[dict] = None, - metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None, + element_metadata: dict | None = None, + metadata: dict[str, Any] | ut.NamedList | None = None, **kwargs, ): """Initialize a CompressedStringList. @@ -60,9 +61,9 @@ class CompressedCharacterList(CompressedStringList): @splitAsCompressedList.register def _( data: ut.StringList, - groups_or_partitions: Union[list, Partitioning], - names: Optional[Union[ut.Names, Sequence[str]]] = None, - metadata: Optional[dict] = None, + groups_or_partitions: list | Partitioning, + names: ut.Names | Sequence[str] | None = None, + metadata: dict | None = None, ) -> CompressedStringList: """Handle lists of strings.""" diff --git a/tests/test_base.py b/tests/test_base.py index 164e519..a43c7a1 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -2,9 +2,9 @@ import biocutils as ut import pytest +from biocframe import BiocFrame from compressed_lists import CompressedList -from biocframe import BiocFrame __author__ = "Jayaram Kancherla" __copyright__ = "Jayaram Kancherla" diff --git a/tests/test_comp_custom.py b/tests/test_comp_custom.py index 82bd860..105cc76 100644 --- a/tests/test_comp_custom.py +++ b/tests/test_comp_custom.py @@ -1,4 +1,5 @@ -from typing import Any, List, Optional, Sequence +from collections.abc import Sequence +from typing import Any import pytest @@ -17,20 +18,20 @@ def __init__( unlist_data: Any, partitioning: Partitioning, element_type: Any = None, - element_metadata: Optional[dict] = None, - metadata: Optional[dict] = None, + element_metadata: dict | None = None, + metadata: dict | None = None, validate: bool = True, ): super().__init__( unlist_data, partitioning, element_type="float", element_metadata=element_metadata, metadata=metadata ) - def extract_range(self, start: int, end: int) -> List[float]: + def extract_range(self, start: int, end: int) -> list[float]: return self._unlist_data[start:end] @classmethod def from_list( - cls, lst: List[Any], names: Optional[Sequence[str]] = None, metadata: Optional[dict] = None + cls, lst: list[Any], names: Sequence[str] | None = None, metadata: dict | None = None ) -> "CompressedCustomFloatList": flat_data = [] for sublist in lst: