1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
import base64
import codecs
import hashlib
import mimetypes
import os
from lektor_ng.utils import deprecated
class FileContents:
@deprecated(name="FileContents", version="3.4.0")
def __init__(self, filename):
self.filename = filename
self._md5 = None
self._sha1 = None
self._integrity = None
self._mimetype = mimetypes.guess_type(filename)[0] or "application/octet-stream"
@property
def sha1(self):
self._ensure_hashes()
return self._sha1
@property
def md5(self):
self._ensure_hashes()
return self._md5
@property
def integrity(self):
self._ensure_hashes()
return self._integrity
@property
def mimetype(self):
return self._mimetype
@property
def bytes(self):
try:
return os.stat(self.filename).st_size
except OSError:
return 0
def as_data_url(self, mediatype=None):
if mediatype is None:
mediatype = self.mimetype
return f"data:{mediatype};base64,{self.as_base64()}"
def as_text(self):
with self.open() as f:
return f.read()
def as_bytes(self):
with self.open("rb") as f:
return f.read()
def as_base64(self):
return base64.b64encode(self.as_bytes())
def open(self, mode="r", encoding=None):
if mode == "rb":
return open(self.filename, "rb")
if mode != "r":
raise TypeError("Can only open files for reading")
# pylint: disable=deprecated-method
return codecs.open(self.filename, encoding=encoding or "utf-8")
def _ensure_hashes(self):
if self._md5 is not None:
return
with self.open("rb") as f:
md5 = hashlib.md5()
sha1 = hashlib.sha1()
sha384 = hashlib.sha384()
while 1:
chunk = f.read(16384)
if not chunk:
break
md5.update(chunk)
sha1.update(chunk)
sha384.update(chunk)
self._md5 = md5.hexdigest()
self._sha1 = sha1.hexdigest()
self._integrity = "sha384-" + base64.b64encode(sha384.digest()).decode("ascii")
def __repr__(self):
return f"<FileContents {self.filename!r} md5={self.md5!r}>"
|