The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

%module(directors="1") _cl_py
/* NOTA BENE:
** SWIG is an exceedingly complex tool that didn't support C++ until
** recently. The way SWIG is employed in pyclene seems to stretch even recent
** versions of the tool a little beyond their limits--the process of generating
** the pyclene wrapper code has broken between each minor SWIG release that DSR
** has tried (1.3.20, 1.3.21, 1.3.22, and 1.3.23).
** SWIG 1.3.23 seems inferior to 1.3.22, in that it has more bugs and
** generates slower, more bloated binaries. DSR REQUESTS THAT UNTIL FURTHER
** NOTICE, CONTRIBUTIONS REFRAIN FROM CHECKING IN ANY FILES GENERATED BY ANY
** VERSION OF SWIG EXCEPT 1.3.22.
**
** Many of the SWIG directives in this file and the supporting files will at
** first appear bizarrely quirky, but most were formulated deliberately. Due
** to bugs in SWIG, directives don't always work as they "should", so many of
** the present directives have needed to be coaxed into working. DSR requests
** that contributors use exquisite care when modifying SWIG directives, and
** use the test suite (located in the ./tests directory) to confirm that the
** altered directives work as expected, and do not cause serious regressions in
** the size or performance of the binaries (the test program
** ./tests/progs/pydevbench/pydevbench.py will help you measure the performance
** impact of your changes).
**
** Issues of particular note:
**
** - Directors
** DSR has made the choice of which CLucene C++ classes to "directorize"
** very carefully, because SWIG's directors impose a heavy price in code size
** and performance. Please don't directorize any more classes without
** discussing the decision with DSR.
**
** - Preprocessor Interaction
** The interaction between the SWIG preprocessor and the C++ preprocessor
** can be quite confusing. The best way to unravel SWIG preprocessor issues
** is to examine the SWIG-generated C++ code (_clucene_wrap.cpp) and Python
** code (_cl_py.py).
**
** - 64-bit Portability
** DSR has configured CLucene's int_t and long_t types and the dependent
** SWIG directives so that the SWIG-generated C++ files can be compiled
** unchanged on both x86 and x86-64. For the sake of end-user-friendliness,
** it is crucial that this portability be preserved.
*/
/* The following symbol needs to be uncommented before generating a Unicode
** version of the SWIG wrapper code: */
//#define _UNICODE
#ifdef _UNICODE
/* Make the C++ preprocessor (as opposed to only the SWIG preprocessor) aware
** that _UNICODE is defined. */
%{
#define _UNICODE
#define UNICODE
%}
#endif
/* Define _SUMO to create a version of pyclene that wraps elements of CLucene
** that are unlikely to be of any use to most Python client programs.
** Sumo builds are somewhat larger, and are intended primarily for quality
** assurance of CLucene itself. */
#define _SUMO
#ifdef _SUMO
/* Make the C++ preprocessor (as opposed to only the SWIG preprocessor) aware
** that _SUMO is defined. */
%{ #define _SUMO %}
#endif
/* SWIG preprocessor symbols for use during code generation: */
/* We use %define for those symbols that're used only be SWIG, and should not
** be exposed as constants in the generated module. */
%define yes 1 %enddef
%define no 0 %enddef
/* Prevent SWIG from wrapping various global variables/definitions that are of
** no value at the Python level. */
%ignore global_pythonLuceneModule;
%ignore global_DocumentConstructor;
%ignore global_FieldConstructor;
%ignore global_string__fields;
%ignore global_string__value;
%ignore global_string__isStored;
%ignore global_string__isIndexed;
%ignore global_string__isTokenized;
%ignore DELETE_TYPE_NONE;
%ignore DELETE_TYPE_DELETE;
%ignore DELETE_TYPE_DELETE_ARRAY;
%ignore STOP_WORDS;
%ignore STOP_WORDS_LENGTH;
%ignore LUCENE_STREAM_BUFFER_SIZE;
%ignore LUCENE_WRITER_INDEX_INTERVAL;
%ignore LUCENE_SCORE_CACHE_SIZE;
%ignore CHAR_RADIX;
%ignore MAX_PATH;
%ignore CL_MAX_DIR;
%ignore FILE_ATTRIBUTE_DIRECTORY;
%ignore MAX_POSSIBLE_CHARS_IN_FLOAT_REPR;
/* Expose to Python a boolean flag called UNICODE_BUILD. */
const bool UNICODE_BUILD;
#ifdef UNICODE_BUILD
%{ const bool UNICODE_BUILD = true; %}
#else
%{ const bool UNICODE_BUILD = false; %}
#endif
/* Expose to Python a boolean flag called SUMO_BUILD. */
const bool SUMO_BUILD;
#ifdef _SUMO
%{ const bool SUMO_BUILD = true; %}
#else
%{ const bool SUMO_BUILD = false; %}
#endif
/* Define what happens when an exception occurs in the Python implementation
** of a directorized class's method: */
%feature("director:except") {
if ($error != NULL) {
throw Swig::DirectorMethodException();
}
}
/* Define generic error handler for wrapped methods: */
/* YYY:CONCURRENCY: Insert "free threads"/"constrain threads" directives here.
** Also need to reacquire the GIL during director callbacks--investigate the
** new PyGILState_* funcs added in 2.3. */
%{ class PythonExceptionAlreadySet {}; %}
%exception {
try {
$action
} catch (Swig::DirectorException) {
SWIG_fail;
} catch (PythonExceptionAlreadySet) {
SWIG_fail;
} catch (THROW_TYPE &e) { /* THROW_TYPE is defined in CL's StdHeader.h. */
PyErr_SetString(PyExc_Exception, e.what());
SWIG_fail;
}
}
%pythoncode %{
import datetime, time
# Utility functions:
def _maybeDatetimeToInt(t):
if isinstance(t, datetime.datetime):
t = int(time.mktime(t.timetuple()))
return t
def _makePythonIteratorCompliantNextMethod(originalMethod):
# $originalMethod is an unbound method that's designed to return one item
# per call until exhaustion, when it returns None.
# We generate a method compliant with the Python iterator protocol, which
# requires that StopIteration be raised upon exhaustion.
def iteratorCompliantMethod(self):
nextItem = originalMethod(self)
if nextItem is None:
raise StopIteration
return nextItem
return iteratorCompliantMethod
def _makeSingleShotMethod(originalMethod, tag, exceptionClass=IOError):
tagAttrName = '_%s_singleShot' % tag
def singleShot(self):
if getattr(self, tagAttrName, False):
raise exceptionClass('Already %s.' % tag)
ret = originalMethod(self)
setattr(self, tagAttrName, True)
return ret
return singleShot
%}
/* Make sure to import the masking of standard types from CLucene's StdHeader.h.
** If this isn't done, SWIG becomes confused. */
/* Force SWIG to ignore various things defined in StdHeader.h */
%ignore mutex;
%ignore DEFINE_MUTEX;
%ignore STATIC_DEFINE_MUTEX;
%ignore LOCK_MUTEX;
%ignore UNLOCK_MUTEX;
%ignore lucenestrdup;
%ignore lucenewcsdup;
%ignore O_RANDOM;
%ignore O_BINARY;
%include "CLucene/StdHeader.h"
/* Work around SWIG 1.3.21 bug (SWIG's preprocessor computes the int_t
** differently from the preprocessor of any C++ compiler I've tried).
** By overriding the definition here, I'm able to force SWIG to generate
** correct code. (The definition of int_t as int is correct on both x86 and
** x86-64.) */
#undef int_t
#define int_t int
/* SWIG standard support files: */
%include "typemaps.i"
%include "std_vector.i"
#ifndef _UNICODE
%include "std_string.i"
#else
%include "std_wstring.i"
#endif
/* SWIG/pyclene support files: */
%include "supp_props.i"
/* Necessary C++-level inclusions in generated wrapper file: */
%{ #include "pyclene.h" %}
%include "pyclene.h"
%{
/* Compile entire extension and supporting code as one compilation unit? */
#ifdef MONOLITHIC_COMPILATION
#include "nodist__clucene_source_files__include_all.h"
#else
#include "CLucene.h"
#include "CLucene/StdHeader.h"
#include "CLucene/LuceneThreads.h"
#include "CLucene/analysis/AnalysisHeader.h"
#include "CLucene/util/FastCharStream.h"
#include "CLucene/analysis/standard/StandardAnalyzer.h"
#include "CLucene/document/Document.h"
#include "CLucene/document/DateField.h"
#include "CLucene/index/IndexWriter.h"
#include "CLucene/index/Term.h"
#include "CLucene/index/Terms.h"
#include "CLucene/queryParser/QueryParser.h"
#include "CLucene/search/BooleanClause.h"
#include "CLucene/search/DateFilter.h"
#include "CLucene/search/FuzzyQuery.h"
#include "CLucene/search/IndexSearcher.h"
#include "CLucene/search/MultiSearcher.h"
#include "CLucene/search/MultiTermQuery.h"
#include "CLucene/search/PrefixQuery.h"
#include "CLucene/search/PhraseQuery.h"
#include "CLucene/search/RangeQuery.h"
#include "CLucene/search/SearchHeader.h"
#include "CLucene/search/ScoreDoc.h"
#include "CLucene/search/TermQuery.h"
#include "CLucene/search/WildcardQuery.h"
#include "CLucene/store/FSDirectory.h"
#include "CLucene/store/RAMDirectory.h"
#include "CLucene/util/BitSet.h"
#include "CLucene/util/Reader.h"
#endif /* def MONOLITHIC_COMPILATION? */
%}
/* More SWIG/pyclene support files: */
/* pyclene_typemaps needs string conversions funcs to have been declared. */
#ifndef _UNICODE
%{
static inline int SWIG_AsCharPtr(PyObject *obj, char **val);
static inline PyObject *SWIG_FromCharPtr(const char* cptr);
%}
#else
%{
static inline int SWIG_AsWCharPtr(PyObject *obj, wchar_t **val);
static inline PyObject *SWIG_FromWCharPtr(const wchar_t * cptr);
%}
#endif
%include "pyclene_typemaps.i"
%{
#include "supp_document.cpp"
#include "supp_index.cpp"
#include "supp_search.cpp"
#include "supp_util.cpp"
%}
/******************* lucene::util : BEGIN *******************/
%ignore lucene::util::Arrays;
%include "CLucene/util/Arrays.h"
/* Reader class: */
/* There is little point in exposing the abstract class lucene::util::Reader,
** since it can't be subclassed by ordinary Python client code. Enabling
** directors for Reader would KILL performance since typical CLucene internal
** client code of Readers operates them so granularly (e.g., char-by-char).
**
** The only good reason for exposing Reader is to allow
** isinstance(objThatsEitherStringReaderOrFileReader, lucene.Reader) to work
** as expected. */
%ignore lucene::util::Reader;
#ifdef ZZZ_DECIDE_WHETHER_TO_WRAP_THESE
/* Suppress SWIG's desire to create a default constructor wrapper for this
** abstract class: */
%nodefault lucene::util::Reader;
%ignore lucene::util::Reader::~Reader;
/*%ignore lucene::util::Reader::close;*/
%ignore lucene::util::Reader::read;
%ignore lucene::util::Reader::available;
%ignore lucene::util::Reader::readChar;
%ignore lucene::util::Reader::peek;
%ignore lucene::util::Reader::position;
%ignore lucene::util::Reader::seek;
#endif /* ZZZ_DECIDE_WHETHER_TO_WRAP_THESE */
/* FileReader class: */
%ignore FILEREADER_CACHE;
%extend lucene::util::FileReader {
%{ static %} PyObject *__eq__(lucene::util::Reader *other) {
/* YYY: (This equality method chokes on any $other than a Reader.) */
/* Need to compare the underlying C++ obj pointers, rather than the Python
** proxy objects. */
return PyBool_FromLong(self == other);
}
};
/* Expose the FileReader::close method. */
%ignore lucene::util::FileReader::read;
%ignore lucene::util::FileReader::available;
%ignore lucene::util::FileReader::readChar;
%ignore lucene::util::FileReader::peek;
%ignore lucene::util::FileReader::position;
%ignore lucene::util::FileReader::seek;
%feature("shadow") lucene::util::FileReader::close %{
close = _makeSingleShotMethod($action, 'closed')
%}
/* StringReader class: */
%ignore lucene::util::StringReader::StringReader(const char_t* value);
/* Expose the StringReader::close method. */
%ignore lucene::util::StringReader::read;
%ignore lucene::util::StringReader::available;
%ignore lucene::util::StringReader::readChar;
%ignore lucene::util::StringReader::peek;
%ignore lucene::util::StringReader::position;
%ignore lucene::util::StringReader::seek;
%feature("shadow") lucene::util::StringReader::StringReader %{
def __init__(self, s):
# Retain a reference to the str or unicode object so it's guaranteed
# not to be collected during the life of this StringReader.
self._s = s
# If this is a non-unicode build, we pass the C++ StringReader a
# pointer to the str's internal buffer, so its deleteValue constructor
# parameter is False.
# For Unicode builds, copying is required, so the C++ StringReader's
# deleteValue constructor is True.
newobj = $action(s, len(s), UNICODE_BUILD)
# Remember to execute the SWIG boilerplate:
self.this = newobj.this
self.thisown = 1
del newobj.thisown
%}
%feature("shadow") lucene::util::StringReader::close %{
close = _makeSingleShotMethod($action, 'closed')
%}
%include "CLucene/util/Reader.h"
/******************* lucene::util : END *******************/
/******************* lucene::store : BEGIN *******************/
%ignore lucene::store::DIRECTORIES_MUTEX;
/* InputStream class: */
#ifndef _SUMO
%ignore lucene::store::InputStream;
#else /* def _SUMO? */
%newobject lucene::store::InputStream::clone;
%ignore lucene::store::InputStream::readInternal;
%ignore lucene::store::InputStream::seekInternal;
%extend lucene::store::InputStream {
%{ static %} char_t *readString() {
/* Order readString not to duplicate the string before returning it.
** (That duplication will be performed by the C->Python string output
** mechanism.) */
return self->readString(false);
}
%{ static %} PyObject *readByte() {
/* Return the byte as a single-character Python string rather than an int. */
char s[1];
s[0] = (char) self->readByte();
return PyString_FromStringAndSize(s, 1);
}
%{ static %} PyObject *readBytes(const int_t nBytes) {
if (nBytes > self->Length() - self->getFilePointer()) {
PyErr_SetString(PyExc_IOError, "Can't read past the end of the stream.");
return NULL;
}
PyObject *retBuf = PyString_FromStringAndSize(NULL, nBytes);
l_byte_t *internalBuf = NULL;
FAIL_IF_NULL(retBuf);
internalBuf = (l_byte_t *) PyString_AS_STRING(retBuf);
try {
self->readBytes(internalBuf, 0, nBytes);
} catch (THROW_TYPE &e) { /* THROW_TYPE is defined in CL's StdHeader.h. */
PyErr_SetString(PyExc_IOError, e.what());
goto fail;
}
return retBuf;
fail:
if (!PyErr_Occurred()) {
PyErr_NoMemory();
}
Py_DECREF(retBuf);
return NULL;
}
#ifndef _UNICODE
/* If not compiled to support Unicode, just call our extended version of
** readBytes (returns a Python string). */
%{ static %} PyObject *readChars(const int_t nChars) {
return lucene_store_InputStream_readBytes(self, nChars);
}
#else
%{ static %} PyObject *readChars(const int_t nChars) {
/* We ingore the output buffer pointer, returning the result via a Python
** string or unicode instead. */
wchar_t *buf = (wchar_t *) PyObject_Malloc(sizeof(wchar_t) * nChars + 1);
PyObject *pyRet = NULL;
try {
self->readChars(buf, 0, nChars);
} catch (THROW_TYPE &e) { /* THROW_TYPE is defined in CL's StdHeader.h. */
PyErr_SetString(PyExc_IOError, e.what());
goto fail;
}
pyRet = PyUnicode_FromWideChar(buf, stringLength(buf));
FAIL_IF_NULL(pyRet);
PyObject_Free(buf);
return pyRet;
fail:
PyObject_Free(buf);
Py_XDECREF(pyRet);
return NULL;
}
#endif
/* "File-like" read method. */
%{ static %} PyObject *read(const int_t nBytes=-1) {
const long_t bytesLeft = self->Length() - self->getFilePointer();
const int_t bytesToActuallyRead =
nBytes == -1 ?
(int_t)bytesLeft
: (nBytes > bytesLeft ? (int_t)bytesLeft : nBytes)
;
return lucene_store_InputStream_readBytes(self, bytesToActuallyRead);
}
};
/* We implemented these methods via extension above; don't need the originals. */
%ignore lucene::store::InputStream::readByte(); /* The unpythonic version that returns l_byte_t. */
%ignore lucene::store::InputStream::readBytes(l_byte_t *b, const int_t offset, const int_t len);
%ignore lucene::store::InputStream::readChars(char_t* buffer, const int_t start, const int_t len);
%ignore lucene::store::InputStream::readString();
%ignore lucene::store::InputStream::readString(const bool unique);
DEF_PROPERTY_RO(lucene::store::InputStream, filePointer, long_t,
lucene_store_InputStream_filePointer_get, lucene_store_InputStream_filePointer_set, getFilePointer, yes
)
%ignore lucene::store::InputStream::getFilePointer;
%rename (__len__) lucene::store::InputStream::Length;
#endif /* ndef _SUMO */
/* If InputStream.h is used instead of .i, SWIG refuses to recognize
** InputStream subclasses such as FSInputStream as non-virtual. */
%include "CLucene/store/InputStream.i"
/* RAMFile class: */
%ignore lucene::store::RAMFile;
/* RAMLock class: */
%ignore lucene::store::RAMLock;
/* RAMInputStream class: */
%ignore lucene::store::RAMInputStream;
/* RAMOutputStream class: */
%ignore lucene::store::RAMOutputStream;
/* OutputStream class: */
#ifndef _SUMO
%ignore lucene::store::OutputStream;
#else /* def _SUMO? */
%ignore lucene::store::OutputStream::clone;
%rename (__len__) lucene::store::OutputStream::Length;
%extend lucene::store::OutputStream {
%{ static %} PyObject *writeByte(PyObject *b) {
if (!PyString_Check(b) || PyString_GET_SIZE(b) != 1) {
PyErr_SetString(PyExc_TypeError,
"The byte must be passed as a single-character string."
);
return NULL;
}
self->writeByte( (l_byte_t) PyString_AS_STRING(b)[0] );
RETURN_PY_NONE;
}
%{ static %} PyObject *writeChars(const char_t* s, const int_t length) {
try {
self->writeChars(s, 0, length);
} catch (THROW_TYPE &e) { /* THROW_TYPE is defined in CL's StdHeader.h. */
PyErr_SetString(PyExc_IOError, e.what());
goto fail;
}
RETURN_PY_NONE;
fail:
return NULL;
}
/* Make an OutputStream "act like" a normal Python output stream to the
** extent that it has a write method and can be the target of the >> operator.
** Because an appropriate typemap is defined, SWIG will wrap this method to
** accept a Python string. */
%{ static %} PyObject *write(const l_byte_t* b, const int_t length) {
self->writeBytes(b, length);
RETURN_PY_NONE;
}
};
%ignore lucene::store::OutputStream::writeByte(const l_byte_t b);
%ignore lucene::store::OutputStream::writeChars(const char_t* s, const int_t start, const int_t length);
%ignore lucene::store::OutputStream::seek(const long_t pos);
DEF_PROPERTY_RO(lucene::store::OutputStream, filePointer, long_t,
lucene_store_OutputStream_filePointer_get, lucene_store_OutputStream_filePointer_set, getFilePointer, yes
)
%ignore lucene::store::OutputStream::getFilePointer;
#endif /* ndef _SUMO */
%include "CLucene/store/OutputStream.h"
/* LuceneLock and LuceneLockWith classes: */
#ifndef _SUMO
%ignore lucene::store::LuceneLock;
%ignore lucene::store::LuceneLockWith;
#else /* def _SUMO ? */
%rename (Lock) lucene::store::LuceneLock;
%rename (LockWith) lucene::store::LuceneLockWith;
#endif /* ndef _SUMO */
/* SWIG chokes on nonexistent syntax error in Lock.h; must use Lock.i. */
%include "CLucene/store/Lock.i"
/* FSLock class: */
#ifndef _SUMO
%ignore lucene::store::FSLock;
#else /* def _SUMO? */
%immutable lucene::store::FSLock::fname;
%rename (filename) lucene::store::FSLock::fname;
#endif /* ndef _SUMO */
/* Directory class: */
#ifndef _SUMO
/* In a non-sumo build, treat Directories as "semi-opaque handles" only. */
/* Do not ignore the Directory::list() method. */
%ignore lucene::store::Directory::fileExists;
%ignore lucene::store::Directory::fileModified;
%ignore lucene::store::Directory::deleteFile;
%ignore lucene::store::Directory::renameFile;
%ignore lucene::store::Directory::fileLength;
%ignore lucene::store::Directory::createFile;
%ignore lucene::store::Directory::openFile;
%ignore lucene::store::Directory::makeLock;
/* Do not ignore the Directory::close() method. */
#else /* def _SUMO? */
%newobject lucene::store::Directory::createFile;
%newobject lucene::store::Directory::openFile;
%newobject lucene::store::Directory::makeLock;
#endif /* ndef _SUMO */
%nodefault lucene::store::Directory;
%include "CLucene/store/Directory.h"
/* FSDirectory.i also declares FSInputStream and FSOutputStream. */
#ifndef _SUMO
%ignore lucene::store::FSInputStream;
%ignore lucene::store::FSOutputStream;
#else
/* Because we ignore the original clone method and replace it by extention,
** SWIG forgets that it returns a new object. */
%newobject lucene::store::FSInputStream::clone;
%extend lucene::store::FSInputStream {
/* Define the clone method to return an FSInputStream, not the more general
** InputStream. Otherwise, SWIG only recognizes that the return value is
** an InputStream, not an FSInputStream, which is confusing to the Python
** client programmer (e.g., the clone lacks the isClone property). */
%{ static %} FSInputStream& clone() {
return *new FSInputStream(*self);
}
}
%ignore lucene::store::FSInputStream::clone;
%ignore lucene::store::FSInputStream::FSInputStream(lucene::store::FSInputStream& clone);
%rename (FSInputStream_FromFilename) lucene::store::FSInputStream::FSInputStream(const char_t* path);
%rename (__len__) lucene::store::FSInputStream::Length;
/*
%feature("shadow") lucene::store::FSInputStream::Length %{
def __len__(self):
return $action(self.this)
%}
*/
#endif /* ndef _SUMO */
/* FSDirectory class: */
%ignore lucene::store::FSDirectory::list;
%ignore lucene::store::FSDirectory::getDirectory;
/* Suppress the static version of fileModified. */
%ignore lucene::store::FSDirectory::fileModified;
%ignore lucene::store::FSDirectory::refInc;
DEF_PROPERTY_RO(lucene::store::FSDirectory, name, const char_t *,
lucene_store_FSDirectory_name_get, lucene_store_FSDirectory_name_set, getDirName, yes
)
%ignore lucene::store::FSDirectory::getDirName() const;
#ifndef _SUMO
%ignore lucene::store::FSDirectory::fileExists;
%ignore lucene::store::FSDirectory::fileLength;
%ignore lucene::store::FSDirectory::deleteFile;
%ignore lucene::store::FSDirectory::renameFile;
%ignore lucene::store::FSDirectory::createFile;
%ignore lucene::store::FSDirectory::openFile;
%ignore lucene::store::FSDirectory::makeLock;
%ignore lucene::store::FSDirectory::refInc;
/* Do not ignore the close() method. */
#endif /* ndef _SUMO */
/* Have to use FSDirectory.i instead of .h because SWIG fails to parse .h. */
%include "CLucene/store/FSDirectory.i"
/* RAMDirectory class: */
#ifndef _SUMO
/* Do not ignore the list() method (it's defined by extension far below). */
%ignore lucene::store::RAMDirectory::fileExists;
%ignore lucene::store::RAMDirectory::fileModified;
%ignore lucene::store::RAMDirectory::fileLength;
%ignore lucene::store::RAMDirectory::deleteFile;
%ignore lucene::store::RAMDirectory::renameFile;
%ignore lucene::store::RAMDirectory::createFile;
%ignore lucene::store::RAMDirectory::openFile;
%ignore lucene::store::RAMDirectory::makeLock;
/* Do not ignore the close() method. */
#else /* def _SUMO? */
#ifdef ZZZ_DECIDE_WHETHER_TO_WRAP_THESE
/* I'm not convinced that a Python client programmer will need to treat a
** RAMDirectory as anything other than an opaque handle. */
%{
#define RAISE_IO_ERROR_IF_FILE_EXISTENCE_COND(name, condition) \
if (condition) { \
PyObject *msg = PyString_FromFormat("The file \"%s\" %s.", \
name, (condition) ? "exists" : "does not exist" \
); \
if (msg == NULL) { \
PyErr_NoMemory(); \
throw PythonExceptionAlreadySet(); \
} \
PyErr_SetObject(PyExc_IOError, msg); \
Py_DECREF(msg); \
throw PythonExceptionAlreadySet(); \
}
%}
/* Since we're suppressing the original versions and creating replacments by
** extension, SWIG does not honor the newobject declaration for Directory on
** the following methods of RAMDirectory: */
%newobject lucene::store::RAMDirectory::createFile;
%newobject lucene::store::RAMDirectory::openFile;
%extend lucene::store::RAMDirectory {
/* Can't figure out how to force SWIG to honor the newobject declaration
** on these extended methods (%newobject lucene::store::RAMDirectory::createFile,
** for example, does not work). */
%{ static %} lucene::store::OutputStream *createFile(const char_t* name) {
RAISE_IO_ERROR_IF_FILE_EXISTENCE_COND(name, self->fileExists(name));
return &self->createFile(name);
}
%{ static %} lucene::store::InputStream *openFile(const char_t *name) {
RAISE_IO_ERROR_IF_FILE_EXISTENCE_COND(name, !self->fileExists(name));
return &self->openFile(name);
}
%{ static %} long_t fileModified(const char_t* name) const {
RAISE_IO_ERROR_IF_FILE_EXISTENCE_COND(name, !self->fileExists(name));
return self->fileModified(name);
}
%{ static %} long_t fileLength(const char_t* name) const {
RAISE_IO_ERROR_IF_FILE_EXISTENCE_COND(name, !self->fileExists(name));
return self->fileLength(name);
}
%{ static %} void deleteFile(const char_t* name) {
RAISE_IO_ERROR_IF_FILE_EXISTENCE_COND(name, !self->fileExists(name));
return self->deleteFile(name, true);
}
%{ static %} void renameFile(const char_t* from, const char_t* to) {
RAISE_IO_ERROR_IF_FILE_EXISTENCE_COND(from, !self->fileExists(from));
RAISE_IO_ERROR_IF_FILE_EXISTENCE_COND(to, self->fileExists(to));
return self->renameFile(from, to);
}
};
/* We implemented these methods via extension above; don't need the originals. */
%ignore lucene::store::RAMDirectory::createFile(const char_t* name);
%ignore lucene::store::RAMDirectory::openFile(const char_t* name);
%ignore lucene::store::RAMDirectory::fileModified(const char_t* name) const;
%ignore lucene::store::RAMDirectory::fileLength(const char_t* name) const;
%ignore lucene::store::RAMDirectory::deleteFile(const char_t* name, const bool throwError = true);
%ignore lucene::store::RAMDirectory::renameFile(const char_t* from, const char_t* to);
%ignore lucene::store::RAMDirectory::list(char_t**& list, int_t& size);
#else /* ZZZ_DECIDE_WHETHER_TO_WRAP_THESE */
#ifdef ZZZ_MERE_CODE_BLOAT
%define SUPPRESS_RD_METH(sig)
%{ static %} PyObject *sig {
PyErr_SetString(PyExc_NotImplementedError,
"This method of RAMDirectory is not exposed to Python."
);
return NULL;
}
%enddef
%extend lucene::store::RAMDirectory {
SUPPRESS_RD_METH(fileExists(const char_t* name));
SUPPRESS_RD_METH(fileModified(const char_t* name));
SUPPRESS_RD_METH(fileLength(const char_t* name));
SUPPRESS_RD_METH(deleteFile(const char_t* name, const bool throwError = true));
SUPPRESS_RD_METH(renameFile(const char_t* from, const char_t* to));
SUPPRESS_RD_METH(createFile(const char_t* name));
SUPPRESS_RD_METH(openFile(const char_t* name));
SUPPRESS_RD_METH(makeLock(const char_t* name));
};
#endif /* ZZZ_MERE_CODE_BLOAT */
/* Ignore the original implementations in favor of our suppressors. */
%ignore lucene::store::RAMDirectory::fileExists;
%ignore lucene::store::RAMDirectory::fileModified;
%ignore lucene::store::RAMDirectory::fileLength;
%ignore lucene::store::RAMDirectory::deleteFile;
%ignore lucene::store::RAMDirectory::renameFile;
%ignore lucene::store::RAMDirectory::createFile;
%ignore lucene::store::RAMDirectory::openFile;
%ignore lucene::store::RAMDirectory::makeLock;
#endif /* ZZZ_DECIDE_WHETHER_TO_WRAP_THESE */
#endif /* ndef _SUMO */
%extend lucene::store::RAMDirectory {
%{ static %} PyObject *list() {
char_t **dirList = NULL;
char_t **&dirListRef = dirList;
int_t size = -1;
int_t &sizeRef = size;
try {
self->list(dirListRef, sizeRef);
} catch (THROW_TYPE &e) { /* THROW_TYPE is defined in CL's StdHeader.h. */
PyErr_SetString(PyExc_Exception, e.what());
return NULL;
}
if (size < 0) {
PyErr_SetString(PyExc_IOError, "Directory size less than zero.");
return NULL;
}
PyObject *ret = PyList_New(size);
if (ret == NULL) {
goto fail;
}
for (int i = 0; i < size; i++) {
PyObject *item = NULL;
CONVERT_STRING_OUT(dirList[i], item);
if (item == NULL) {
goto fail;
}
PyList_SET_ITEM(ret, i, item); /* PyList_SET_ITEM steals ref to item. */
}
delete[] dirList;
return ret;
fail:
if (!PyErr_Occurred()) {
PyErr_NoMemory();
}
delete[] dirList;
Py_XDECREF(ret);
return NULL;
}
};
/* Ignore the original of list(), which we just implemented a custom version
** of above. */
%ignore lucene::store::RAMDirectory::list(char_t**& list, int_t& size);
%include "CLucene/store/RAMDirectory.i"
#ifdef _SUMO /* Only expose TransactionalRAMDirectory for testing purposes. */
%include "CLucene/store/TransactionalRAMDirectory.h"
/* The deleteFile, renameFile, createFile, and openFile methods of
** RAMDirectory, TransactionalRAMDirectory's implementation of which we need to
** test, are deliberately not exposed to Python. At present (2005.03.18),
** there appears to be no reason to expose these methods.
** The TransactionalRAMDirectory implementations still must be tested, so we
** create 'dummy access' methods that provide just enough exposure for Python
** test cases to verify the transactional behavior of the methods. */
%extend lucene::store::TransactionalRAMDirectory {
PyObject *dummy_createFile(const char_t* name, PyObject *pyContents) {
if (!PyString_Check(pyContents)) {
PyErr_SetString(PyExc_TypeError, "dummy_createFile requires as second arg");
throw PythonExceptionAlreadySet();
}
const l_byte_t* contents;
int length;
PyString_AsStringAndSize( pyContents, (char **) &contents, &length);
OutputStream* os = &self->createFile(name);
_TRY {
os->writeBytes(contents, length);
} _FINALLY(
os->close();
delete os;
);
RETURN_PY_NONE;
}
PyObject *dummy_deleteFile(const char_t* name) {
self->deleteFile(name);
RETURN_PY_NONE;
}
PyObject *dummy_renameFile(const char_t* from, const char_t* to) {
self->renameFile(from, to);
RETURN_PY_NONE;
}
PyObject *dummy_readFile(const char_t* name) {
PyObject *pyContents = NULL;
InputStream* is = &self->openFile(name);
_TRY {
long_t fileSize = self->fileLength(name);
pyContents = PyString_FromStringAndSize(NULL, fileSize);
if (pyContents == NULL) {
PyErr_NoMemory();
throw PythonExceptionAlreadySet();
}
is->readBytes((l_byte_t *) PyString_AS_STRING(pyContents), 0, fileSize);
} _FINALLY(
is->close();
delete is;
if (PyErr_Occurred()) {
Py_XDECREF(pyContents);
pyContents = NULL;
}
);
return pyContents;
}
};
#endif /* def _SUMO */
/******************* lucene::store : END *******************/
/******************* lucene::document : BEGIN *******************/
/* Field class: */
/* Now implemented in pure Python; CLucene's Field class is not exposed. */
/* DateField class:
** The CLucene DateField class is purely static. I expose its members to SWIG
** primitively, because if I allow SWIG to know of the class, it builds
** boilerplate that is only necessary for a non-static class. */
PyObject *DateField_timeToString(long_t ticks);
long_t DateField_stringToTime(const char_t* s);
%{
static PyObject *DateField_timeToString(long_t ticks) {
char_t *cString = lucene::document::DateField::timeToString(ticks);
PyObject *pyString;
CONVERT_STRING_OUT(cString, pyString);
delete[] cString;
return pyString;
}
static long_t DateField_stringToTime(const char_t* s) {
return lucene::document::DateField::stringToTime(s);
}
%}
/* The Document class is now implemented in pure Python; CLucene's C++ Document
** class is not exposed.
** In fact, nothing from lucene::document is directly exposed for wrapping by
** SWIG, but we still need to make SWIG aware of the lucene::document namespace
** because other header files refer to it. */
%ignore lucene::document;
%include "CLucene/document/Document.h"
/******************* lucene::document : END *******************/
/************************* lucene::index : BEGIN *************************/
/* For the sake of performance (a 4-5x gain), Terms are exposed as 2-tuples
** of (fieldName, text) rather than as class instances. */
%ignore lucene::index::Term;
%include "CLucene/index/Term.i"
/* TermDocs class: */
%rename (doc) lucene::index::TermDocs::Doc() const;
%rename (freq) lucene::index::TermDocs::Freq() const;
%ignore lucene::index::TermDocs::read(int_t docs[], int_t freqs[]);
/* TermPositions class: */
/* TermEnum class: */
%rename (docFreq) lucene::index::TermEnum::DocFreq() const;
/* TermEnum::getTerm accepts a boolean that indicates whether the Term
** reference that it returns is owned by the client client code or merely
** borrowed (the reference counting system is implemented in util/Misc.h by
** IGCollectable). We unconditionally pass true, so we own the reference.
** Then, pyclene.lucene.Term.__del__ is defined to decrement the C++ Term
** object's IGCollectable reference count rather than deleting it outright.
** Conclusion: even though the object returned by TermEnum::getTerm is not
** truly a new object, we must treat it as such. */
/* CACHE_TERM_TUPLES actually worsened the speed of TermEnum iteration slightly
** because the overhead of dictionary lookups on the Term's field and text
** (which are initially available only as C strings, not Python strings)
** outweighed the value of not reconstructing the tuple. */
/*#define CACHE_TERM_TUPLES*/
#ifdef CACHE_TERM_TUPLES
%{ static PyObject *global_termTupleCache = PyDict_New(); %}
#endif
%extend lucene::index::TermEnum {
%{ static %} PyObject *term() {
/* supp_convertTermToPythonTuple is defined in supp_index.cpp */
return supp_convertTermToPythonTuple(self->getTerm(false));
}
%{ static %} PyObject *itercall() {
if (!self->next()) {
RETURN_PY_NONE;
}
lucene::index::Term *term = self->getTerm(false);
PyObject *entry = NULL; /* entry consists of (termTuple, frequency) */
PyObject *termTuple = NULL; /* termTuple consists of (fieldName, text) */
bool entryAlreadyContainsTermTuple = false;
#ifdef CACHE_TERM_TUPLES
const char *termField = term->Field();
const char *termText = term->Text();
PyObject *fieldCache = PyDict_GetItemString(global_termTupleCache, termField);
if (fieldCache == NULL) {
fieldCache = PyDict_New();
FAIL_IF_NULL(fieldCache);
if (PyDict_SetItemString(global_termTupleCache, termField, fieldCache) == -1) {
goto fail;
}
Py_DECREF(fieldCache);
}
termTuple = PyDict_GetItemString(fieldCache, termText);
if (termTuple != NULL) {
Py_INCREF(termTuple);
} else {
#endif
/* supp_convertTermToPythonTuple is defined in supp_index.cpp */
termTuple = supp_convertTermToPythonTuple(term);
FAIL_IF_NULL(termTuple);
#ifdef CACHE_TERM_TUPLES
}
#endif
entry = PyTuple_New(2);
FAIL_IF_NULL(entry);
PyTuple_SET_ITEM(entry, 0, termTuple);
entryAlreadyContainsTermTuple = true;
PyTuple_SET_ITEM(entry, 1, PyInt_FromLong(self->DocFreq()));
#ifdef CACHE_TERM_TUPLES
if (PyDict_SetItemString(fieldCache, termText, termTuple) == -1) {
goto fail;
}
Py_DECREF(termTuple);
#endif /* CACHE_TERM_TUPLES */
return entry;
fail:
if (!PyErr_Occurred()) PyErr_NoMemory();
if (!entryAlreadyContainsTermTuple) Py_XDECREF(termTuple);
Py_XDECREF(entry);
return NULL;
}
};
/* Implement TermEnum.__iter__ here in C++ so that it applies natively to
** lucene.clucene.TermEnum (including pointers returned from the internals of
** CLucene), not only to lucene.TermEnum. */
PyObject *TermEnum__iter__(PyObject *self); /* Make SWIG aware of it. */
%{
static PyObject *TermEnum__iter__(PyObject *self) {
PyObject *iterTarg = PyObject_GetAttrString(self, "itercall");
if (iterTarg == NULL) return NULL;
PyObject *iter = PyCallIter_New(iterTarg, Py_None);
Py_DECREF(iterTarg);
return iter;
}
%}
%ignore lucene::index::TermEnum::getTerm(const bool pointer=true);
%include "CLucene/index/Terms.i"
#ifdef ZZZ_DECIDE_WHETHER_TO_WRAP_THESE
/* It's not clear to me at present whether specific access to these
** subclasses of TermEnum would actually be valuable to the client
** programmer, so I'm deferring their wrapping.
** If they are wrapped at some point in the future, I'll need to move
** lucene.TermEnum.__iter__ to the C++ level so that it's unified with the
** whole _cl_py.TermEnum class hierarchy, rather than existing only on a
** branch of the hierarchy.
/* FuzzyTermEnum class: */
%include "CLucene/search/FuzzyTermEnum.i"
/* WildcardTermEnum class: */
%include "CLucene/search/WildcardTermEnum.h"
#endif /* ZZZ_DECIDE_WHETHER_TO_WRAP_THESE */
/* IndexReader class: */
%immutable lucene::index::IndexReader::directory; /* YYY: Add immutability *enforcer*. */
%newobject lucene::index::IndexReader::open;
%rename (openFromDirName) lucene::index::IndexReader::open(const char_t*, const bool);
%rename (openFromDir) lucene::index::IndexReader::open(lucene::store::Directory&, const bool);
%rename (numDocs) lucene::index::IndexReader::NumDocs();
%rename (maxDoc) lucene::index::IndexReader::MaxDoc const;
%newobject lucene::index::IndexReader::document;
%rename (deleteAt) lucene::index::IndexReader::Delete(const int_t docNum);
%rename (deleteWithTerm) lucene::index::IndexReader::Delete(lucene::index::Term* term);
%ignore lucene::index::IndexReader::getNorms(const char_t* field);
%newobject lucene::index::IndexReader::getTerms() const;
%rename (termsAll) lucene::index::IndexReader::getTerms() const;
%newobject lucene::index::IndexReader::getTerms(const lucene::index::Term* t) const;
%rename (termsSpecific) lucene::index::IndexReader::getTerms(const lucene::index::Term* t) const;
%newobject lucene::index::IndexReader::termDocs;
%rename (termDocsAll) lucene::index::IndexReader::termDocs() const;
%rename (termDocsContaining) lucene::index::IndexReader::termDocs(lucene::index::Term* term) const;
%newobject lucene::index::IndexReader::termPositions;
%rename (termPositionsAll) lucene::index::IndexReader::termPositions() const;
%rename (termPositionsContaining) lucene::index::IndexReader::termPositions(lucene::index::Term* term);
/* IndexReader support classes: */
%ignore lucene::index::IndexReaderLockWith;
/* Have to use custom IndexReader.i rather than IndexReader.h because
** otherwise, SWIG isn't able to resolve all involved classes to their
** namespaces, and generates incorrect code. */
%include "CLucene/index/IndexReader.i"
/* IndexWriter class: */
%extend lucene::index::IndexWriter {
%{ static %} PyObject *addIndexes(PyObject *pyDirs) {
if (!PySequence_Check(pyDirs)) {
PyErr_SetString(PyExc_TypeError, "$dirs must be a sequence.");
return NULL;
}
lucene::store::Directory **cDirs = NULL;
int nDirs = PySequence_Size(pyDirs);
if (nDirs == -1) { /* PySequence_Size call failed. */
goto fail;
} else if (nDirs == 0) {
PyErr_SetString(PyExc_ValueError, "$dirs must not be empty.");
goto fail;
}
cDirs = new lucene::store::Directory *[nDirs];
for (int i = 0; i < nDirs; i++) {
PyObject *curPyDir = PySequence_GetItem(pyDirs, i);
if (curPyDir == NULL) goto fail;
/* Invoke SWIG-defined conversion mechanism: */
const int convAttempt = SWIG_ConvertPtr(curPyDir, (void **) &cDirs[i],
SWIGTYPE_p_lucene__store__Directory, SWIG_POINTER_EXCEPTION | 0
);
Py_DECREF(curPyDir);
if (convAttempt == -1) {
goto fail;
} else if (cDirs[i] == NULL) {
PyErr_SetString(PyExc_TypeError, "Expected Directory object; got None.");
goto fail;
}
}
try {
self->addIndexes(cDirs, nDirs);
} catch (THROW_TYPE &e) { /* THROW_TYPE is defined in CL's StdHeader.h. */
PyErr_SetString(PyExc_Exception, e.what());
goto fail;
}
delete[] cDirs;
RETURN_PY_NONE;
fail:
if (!PyErr_Occurred()) PyErr_NoMemory();
if (cDirs != NULL) delete[] cDirs;
return NULL;
}
};
/* Suppress original C++ impl; we defined our own Python-oriented impl above. */
%ignore lucene::index::IndexWriter::addIndexes(lucene::store::Directory** dirs, const int_t dirsLength);
%ignore lucene::index::IndexWriter::segmentInfos;
%ignore lucene::index::IndexWriter::directory;
%ignore lucene::index::IndexWriter::infoStream;
/* The next three methods are private in the Java impl: */
%ignore lucene::index::IndexWriter::deleteSegments(lucene::util::VoidList<lucene::index::SegmentReader*> &segments);
%ignore lucene::index::IndexWriter::deleteFiles(const StringArrayConst& files, lucene::store::Directory& directory);
%ignore lucene::index::IndexWriter::deleteFiles(const StringArrayConst& files, StringArrayConst& deletable);
/* IndexWriter support classes: */
%ignore lucene::index::IndexWriterLockWith;
%ignore lucene::index::IndexWriterLockWith2;
/* Have to use custom IndexWriter.i rather than IndexWriter.h because
** otherwise, SWIG chokes on nonexistent syntax error. */
%include "CLucene/index/IndexWriter.i"
/************************* lucene::index : END *************************/
/******************* lucene::search : BEGIN *******************/
/* Hits class: */
%feature("shadow") lucene::search::Hits::Hits %{
def __init__(self, searcher=None, query=None, filter=None,
_bypass=None
):
if _bypass is not None:
self.this = _bypass
self.thisown = 1
del _bypass.thisown
else:
newobj = $action(
(searcher is not None and searcher.this) or None,
(query is not None and query.this) or None,
(filter is not None and filter.this) or None
)
# Remember to execute the SWIG boilerplate:
self.this = newobj.this
self.thisown = 1
del newobj.thisown
self._searcher = searcher
%}
/* SWIG 1.3.23 ignores the shadow directive unless the 'const' modifier is
** explicitly included: */
//%feature("shadow") lucene::search::Hits::Length() %{
%feature("shadow") lucene::search::Hits::Length() const %{
def __len__(self):
return $action(self.this)
%}
%feature("shadow") lucene::search::Hits::id(const int_t) %{
def id(self, n):
self._rangeCheck(n)
return $action(self.this, n)
%}
%feature("shadow") lucene::search::Hits::doc(const int_t n) %{
def doc(self, n):
self._rangeCheck(n)
return $action(self.this, n)
%}
%feature("shadow") lucene::search::Hits::score(const int_t n) %{
def score(self, n):
self._rangeCheck(n)
return $action(self.this, n)
%}
%ignore lucene::search::HitDoc; /* Internal supporting class for Hits. */
/* HitCollector class: */
/* Directorize HitCollector so that Python client code can create custom impls: */
%feature("director") lucene::search::HitCollector;
%include "CLucene/search/HitCollector.h"
/* Searcher class: */
/* ZZZ:
** I temporarily 'undirectorized' Searcher and IndexSearcher to escape problems
** that arose after I transitioned from class-based Terms to tuple-based Terms.
** Perhaps I'll have to redirectorize them later for adequate flexibility,
** but there would be considerable performance benefits to not doing so. */
/*%fea ture("director") lucene::search::Searcher;*/
%nodefault lucene::search::Searcher;
%{
#define GENERIC_TRY try
#define GENERIC_CATCH \
catch (THROW_TYPE &e) { \
PyErr_SetString(PyExc_Exception, e.what()); \
return NULL; \
}
%}
/* Experimental rewrite of dynamic-search-selection method in C++: */
%ignore lucene::search::Searcher::Search;
%extend lucene::search::Searcher {
%{ static %} PyObject *search(lucene::search::Query& query,
/* Any of the next three can be missing (i.e., None). */
PyObject *pyFilter, PyObject *pyLimitNDocs, PyObject *pyCollector
)
{
const bool noFilter = (pyFilter == Py_None);
const bool noLimit = (pyLimitNDocs == Py_None);
const bool noCollector = (pyCollector == Py_None);
lucene::search::Filter *filter = NULL;
int_t limitNDocs = -1;
lucene::search::HitCollector *collector = NULL;
/* Convert pyFilter, if any, via SWIG pointer conversion mechanism. */
if (!noFilter) {
if (-1 == (SWIG_ConvertPtr(
pyFilter, (void **) &filter,
SWIGTYPE_p_lucene__search__Filter, SWIG_POINTER_EXCEPTION | 0)
))
{
return NULL; /* SWIG will have already set a TypeError. */
}
}
/* Convert pyLimitNDocs, if any. */
if (noLimit) {
limitNDocs = 50; /* Matches CLucene default. */
} else {
limitNDocs = (int_t) PyInt_AsLong(pyLimitNDocs);
if (PyErr_Occurred()) {
return NULL; /* PyInt_AsLong will have already set an exception. */
}
}
/* Convert pyCollector, if any, via SWIG pointer conversion mechanism. */
if (!noCollector) {
if (-1 == (SWIG_ConvertPtr(
pyCollector, (void **) &collector,
SWIGTYPE_p_lucene__search__HitCollector, SWIG_POINTER_EXCEPTION | 0)
))
{
return NULL; /* SWIG will have already set a TypeError. */
}
}
if (noLimit) {
if (noFilter && noCollector) {
lucene::search::Hits *result;
GENERIC_TRY {
lucene::search::Hits &_result_ref = self->search(query, filter);
result = (lucene::search::Hits *) &_result_ref;
} GENERIC_CATCH
PyObject *pyResult = SWIG_NewPointerObj((void*)(result), SWIGTYPE_p_lucene__search__Hits, 1);
return pyResult;
} else if (noFilter) {
GENERIC_TRY {
self->search(query, *collector);
} GENERIC_CATCH
RETURN_PY_NONE; /* Underlying method has void return type. */
}
}
/* This is not an 'else if' clause because control needs to be able to fall
** through from above. */
if (noCollector) {
/* In the absence of these range checks, CLucene crashes. */
if (limitNDocs <= 0) {
PyErr_SetString(PyExc_ValueError, "limitNDocs must be greater than zero.");
return NULL;
} else if (limitNDocs > 1000) {
PyErr_SetString(PyExc_RuntimeError, /* Really more of a CLBugGuard. */
"This version of CLucene does not operate reliably with large limitNDocs values."
);
return NULL;
}
lucene::search::TopDocs *result;
GENERIC_TRY {
lucene::search::TopDocs &_result_ref = self->Search(query, filter, limitNDocs);
result = (lucene::search::TopDocs *) &_result_ref;
} GENERIC_CATCH
PyObject *pyResult = SWIG_NewPointerObj((void*)(result), SWIGTYPE_p_lucene__search__TopDocs, 1);
return pyResult;
} else {
GENERIC_TRY {
self->Search(query, filter, *collector);
} GENERIC_CATCH
RETURN_PY_NONE; /* Underlying method has void return type. */
}
} /* End of %extend-ed search method. */
};
/* Ignore old impl in favor of our extended version: */
%ignore lucene::search::Searcher::search;
%newobject lucene::search::Searcher::doc;
/* Query class: */
/* ZZZ: In the initial pass, did not wrap the Scorer class or methods used to
** access instances of it. If it is ever wrapped, I suppose it ought to be
** directorized, as long as the performance penalty isn't too severe. */
%ignore lucene::search::Query::scorer;
/* Query.boost is exposed as a public member variable. */
%ignore lucene::search::Query::setBoost(float_t b);
%ignore lucene::search::Query::getBoost();
DEF_PROPERTY_RO(lucene::search::Query, name, const char_t *,
lucene_search_Query_name_get, lucene_search_Query_name_set, getQueryName, yes
)
/* In Python, this info can be determined via introspection: */
%ignore lucene::search::Query::getQueryName() const;
%ignore lucene::search::Query::instanceOf(const char_t* other);
/* Would rename toString to __str__, but it takes a parameter. */
%newobject lucene::search::Query::toString(const char_t* field);
/* We have to use a custom SearchHeader.i file instead of SearchHeader.h
** because SWIG isn't able to track all of the referenced classes back to their
** correct namespaces. */
%include "CLucene/search/SearchHeader.i"
/* MultiSearcher class: */
/* Suppress the C++ constructor in favor of a Python-oriented one: */
%ignore lucene::search::MultiSearcher::MultiSearcher;
%newobject new_MultiSearcher;
lucene::search::MultiSearcher *new_MultiSearcher(PyObject *pySearchers);
%{
static lucene::search::MultiSearcher *new_MultiSearcher(PyObject *pySearchers) {
if (!PySequence_Check(pySearchers)) {
PyErr_SetString(PyExc_TypeError, "$searchers must be a sequence.");
return NULL;
}
lucene::search::Searcher **cSearchers = NULL;
int nSearchers = PySequence_Size(pySearchers);
if (nSearchers == -1) { /* PySequence_Size call failed. */
goto fail;
} else if (nSearchers == 0) {
PyErr_SetString(PyExc_ValueError, "$searchers must not be empty.");
goto fail;
}
cSearchers = new lucene::search::Searcher *[nSearchers];
for (int i = 0; i < nSearchers; i++) {
PyObject *curPySearcher = PySequence_GetItem(pySearchers, i);
if (curPySearcher == NULL) goto fail;
/* Invoke SWIG-defined conversion mechanism: */
const int convAttempt = SWIG_ConvertPtr(curPySearcher, (void **) &cSearchers[i],
SWIGTYPE_p_lucene__search__Searcher, SWIG_POINTER_EXCEPTION | 0
);
Py_DECREF(curPySearcher);
if (convAttempt == -1) goto fail;
if (cSearchers[i] == NULL) {
PyErr_SetString(PyExc_TypeError, "Expected Searcher object; got None.");
goto fail;
}
}
{
lucene::search::MultiSearcher *ms;
try {
ms = new lucene::search::MultiSearcher(cSearchers, nSearchers);
} catch (THROW_TYPE &e) { /* THROW_TYPE is defined in CL's StdHeader.h. */
PyErr_SetString(PyExc_Exception, e.what());
goto fail;
}
return ms;
}
fail:
if (!PyErr_Occurred()) PyErr_NoMemory();
if (cSearchers != NULL) delete[] cSearchers;
throw PythonExceptionAlreadySet();
}
%}
/* The Java implementation of Lucene has deprecated the "searcherIndex" method
** in favor of "subSearcher"; since pyclene arrives on the scene after that,
** we don't bother making the old method name available. */
%rename (subSearcher) searcherIndex(int_t n);
%ignore lucene::search::MultiSearcher::Search;
/* MultiHitCollector is a subclass of HitCollector; we don't need to wrap it
** specifically for Python code to access it via the HitCollector interface. */
%ignore lucene::search::MultiHitCollector;
%include "CLucene/search/MultiSearcher.h"
/* TermQuery class: */
DEF_PROPERTY_RO(lucene::search::TermQuery, term, lucene::index::Term *,
lucene_search_TermQuery_term_get, lucene_search_TermQuery_term_set,
getTerm, yes
)
%feature("shadow") lucene::search::TermQuery::prepare(IndexReader& reader) %{
def prepare(self, reader):
$action(self, reader)
self._prepared = True
%}
%feature("shadow") lucene::search::TermQuery::normalize(const float_t norm) %{
def normalize(self, norm):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
$action(self, norm)
%}
%feature("shadow") lucene::search::TermQuery::sumOfSquaredWeights(Searcher& searcher) %{
def sumOfSquaredWeights(self, searcher):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
return $action(self, (searcher is not None and searcher.this) or None)
%}
%include "CLucene/search/TermQuery.h"
/* MultiTermQuery class: */
%ignore lucene::search::MultiTermQuery::getQuery;
%feature("shadow") lucene::search::MultiTermQuery::normalize(const float_t norm) %{
def normalize(self, norm):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
$action(self, norm)
%}
%feature("shadow") lucene::search::MultiTermQuery::sumOfSquaredWeights(Searcher& searcher) %{
def sumOfSquaredWeights(self, searcher):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
return $action(self, (searcher is not None and searcher.this) or None)
%}
%include "CLucene/search/MultiTermQuery.h"
/* PhraseQuery class: */
%extend lucene::search::PhraseQuery {
%{ static %} PyObject *terms_get() {
Term **terms = NULL;
int_t size[1];
self->getTerms(terms, *size);
PyObject *pyTerms = PyTuple_New(size[0]);
if (pyTerms == NULL) goto fail;
for (int i = 0; i < size[0]; i++) {
/* supp_convertTermToPythonTuple is defined in supp_index.i */
PyObject *t = supp_convertTermToPythonTuple(terms[i]);
if (t == NULL) goto fail;
PyTuple_SET_ITEM(pyTerms, i, t);
}
/* PhraseQuery::getTerms doesn't call IGCollectable::pointer() on each
** Term before placing it in the array, so we need not call
** IGCollectable::finalize(). */
delete[] terms;
return pyTerms;
fail:
Py_XDECREF(pyTerms);
delete[] terms;
if (!PyErr_Occurred()) PyErr_NoMemory();
return NULL;
}
};
%warnfilter(2) PhraseQuery_terms_get;
DEF_PROPERTY_RO(lucene::search::PhraseQuery, terms, PyObject *,
lucene_search_PhraseQuery_terms_get, lucene_search_PhraseQuery_terms_set,
getTerms, no
)
/* Suppress original impls in favor of our Python-oriented replacements: */
%ignore lucene::search::PhraseQuery::terms;
%ignore lucene::search::PhraseQuery::getTerms;
/* Expose slop as r/w property: */
%extend lucene::search::PhraseQuery {
int_t slop;
};
%{
static int_t lucene_search_PhraseQuery_slop_get(lucene::search::PhraseQuery *self) {
return self->getSlop();
}
static void lucene_search_PhraseQuery_slop_set(lucene::search::PhraseQuery *self, int_t slop) {
self->setSlop(slop);
}
%}
/* Suppress original impls in favor of our Python-oriented replacements: */
%ignore lucene::search::PhraseQuery::getSlop;
%ignore lucene::search::PhraseQuery::setSlop;
%feature("shadow") lucene::search::PhraseQuery::prepare(IndexReader& reader) %{
def prepare(self, reader):
$action(self, reader)
self._prepared = True
%}
%feature("shadow") lucene::search::PhraseQuery::normalize(const float_t norm) %{
def normalize(self, norm):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
$action(self, norm)
%}
%feature("shadow") lucene::search::PhraseQuery::sumOfSquaredWeights(Searcher& searcher) %{
def sumOfSquaredWeights(self, searcher):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
return $action(self, (searcher is not None and searcher.this) or None)
%}
%include "CLucene/search/PhraseQuery.h"
/* BooleanClause class: */
%rename (_deleteQuery) lucene::search::BooleanClause::deleteQuery;
%include "CLucene/search/BooleanClause.h"
/* BooleanQuery class: */
%extend lucene::search::BooleanQuery {
%{ static %} PyObject *clauses_get() {
lucene::search::BooleanClause **clauses = self->getClauses();
if (clauses == NULL) return PyErr_NoMemory();
const int_t nClauses = self->getClauseCount();
PyObject *pyClauses = PyTuple_New(nClauses);
if (pyClauses == NULL) goto fail;
for (int i = 0; i < nClauses; i++) {
/* Grabbed this conversion snippet from the SWIG-generated BooleanClause
** constructor _wrap_new_BooleanClause: */
PyObject *c = SWIG_NewPointerObj((void *) clauses[i], SWIGTYPE_p_lucene__search__BooleanClause,
0 /* Zero (false) indicates that the Python proxy doesn't own this. */
);
if (c == NULL) goto fail;
PyTuple_SET_ITEM(pyClauses, i, c);
}
delete[] clauses;
return pyClauses;
fail:
delete[] clauses;
Py_XDECREF(pyClauses);
if (!PyErr_Occurred()) PyErr_NoMemory();
return NULL;
}
};
DEF_PROPERTY_RO(lucene::search::BooleanQuery, clauses, PyObject *,
lucene_search_BooleanQuery_clauses_get, lucene_search_BooleanQuery_clauses_set,
getClauses, no
)
/* Python users can access the clause count as len(q.clauses): */
%ignore lucene::search::BooleanQuery::getClauseCount();
/* Due to difficulties in unifying the CLucene+Term+Query/Python memory
** management models, I decided to expose only the add(BooleanClause) variant
** of BooleanQuery::add. */
%ignore lucene::search::BooleanQuery::add(Query& query, const bool deleteQuery, const bool required, const bool prohibited);
%feature("shadow") lucene::search::BooleanQuery::prepare(IndexReader& reader) %{
def prepare(self, reader):
$action(self, reader)
self._prepared = True
%}
%feature("shadow") lucene::search::BooleanQuery::normalize(const float_t norm) %{
def normalize(self, norm):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
$action(self, norm)
%}
%feature("shadow") lucene::search::BooleanQuery::sumOfSquaredWeights(Searcher& searcher) %{
def sumOfSquaredWeights(self, searcher):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
return $action(self, (searcher is not None and searcher.this) or None)
%}
%include "CLucene/search/BooleanQuery.h"
/* WildcardQuery class: */
%feature("shadow") lucene::search::WildcardQuery::prepare(IndexReader& reader) %{
def prepare(self, reader):
$action(self, reader)
self._prepared = True
%}
%include "CLucene/search/WildcardQuery.h"
/* PrefixQuery class: */
%ignore lucene::search::PrefixQuery::getQuery;
%feature("shadow") lucene::search::PrefixQuery::prepare(IndexReader& reader) %{
def prepare(self, reader):
$action(self, reader)
self._prepared = True
%}
%feature("shadow") lucene::search::PrefixQuery::normalize(const float_t norm) %{
def normalize(self, norm):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
$action(self, norm)
%}
%feature("shadow") lucene::search::PrefixQuery::sumOfSquaredWeights(Searcher& searcher) %{
def sumOfSquaredWeights(self, searcher):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
return $action(self, (searcher is not None and searcher.this) or None)
%}
%include "CLucene/search/PrefixQuery.h"
/* FilteredTermEnum class: */
/* For the sake of FuzzyQuery.h, we make SWIG aware of FilteredTermEnum, then
** ignore it (Python programmers can accesss it via the generic TermEnum
** interface). */
%ignore lucene::search::FilteredTermEnum;
%include "CLucene/search/FilteredTermEnum.i"
/* FuzzyQuery class: */
%feature("shadow") lucene::search::FuzzyQuery::prepare(IndexReader& reader) %{
def prepare(self, reader):
$action(self, reader)
self._prepared = True
%}
%include "CLucene/search/FuzzyQuery.h"
/* RangeQuery class: */
%ignore lucene::search::RangeQuery::getQuery;
%feature("shadow") lucene::search::RangeQuery::prepare(IndexReader& reader) %{
def prepare(self, reader):
$action(self, reader)
self._prepared = True
%}
%feature("shadow") lucene::search::RangeQuery::normalize(const float_t norm) %{
def normalize(self, norm):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
$action(self, norm)
%}
%feature("shadow") lucene::search::RangeQuery::sumOfSquaredWeights(Searcher& searcher) %{
def sumOfSquaredWeights(self, searcher):
if not getattr(self, '_prepared', False):
raise IOError('The prepare method must be called first.')
return $action(self, (searcher is not None and searcher.this) or None)
%}
%include "CLucene/search/RangeQuery.h"
/* Filter class: */
/* Directorize Filter so that Python client code can create custom impls: */
%feature("director") lucene::search::Filter;
/* ZZZ: Couldn't convince SWIG to apply this directive; manually inserted the
** deletion into the typemap. */
/*%newobject lucene::search::Filter::bits;*/
%include "CLucene/search/Filter.h"
/* DateFilter class: */
/* Directorize DateFilter so that Python client code can create custom impls: */
/* YYY: Don't need to explicitly directorize b/c superclass is directorized, right? */
/* %feature("director") lucene::search::DateFilter; */
%newobject lucene::search::DateFilter::Before;
%newobject lucene::search::DateFilter::After;
%feature("shadow") lucene::search::DateFilter::DateFilter %{
def __init__(self, field, fromTime, toTime):
fromTime = _maybeDatetimeToInt(fromTime)
toTime = _maybeDatetimeToInt(toTime)
newobj = $action(field, fromTime, toTime)
# Remember to execute the SWIG boilerplate:
self.this = newobj.this
self.thisown = 1
del newobj.thisown
%}
/* I couldn't convince SWIG's %feature("shadow") directive to static methods
** (such as Before or After). */
%include "CLucene/search/DateFilter.h"
/* TopDocs class: */
/* Expose totalHits as int and scoreDocs as a list of ScoreDoc objects.
** Ignore low-level C++ infrastructural fields. */
%ignore lucene::search::TopDocs::TopDocs(const int_t, lucene::search::ScoreDoc **, const int_t);
%immutable lucene::search::TopDocs::scoreDocs;
%ignore lucene::search::TopDocs::scoreDocsLength;
%ignore lucene::search::TopDocs::deleteScoreDocs;
%extend lucene::search::TopDocs {
%{ static %} PyObject *__iter__() {
/* YYY: Optimization: Should create a TopDocsIterator type instead of
** materializing a tuple and then returning the tuple's iterator. */
/* supp_convertScoreDocsArrayToTupleOfScoreDocsObjects is implemented in
** supp_search.cpp: */
PyObject *pySDocs = supp_convertScoreDocsArrayToTupleOfScoreDocsObjects(
self->scoreDocs, self->scoreDocsLength
);
if (pySDocs == NULL) return NULL;
/* Refcount note: ret is of type tupleiterobject; that type creates a new
** reference to pySDocs for itself, then discards that reference when the
** tupleiterobject object is garbage collected (see Python's
** tupleobject.c:tuple_iter/tupleiter_dealloc). */
PyObject *ret = PyObject_GetIter(pySDocs);
Py_DECREF(pySDocs);
return ret;
}
};
/* Have to use custom TopDocs.i rather than TopDocs.h because otherwise, SWIG
** isn't able to resolve all involved classes to their namespaces, and
** generates incorrect code. */
%include "CLucene/search/TopDocs.i"
/* ScoreDoc class: */
%extend lucene::search::ScoreDoc {
%{ static %} PyObject *__repr__() {
char scoreStr[MAX_POSSIBLE_CHARS_IN_FLOAT_REPR];
sprintf(scoreStr, "%f", self->score);
return PyString_FromFormat("<ScoreDoc (doc=%d, score=%s)>", self->doc, scoreStr);
}
};
%include "CLucene/search/ScoreDoc.h"
/* IndexSearcher class: */
/* ZZZ:
** I temporarily 'undirectorized' Searcher and IndexSearcher to escape problems
** that arose after I transitioned from class-based Terms to tuple-based Terms.
** Perhaps I'll have to redirectorize them later for adequate flexibility,
** but there would be considerable performance benefits to not doing so. */
/*%fea ture("director") lucene::search::IndexSearcher;*/
%rename (IndexSearcher_FromString) lucene::search::IndexSearcher::IndexSearcher(const char_t* path);
%rename (IndexSearcher_FromIndexReader) lucene::search::IndexSearcher::IndexSearcher(lucene::index::IndexReader& r);
/* The next two classes are subclasses of HitCollector, so Python code can
** access them at least minimally without any specific wrapping.
** Since HitCollector is directorized, I don't foresee any need to expose these
** classes explicitly. */
%ignore lucene::search::SimpleFilteredCollector;
%ignore lucene::search::SimpleTopDocsCollector;
/* Have to use custom IndexSearcher.i rather than IndexSearcher.h because
** otherwise, SWIG isn't able to resolve all involved classes to their
** namespaces, and generates code that causes a metaclass conflict. */
%include "CLucene/search/IndexSearcher.i"
/******************* lucene::search : END *******************/
/******************* lucene::analysis : BEGIN *******************/
%ignore lucene::analysis::standard::tokenImage;
/* Token class: */
%ignore lucene::analysis::Token::Token(const char_t* text, const int_t start, const int_t end);
/* YYY: Optimization: It might be worth exploring whether a Python-centric
** implementation of Token that stores its properties as Python objects rather
** than recreating them from their C++ counterparts every time they're accessed
** from Python would perform better in a typical program. */
/* positionIncrement property: */
DEF_PROPERTY_RW(
lucene::analysis::Token, positionIncrement, int_t,
lucene_analysis_Token_positionIncrement_get,
lucene_analysis_Token_positionIncrement_set,
getPositionIncrement,
setPositionIncrement
)
/* 'text' property: */
%ignore lucene::analysis::Token::termText;
%ignore lucene::analysis::Token::TermText;
DEF_PROPERTY_RO(lucene::analysis::Token, text, const char_t *,
lucene_analysis_Token_text_get, lucene_analysis_Token_text_set, TermText, yes
)
/* 'start' property: */
%ignore lucene::analysis::Token::StartOffset;
DEF_PROPERTY_RO(lucene::analysis::Token, start, int_t,
lucene_analysis_Token_start_get, lucene_analysis_Token_start_set, StartOffset, yes
)
/* 'end' property: */
%ignore lucene::analysis::Token::EndOffset;
DEF_PROPERTY_RO(lucene::analysis::Token, end, int_t,
lucene_analysis_Token_end_get, lucene_analysis_Token_end_set, EndOffset, yes
)
/* 'type' property: */
%ignore lucene::analysis::Token::Type;
DEF_PROPERTY_RO(lucene::analysis::Token, type, const char_t *,
lucene_analysis_Token_type_get, lucene_analysis_Token_type_set, Type, yes
)
/* 'sourceSlice' property (defined for Python's sake only): */
%{
static PyObject *lucene_analysis_Token_sourceSlice_get(lucene::analysis::Token *self) {
PyObject *start, *end, *slice;
if ( (start = PyInt_FromLong(self->StartOffset())) == NULL ) {
return NULL;
}
if ( (end = PyInt_FromLong(self->EndOffset())) == NULL ) {
Py_DECREF(start);
return NULL;
}
slice = PySlice_New(start, end, NULL);
/* PySlice_New created its own refs: */
Py_DECREF(start);
Py_DECREF(end);
return slice;
}
%}
DEF_PROPERTY_RO(lucene::analysis::Token, sourceSlice, PyObject *,
lucene_analysis_Token_sourceSlice_get, lucene_analysis_Token_sourceSlice_set,
bogus, no
)
/* TokenStream class: */
/* I originally used directors to expose the TokenStream class and its
** subclasses in a Python-customizable manner, but became so discouraged by
**
** a) SWIG-director bugs
** b) the performance hit of the director-derived-checks when using unextended
** C++ TokenStream subclasses such as StandardAnalyzer
**
** that I reverted to writing a 'has-a' TokenStream C++ subclass that
** simply holds a reference to a Python object and delegates method calls to
** it. (See the supp_analysis inclusions just after the SWIG-inclusion of
** AnalysisHeader.h at the end of this section). */
/*%fea ture("director") lucene::analysis::TokenStream;*/
/* SWIG is smart enough to realize that this newobject directive also applies
** to subclasses' next methods. */
%newobject lucene::analysis::TokenStream::next;
%feature("shadow") lucene::analysis::TokenStream::close %{
close = _makeSingleShotMethod($action, 'closed')
%}
/* None of the direct subclasses of TokenStream are exposed to Python: */
%ignore lucene::analysis::Tokenizer;
%ignore lucene::analysis::TokenFilter;
/* Analyzer class: */
/* The performance hit of directorizing Analyzer is minor since Analyzer is
** not called very granularly. */
%feature("director") lucene::analysis::Analyzer;
%newobject lucene::analysis::Analyzer::tokenStream;
%include "CLucene/analysis/AnalysisHeader.h"
/* Include the Python-oriented PythonTokenStream only at the C++ level (don't
** let SWIG become aware of it). */
%{
#include "supp_analysis.h"
#include "supp_analysis.cpp"
%}
/* StandardTokenizer class: */
/* This class is wrapped rather opaquely; nothing more than the methods defined
** by its ancestor TokenStream are exposed. For a justification of this
** opacity, see the notes about the lack of malleability in CLucene's
** analysis code (above). */
%ignore lucene::analysis::standard::StandardTokenizer::rd;
/* Note that the close method is exposed. */
%ignore lucene::analysis::standard::StandardTokenizer::ReadNumber;
%ignore lucene::analysis::standard::StandardTokenizer::ReadAlphaNum;
%ignore lucene::analysis::standard::StandardTokenizer::ReadApostrophe;
%ignore lucene::analysis::standard::StandardTokenizer::ReadAt;
%ignore lucene::analysis::standard::StandardTokenizer::ReadCompany;
%feature("shadow") lucene::analysis::standard::StandardTokenizer::StandardTokenizer %{
def __init__(self, reader):
if reader is None:
reader = ''
if isinstance(reader, basestring):
reader = StringReader(reader)
newobj = $action(reader)
# Remember to execute the SWIG boilerplate:
self.this = newobj.this
self.thisown = 1
del newobj.thisown
# Unless ref to reader is maintained, it can be released prematurely.
self._reader = reader
%}
%newobject lucene::analysis::standard::StandardTokenizer::next;
/*
%feature("shadow") lucene::analysis::standard::StandardTokenizer::next %{
def next(self):
# Make this method compliant with Python iterator protocol.
nextItem = $action(self)
if nextItem is None:
raise StopIteration
return nextItem
%}
*/
%feature("shadow") lucene::analysis::standard::StandardTokenizer::close %{
close = _makeSingleShotMethod($action, 'closed')
%}
%include "CLucene/analysis/standard/StandardTokenizer.h"
/* StandardAnalyzer class: */
%ignore lucene::analysis::standard::StandardAnalyzer::StandardAnalyzer(char_t* stopWords[], int_t stopWordsLength);
%newobject lucene::analysis::standard::StandardAnalyzer::tokenStream;
%feature("shadow") lucene::analysis::standard::StandardAnalyzer::tokenStream %{
def tokenStream(self, fieldName, reader):
ts = $action(self, fieldName, reader)
# Unless these refs are retained, necessary supporting objects might
# be prematurely garbage collected:
ts._ref_analyzer = self
ts._ref_reader = reader
return ts
%}
%include "CLucene/analysis/standard/StandardAnalyzer.h"
/******************* lucene::analysis : END *******************/
/******************* lucene::queryParser : BEGIN *******************/
/* The same malleability/opacity justifications that apply to the analysis
** code (e.g., StandardTokenizer and StandardAnalyzer) also apply to the query
** parsing code--better to do it in Python. All of the required Query
** subclasses are exposed to allow a Python query parser to emit an objectified
** CLucene query. */
/* QueryParserBase class: */
%ignore lucene::queryParser::QueryParserBase;
%include "CLucene/queryParser/QueryParserBase.h"
/* QueryParser class: */
%newobject lucene::queryParser::QueryParser::Parse;
%rename (parseStatic) lucene::queryParser::QueryParser::Parse(const char_t* query, const char_t* field, Analyzer& analyzer);
/* Only expose the string-based variant of non-static Parse: */
%rename (parse) lucene::queryParser::QueryParser::Parse(const char_t *query);
%ignore lucene::queryParser::QueryParser::Parse(Reader& reader);
%include "CLucene/queryParser/QueryParser.h"
/******************* lucene::queryParser : END *******************/
/* Apply post-processing to generated classes that we couldn't do by more
** elegant means: */
%pythoncode %{
# Directory class:
Directory.__iter__ = lambda self: iter(self.list())
# TermEnum class:
TermEnum.__iter__ = lambda self: _cl_c.TermEnum__iter__(self)
# Token class:
Token.__repr__ = lambda self: '<Token [%d:%d] %s "%s"; pi %d>' % (
self.start, self.end, self.type, self.text, self.positionIncrement
)
# Add an optional argument to the Token constructor to facilite more concise
# setting of the positionIncrement.
_oldTokenConstructor = Token.__init__
def _newTokenConstructor(self, text, start, end, typ='word', positionIncrement=1):
_oldTokenConstructor(self, text, start, end, typ)
# It costs a method call to set positionIncrement; don't do so unless it has
# a non-default value.
if positionIncrement != 1:
self.positionIncrement = positionIncrement
Token.__init__ = _newTokenConstructor
# TokenStream class:
TokenStream.__iter__ = lambda self: iter(self.next, None)
# StandardTokenizer class:
StandardTokenizer.__iter__ = lambda self: iter(self.next, None)
# Hits class:
def _Hits__rangeCheck(self, n):
if n < 0 or n >= len(self):
raise IndexError('Hit number %d not in range(0, %d).' % (n, len(self)))
Hits._rangeCheck = _Hits__rangeCheck
del _Hits__rangeCheck
Hits.__getitem__ = Hits.doc
def _Hits___iter__(self):
for i in xrange(len(self)):
yield self.doc(i)
Hits.__iter__ = _Hits___iter__
# DateFilter class:
def _new_DateFilter_Before(field, cutoffTime):
cutoffTime = _maybeDatetimeToInt(cutoffTime)
return _cl_c.DateFilter_Before(field, cutoffTime)
_new_DateFilter_Before = staticmethod(_new_DateFilter_Before)
DateFilter.Before = _new_DateFilter_Before
def _new_DateFilter_After(field, cutoffTime):
cutoffTime = _maybeDatetimeToInt(cutoffTime)
return _cl_c.DateFilter_After(field, cutoffTime)
_new_DateFilter_After = staticmethod(_new_DateFilter_After)
DateFilter.After = _new_DateFilter_After
# TopDocs class:
TopDocs.__len__ = lambda self: self.totalHits
# ScoreDoc class:
def _ScoreDoc___eq__(self, other):
if not isinstance(other, ScoreDoc):
return False
return self.doc == other.doc and self.score == other.score
ScoreDoc.__eq__ = _ScoreDoc___eq__
%}
/* The following code is injected into the module's initialization function. */
%init %{
/* HI__I_AM_A_BAIT_TOKEN_DELIBERATELY_INSERTED_AT_END_OF_HUGE_FILE__SO_LEAVE_ME_HERE
** HI__I_AM_A_BAIT_TOKEN_DELIBERATELY_INSERTED_AT_END_OF_HUGE_FILE__SO_LEAVE_ME_HERE */
%}