Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ repos:

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.15.6
rev: v0.16.2
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def build_cmake(self, ext):
ext_modules=[CMakeExtension("iranges")],
cmdclass={"build_ext": build_ext},
)
except: # noqa
except:
print(
"\n\nAn error occurred while building the project, "
"please ensure you have the most updated version of setuptools, "
Expand Down
93 changes: 46 additions & 47 deletions src/iranges/IRanges.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

from collections.abc import Sequence
from copy import deepcopy
from typing import Any, Dict, List, Literal, Optional, Sequence, Tuple, Union
from typing import Any, Literal
from warnings import warn

import biocutils as ut
Expand Down Expand Up @@ -63,11 +64,11 @@ class IRanges(ut.BiocObject):

def __init__(
self,
start: Union[np.ndarray, Sequence[int]] = [],
width: Union[np.ndarray, Sequence[int]] = [],
names: Optional[Union[Sequence[str], ut.Names]] = None,
mcols: Optional[BiocFrame] = None,
metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None,
start: np.ndarray | Sequence[int] = [],
width: np.ndarray | Sequence[int] = [],
names: Sequence[str] | ut.Names | None = None,
mcols: BiocFrame | None = None,
metadata: dict[str, Any] | ut.NamedList | None = None,
_validate: bool = True,
):
"""
Expand Down Expand Up @@ -151,7 +152,7 @@ def _sanitize_names(self, names):

def _validate_names(self):
if self._names is None:
return None
return

if not isinstance(self._names, ut.Names):
raise ValueError("'names' should be a list of strings.")
Expand Down Expand Up @@ -185,7 +186,7 @@ def get_start(self) -> np.ndarray:
"""
return self._start

def set_start(self, start: Union[np.ndarray, Sequence[int]], in_place: bool = False) -> IRanges:
def set_start(self, start: np.ndarray | Sequence[int], in_place: bool = False) -> IRanges:
"""Modify start positions (in-place operation).

Args:
Expand Down Expand Up @@ -222,7 +223,7 @@ def start(self) -> np.ndarray:
return self.get_start()

@start.setter
def start(self, start: Union[np.ndarray, Sequence[int]]):
def start(self, start: np.ndarray | Sequence[int]):
"""Modify start positions (in-place operation).

Args:
Expand All @@ -245,7 +246,7 @@ def get_width(self) -> np.ndarray:
"""
return self._width

def set_width(self, width: Union[np.ndarray, Sequence[int]], in_place: bool = False) -> IRanges:
def set_width(self, width: np.ndarray | Sequence[int], in_place: bool = False) -> IRanges:
"""
Args:
width:
Expand Down Expand Up @@ -282,7 +283,7 @@ def width(self) -> np.ndarray:
return self.get_width()

@width.setter
def width(self, width: Union[np.ndarray, Sequence[int]]):
def width(self, width: np.ndarray | Sequence[int]):
"""Set or modify width of each interval (in-place operation).

Args:
Expand Down Expand Up @@ -323,7 +324,7 @@ def end(self) -> np.ndarray:
"""
return self.get_end()

def get_names(self) -> Optional[ut.Names]:
def get_names(self) -> ut.Names | None:
"""Get range names.

Returns:
Expand All @@ -332,7 +333,7 @@ def get_names(self) -> Optional[ut.Names]:
"""
return self._names

def set_names(self, names: Optional[Union[ut.Names, Sequence[str]]], in_place: bool = False) -> IRanges:
def set_names(self, names: ut.Names | Sequence[str] | None, in_place: bool = False) -> IRanges:
"""
Args:
names:
Expand All @@ -352,7 +353,7 @@ 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:
"""Get names.

Returns:
Expand All @@ -362,7 +363,7 @@ def names(self) -> Optional[ut.Names]:
return self.get_names()

@names.setter
def names(self, names: Optional[Sequence[str]]):
def names(self, names: Sequence[str] | None):
"""Set new names (in-place operation).

Args:
Expand All @@ -388,7 +389,7 @@ def get_mcols(self) -> BiocFrame:
"""
return self._mcols

def set_mcols(self, mcols: Optional[BiocFrame], in_place: bool = False) -> IRanges:
def set_mcols(self, mcols: BiocFrame | None, in_place: bool = False) -> IRanges:
"""Set new metadata about ranges.

Args:
Expand Down Expand Up @@ -419,7 +420,7 @@ def mcols(self) -> BiocFrame:
return self.get_mcols()

@mcols.setter
def mcols(self, mcols: Optional[BiocFrame]):
def mcols(self, mcols: BiocFrame | None):
"""Set new metadata about ranges (in-place operation).

Args:
Expand All @@ -444,7 +445,7 @@ def __len__(self) -> int:
"""
return len(self._start)

def __getitem__(self, subset: Union[Sequence, int, str, bool, slice, range]) -> IRanges:
def __getitem__(self, subset: Sequence | int | str | bool | slice | range) -> IRanges:
"""Subset the IRanges.

Args:
Expand All @@ -465,7 +466,7 @@ def __getitem__(self, subset: Union[Sequence, int, str, bool, slice, range]) ->
metadata=self._metadata,
)

def __setitem__(self, args: Union[Sequence, int, str, bool, slice, range], value: IRanges):
def __setitem__(self, args: Sequence | int | str | bool | slice | range, value: IRanges):
"""Add or update positions (in-place operation).

Args:
Expand Down Expand Up @@ -502,7 +503,7 @@ def __setitem__(self, args: Union[Sequence, int, str, bool, slice, range], value

self.delete_nclist_index()

def get_row(self, index_or_name: Union[str, int]) -> IRanges:
def get_row(self, index_or_name: str | int) -> IRanges:
"""Access a row by index or row name.

Args:
Expand Down Expand Up @@ -677,8 +678,8 @@ def __deepcopy__(self, memo) -> IRanges:
#############################

def shift_and_clip_ranges(
self, shift: np.ndarray, width: Union[int, None] = None, circle_length: Union[int, None] = None
) -> Tuple[np.ndarray, np.ndarray, int, bool]:
self, shift: np.ndarray, width: int | None = None, circle_length: int | None = None
) -> tuple[np.ndarray, np.ndarray, int, bool]:
"""Shift and clip interval ranges.

Args:
Expand All @@ -705,10 +706,10 @@ def shift_and_clip_ranges(

def coverage(
self,
shift: Optional[np.ndarray] = None,
width: Union[int, None] = None,
weight: Optional[np.ndarray] = None,
circle_length: Union[int, None] = None,
shift: np.ndarray | None = None,
width: int | None = None,
weight: np.ndarray | None = None,
circle_length: int | None = None,
method: Literal["auto", "sort", "hash", "naive"] = "auto",
) -> np.ndarray:
"""Compute weighted coverage of ranges.
Expand Down Expand Up @@ -842,7 +843,7 @@ def sort(self, decreasing: bool = False, in_place: bool = False) -> IRanges:
output = self._define_output(in_place)
return output[order]

def gaps(self, start: Optional[int] = None, end: Optional[int] = None) -> IRanges:
def gaps(self, start: int | None = None, end: int | None = None) -> IRanges:
"""Gaps returns an ``IRanges`` object representing the set of intervals that remain after the ranges are
removed specified by the start and end arguments.

Expand Down Expand Up @@ -950,7 +951,7 @@ def disjoint_bins(self) -> np.ndarray:
#### intra-range methods ####
#############################

def shift(self, shift: Union[int, List[int], np.ndarray], in_place: bool = False) -> IRanges:
def shift(self, shift: int | list[int] | np.ndarray, in_place: bool = False) -> IRanges:
"""Shift ranges by specified amount.

Args:
Expand Down Expand Up @@ -982,9 +983,9 @@ def shift(self, shift: Union[int, List[int], np.ndarray], in_place: bool = False

def narrow(
self,
start: Optional[Union[int, List[int], np.ndarray]] = None,
width: Optional[Union[int, List[int], np.ndarray]] = None,
end: Optional[Union[int, List[int], np.ndarray]] = None,
start: int | list[int] | np.ndarray | None = None,
width: int | list[int] | np.ndarray | None = None,
end: int | list[int] | np.ndarray | None = None,
in_place: bool = False,
) -> IRanges:
"""Narrow ranges.
Expand Down Expand Up @@ -1027,8 +1028,8 @@ def narrow(

def resize(
self,
width: Union[int, List[int], np.ndarray],
fix: Union[Literal["start", "end", "center"], List[Literal["start", "end", "center"]]] = "start",
width: int | list[int] | np.ndarray,
fix: Literal["start", "end", "center"] | list[Literal["start", "end", "center"]] = "start",
in_place: bool = False,
) -> IRanges:
"""Resize ranges to the specified ``width`` where either the ``start``, ``end``, or ``center`` is used as an
Expand Down Expand Up @@ -1293,8 +1294,8 @@ def reflect(self, bounds: IRanges, in_place: bool = False) -> IRanges:

def restrict(
self,
start: Optional[Union[int, List[int], np.ndarray]] = None,
end: Optional[Union[int, List[int], np.ndarray]] = None,
start: int | list[int] | np.ndarray | None = None,
end: int | list[int] | np.ndarray | None = None,
keep_all_ranges: bool = False,
) -> IRanges:
"""Restrict ranges to a given start and end positions.
Expand Down Expand Up @@ -1370,10 +1371,10 @@ def restrict(

def threebands(
self,
start: Optional[Union[int, np.ndarray]] = None,
end: Optional[Union[int, np.ndarray]] = None,
width: Optional[Union[int, np.ndarray]] = None,
) -> Dict[str, IRanges]:
start: int | np.ndarray | None = None,
end: int | np.ndarray | None = None,
width: int | np.ndarray | None = None,
) -> dict[str, IRanges]:
"""Split ranges into three parts: left, middle, and right.

Args:
Expand Down Expand Up @@ -1417,7 +1418,7 @@ def threebands(
"right": IRanges(right_starts, right_widths),
}

def overlap_indices(self, start: Optional[int] = None, end: Optional[int] = None) -> np.ndarray:
def overlap_indices(self, start: int | None = None, end: int | None = None) -> np.ndarray:
"""Find overlaps with the start and end positions.

Args:
Expand Down Expand Up @@ -1868,7 +1869,7 @@ def precede(
select: Literal["all", "first"] = "first",
delete_index: bool = True,
num_threads: int = 1,
) -> Union[np.ndarray, BiocFrame]:
) -> np.ndarray | BiocFrame:
"""Find nearest positions that are upstream/precede each query range.

Args:
Expand Down Expand Up @@ -1930,7 +1931,7 @@ def follow(
select: Literal["all", "last"] = "last",
delete_index: bool = True,
num_threads: int = 1,
) -> Union[np.ndarray, BiocFrame]:
) -> np.ndarray | BiocFrame:
"""Find nearest positions that are downstream/follow each query range.

Args:
Expand Down Expand Up @@ -2013,7 +2014,7 @@ def nearest(
adjacent_equals_overlap: bool = True,
delete_index: bool = True,
num_threads: int = 1,
) -> Union[np.ndarray, BiocFrame]:
) -> np.ndarray | BiocFrame:
"""Find nearest ranges in both directions.

Args:
Expand Down Expand Up @@ -2241,9 +2242,7 @@ def combine(self, *other: IRanges) -> IRanges:
######>> window methods <<######
################################

def tile(
self, n: Optional[Union[int, np.ndarray]] = None, width: Optional[Union[int, np.ndarray]] = None
) -> List[IRanges]:
def tile(self, n: int | np.ndarray | None = None, width: int | np.ndarray | None = None) -> list[IRanges]:
"""Split ranges into either n equal parts or parts of fixed width.

Args:
Expand Down Expand Up @@ -2297,7 +2296,7 @@ def tile(

return result

def sliding_windows(self, width: int, step: int = 1) -> List[IRanges]:
def sliding_windows(self, width: int, step: int = 1) -> list[IRanges]:
"""Create sliding windows of fixed width and step size.

Args:
Expand Down
2 changes: 1 addition & 1 deletion src/iranges/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
del version, PackageNotFoundError

from .IRanges import IRanges
from .utils import normalize_array
from .irangeslist import CompressedIRangesList
from .utils import normalize_array
23 changes: 12 additions & 11 deletions src/iranges/irangeslist.py
Original file line number Diff line number Diff line change
@@ -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 compressed_lists import CompressedList, Partitioning
Expand All @@ -20,8 +21,8 @@ def __init__(
self,
unlist_data: IRanges,
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 CompressedIRangesList.
Expand Down Expand Up @@ -52,9 +53,9 @@ def __init__(
@classmethod
def from_list(
cls,
lst: List[IRanges],
names: Optional[Union[ut.Names, Sequence[str]]] = None,
metadata: Optional[Union[Dict[str, Any], ut.NamedList]] = None,
lst: list[IRanges],
names: ut.Names | Sequence[str] | None = None,
metadata: dict[str, Any] | ut.NamedList | None = None,
) -> CompressedIRangesList:
"""Create a `CompressedIRangesList` from a regular list.

Expand Down Expand Up @@ -141,18 +142,18 @@ 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


@splitAsCompressedList.register
def _(
data: IRanges,
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,
) -> CompressedIRangesList:
"""Handle lists of IRanges objects."""

Expand Down
Loading
Loading