#1130691 python3-apt: _file_is_same() always returns False, causing packages to re-download every run

Package:
python3-apt
Source:
python3-apt
Description:
Python 3 interface to libapt-pkg
Submitter:
Eddy Pronk
Date:
2026-03-14 07:35:02 UTC
Severity:
normal
#1130691#5
Date:
2026-03-14 07:33:40 UTC
From:
To:
Dear Maintainer,

`apt.package._file_is_same()` always returns `False` even when the cached
`.deb` file is present and correct. This causes every call to
`Version.fetch_binary()` to re-download the package from the network,
bypassing the destination-path cache entirely.

**Root cause**

Two bugs in `apt/package.py`:

Bug 1 — file opened in text mode:

```python
with open(path) as fobj:          # should be open(path, "rb")
```

Bug 2 — order-sensitive hash comparison:

```python
return apt_pkg.Hashes(fobj).hashes == hashes
```

`HashStringList.__eq__` compares element-by-element (list semantics).
`apt_pkg.Hashes(file)` computes all hash types (MD5, SHA1, SHA256, SHA512),
but the package records only store a subset. The lists differ in both order
and length, so `==` always returns `False`.

**Reproduction**

```python
import apt, apt_pkg, tempfile
from apt.package import _file_is_same

cache = apt.Cache(memonly=True)
version = cache["hello"].candidate
with tempfile.TemporaryDirectory() as tmpdir:
    path = version.fetch_binary(tmpdir)
    print(_file_is_same(path, version.size, version._records.hashes))
    # prints: False  (expected: True)
```

**Fix**

```python
def _file_is_same(path: str, size: int, hashes: apt_pkg.HashStringList) -> bool:
    """Return ``True`` if the file is the same."""
    if os.path.exists(path) and os.path.getsize(path) == size:
        with open(path, "rb") as fobj:
            file_set = {str(h) for h in apt_pkg.Hashes(fobj).hashes}
            return {str(h) for h in hashes} <= file_set
    return False
```

A patch is attached.