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)):