Source code for scopesim.server.example_data_utils
# -*- coding: utf-8 -*-
"""Store the example data functions here instead of polluting database.py."""
import shutil
from pathlib import Path
from typing import Optional, Union
from collections.abc import Iterable
import httpx
import bs4
from astropy.utils.data import download_file
from scopesim import rc
[docs]def get_server_elements(url: str, unique_str: str = "/") -> list[str]:
"""
Return a list of file and/or directory paths on the HTTP server ``url``.
Parameters
----------
url : str
The URL of the IRDB HTTP server.
unique_str : str, list
A unique string to look for in the beautiful HTML soup:
"/" for directories this, ".zip" for packages
Returns
-------
paths : list
List of paths containing in ``url`` which contain ``unique_str``
"""
if isinstance(unique_str, str):
unique_str = [unique_str]
try:
result = httpx.get(url).content
except Exception as error:
raise ValueError(f"URL returned error: {url}") from error
soup = bs4.BeautifulSoup(result, features="lxml")
paths = soup.findAll("a", href=True)
select_paths = []
for the_str in unique_str:
select_paths += [tmp.string for tmp in paths
if tmp.string is not None and the_str in tmp.string]
return select_paths
[docs]def list_example_data(url: Optional[str] = None,
return_files: bool = False,
silent: bool = False) -> list[str]:
"""
List all example files found under ``url``.
Parameters
----------
url : str
The URL of the database HTTP server. If left as None, defaults to the
value in scopesim.rc.__config__["!SIM.file.server_base_url"]
return_files : bool
If True, returns a list of file names
silent : bool
If True, does not print the list of file names
Returns
-------
all_files : list of str
A list of paths to the example files relative to ``url``.
The full string should be passed to ``download_example_data``.
"""
def print_file_list(the_files, loc=""):
print(f"\nFiles saved {loc}\n" + "=" * (len(loc) + 12))
for _file in the_files:
print(_file)
if url is None:
url = rc.__config__["!SIM.file.server_base_url"]
return_file_list = []
server_files = []
folders = get_server_elements(url, "example_data")
for folder in folders:
files = get_server_elements(url + folder, ("fits", "txt", "dat"))
server_files += files
if not silent:
print_file_list(server_files, f"on the server: {url + 'example_data/'}")
return_file_list += server_files
if return_files:
return return_file_list
return None
[docs]def download_example_data(file_path: Union[Iterable[str], str],
save_dir: Optional[Union[Path, str]] = None,
url: Optional[str] = None,
from_cache: Optional[bool] = None) -> list[Path]:
"""
Download example fits files to the local disk.
Parameters
----------
file_path : str, list
Name(s) of FITS file(s) as given by ``list_example_data()``
save_dir : str
The place on the local disk where the downloaded files are to be saved.
If left as None, defaults to the current working directory.
url : str
The URL of the database HTTP server. If left as None, defaults to the
value in scopesim.rc.__config__["!SIM.file.server_base_url"]
from_cache : bool
Use the cached versions of the files. If None, defaults to the RC
value: ``!SIM.file.use_cached_downloads``
Returns
-------
save_path : Path or list of Paths
The absolute path(s) to the saved files
"""
if isinstance(file_path, Iterable) and not isinstance(file_path, str):
# Recursive
save_path = [download_example_data(thefile, save_dir, url)
for thefile in file_path]
return save_path
if not isinstance(file_path, str):
raise TypeError("file_path must be str or iterable of str, found "
f"{type(file_path) = }")
if url is None:
url = rc.__config__["!SIM.file.server_base_url"]
if save_dir is None:
save_dir = Path.cwd()
save_dir = Path(save_dir)
save_dir.mkdir(parents=True, exist_ok=True)
file_path = Path(file_path)
try:
if from_cache is None:
from_cache = rc.__config__["!SIM.file.use_cached_downloads"]
cache_path = download_file(f"{url}example_data/{file_path}",
cache=from_cache)
save_path = save_dir / file_path.name
file_path = shutil.copy2(cache_path, str(save_path))
except httpx.HTTPError as error:
msg = f"Unable to find file: {url + 'example_data/' + file_path}"
raise ValueError(msg) from error
save_path = save_path.absolute()
return save_path