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

Revert "Drop 3.9" #95 #110

Merged
merged 2 commits into from
Dec 3, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
# Use macos-13 because pip binary packages for ARM aren't
# available for many dependencies
os: [macos-13, macos-14, ubuntu-latest]
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.9", "3.10", "3.11", "3.12"]
exclude:
# Just run macos tests on one Python version
- os: macos-13
Expand All @@ -36,6 +36,8 @@ jobs:
python-version: "3.11"
- os: macos-13
python-version: "3.12"
- os: macos-14
python-version: "3.9"
- os: macos-14
python-version: "3.10"
- os: macos-14
Expand Down
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dependencies = [
"pyranges",
"pyparsing>=3"
]
requires-python = ">=3.10"
requires-python = ">=3.9"
classifiers = [
"Development Status :: 4 - Beta",
"License :: OSI Approved :: Apache Software License",
Expand All @@ -28,6 +28,7 @@ classifiers = [
"Intended Audience :: Science/Research",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down Expand Up @@ -61,8 +62,8 @@ addopts = "--cov=vcztools --cov-report=term-missing"
write_to = "vcztools/_version.py"

[tool.ruff]
# Assume Python 3.10
target-version = "py310"
# Assume Python 3.9
target-version = "py39"

# Same as Black.
line-length = 88
Expand Down
4 changes: 3 additions & 1 deletion tests/test_regions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

import pytest

from vcztools.regions import parse_region_string
Expand All @@ -13,6 +15,6 @@
],
)
def test_parse_region_string(
targets: str, expected: tuple[str, int | None, int | None]
targets: str, expected: tuple[str, Optional[int], Optional[int]]
):
assert parse_region_string(targets) == expected
6 changes: 3 additions & 3 deletions tests/test_vcf_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def test_write_vcf__filtering(tmp_path, include, exclude, expected_chrom_pos):
assert len(variants) == len(expected_chrom_pos)
assert v.samples == ["NA00001", "NA00002", "NA00003"]

for variant, chrom_pos in zip(variants, expected_chrom_pos, strict=True):
for variant, chrom_pos in zip(variants, expected_chrom_pos):
chrom, pos = chrom_pos
assert variant.CHROM == chrom
assert variant.POS == pos
Expand Down Expand Up @@ -141,7 +141,7 @@ def test_write_vcf__regions(tmp_path, regions, targets,

assert v.samples == ["NA00001", "NA00002", "NA00003"]

for variant, chrom_pos in zip(variants, expected_chrom_pos, strict=True):
for variant, chrom_pos in zip(variants, expected_chrom_pos):
chrom, pos = chrom_pos
assert variant.CHROM == chrom
assert variant.POS == pos
Expand Down Expand Up @@ -230,7 +230,7 @@ def test_write_vcf__regions_samples_filtering(
assert len(variants) == len(expected_chrom_pos)
assert v.samples == ["NA00001"]

for variant, chrom_pos in zip(variants, expected_chrom_pos, strict=True):
for variant, chrom_pos in zip(variants, expected_chrom_pos):
chrom, pos = chrom_pos
assert variant.CHROM == chrom
assert variant.POS == pos
Expand Down
2 changes: 1 addition & 1 deletion vcztools/filter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import functools
import operator
from collections.abc import Callable
from typing import Callable

import numpy as np
import pyparsing as pp
Expand Down
33 changes: 15 additions & 18 deletions vcztools/query.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import functools
import itertools
import math
from collections.abc import Callable
from typing import Callable, Optional, Union

import numpy as np
import pyparsing as pp
Expand Down Expand Up @@ -62,10 +62,10 @@ def __call__(self, *args, **kwargs):
class QueryFormatGenerator:
def __init__(
self,
query_format: str | pp.ParseResults,
query_format: Union[str, pp.ParseResults],
*,
include: str | None = None,
exclude: str | None = None,
include: Optional[str] = None,
exclude: Optional[str] = None,
):
if isinstance(query_format, str):
parser = QueryFormatParser()
Expand Down Expand Up @@ -99,7 +99,7 @@ def generate(root):
end = start + v_chunk_size

for gt_row, phase in zip(
gt_zarray[start:end], phase_zarray[start:end], strict=True
gt_zarray[start:end], phase_zarray[start:end]
):

def stringify(gt_and_phase: tuple):
Expand All @@ -113,7 +113,7 @@ def stringify(gt_and_phase: tuple):
return separator.join(gt)

gt_row = gt_row.tolist()
yield map(stringify, zip(gt_row, phase, strict=True))
yield map(stringify, zip(gt_row, phase))
else:
# TODO: Support datasets without the phasing data
raise NotImplementedError
Expand Down Expand Up @@ -230,8 +230,8 @@ def _compose_sample_loop_generator(

def generate(root):
iterables = (generator(root) for generator in generators)
zipped = zip(*iterables, strict=True)
zipped_zipped = (zip(*element, strict=True) for element in zipped)
zipped = zip(*iterables)
zipped_zipped = (zip(*element) for element in zipped)
flattened_zipped_zipped = (
(
subsubelement
Expand All @@ -245,7 +245,7 @@ def generate(root):
return generate

def _compose_element_generator(
self, element: str | pp.ParseResults, *, sample_loop=False
self, element: Union[str, pp.ParseResults], *, sample_loop=False
) -> Callable:
if isinstance(element, pp.ParseResults):
if element.get_name() == "subfield":
Expand All @@ -272,7 +272,7 @@ def generate(root):
return generate

def _compose_filter_generator(
self, *, include: str | None = None, exclude: str | None = None
self, *, include: Optional[str] = None, exclude: Optional[str] = None
) -> Callable:
assert not (include and exclude)

Expand Down Expand Up @@ -305,8 +305,8 @@ def _compose_generator(
self,
parse_results: pp.ParseResults,
*,
include: str | None = None,
exclude: str | None = None,
include: Optional[str] = None,
exclude: Optional[str] = None,
) -> Callable:
generators = (
self._compose_element_generator(element) for element in parse_results
Expand All @@ -318,10 +318,7 @@ def _compose_generator(
def generate(root) -> str:
iterables = (generator(root) for generator in generators)
filter_iterable = filter_generator(root)

for results, filter_indicator in zip(
zip(*iterables, strict=True), filter_iterable, strict=True
):
for results, filter_indicator in zip(zip(*iterables), filter_iterable):
if filter_indicator:
results = map(str, results)
yield "".join(results)
Expand All @@ -334,8 +331,8 @@ def write_query(
output=None,
*,
query_format: str,
include: str | None = None,
exclude: str | None = None,
include: Optional[str] = None,
exclude: Optional[str] = None,
):
if include and exclude:
raise ValueError(
Expand Down
27 changes: 14 additions & 13 deletions vcztools/regions.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import re
from typing import Any
from typing import Any, Optional

import numpy as np
import pandas as pd
from pyranges import PyRanges


def parse_region_string(region: str) -> tuple[str, int | None, int | None]:
def parse_region_string(region: str) -> tuple[str, Optional[int], Optional[int]]:
"""Return the contig, start position and end position from a region string."""
if re.search(r":\d+-\d*$", region):
contig, start_end = region.rsplit(":", 1)
Expand All @@ -21,7 +21,7 @@ def parse_region_string(region: str) -> tuple[str, int | None, int | None]:


def regions_to_pyranges(
regions: list[tuple[str, int | None, int | None]], all_contigs: list[str]
regions: list[tuple[str, Optional[int], Optional[int]]], all_contigs: list[str]
) -> PyRanges:
"""Convert region tuples to a PyRanges object."""

Expand All @@ -44,7 +44,7 @@ def regions_to_pyranges(
return PyRanges(chromosomes=chromosomes, starts=starts, ends=ends)


def parse_regions(regions: str | None, all_contigs: list[str]) -> PyRanges | None:
def parse_regions(regions: Optional[str], all_contigs: list[str]) -> Optional[PyRanges]:
"""Return a PyRanges object from a comma-separated set of region strings."""
if regions is None:
return None
Expand All @@ -54,21 +54,22 @@ def parse_regions(regions: str | None, all_contigs: list[str]) -> PyRanges | Non


def parse_targets(
targets: str | None, all_contigs: list[str]
) -> tuple[PyRanges | None, bool]:
targets: Optional[str], all_contigs: list[str]
) -> tuple[Optional[PyRanges], bool]:
"""Return a PyRanges object from a comma-separated set of region strings,
optionally preceeded by a ^ character to indicate complement."""
if targets is None:
return None, False
complement = targets.startswith("^")
return parse_regions(
targets[1:] if complement else targets, all_contigs
), complement
return (
parse_regions(targets[1:] if complement else targets, all_contigs),
complement,
)


def regions_to_chunk_indexes(
regions: PyRanges | None,
targets: PyRanges | None,
regions: Optional[PyRanges],
targets: Optional[PyRanges],
complement: bool,
regions_index: Any,
):
Expand Down Expand Up @@ -112,8 +113,8 @@ def regions_to_chunk_indexes(


def regions_to_selection(
regions: PyRanges | None,
targets: PyRanges | None,
regions: Optional[PyRanges],
targets: Optional[PyRanges],
complement: bool,
variant_contig: Any,
variant_position: Any,
Expand Down
2 changes: 1 addition & 1 deletion vcztools/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def stats(vcz, output):
).astype(np.int64)

for contig, contig_length, nr in zip(
contigs, contig_lengths, num_records_per_contig, strict=True
contigs, contig_lengths, num_records_per_contig
):
if nr > 0:
print(f"{contig}\t{contig_length}\t{nr}", file=output)
2 changes: 1 addition & 1 deletion vcztools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def open_file_like(file):
"""A context manager for opening a file path or string (and closing on exit),
or passing a file-like object through."""
with ExitStack() as stack:
if isinstance(file, str | Path):
if isinstance(file, (str, Path)):
file = stack.enter_context(open(file, mode="w"))
yield file

Expand Down
7 changes: 4 additions & 3 deletions vcztools/vcf_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
import sys
from datetime import datetime
from typing import Optional

import numpy as np
import zarr
Expand Down Expand Up @@ -89,8 +90,8 @@ def write_vcf(
no_update=None,
samples=None,
drop_genotypes: bool = False,
include: str | None = None,
exclude: str | None = None,
include: Optional[str] = None,
exclude: Optional[str] = None,
) -> None:
"""Convert a dataset to a VCF file.

Expand Down Expand Up @@ -307,7 +308,7 @@ def c_chunk_to_vcf(
*,
drop_genotypes,
no_update,
preceding_future: concurrent.futures.Future | None = None,
preceding_future=None,
):
chrom = contigs[get_vchunk_array(root["variant_contig"], v_chunk, v_mask_chunk)]
# TODO check we don't truncate silently by doing this
Expand Down
Loading