Merge pull request #1637 from 3b1b/add_warnings

Add warnings and use rich to display log
This commit is contained in:
Grant Sanderson 2021-10-15 12:13:02 -07:00 committed by GitHub
commit ed3d44120c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 70 additions and 35 deletions

View file

@ -1,3 +1,7 @@
import pkg_resources
__version__ = pkg_resources.get_distribution("manimgl").version
from manimlib.constants import * from manimlib.constants import *
from manimlib.animation.animation import * from manimlib.animation.animation import *

View file

@ -2,11 +2,16 @@
import manimlib.config import manimlib.config
import manimlib.extract_scene import manimlib.extract_scene
import manimlib.utils.init_config import manimlib.utils.init_config
from manimlib import __version__
def main(): def main():
args = manimlib.config.parse_cli() args = manimlib.config.parse_cli()
print(f"ManimGL \033[32mv{__version__}\033[0m")
if args.version and args.file == None:
return
if args.config: if args.config:
manimlib.utils.init_config.init_customization() manimlib.utils.init_config.init_customization()
else: else:

View file

@ -9,6 +9,7 @@ from screeninfo import get_monitors
from manimlib.utils.config_ops import merge_dicts_recursively from manimlib.utils.config_ops import merge_dicts_recursively
from manimlib.utils.init_config import init_customization from manimlib.utils.init_config import init_customization
from manimlib.logger import log
def parse_cli(): def parse_cli():
@ -136,10 +137,15 @@ def parse_cli():
"--config_file", "--config_file",
help="Path to the custom configuration file", help="Path to the custom configuration file",
) )
parser.add_argument(
"-v", "--version",
action="store_true",
help="Display the version of manimgl"
)
args = parser.parse_args() args = parser.parse_args()
return args return args
except argparse.ArgumentError as err: except argparse.ArgumentError as err:
print(str(err)) log.error(str(err))
sys.exit(2) sys.exit(2)
@ -185,36 +191,45 @@ def get_custom_config():
return config return config
def check_temporary_storage(config):
if config["directories"]["temporary_storage"] == "" and sys.platform == "win32":
log.warning("You may be using Windows platform and have not specified the `temporary\
_storage` path, which may cause OSError. So it is recommended that you specify the `temporary\
_storage` in the config file (.yml)")
def get_configuration(args): def get_configuration(args):
global __config_file__ global __config_file__
# ensure __config_file__ always exists # ensure __config_file__ always exists
if args.config_file is not None: if args.config_file is not None:
if not os.path.exists(args.config_file): if not os.path.exists(args.config_file):
print(f"Can't find {args.config_file}.") log.error(f"Can't find {args.config_file}.")
if sys.platform == 'win32': if sys.platform == 'win32':
print(f"Copying default configuration file to {args.config_file}...") log.info(f"Copying default configuration file to {args.config_file}...")
os.system(f"copy default_config.yml {args.config_file}") os.system(f"copy default_config.yml {args.config_file}")
elif sys.platform in ["linux2", "darwin"]: elif sys.platform in ["linux2", "darwin"]:
print(f"Copying default configuration file to {args.config_file}...") log.info(f"Copying default configuration file to {args.config_file}...")
os.system(f"cp default_config.yml {args.config_file}") os.system(f"cp default_config.yml {args.config_file}")
else: else:
print("Please create the configuration file manually.") log.info("Please create the configuration file manually.")
print("Read configuration from default_config.yml.") log.info("Read configuration from default_config.yml.")
else: else:
__config_file__ = args.config_file __config_file__ = args.config_file
global_defaults_file = os.path.join(get_manim_dir(), "manimlib", "default_config.yml") global_defaults_file = os.path.join(get_manim_dir(), "manimlib", "default_config.yml")
if not (os.path.exists(global_defaults_file) or os.path.exists(__config_file__)): if not (os.path.exists(global_defaults_file) or os.path.exists(__config_file__)):
print("There is no configuration file detected. Initial configuration:\n") log.info("There is no configuration file detected. Initial configuration:\n")
init_customization() init_customization()
elif not os.path.exists(__config_file__): elif not os.path.exists(__config_file__):
print(f"Warning: Using the default configuration file, which you can modify in {global_defaults_file}") log.info(f"Using the default configuration file, which you can modify in `{global_defaults_file}`")
print(f"If you want to create a local configuration file, you can create a file named {__config_file__}, or run manimgl --config") log.info(f"If you want to create a local configuration file, you can create a file named \
`{__config_file__}`, or run `manimgl --config`")
custom_config = get_custom_config() custom_config = get_custom_config()
check_temporary_storage(custom_config)
write_file = any([args.write_file, args.open, args.finder]) write_file = any([args.write_file, args.open, args.finder])
if args.transparent: if args.transparent:
@ -319,9 +334,9 @@ def get_camera_configuration(args, custom_config):
try: try:
bg_color = args.color or custom_config["style"]["background_color"] bg_color = args.color or custom_config["style"]["background_color"]
camera_config["background_color"] = colour.Color(bg_color) camera_config["background_color"] = colour.Color(bg_color)
except AttributeError as err: except ValueError as err:
print("Please use a valid color") log.error("Please use a valid color")
print(err) log.error(err)
sys.exit(2) sys.exit(2)
# If rendering a transparent image/move, make sure the # If rendering a transparent image/move, make sure the

View file

@ -1,9 +1,9 @@
import inspect import inspect
import sys import sys
import logging
from manimlib.scene.scene import Scene from manimlib.scene.scene import Scene
from manimlib.config import get_custom_config from manimlib.config import get_custom_config
from manimlib.logger import log
class BlankScene(Scene): class BlankScene(Scene):
@ -41,8 +41,11 @@ def prompt_user_for_choice(scene_classes):
name_to_class[split_str] if not split_str.isnumeric() else scene_classes[int(split_str)-1] name_to_class[split_str] if not split_str.isnumeric() else scene_classes[int(split_str)-1]
for split_str in user_input.replace(" ", "").split(",") for split_str in user_input.replace(" ", "").split(",")
] ]
except IndexError:
log.error("Invalid scene number")
sys.exit(2)
except KeyError: except KeyError:
logging.log(logging.ERROR, "Invalid scene") log.error("Invalid scene name")
sys.exit(2) sys.exit(2)
except EOFError: except EOFError:
sys.exit(1) sys.exit(1)
@ -78,10 +81,7 @@ def get_scenes_to_render(scene_classes, scene_config, config):
found = True found = True
break break
if not found and (scene_name != ""): if not found and (scene_name != ""):
logging.log( log.error(f"No scene named {scene_name} found")
logging.ERROR,
f"No scene named {scene_name} found",
)
if result: if result:
return result return result
if len(scene_classes) == 1: if len(scene_classes) == 1:

9
manimlib/logger.py Normal file
View file

@ -0,0 +1,9 @@
import logging
from rich.logging import RichHandler
FORMAT = "%(message)s"
logging.basicConfig(
level="NOTSET", format=FORMAT, datefmt="[%X]", handlers=[RichHandler()]
)
log = logging.getLogger("rich")

View file

@ -2,7 +2,6 @@ import inspect
import random import random
import platform import platform
import itertools as it import itertools as it
import logging
from functools import wraps from functools import wraps
from tqdm import tqdm as ProgressDisplay from tqdm import tqdm as ProgressDisplay
@ -21,6 +20,7 @@ from manimlib.utils.family_ops import extract_mobject_family_members
from manimlib.utils.family_ops import restructure_list_to_exclude_certain_family_members from manimlib.utils.family_ops import restructure_list_to_exclude_certain_family_members
from manimlib.event_handler.event_type import EventType from manimlib.event_handler.event_type import EventType
from manimlib.event_handler import EVENT_DISPATCHER from manimlib.event_handler import EVENT_DISPATCHER
from manimlib.logger import log
class Scene(object): class Scene(object):
@ -101,6 +101,8 @@ class Scene(object):
# If there is a window, enter a loop # If there is a window, enter a loop
# which updates the frame while under # which updates the frame while under
# the hood calling the pyglet event loop # the hood calling the pyglet event loop
log.info("Tips: You are now in the interactive mode. Now you can use the keyboard\
and the mouse to interact with the scene. Just press `q` if you want to quit.")
self.quit_interaction = False self.quit_interaction = False
self.lock_static_mobject_data() self.lock_static_mobject_data()
while not (self.window.is_closing or self.quit_interaction): while not (self.window.is_closing or self.quit_interaction):
@ -132,6 +134,8 @@ class Scene(object):
local_ns["touch"] = self.interact local_ns["touch"] = self.interact
for term in ("play", "wait", "add", "remove", "clear", "save_state", "restore"): for term in ("play", "wait", "add", "remove", "clear", "save_state", "restore"):
local_ns[term] = getattr(self, term) local_ns[term] = getattr(self, term)
log.info("Tips: Now the embed iPython terminal is open. But you can't interact with \
the window directly. To do so, you need to type `touch()` or `self.interact()`")
shell(local_ns=local_ns, stack_depth=2) shell(local_ns=local_ns, stack_depth=2)
# End scene when exiting an embed. # End scene when exiting an embed.
raise EndSceneEarlyException() raise EndSceneEarlyException()
@ -459,8 +463,7 @@ class Scene(object):
@handle_play_like_call @handle_play_like_call
def play(self, *args, **kwargs): def play(self, *args, **kwargs):
if len(args) == 0: if len(args) == 0:
logging.log( log.warning(
logging.WARNING,
"Called Scene.play with no animations" "Called Scene.play with no animations"
) )
return return
@ -602,7 +605,7 @@ class Scene(object):
try: try:
char = chr(symbol) char = chr(symbol)
except OverflowError: except OverflowError:
print(" Warning: The value of the pressed key is too large.") log.warning("The value of the pressed key is too large.")
return return
event_data = {"symbol": symbol, "modifiers": modifiers} event_data = {"symbol": symbol, "modifiers": modifiers}

View file

@ -12,6 +12,7 @@ from manimlib.utils.file_ops import guarantee_existence
from manimlib.utils.file_ops import add_extension_if_not_present from manimlib.utils.file_ops import add_extension_if_not_present
from manimlib.utils.file_ops import get_sorted_integer_files from manimlib.utils.file_ops import get_sorted_integer_files
from manimlib.utils.sounds import get_full_sound_file_path from manimlib.utils.sounds import get_full_sound_file_path
from manimlib.logger import log
class SceneFileWriter(object): class SceneFileWriter(object):
@ -231,7 +232,7 @@ class SceneFileWriter(object):
**kwargs **kwargs
) )
if len(partial_movie_files) == 0: if len(partial_movie_files) == 0:
print("No animations in this scene") log.warning("No animations in this scene")
return return
# Write a file partial_file_list.txt containing all # Write a file partial_file_list.txt containing all
@ -300,7 +301,7 @@ class SceneFileWriter(object):
self.print_file_ready_message(file_path) self.print_file_ready_message(file_path)
def print_file_ready_message(self, file_path): def print_file_ready_message(self, file_path):
print(f"\nFile ready at {file_path}\n") log.info(f"\nFile ready at {file_path}\n")
def should_open_file(self): def should_open_file(self):
return any([ return any([

View file

@ -5,6 +5,7 @@ from manimlib.utils.simple_functions import choose
from manimlib.utils.space_ops import find_intersection from manimlib.utils.space_ops import find_intersection
from manimlib.utils.space_ops import cross2d from manimlib.utils.space_ops import cross2d
from manimlib.utils.space_ops import midpoint from manimlib.utils.space_ops import midpoint
from manimlib.logger import log
CLOSED_THRESHOLD = 0.001 CLOSED_THRESHOLD = 0.001
@ -68,9 +69,9 @@ def interpolate(start, end, alpha):
try: try:
return (1 - alpha) * start + alpha * end return (1 - alpha) * start + alpha * end
except TypeError: except TypeError:
print(type(start), start.dtype) log.debug(type(start), start.dtype)
print(type(end), start.dtype) log.debug(type(end), start.dtype)
print(alpha) log.debug(alpha)
import sys import sys
sys.exit(2) sys.exit(2)

View file

@ -3,11 +3,12 @@ import time
from manimlib.constants import BLACK from manimlib.constants import BLACK
from manimlib.mobject.numbers import Integer from manimlib.mobject.numbers import Integer
from manimlib.mobject.types.vectorized_mobject import VGroup from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.logger import log
def print_family(mobject, n_tabs=0): def print_family(mobject, n_tabs=0):
"""For debugging purposes""" """For debugging purposes"""
print("\t" * n_tabs, mobject, id(mobject)) log.debug("\t" * n_tabs + str(mobject) + " " + str(id(mobject)))
for submob in mobject.submobjects: for submob in mobject.submobjects:
print_family(submob, n_tabs + 1) print_family(submob, n_tabs + 1)

View file

@ -1,4 +1,3 @@
import logging
import sys import sys
import os import os
import hashlib import hashlib
@ -7,6 +6,7 @@ from contextlib import contextmanager
from manimlib.utils.directories import get_tex_dir from manimlib.utils.directories import get_tex_dir
from manimlib.config import get_manim_dir from manimlib.config import get_manim_dir
from manimlib.config import get_custom_config from manimlib.config import get_custom_config
from manimlib.logger import log
SAVED_TEX_CONFIG = {} SAVED_TEX_CONFIG = {}
@ -87,15 +87,11 @@ def tex_to_dvi(tex_file):
exit_code = os.system(" ".join(commands)) exit_code = os.system(" ".join(commands))
if exit_code != 0: if exit_code != 0:
log_file = tex_file.replace(".tex", ".log") log_file = tex_file.replace(".tex", ".log")
logging.log( log.error("LaTeX Error! Not a worry, it happens to the best of us.")
logging.ERROR,
"\n\n LaTeX Error! Not a worry, it happens to the best of us.\n"
)
with open(log_file, "r") as file: with open(log_file, "r") as file:
for line in file.readlines(): for line in file.readlines():
if line.startswith("!"): if line.startswith("!"):
print(line[1:]) log.debug(f"The error could be: `{line[2:-1]}`")
logging.log(logging.INFO, line)
sys.exit(2) sys.exit(2)
return result return result