Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1from pathlib import Path 

2from typing import Union 

3import ssl, certifi 

4import urllib.request 

5from rich.progress import Progress 

6 

7class DownloadError(Exception): 

8 pass 

9 

10 

11def download_file(url:str, local_path:Path, chunk_size:int=16 * 1024, context=None): 

12 """ adapted from https://stackoverflow.com/a/1517728 """ 

13 local_path = Path(local_path) 

14 local_path.parent.mkdir(parents=True, exist_ok=True) 

15 

16 with urllib.request.urlopen(url, context=context) as response, open(local_path, 'wb') as f, Progress() as progress: 

17 task = progress.add_task("[red]Downloading", total=response.length) 

18 while True: 

19 chunk = response.read(chunk_size) 

20 progress.update(task, advance=chunk_size) 

21 if not chunk: 

22 break 

23 f.write(chunk) 

24 

25 return local_path 

26 

27 

28def cached_download(url: str, local_path: Union[str, Path], force: bool = False) -> None: 

29 """ 

30 Downloads a file if a local file does not already exist. 

31 

32 Args: 

33 url (str): The url of the file to download. 

34 local_path (str, Path): The local path of where the file should be. 

35 If this file isn't there or the file size is zero then this function downloads it to this location. 

36 force (bool): Whether or not the file should be forced to download again even if present in the local path. 

37 Default False. 

38 

39 Raises: 

40 DownloadError: Raises an exception if it cannot download the file. 

41 IOError: Raises an exception if the file does not exist or is empty after downloading. 

42 """ 

43 local_path = Path(local_path) 

44 if (not local_path.exists() or local_path.stat().st_size == 0) or force: 

45 try: 

46 print(f"Downloading {url} to {local_path}") 

47 download_file(url, local_path) 

48 except Exception: 

49 try: 

50 download_file(url, local_path, context=ssl.create_default_context(cafile=certifi.where())) 

51 except Exception as err: 

52 raise DownloadError(f"Error downloading {url} to {local_path}:\n{err}") 

53 

54 if not local_path.exists() or local_path.stat().st_size == 0: 

55 raise IOError(f"Error reading {local_path}")