Repository: pypa/auditwheel

Issue:
auditwheel repair: whls not getting compressed for auditwheel 5.1.0 and above?
After upgrading to 5.1.0, we noticed that our wheels are not getting compressed, resulting in very large whls after running `auditwheel repair foo.whl`:

```
-rw-r--r-- 1 root root 104093514 Jan  7 01:54 accera-1.2.1.dev17-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.5.1.0.whl
```

auditwheel 5.0.0 was able to compress the whls by roughly 70%:

```
-rw-r--r-- 1 root root  35413658 Jan  7 01:44 accera-1.2.1.dev17-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.5.0.0.whl
```

The contents of both files are the same after unzipping, so the binaries themselves are unchanged but the whl does not seem to be compressed when using auditwheel 5.1.0 and above.

```shell
[root@9a0260dd545d wheelhouse]# ls -al accera-5.0.0/
total 101324
drwxr-xr-x 8 root root      4096 Jan  7 01:44 .
drwxr-xr-x 6 root root      4096 Jan  7 01:55 ..
-rw-r--r-- 1 root root       476 Jan  7 01:44 Constants.py
-rw-r--r-- 1 root root      3219 Jan  7 01:44 Debug.py
drwxr-xr-x 2 root root      4096 Jan  7 01:44 hat
-rw-r--r-- 1 root root      1035 Jan  7 01:44 __init__.py
drwxr-xr-x 2 root root      4096 Jan  7 01:44 lang
-rwxr-xr-x 1 root root 103664768 Jan  7 01:44 _lang_python.cpython-38-x86_64-linux-gnu.so
-rw-r--r-- 1 root root     20883 Jan  7 01:44 Package.py
-rw-r--r-- 1 root root      1563 Jan  7 01:44 Parameter.py
drwxr-xr-x 2 root root      4096 Jan  7 01:44 samples
-rw-r--r-- 1 root root      9045 Jan  7 01:44 Targets.py
drwxr-xr-x 2 root root      4096 Jan  7 01:44 test
drwxr-xr-x 3 root root      4096 Jan  7 01:44 tools
drwxr-xr-x 2 root root      4096 Jan  7 01:44 tuning
-rw-r--r-- 1 root root        36 Jan  7 01:44 _version.py


[root@9a0260dd545d wheelhouse]# ls -al accera-5.1.0/
total 101324
drwxr-xr-x 8 root root      4096 Jan  7 01:54 .
drwxr-xr-x 6 root root      4096 Jan  7 01:55 ..
-rw-r--r-- 1 root root       476 Jan  7 01:54 Constants.py
-rw-r--r-- 1 root root      3219 Jan  7 01:54 Debug.py
drwxr-xr-x 2 root root      4096 Jan  7 01:54 hat
-rw-r--r-- 1 root root      1035 Jan  7 01:54 __init__.py
drwxr-xr-x 2 root root      4096 Jan  7 01:54 lang
-rwxr-xr-x 1 root root 103664768 Jan  7 01:54 _lang_python.cpython-38-x86_64-linux-gnu.so
-rw-r--r-- 1 root root     20883 Jan  7 01:54 Package.py
-rw-r--r-- 1 root root      1563 Jan  7 01:54 Parameter.py
drwxr-xr-x 2 root root      4096 Jan  7 01:54 samples
-rw-r--r-- 1 root root      9045 Jan  7 01:54 Targets.py
drwxr-xr-x 2 root root      4096 Jan  7 01:54 test
drwxr-xr-x 3 root root      4096 Jan  7 01:54 tools
drwxr-xr-x 2 root root      4096 Jan  7 01:54 tuning
-rw-r--r-- 1 root root        36 Jan  7 01:54 _version.py
```


Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/pypa/auditwheel/pull/367?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa) Report
> Merging [#367](https://codecov.io/gh/pypa/auditwheel/pull/367?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa) (1dd0172) into [main](https://codecov.io/gh/pypa/auditwheel/commit/68aad23937225a629d70cb4b3e224abd07f16f44?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa) (68aad23) will **decrease** coverage by `1.41%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/pypa/auditwheel/pull/367/graphs/tree.svg?width=650&height=150&src=pr&token=Em0HVspBmj&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa)](https://codecov.io/gh/pypa/auditwheel/pull/367?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa)

```diff
@@            Coverage Diff             @@
##             main     #367      +/-   ##
==========================================
- Coverage   92.35%   90.93%   -1.42%     
==========================================
  Files          23       23              
  Lines        1256     1258       +2     
  Branches      307      307              
==========================================
- Hits         1160     1144      -16     
- Misses         55       67      +12     
- Partials       41       47       +6     
```


| [Impacted Files](https://codecov.io/gh/pypa/auditwheel/pull/367?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa) | Coverage Δ | |
|---|---|---|
| [src/auditwheel/tools.py](https://codecov.io/gh/pypa/auditwheel/pull/367/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa#diff-c3JjL2F1ZGl0d2hlZWwvdG9vbHMucHk=) | `93.93% <100.00%> (+0.18%)` | :arrow_up: |
| [src/auditwheel/main\_addtag.py](https://codecov.io/gh/pypa/auditwheel/pull/367/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa#diff-c3JjL2F1ZGl0d2hlZWwvbWFpbl9hZGR0YWcucHk=) | `65.78% <0.00%> (-23.69%)` | :arrow_down: |
| [src/auditwheel/main.py](https://codecov.io/gh/pypa/auditwheel/pull/367/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa#diff-c3JjL2F1ZGl0d2hlZWwvbWFpbi5weQ==) | `94.44% <0.00%> (-5.56%)` | :arrow_down: |
| [src/auditwheel/wheeltools.py](https://codecov.io/gh/pypa/auditwheel/pull/367/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa#diff-c3JjL2F1ZGl0d2hlZWwvd2hlZWx0b29scy5weQ==) | `87.85% <0.00%> (-2.15%)` | :arrow_down: |
| [src/auditwheel/elfutils.py](https://codecov.io/gh/pypa/auditwheel/pull/367/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa#diff-c3JjL2F1ZGl0d2hlZWwvZWxmdXRpbHMucHk=) | `93.06% <0.00%> (-1.99%)` | :arrow_down: |
| [src/auditwheel/policy/\_\_init\_\_.py](https://codecov.io/gh/pypa/auditwheel/pull/367/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa#diff-c3JjL2F1ZGl0d2hlZWwvcG9saWN5L19faW5pdF9fLnB5) | `99.09% <0.00%> (-0.91%)` | :arrow_down: |
| [src/auditwheel/lddtree.py](https://codecov.io/gh/pypa/auditwheel/pull/367/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa#diff-c3JjL2F1ZGl0d2hlZWwvbGRkdHJlZS5weQ==) | `89.74% <0.00%> (-0.65%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pypa/auditwheel/pull/367?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pypa/auditwheel/pull/367?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa). Last update [68aad23...1dd0172](https://codecov.io/gh/pypa/auditwheel/pull/367?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pypa).


Patch:
diff --git a/src/auditwheel/tools.py b/src/auditwheel/tools.py
index ed8b514..bce72f2 100644
--- a/src/auditwheel/tools.py
+++ b/src/auditwheel/tools.py
@@ -70,19 +70,21 @@ def dir2zip(in_dir: str, zip_fname: str, date_time: Optional[datetime] = None) -
         st = os.stat(in_dir)
         date_time = datetime.fromtimestamp(st.st_mtime, tz=timezone.utc)
     date_time_args = date_time.timetuple()[:6]
-    with zipfile.ZipFile(zip_fname, "w", compression=zipfile.ZIP_DEFLATED) as z:
+    compression = zipfile.ZIP_DEFLATED
+    with zipfile.ZipFile(zip_fname, "w", compression=compression) as z:
         for root, dirs, files in os.walk(in_dir):
             for dir in dirs:
                 dname = os.path.join(root, dir)
                 out_dname = os.path.relpath(dname, in_dir) + "/"
-                zinfo = zipfile.ZipInfo(out_dname, date_time=date_time_args)
-                zinfo.external_attr = os.stat(dname).st_mode << 16
-                z.writestr(zinfo, "")
+                zinfo = zipfile.ZipInfo.from_file(dname, out_dname)
+                zinfo.date_time = date_time_args
+                z.writestr(zinfo, b"")
             for file in files:
                 fname = os.path.join(root, file)
                 out_fname = os.path.relpath(fname, in_dir)
-                zinfo = zipfile.ZipInfo(out_fname, date_time=date_time_args)
-                zinfo.external_attr = os.stat(fname).st_mode << 16
+                zinfo = zipfile.ZipInfo.from_file(fname, out_fname)
+                zinfo.date_time = date_time_args
+                zinfo.compress_type = compression
                 with open(fname, "rb") as fp:
                     z.writestr(zinfo, fp.read())
 


Test patch:
diff --git a/tests/unit/test_tools.py b/tests/unit/test_tools.py
index dd2a086..ee79467 100644
--- a/tests/unit/test_tools.py
+++ b/tests/unit/test_tools.py
@@ -87,3 +87,14 @@ def test_zip2dir_round_trip_permissions(tmp_path):
     dir2zip(str(tmp_path / "unzip1"), str(tmp_path / "tmp.zip"))
     zip2dir(str(tmp_path / "tmp.zip"), str(extract_path))
     _check_permissions(extract_path)
+
+
+def test_dir2zip_deflate(tmp_path):
+    buffer = b"\0" * 1024 * 1024
+    input_dir = tmp_path / "input_dir"
+    input_dir.mkdir()
+    input_file = input_dir / "zeros.bin"
+    input_file.write_bytes(buffer)
+    output_file = tmp_path / "ouput.zip"
+    dir2zip(str(input_dir), str(output_file))
+    assert output_file.stat().st_size < len(buffer) / 4