Source code for anim.cli

import argparse
import logging
import multiprocessing
import traceback

import anim
import anim.log  # noqa: F401
from anim.anim import simple_building
from anim.tools import Timing

logger = logging.getLogger(__name__)


[docs] def usage(): parser = argparse.ArgumentParser() parser.add_argument("pythonfile", type=str, help="python file containing functions to plot and compute date") parser.add_argument( "-v", "--verbose", action="store", help="verbose", choices=["ERROR", "WARNING", "INFO", "DEBUG"], default="INFO", ) group1 = parser.add_argument_group("Image Creation", "parameters for image creation") group1.add_argument( "-j", "--nprocess", action="store", type=int, default=multiprocessing.cpu_count() - 1, help=f"number of core to use. By default, max-1 ({multiprocessing.cpu_count()-1})", ) group1.add_argument( "--no-compute", action="store_true", help="Don't compute any images. Use only ffmpeg. Usefull if images are already computed and takes time", ) group1.add_argument( "--no-convert", action="store_true", help="Don't compute any video. Only compute images", ) group1.add_argument("-f", "--force", action="store_true", help="force saving images even if they already exist") group1.add_argument( "-s", "--show", action="store", nargs="?", const=None, default=False, help=( "Show the first image from animation then quit. Usefull to visualize and check if your parameters are correct, before doing all the computations. " "if nothing is specified after '-s', show the image with `plt.show()`. If an argument is specified, we store the image using the name specified." "You can specify a patern name for example `image_{i:03d}.png`, and the i will be interpolated to the indice of the image, usefull when you specified --only arg" ), ) group1.add_argument( "--only", action="store", nargs="+", type=int, default=[], help="compute only images with specified indices, without multiprocessing. Usefull for debbuging purposes.", ) group1.add_argument( "--ffmpeg-log", action="store_true", help="print all ffmpeg logs. If not specified, run `ffmpeg` with `-loglevel quiet`", ) group2 = parser.add_argument_group("ImGifage Creation", "parameters for gif creation") group2.add_argument( "-g", "--gif", nargs="?", type=int, const=5, default=False, help="Create a 5s gif (by default) to test the animation", ) group2.add_argument( "--folder", type=str, default=None, help="specify the folder where images and video will be stored. Overwrite the `ANIM_OUTPUT_FOLDER` in the python script", ) return parser.parse_args()
[docs] def execfile_(filepath, _globals): """Executes a Python code defined in a file""" with open(filepath, "rb") as stream: source = stream.read() code = compile(source, filepath, "exec") exec(code, _globals)
[docs] def eval_config_file(filename: str): """Evaluate a config file.""" namespace = dict(__file__=filename) logger.info(f"loading file {filename}...") with Timing() as dt: try: execfile_(filename, namespace) except SyntaxError as err: raise RuntimeError(f"There is a syntax error in your configuration file: {err}\n") except SystemExit: raise RuntimeError("The configuration file (or one of the modules it imports) " "called sys.exit()") except Exception: raise RuntimeError( "There is a programmable error in your configuration " f"file:\n\n{traceback.format_exc()}" ) logger.info(f"loading done ! ({dt})") return namespace
[docs] def app(): args = usage() anim.log.create_logger(level=args.verbose) with Timing() as dt: namespace = eval_config_file(args.pythonfile) FOLDER = namespace.get("ANIM_OUTPUT_FOLDER", None) if FOLDER is None: msg = "miss variable `ANIM_OUTPUT_FOLDER` in the python file" logging.error(msg) raise ValueError(msg) # parameter specified in command line overwrite the script one if args.folder is not None: FOLDER = args.folder func_plot = namespace.get("plot", None) if func_plot is None: msg = "miss function named `plot` in the python file" logging.error(msg) raise ValueError(msg) fps = namespace.get("ANIM_FPS", None) if fps is None: msg = "miss variable `ANIM_FPS` in the python file" logging.error(msg) raise ValueError(msg) compute = namespace.get("compute", None) savefig_kwargs = namespace.get("ANIM_SAVEFIG_KWARGS", dict()) max_frames = namespace.get("ANIM_MAX_FRAMES", None) max_frames = args.gif * fps if args.gif is not False else max_frames get_dask_client = namespace.get("get_dask_client", None) if (args.show is not False) or len(args.only) > 0: simple_building( f_plot=func_plot, compute=compute, max_frames=max_frames, indices=args.only, savefig_kwargs=savefig_kwargs, show=args.show, ) else: videoName = anim.animate( f_plot=func_plot, workFolder=FOLDER, fps=fps, compute=compute, max_frames=max_frames, savefig_kwargs=savefig_kwargs, client=get_dask_client, force=args.force, nprocess=args.nprocess, only_convert=args.no_compute, no_convert=args.no_convert, ffmpeg_log=args.ffmpeg_log, ) if args.gif is not False: anim.video2gif(videoName, args.gif) logger.info(f"total time for anim tool : {dt}")
if __name__ == "__main__": app()