Skip to content
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
2 changes: 1 addition & 1 deletion gffquant/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from enum import Enum, auto, unique


__version__ = "2.18.5"
__version__ = "2.18.6"
__tool__ = "gffquant"


Expand Down
30 changes: 18 additions & 12 deletions gffquant/annotation/count_annotator.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ def annotate(self, refmgr, db, count_manager, gene_group_db=False):
if self.strand_specific else None
)

grouped_counts = {}

for rid in set(count_manager.uniq_seqcounts).union(
count_manager.ambig_seqcounts
):
Expand All @@ -305,24 +307,28 @@ def annotate(self, refmgr, db, count_manager, gene_group_db=False):
if gene_group_db:
ref_tokens = ref.split(".")
gene_id, ggroup_id = ".".join(ref_tokens[:-1]), ref_tokens[-1]
grouped_counts.setdefault(ggroup_id, np.zeros(self.bins))
grouped_counts[ggroup_id] += counts
else:
ggroup_id, gene_id = ref, ref
gene_id = ref
region_annotation = db.query_sequence(gene_id)
if region_annotation is not None:
_, _, region_annotation = region_annotation
self.distribute_feature_counts(counts, region_annotation)
else:
self.unannotated_counts += counts[:4]

gcounts = self.gene_counts.setdefault(gene_id, np.zeros(self.bins))
gcounts += counts
self.total_gene_counts += counts[:4]

region_annotation = db.query_sequence(ggroup_id)
if region_annotation is not None:
_, _, region_annotation = region_annotation
# logger.info(
# "GCAnnotator: Distributing counts of Gene %s (group=%s) %s %s",
# gene_id, ggroup_id, counts[0], counts[2],
# )
self.distribute_feature_counts(counts, region_annotation)

else:
# logger.info("GCAnnotator: Gene %s (group=%s) has no information in database.", gene_id, ggroup_id)
for group_id, counts in grouped_counts.items():
if group_id == "0":
self.unannotated_counts += counts[:4]
else:
region_annotation = db.query_sequence(int(group_id, 16), grouped_db=True,)
if region_annotation is not None:
_, _, region_annotation = region_annotation
self.distribute_feature_counts(counts, region_annotation)

self.calculate_scaling_factors()
23 changes: 16 additions & 7 deletions gffquant/db/annotation_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def from_db(cls, db_path, in_memory=True):
return SQL_ADM(db_path)

@abstractmethod
def query_sequence_internal(self, seqid, start=None, end=None):
def query_sequence_internal(self, seqid, start=None, end=None, grouped_db=False,):
...

@abstractmethod
Expand All @@ -59,17 +59,22 @@ def get_features(self, category_id):
def get_categories(self):
...

def query_sequence(self, seqid, start=None, end=None):
def query_sequence(self, seqid, start=None, end=None, grouped_db=False,):
""" Returns strand, seq-feature id (e.g. contig id), functional categories """
db_sequence = self.query_sequence_internal(seqid, start=start, end=end)
db_sequence = self.query_sequence_internal(seqid, start=start, end=end, grouped_db=grouped_db,)

if db_sequence is None:
return None

strand = getattr(db_sequence, "strand", None)
featureid = getattr(db_sequence, "feature_id", None)

categories = tuple()
for cat_features in db_sequence.annotation_str.strip().split(";"):
category, features = cat_features.split("=")
categories += ((category, tuple(feature.strip() for feature in features.split(",") if feature.strip())),)
return db_sequence.strand, db_sequence.featureid, categories

return strand, featureid, categories
Comment on lines +62 to +77

@coderabbitai coderabbitai Bot Jul 18, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify all query_sequence_internal implementations accept `grouped_db`.

rg 'def query_sequence_internal' -A 2

Repository: cschu/gff_quantifier

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== annotation_db.py =="
wc -l gffquant/db/annotation_db.py
sed -n '1,220p' gffquant/db/annotation_db.py

echo
echo "== search for query_sequence_internal =="
rg -n "query_sequence_internal|class .*AnnotationDatabaseManager|class .*Dict_ADM" gffquant -S

echo
echo "== file list around db package =="
find gffquant -maxdepth 3 -type f | sort

Repository: cschu/gff_quantifier

Length of output: 10728


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Dict_ADM implementation =="
sed -n '230,290p' gffquant/db/annotation_db.py

echo
echo "== grouped_db references =="
rg -n "grouped_db" gffquant -S

echo
echo "== query_sequence calls =="
rg -n "query_sequence\(" gffquant -S

Repository: cschu/gff_quantifier

Length of output: 3229


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
text = Path('gffquant/db/annotation_db.py').read_text()

# Extract the abstract/base and subclass signatures in a simple read-only way.
for needle in [
    'def query_sequence_internal(self, seqid, start=None, end=None):',
    'def query_sequence_internal(self, seqid, start=None, end=None, grouped_db=False,):',
]:
    print(needle, '->', text.count(needle))

print("\nRelevant lines:")
for i, line in enumerate(text.splitlines(), 1):
    if 'query_sequence_internal' in line or 'grouped_db' in line:
        print(f"{i}: {line}")
PY

Repository: cschu/gff_quantifier

Length of output: 787


Update query_sequence_internal to accept grouped_db: add the new kwarg to AnnotationDatabaseManager.query_sequence_internal and Dict_ADM.query_sequence_internal; query_sequence() now always forwards it, so Dict_ADM will raise TypeError as-is.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gffquant/db/annotation_db.py` around lines 62 - 78, Update both
AnnotationDatabaseManager.query_sequence_internal and
Dict_ADM.query_sequence_internal to accept the grouped_db keyword argument,
preserving their existing behavior while allowing query_sequence to forward it
without raising TypeError.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cschu, you’re welcome! 🐇


@abstractmethod
def query_feature(self, feature_id):
Expand Down Expand Up @@ -192,8 +197,12 @@ def __init__(self, db_path):
super().__init__()
self.db_session = db_path

def query_sequence_internal(self, seqid, start=None, end=None):
if start is not None and end is not None:
def query_sequence_internal(self, seqid, start=None, end=None, grouped_db=False,):
if grouped_db:
db_sequence = self.db_session.query(db.AnnotationGroup) \
.filter(db.AnnotationGroup.id == seqid) \
.one_or_none()
elif start is not None and end is not None:
db_sequence = self.db_session.query(db.AnnotatedSequence) \
.filter(db.AnnotatedSequence.seqid == seqid) \
.filter((db.AnnotatedSequence.start == start) & (db.AnnotatedSequence.end == end)).one_or_none()
Expand Down Expand Up @@ -229,7 +238,7 @@ def __init__(self, db_path):
super().__init__()
self.db = db_path

def query_sequence_internal(self, seqid, start=None, end=None):
def query_sequence_internal(self, seqid, start=None, end=None, grouped_db=False,):
if start is not None and end is not None:
seqs = [
seq
Expand Down
10 changes: 10 additions & 0 deletions gffquant/db/models/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@
from .meta import Base


class AnnotationGroup(Base):
__tablename__ = "annotation_group"

id = Column(Integer, primary_key=True)
id16 = Column(String, index=True)
annotation_str = Column(String)
n_members = Column(Integer)
sha256 = Column(String)


class AnnotationString(Base):
__tablename__ = "annotationstring"

Expand Down
Loading