On Sun, Mar 07, 2004 at 07:15:28PM -0600, Jason Sibre wrote: > The problem is that an instance of htmltext that came from the c version > will not accept a mapping object other than a dict, or a subclass of one, > while the python version of htmltext will allow you to provide any > 'mapping-like' object. This is a known bug that I haven't got around to fixing yet. I'm sorry you had to discover it yourself. I've just whipped up a patch that I think fixes the problem in an elegant way. See the attachment. Neil Index: src/_c_htmltext.c =================================================================== --- src/_c_htmltext.c (revision 23644) +++ src/_c_htmltext.c (working copy) @@ -23,8 +23,19 @@ #define QuoteWrapper_Check(v) ((v)->ob_type == &QuoteWrapper_Type) + typedef struct { PyObject_HEAD + PyObject *obj; +} DictWrapperObject; + +static PyTypeObject DictWrapper_Type; + +#define DictWrapper_Check(v) ((v)->ob_type == &DictWrapper_Type) + + +typedef struct { + PyObject_HEAD int html; char *buf; size_t size; @@ -179,6 +190,38 @@ } static PyObject * +dict_wrapper_new(PyObject *o) +{ + DictWrapperObject *self; + self = PyObject_New(DictWrapperObject, &DictWrapper_Type); + if (self == NULL) + return NULL; + Py_INCREF(o); + self->obj = o; + return (PyObject *)self; +} + +static void +dict_wrapper_dealloc(DictWrapperObject *self) +{ + Py_DECREF(self->obj); + PyObject_Del(self); +} + +static PyObject * +dict_wrapper_subscript(DictWrapperObject *self, PyObject *key) +{ + PyObject *v, *w;; + v = PyObject_GetItem(self->obj, key); + if (v == NULL) { + return NULL; + } + w = quote_wrapper_new(v); + Py_DECREF(v); + return w; +} + +static PyObject * htmltext_from_string(PyObject *s) { /* note, this takes a reference */ @@ -316,21 +359,9 @@ } } if (do_dict) { - int pos = 0; - PyObject *key, *value; - wargs = PyDict_New(); - while (PyDict_Next(args, &pos, &key, &value)) { - PyObject *wvalue = wrap_arg(value); - if (wvalue == NULL) { - Py_DECREF(wargs); - return NULL; - } - if (PyDict_SetItem(wargs, key, wvalue) < 0) { - Py_DECREF(wargs); - return NULL; - } - Py_DECREF(wvalue); - } + wargs = dict_wrapper_new(args); + if (wargs == NULL) + return NULL; } else if (PyTuple_Check(args)) { long i, n = PyTuple_GET_SIZE(args); @@ -808,6 +839,30 @@ (unaryfunc)quote_wrapper_str, /*tp_str*/ }; +static PyMappingMethods dict_wrapper_as_mapping = { + 0, /*mp_length*/ + (binaryfunc)dict_wrapper_subscript, /*mp_subscript*/ + 0, /*mp_ass_subscript*/ +}; + +static PyTypeObject DictWrapper_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "DictWrapper", /*tp_name*/ + sizeof(DictWrapperObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)dict_wrapper_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &dict_wrapper_as_mapping,/*tp_as_mapping*/ +}; + static PyNumberMethods template_io_as_number = { 0, /*nb_add*/ 0, /*nb_subtract*/ Index: _py_htmltext.py =================================================================== --- _py_htmltext.py (revision 23644) +++ _py_htmltext.py (working copy) @@ -72,24 +72,18 @@ def __mod__(self, args): codes = [] usedict = 0 - klass = self.__class__ for format in _format_re.findall(self.s): if format[-1] != '%': if format[1] == '(': usedict = 1 codes.append(format[-1]) if usedict: - if not hasattr(args, "items"): - raise TypeError, "mapping required" - wrapped_args = {} - for (k, v) in args.items(): - wrapped_args[k] = _wraparg(klass, v) - args = wrapped_args + args = _DictWrapper(args) else: if len(codes) == 1 and not isinstance(args, TupleType): args = (args,) - args = tuple([_wraparg(klass, arg) for arg in args]) - return klass(self.s % args) + args = tuple([_wraparg(arg) for arg in args]) + return self.__class__(self.s % args) def __add__(self, other): if isinstance(other, StringType): @@ -169,8 +163,15 @@ def __repr__(self): return self.escape(`self.value`) -def _wraparg(klass, arg): - if (classof(arg) is klass or +class _DictWrapper(object): + def __init__(self, value): + self.value = value + + def __getitem__(self, key): + return _wraparg(self.value[key]) + +def _wraparg(arg): + if (classof(arg) is htmltext or isinstance(arg, IntType) or isinstance(arg, LongType) or isinstance(arg, FloatType)):