diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 74ff6d3..0f87cdc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,13 +5,13 @@ repos: - id: docformatter args: [--in-place, --pre-summary-newline, --make-summary-multi] - repo: https://github.com/myint/autoflake - rev: v1.5.1 + rev: v1.5.3 hooks: - id: autoflake args: ['--in-place', '--remove-all-unused-imports', '--remove-unused-variable'] exclude: ".*(.fits|.fts|.fit|.txt|tca.*|extern.*|.rst|.md|__init__.py)$" - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 22.8.0 hooks: - id: black exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 09ac3e8..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,19 +0,0 @@ -# Exclude specific files -# All files which are tracked by git and not explicitly excluded here are included by setuptools_scm -# Prune folders -prune build -prune docs/_build -prune docs/api -prune .circleci -prune .github -prune .jupyter -prune binder - -# exclude a bunch of common hidden files, you probably want to add your own here -exclude .mailmap -exclude .gitignore -exclude .gitattributes -exclude .editorconfig -exclude .zenodo.json -exclude *.yml -exclude *.yaml diff --git a/hvpy/__init__.py b/hvpy/__init__.py index 6fe14b1..a86fdde 100644 --- a/hvpy/__init__.py +++ b/hvpy/__init__.py @@ -2,5 +2,6 @@ from .datasource import * from .event import * from .facade import * -from .utils import create_layers, create_events +from .helpers import createMovie +from .utils import create_events, create_layers, save_file from .version import __version__ diff --git a/hvpy/helpers.py b/hvpy/helpers.py new file mode 100644 index 0000000..b04aa48 --- /dev/null +++ b/hvpy/helpers.py @@ -0,0 +1,126 @@ +import time +from typing import Union, Optional +from pathlib import Path +from datetime import datetime + +from hvpy.api_groups.movies.queue_movie import queueMovieInputParameters +from hvpy.facade import downloadMovie, getMovieStatus, queueMovie +from hvpy.utils import _add_shared_docstring, save_file + +__all__ = [ + "createMovie", +] + + +@_add_shared_docstring(queueMovieInputParameters) +def createMovie( + startTime: datetime, + endTime: datetime, + layers: str, + events: str, + eventsLabels: bool, + imageScale: float, + format: Optional[str] = "mp4", + frameRate: Optional[str] = "15", + maxFrames: Optional[str] = None, + scale: Optional[bool] = None, + scaleType: Optional[str] = None, + scaleX: Optional[float] = None, + scaleY: Optional[float] = None, + movieLength: Optional[float] = None, + watermark: Optional[bool] = True, + width: Optional[str] = None, + height: Optional[str] = None, + x0: Optional[str] = None, + y0: Optional[str] = None, + x1: Optional[str] = None, + y1: Optional[str] = None, + x2: Optional[str] = None, + y2: Optional[str] = None, + size: Optional[int] = None, + movieIcons: Optional[int] = None, + followViewport: Optional[int] = None, + reqObservationDate: Optional[datetime] = None, + overwrite: bool = False, + filename: Union[str, Path] = None, + hq: bool = False, + timeout: float = 5, +) -> Path: + """ + Automatically creates a movie using `queueMovie`, `getMovieStatus` and + `downloadMovie` functions. + + Parameters + ---------- + {Insert} + overwrite + Whether to overwrite the file if it already exists. + Default is `False`. + filename + The path to save the file to. + Optional, will default to ``f"{starttime}_{endtime}.{format}"``. + hq + Download a higher-quality movie file (valid for "mp4" movies only, ignored otherwise). + Default is `False`, optional. + timeout + The timeout in minutes to wait for the movie to be created. + Default is 5 minutes. + + Examples + -------- + >>> from hvpy import createMovie, DataSource, create_events, create_layers + >>> from datetime import datetime, timedelta + >>> movie_location = createMovie( + ... startTime=datetime.today() - timedelta(days=15, minutes=5), + ... endTime=datetime.today() - timedelta(days=15), + ... layers=create_layers([(DataSource.AIA_171, 100)]), + ... events=create_events(["AR"]), + ... eventsLabels=True, + ... imageScale=1, + ... filename="my_movie", + ... ) + >>> # This is to cleanup the file created from the example + >>> # you don't need to do this + >>> from pathlib import Path + >>> Path('my_movie.mp4').unlink() + """ + input_params = locals() + # These are used later on but we want to avoid passing + # them into queueMovie. + input_params.pop("overwrite") + input_params.pop("filename") + input_params.pop("hq") + input_params.pop("timeout") + res = queueMovie(**input_params) + if res.get("error"): + raise RuntimeError(res["error"]) + timeout_counter = time.time() + 60 * timeout # Default 5 minutes + while True: + status = getMovieStatus( + id=res["id"], + format=format, + token=res["token"], + ) + if status["status"] in [0, 1]: + time.sleep(3) + if status["status"] == 2: + break + if time.time() > timeout_counter: + raise RuntimeError(f"Exceeded timeout of {timeout} minutes.") + if status["status"] == 3: + raise RuntimeError(status["error"]) + binary_data = downloadMovie( + id=res["id"], + format=format, + hq=hq, + ) + if filename is None: + filename = f"{res['id']}_{startTime.date()}_{endTime.date()}.{format}" + else: + filename = f"{filename}.{format}" + save_file( + data=binary_data, + filename=filename, + overwrite=overwrite, + ) + return Path(filename) diff --git a/hvpy/tests/test_helper.py b/hvpy/tests/test_helper.py new file mode 100644 index 0000000..96a1188 --- /dev/null +++ b/hvpy/tests/test_helper.py @@ -0,0 +1,95 @@ +from pathlib import Path +from datetime import datetime + +import pytest + +from hvpy.datasource import DataSource +from hvpy.helpers import createMovie +from hvpy.utils import create_events, create_layers + + +def test_createMovie(start_time, end_time, tmp_path): + f1 = tmp_path / "movie" + result = createMovie( + startTime=start_time, + endTime=end_time, + layers=create_layers([(DataSource.AIA_171, 100)]), + events=create_events(["AR"]), + eventsLabels=True, + imageScale=1, + filename=f1, + ) + assert isinstance(result, Path) + assert result.exists() + assert result == tmp_path / "movie.mp4" + + result = createMovie( + startTime=start_time, + endTime=end_time, + layers=create_layers([(DataSource.AIA_171, 100)]), + events=create_events(["AR"]), + eventsLabels=True, + imageScale=1, + filename=f1, + overwrite=True, + ) + assert isinstance(result, Path) + assert result.exists() + assert result == tmp_path / "movie.mp4" + + +def test_createMovie_with_none_filename(start_time, end_time): + result = createMovie( + startTime=start_time, + endTime=end_time, + layers=create_layers([(DataSource.AIA_171, 100)]), + events=create_events(["AR"]), + eventsLabels=True, + imageScale=1, + ) + assert isinstance(result, Path) + assert result.exists() + result.unlink() # clean up + + +def test_createMovie_timeout(start_time, end_time, tmp_path): + f1 = tmp_path / "movie" + with pytest.raises(RuntimeError): + createMovie( + startTime=start_time, + endTime=end_time, + layers=create_layers([(DataSource.AIA_171, 100)]), + events=create_events(["AR"]), + eventsLabels=True, + imageScale=1, + filename=f1, + timeout=0.5, + ) + + +def test_error_handling2(tmp_path): + f1 = tmp_path / "movie" + with pytest.raises(RuntimeError): + createMovie( + startTime=datetime(2010, 1, 1), + endTime=datetime(2010, 1, 2), + layers=create_layers([(DataSource.AIA_171, 100)]), + events=create_events(["AR"]), + eventsLabels=True, + imageScale=1, + filename=f1, + ) + + +def test_error_handling(tmp_path): + f1 = tmp_path / "movie" + with pytest.raises(RuntimeError): + createMovie( + startTime=datetime(2010, 1, 1), + endTime=datetime(2010, 1, 2), + layers=create_layers([(DataSource.AIA_171, 100)]), + events=create_events(["AR"]), + eventsLabels=True, + imageScale=1, + filename=f1, + ) diff --git a/hvpy/tests/test_utils.py b/hvpy/tests/test_utils.py index 10a48b3..eddc1a0 100644 --- a/hvpy/tests/test_utils.py +++ b/hvpy/tests/test_utils.py @@ -84,7 +84,7 @@ def test_save_file(tmp_path): ) save_file(res, f1, overwrite=False) assert f1.exists() - with pytest.raises(ValueError, match="already exists"): + with pytest.raises(FileExistsError, match="already exists"): save_file(res, f1, overwrite=False) save_file(res, f1, overwrite=True) assert f1.exists() diff --git a/hvpy/utils.py b/hvpy/utils.py index 0c2a3d3..2d4d031 100644 --- a/hvpy/utils.py +++ b/hvpy/utils.py @@ -148,5 +148,5 @@ def save_file(data: bytearray, filename: Union[Path, str], overwrite: bool = Fal if isinstance(filename, str): filename = Path(filename) if filename.exists() and not overwrite: - raise ValueError(f"{filename} already exists. Use overwrite=True to overwrite.") + raise FileExistsError(f"{filename} already exists. Use overwrite=True to overwrite.") filename.write_bytes(data)