From ab11781795d83e2469138ce7ec002570e976eb8e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A9=20Wobst?= Date: Sat, 14 May 2011 10:39:40 +0000 Subject: [PATCH] new filelocator module git-svn-id: https://pyx.svn.sourceforge.net/svnroot/pyx/trunk/pyx@3064 069f4177-920e-0410-937b-c2a4a81bcd90 --- CHANGES | 1 + pyx/filelocator.py | 251 ++++++++++++++++++++++++++++++++++++++++++++ pyx/pycompat.py | 8 ++ pyx/pykpathsea/__init__.py | 128 +++++----------------- pyx/pykpathsea/pykpathsea.c | 105 +++++++++--------- pyxrc | 14 ++- setup.cfg | 2 +- 7 files changed, 351 insertions(+), 158 deletions(-) create mode 100644 pyx/filelocator.py create mode 100644 pyx/pycompat.py rewrite pyx/pykpathsea/__init__.py (73%) diff --git a/CHANGES b/CHANGES index 60b2afcb..fd473afb 100644 --- a/CHANGES +++ b/CHANGES @@ -108,6 +108,7 @@ TODO: - new PS and PDF writer options: strip_fonts, text_as_path, mesh_as_bitmap, mesh_as_bitmap_resolution (TODO: documentation) - fix for commented out UniqueID + - new filelocator module - graph modules: - bar style on graphxyz (single datasets only) - graphxyz: diff --git a/pyx/filelocator.py b/pyx/filelocator.py new file mode 100644 index 00000000..76e4ad24 --- /dev/null +++ b/pyx/filelocator.py @@ -0,0 +1,251 @@ +builtinopen = open + +import os, cStringIO, warnings + +import config, pycompat + + +# Locator methods implement a open method similar to the builtin open +# function by searching for a file according to a specific rule. + +locator_classes = {} + +class local: + # locates files in the current directory + + def opener(self, filename, formats, mode): + return lambda: builtinopen(filename, mode) + +locator_classes["local"] = local + + +class internal: + # locates files within the pyx data tree + + def opener(self, filename, formats, mode): + extension = os.path.splitext(filename)[1][1:] + if not extension: + return None + try: + import pkgutil + raise ImportError + except ImportError: + return lambda: builtinopen(os.path.join(os.path.dirname(__file__), "data", extension, filename), mode) + else: + try: + data = pkgutil.get_data("pyx", "data/%s/%s" % (extension, filename)) + except IOError: + return None + else: + if data: + # ignoring mode?! + return lambda: cStringIO.StringIO(data) + +locator_classes["internal"] = internal + + +class recursivedir: + # locates files by searching recursively in a list of directories + + def __init__(self): + self.dirs = config.getlist("locator", "recursivedir") + self.full_filenames = {} + + def opener(self, filename, formats, mode): + if filename in self.full_filenames: + return lambda: builtinopen(self.full_filenames[filename], mode) + while self.dirs: + dir = self.dirs.pop(0) + for item in os.listdir(dir): + full_item = os.path.join(dir, item) + if os.path.isdir(full_item): + self.dirs.insert(0, full_item) + else: + self.full_filenames[item] = full_item + if filename in self.full_filenames: + return lambda: builtinopen(self.full_filenames[filename], mode) + +locator_classes["recursivedir"] = recursivedir + + +class ls_R: + # locates files by searching a list of ls-R files + + def __init__(self): + self.ls_Rs = config.getlist("locator", "ls-R") + self.full_filenames = {} + + def opener(self, filename, formats, mode): + while self.ls_Rs and filename not in self.full_filenames: + lsr = self.ls_Rs.pop(0) + base_dir = os.path.dirname(lsr) + dir = None + first = True + for line in builtinopen(lsr): + line = line.rstrip() + if first and line.startswith("%"): + continue + first = False + if line.endswith(":"): + dir = os.path.join(base_dir, line[:-1]) + elif line: + self.full_filenames[line] = os.path.join(dir, line) + if filename in self.full_filenames: + def _opener(): + try: + return builtinopen(self.full_filenames[filename], mode) + except IOError: + warnings.warn("'%s' should be available at '%s' according to the ls-R file, " + "but the file is not available at this location; " + "update your ls-R file" % (filename, self.full_filenames[filename])) + return _opener + +locator_classes["ls-R"] = ls_R + + +class pykpathsea: + + def opener(self, filename, formats, mode): + import pykpathsea + for format in formats: + full_filename = pykpathsea.find_file(filename, format) + return lambda: builtinopen(full_filename, mode) + +locator_classes["pykpathsea"] = pykpathsea + + +# class libkpathsea: +# # locate files by libkpathsea using ctypes +# +# def opener(self, filename, formats, mode): +# pass +# +# locator_classes["libpathsea"] = libkpathsea + + +class kpsewhich: + + def opener(self, filename, formats, mode): + for format in formats: + try: + full_filenames = os.popen('kpsewhich --format="%s" "%s"' % (format, filename)).read() + except OSError: + return + if full_filenames: + break + else: + return + full_filename = full_filenames.split("\n")[0] + def _opener(): + try: + return builtinopen(full_filename, mode) + except IOError: + warnings.warn("'%s' should be available at '%s' according to kpsewhich, " + "but the file is not available at this location; " + "update your kpsewhich database" % (filename, full_filename)) + return _opener + +locator_classes["kpsewhich"] = kpsewhich + + +class locate: + + def opener(self, filename, formats, mode): + try: + full_filenames = os.popen("locate \"%s\"" % filename).read() + except OSError: + return + if not full_filenames: + return + full_filename = full_filenames.split("\n")[0] + def _opener(): + try: + return builtinopen(full_filenames, mode) + except IOError: + warnings.warn("'%s' should be available at '%s' according to the locate database, " + "but the file is not available at this location; " + "update your locate database" % (filename, self.full_filenames[filename])) + return _opener + +locator_classes["locate"] = locate + + +methods = [locator_classes[method]() + for method in config.getlist("locator", "methods", "local internal pykpathsea kpathsea locate")] + +openers = {} + +def open(filename, formats, mode="r"): + formats = tuple(formats) + if (filename, formats) in openers: + return openers[(filename, formats)]() + for method in methods: + opener = method.opener(filename, formats, mode) + if opener: + try: + file = opener() + except IOError: + file = None + if file: + openers[(filename, formats)] = opener + return file + raise IOError("Could not locate the file '%s'." % filename) + + +class formats: + gf = "gf" + pk = "pk" + any_glyph = "bitmap font" + tfm = "tfm" + afm = "afm" + base = "base" + bib = "bib" + bst = "bst" + cnf = "cnf" + db = "ls-R" + fmt = "fmt" + fontmap = "map" + mem = "mem" + mf = "mf" + mfpool = "mfpool" + mft = "mft" + mp = "mp" + mppool = "mppool" + mpsupport = "MetaPost support" + ocp = "ocp" + ofm = "ofm" + opl = "opl" + otp = "otp" + ovf = "ovf" + ovp = "ovp" + pict = "graphics/figure" + tex = "tex" + texdoc = "TeX system documentation" + texpool = "texpool" + texsource = "TeX system sources" + tex_ps_header = "PostScript header" + troff_font = "Troff fonts" + type1 = "type1 fonts" + vf = "vf" + dvips_config = "dvips config" + ist = "ist" + truetype = "truetype fonts" + type42 = "type42 fonts" + web2c = "web2c files" + program_text = "other text files" + program_binary = "other binary files" + miscfonts = "misc fonts" + web = "web" + cweb = "cweb" + enc = "enc files" + cmap = "cmap files" + subfont_definition = "subfont definition files" + opentype = "opentype fonts" + pdftex_config = "pdftex config" + lig = "lig files" + texmfscripts = "texmfscripts" + lua = "lua" + font_feature = "font feature files" + cid_maps = "cid maps" + mlbib = "mlbib" + mlbst = "mlbst" diff --git a/pyx/pycompat.py b/pyx/pycompat.py new file mode 100644 index 00000000..967b02ae --- /dev/null +++ b/pyx/pycompat.py @@ -0,0 +1,8 @@ +def popen(cmd, mode="r"): + try: + import subprocess + return subprocess.Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout + except ImportError: + import os + return os.popen(command, mode) + diff --git a/pyx/pykpathsea/__init__.py b/pyx/pykpathsea/__init__.py dissimilarity index 73% index eabd3600..2f9dbc97 100644 --- a/pyx/pykpathsea/__init__.py +++ b/pyx/pykpathsea/__init__.py @@ -1,99 +1,29 @@ -# -*- coding: ISO-8859-1 -*- -# -# -# Copyright (C) 2003-2004 Jörg Lehmann -# Copyright (C) 2003-2004 André Wobst -# Copyright (C) 2010 Michael Schinler -# -# This file is part of PyX (http://pyx.sourceforge.net/). -# -# PyX 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 2 of the License, or -# (at your option) any later version. -# -# PyX 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 PyX; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - - -try: - from _pykpathsea import * -except: - find_file_cache = {} - try: - import subprocess - def find_file(filename, kpse_file_format): - command = ("kpsewhich", "--format=%s"%kpse_file_format, filename) - if not find_file_cache.has_key(command): - find_file_cache[command] = subprocess.Popen(command, stdout=subprocess.PIPE).communicate(input=None)[0].strip() - return find_file_cache[command] - except ImportError: - import os - def find_file(filename, kpse_file_format): - command = 'kpsewhich --format="%s" %s' % (kpse_file_format, filename) - if not find_file_cache.has_key(command): - find_file_cache[command] = os.popen(command, "r").readline().strip() - return find_file_cache[command] - kpse_gf_format = "gf" - kpse_pk_format = "pk" - kpse_any_glyph_format = "bitmap font" - kpse_tfm_format = "tfm" - kpse_afm_format = "afm" - kpse_base_format = "base" - kpse_bib_format = "bib" - kpse_bst_format = "bst" - kpse_cnf_format = "cnf" - kpse_db_format = "ls-R" - kpse_fmt_format = "fmt" - kpse_fontmap_format = "map" - kpse_mem_format = "mem" - kpse_mf_format = "mf" - kpse_mfpool_format = "mfpool" - kpse_mft_format = "mft" - kpse_mp_format = "mp" - kpse_mppool_format = "mppool" - kpse_mpsupport_format = "MetaPost support" - kpse_ocp_format = "ocp" - kpse_ofm_format = "ofm" - kpse_opl_format = "opl" - kpse_otp_format = "otp" - kpse_ovf_format = "ovf" - kpse_ovp_format = "ovp" - kpse_pict_format = "graphics/figure" - kpse_tex_format = "tex" - kpse_texdoc_format = "TeX system documentation" - kpse_texpool_format = "texpool" - kpse_texsource_format = "TeX system sources" - kpse_tex_ps_header_format = "PostScript header" - kpse_troff_font_format = "Troff fonts" - kpse_type1_format = "type1 fonts" - kpse_vf_format = "vf" - kpse_dvips_config_format = "dvips config" - kpse_ist_format = "ist" - kpse_truetype_format = "truetype fonts" - kpse_type42_format = "type42 fonts" - kpse_web2c_format = "web2c files" - kpse_program_text_format = "other text files" - kpse_program_binary_format = "other binary files" - kpse_miscfonts_format = "misc fonts" - kpse_web_format = "web" - kpse_cweb_format = "cweb" - kpse_enc_format = "enc files" - kpse_cmap_format = "cmap files" - kpse_subfont_definition_format = "subfont definition files" - kpse_opentype_format = "opentype fonts" - kpse_pdftex_config_format = "pdftex config" - kpse_lig_format = "lig files" - kpse_texmfscripts_format = "texmfscripts" - kpse_lua_format = "lua" - kpse_font_feature_format = "font feature files" - kpse_cid_maps_format = "cid maps" - kpse_mlbib_format = "mlbib" - kpse_mlbst_format = "mlbst" - +# -*- coding: ISO-8859-1 -*- +# +# +# Copyright (C) 2003-2004 Jörg Lehmann +# Copyright (C) 2003-2004 André Wobst +# Copyright (C) 2010 Michael Schinler +# +# This file is part of PyX (http://pyx.sourceforge.net/). +# +# PyX 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 2 of the License, or +# (at your option) any later version. +# +# PyX 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 PyX; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + +try: + from _pykpathsea import find_file +except ImportError: + def find_file(*args): + raise NotImplemented diff --git a/pyx/pykpathsea/pykpathsea.c b/pyx/pykpathsea/pykpathsea.c index 02c8a493..c824ac7f 100644 --- a/pyx/pykpathsea/pykpathsea.c +++ b/pyx/pykpathsea/pykpathsea.c @@ -16,6 +16,7 @@ * USA. */ +#include #include #include #include @@ -23,13 +24,58 @@ static PyObject *py_kpse_find_file(PyObject *self, PyObject *args) { char *filename; - int kpse_file_format; + char *format; char *completefilename; PyObject *returnvalue; + kpse_file_format_type kpse_file_format; - if (PyArg_ParseTuple(args, "si", &filename, &kpse_file_format)) { - completefilename = kpse_find_file(filename, (kpse_file_format_type) kpse_file_format, 1); + if (PyArg_ParseTuple(args, "ss", &filename, &format)) { + if (!strcmp(format, "gf")) kpse_file_format = kpse_gf_format; else + if (!strcmp(format, "pk")) kpse_file_format = kpse_pk_format; else + if (!strcmp(format, "bitmap font")) kpse_file_format = kpse_any_glyph_format; else + if (!strcmp(format, "tfm")) kpse_file_format = kpse_tfm_format; else + if (!strcmp(format, "afm")) kpse_file_format = kpse_afm_format; else + if (!strcmp(format, "base")) kpse_file_format = kpse_base_format; else + if (!strcmp(format, "bib")) kpse_file_format = kpse_bib_format; else + if (!strcmp(format, "bst")) kpse_file_format = kpse_bst_format; else + if (!strcmp(format, "cnf")) kpse_file_format = kpse_cnf_format; else + if (!strcmp(format, "ls-R")) kpse_file_format = kpse_db_format; else + if (!strcmp(format, "fmt")) kpse_file_format = kpse_fmt_format; else + if (!strcmp(format, "map")) kpse_file_format = kpse_fontmap_format; else + if (!strcmp(format, "mem")) kpse_file_format = kpse_mem_format; else + if (!strcmp(format, "mf")) kpse_file_format = kpse_mf_format; else + if (!strcmp(format, "mfpool")) kpse_file_format = kpse_mfpool_format; else + if (!strcmp(format, "mft")) kpse_file_format = kpse_mft_format; else + if (!strcmp(format, "mp")) kpse_file_format = kpse_mp_format; else + if (!strcmp(format, "mppool")) kpse_file_format = kpse_mppool_format; else + if (!strcmp(format, "MetaPost support")) kpse_file_format = kpse_mpsupport_format; else + if (!strcmp(format, "ocp")) kpse_file_format = kpse_ocp_format; else + if (!strcmp(format, "ofm")) kpse_file_format = kpse_ofm_format; else + if (!strcmp(format, "opl")) kpse_file_format = kpse_opl_format; else + if (!strcmp(format, "otp")) kpse_file_format = kpse_otp_format; else + if (!strcmp(format, "ovf")) kpse_file_format = kpse_ovf_format; else + if (!strcmp(format, "ovp")) kpse_file_format = kpse_ovp_format; else + if (!strcmp(format, "graphics/figure")) kpse_file_format = kpse_pict_format; else + if (!strcmp(format, "tex")) kpse_file_format = kpse_tex_format; else + if (!strcmp(format, "TeX system documentation")) kpse_file_format = kpse_texdoc_format; else + if (!strcmp(format, "texpool")) kpse_file_format = kpse_texpool_format; else + if (!strcmp(format, "TeX system sources")) kpse_file_format = kpse_texsource_format; else + if (!strcmp(format, "PostScript header")) kpse_file_format = kpse_tex_ps_header_format; else + if (!strcmp(format, "Troff fonts")) kpse_file_format = kpse_troff_font_format; else + if (!strcmp(format, "type1 fonts")) kpse_file_format = kpse_type1_format; else + if (!strcmp(format, "vf")) kpse_file_format = kpse_vf_format; else + if (!strcmp(format, "dvips config")) kpse_file_format = kpse_dvips_config_format; else + if (!strcmp(format, "ist")) kpse_file_format = kpse_ist_format; else + if (!strcmp(format, "truetype fonts")) kpse_file_format = kpse_truetype_format; else + if (!strcmp(format, "type42 fonts")) kpse_file_format = kpse_type42_format; else + if (!strcmp(format, "web2c files")) kpse_file_format = kpse_web2c_format; else + if (!strcmp(format, "other text files")) kpse_file_format = kpse_program_text_format; else + if (!strcmp(format, "other binary files")) kpse_file_format = kpse_program_binary_format; else + if (!strcmp(format, "misc fonts")) kpse_file_format = kpse_miscfonts_format; else + return NULL; + + completefilename = kpse_find_file(filename, kpse_file_format, 1); returnvalue = Py_BuildValue("s", completefilename); /* XXX: free(completefilename); */ return returnvalue; @@ -46,59 +92,10 @@ static PyMethodDef pykpathsea_methods[] = { {NULL, NULL} }; -#define AddInt(x) PyDict_SetItemString(dict, #x, PyInt_FromLong(x)) +#define AddFormat(key, value) PyDict_SetItemString(format, PyString_FromString(key), PyInt_FromLong(value)) void init_pykpathsea(void) { - PyObject *module = Py_InitModule("_pykpathsea", pykpathsea_methods); - PyObject *dict = PyModule_GetDict(module); + Py_InitModule("_pykpathsea", pykpathsea_methods); kpse_set_program_name("dvips", "dvips"); - - AddInt(kpse_gf_format); - AddInt(kpse_pk_format); - AddInt(kpse_any_glyph_format); - AddInt(kpse_tfm_format); - AddInt(kpse_afm_format); - AddInt(kpse_base_format); - AddInt(kpse_bib_format); - AddInt(kpse_bst_format); - AddInt(kpse_cnf_format); - AddInt(kpse_db_format); - AddInt(kpse_fmt_format); - AddInt(kpse_fontmap_format); - AddInt(kpse_mem_format); - AddInt(kpse_mf_format); - AddInt(kpse_mfpool_format); - AddInt(kpse_mft_format); - AddInt(kpse_mp_format); - AddInt(kpse_mppool_format); - AddInt(kpse_mpsupport_format); - AddInt(kpse_ocp_format); - AddInt(kpse_ofm_format); - AddInt(kpse_opl_format); - AddInt(kpse_otp_format); - AddInt(kpse_ovf_format); - AddInt(kpse_ovp_format); - AddInt(kpse_pict_format); - AddInt(kpse_tex_format); - AddInt(kpse_texdoc_format); - AddInt(kpse_texpool_format); - AddInt(kpse_texsource_format); - AddInt(kpse_tex_ps_header_format); - AddInt(kpse_troff_font_format); - AddInt(kpse_type1_format); - AddInt(kpse_vf_format); - AddInt(kpse_dvips_config_format); - AddInt(kpse_ist_format); - AddInt(kpse_truetype_format); - AddInt(kpse_type42_format); - AddInt(kpse_web2c_format); - AddInt(kpse_program_text_format); - AddInt(kpse_program_binary_format); - AddInt(kpse_miscfonts_format); - /* - AddInt(kpse_web_format); - AddInt(kpse_cweb_format); - */ - } diff --git a/pyxrc b/pyxrc index 53c209f0..1f9802d8 100644 --- a/pyxrc +++ b/pyxrc @@ -17,13 +17,17 @@ warnings = shortest [text] # runtime configuration of the text module # -# 'fontmaps' is a string, namely a whitespace separated list of font +# 'psfontmaps' is a whitespace separated list of options listing font # mapping files. Those files contain information about the available # type1 fonts. Depending on your TeX-installation you may need to add -# further font mapping files like psfonts.cmz if your TeX installation -# is not configured to use type1 fonts by default. For further +# further font mapping files like psfonts.cmz (if your TeX installation +# is not configured to use type1 fonts by default). For further # information browse the FAQ for the term 'font mapping file'. -fontmaps = psfonts.map +psfontmaps = psfonts.map + +# 'pdffontmaps' is similar to psfontmaps, but it used when pdf output +# is generated. (Note that pdf has a different set of builtin fonts.) +pdffontmaps = pdftex.map # 'waitfortex' is an positive integer, namely the number of seconds # to be waited for an appropriate response from TeX/LaTeX. @@ -43,3 +47,5 @@ showwaitfortex = 5 # operations (e.g. the usage of PyX markers). texipc = 0 +[locator] +methods = local internal pykpathsea kpathsea locate diff --git a/setup.cfg b/setup.cfg index 9086d398..cd3a4185 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,7 +6,7 @@ build_t1code=0 # Python bindings for the kpathsea library. You need the kpathsea header # and library and you may need to specify their location below. -build_pykpathsea=0 +build_pykpathsea=1 [build_ext] # additional include and library directories: -- 2.11.4.GIT