patch-fixer 0.3.1__py3-none-any.whl → 0.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
patch_fixer/__init__.py CHANGED
@@ -1 +1,2 @@
1
- from .patch_fixer import fix_patch
1
+ from .patch_fixer import fix_patch
2
+ from .split import split_patch
@@ -204,7 +204,7 @@ def fix_patch(patch_lines, original, remove_binary=False):
204
204
  ) = capture_hunk(current_hunk, original_lines, offset, last_hunk, hunk_context)
205
205
  except MissingHunkError:
206
206
  raise NotImplementedError(f"Could not find hunk in {current_file}:"
207
- f"\n\n{"".join(current_hunk)}")
207
+ f"\n\n{''.join(current_hunk)}")
208
208
  fixed_lines.append(fixed_header)
209
209
  fixed_lines.extend(current_hunk)
210
210
  current_hunk = []
@@ -415,7 +415,7 @@ def fix_patch(patch_lines, original, remove_binary=False):
415
415
  ) = capture_hunk(current_hunk, original_lines, offset, last_hunk, hunk_context)
416
416
  except MissingHunkError:
417
417
  raise NotImplementedError(f"Could not find hunk in {current_file}:"
418
- f"\n\n{"".join(current_hunk)}")
418
+ f"\n\n{''.join(current_hunk)}")
419
419
  fixed_lines.append(fixed_header)
420
420
  fixed_lines.extend(current_hunk)
421
421
  current_hunk = []
@@ -437,7 +437,7 @@ def fix_patch(patch_lines, original, remove_binary=False):
437
437
  ) = capture_hunk(current_hunk, original_lines, offset, last_hunk, hunk_context)
438
438
  except MissingHunkError:
439
439
  raise NotImplementedError(f"Could not find hunk in {current_file}:"
440
- f"\n\n{"".join(current_hunk)}")
440
+ f"\n\n{''.join(current_hunk)}")
441
441
  fixed_lines.append(fixed_header)
442
442
  fixed_lines.extend(current_hunk)
443
443
 
patch_fixer/split.py ADDED
@@ -0,0 +1,119 @@
1
+ """
2
+ Idea:
3
+
4
+ 1. main function takes in:
5
+ a. patch file
6
+ b. list of files to split out
7
+ 2. reads patch file, splits based on file headers (assumed to be valid)
8
+ 3. for each file being patched:
9
+ a. if the file is in the list, send its hunks to output 1
10
+ b. otherwise send its hunks to output 2
11
+ c. hunks include all header lines so each output is a valid diff
12
+
13
+ Could share some functionality with refactored, modular version of fix_patch
14
+ """
15
+
16
+ import re
17
+ from typing import List, Tuple
18
+
19
+ from .patch_fixer import match_line, normalize_line, split_ab
20
+
21
+
22
+ def get_file_path_from_diff(line: str) -> str:
23
+ """Extract the file path from a diff line."""
24
+ match_groups, line_type = match_line(line)
25
+ if line_type != "DIFF_LINE":
26
+ raise ValueError(f"Expected DIFF_LINE but got {line_type}")
27
+
28
+ # get the 'a' path (source file)
29
+ a_path, _ = split_ab(match_groups)
30
+ return a_path
31
+
32
+
33
+ def split_patch(patch_lines: List[str], files_to_include: List[str]) -> Tuple[List[str], List[str]]:
34
+ """
35
+ Split a patch into two parts based on a list of files to include.
36
+
37
+ Parameters
38
+ ----------
39
+ patch_lines : List[str]
40
+ Lines of the patch file to split.
41
+ files_to_include : List[str]
42
+ List of file paths (relative, starting with ./) to include in the first output.
43
+ Files not in this list go to the second output.
44
+
45
+ Returns
46
+ -------
47
+ included_lines : List[str]
48
+ Lines for the patch containing only the included files.
49
+ excluded_lines : List[str]
50
+ Lines for the patch containing all other files.
51
+
52
+ Notes
53
+ -----
54
+ The function preserves all header information for each file's hunks
55
+ to ensure both output patches are valid. File paths are normalized
56
+ to start with './' for comparison purposes.
57
+
58
+ Raises
59
+ ------
60
+ ValueError
61
+ If the patch format is invalid or cannot be parsed.
62
+ """
63
+ if not patch_lines:
64
+ raise ValueError("Empty patch provided")
65
+
66
+ # normalize file paths to include
67
+ normalized_include = set()
68
+ for path in files_to_include:
69
+ if not path.startswith("./"):
70
+ path = f"./{path}"
71
+ normalized_include.add(path)
72
+
73
+ included_lines = []
74
+ excluded_lines = []
75
+ current_file_lines = []
76
+ current_file_path = None
77
+ in_file_block = False
78
+
79
+ for line in patch_lines:
80
+ match_groups, line_type = match_line(line)
81
+
82
+ if line_type == "DIFF_LINE":
83
+ # start of a new file block
84
+ if in_file_block and current_file_lines:
85
+ # output the previous file block
86
+ if current_file_path in normalized_include:
87
+ included_lines.extend(current_file_lines)
88
+ else:
89
+ excluded_lines.extend(current_file_lines)
90
+
91
+ # start collecting new file block
92
+ current_file_lines = [normalize_line(line)]
93
+ current_file_path = get_file_path_from_diff(line)
94
+ in_file_block = True
95
+
96
+ elif in_file_block:
97
+ # continue collecting lines for current file
98
+ current_file_lines.append(normalize_line(line))
99
+
100
+ else:
101
+ # lines before any diff (shouldn't happen in well-formed patches)
102
+ # add to both outputs to preserve any global headers
103
+ normalized = normalize_line(line)
104
+ included_lines.append(normalized)
105
+ excluded_lines.append(normalized)
106
+
107
+ # don't forget the last file block
108
+ if in_file_block and current_file_lines:
109
+ if current_file_path in normalized_include:
110
+ included_lines.extend(current_file_lines)
111
+ else:
112
+ excluded_lines.extend(current_file_lines)
113
+
114
+ # handle edge case where no files were split (no diff lines)
115
+ if not in_file_block:
116
+ # patch had no diff lines at all
117
+ return patch_lines, []
118
+
119
+ return included_lines, excluded_lines
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patch-fixer
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Fixes erroneous git apply patches to the best of its ability.
5
5
  Maintainer-email: Alex Mueller <amueller474@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1,8 @@
1
+ patch_fixer/__init__.py,sha256=n5DDMr4jbO3epK3ybBvjDyRddTWlWamN6ao5BC7xHFo,65
2
+ patch_fixer/patch_fixer.py,sha256=GAavb15H5cEoNFgGlO5hIY7EOF88VCsjHcLrfyGW4_0,20587
3
+ patch_fixer/split.py,sha256=l0rHM6-ZBuB9Iv6Ng6rxqZH5eKfvk2t87j__nDu67kM,3869
4
+ patch_fixer-0.3.2.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
5
+ patch_fixer-0.3.2.dist-info/METADATA,sha256=DWi_Bf1beGb5Q0RyGxyDRlmb9RYjCuUhYcvJF0TisY0,2828
6
+ patch_fixer-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ patch_fixer-0.3.2.dist-info/top_level.txt,sha256=yyp3KjFgExJsrFsS9ZBCnkhb05xg8hPYhB7ncdpTOv0,12
8
+ patch_fixer-0.3.2.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- patch_fixer/__init__.py,sha256=bSp2H7JW2kz1WrT0dqlg64kZpklKPp1FZlDhq2XJ2uU,34
2
- patch_fixer/patch_fixer.py,sha256=1Ny2NwVL4qStbVCrv6QE3b_8oPsFkPomJDLoAGUqNvI,20587
3
- patch_fixer-0.3.1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
4
- patch_fixer-0.3.1.dist-info/METADATA,sha256=iOhEx8d5WJV3X-mMu-0hAjQWXD-gBEPWKkiE-HnNyso,2828
5
- patch_fixer-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
- patch_fixer-0.3.1.dist-info/top_level.txt,sha256=yyp3KjFgExJsrFsS9ZBCnkhb05xg8hPYhB7ncdpTOv0,12
7
- patch_fixer-0.3.1.dist-info/RECORD,,