Skip to content

Commit

Permalink
Merge pull request #169 from openzim/check_zim_filename
Browse files Browse the repository at this point in the history
Add utility to validate ZIM folder and filename are OK
  • Loading branch information
benoit74 authored Jun 20, 2024
2 parents baec9c1 + f4176f0 commit 05984c3
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 1 deletion.
84 changes: 84 additions & 0 deletions src/zimscraperlib/zim/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import datetime
import pathlib
import re
import tempfile
from collections.abc import Sequence

from zimscraperlib import logger
Expand Down Expand Up @@ -210,3 +211,86 @@ def make_zim_file(
raise
finally:
zim_file.finish()


class BadZimfileDataError(Exception):
"""A generic exception for any problem encountered in validate_zimfile_creatable"""

pass


class ZimFolderNotFoundError(BadZimfileDataError):
"""Exception raised in validate_zimfile_creatable when folder does not exists"""

pass


class BadZimFolderError(BadZimfileDataError):
"""Exception raised in validate_zimfile_creatable when folder is not a directory"""

pass


class ZimFolderNotWritableError(BadZimfileDataError):
"""Exception raised in validate_zimfile_creatable when folder is not writable"""

pass


class BadZimFilenameError(BadZimfileDataError):
"""
Exception raised in validate_zimfile_creatable when filename is not creatable
This usually occurs when bad characters are present in filename (typically
characters not supported on current filesystem).
"""

pass


def validate_zimfile_creatable(folder: str | pathlib.Path, filename: str):
"""Validate that a ZIM can be created in given folder with given filename
Any problem encountered raises an exception inheriting from BadZimfileDataError
Checks that:
- folder passed exists (or raise ZimFolderNotFoundError exception)
- folder passed is a directory (or raise BadZimFolderError exception)
- folder is writable, i.e. it is possible to create a file in folder (or raise
ZimFolderNotWritableError exception with inner exception details)
- filename is creatable, i.e. there is no bad characters in filename (or raise
BadZimFilenameError exception with inner exception details)
"""
folder = pathlib.Path(folder)

# ensure folder exists
if not folder.exists():
raise ZimFolderNotFoundError(
f"Folder to create the ZIM does not exist: {folder}"
)

# ensure folder is a directory
if not folder.is_dir():
raise BadZimFolderError(
f"Folder to create the ZIM is not a directory: {folder}"
)

logger.debug(f"Attempting to confirm output is writable in directory {folder}")

try:
# ensure folder is writable
with tempfile.NamedTemporaryFile(dir=folder, delete=True) as fh:
logger.debug(f"Output is writable. Temporary file used for test: {fh.name}")
except Exception as e:
raise ZimFolderNotWritableError(
f"Folder to create the ZIM is not writable: {folder}"
) from e

# ensure ZIM file is creatable with the given name
file_path = folder / filename
try:
logger.debug(f"Confirming ZIM file can be created at {file_path}")
file_path.touch()
file_path.unlink()
except Exception as e:
raise BadZimFilenameError(f"ZIM filename is not creatable: {file_path}") from e
46 changes: 45 additions & 1 deletion tests/zim/test_fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@
import pytest

from zimscraperlib.zim.archive import Archive
from zimscraperlib.zim.filesystem import FileItem, make_zim_file
from zimscraperlib.zim.filesystem import (
BadZimFilenameError,
BadZimFolderError,
FileItem,
ZimFolderNotFoundError,
ZimFolderNotWritableError,
make_zim_file,
validate_zimfile_creatable,
)


def test_fileitem(tmp_path, png_image):
Expand Down Expand Up @@ -143,3 +151,39 @@ def test_make_zim_file_no_file_on_error(tmp_path, png_image, build_data):
# create a ZIM file, so SEGFAULT on exit it (somewhat) OK
assert py.returncode in (0, 11, -6, -11) # SIGSEV is 11
assert not build_data["fpath"].exists()


@pytest.fixture(scope="module")
def valid_zim_filename():
return "myfile.zim"


def test_validate_zimfile_creatable_ok(tmp_path, valid_zim_filename):

validate_zimfile_creatable(tmp_path, valid_zim_filename)


def test_validate_zimfile_creatable_folder_not_exists(tmp_path, valid_zim_filename):

with pytest.raises(ZimFolderNotFoundError):
validate_zimfile_creatable(tmp_path / "foo", valid_zim_filename)


def test_validate_zimfile_creatable_bad_folder(tmp_path, valid_zim_filename):

with pytest.raises(BadZimFolderError):
(tmp_path / "foo.txt").touch()
validate_zimfile_creatable(tmp_path / "foo.txt", valid_zim_filename)


def test_validate_zimfile_creatable_folder_not_writable(tmp_path, valid_zim_filename):

with pytest.raises(ZimFolderNotWritableError):
(tmp_path / "foo").mkdir(mode=111)
validate_zimfile_creatable(tmp_path / "foo", valid_zim_filename)


def test_validate_zimfile_creatable_bad_name(tmp_path):

with pytest.raises(BadZimFilenameError):
validate_zimfile_creatable(tmp_path, "t\0t\0.zim")

0 comments on commit 05984c3

Please sign in to comment.