@@ -98,6 +98,20 @@ def _timeout_from_environment(env_var: str, default_value: float) -> float:
98
98
return timeout
99
99
100
100
101
+ @functools .lru_cache
102
+ def _calc_tmpdir_buffer_size (tmpdir : str ) -> int :
103
+ """Compute the block size as 256 blocks of typical size
104
+ (i.e. 4096 bytes) or 10 times the file system block size,
105
+ whichever is higher.
106
+
107
+ This is a reasonable compromise between
108
+ using memory for buffering and the number of system calls
109
+ issued to read from or write to temporary files.
110
+ """
111
+ fsstats = os .statvfs (tmpdir )
112
+ return max (10 * fsstats .f_bsize , 256 * 4096 )
113
+
114
+
101
115
class HttpResourcePathConfig :
102
116
"""Configuration class to encapsulate the configurable items used by class
103
117
HttpResourcePath.
@@ -381,8 +395,8 @@ def tmpdir_buffersize(self) -> tuple[str, int]:
381
395
# whichever is higher. This is a reasonable compromise between
382
396
# using memory for buffering and the number of system calls
383
397
# issued to read from or write to temporary files.
384
- fsstats = os . statvfs (tmpdir )
385
- self ._tmpdir_buffersize = (tmpdir , max ( 10 * fsstats . f_bsize , 256 * 4096 ) )
398
+ bufsize = _calc_tmpdir_buffer_size (tmpdir )
399
+ self ._tmpdir_buffersize = (tmpdir , bufsize )
386
400
387
401
return self ._tmpdir_buffersize
388
402
@@ -1480,17 +1494,20 @@ def _sign_with_macaroon(self, activity: ActivityCaveat, expiration_time_seconds:
1480
1494
except json .JSONDecodeError :
1481
1495
raise ValueError (f"could not deserialize response to POST request for URL { self } " )
1482
1496
1483
- def _as_local (self , multithreaded : bool = True ) -> tuple [str , bool ]:
1497
+ def _as_local (self , multithreaded : bool = True , tmpdir : ResourcePath | None = None ) -> tuple [str , bool ]:
1484
1498
"""Download object over HTTP and place in temporary directory.
1485
1499
1486
1500
Parameters
1487
1501
----------
1488
1502
multithreaded : `bool`, optional
1489
1503
If `True` the transfer will be allowed to attempt to improve
1490
- throughput by using parallel download streams. This may of no
1504
+ throughput by using parallel download streams. This may of no
1491
1505
effect if the URI scheme does not support parallel streams or
1492
1506
if a global override has been applied. If `False` parallel
1493
1507
streams will be disabled.
1508
+ tmpdir : `ResourcePath` or `None`, optional
1509
+ Explicit override of the temporary directory to use for remote
1510
+ downloads.
1494
1511
1495
1512
Returns
1496
1513
-------
@@ -1509,9 +1526,14 @@ def _as_local(self, multithreaded: bool = True) -> tuple[str, bool]:
1509
1526
f"Unable to download resource { self } ; status: { resp .status_code } { resp .reason } "
1510
1527
)
1511
1528
1512
- tmpdir , buffer_size = self ._config .tmpdir_buffersize
1529
+ if tmpdir is None :
1530
+ temp_dir , buffer_size = self ._config .tmpdir_buffersize
1531
+ tmpdir = ResourcePath (temp_dir , forceDirectory = True )
1532
+ else :
1533
+ buffer_size = _calc_tmpdir_buffer_size (tmpdir .ospath )
1534
+
1513
1535
with ResourcePath .temporary_uri (
1514
- suffix = self .getExtension (), prefix = ResourcePath ( tmpdir , forceDirectory = True ) , delete = False
1536
+ suffix = self .getExtension (), prefix = tmpdir , delete = False
1515
1537
) as tmp_uri :
1516
1538
expected_length = int (resp .headers .get ("Content-Length" , "-1" ))
1517
1539
with time_this (
0 commit comments