@@ -12,6 +12,10 @@ def parse_patch_blocks(text: str, multiple: bool = True) -> Union[str, List[str]
1212 """
1313 Extract content between *** Begin Patch and *** End Patch markers (inclusive),
1414 ensuring that both markers are at zero indentation (start of line, no leading spaces).
15+
16+ If only one identifier is present:
17+ - If only "Begin Patch" exists: returns from Begin Patch to end of text
18+ - If only "End Patch" exists: returns from start of text to End Patch
1519
1620 Args:
1721 text: Full input text containing one or more patch blocks.
@@ -21,13 +25,72 @@ def parse_patch_blocks(text: str, multiple: bool = True) -> Union[str, List[str]
2125 A string (single patch), list of strings (multiple patches), or None if not found.
2226 """
2327
24- pattern = r"(?m)^(\*\*\* Begin Patch[\s\S]*?^\*\*\* End Patch)$"
25- matches = re .findall (pattern , text )
26-
27- if not matches :
28+ # First, try to find complete blocks (both Begin and End markers)
29+ complete_pattern = r"(?m)^(\*\*\* Begin Patch[\s\S]*?^\*\*\* End Patch)$"
30+ complete_matches = re .findall (complete_pattern , text )
31+
32+ # If we found complete matches, return them (preserving original behavior)
33+ if complete_matches :
34+ return complete_matches if multiple else complete_matches [0 ]
35+
36+ # If no complete matches, look for partial identifiers
37+ begin_pattern = r"(?m)^(\*\*\* Begin Patch).*$"
38+ end_pattern = r"(?m)^(\*\*\* End Patch).*$"
39+
40+ begin_matches = list (re .finditer (begin_pattern , text ))
41+ end_matches = list (re .finditer (end_pattern , text ))
42+
43+ partial_matches = []
44+
45+ # Handle cases with only Begin markers (from Begin to end of text)
46+ if begin_matches and not end_matches :
47+ for match in begin_matches :
48+ start_pos = match .start ()
49+ partial_content = text [start_pos :]
50+ partial_matches .append (partial_content )
51+
52+ # Handle cases with only End markers (from start of text to End)
53+ elif end_matches and not begin_matches :
54+ for match in end_matches :
55+ end_pos = match .end ()
56+ partial_content = text [:end_pos ]
57+ partial_matches .append (partial_content )
58+
59+ # Handle mixed cases (some begins without ends, some ends without begins)
60+ elif begin_matches or end_matches :
61+ # Get all Begin positions
62+ begin_positions = [m .start () for m in begin_matches ]
63+ end_positions = [m .end () for m in end_matches ]
64+
65+ # For each Begin, try to find corresponding End
66+ for begin_pos in begin_positions :
67+ corresponding_end = None
68+ for end_pos in end_positions :
69+ if end_pos > begin_pos :
70+ corresponding_end = end_pos
71+ break
72+
73+ if corresponding_end :
74+ # Complete pair found
75+ partial_content = text [begin_pos :corresponding_end ]
76+ else :
77+ # Begin without End - go to end of text
78+ partial_content = text [begin_pos :]
79+
80+ partial_matches .append (partial_content )
81+
82+ # Handle orphaned End markers (Ends that don't have corresponding Begins)
83+ for end_pos in end_positions :
84+ has_corresponding_begin = any (begin_pos < end_pos for begin_pos in begin_positions )
85+ if not has_corresponding_begin :
86+ # End without Begin - from start of text
87+ partial_content = text [:end_pos ]
88+ partial_matches .append (partial_content )
89+
90+ if not partial_matches :
2891 return None
29-
30- return matches if multiple else matches [0 ]
92+
93+ return partial_matches if multiple else partial_matches [0 ]
3194
3295# --------------------------------------------------------------------------- #
3396# User-facing API
@@ -144,7 +207,9 @@ def process_patch(
144207
145208 # Normalize line endings before processing
146209 patches_text = open_fn (patch_path )
147- patches = parse_patch_blocks (patches_text ) or ["" ]
210+ print (f"{ patches_text = } " )
211+ patches = parse_patch_blocks (patches_text )#or [""]
212+ print (f"{ patches = } " )
148213
149214 all_paths_needed = []
150215 for text in patches :
0 commit comments