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

Align 1247 with latest staging code #616

Merged
merged 3 commits into from
Jul 10, 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
75 changes: 55 additions & 20 deletions viewer/target_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -1661,24 +1661,6 @@ def process_bundle(self):
canon_sites=canon_sites_by_conf_sites,
xtalforms=xtalform_objects,
)
# enumerate xtalform_sites. a bit trickier than others because
# requires alphabetic enumeration
last_xtsite = (
XtalformSite.objects.filter(
pk__in=[
k.instance.pk
for k in xtalform_sites_objects.values() # pylint: disable=no-member
]
)
.order_by("-xtalform_site_num")[0]
.xtalform_site_num
)

xtnum = alphanumerator(start_from=last_xtsite)
for val in xtalform_sites_objects.values(): # pylint: disable=no-member
if not val.instance.xtalform_site_num:
val.instance.xtalform_site_num = next(xtnum)
val.instance.save()

# now can update CanonSite with ref_conf_site
# also, fill the canon_site_num field
Expand Down Expand Up @@ -1880,13 +1862,66 @@ def process_bundle(self):

logger.debug("xtalform objects tagged")

# enumerate xtalform_sites. a bit trickier than others because
# requires alphabetic enumeration starting from the letter of
# the chain and following from there

# sort the dictionary
# fmt: off
xtls_sort_qs = XtalformSite.objects.filter(
pk__in=[k.instance.pk for k in xtalform_sites_objects.values() ], # pylint: disable=no-member
).annotate(
obvs=Count("canon_site__canonsiteconf__siteobservation", default=0),
).order_by("-obvs", "xtalform_site_id")
# ordering by xtalform_site_id is not strictly necessary, but
# makes the sorting consistent

# fmt: on

_xtalform_sites_objects = {}
for xtl in xtls_sort_qs:
key = f"{xtl.xtalform_site_id}/{xtl.version}"
_xtalform_sites_objects[key] = xtalform_sites_objects[
key
] # pylint: disable=no-member

if self.version_number == 1:
# first upload, use the chain letter
xtnum = alphanumerator(
start_from=xtls_sort_qs[0].lig_chain.lower(), drop_first=False
)
else:
# subsequent upload, just use the latest letter as starting point
# fmt: off
last_xtsite = XtalformSite.objects.filter(
pk__in=[
k.instance.pk
for k in _xtalform_sites_objects.values() # pylint: disable=no-member
]
).order_by(
"-xtalform_site_num"
)[0].xtalform_site_num
# fmt: on
xtnum = alphanumerator(start_from=last_xtsite)

# this should be rare, as Frank said, all crystal-related
# issues should be resolved by the time of the first
# upload. In fact, I'll mark this momentous occasion here:
logger.warning("New XtalformSite objects added in subsequent uploads")

for val in _xtalform_sites_objects.values(): # pylint: disable=no-member
if not val.instance.xtalform_site_num:
val.instance.xtalform_site_num = next(xtnum)
val.instance.save()

cat_xtalsite = TagCategory.objects.get(category="CrystalformSites")
for val in xtalform_sites_objects.values(): # pylint: disable=no-member
for val in _xtalform_sites_objects.values(): # pylint: disable=no-member
prefix = (
f"F{val.instance.xtalform.xtalform_num}"
+ f"{val.instance.xtalform_site_num}"
)
tag = f"{val.instance.xtalform.name} - {val.instance.xtalform_site_id}"
# tag = f"{val.instance.xtalform.name} - {val.instance.xtalform_site_id}"
tag = val.instance.xtalform_site_id
so_list = [
site_observation_objects[k].instance for k in val.index_data["residues"]
]
Expand Down
18 changes: 14 additions & 4 deletions viewer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,17 @@ def restore_curated_tags(filename: str) -> None:
logger.error(exc)


def alphanumerator(start_from: str = "") -> Generator[str, None, None]:
"""Return alphabetic generator (A, B .. AA, AB...) starting from a specified point."""
def alphanumerator(
start_from: str = "", drop_first: bool = True
) -> Generator[str, None, None]:
"""Return alphabetic generator (A, B .. AA, AB...) starting from a specified point.

drop_first - as per workflow, usually it's given the last letter
of previous sequence so the the next in the pipeline should be
start_from + 1. drop_first = False indicates this is not necessary
and start_from will be the first the iterator produces

"""

# since product requries finite maximum return string length set
# to 10 characters. that should be enough for fragalysis (and to
Expand All @@ -426,7 +435,8 @@ def alphanumerator(start_from: str = "") -> Generator[str, None, None]:
if start_from is not None and start_from != '':
start_from = start_from.lower()
generator = itertools.dropwhile(lambda x: x != start_from, generator) # type: ignore[assignment]
# and drop one more, then it starts from after the start from as it should
_ = next(generator)
if drop_first:
# drop one more, then it starts from after the start from as it should
_ = next(generator)

return generator