Skip to content

Commit

Permalink
Merge pull request #179 from pbashyal-nmdp/drbx_blender
Browse files Browse the repository at this point in the history
Support DRBX Blending
  • Loading branch information
mmaiers-nmdp authored Oct 1, 2022
2 parents 0952a16 + 6d013a2 commit e1cf309
Show file tree
Hide file tree
Showing 11 changed files with 358 additions and 10 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
PROJECT_NAME := $(shell basename `pwd`)
PACKAGE_NAME := pyard

.PHONY: clean clean-test clean-pyc clean-build docs help
.DEFAULT_GOAL := help
define BROWSER_PYSCRIPT
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ ard.redux_gl('B14', 'lg')
| `exon` | Reduce/Expand to exon level |
| `U2` | Reduce to 2 field unambiguous level |

## Perform DRB1 blending with DRB3, DRB4 and DRB5

```python
import pyard

pyard.dr_blender(drb1='HLA-DRB1*03:01+DRB1*04:01', drb3='DRB3*01:01', drb4='DRB4*01:03')
# >>> 'DRB3*01:01+DRB4*01:03'
```
# Command Line Tools

## Using `py-ard` from the command line
Expand Down
2 changes: 1 addition & 1 deletion api-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ openapi: 3.0.3
info:
title: ARD Reduction
description: Reduce to ARD Level
version: "0.8.0"
version: "0.8.1"
servers:
- url: 'http://localhost:8080'
tags:
Expand Down
3 changes: 2 additions & 1 deletion pyard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
# > http://www.opensource.org/licenses/lgpl-license.php
#
from .pyard import ARD
from .blender import blender as dr_blender

__author__ = """NMDP Bioinformatics"""
__version__ = "0.8.0"
__version__ = "0.8.1"
225 changes: 225 additions & 0 deletions pyard/blender.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# drbx blender


def blender(drb1, drb3="", drb4="", drb5=""):
try:
drb1_1, drb1_2 = drb1.split("+")
drb1_allele_1 = drb1_1.split("*")[1]
drb1_allele_2 = drb1_2.split("*")[1]
drb1_fam_1 = drb1_allele_1.split(":")[0]
drb1_fam_2 = drb1_allele_2.split(":")[0]
except Exception:
return ""
x1 = expdrbx(drb1_fam_1)
x2 = expdrbx(drb1_fam_2)
xx = "".join(sorted([x1, x2]))

if xx == "00":
if drb3 != "":
raise DRBXBlenderError("DRB3", "none")
if drb4 != "":
raise DRBXBlenderError("DRB4", "none")
if drb5 != "":
raise DRBXBlenderError("DRB5", "none")
return ""

# handle 03
if xx == "03":
if drb4 != "":
raise DRBXBlenderError("DRB4", "none")
if drb5 != "":
raise DRBXBlenderError("DRB5", "none")
if drb3 != "":
# if 2 copies
drb3_g = drb3.split("+")
if len(drb3_g) == 2:
# homozygous, return one copy
if drb3_g[1] == drb3_g[0]:
return drb3_g[0]
else:
raise DRBXBlenderError("DRB3 het", "hom")
else:
return drb3
return ""

# handle 04
if xx == "04":
if drb3 != "":
raise DRBXBlenderError("DRB3", "none")
if drb5 != "":
raise DRBXBlenderError("DRB5", "none")
if drb4 != "":
# if 2 copies
drb4_g = drb4.split("+")
if len(drb4_g) == 2:
# homozygous, return one copy
if drb4_g[1] == drb4_g[0]:
return drb4_g[0]
else:
raise DRBXBlenderError("DRB4 het", "hom")
else:
return drb4
return ""

# handle 05
if xx == "05":
if drb3 != "":
raise DRBXBlenderError("DRB3", "none")
if drb4 != "":
raise DRBXBlenderError("DRB4", "none")
if drb5 != "":
# if 2 copies
drb5_g = drb5.split("+")
if len(drb5_g) == 2:
# homozygous, return one copy
if drb5_g[1] == drb5_g[0]:
return drb5_g[0]
else:
raise DRBXBlenderError("DRB5 het", "hom")
else:
return drb5
return ""
# handle 33
if xx == "33":
if drb4 != "":
raise DRBXBlenderError("DRB4", "none")
if drb5 != "":
raise DRBXBlenderError("DRB5", "none")
if drb3 != "":
return drb3
return ""

# handle 44
if xx == "44":
if drb3 != "":
raise DRBXBlenderError("DRB3", "none")
if drb5 != "":
raise DRBXBlenderError("DRB5", "none")
if drb4 != "":
return drb4
return ""

# handle 55
if xx == "55":
if drb3 != "":
raise DRBXBlenderError("DRB3", "none")
if drb4 != "":
raise DRBXBlenderError("DRB4", "none")
if drb5 != "":
return drb5
return ""

# handle 34
if xx == "34":
if drb5 != "":
raise DRBXBlenderError("DRB5", "none")
retg = []

if drb3 != "":
# if 2 copies
drb3_g = drb3.split("+")
if len(drb3_g) == 2:
# homozygous, return one copy
if drb3_g[1] == drb3_g[0]:
retg.append(drb3_g[0])
else:
raise DRBXBlenderError("DRB3 het", "hom")
elif len(drb3_g) == 1:
retg.append(drb3_g[0])
if drb4 != "":
# if 2 copies
drb4_g = drb4.split("+")
if len(drb4_g) == 2:
# homozygous, return one copy
if drb4_g[1] == drb4_g[0]:
retg.append(drb4_g[0])
else:
raise DRBXBlenderError("DRB4 het", "hom")
elif len(drb4_g) == 1:
retg.append(drb4_g[0])

return "+".join(retg)

# handle 35
if xx == "35":
if drb4 != "":
raise DRBXBlenderError("DRB4", "none")
retg = []

if drb3 != "":
# if 2 copies
drb3_g = drb3.split("+")
if len(drb3_g) == 2:
# homozygous, return one copy
if drb3_g[1] == drb3_g[0]:
retg.append(drb3_g[0])
else:
raise DRBXBlenderError("DRB3 het", "hom")
elif len(drb3_g) == 1:
retg.append(drb3_g[0])
if drb5 != "":
# if 2 copies
drb5_g = drb5.split("+")
if len(drb5_g) == 2:
# homozygous, return one copy
if drb5_g[1] == drb5_g[0]:
retg.append(drb5_g[0])
else:
raise DRBXBlenderError("DRB5 het", "hom")
elif len(drb5_g) == 1:
retg.append(drb5_g[0])

return "+".join(retg)

# handle 45
if xx == "45":
if drb3 != "":
raise DRBXBlenderError("DRB3", "none")
retg = []

if drb4 != "":
# if 2 copies
drb4_g = drb4.split("+")
if len(drb4_g) == 2:
# homozygous, return one copy
if drb4_g[1] == drb4_g[0]:
retg.append(drb4_g[0])
else:
raise DRBXBlenderError("DRB4 het", "hom")
elif len(drb4_g) == 1:
retg.append(drb4_g[0])
if drb5 != "":
# if 2 copies
drb5_g = drb5.split("+")
if len(drb5_g) == 2:
# homozygous, return one copy
if drb5_g[1] == drb5_g[0]:
retg.append(drb5_g[0])
else:
raise DRBXBlenderError("DRB5 het", "hom")
elif len(drb5_g) == 1:
retg.append(drb5_g[0])

return "+".join(retg)

print("blender fail", xx, drb1_fam_1, drb1_fam_2)
return ""


def expdrbx(drb1_fam):
if drb1_fam in ["03", "05", "06", "11", "12", "13", "14"]:
return "3"
if drb1_fam in ["04", "07", "09"]:
return "4"
if drb1_fam in ["02", "15", "16"]:
return "5"
return "0"


class DRBXBlenderError(Exception):
def __init__(self, found, expected):
self.found = found
self.expected = expected

def __str__(self):
return f"{self.found} where {self.expected} expected"
2 changes: 1 addition & 1 deletion pyard/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ def similar_alleles(connection: sqlite3.Connection, allele_name: str) -> Set[str
:param allele_name: Allele name to use as a prefix to find similar alleles
:return: list of similar alleles
"""
query = f"SELECT allele FROM alleles WHERE allele LIKE ?"
query = "SELECT allele FROM alleles WHERE allele LIKE ?"
cursor = connection.execute(query, (f"{allele_name}%",))
result = cursor.fetchall()
# fetchall() returns a list of tuples of results
Expand Down
4 changes: 0 additions & 4 deletions pyard/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,3 @@ def get_P_name(a: str) -> str:
if last_char in PandG_chars + expression_chars:
a = a[:-1]
return ":".join(a.split(":")[0:2]) + "P"


def number_of_fields(allele: str) -> int:
return len(allele.split(":"))
10 changes: 8 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.8.0
current_version = 0.8.1
commit = True
tag = True

Expand All @@ -19,4 +19,10 @@ replace = version: "{new_version}"
universal = 1

[flake8]
exclude = docs
exclude =
venv,
.git,
__pycache__,
build,
dist,
docs
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

setup(
name="py-ard",
version="0.8.0",
version="0.8.1",
description="ARD reduction for HLA with Python",
long_description=readme + "\n\n" + history,
long_description_content_type="text/markdown",
Expand Down
56 changes: 56 additions & 0 deletions tests/features/drbx_blender.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Feature: DRB1 blends with DRB3, DRB4, DRB5

Scenario Outline: DRB1 blends

Given a subject has <DRB1_SLUG> DRB1 SLUG
And a subject has <DRB3> DRB3 allele
And a subject has <DRB4> DRB4 allele
And a subject has <DRB5> DRB5 allele
When I blend the DRBX alleles with DRB1 allele
Then it should blend as <DRBX_BLEND>

Examples: All blends with DRB1
| DRB1_SLUG | DRB3 | DRB4 | DRB5 | DRBX_BLEND |
| HLA-DRB1*03:01+DRB1*04:01 | DRB3*01:01 | DRB4*01:03 | no | DRB3*01:01+DRB4*01:03 |
| HLA-DRB1*03:01+DRB1*04:01 | DRB3*01:01 | DRB4*01:03 | no | DRB3*01:01+DRB4*01:03 |
| HLA-DRB1*03:01+DRB1*04:01 | no | DRB4*01:03 | no | DRB4*01:03 |
| HLA-DRB1*03:01+DRB1*04:01 | DRB3*01:03 | no | no | DRB3*01:03 |
| HLA-DRB1*01:01+DRB1*08:01 | no | no | no | nothing |
| HLA-DRB1*01:01+DRB1*03:01 | no | no | no | nothing |
| HLA-DRB1*01:01+DRB1*04:01 | no | no | no | nothing |
| HLA-DRB1*03:01+DRB1*13:01 | DRB3*01:01 | no | no | DRB3*01:01 |
| HLA-DRB1*15:01+DRB1*16:01 | no | no | DRB5*01:03 | DRB5*01:03 |

Scenario Outline: DRB1 doesn't blend

Given a subject has <DRB1_SLUG> DRB1 SLUG
And a subject has <DRB3> DRB3 allele
And a subject has <DRB4> DRB4 allele
And a subject has <DRB5> DRB5 allele
When I blend the DRBX alleles with DRB1 allele, it shouldn't blend
Then <Expected> was expected, but found <Found>

Examples: Doesn't blend with DRB1
| DRB1_SLUG | DRB3 | DRB4 | DRB5 | Expected | Found |
| HLA-DRB1*03:01+DRB1*04:01 | DRB3*01:01 | DRB4*01:03 | DRB5*01:05 | none | DRB5 |
| HLA-DRB1*03:01+DRB1*04:01 | DRB3*01:01+DRB3*02:01 | DRB4*01:03 | no | hom | DRB3 het |
| HLA-DRB1*03:01+DRB1*04:01 | DRB3*01:01 | DRB4*01:03+DRB4*01:05 | no | hom | DRB4 het |
| HLA-DRB1*01:01+DRB1*08:01 | DRB3*01:01 | no | no | none | DRB3 |
| HLA-DRB1*01:01+DRB1*08:01 | no | DRB4*01:01 | no | none | DRB4 |
| HLA-DRB1*01:01+DRB1*08:01 | no | no | DRB5*01:01 | none | DRB5 |
| HLA-DRB1*01:01+DRB1*03:01 | DRB3*01:01 | DRB4*01:03 | no | none | DRB4 |
| HLA-DRB1*01:01+DRB1*03:01 | DRB3*01:01 | no | DRB5*01:03 | none | DRB5 |
| HLA-DRB1*01:01+DRB1*04:01 | no | DRB4*01:01+DRB4*01:03 | no | hom | DRB4 het |
| HLA-DRB1*01:01+DRB1*04:01 | DRB3*01:01 | DRB4*01:03 | no | none | DRB3 |
| HLA-DRB1*01:01+DRB1*04:01 | no | DRB4*01:01 | DRB5*01:03 | none | DRB5 |
| HLA-DRB1*03:01+DRB1*13:01 | DRB3*01:01 | DRB4*01:03 | no | none | DRB4 |
| HLA-DRB1*03:01+DRB1*13:01 | DRB3*01:01 | no | DRB5*01:03 | none | DRB5 |
| HLA-DRB1*03:01+DRB1*13:01 | no | DRB4*01:01 | DRB5*01:03 | none | DRB4 |
| HLA-DRB1*04:01+DRB1*09:01 | DRB3*01:01 | no | no | none | DRB3 |
| HLA-DRB1*04:01+DRB1*09:01 | DRB3*01:01 | DRB4*01:03 | no | none | DRB3 |
| HLA-DRB1*04:01+DRB1*09:01 | DRB3*01:01 | no | DRB5*01:03 | none | DRB3 |
| HLA-DRB1*15:01+DRB1*16:01 | no | DRB4*01:01 | DRB5*01:03 | none | DRB4 |
| HLA-DRB1*15:01+DRB1*16:01 | DRB3*01:01 | no | no | none | DRB3 |
| HLA-DRB1*15:01+DRB1*16:01 | DRB3*01:01 | DRB4*01:03 | no | none | DRB3 |
| HLA-DRB1*15:01+DRB1*16:01 | DRB3*01:01 | no | DRB5*01:03 | none | DRB3 |
| HLA-DRB1*15:01+DRB1*16:01 | no | DRB4*01:01 | DRB5*01:03 | none | DRB4 |
Loading

0 comments on commit e1cf309

Please sign in to comment.