1818import tempfile
1919import time
2020from collections import defaultdict
21- from typing import List , Dict
21+ from typing import List , Dict , Union , Tuple
2222from typing import NamedTuple
2323from urllib .parse import quote_plus
2424from urllib .parse import unquote
2525from urllib .parse import urlparse
2626from urllib .parse import urlunparse
2727
28+ import aiofiles
2829import aiohttp
2930import attr
3031import packageurl
@@ -1600,7 +1601,7 @@ async def fetch_links(
16001601 name using the `index_url` of this repository.
16011602 """
16021603 package_url = f"{ self .index_url } /{ normalized_name } "
1603- text = await CACHE .get (
1604+ text , _ = await CACHE .get (
16041605 path_or_url = package_url ,
16051606 credentials = self .credentials ,
16061607 as_text = True ,
@@ -1678,7 +1679,7 @@ async def get(
16781679 force = False ,
16791680 verbose = False ,
16801681 echo_func = None ,
1681- ):
1682+ ) -> Tuple [ Union [ str , bytes ], str ] :
16821683 """
16831684 Return the content fetched from a ``path_or_url`` through the cache.
16841685 Raise an Exception on errors. Treats the content as text if as_text is
@@ -1699,13 +1700,13 @@ async def get(
16991700 echo_func = echo_func ,
17001701 )
17011702 wmode = "w" if as_text else "wb"
1702- with open (cached , wmode ) as fo :
1703- fo .write (content )
1704- return content
1703+ async with aiofiles . open (cached , mode = wmode ) as fo :
1704+ await fo .write (content )
1705+ return content , cached
17051706 else :
17061707 if TRACE_DEEP :
17071708 print (f" FILE CACHE HIT: { path_or_url } " )
1708- return get_local_file_content (path = cached , as_text = as_text )
1709+ return await get_local_file_content (path = cached , as_text = as_text ), cached
17091710
17101711
17111712CACHE = Cache ()
@@ -1737,13 +1738,13 @@ async def get_file_content(
17371738 elif path_or_url .startswith ("file://" ) or (
17381739 path_or_url .startswith ("/" ) and os .path .exists (path_or_url )
17391740 ):
1740- return get_local_file_content (path = path_or_url , as_text = as_text )
1741+ return await get_local_file_content (path = path_or_url , as_text = as_text )
17411742
17421743 else :
17431744 raise Exception (f"Unsupported URL scheme: { path_or_url } " )
17441745
17451746
1746- def get_local_file_content (path , as_text = True ):
1747+ async def get_local_file_content (path : str , as_text = True ) -> str :
17471748 """
17481749 Return the content at `url` as text. Return the content as bytes is
17491750 `as_text` is False.
@@ -1752,8 +1753,8 @@ def get_local_file_content(path, as_text=True):
17521753 path = path [7 :]
17531754
17541755 mode = "r" if as_text else "rb"
1755- with open (path , mode ) as fo :
1756- return fo .read ()
1756+ async with aiofiles . open (path , mode = mode ) as fo :
1757+ return await fo .read ()
17571758
17581759
17591760class RemoteNotFetchedException (Exception ):
@@ -1835,7 +1836,7 @@ async def fetch_and_save(
18351836 errors. Treats the content as text if as_text is True otherwise as treat as
18361837 binary.
18371838 """
1838- content = await CACHE .get (
1839+ content , path = await CACHE .get (
18391840 path_or_url = path_or_url ,
18401841 credentials = credentials ,
18411842 as_text = as_text ,
@@ -1844,7 +1845,8 @@ async def fetch_and_save(
18441845 )
18451846
18461847 output = os .path .join (dest_dir , filename )
1847- wmode = "w" if as_text else "wb"
1848- with open (output , wmode ) as fo :
1849- fo .write (content )
1848+ if os .path .exists (output ):
1849+ os .remove (output )
1850+
1851+ os .symlink (os .path .abspath (path ), output )
18501852 return content
0 commit comments