Source code for lookatme.pres

"""
Defines Presentation specific objects
"""


import os
import threading
import time

import lookatme.ascii_art
import lookatme.config
import lookatme.contrib
import lookatme.prompt
import lookatme.themes
import lookatme.tui
from lookatme.parser import Parser
from lookatme.utils import dict_deep_update


[docs]class Presentation(object): """Defines a presentation """ def __init__(self, input_stream, theme, style_override=None, live_reload=False, single_slide=False, preload_extensions=None, safe=False, no_ext_warn=False, ignore_ext_failure=False): """Creates a new Presentation :param stream input_stream: An input stream from which to read the slide data """ self.preload_extensions = preload_extensions or [] self.input_filename = None if hasattr(input_stream, "name"): lookatme.config.SLIDE_SOURCE_DIR = os.path.dirname( input_stream.name) self.input_filename = input_stream.name self.style_override = style_override self.live_reload = live_reload self.tui = None self.single_slide = single_slide self.safe = safe self.no_ext_warn = no_ext_warn self.ignore_ext_failure = ignore_ext_failure self.initial_load_complete = False self.theme_mod = __import__( "lookatme.themes." + theme, fromlist=[theme]) if self.live_reload: self.reload_thread = threading.Thread(target=self.reload_watcher) self.reload_thread.daemon = True self.reload_thread.start() self.reload(data=input_stream.read()) self.initial_load_complete = True
[docs] def reload_watcher(self): """Watch for changes to the input filename, automatically reloading when the modified time has changed. """ if self.input_filename is None: return last_mod_time = os.path.getmtime(self.input_filename) while True: try: curr_mod_time = os.path.getmtime(self.input_filename) if curr_mod_time != last_mod_time: self.get_tui().reload() self.get_tui().loop.draw_screen() last_mod_time = curr_mod_time except Exception: pass finally: time.sleep(0.25)
[docs] def reload(self, data=None): """Reload this presentation :param str data: The data to render for this slide deck (optional) """ if data is None: with open(str(self.input_filename), "r") as f: data = f.read() parser = Parser(single_slide=self.single_slide) self.meta, self.slides = parser.parse(data) # only load extensions once! Live editing does not support # auto-extension reloading if not self.initial_load_complete: safe_exts = set(self.preload_extensions) new_exts = set() # only load if running with safe=False if not self.safe: source_exts = set(self.meta.get("extensions", [])) new_exts = source_exts - safe_exts self.warn_exts(new_exts) all_exts = safe_exts | new_exts lookatme.contrib.load_contribs( all_exts, safe_exts, self.ignore_ext_failure, ) # style override order: # 1. theme settings self.styles = lookatme.themes.ensure_defaults(self.theme_mod) # 2. inline styles from the presentation dict_deep_update(self.styles, self.meta.get("styles", {})) # 3. CLI style overrides if self.style_override is not None: self.styles["style"] = self.style_override # type: ignore lookatme.config.STYLE = self.styles self.initial_load_complete = True
[docs] def warn_exts(self, exts): """Warn about source-provided extensions that are to-be-loaded """ if len(exts) == 0 or self.no_ext_warn: return warning = lookatme.ascii_art.WARNING print("\n".join([" " + x for x in warning.split("\n")])) print("New extensions required by {!r} are about to be loaded:\n".format( self.input_filename )) for ext in exts: print(" - {!r}".format("lookatme.contrib." + ext)) print("") if not lookatme.prompt.yes("Are you ok with attempting to load them?"): print("Bailing due to unacceptance of source-required extensions") exit(1)
[docs] def run(self, start_slide=0): """Run the presentation! """ self.tui = lookatme.tui.create_tui(self, start_slide=start_slide) self.tui.run()
[docs] def get_tui(self) -> lookatme.tui.MarkdownTui: if self.tui is None: raise ValueError( "Tui has not been set, has the presentation been run yet?") return self.tui