### Install the library Source: https://github.com/cscorley/whatthepatch/blob/main/README.rst Use pip to install the package from PyPI. ```bash $ pip install whatthepatch ``` -------------------------------- ### Example patch file content Source: https://github.com/cscorley/whatthepatch/blob/main/README.rst A sample unified diff file content used for demonstration. ```diff --- lao 2012-12-26 23:16:54.000000000 -0600 +++ tzu 2012-12-26 23:16:50.000000000 -0600 @@ -1,7 +1,6 @@ --The Way that can be told of is not the eternal Way; --The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; --The Named is the mother of all things. ++The named is the mother of all things. ++ Therefore let there always be non-being, so we may see their subtlety, And let there always be being, @@ -9,3 +8,6 @@ The two are the same, But after they are produced, they have different names. ++They both may be called deep and profound. ++Deeper and more profound, ++The door of all subtleties! ``` -------------------------------- ### Apply Diff with whatthepatch.apply_diff Source: https://context7.com/cscorley/whatthepatch/llms.txt Applies a parsed diff to original source text, returning the modified content as a list of lines. This example demonstrates applying a unified diff to a multi-line string. ```python import whatthepatch # Original source text original = """The Way that can be told of is not the eternal Way; The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; The Named is the mother of all things. Therefore let there always be non-being, so we may see their subtlety, And let there always be being, so we may see their outcome. The two are the same, But after they are produced, they have different names.""" # Unified diff to apply patch_text = """--- lao\t2013-01-05 16:56:19.000000000 -0600 +++ tzu\t2013-01-05 16:56:35.000000000 -0600 @@ -1,7 +1,6 @@ -The Way that can be told of is not the eternal Way; -The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; -The Named is the mother of all things. +The named is the mother of all things. + Therefore let there always be non-being, so we may see their subtlety, And let there always be being, @@ -9,3 +8,6 @@ The two are the same, But after they are produced, they have different names. +They both may be called deep and profound. +Deeper and more profound, +The door of all subtleties!""" # Parse and apply the diff diff = next(whatthepatch.parse_patch(patch_text)) result = whatthepatch.apply_diff(diff, original) # Result is a list of lines print("\n".join(result)) # Output: # The Nameless is the origin of Heaven and Earth; # The named is the mother of all things. # # Therefore let there always be non-being, # ... # They both may be called deep and profound. # Deeper and more profound, # The door of all subtleties! ``` -------------------------------- ### Apply and Reverse Patches Source: https://context7.com/cscorley/whatthepatch/llms.txt Demonstrates applying a patch and reversing it to recover the original text. ```python modified_text = """The Nameless is the origin of Heaven and Earth; The named is the mother of all things. Therefore let there always be non-being, so we may see their subtlety, And let there always be being, so we may see their outcome. The two are the same, But after they are produced, they have different names. They both may be called deep and profound. Deeper and more profound, The door of all subtleties!""" patch_text = """--- lao 2013-01-05 16:56:19.000000000 -0600 +++ tzu 2013-01-05 16:56:35.000000000 -0600 @@ -1,7 +1,6 @@ -The Way that can be told of is not the eternal Way; -The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; -The Named is the mother of all things. +The named is the mother of all things. + Therefore let there always be non-being, """ # Parse the diff diff = next(whatthepatch.parse_patch(patch_text)) # Apply in reverse to get original text back original = whatthepatch.apply_diff(diff, modified_text, reverse=True) print(original[0]) # Output: The Way that can be told of is not the eternal Way; print(original[1]) # Output: The name that can be named is not the eternal name. ``` -------------------------------- ### Apply a patch Source: https://github.com/cscorley/whatthepatch/blob/main/README.rst Initial step for applying a patch by importing the library. ```python >>> import whatthepatch ``` -------------------------------- ### Use External Patch Utility Source: https://context7.com/cscorley/whatthepatch/llms.txt Delegates patch application to the system's native patch command. ```python import whatthepatch from whatthepatch.exceptions import SubprocessException original = """Line 1 Line 2 Line 3""" patch_text = """--- file.txt +++ file.txt @@ -1,3 +1,3 @@ Line 1 -Line 2 +Line 2 Modified Line 3 """ diff = next(whatthepatch.parse_patch(patch_text)) try: # use_patch=True delegates to system 'patch' command # Returns tuple: (result_lines, rejected_lines) result, rejected = whatthepatch.apply_diff(diff, original, use_patch=True) print("\n".join(result)) if rejected: print(f"Rejected hunks: {rejected}") except SubprocessException as e: print(f"Patch command failed with code {e.code}: {e}") ``` -------------------------------- ### Reverse Patching with apply_diff Source: https://context7.com/cscorley/whatthepatch/llms.txt Demonstrates how to apply a diff in reverse to undo changes, effectively reverting modified text back to its original state. This is achieved by setting the `reverse` parameter to `True` in the `apply_diff` function. ```python import whatthepatch ``` -------------------------------- ### Apply diff using system patch Source: https://github.com/cscorley/whatthepatch/blob/main/README.rst Uses the system's patch utility to apply the diff if the default application method is insufficient. ```python apply_diff(diff, lao, use_patch=True) ``` -------------------------------- ### Parse and apply a diff Source: https://github.com/cscorley/whatthepatch/blob/main/README.rst Reads a diff file and a target file, parses the diff, and applies it to the target text. ```python >>> with open('tests/casefiles/diff-default.diff') as f: ... text = f.read() ... >>> with open('tests/casefiles/lao') as f: ... lao = f.read() ... >>> diff = [x for x in whatthepatch.parse_patch(text)] >>> diff = diff[0] >>> tzu = whatthepatch.apply_diff(diff, lao) >>> tzu # doctest: +NORMALIZE_WHITESPACE ['The Nameless is the origin of Heaven and Earth;', 'The named is the mother of all things.', '', 'Therefore let there always be non-being,', ' so we may see their subtlety,', 'And let there always be being,', ' so we may see their outcome.', 'The two are the same,', 'But after they are produced,', ' they have different names.', 'They both may be called deep and profound.', 'Deeper and more profound,', 'The door of all subtleties!'] ``` -------------------------------- ### Handle Patch Exceptions Source: https://context7.com/cscorley/whatthepatch/llms.txt Demonstrates catching HunkApplyException when patch context does not match the source. ```python import whatthepatch from whatthepatch.exceptions import HunkApplyException, ParseException # Source text that doesn't match the patch context wrong_source = """This is completely different text. It has nothing to do with the patch. The patch will fail to apply.""" patch_text = """--- original.txt +++ modified.txt @@ -1,3 +1,3 @@ First line of content -Second line to change +Second line changed Third line stays same """ diff = next(whatthepatch.parse_patch(patch_text)) try: result = whatthepatch.apply_diff(diff, wrong_source) except HunkApplyException as e: print(f"Failed to apply patch: {e}") print(f"Problem in hunk: {e.hunk}") # Output: Failed to apply patch: context line 1, "First line of content" # does not match "This is completely different text.", in hunk #0 # Output: Problem in hunk: 0 ``` -------------------------------- ### Parse Unified Diff with whatthepatch.parse_patch Source: https://context7.com/cscorley/whatthepatch/llms.txt Parses a unified diff from a string and iterates through the changes. Access header information and individual line changes. ```python import whatthepatch # Parse a unified diff from a string patch_text = """--- old_file.py\t2024-01-01 12:00:00.000000000 -0500 +++ new_file.py\t2024-01-02 12:00:00.000000000 -0500 @@ -1,4 +1,5 @@ def hello(): - print(\"Hello\") + print(\"Hello, World!\") + return True hello () """ for diff in whatthepatch.parse_patch(patch_text): # Access header information print(f"Old file: {diff.header.old_path}") # Output: Old file: old_file.py print(f"New file: {diff.header.new_path}") # Output: New file: new_file.py # Iterate through changes for change in diff.changes: if change.old is None: print(f"+ Line {change.new}: {change.line}") # Added line elif change.new is None: print(f"- Line {change.old}: {change.line}") # Removed line else: print(f" Line {change.old}->{change.new}: {change.line}") # Context line # Output: # - Line 2: print(\"Hello\") # + Line 2: print(\"Hello, World!\") # + Line 3: return True ``` -------------------------------- ### Parse Git Patches Source: https://context7.com/cscorley/whatthepatch/llms.txt Extracts header information and changes from Git-formatted patches. ```python import whatthepatch git_patch = """diff --git a/src/main.py b/src/main.py index a1b2c3d..e4f5g6h 100644 --- a/src/main.py +++ b/src/main.py @@ -10,6 +10,7 @@ def main(): config = load_config() logger = setup_logging() + logger.info("Application starting") try: run_application(config) """ for diff in whatthepatch.parse_patch(git_patch): print(f"Old path: {diff.header.old_path}") # Output: src/main.py print(f"New path: {diff.header.new_path}") # Output: src/main.py print(f"Old version: {diff.header.old_version}") # Output: a1b2c3d print(f"New version: {diff.header.new_version}") # Output: e4f5g6h # Find added lines added = [c for c in diff.changes if c.old is None] print(f"Lines added: {len(added)}") # Output: Lines added: 1 ``` -------------------------------- ### Categorize and inspect changes in a patch Source: https://context7.com/cscorley/whatthepatch/llms.txt Iterate through parsed diff changes to identify removed, added, and context lines using the Change namedtuple attributes. ```python import whatthepatch patch_text = """--- config.json +++ config.json @@ -1,8 +1,9 @@ { "name": "myapp", - "version": "1.0.0", + "version": "1.1.0", "debug": false, + "logging": true, "settings": { "timeout": 30 } } """ for diff in whatthepatch.parse_patch(patch_text): # Categorize changes removed = [] added = [] context = [] for change in diff.changes: if change.old is not None and change.new is None: removed.append(change) elif change.old is None and change.new is not None: added.append(change) else: context.append(change) print(f"Removed lines: {len(removed)}") # Output: Removed lines: 1 print(f"Added lines: {len(added)}") # Output: Added lines: 2 print(f"Context lines: {len(context)}") # Output: Context lines: 6 # Show specific changes for r in removed: print(f"Removed from line {r.old}: {r.line.strip()}") # Output: Removed from line 3: "version": "1.0.0", for a in added: print(f"Added at line {a.new}: {a.line.strip()}") # Output: Added at line 3: "version": "1.1.0", # Output: Added at line 5: "logging": true," ``` -------------------------------- ### apply_diff Source: https://context7.com/cscorley/whatthepatch/llms.txt Applies a parsed diff object to source text, returning the modified content as a list of lines. ```APIDOC ## apply_diff ### Description Applies a parsed diff object to source text, returning the modified content as a list of lines. Supports forward and reverse application. ### Parameters #### Request Body - **diff** (namedtuple) - Required - The parsed diff object. - **original** (string) - Required - The original source text. - **reverse** (boolean) - Optional - If set to True, applies the diff in reverse to undo changes. ### Response - **result** (list of strings) - The modified content as a list of lines. ``` -------------------------------- ### Parse multiple diffs in a single patch file Source: https://context7.com/cscorley/whatthepatch/llms.txt Handle patch files containing multiple file diffs by iterating over the list returned by parse_patch. ```python import whatthepatch multi_patch = """diff --git a/file1.py b/file1.py index abc1234..def5678 100644 --- a/file1.py +++ b/file1.py @@ -1,3 +1,4 @@ import os +import sys def main(): diff --git a/file2.py b/file2.py index 111aaaa..222bbbb 100644 --- a/file2.py +++ b/file2.py @@ -5,6 +5,7 @@ class Helper: def __init__(self): self.ready = False + self.initialized = True """ diffs = list(whatthepatch.parse_patch(multi_patch)) print(f"Number of file diffs: {len(diffs)}") # Output: Number of file diffs: 2 for i, diff in enumerate(diffs): print(f"\nDiff {i + 1}: {diff.header.new_path}") additions = sum(1 for c in diff.changes if c.old is None) deletions = sum(1 for c in diff.changes if c.new is None) print(f" +{additions} -{deletions}") # Output: # Number of file diffs: 2 # # Diff 1: file1.py # +1 -0 # # Diff 2: file2.py # +1 -0 ``` -------------------------------- ### Parse SVN Patches Source: https://context7.com/cscorley/whatthepatch/llms.txt Extracts revision information from Subversion-formatted patches. ```python import whatthepatch svn_patch = """Index: project/src/utils.py =================================================================== --- project/src/utils.py (revision 1234) +++ project/src/utils.py (revision 1235) @@ -5,7 +5,7 @@ def calculate_total(items): total = 0 for item in items: - total += item.price + total += item.price * item.quantity return total """ for diff in whatthepatch.parse_patch(svn_patch): print(f"Index path: {diff.header.index_path}") # Output: project/src/utils.py print(f"Old revision: {diff.header.old_version}") # Output: 1234 print(f"New revision: {diff.header.new_version}") # Output: 1235 ``` -------------------------------- ### Parse a patch file Source: https://github.com/cscorley/whatthepatch/blob/main/README.rst Use parse_patch to iterate through diffs and retrieve structured change information. ```python >>> import whatthepatch >>> import pprint >>> with open('tests/casefiles/diff-unified.diff') as f: ... text = f.read() ... >>> for diff in whatthepatch.parse_patch(text): ... print(diff) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE ... diff(header=header(index_path=None, old_path='lao', old_version='2013-01-05 16:56:19.000000000 -0600', new_path='tzu', new_version='2013-01-05 16:56:35.000000000 -0600'), changes=[Change(old=1, new=None, line='The Way that can be told of is not the eternal Way;', hunk=1), Change(old=2, new=None, line='The name that can be named is not the eternal name.', hunk=1), Change(old=3, new=1, line='The Nameless is the origin of Heaven and Earth;', hunk=1), Change(old=4, new=None, line='The Named is the mother of all things.', hunk=1), Change(old=None, new=2, line='The named is the mother of all things.', hunk=1), Change(old=None, new=3, line='', hunk=1), Change(old=5, new=4, line='Therefore let there always be non-being,', hunk=1), Change(old=6, new=5, line=' so we may see their subtlety,', hunk=1), Change(old=7, new=6, line='And let there always be being,', hunk=1), Change(old=9, new=8, line='The two are the same,', hunk=2), Change(old=10, new=9, line='But after they are produced,', hunk=2), Change(old=11, new=10, line=' they have different names.', hunk=2), Change(old=None, new=11, line='They both may be called deep and profound.', hunk=2), Change(old=None, new=12, line='Deeper and more profound,', hunk=2), Change(old=None, new=13, line='The door of all subtleties!', hunk=2)], text='...') ``` -------------------------------- ### parse_patch Source: https://context7.com/cscorley/whatthepatch/llms.txt Parses patch content from a string or iterable of lines and yields diff objects containing header information and change details. ```APIDOC ## parse_patch ### Description Parses patch content from a string or iterable of lines and yields diff objects containing header information and change details. ### Parameters #### Request Body - **patch_text** (string or iterable) - Required - The patch content to be parsed. ### Response - **diff** (namedtuple) - Contains header information, a list of changes, and the original text. - **change** (namedtuple) - Contains 'old' (line number), 'new' (line number), 'line' (content), and 'hunk' (hunk number). ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.