2525import re
2626import sqlite3
2727import sys
28+ from collections import Counter
2829from typing import Iterable , List
2930
3031from . import broad_splits , smart_sort
@@ -408,8 +409,8 @@ def redux(self, glstring: str, redux_type: VALID_REDUCTION_TYPES) -> str:
408409 )
409410
410411 # Handle MAC
411- if self ._config ["reduce_MAC" ] and self . is_mac ( glstring ):
412- if db . is_valid_mac_code ( self .db_connection , code ):
412+ if self ._config ["reduce_MAC" ] and code . isalpha ( ):
413+ if self .is_mac ( glstring ): # Make sure it's a valid MAC
413414 if HLA_regex .search (glstring ):
414415 # Remove HLA- prefix
415416 allele_name = glstring .split ("-" )[1 ]
@@ -436,12 +437,7 @@ def validate(self, glstring):
436437 :param glstring: GL String to validate
437438 :return: boolean indicating success
438439 """
439- try :
440- return self ._is_valid_gl (glstring )
441- except InvalidAlleleError as e :
442- raise InvalidTypingError (
443- f"{ glstring } is not valid GL String. \n { e .message } " , e
444- ) from None
440+ return self ._is_valid_gl (glstring )
445441
446442 def is_XX (self , glstring : str , loc_antigen : str = None , code : str = None ) -> bool :
447443 if loc_antigen is None or code is None :
@@ -484,12 +480,39 @@ def is_mac(self, allele: str) -> bool:
484480 :return: True if MAC
485481 """
486482 if ":" in allele :
487- code = allele .split (":" )[1 ]
488- try :
483+ allele_split = allele .split (":" )
484+ if len (allele_split ) == 2 : # MACs have only single :
485+ locus_antigen , code = allele_split
489486 if code .isalpha ():
490- return db .is_valid_mac_code (self .db_connection , code )
491- except sqlite3 .OperationalError as e :
492- print ("Error: " , e )
487+ try :
488+ alleles = db .mac_code_to_alleles (self .db_connection , code )
489+ if alleles :
490+ if any (map (lambda a : ":" in a , alleles )):
491+ # allele specific antigen codes have ':' in the MAC mapping
492+ # e.g. CFWRN -> 15:01/15:98/15:157/15:202/
493+ # 15:239/15:280/15:340/35:43/35:67/35:79/35:102/35:118/35:185/51:220
494+ # Extract the antigens from the mapped alleles
495+ antigen_groups = map (lambda a : a .split (":" )[0 ], alleles )
496+ # Rule 1: The 1st field with the most allele designations in the request is
497+ # the 1st field of the allele code designation
498+ # Rule 2: If there is a tie in the number of alleles designations sharing the 1st field,
499+ # the 1st field with the lowest numeric value is selected.
500+ antigen_counts = Counter (antigen_groups )
501+ # Create a table of antigen to it's counts
502+ # '15': 7
503+ # '35': 6
504+ # '51': 1
505+ # Valid antigen is the first most common one.
506+ # As it's presorted in db, also satisfies Rule 2.
507+ valid_antigen = antigen_counts .most_common (1 ).pop ()[0 ]
508+ # Get antigen value 15 from 'DRB1*15'
509+ provided_antigen = locus_antigen .split ("*" ).pop ()
510+ # The MAC is only valid if the given antigen satisfies the antigen matching Rule 1 and 2
511+ return provided_antigen == valid_antigen
512+ # Valid when antigen group codes
513+ return True
514+ except sqlite3 .OperationalError as e :
515+ print ("Error: " , e )
493516 return False
494517
495518 def is_v2 (self , allele : str ) -> bool :
@@ -719,8 +742,8 @@ def expand_mac(self, mac_code: str):
719742 :return: GL String of expanded alleles
720743 :rtype: str
721744 """
722- locus_antigen , code = mac_code . split ( ":" )
723- if db . is_valid_mac_code ( self . db_connection , code ):
745+ if self . is_mac ( mac_code ): # Validate MAC first
746+ locus_antigen , code = mac_code . split ( ":" )
724747 if HLA_regex .search (mac_code ):
725748 locus_antigen = locus_antigen .split ("-" )[1 ] # Remove HLA- prefix
726749 return "/" .join (
0 commit comments