Remove _errors and ghostscript test
parent
9879a87c6f
commit
4938c48853
|
|
@ -4,6 +4,7 @@
|
|||
ghostscript - A Python interface for the Ghostscript interpreter C-API
|
||||
"""
|
||||
#
|
||||
# Modifications 2018 by Vinayak Mehta <vmehta94@gmail.com>
|
||||
# Copyright 2010-2018 by Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
|
@ -20,60 +21,22 @@ ghostscript - A Python interface for the Ghostscript interpreter C-API
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2010-2018 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3)"
|
||||
__version__ = '0.6'
|
||||
|
||||
__all__ = ['Ghostscript', 'revision',
|
||||
'GhostscriptError', 'PleaseDisplayUsage']
|
||||
|
||||
import atexit
|
||||
from . import _gsprint as gs
|
||||
|
||||
|
||||
GhostscriptError = gs.GhostscriptError
|
||||
__author__ = 'Hartmut Goebel <h.goebel@crazy-compilers.com>'
|
||||
__copyright__ = 'Copyright 2010-2018 by Hartmut Goebel <h.goebel@crazy-compilers.com>'
|
||||
__license__ = 'GNU General Public License version 3 (GPL v3)'
|
||||
__version__ = '0.6'
|
||||
|
||||
|
||||
def PleaseDisplayUsage(Warning):
|
||||
"""
|
||||
This exception is raised when Ghostscript asks the application to
|
||||
display the usage. The application should catch the exception an
|
||||
print the usage message.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def revision():
|
||||
"""
|
||||
This function returns the revision numbers and strings of the
|
||||
Ghostscript interpreter library as a dict. You should call it
|
||||
before any other interpreter library functions to make sure that
|
||||
the correct version of the Ghostscript interpreter has been
|
||||
loaded.
|
||||
"""
|
||||
rev = gs.revision()
|
||||
return dict((f, getattr(rev, f)) for f, _ in rev._fields_)
|
||||
|
||||
|
||||
MAX_STRING_LENGTH = gs.MAX_STRING_LENGTH
|
||||
|
||||
|
||||
class Ghostscript(object):
|
||||
@staticmethod
|
||||
def revision():
|
||||
return revision()
|
||||
|
||||
class __Ghostscript(object):
|
||||
def __init__(self, instance, args, stdin=None, stdout=None, stderr=None):
|
||||
self._initialized = False
|
||||
self._callbacks = None
|
||||
if stdin or stdout or stderr:
|
||||
self.set_stdio(stdin, stdout, stderr)
|
||||
rc = gs.init_with_args(instance, args)
|
||||
if rc == gs.e_Info:
|
||||
raise PleaseDisplayUsage
|
||||
self._initialized = True
|
||||
if rc == gs.e_Quit:
|
||||
self.exit()
|
||||
|
|
@ -117,15 +80,10 @@ class Ghostscript(object):
|
|||
self._initialized = False
|
||||
|
||||
|
||||
__Ghostscript = Ghostscript
|
||||
__instance__ = None
|
||||
|
||||
|
||||
def Ghostscript(*args, **kwargs):
|
||||
"""Factory function for setting up a Ghostscript instance
|
||||
"""
|
||||
Factory function for setting up a Ghostscript instance
|
||||
"""
|
||||
global __instance__, __object_count__
|
||||
global __instance__
|
||||
# Ghostscript only supports a single instance
|
||||
if __instance__ is None:
|
||||
__instance__ = gs.new_instance()
|
||||
|
|
@ -133,3 +91,6 @@ def Ghostscript(*args, **kwargs):
|
|||
stdin=kwargs.get('stdin', None),
|
||||
stdout=kwargs.get('stdout', None),
|
||||
stderr=kwargs.get('stderr', None))
|
||||
|
||||
|
||||
__instance__ = None
|
||||
|
|
|
|||
|
|
@ -1,123 +0,0 @@
|
|||
"""
|
||||
Definition of Ghostscript error codes
|
||||
"""
|
||||
#
|
||||
# Copyright (C) 2010-2018 by Hartmut Goebel
|
||||
#
|
||||
# Based on iapi.h which is
|
||||
# Copyright (C) 1989, 1995, 1998, 1999 Aladdin Enterprises. All rights reserved.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2010-2018 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3)"
|
||||
__version__ = "0.6"
|
||||
|
||||
|
||||
LEVEL1_ERROR_NAMES = ["unknownerror", "dictfull", "dictstackoverflow",
|
||||
"dictstackunderflow", "execstackoverflow",
|
||||
"interrupt", "invalidaccess", "invalidexit",
|
||||
"invalidfileaccess", "invalidfont",
|
||||
"invalidrestore", "ioerror", "limitcheck",
|
||||
"nocurrentpoint", "rangecheck", "stackoverflow",
|
||||
"stackunderflow", "syntaxerror", "timeout",
|
||||
"typecheck", "undefined", "undefinedfilename",
|
||||
"undefinedresult", "unmatchedmark", "VMerror"]
|
||||
|
||||
LEVEL2_ERROR_NAMES = ["configurationerror", "invalidcontext",
|
||||
"undefinedresource", "unregistered",
|
||||
"invalidid"]
|
||||
|
||||
ERROR_NAMES = LEVEL1_ERROR_NAMES + LEVEL2_ERROR_NAMES
|
||||
|
||||
PSEUDO_ERROR_NAMES = ['Fatal', 'Quit', 'InterpreterExit', 'RemapColor',
|
||||
'ExecStackUnderflow', 'VMreclaim', 'NeedInput',
|
||||
'NeedStdin', 'NeedStdout', 'NeedStderr', 'Info']
|
||||
|
||||
|
||||
def error2name(ecode):
|
||||
if ecode <= e_Fatal:
|
||||
return PSEUDO_ERROR_NAMES[-ecode-100]
|
||||
else:
|
||||
return ERROR_NAMES[-ecode-1]
|
||||
|
||||
|
||||
#
|
||||
# Internal code for a fatal error.
|
||||
# gs_interpret also returns this for a .quit with a positive exit code.
|
||||
#
|
||||
e_Fatal = -100
|
||||
|
||||
#
|
||||
# Internal code for the .quit operator.
|
||||
# The real quit code is an integer on the operand stack.
|
||||
# gs_interpret returns this only for a .quit with a zero exit code.
|
||||
#
|
||||
e_Quit = -101
|
||||
|
||||
#
|
||||
# Internal code for a normal exit from the interpreter.
|
||||
# Do not use outside of interp.c.
|
||||
#
|
||||
e_InterpreterExit = -102
|
||||
|
||||
#
|
||||
# Internal code that indicates that a procedure has been stored in the
|
||||
# remap_proc of the graphics state, and should be called before retrying
|
||||
# the current token. This is used for color remapping involving a call
|
||||
# back into the interpreter -- inelegant, but effective.
|
||||
#
|
||||
e_RemapColor = -103
|
||||
|
||||
#
|
||||
# Internal code to indicate we have underflowed the top block
|
||||
# of the e-stack.
|
||||
#
|
||||
e_ExecStackUnderflow = -104
|
||||
|
||||
#
|
||||
# Internal code for the vmreclaim operator with a positive operand.
|
||||
# We need to handle this as an error because otherwise the interpreter
|
||||
# won't reload enough of its state when the operator returns.
|
||||
#
|
||||
e_VMreclaim = -105
|
||||
|
||||
#
|
||||
# Internal code for requesting more input from run_string.
|
||||
#
|
||||
e_NeedInput = -106
|
||||
|
||||
#
|
||||
# Internal code for stdin callout.
|
||||
#
|
||||
e_NeedStdin = -107
|
||||
|
||||
#
|
||||
# Internal code for stdout callout.
|
||||
#
|
||||
e_NeedStdout = -108
|
||||
|
||||
#
|
||||
# Internal code for stderr callout.
|
||||
#
|
||||
e_NeedStderr = -109
|
||||
|
||||
#
|
||||
# Internal code for a normal exit when usage info is displayed.
|
||||
# This allows Window versions of Ghostscript to pause until
|
||||
# the message can be read.
|
||||
#
|
||||
e_Info = -110
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
ghostscript._gsprint - A low-level interface to the Ghostscript C-API using ctypes
|
||||
"""
|
||||
#
|
||||
# Modifications 2018 by Vinayak Mehta <vmehta94@gmail.com>
|
||||
# Copyright 2010-2018 by Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
#
|
||||
# Display_callback Structure by Lasse Fister <commander@graphicore.de> in 2013
|
||||
|
|
@ -22,62 +23,38 @@ ghostscript._gsprint - A low-level interface to the Ghostscript C-API using ctyp
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2010-2018 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3)"
|
||||
__version__ = "0.6"
|
||||
|
||||
import sys
|
||||
from ctypes import *
|
||||
|
||||
from ._errors import e_Quit, e_Info
|
||||
|
||||
# base/gserrors.h
|
||||
#
|
||||
# Internal code for a normal exit when usage info is displayed.
|
||||
# This allows Window versions of Ghostscript to pause until
|
||||
# the message can be read.
|
||||
#
|
||||
e_Info = -110
|
||||
|
||||
MAX_STRING_LENGTH = 65535
|
||||
#
|
||||
# Internal code for the .quit operator.
|
||||
# The real quit code is an integer on the operand stack.
|
||||
# gs_interpret returns this only for a .quit with a zero exit code.
|
||||
#
|
||||
e_Quit = -101
|
||||
|
||||
__author__ = 'Hartmut Goebel <h.goebel@crazy-compilers.com>'
|
||||
__copyright__ = 'Copyright 2010-2018 by Hartmut Goebel <h.goebel@crazy-compilers.com>'
|
||||
__license__ = 'GNU General Public License version 3 (GPL v3)'
|
||||
__version__ = '0.6'
|
||||
|
||||
gs_main_instance = c_void_p
|
||||
display_callback = c_void_p
|
||||
|
||||
|
||||
class Revision(Structure):
|
||||
_fields_ = [
|
||||
("product", c_char_p),
|
||||
("copyright", c_char_p),
|
||||
("revision", c_long),
|
||||
("revisiondate", c_long)
|
||||
]
|
||||
# https://www.ghostscript.com/doc/current/API.htm
|
||||
|
||||
|
||||
class GhostscriptError(Exception):
|
||||
def __init__(self, ecode):
|
||||
# :todo:
|
||||
Exception.__init__(self, error2name(ecode))
|
||||
self.code = ecode
|
||||
|
||||
|
||||
def revision():
|
||||
"""
|
||||
Get version numbers and strings.
|
||||
|
||||
This is safe to call at any time.
|
||||
You should call this first to make sure that the correct version
|
||||
of the Ghostscript is being used.
|
||||
|
||||
Returns a Revision instance
|
||||
"""
|
||||
revision = Revision()
|
||||
rc = libgs.gsapi_revision(pointer(revision), sizeof(revision))
|
||||
if rc:
|
||||
raise ArgumentError("Revision structure size is incorrect, "
|
||||
"requires %s bytes" % rc)
|
||||
return revision
|
||||
|
||||
|
||||
def new_instance(): # display_callback=None):
|
||||
"""
|
||||
Create a new instance of Ghostscript
|
||||
def new_instance():
|
||||
"""Create a new instance of Ghostscript
|
||||
|
||||
This instance is passed to most other API functions.
|
||||
"""
|
||||
|
|
@ -91,8 +68,7 @@ def new_instance(): # display_callback=None):
|
|||
|
||||
|
||||
def delete_instance(instance):
|
||||
"""
|
||||
Destroy an instance of Ghostscript
|
||||
"""Destroy an instance of Ghostscript
|
||||
|
||||
Before you call this, Ghostscript must have finished.
|
||||
If Ghostscript has been initialised, you must call exit()
|
||||
|
|
@ -105,11 +81,9 @@ c_stdstream_call_t = CFUNCTYPE(c_int, gs_main_instance, POINTER(c_char), c_int)
|
|||
|
||||
|
||||
def _wrap_stdin(infp):
|
||||
"""
|
||||
Wrap a filehandle into a C function to be used as `stdin` callback
|
||||
"""Wrap a filehandle into a C function to be used as `stdin` callback
|
||||
for ``set_stdio``. The filehandle has to support the readline() method.
|
||||
"""
|
||||
|
||||
def _wrap(instance, dest, count):
|
||||
try:
|
||||
data = infp.readline(count)
|
||||
|
|
@ -127,12 +101,10 @@ def _wrap_stdin(infp):
|
|||
|
||||
|
||||
def _wrap_stdout(outfp):
|
||||
"""
|
||||
Wrap a filehandle into a C function to be used as `stdout` or
|
||||
"""Wrap a filehandle into a C function to be used as `stdout` or
|
||||
`stderr` callback for ``set_stdio``. The filehandle has to support the
|
||||
write() and flush() methods.
|
||||
"""
|
||||
|
||||
def _wrap(instance, str, count):
|
||||
outfp.write(str[:count])
|
||||
outfp.flush()
|
||||
|
|
@ -145,8 +117,7 @@ _wrap_stderr = _wrap_stdout
|
|||
|
||||
|
||||
def set_stdio(instance, stdin, stdout, stderr):
|
||||
"""
|
||||
Set the callback functions for stdio.
|
||||
"""Set the callback functions for stdio.
|
||||
|
||||
``stdin``, ``stdout`` and ``stderr`` have to be ``ctypes``
|
||||
callback functions matching the ``_gsprint.c_stdstream_call_t``
|
||||
|
|
@ -173,13 +144,8 @@ def set_stdio(instance, stdin, stdout, stderr):
|
|||
return rc
|
||||
|
||||
|
||||
# :todo: set_poll (instance, int(*poll_fn)(void *caller_handle));
|
||||
# :todo: set_display_callback(instance, callback):
|
||||
|
||||
|
||||
def init_with_args(instance, argv):
|
||||
"""
|
||||
Initialise the interpreter.
|
||||
"""Initialise the interpreter
|
||||
|
||||
1. If quit or EOF occur during init_with_args(), the return value
|
||||
will be e_Quit. This is not an error. You must call exit() and
|
||||
|
|
@ -200,8 +166,7 @@ def init_with_args(instance, argv):
|
|||
|
||||
|
||||
def exit(instance):
|
||||
"""
|
||||
Exit the interpreter
|
||||
"""Exit the interpreter
|
||||
|
||||
This must be called on shutdown if init_with_args() has been
|
||||
called, and just before delete_instance()
|
||||
|
|
@ -230,7 +195,7 @@ def __win32_finddll():
|
|||
# Look up different variants of Ghostscript and take the highest
|
||||
# version for which the DLL is to be found in the filesystem.
|
||||
for key_name in ('AFPL Ghostscript', 'Aladdin Ghostscript',
|
||||
'GPL Ghostscript', 'GNU Ghostscript'):
|
||||
'GNU Ghostscript', 'GPL Ghostscript'):
|
||||
try:
|
||||
k1 = OpenKey(HKEY_LOCAL_MACHINE, "Software\\%s" % key_name)
|
||||
for num in range(0, QueryInfoKey(k1)[0]):
|
||||
|
|
@ -256,17 +221,18 @@ def __win32_finddll():
|
|||
if sys.platform == 'win32':
|
||||
libgs = __win32_finddll()
|
||||
if not libgs:
|
||||
raise RuntimeError('Can not find Ghostscript DLL in registry')
|
||||
raise RuntimeError('Please make sure that Ghostscript is installed')
|
||||
libgs = windll.LoadLibrary(libgs)
|
||||
else:
|
||||
try:
|
||||
libgs = cdll.LoadLibrary("libgs.so")
|
||||
libgs = cdll.LoadLibrary('libgs.so')
|
||||
except OSError:
|
||||
# shared object file not found
|
||||
import ctypes.util
|
||||
|
||||
libgs = ctypes.util.find_library('gs')
|
||||
if not libgs:
|
||||
raise RuntimeError('Can not find Ghostscript library (libgs)')
|
||||
raise RuntimeError('Please make sure that Ghostscript is installed')
|
||||
libgs = cdll.LoadLibrary(libgs)
|
||||
|
||||
del __win32_finddll
|
||||
|
|
|
|||
|
|
@ -181,8 +181,10 @@ class Lattice(BaseParser):
|
|||
gs_call = '-q -sDEVICE=png16m -o {} -r600 {}'.format(
|
||||
self.imagename, self.filename)
|
||||
gs_call = gs_call.encode().split()
|
||||
with Ghostscript(*gs_call) as gs:
|
||||
null = open(os.devnull, 'wb')
|
||||
with Ghostscript(*gs_call, stdout=null) as gs:
|
||||
pass
|
||||
null.close()
|
||||
|
||||
def _generate_table_bbox(self):
|
||||
self.image, self.threshold = adaptive_threshold(
|
||||
|
|
|
|||
|
|
@ -74,21 +74,6 @@ def test_no_tables_found_warnings_suppressed():
|
|||
pytest.fail('Unexpected warning: {}'.format(warning_text))
|
||||
|
||||
|
||||
def test_ghostscript_not_found(monkeypatch):
|
||||
import distutils
|
||||
|
||||
def _find_executable_patch(arg):
|
||||
return ''
|
||||
|
||||
monkeypatch.setattr(distutils.spawn, 'find_executable', _find_executable_patch)
|
||||
|
||||
message = ('Please make sure that Ghostscript is installed and available'
|
||||
' on the PATH environment variable')
|
||||
filename = os.path.join(testdir, 'foo.pdf')
|
||||
with pytest.raises(Exception, message=message):
|
||||
tables = camelot.read_pdf(filename)
|
||||
|
||||
|
||||
def test_no_password():
|
||||
filename = os.path.join(testdir, 'health_protected.pdf')
|
||||
message = 'file has not been decrypted'
|
||||
|
|
|
|||
Loading…
Reference in New Issue