diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 083611e..7bfccdd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,10 +9,6 @@ repos: - id: check-yaml - id: debug-statements - id: check-merge-conflict - - repo: https://github.com/asottile/seed-isort-config - rev: v1.8.0 - hooks: - - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort rev: 'v5.0.9' hooks: diff --git a/.travis.yml b/.travis.yml index 9f853ca..0acf19e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,15 +3,15 @@ sudo: true language: python dist: xenial -install: +before_install: - sudo rm -f /etc/ImageMagick-6/policy.xml - - sudo apt-get install xvfb libreoffice libfile-mimeinfo-perl inkscape poppler-utils qpdf imagemagick libimage-exiftool-perl ufraw-batch ffmpeg ghostscript libsecret-1-0 -y + # main requirements + - sudo apt-get install -y poppler-utils qpdf libfile-mimeinfo-perl libimage-exiftool-perl ghostscript libsecret-1-0 + # optionals + - sudo apt-get install libreoffice inkscape ufraw-batch ffmpeg xvfb - DRAWIO_VERSION="12.6.5" && curl -LO https://github.com/jgraph/drawio-desktop/releases/download/v${DRAWIO_VERSION}/draw.io-amd64-${DRAWIO_VERSION}.deb && sudo dpkg -i draw.io-amd64-${DRAWIO_VERSION}.deb - - pip install xvfbwrapper - - python setup.py install - - pip install pytest - - python3 -m pip install -U mypy==0.770 - +install: + - pip install ".[all, testing]" before_script: - export DISPLAY=:99.0 - which Xvfb @@ -28,6 +28,8 @@ jobs: - stage: static-tests name: fmt python: "3.7" + before_install: skip + install: skip before_script: - pip install black isort script: @@ -38,6 +40,8 @@ jobs: - stage: static-tests name: flake8 python: "3.7" + before_install: skip + install: skip before_script: - pip install flake8 script: @@ -46,8 +50,10 @@ jobs: - stage: static-tests name: mypy python: "3.7" + before_install: skip + install: skip before_script: - - pip install mypy + - pip install mypy==0.770 script: - mypy --version - mypy --ignore-missing-imports --disallow-untyped-defs . diff --git a/README.rst b/README.rst index 0dbee42..c489965 100644 --- a/README.rst +++ b/README.rst @@ -47,7 +47,7 @@ Those file formats are generated using libreoffice. The preview generation has a default timeout of 60 seconds. It is possible to change this timeout by setting the `LIBREOFFICE_PROCESS_TIMEOUT` environment variable to a number of seconds. Setting a zero or negative value for this variable will disable the timeout. - + Archive file ~~~~~~~~~~~~ @@ -69,25 +69,133 @@ Video format Installation ------------ -Dependencies: - -``apt-get install zlib1g-dev libjpeg-dev python3-pythonmagick inkscape xvfb poppler-utils libfile-mimeinfo-perl qpdf libimage-exiftool-perl ufraw-batch ffmpeg`` -After installing dependencies, you can install preview-generator using ``pip``:: +Mandatory Dependencies: +~~~~~~~~~~~~~~~~~~~~~~~ - pip install preview-generator +On debian : -Optional dependencies: +```bash +apt-get install poppler-utils qpdf libfile-mimeinfo-perl libimage-exiftool-perl ghostscript libsecret-1-0 zlib1g-dev libjpeg-dev +``` -To handle previews for office documents you will need ``LibreOffice``, if you don't have it already:: +install preview_generator without external addons: - apt-get install libreoffice +```bash +pip install preview-generator +``` +To install all previews builders dependencies: +```bash +pip install preview-generator[all] +sudo apt-get install libreoffice inkscape ufraw-batch ffmpeg xvfb +DRAWIO_VERSION="12.6.5" && curl -LO https://github.com/jgraph/drawio-desktop/releases/download/v${DRAWIO_VERSION}/draw.io-amd64-${DRAWIO_VERSION}.deb && sudo dpkg -i draw.io-amd64-${DRAWIO_VERSION}.deb +``` To check dependencies, you can run:: preview --check-dependencies +Office Files (LibreOffice) +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +```bash +apt-get install libreoffice +``` + +DTP(Scribus) +~~~~~~~~~~~~ +If you need to preview scribus `.sla` files you will need scribus >= 1.5. + +On debian : + +```bash +apt-get install scribus xvfb +pip install preview-generator[scribus] +``` + + +If scribus >=1.5 is not available in your distribution you can use an AppImage. + +Download the last AppImage from the official website https://www.scribus.net/downloads/unstable-branch/ + +.. code:: console + + mv /path/to/image/scribus-x.y.appimage /usr/local/bin/scribus + chmod +x /usr/local/bin/scribus + + +Vector Images (Inkscape) +~~~~~~~~~~~~~~~~~~~~~~~~ + +on debian: + +```bash +apt-get install inkscape +``` + + +Vector Images (cairosvg) +~~~~~~~~~~~~~~~~~~~~~~~~ + +```bash +pip install preview-generator[cairosvg] +``` + +Video(ffmpeg) +~~~~~~~~~~~~~ + +On debian : + +```bash +apt-get install ffmpeg +pip install preview-generator[video] +``` + +RAW Images(ufraw-batch) +~~~~~~~~~~~~~ + +On debian : + +```bash +apt-get install ufraw-batch +``` + +Diagram(DrawIO) +~~~~~~~~~~~~~~~ + +1. install xvfb +2.install [draw-io package](https://github.com/jgraph/drawio-desktop/releases): +3.install python specific dependencies: + +on debian: + +```bash +apt install xvfb +DRAWIO_VERSION="12.6.5" && curl -LO https://github.com/jgraph/drawio-desktop/releases/download/v${DRAWIO_VERSION}/draw.io-amd64-${DRAWIO_VERSION}.deb && sudo dpkg -i draw.io-amd64-${DRAWIO_VERSION}.deb +pip install preview-generator[drawio] +``` + + +3D files (VTK) +~~~~~~~~~~~~~~ + +:warning: VTK lib provided from pypi may not be builded for latest python version. You +can either decide to downgrade python version or build VTK yourself to make things work as expected. + +On debian : + +```bash +pip install preview-generator[3D] +``` + +HEIC support +~~~~~~~~~~~~ + +Building ImageMagick with heic support: `Building ImageMagick with heic support`_ . + +.. _`Building ImageMagick with heic support`: doc/build_im_with_heic_support.rst + ----- Usage @@ -328,20 +436,7 @@ will print Preview created at path : the_zip-a733739af8006558720be26c4dc5569a.txt ------------- -HEIC support ------------- - -Building ImageMagick with heic support: `Building ImageMagick with heic support`_ . -.. _`Building ImageMagick with heic support`: doc/build_im_with_heic_support.rst - ---------------- -Draw.io support ---------------- - -1. install package ``xvfb``. -2. install draw-io package ------------ Known Issues diff --git a/contribute.rst b/contribute.rst index cc15866..95c725a 100644 --- a/contribute.rst +++ b/contribute.rst @@ -44,45 +44,10 @@ From scratch on a terminal : * build your virtual env (env will be called "myenv", you can name it the way you want): `python3 -m venv myenv` * if it's not already, activate it : `source myenv/bin/activate`. (`deactivate` to deactivate) - install dependencies : + * `apt-get install poppler-utils qpdf libfile-mimeinfo-perl libimage-exiftool-perl ghostscript libsecret-1-0 zlib1g-dev libjpeg-dev` + * `pip install -e ".[dev, all]"` + * install external apt dependencies for specific builder (see README.md) - * `apt-get install libimage-exiftool-perl` - * `apt-get install zlib1g-dev` - * `apt-get install libjpeg-dev` - * `apt-get install python3-pythonmagick` - * `apt-get install inkscape` - * `apt-get install xvfb` - * `apt-get install poppler-utils` - * `apt-get install qpdf` - * `apt-get install libfile-mimeinfo-perl` - * `apt-get install ufraw-batch` - * `apt-get install ffmpeg` - * `pip install wand` - * `pip install Pillow` - * `pip install PyPDF2` - * `pip install python-magic` - * `pip install pyexifinfo` - * `pip install packaging` - * `pip install xvfbwrapper` - * `pip install pdf2image` - * `pip install pathlib` - * if you use python 3.5 or less `pip install typing` - - -.. code:: console - - # general dependencies - apt-get install zlib1g-dev libjpeg-dev python3-pythonmagick inkscape xvfb poppler-utils qpdf libfile-mimeinfo-perl libimage-exiftool-perl - pip install wand Pillow PyPDF2 python-magic pyexifinfo packaging xvfbwrapper pdf2image pathlib - -If you need to preview scribus `.sla` files you will need scribus >= 1.5. -If it's not available in your distribution you can use an AppImage. - -Download the last AppImage from the official website https://www.scribus.net/downloads/unstable-branch/ - -.. code:: console - - mv /path/to/image/scribus-x.y.appimage /usr/local/bin/scribus - chmod +x /usr/local/bin/scribus ----------------- Code Convention : diff --git a/preview_generator/preview/builder/document__drawio.py b/preview_generator/preview/builder/document__drawio.py index 213f164..9b4fd62 100644 --- a/preview_generator/preview/builder/document__drawio.py +++ b/preview_generator/preview/builder/document__drawio.py @@ -5,8 +5,6 @@ import tempfile import typing -from xvfbwrapper import Xvfb - from preview_generator.exception import BuilderDependencyNotFound from preview_generator.exception import IntermediateFileBuildingFailed from preview_generator.preview.builder.image__pillow import ImagePreviewBuilderPillow @@ -15,12 +13,20 @@ from preview_generator.utils import MimetypeMapping from preview_generator.utils import executable_is_available +xvfbwrapper_installed = True +try: + from xvfbwrapper import Xvfb +except ImportError: + xvfbwrapper_installed = False + class ImagePreviewBuilderDrawio(PreviewBuilder): DRAWIO_MIMETYPES_MAPPING = [MimetypeMapping("application/drawio", ".drawio")] @classmethod def check_dependencies(cls) -> None: + if not xvfbwrapper_installed: + raise BuilderDependencyNotFound("this builder requires xvfbwrapper") if not executable_is_available("xvfb-run"): raise BuilderDependencyNotFound("this builder requires xvfb-run to be available") diff --git a/preview_generator/preview/builder/document__scribus.py b/preview_generator/preview/builder/document__scribus.py index e68f6d0..b78fe90 100644 --- a/preview_generator/preview/builder/document__scribus.py +++ b/preview_generator/preview/builder/document__scribus.py @@ -10,8 +10,6 @@ from subprocess import check_output import typing -from xvfbwrapper import Xvfb - from preview_generator.exception import BuilderDependencyNotFound from preview_generator.extension import mimetypes_storage from preview_generator.preview.builder.document_generic import DocumentPreviewBuilder @@ -20,6 +18,12 @@ from preview_generator.utils import LOGGER_NAME from preview_generator.utils import executable_is_available +xvfbwrapper_installed = True +try: + from xvfbwrapper import Xvfb +except ImportError: + xvfbwrapper_installed = False + SCRIPT_FOLDER_NAME = "scripts" SCRIPT_NAME = "scribus_sla_to_pdf.py" parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -29,6 +33,8 @@ class DocumentPreviewBuilderScribus(DocumentPreviewBuilder): @classmethod def check_dependencies(cls) -> None: + if not xvfbwrapper_installed: + raise BuilderDependencyNotFound("this builder requires xvfbwrapper") if not executable_is_available("scribus"): raise BuilderDependencyNotFound("this builder requires scribus to be available") diff --git a/preview_generator/preview/builder/image__cairosvg.py b/preview_generator/preview/builder/image__cairosvg.py index 959801f..cac0cf5 100644 --- a/preview_generator/preview/builder/image__cairosvg.py +++ b/preview_generator/preview/builder/image__cairosvg.py @@ -3,12 +3,18 @@ import tempfile import typing -import cairosvg - +# HACK - G.M - 2020-12-26 - Hack to allow loading modules without cairosvg installed +from preview_generator.exception import BuilderDependencyNotFound from preview_generator.preview.builder.image__pillow import ImagePreviewBuilderPillow # nopep8 from preview_generator.preview.generic_preview import ImagePreviewBuilder from preview_generator.utils import ImgDims +cairosvg_installed = True +try: + import cairosvg +except ImportError: + cairosvg_installed = False + class ImagePreviewBuilderCairoSVG(ImagePreviewBuilder): """ @@ -23,6 +29,11 @@ def get_label(cls) -> str: def get_supported_mimetypes(cls) -> typing.List[str]: return ["image/svg+xml", "image/svg"] + @classmethod + def check_dependencies(cls) -> None: + if not cairosvg_installed: + raise BuilderDependencyNotFound("this builder requires cairosvg to be available") + def build_jpeg_preview( self, file_path: str, diff --git a/preview_generator/preview/builder/video__ffmpeg.py b/preview_generator/preview/builder/video__ffmpeg.py index 2b30673..77ec376 100644 --- a/preview_generator/preview/builder/video__ffmpeg.py +++ b/preview_generator/preview/builder/video__ffmpeg.py @@ -1,14 +1,21 @@ # -*- coding: utf-8 -*- import json +from shutil import which +from subprocess import check_output import typing -import ffmpeg - from preview_generator import utils +from preview_generator.exception import BuilderDependencyNotFound from preview_generator.exception import PreviewGeneratorException from preview_generator.preview.generic_preview import PreviewBuilder +ffmpeg_installed = True +try: + import ffmpeg +except ImportError: + ffmpeg_installed = False + class NoVideoStream(PreviewGeneratorException): pass @@ -21,6 +28,18 @@ class VideoPreviewBuilderFFMPEG(PreviewBuilder): def get_label(cls) -> str: return "Video files - based on ffmpeg" + @classmethod + def check_dependencies(cls) -> None: + if not ffmpeg_installed: + raise BuilderDependencyNotFound("this builder requires ffmpeg to be available") + + @classmethod + def dependencies_versions(cls) -> typing.Optional[str]: + return "{} from {}".format( + check_output(["ffmpeg", "-version"], universal_newlines=True).strip().split("\n")[0], + which("ffmpeg"), + ) + @classmethod def get_supported_mimetypes(cls) -> typing.List[str]: return [ diff --git a/setup.cfg b/setup.cfg index 576f3b6..931a9c9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,8 +9,6 @@ force_grid_wrap = 0 use_parentheses = true skip_glob = .eggs*,.venv extra_standard_library = hashlib, logging, mimetype, typing, os, sys, abc, io, json, datetime, subprocess, tempfile, shutil, argparse -known_third_party =PIL,PyPDF2,cairosvg,ffmpeg,filelock,magic,pdf2image,pyexifinfo,pytablewriter,pytest,scribus,wand,xvfbwrapper -known_first_party = preview_generator [flake8] max-line-length = 100 show-source = True diff --git a/setup.py b/setup.py index 726c61b..6dd83b3 100644 --- a/setup.py +++ b/setup.py @@ -32,15 +32,16 @@ testpkgs = [] # type: List[str] install_requires = [ + # mimetype_guessing "python-magic", + # wand builder "Wand", + # commons + "pdf2image", "PyPDF2", "pyexifinfo", - "xvfbwrapper", "pathlib", "pdf2image", - "cairosvg", - "ffmpeg-python", "filelock", ] @@ -51,8 +52,29 @@ install_requires.append("Pillow") tests_require = ["pytest"] - devtools_require = ["flake8", "isort", "mypy", "pre-commit"] +cairo_require = ["cairosvg"] +scribus_require = drawio_require = ["xvfbwrapper"] +video_require = ["ffmpeg-python"] +cad3d_require = ["vtk"] + +# TODO - G.M - 2021-06-18 - restore vtk as normal requirement, vtk is not compatible +# with current version of python see https://gitlab.kitware.com/vtk/vtk/-/issues/18074, +all_require = [cairo_require, scribus_require, video_require, drawio_require] +if py_version < (3, 9): + all_require.append(cad3d_require) + +extras_require = { + "cairosvg": cairo_require, + "drawio": drawio_require, + "scribus": scribus_require, + "video": video_require, + "3D": cad3d_require, + "all": all_require, + # specials + "testing": tests_require, + "dev": tests_require + devtools_require, +} # add black for python 3.6+ if sys.version_info.major == 3 and sys.version_info.minor >= 6: @@ -61,11 +83,6 @@ if py_version <= (3, 4): install_requires.append("typing") -# TODO - G.M - 2019-11-05 - restore vtk as normal requirement, vtk is not compatible -# with current version of vtk see https://gitlab.kitware.com/vtk/vtk/issues/17670, -if py_version < (3, 8): - install_requires.append("vtk") - setup( name="preview_generator", version=infos.__version__, @@ -94,7 +111,7 @@ install_requires=install_requires, python_requires=">= 3.5", include_package_data=True, - extras_require={"testing": tests_require, "dev": tests_require + devtools_require}, + extras_require=extras_require, test_suite="py.test", # TODO : change test_suite tests_require=testpkgs, package_data={"preview_generator": ["i18n/*/LC_MESSAGES/*.mo", "templates/*/*", "public/*/*"]}, diff --git a/tests/input/stl/test_stl_vtk.py b/tests/input/stl/test_stl_vtk.py index 6af8c70..8b8edb9 100644 --- a/tests/input/stl/test_stl_vtk.py +++ b/tests/input/stl/test_stl_vtk.py @@ -22,9 +22,7 @@ def setup_function(function: typing.Callable) -> None: shutil.rmtree(CACHE_DIR, ignore_errors=True) -@pytest.mark.xfail( - sys.version_info[:2] >= (3, 8), reason="vtk support for python 3.8 and later is broken" -) +@pytest.mark.xfail(sys.version_info[:2] >= (3, 9), reason="vtk support for python 3.9+ broken") def test_to_jpeg() -> None: os.makedirs(CACHE_DIR) builder = ImagePreviewBuilderVtk() @@ -48,9 +46,7 @@ def test_to_jpeg() -> None: assert jpeg.width == 512 -@pytest.mark.xfail( - sys.version_info[:2] >= (3, 8), reason="vtk support for python 3.8 and later is broken" -) +@pytest.mark.xfail(sys.version_info[:2] >= (3, 9), reason="vtk support for python 3.9+ broken") def test_get_nb_page() -> None: os.makedirs(CACHE_DIR) builder = ImagePreviewBuilderVtk()