1
1
#! /usr/bin/env python3
2
2
# -*- coding: utf-8 -*-
3
3
import argparse
4
+ import hashlib
4
5
import html
5
6
import os
6
7
from pathlib import Path
15
16
16
17
17
18
def convert (problem_root : Path , options : argparse .Namespace , statement_file : Path ) -> bool :
18
- """Convert a Markdown statement to HTML
19
+ """Convert a Markdown statement to HTML. Writes output to current working directory.
19
20
20
21
Args:
21
22
problem: path to problem directory
@@ -85,7 +86,7 @@ def is_fn_id(s):
85
86
allowed_classes = ('sample' , 'problemheader' , 'problembody' , 'sampleinteractionwrite' , 'sampleinteractionread' )
86
87
87
88
# Annoying: nh3 will ignore exceptions in attribute_filter
88
- image_fail_reason : str | None = None
89
+ image_fail_reason : list [ Exception ] = []
89
90
90
91
def attribute_filter (tag , attribute , value ):
91
92
if attribute == 'class' and value in allowed_classes :
@@ -103,10 +104,9 @@ def attribute_filter(tag, attribute, value):
103
104
statement_util .assert_image_is_valid (statement_dir , value )
104
105
except Exception as e :
105
106
nonlocal image_fail_reason
106
- image_fail_reason = str (e )
107
+ image_fail_reason . append (e )
107
108
return None
108
- copy_image (statement_dir , value )
109
- return value
109
+ return copy_image (statement_dir , value )
110
110
return None
111
111
112
112
statement_html = nh3 .clean (
@@ -126,22 +126,25 @@ def attribute_filter(tag, attribute, value):
126
126
)
127
127
128
128
if image_fail_reason :
129
- assert isinstance (image_fail_reason , str )
130
- if 'Unsupported' in image_fail_reason :
131
- raise ValueError (image_fail_reason )
132
- raise FileNotFoundError (image_fail_reason )
129
+ # We don't have a great way to emit multiple errors from here, so just re-raise the first error
130
+ raise image_fail_reason [0 ]
133
131
134
132
return statement_html
135
133
136
134
137
- def copy_image (statement_dir : Path , img_src : str ) -> None :
138
- """Copy image to output directory
135
+ def copy_image (statement_dir : Path , img_src : str ) -> str :
136
+ """Copy image to working directory (with new filename) and returns the new filename
139
137
140
138
Args:
141
139
statement_dir: the directory with problem statement files
142
140
img_src: the image source as in the Markdown statement
143
141
"""
144
142
145
- if os .path .isfile (img_src ): # already copied
146
- return
147
- shutil .copyfile (statement_dir / img_src , img_src )
143
+ # We rename to sha256 of contents, and preserve the suffix. This flattens
144
+ # the directory structure to a single folders in a simple way.
145
+ with open (statement_dir / img_src , 'rb' ) as f :
146
+ filename = hashlib .file_digest (f , 'sha256' ).hexdigest () + Path (img_src ).suffix
147
+
148
+ if not os .path .isfile (filename ): # check if already copied
149
+ shutil .copyfile (statement_dir / img_src , filename )
150
+ return filename
0 commit comments