Merge remote-tracking branch 'origin/pr/5236'
This commit is contained in:
commit
60dae30aa0
|
|
@ -230,9 +230,16 @@ def suggested_fn_from_title(url_path, title=None):
|
|||
|
||||
suggested_fn = None # type: typing.Optional[str]
|
||||
if ext.lower() in ext_whitelist and title:
|
||||
suggested_fn = utils.sanitize_filename(title)
|
||||
suggested_fn = utils.sanitize_filename(
|
||||
title,
|
||||
max_bytes=(255 - len("(123).download"))
|
||||
)
|
||||
if not suggested_fn.lower().endswith((".html", ".htm")):
|
||||
suggested_fn += ".html"
|
||||
suggested_fn = utils.sanitize_filename(
|
||||
suggested_fn,
|
||||
max_bytes=(255 - len("(123).download"))
|
||||
)
|
||||
|
||||
return suggested_fn
|
||||
|
||||
|
|
|
|||
|
|
@ -520,7 +520,8 @@ def force_encoding(text: str, encoding: str) -> str:
|
|||
|
||||
|
||||
def sanitize_filename(name: str,
|
||||
replacement: typing.Optional[str] = '_') -> str:
|
||||
replacement: typing.Optional[str] = '_',
|
||||
max_bytes: typing.Optional[int] = None) -> str:
|
||||
"""Replace invalid filename characters.
|
||||
|
||||
Note: This should be used for the basename, as it also removes the path
|
||||
|
|
@ -529,6 +530,7 @@ def sanitize_filename(name: str,
|
|||
Args:
|
||||
name: The filename.
|
||||
replacement: The replacement character (or None).
|
||||
max_bytes: The biggest length in bytes allowed (or None, which is ∞).
|
||||
"""
|
||||
if replacement is None:
|
||||
replacement = ''
|
||||
|
|
@ -550,6 +552,34 @@ def sanitize_filename(name: str,
|
|||
|
||||
for bad_char in bad_chars:
|
||||
name = name.replace(bad_char, replacement)
|
||||
|
||||
if max_bytes:
|
||||
# Truncate the filename if it's too long.
|
||||
root, ext = os.path.splitext(name)
|
||||
root = root[:max_bytes - len(ext)]
|
||||
excess = len(os.fsencode(root + ext)) - max_bytes
|
||||
|
||||
while excess > 0 and root:
|
||||
# Max 4 bytes per character is assumed.
|
||||
# Integer division floors to -∞, not to 0.
|
||||
root = root[:(-excess // 4)]
|
||||
excess = len(os.fsencode(root + ext)) - max_bytes
|
||||
|
||||
if not root:
|
||||
# Trimming the root is not enough. We must trim the extension.
|
||||
# We leave one character in the root, so that the filename
|
||||
# doesn't start with a dot, which makes the file hidden.
|
||||
root = name[0]
|
||||
excess = len(os.fsencode(root + ext)) - max_bytes
|
||||
while excess > 0 and ext:
|
||||
ext = ext[:(-excess // 4)]
|
||||
excess = len(os.fsencode(root + ext)) - max_bytes
|
||||
|
||||
if not ext:
|
||||
raise ValueError("max_bytes is too small")
|
||||
|
||||
name = root + ext
|
||||
|
||||
return name
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -644,6 +644,13 @@ def test_sanitize_filename_empty_replacement():
|
|||
assert utils.sanitize_filename(name, replacement=None) == 'Bad File'
|
||||
|
||||
|
||||
@hypothesis.given(filename=strategies.text(min_size=100),
|
||||
max_bytes=strategies.integers(min_value=50))
|
||||
def test_sanitize_filename_invariants(filename, max_bytes):
|
||||
sanitized = utils.sanitize_filename(filename, max_bytes=max_bytes)
|
||||
assert len(os.fsencode(sanitized)) <= max_bytes
|
||||
|
||||
|
||||
class TestGetSetClipboard:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
|
|
|||
Loading…
Reference in New Issue