def process_imports(lines: List[str]) -> List[str]: log = __logging.get_log() line_data = list(lines) for idx, line in enumerate(line_data): if not line.strip().startswith('[IMPORT '): continue import_statement = line.strip() import_name = import_statement \ .replace('[IMPORT ', '') \ .replace(']', '') \ .strip() log.verbose(f"Loading import: {import_name}...") markdown = get_shared_markdown(import_name) if markdown is not None: markdown_lines = markdown.split('\n') else: markdown_lines = ['', f'ERROR: IMPORT {import_name} not found', ''] line_data = line_data[:idx] + markdown_lines + line_data[idx + 1:] return process_imports(line_data) return line_data
def get_markdown(template_path: str, data: Dict[str, Any] = None) -> str: if data is None: data = {} cache = __caching.get_cache() log = __logging.get_log() key = f'markdown: {template_path}' entry = cache.get_markdown(key) if entry: log.trace(f"CACHE HIT: Reusing {template_path} from MARKDOWN cache.") if not data: return entry.contents else: return process_variables(entry.contents, data) t0 = datetime.datetime.now() text = load_markdown_contents(template_path) cache.add_markdown(key, key, text) if data: text = process_variables(text, data) dt = datetime.datetime.now() - t0 msg = f"Created contents for {template_path} in {int(dt.total_seconds() * 1000):,} ms." log.trace(f"GENERATING MARKDOWN: {msg}") return text
def get_page(template_path: str, data: Dict[str, Any]) -> str: cache = __caching.get_cache() log = __logging.get_log() key = f'name: {template_path}, data: {data}' entry = cache.get_html(key) if entry: log.trace(f"CACHE HIT: Reusing {template_path} from HTML cache.") return entry.contents t0 = datetime.datetime.now() # Get the markdown with imports and substitutions markdown = get_markdown(template_path, data) # Convert markdown to HTML html = get_html(markdown) cache.add_html(key, key, str(data), html) dt = datetime.datetime.now() - t0 msg = f"Created contents for {template_path}:{data} in {int(dt.total_seconds() * 1000):,} ms." log.info(f"GENERATING HTML: {msg}") return html
def init_logging(config) -> logbook.Logger: logbook.StreamHandler(sys.stdout, level='TRACE').push_application() log = logbook.Logger('App') log.notice('Logging initialized.') md_log = logging.get_log() md_log.log_level = LogLevel.trace return log
def test_logging_off(): log = logging.get_log() level = log.log_level try: log.log_level = LogLevel.off assert not log.should_log(LogLevel.error, 'MSG') assert not log.should_log(LogLevel.verbose, 'MSG') finally: log.log_level = level
def test_can_change_log_level(): log = logging.get_log() level = log.log_level try: log.log_level = LogLevel.error assert log.log_level == LogLevel.error finally: log.log_level = level
def load_markdown_contents(template_path: str, data: Dict[str, Any]) -> str: log = __logging.get_log() log.verbose(f"Loading markdown template: {template_path}") landing_md = get_page_markdown(template_path) lines = landing_md.split('\n') lines = process_imports(lines) lines = process_variables(lines, data) final_markdown = "\n".join(lines).strip() return final_markdown
def load_markdown_contents(template_path: str) -> Optional[str]: if not template_path: return '' log = __logging.get_log() log.verbose(f"Loading markdown template: {template_path}") page_md = get_page_markdown(template_path) if not page_md: return '' lines = page_md.split('\n') lines = process_imports(lines) final_markdown = "\n".join(lines).strip() return final_markdown
def get_page(template_path: str, data: Dict[str, Any]) -> str: if not template_path or not template_path.strip(): raise ArgumentExpectedException('template_path') template_path = template_path.strip().lower() cache = __caching.get_cache() log = __logging.get_log() key = f'html: {template_path}' entry = cache.get_html(key) if entry: log.trace(f"CACHE HIT: Reusing {template_path} from HTML cache.") contents = entry.contents # Is there data that needs to be folded in? Process it. if data: contents = process_variables(contents, data) # Return the cached data, no need to transform for variables. return contents t0 = datetime.datetime.now() # Get the markdown with imports and substitutions markdown = get_markdown(template_path) inline_variables = {} markdown = get_inline_variables(markdown, inline_variables, log) # Convert markdown to HTML html = get_html(markdown) # Cache inline variables, but not the passed in data as that varies per request (query string, etc). html = process_variables(html, inline_variables) cache.add_html(key, key, html) # Replace the passed variables each time. html = process_variables(html, data) dt = datetime.datetime.now() - t0 msg = f"Created contents for {template_path}:{data} in {int(dt.total_seconds() * 1000):,} ms." log.info(f"GENERATING HTML: {msg}") return html
def process_variables(lines: List[str], data: Dict[str, Any]) -> List[str]: log = __logging.get_log() line_data = list(lines) keys = list(data.keys()) key_placeholders = { key: f"${key.strip().upper()}$" for key in keys if key and isinstance(key, str) } for idx, line in enumerate(line_data): for key in keys: if key_placeholders[key] not in line: continue log.verbose(f"Replacing {key_placeholders[key]} in:\n{line}") line_data[idx] = line.replace(key_placeholders[key], str(data[key])) return line_data
def get_markdown(template_path: str, data: Dict[str, Any]) -> str: cache = __caching.get_cache() log = __logging.get_log() key = f'name: {template_path}, data: {data}' entry = cache.get_markdown(key) if entry: log.trace(f"CACHE HIT: Reusing {template_path} from MARKDOWN cache.") return entry.contents t0 = datetime.datetime.now() text = load_markdown_contents(template_path, data) cache.add_markdown(key, key, str(data), text) dt = datetime.datetime.now() - t0 msg = f"Created contents for {template_path}:{data} in {int(dt.total_seconds() * 1000):,} ms." log.trace(f"GENERATING MARKDOWN: {msg}") return text
def process_variables(raw_text: str, data: Dict[str, Any]) -> str: if not raw_text: return raw_text log = __logging.get_log() keys = list(data.keys()) key_placeholders = { key: f"${key.strip().upper()}$" for key in keys if key and isinstance(key, str) } transformed_text = raw_text for key in keys: if key_placeholders[key] not in transformed_text: continue log.verbose(f"Replacing {key_placeholders[key]}...") transformed_text = transformed_text.replace(key_placeholders[key], str(data[key])) return transformed_text
def process_imports(lines: List[str]) -> List[str]: log = __logging.get_log() line_data = list(lines) for idx, line in enumerate(line_data): if not line.strip().startswith('[IMPORT '): continue import_statement = line.strip() import_name = import_statement \ .replace('[IMPORT ', '') \ .replace(']', '') \ .strip() imported_file = os.path.join('_shared', import_name + '.md') log.verbose(f"Loading import: {imported_file}...") markdown = get_page_markdown(imported_file) markdown_lines = markdown.split('\n') line_data = line_data[:idx] + markdown_lines + line_data[idx + 1:] return process_imports(line_data) return line_data
def set_template_folder(full_path: str): from ..exceptions import PathException import markdown_subtemplate.logging as logging log = logging.get_log() test_path = os.path.abspath(full_path) if test_path != full_path: msg = f"{full_path} is not an absolute path." log.error("engine.set_template_folder: " + msg) raise PathException(msg) if not os.path.exists(full_path): msg = f"{full_path} does not exist." log.error("engine.set_template_folder: " + msg) raise PathException(msg) if not os.path.isdir(full_path): msg = f"{full_path} is not a directory." log.error("engine.set_template_folder: " + msg) raise PathException(msg) log.info(f"Template folder set: {full_path}") FileStore.__template_folder = full_path
def test_default_log_level(): log = logging.get_log() assert log.log_level == LogLevel.info
def test_should_log_no(): log = logging.get_log() assert not log.should_log(LogLevel.verbose, "MSG") assert not log.should_log(LogLevel.trace, "MSG")
def test_should_log_yes(): log = logging.get_log() assert log.should_log(LogLevel.info, "MSG") assert log.should_log(LogLevel.error, "MSG")