1515from itertools import product
1616from os .path import splitext
1717from pathlib import Path
18+ from tempfile import TemporaryDirectory
1819from types import TracebackType
20+ from typing import Any , ClassVar
1921
2022from packaging .utils import parse_wheel_filename
2123
@@ -98,8 +100,13 @@ class InWheel(InTemporaryDirectory):
98100 On entering, you'll find yourself in the root tree of the wheel. If you've
99101 asked for an output wheel, then on exit we'll rewrite the wheel record and
100102 pack stuff up for you.
103+
104+ If `out_wheel` is None, we assume the wheel won't be modified and we can
105+ cache the unpacked wheel for future use.
101106 """
102107
108+ _whl_cache : ClassVar [dict [Path , TemporaryDirectory [Any ]]] = {}
109+
103110 def __init__ (self , in_wheel : Path , out_wheel : Path | None = None ) -> None :
104111 """Initialize in-wheel context manager
105112
@@ -113,9 +120,28 @@ def __init__(self, in_wheel: Path, out_wheel: Path | None = None) -> None:
113120 """
114121 self .in_wheel = in_wheel .absolute ()
115122 self .out_wheel = None if out_wheel is None else out_wheel .absolute ()
116- super ().__init__ ()
123+ self .read_only = out_wheel is None
124+ self .use_cache = self .in_wheel in self ._whl_cache
125+
126+ if self .use_cache :
127+ logger .debug (
128+ "Reuse %s for %s" , self ._whl_cache [self .in_wheel ], self .in_wheel
129+ )
130+ self ._tmpdir = self ._whl_cache [self .in_wheel ]
131+ if not self .read_only :
132+ self ._whl_cache .pop (self .in_wheel )
133+ else :
134+ super ().__init__ ()
135+ if self .read_only :
136+ self ._whl_cache [self .in_wheel ] = self ._tmpdir
117137
118138 def __enter__ (self ) -> Path :
139+ if self .use_cache or self .read_only :
140+ if not self .use_cache :
141+ zip2dir (self .in_wheel , self .name )
142+ self ._pwd = Path .cwd ()
143+ os .chdir (self .name )
144+ return Path (self .name )
119145 zip2dir (self .in_wheel , self .name )
120146 return super ().__enter__ ()
121147
@@ -132,6 +158,16 @@ def __exit__(
132158 if timestamp :
133159 date_time = datetime .fromtimestamp (int (timestamp ), tz = timezone .utc )
134160 dir2zip (self .name , self .out_wheel , date_time )
161+ if self .use_cache or self .read_only :
162+ logger .debug (
163+ "Exiting reused %s for %s" ,
164+ self ._whl_cache [self .in_wheel ],
165+ self .in_wheel ,
166+ )
167+ os .chdir (self ._pwd )
168+ if not self .use_cache :
169+ super ().__exit__ (exc , value , tb )
170+ return None
135171 return super ().__exit__ (exc , value , tb )
136172
137173
0 commit comments