Skip to content

Quilt-style patches that add multiple files in a row fail to parse #143

Description

@cartr

When you try to parse the following patch file with e.g. PatchSet.from_string, a UnidiffParseError is thrown:

--- /dev/null
+++ b/1.txt
@@ -0,0 +1 @@
+a
--- /dev/null
+++ b/2.txt
@@ -0,0 +1 @@
+b
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/lib/python3.14/site-packages/unidiff/patch.py", line 639, in from_string
    return cls(cls._convert_string(data, encoding, errors),
               metadata_only=metadata_only)
  File "/lib/python3.14/site-packages/unidiff/patch.py", line 449, in __init__
    self._parse(data, encoding=encoding, metadata_only=metadata_only)
    ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.14/site-packages/unidiff/patch.py", line 548, in _parse
    raise UnidiffParseError('Target without source: %s' % line)
unidiff.errors.UnidiffParseError: Target without source: +++ b/2.txt

(The quilt utility used in Debian packaging generates unified diff files in this format. Here's a real-world example: https://sources.debian.org/patches/glibc/2.41-12+deb13u3/alpha/submitted-fts64.diff/ )

I suspect the issue here is that, because the source filenames are both /dev/null, this "processing a rename" condition gets incorrectly used when parsing the second --- /dev/null line:

# reset current file, unless we are processing a rename
# (in that case, source files should match)
if current_file is not None and not (
current_file.source_file == source_file):
current_file = None
elif current_file is not None:
current_file.source_timestamp = source_timestamp

The condition should probably be updated to check whether current_file has any hunks, or track the "in the middle of Git-style patch info" state in some other more robust way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions