"""Reproduce this guide's HTML conversions without network access or installation.""" from pathlib import Path from importlib.metadata import version import argparse import datetime import hashlib import json import platform import shutil import subprocess import time from bs4 import BeautifulSoup from markdownify import markdownify from markitdown import MarkItDown LAB = Path(__file__).resolve().parent SAMPLES = ['article', 'headerless', 'colgroup-header', 'colgroup-thead'] def language(pre): code = pre.find('code') for value in (code or pre).get('class', []): if value.startswith('language-'): return value.removeprefix('language-') return '' def selected_html(text): soup = BeautifulSoup(text, 'html.parser') selected = soup.select_one('main article') or soup.find('article') or soup.body or soup return str(selected) def fixtures(): corpus = LAB / 'corpus' probes = { 'headerless': ( '

Queue export

\n' '

The source contains data cells without column labels.

\n' '\n' '
AmberQueued
BirchDone
\n', {'headings': [{'level': 1, 'text': 'Queue export'}], 'paragraphs': ['The source contains data cells without column labels.'], 'tables': [{'header': [], 'rows': [['Amber', 'Queued'], ['Birch', 'Done']]}]}), 'colgroup-header': ( '

Labelled queue export

\n' '

The column group precedes a row containing explicit header cells.

\n' '\n' '\n' '\n' '
TaskState
AmberQueued
BirchDone
\n', {'headings': [{'level': 1, 'text': 'Labelled queue export'}], 'paragraphs': ['The column group precedes a row containing explicit header cells.'], 'tables': [{'header': ['Task', 'State'], 'rows': [['Amber', 'Queued'], ['Birch', 'Done']]}]}) } for name, (html, truth) in probes.items(): (corpus / (name + '.html')).write_text(html) (corpus / (name + '.truth.json')).write_text(json.dumps( {'kind': 'doc', 'format': 'html', **truth}, indent=2) + '\n') html, truth = probes['colgroup-header'] wrapped = html.replace('TaskState', 'TaskState') (corpus / 'colgroup-thead.html').write_text(wrapped) (corpus / 'colgroup-thead.truth.json').write_text(json.dumps( {'kind': 'doc', 'format': 'html', **truth}, indent=2) + '\n') # Publishable plain-text mirrors: exact bytes, never advertised as rendered HTML. for name in SAMPLES: (corpus / (name + '.txt')).write_bytes((corpus / (name + '.html')).read_bytes()) def main(): parser = argparse.ArgumentParser() parser.add_argument('--examples', action='store_true') args = parser.parse_args() if args.examples: raise SystemExit('Run the standalone example scripts with your own input.html.') fixtures() manifest = LAB / 'runs.json' archive = LAB / 'upstream-runs.json' if not archive.exists(): archive.write_bytes(manifest.read_bytes()) old = json.loads(archive.read_text()) tools = { 'markitdown': version('markitdown'), 'markdownify': version('markdownify'), 'markdownify-selected': version('markdownify'), 'markdownify-infer-header': version('markdownify'), 'pandoc-gfm': subprocess.check_output(['pandoc', '--version'], text=True).splitlines()[0], } manifest_data = {**old, 'python': platform.python_version(), 'date': datetime.date.today().isoformat(), 'tools': {**old['tools'], **tools}} manifest_data['results'] = [r for r in old['results'] if r['tool'] not in tools] converter = MarkItDown(enable_plugins=False) observations = [] for tool in tools: output_dir = LAB / tool output_dir.mkdir(exist_ok=True) for name in SAMPLES: source = LAB / 'corpus' / (name + '.html') html = source.read_text() start = time.perf_counter() error = None try: if tool == 'markitdown': output = converter.convert(str(source)).text_content elif tool == 'markdownify': output = markdownify(html, heading_style='ATX') elif tool == 'markdownify-selected': output = markdownify(selected_html(html), heading_style='ATX', code_language_callback=language) elif tool == 'markdownify-infer-header': output = markdownify(html, heading_style='ATX', table_infer_header=True) else: output = subprocess.check_output( ['pandoc', '-f', 'html', '-t', 'gfm', '--wrap=none', str(source)], text=True) except Exception as exc: output, error = '', repr(exc) elapsed = round(time.perf_counter() - start, 6) destination = output_dir / (name + '.md') destination.write_text(output) manifest_data['results'].append({ 'tool': tool, 'sample': name, 'output': str(destination.relative_to(LAB)), 'elapsed_s': elapsed, 'error': error}) observations.append({'tool': tool, 'sample': name, 'elapsed_s': elapsed, 'error': error, 'sha256': hashlib.sha256(output.encode()).hexdigest()}) manifest.write_text(json.dumps(manifest_data, indent=2) + '\n') details = { 'executed_at': datetime.datetime.now().astimezone().isoformat(), 'python': platform.python_version(), 'tools': tools, 'pandoc_path': shutil.which('pandoc'), 'beautifulsoup4': version('beautifulsoup4'), 'options': {'markdownify': {'heading_style': 'ATX'}, 'markdownify-selected': {'heading_style': 'ATX', 'selector': 'main article > article > body fallback', 'code_language_callback': 'language(pre)'}, 'markdownify-infer-header': {'heading_style': 'ATX', 'table_infer_header': True}, 'markitdown': {'enable_plugins': False}, 'pandoc-gfm': ['-f', 'html', '-t', 'gfm', '--wrap=none']}, 'results': observations, 'boundary': 'HTML conversion only; no GitHub.com rendering, no fetching, no JavaScript execution; Markovo upstream snapshot not rerun.'} (LAB / 'html-run.json').write_text(json.dumps(details, indent=2) + '\n') print(json.dumps({'python': details['python'], 'tools': tools, 'conversions': len(observations), 'errors': [o for o in observations if o['error']]}, indent=2)) if __name__ == '__main__': main()