Skip to content

Commit 26a7dd0

Browse files
committed
Document modules
- Document all the modules in loader/reducers and handlers packages
1 parent 6b41868 commit 26a7dd0

22 files changed

+1238
-113
lines changed

pyard/ard_refactored.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
)
1717
from .exceptions import InvalidMACError, InvalidTypingError
1818
from .handlers import (
19-
AlleleReducer,
20-
GLStringProcessor,
19+
AlleleHandler,
20+
GLStringHandler,
2121
MACHandler,
2222
SerologyHandler,
2323
V2Handler,
@@ -118,8 +118,8 @@ def _initialize_database(self, imgt_version: str, load_mac: bool):
118118

119119
def _initialize_handlers(self):
120120
"""Initialize all specialized handlers"""
121-
self.allele_reducer = AlleleReducer(self)
122-
self.gl_processor = GLStringProcessor(self)
121+
self.allele_reducer = AlleleHandler(self)
122+
self.gl_processor = GLStringHandler(self)
123123
self.mac_handler = MACHandler(self)
124124
self.serology_handler = SerologyHandler(self)
125125
self.v2_handler = V2Handler(self)

pyard/handlers/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# -*- coding: utf-8 -*-
22

3-
from .allele_reducer import AlleleReducer
4-
from .gl_string_processor import GLStringProcessor
3+
from .allele_handler import AlleleHandler
4+
from .gl_string_processor import GLStringHandler
55
from .mac_handler import MACHandler
66
from .serology_handler import SerologyHandler
77
from .shortnull_handler import ShortNullHandler
88
from .v2_handler import V2Handler
99
from .xx_handler import XXHandler
1010

1111
__all__ = [
12-
"AlleleReducer",
13-
"GLStringProcessor",
12+
"AlleleHandler",
13+
"GLStringHandler",
1414
"MACHandler",
1515
"SerologyHandler",
1616
"V2Handler",

pyard/handlers/allele_handler.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from typing import TYPE_CHECKING
4+
5+
from ..constants import VALID_REDUCTION_TYPE
6+
from ..reducers.reducer_factory import StrategyFactory
7+
8+
if TYPE_CHECKING:
9+
from ..ard import ARD
10+
11+
12+
class AlleleHandler:
13+
"""Handles core allele reduction logic using Strategy Pattern
14+
15+
This class serves as the main handler for reducing HLA alleles to different
16+
resolution levels (G group, P group, lg, etc.). It uses the Strategy Pattern
17+
to delegate the actual reduction logic to specific strategy classes.
18+
"""
19+
20+
def __init__(self, ard_instance: "ARD"):
21+
"""Initialize the AlleleReducer with an ARD instance
22+
23+
Args:
24+
ard_instance: The main ARD object containing database connections
25+
and configuration settings
26+
"""
27+
self.ard = ard_instance
28+
# Factory that creates appropriate reduction strategy based on redux_type
29+
self.strategy_factory = StrategyFactory(ard_instance)
30+
31+
def reduce_allele(
32+
self, allele: str, redux_type: VALID_REDUCTION_TYPE, re_ping=True
33+
) -> str:
34+
"""Core allele reduction logic using Strategy Pattern
35+
36+
Reduces an HLA allele to the specified resolution level by delegating
37+
to the appropriate reduction strategy.
38+
39+
Args:
40+
allele: HLA allele string to reduce (e.g., "A*01:01:01:01")
41+
redux_type: Type of reduction to perform (G, P, lg, lgx, W, exon, U2, S)
42+
re_ping: Whether to re-ping for P groups when G groups are unavailable
43+
44+
Returns:
45+
Reduced allele string according to the specified redux_type
46+
"""
47+
# Get the appropriate reduction strategy for the redux_type
48+
strategy = self.strategy_factory.get_strategy(redux_type)
49+
# Execute the reduction using the selected strategy
50+
return strategy.reduce(allele)
51+
52+
def add_lg_suffix(self, redux_allele):
53+
"""Add lg suffix to reduced allele - kept for backward compatibility
54+
55+
Appends the appropriate suffix ('g' or 'ARS') to reduced alleles.
56+
Handles both single alleles and ambiguous allele lists separated by '/'.
57+
58+
Args:
59+
redux_allele: Reduced allele string, may contain multiple alleles
60+
separated by '/'
61+
62+
Returns:
63+
Allele string with appropriate suffix added to each allele
64+
"""
65+
# Handle ambiguous alleles (multiple alleles separated by '/')
66+
if "/" in redux_allele:
67+
return "/".join(
68+
[self.add_lg_suffix(allele) for allele in redux_allele.split("/")]
69+
)
70+
# Use 'ARS' suffix if configured, otherwise use 'g' suffix
71+
if self.ard._config["ARS_as_lg"]:
72+
return redux_allele + "ARS"
73+
return redux_allele + "g"

pyard/handlers/allele_reducer.py

Lines changed: 0 additions & 34 deletions
This file was deleted.

pyard/handlers/gl_string_processor.py

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,54 +10,104 @@
1010
from ..ard import ARD
1111

1212

13-
class GLStringProcessor:
14-
"""Handles GL string parsing, validation and processing"""
13+
class GLStringHandler:
14+
"""Handles GL string parsing, validation and processing
15+
16+
GL (Genotype List) strings represent HLA typing data using standardized
17+
delimiters to express ambiguity and relationships between alleles.
18+
This class processes these complex strings by parsing delimiters and
19+
applying reductions to individual components.
20+
"""
1521

1622
def __init__(self, ard_instance: "ARD"):
23+
"""Initialize the GLStringHandler with an ARD instance
24+
25+
Args:
26+
ard_instance: The main ARD object for database access and configuration
27+
"""
1728
self.ard = ard_instance
1829

1930
def process_gl_string(
2031
self, glstring: str, redux_type: VALID_REDUCTION_TYPE = "lgx"
2132
) -> str:
22-
"""Main GL string processing logic extracted from redux method"""
33+
"""Main GL string processing logic extracted from redux method
34+
35+
Processes GL strings by parsing delimiters in order of precedence
36+
and applying reductions to individual components. GL string delimiters:
37+
^ = unphased genotype list
38+
| = phased genotype list
39+
+ = allele list (multiple alleles at same locus)
40+
~ = possible allele list
41+
/ = ambiguous allele list
42+
43+
Args:
44+
glstring: GL string to process (e.g., "A*01:01+A*02:01^B*07:02")
45+
redux_type: Type of reduction to apply to each component
46+
47+
Returns:
48+
Processed GL string with reductions applied
49+
"""
2350
validate_reduction_type(redux_type)
2451

52+
# Validate GL string structure if strict mode is enabled
2553
if self.ard._config["strict"]:
2654
self.validate_gl_string(glstring)
2755

28-
# Handle GL string delimiters
56+
# Handle GL string delimiters in order of precedence
57+
# Unphased genotype list (highest precedence)
2958
if "^" in glstring:
3059
return self._sorted_unique_gl(
3160
[self.ard.redux(a, redux_type) for a in glstring.split("^")], "^"
3261
)
3362

63+
# Phased genotype list
3464
if "|" in glstring:
3565
return self._sorted_unique_gl(
3666
[self.ard.redux(a, redux_type) for a in glstring.split("|")], "|"
3767
)
3868

69+
# Allele list (multiple alleles at same locus)
3970
if "+" in glstring:
4071
return self._sorted_unique_gl(
4172
[self.ard.redux(a, redux_type) for a in glstring.split("+")], "+"
4273
)
4374

75+
# Possible allele list
4476
if "~" in glstring:
4577
return self._sorted_unique_gl(
4678
[self.ard.redux(a, redux_type) for a in glstring.split("~")], "~"
4779
)
4880

81+
# Ambiguous allele list (lowest precedence)
4982
if "/" in glstring:
5083
return self._sorted_unique_gl(
5184
[self.ard.redux(a, redux_type) for a in glstring.split("/")], "/"
5285
)
5386

87+
# Single allele - return as-is for further processing
5488
return glstring
5589

5690
def _sorted_unique_gl(self, gls: List[str], delim: str) -> str:
57-
"""Make a list of sorted unique GL Strings separated by delim"""
91+
"""Make a list of sorted unique GL Strings separated by delim
92+
93+
Creates a sorted, deduplicated list of GL string components.
94+
Different delimiters have different sorting behaviors:
95+
- '~' preserves original order (no sorting/deduplication)
96+
- '+' sorts but keeps structure intact
97+
- Others flatten, deduplicate, and sort
98+
99+
Args:
100+
gls: List of GL string components to process
101+
delim: Delimiter to use for joining results
102+
103+
Returns:
104+
Sorted and deduplicated GL string components joined by delimiter
105+
"""
106+
# Possible allele list (~) preserves original order
58107
if delim == "~":
59108
return delim.join(gls)
60109

110+
# Allele list (+) sorts but maintains structure
61111
if delim == "+":
62112
non_empty_gls = filter(lambda s: s != "", gls)
63113
return delim.join(
@@ -71,6 +121,7 @@ def _sorted_unique_gl(self, gls: List[str], delim: str) -> str:
71121
)
72122
)
73123

124+
# Other delimiters: flatten, deduplicate, and sort
74125
all_gls = []
75126
for gl in gls:
76127
all_gls += gl.split(delim)
@@ -87,7 +138,22 @@ def _sorted_unique_gl(self, gls: List[str], delim: str) -> str:
87138
)
88139

89140
def validate_gl_string(self, glstring: str) -> bool:
90-
"""Validate GL string structure and components"""
141+
"""Validate GL string structure and components
142+
143+
Recursively validates GL string by parsing delimiters and checking
144+
that all leaf components (individual alleles) are valid according
145+
to the ARD database.
146+
147+
Args:
148+
glstring: GL string to validate
149+
150+
Returns:
151+
True if all components are valid
152+
153+
Raises:
154+
InvalidAlleleError: If any component allele is invalid
155+
"""
156+
# Recursively validate components separated by each delimiter type
91157
if "^" in glstring:
92158
return all(map(self.validate_gl_string, glstring.split("^")))
93159
if "|" in glstring:
@@ -99,7 +165,7 @@ def validate_gl_string(self, glstring: str) -> bool:
99165
if "/" in glstring:
100166
return all(map(self.validate_gl_string, glstring.split("/")))
101167

102-
# what falls through here is an allele
168+
# Base case: validate individual allele against database
103169
is_valid_allele = self.ard._is_valid(glstring)
104170
if not is_valid_allele:
105171
from ..exceptions import InvalidAlleleError

0 commit comments

Comments
 (0)