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
@@ -1593,7 +1594,7 @@ async def fetch_links(
15931594 name using the `index_url` of this repository.
15941595 """
15951596 package_url = f"{ self .index_url } /{ normalized_name } "
1596- text = await CACHE .get (
1597+ text , _ = await CACHE .get (
15971598 path_or_url = package_url ,
15981599 credentials = self .credentials ,
15991600 as_text = True ,
@@ -1671,7 +1672,7 @@ async def get(
16711672 force = False ,
16721673 verbose = False ,
16731674 echo_func = None ,
1674- ):
1675+ ) -> Tuple [ Union [ str , bytes ], str ] :
16751676 """
16761677 Return the content fetched from a ``path_or_url`` through the cache.
16771678 Raise an Exception on errors. Treats the content as text if as_text is
@@ -1692,13 +1693,13 @@ async def get(
16921693 echo_func = echo_func ,
16931694 )
16941695 wmode = "w" if as_text else "wb"
1695- with open (cached , wmode ) as fo :
1696- fo .write (content )
1697- return content
1696+ async with aiofiles . open (cached , mode = wmode ) as fo :
1697+ await fo .write (content )
1698+ return content , cached
16981699 else :
16991700 if TRACE_DEEP :
17001701 print (f" FILE CACHE HIT: { path_or_url } " )
1701- return get_local_file_content (path = cached , as_text = as_text )
1702+ return await get_local_file_content (path = cached , as_text = as_text ), cached
17021703
17031704
17041705CACHE = Cache ()
@@ -1730,13 +1731,13 @@ async def get_file_content(
17301731 elif path_or_url .startswith ("file://" ) or (
17311732 path_or_url .startswith ("/" ) and os .path .exists (path_or_url )
17321733 ):
1733- return get_local_file_content (path = path_or_url , as_text = as_text )
1734+ return await get_local_file_content (path = path_or_url , as_text = as_text )
17341735
17351736 else :
17361737 raise Exception (f"Unsupported URL scheme: { path_or_url } " )
17371738
17381739
1739- def get_local_file_content (path , as_text = True ):
1740+ async def get_local_file_content (path : str , as_text = True ) -> str :
17401741 """
17411742 Return the content at `url` as text. Return the content as bytes is
17421743 `as_text` is False.
@@ -1745,8 +1746,8 @@ def get_local_file_content(path, as_text=True):
17451746 path = path [7 :]
17461747
17471748 mode = "r" if as_text else "rb"
1748- with open (path , mode ) as fo :
1749- return fo .read ()
1749+ async with aiofiles . open (path , mode = mode ) as fo :
1750+ return await fo .read ()
17501751
17511752
17521753class RemoteNotFetchedException (Exception ):
@@ -1828,7 +1829,7 @@ async def fetch_and_save(
18281829 errors. Treats the content as text if as_text is True otherwise as treat as
18291830 binary.
18301831 """
1831- content = await CACHE .get (
1832+ content , path = await CACHE .get (
18321833 path_or_url = path_or_url ,
18331834 credentials = credentials ,
18341835 as_text = as_text ,
@@ -1837,7 +1838,8 @@ async def fetch_and_save(
18371838 )
18381839
18391840 output = os .path .join (dest_dir , filename )
1840- wmode = "w" if as_text else "wb"
1841- with open (output , wmode ) as fo :
1842- fo .write (content )
1841+ if os .path .exists (output ):
1842+ os .remove (output )
1843+
1844+ os .symlink (os .path .abspath (path ), output )
18431845 return content
0 commit comments