Jump to content

Issue with non-standard library [Python]


Recommended Posts

Sorry if it's a dumb question. I am a beginner.
 
I have tried to convert this Python script for PDF compression into an Alfred workflow. It relies on pdftops from Poppler and ps2pdf from Ghostscript. I have installed both Poppler and Ghostscript using Homebrew on Terminal. Since that, the script is fully functional on Terminal but I didn't manage to convert the code to an Alfred workflow using Alfred-Workflow helper library. It seems Alfred misses the Poppler library.

 

This is my attempt:
#!/usr/bin/python
# encoding: utf-8

from __future__ import division
import sys
import argparse
import tempfile
import subprocess
import os
import shutil
import contextlib
from workflow import Workflow

def main(wf):
 
    query = wf.args[0]
    argv = query

    def main(argv=None):

        parser = argparse.ArgumentParser(description="one weird PDF trick")
        parser.add_argument('before', nargs=1, help="PDF (before)",
                            type=extant_file)
        parser.add_argument('after', nargs="?", help="PDF (after)")
        parser.add_argument('-t', '--tempdir', help="needs a lot of temp space", required=False)

        if argv is None:
            argv = parser.parse_args()

        if argv.tempdir:
            tempfile.tempdir = argv.tempdir

        if not which('pdftops'):   # use poppler to create a .ps
            raise Exception("need pdftops from poppler")
        if not which('ps2pdf'):    # and use ghostscript to create a .pdf
            raise Exception("need ps2pdf from ghostscript")

        with make_temp_directory(prefix='popgho') as tempdir:
            main_with_temp(tempdir, argv)

    def main_with_temp(tempdir, argv):
        os.environ.update({'TMPDIR': tempdir})  # for ghostscript
        postscript = os.path.join(tempdir, 'poppler.ps')
        o_pdf = argv.before[0]
        n_pdf = os.path.join(tempdir, 'ghost.pdf')

        with open(os.devnull, "w") as f:
            subprocess.check_call(['pdftops', o_pdf, postscript],
                                  stdout=f, stderr=f)
            subprocess.check_call(['ps2pdf', postscript, n_pdf],
                                  stdout=f, stderr=f, env=os.environ)

        o_size = os.path.getsize(o_pdf)
        n_size = os.path.getsize(n_pdf)
        compression_ratio = o_size/n_size

        if (argv.after):
            shutil.move(n_pdf, argv.after)
            print("compression: {1}; created: {0}"
                  .format(argv.after, compression_ratio))
        elif (compression_ratio > 1.2):
            shutil.move(n_pdf, o_pdf)
            print("compression: {1}; overwrite: {0}"
                  .format(o_pdf, compression_ratio))
        else:
            os.remove(n_pdf)
            print("compression: {0}; not worth it, deleted new file"
                  .format(compression_ratio))
        os.remove(postscript)

    def which(program):

        def is_exe(fpath):
            return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

        fpath, fname = os.path.split(program)

        if fpath:
            if is_exe(program):
                return program

        else:
            for path in os.environ["PATH"].split(os.pathsep):
                path = path.strip('"')
                exe_file = os.path.join(path, program)
                if is_exe(exe_file):
                    return exe_file

        return None

    def extant_file(x):

        if not os.path.exists(x):
                raise argparse.ArgumentError("{0} does not exist".format(x))
        return x

    @contextlib.contextmanager

    def make_temp_directory(prefix):

        temp_dir = tempfile.mkdtemp(prefix=prefix)
        yield temp_dir
        shutil.rmtree(temp_dir)

    if __name__ == "__main__":
        sys.exit(main())

if __name__ == '__main__':

    wf = Workflow()
    sys.exit(wf.run(main))

Alfred Console:

 

[2016-06-29 20:32:20][trigger.action] Processing output of 'action.script' with arg '(

    "/Users/usuario/Desktop/test.pdf"
)'
[2016-06-29 20:32:21][ERROR: action.script] 20:32:21 workflow.py:2157 DEBUG    Workflow version : 1.0.0
20:32:21 workflow.py:2175 ERROR    need pdftops from poppler
Traceback (most recent call last):
  File "/Users/usuario/Library/Application Support/Alfred 3/Alfred.alfredpreferences/workflows/user.workflow.C3709BD1-8479-4079-B9BB-559C4B577012/workflow/workflow.py", line 2168, in run
    func(self)
  File "pdftrick.py", line 110, in main
    sys.exit(main())
  File "pdftrick.py", line 34, in main
    raise Exception("need pdftops from poppler")
Exception: need pdftops from poppler
20:32:21 workflow.py:2195 DEBUG    Workflow finished in 0.043 seconds.
Edited by xilopaint
Link to comment

It worked! Thanks again!

 

How can I bundle the workflow with Poppler and Ghostscript for distribution since they are not python packages and I could not use pip install as the instructions of Alfred-Workflow documentation?

Edited by xilopaint
Link to comment

The size is not as relevant for my question. I just intend to know how I can bundle a non-python library with the workflow in case it's possible. We can suppose just as an example that Ghostscript was 2MB instead 100+.

Edited by xilopaint
Link to comment

Sorry, I misread your post.

If you want to include a program with your workflow, put it in the workflow's directory. That's the working directory when your workflow is run.

There's no guarantee any given program will work that way, nor that it will work on any system but yours. Depends on the program.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...