diff --git a/quixote/html/_c_htmltext.c b/quixote/html/_c_htmltext.c
index 407a406..d837b09 100644
--- a/quixote/html/_c_htmltext.c
+++ b/quixote/html/_c_htmltext.c
@@ -3,12 +3,6 @@
#include "Python.h"
#include "structmember.h"
-#if PY_VERSION_HEX < 0x02050000
-typedef int Py_ssize_t;
-typedef intargfunc ssizeargfunc;
-typedef inquiry lenfunc;
-#endif
-
typedef struct {
PyObject_HEAD
PyObject *s;
@@ -16,7 +10,7 @@ typedef struct {
static PyTypeObject htmltext_Type;
-#define htmltextObject_Check(v) PyType_IsSubtype((v)->ob_type, &htmltext_Type)
+#define htmltextObject_Check(v) PyType_IsSubtype(Py_TYPE(v), &htmltext_Type)
#define htmltext_STR(v) ((PyObject *)(((htmltextObject *)v)->s))
@@ -27,16 +21,7 @@ typedef struct {
static PyTypeObject QuoteWrapper_Type;
-#define QuoteWrapper_Check(v) ((v)->ob_type == &QuoteWrapper_Type)
-
-typedef struct {
- PyUnicodeObject escaped;
- PyObject *raw;
-} UnicodeWrapperObject;
-
-static PyTypeObject UnicodeWrapper_Type;
-
-#define UnicodeWrapper_Check(v) ((v)->ob_type == &UnicodeWrapper_Type)
+#define QuoteWrapper_Check(v) (Py_TYPE(v) == &QuoteWrapper_Type)
typedef struct {
PyObject_HEAD
@@ -46,7 +31,7 @@ typedef struct {
static PyTypeObject TemplateIO_Type;
-#define TemplateIO_Check(v) ((v)->ob_type == &TemplateIO_Type)
+#define TemplateIO_Check(v) (Py_TYPE(v) == &TemplateIO_Type)
static PyObject *
@@ -56,41 +41,21 @@ type_error(const char *msg)
return NULL;
}
-static int
-string_check(PyObject *v)
-{
- return PyUnicode_Check(v) || PyString_Check(v);
-}
-
static PyObject *
stringify(PyObject *obj)
{
- static PyObject *unicodestr = NULL;
- PyObject *res, *func;
- if (string_check(obj)) {
+ PyObject *res;
+ if (PyUnicode_Check(obj) || PyBytes_Check(obj)) {
Py_INCREF(obj);
return obj;
}
- if (unicodestr == NULL) {
- unicodestr = PyString_InternFromString("__unicode__");
- if (unicodestr == NULL)
- return NULL;
- }
- func = PyObject_GetAttr(obj, unicodestr);
- if (func != NULL) {
- res = PyEval_CallObject(func, (PyObject *)NULL);
- Py_DECREF(func);
- }
- else {
- PyErr_Clear();
- if (obj->ob_type->tp_str != NULL)
- res = (*obj->ob_type->tp_str)(obj);
- else
- res = PyObject_Repr(obj);
- }
+ if (Py_TYPE(obj)->tp_str != NULL)
+ res = (*Py_TYPE(obj)->tp_str)(obj);
+ else
+ res = PyObject_Repr(obj);
if (res == NULL)
return NULL;
- if (!string_check(res)) {
+ if (!PyUnicode_Check(res)) {
Py_DECREF(res);
return type_error("string object required");
}
@@ -98,153 +63,116 @@ stringify(PyObject *obj)
}
static PyObject *
-escape_string(PyObject *obj)
+escape_unicode(PyObject *pystr)
{
- char *s;
- PyObject *newobj;
- Py_ssize_t i, j, extra_space, size, new_size;
- assert (PyString_Check(obj));
- size = PyString_GET_SIZE(obj);
- extra_space = 0;
- for (i=0; i < size; i++) {
- switch (PyString_AS_STRING(obj)[i]) {
- case '&':
- extra_space += 4;
- break;
- case '<':
- case '>':
- extra_space += 3;
- break;
- case '"':
- extra_space += 5;
- break;
- }
- }
- if (extra_space == 0) {
- Py_INCREF(obj);
- return (PyObject *)obj;
- }
- new_size = size + extra_space;
- newobj = PyString_FromStringAndSize(NULL, new_size);
- if (newobj == NULL)
- return NULL;
- s = PyString_AS_STRING(newobj);
- for (i=0, j=0; i < size; i++) {
- switch (PyString_AS_STRING(obj)[i]) {
- case '&':
- s[j++] = '&';
- s[j++] = 'a';
- s[j++] = 'm';
- s[j++] = 'p';
- s[j++] = ';';
- break;
- case '<':
- s[j++] = '&';
- s[j++] = 'l';
- s[j++] = 't';
- s[j++] = ';';
- break;
- case '>':
- s[j++] = '&';
- s[j++] = 'g';
- s[j++] = 't';
- s[j++] = ';';
- break;
- case '"':
- s[j++] = '&';
- s[j++] = 'q';
- s[j++] = 'u';
- s[j++] = 'o';
- s[j++] = 't';
- s[j++] = ';';
- break;
- default:
- s[j++] = PyString_AS_STRING(obj)[i];
- break;
- }
- }
- assert (j == new_size);
- return (PyObject *)newobj;
-}
+ /* Take a PyUnicode pystr and return a new escaped PyUnicode */
+ Py_ssize_t i;
+ Py_ssize_t input_chars;
+ Py_ssize_t extra_chars;
+ Py_ssize_t chars;
+ PyObject *rval;
+ void *input;
+ int kind;
+ Py_UCS4 maxchar;
-static PyObject *
-escape_unicode(PyObject *obj)
-{
- Py_UNICODE *u;
- PyObject *newobj;
- Py_ssize_t i, j, extra_space, size, new_size;
- assert (PyUnicode_Check(obj));
- size = PyUnicode_GET_SIZE(obj);
- extra_space = 0;
- for (i=0; i < size; i++) {
- switch (PyUnicode_AS_UNICODE(obj)[i]) {
+ if (PyUnicode_READY(pystr) == -1)
+ return NULL;
+
+ maxchar = PyUnicode_MAX_CHAR_VALUE(pystr);
+ input_chars = PyUnicode_GET_LENGTH(pystr);
+ input = PyUnicode_DATA(pystr);
+ kind = PyUnicode_KIND(pystr);
+
+ /* Compute the output size */
+ for (i = 0, extra_chars = 0; i < input_chars; i++) {
+ Py_UCS4 c = PyUnicode_READ(kind, input, i);
+ switch (c) {
case '&':
- extra_space += 4;
+ extra_chars += 4;
break;
case '<':
case '>':
- extra_space += 3;
+ extra_chars += 3;
break;
case '"':
- extra_space += 5;
+ extra_chars += 5;
break;
}
}
- if (extra_space == 0) {
- Py_INCREF(obj);
- return (PyObject *)obj;
- }
- new_size = size + extra_space;
- newobj = PyUnicode_FromUnicode(NULL, new_size);
- if (newobj == NULL) {
+ if (extra_chars > PY_SSIZE_T_MAX - input_chars) {
+ PyErr_SetString(PyExc_OverflowError,
+ "string is too long to escape");
return NULL;
}
- u = PyUnicode_AS_UNICODE(newobj);
- for (i=0, j=0; i < size; i++) {
- switch (PyUnicode_AS_UNICODE(obj)[i]) {
- case '&':
- u[j++] = '&';
- u[j++] = 'a';
- u[j++] = 'm';
- u[j++] = 'p';
- u[j++] = ';';
- break;
- case '<':
- u[j++] = '&';
- u[j++] = 'l';
- u[j++] = 't';
- u[j++] = ';';
- break;
- case '>':
- u[j++] = '&';
- u[j++] = 'g';
- u[j++] = 't';
- u[j++] = ';';
- break;
- case '"':
- u[j++] = '&';
- u[j++] = 'q';
- u[j++] = 'u';
- u[j++] = 'o';
- u[j++] = 't';
- u[j++] = ';';
- break;
- default:
- u[j++] = PyUnicode_AS_UNICODE(obj)[i];
- break;
- }
+
+ rval = PyUnicode_New(input_chars + extra_chars, maxchar);
+ if (rval == NULL)
+ return NULL;
+
+ kind = PyUnicode_KIND(rval);
+
+#define ENCODE_OUTPUT do { \
+ chars = 0; \
+ for (i = 0; i < input_chars; i++) { \
+ Py_UCS4 c = PyUnicode_READ(kind, input, i); \
+ switch (c) { \
+ case '&': \
+ output[chars++] = '&'; \
+ output[chars++] = 'a'; \
+ output[chars++] = 'm'; \
+ output[chars++] = 'p'; \
+ output[chars++] = ';'; \
+ break; \
+ case '<': \
+ output[chars++] = '&'; \
+ output[chars++] = 'l'; \
+ output[chars++] = 't'; \
+ output[chars++] = ';'; \
+ break; \
+ case '>': \
+ output[chars++] = '&'; \
+ output[chars++] = 'g'; \
+ output[chars++] = 't'; \
+ output[chars++] = ';'; \
+ break; \
+ case '"': \
+ output[chars++] = '&'; \
+ output[chars++] = 'q'; \
+ output[chars++] = 'u'; \
+ output[chars++] = 'o'; \
+ output[chars++] = 't'; \
+ output[chars++] = ';'; \
+ break; \
+ default: \
+ output[chars++] = c; \
+ } \
+ } \
+ } while (0)
+
+ if (kind == PyUnicode_1BYTE_KIND) {
+ Py_UCS1 *output = PyUnicode_1BYTE_DATA(rval);
+ ENCODE_OUTPUT;
+ } else if (kind == PyUnicode_2BYTE_KIND) {
+ Py_UCS2 *output = PyUnicode_2BYTE_DATA(rval);
+ ENCODE_OUTPUT;
+ } else {
+ Py_UCS4 *output = PyUnicode_4BYTE_DATA(rval);
+ assert(kind == PyUnicode_4BYTE_KIND);
+ ENCODE_OUTPUT;
}
- assert (j == new_size);
- return (PyObject *)newobj;
+ assert (chars == input_chars + extra_chars);
+#undef ENCODE_OUTPUT
+
+#ifdef Py_DEBUG
+ assert(_PyUnicode_CheckConsistency(rval, 1));
+#endif
+return rval;
}
static PyObject *
escape(PyObject *obj)
{
- if (PyString_Check(obj)) {
- return escape_string(obj);
- }
- else if (PyUnicode_Check(obj)) {
+ if (PyUnicode_Check(obj)) {
return escape_unicode(obj);
}
else {
@@ -257,19 +185,11 @@ quote_wrapper_new(PyObject *o)
{
QuoteWrapperObject *self;
if (htmltextObject_Check(o)) {
- /* Necessary to work around a PyString_Format bug. Should be
- * fixed in Python 2.5. */
o = htmltext_STR(o);
Py_INCREF(o);
return o;
}
- if (PyUnicode_Check(o)) {
- /* again, work around PyString_Format bug */
- return PyObject_CallFunctionObjArgs(
- (PyObject *)&UnicodeWrapper_Type, o, NULL);
- }
- if (PyInt_Check(o) ||
- PyFloat_Check(o) ||
+ if (PyFloat_Check(o) ||
PyLong_Check(o)) {
/* no need for wrapper */
Py_INCREF(o);
@@ -327,54 +247,6 @@ quote_wrapper_subscript(QuoteWrapperObject *self, PyObject *key)
return w;
}
-static PyObject *
-unicode_wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *result;
- PyObject *raw = NULL, *escaped = NULL, *newargs = NULL;
- if (!PyArg_ParseTuple(args, "O", &raw))
- goto error;
- escaped = escape(raw);
- if (escaped == NULL)
- goto error;
- newargs = PyTuple_New(1);
- if (newargs == NULL)
- goto error;
- PyTuple_SET_ITEM(newargs, 0, escaped);
- result = PyUnicode_Type.tp_new(type, newargs, kwds);
- if (result == NULL)
- goto error;
- Py_DECREF(newargs);
- Py_INCREF(raw);
- ((UnicodeWrapperObject *)result)->raw = raw;
- return result;
-
-error:
- Py_XDECREF(raw);
- Py_XDECREF(escaped);
- Py_XDECREF(newargs);
- return NULL;
-}
-
-static void
-unicode_wrapper_dealloc(UnicodeWrapperObject *self)
-{
- Py_XDECREF(self->raw);
- PyUnicode_Type.tp_dealloc((PyObject *) self);
-}
-
-static PyObject *
-unicode_wrapper_repr(UnicodeWrapperObject *self)
-{
- PyObject *qr;
- PyObject *r = PyObject_Repr(self->raw);
- if (r == NULL)
- return NULL;
- qr = escape(r);
- Py_DECREF(r);
- return qr;
-}
-
static PyObject *
htmltext_from_string(PyObject *s)
{
@@ -382,7 +254,7 @@ htmltext_from_string(PyObject *s)
PyObject *self;
if (s == NULL)
return NULL;
- assert (string_check(s));
+ assert (PyUnicode_Check(s));
self = PyType_GenericAlloc(&htmltext_Type, 0);
if (self == NULL) {
Py_DECREF(s);
@@ -419,7 +291,7 @@ static void
htmltext_dealloc(htmltextObject *self)
{
Py_DECREF(self->s);
- self->ob_type->tp_free((PyObject *)self);
+ Py_TYPE(self)->tp_free((PyObject *)self);
}
static long
@@ -442,7 +314,7 @@ htmltext_repr(htmltextObject *self)
sr = PyObject_Repr((PyObject *)self->s);
if (sr == NULL)
return NULL;
- rv = PyString_FromFormat("", PyString_AsString(sr));
+ rv = PyUnicode_FromFormat("", PyUnicode_AsUTF8(sr));
Py_DECREF(sr);
return rv;
}
@@ -470,15 +342,8 @@ static PyObject *
htmltext_format(htmltextObject *self, PyObject *args)
{
/* wrap the format arguments with QuoteWrapperObject */
- int is_unicode;
PyObject *rv, *wargs;
- if (PyUnicode_Check(self->s)) {
- is_unicode = 1;
- }
- else {
- is_unicode = 0;
- assert (PyString_Check(self->s));
- }
+ assert (PyUnicode_Check(self->s));
if (PyTuple_Check(args)) {
Py_ssize_t i, n = PyTuple_GET_SIZE(args);
wargs = PyTuple_New(n);
@@ -497,10 +362,7 @@ htmltext_format(htmltextObject *self, PyObject *args)
if (wargs == NULL)
return NULL;
}
- if (is_unicode)
- rv = PyUnicode_Format(self->s, wargs);
- else
- rv = PyString_Format(self->s, wargs);
+ rv = PyUnicode_Format(self->s, wargs);
Py_DECREF(wargs);
return htmltext_from_string(rv);
}
@@ -515,7 +377,16 @@ htmltext_add(PyObject *v, PyObject *w)
Py_INCREF(qv);
Py_INCREF(qw);
}
- else if (string_check(w)) {
+ else if (PyUnicode_Check(v)) {
+ assert (htmltextObject_Check(w));
+ qw = htmltext_STR(w);
+ qv = escape(v);
+ if (qv == NULL)
+ return NULL;
+ Py_INCREF(qw);
+
+ }
+ else if (PyUnicode_Check(w)) {
assert (htmltextObject_Check(v));
qv = htmltext_STR(v);
qw = escape(w);
@@ -523,28 +394,14 @@ htmltext_add(PyObject *v, PyObject *w)
return NULL;
Py_INCREF(qv);
}
- else if (string_check(v)) {
- assert (htmltextObject_Check(w));
- qv = escape(v);
- if (qv == NULL)
- return NULL;
- qw = htmltext_STR(w);
- Py_INCREF(qw);
- }
else {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
- if (PyString_Check(qv)) {
- PyString_ConcatAndDel(&qv, qw);
- rv = qv;
- }
- else {
- assert (PyUnicode_Check(qv));
- rv = PyUnicode_Concat(qv, qw);
- Py_DECREF(qv);
- Py_DECREF(qw);
- }
+ assert (PyUnicode_Check(qv));
+ rv = PyUnicode_Concat(qv, qw);
+ Py_DECREF(qv);
+ Py_DECREF(qw);
return htmltext_from_string(rv);
}
@@ -577,7 +434,7 @@ htmltext_join(PyObject *self, PyObject *args)
Py_INCREF(qvalue);
}
else {
- if (!string_check(value)) {
+ if (!PyUnicode_Check(value)) {
type_error("join requires a list of strings");
goto error;
}
@@ -589,12 +446,8 @@ htmltext_join(PyObject *self, PyObject *args)
goto error;
}
}
- if (PyUnicode_Check(htmltext_STR(self))) {
- rv = PyUnicode_Join(htmltext_STR(self), quoted_args);
- }
- else {
- rv = _PyString_Join(htmltext_STR(self), quoted_args);
- }
+ assert (PyUnicode_Check(htmltext_STR(self)));
+ rv = PyUnicode_Join(htmltext_STR(self), quoted_args);
Py_DECREF(quoted_args);
return htmltext_from_string(rv);
@@ -607,7 +460,7 @@ static PyObject *
quote_arg(PyObject *s)
{
PyObject *ss;
- if (string_check(s)) {
+ if (PyUnicode_Check(s)) {
ss = escape(s);
if (ss == NULL)
return NULL;
@@ -634,7 +487,6 @@ htmltext_call_method1(PyObject *self, PyObject *s, char *method)
return rv;
}
-#if PY_VERSION_HEX >= 0x02060000
static PyObject *
call_method_kwargs(PyObject *self, char *method, PyObject *args,
PyObject *kwargs)
@@ -647,7 +499,6 @@ call_method_kwargs(PyObject *self, char *method, PyObject *args,
Py_DECREF(m);
return rv;
}
-#endif
static PyObject *
htmltext_startswith(PyObject *self, PyObject *s)
@@ -666,13 +517,8 @@ htmltext_replace(PyObject *self, PyObject *args)
{
PyObject *old, *new, *q_old, *q_new, *rv;
Py_ssize_t maxsplit = -1;
-#if PY_VERSION_HEX >= 0x02050000
if (!PyArg_ParseTuple(args,"OO|n:replace", &old, &new, &maxsplit))
return NULL;
-#else
- if (!PyArg_ParseTuple(args,"OO|i:replace", &old, &new, &maxsplit))
- return NULL;
-#endif
q_old = quote_arg(old);
if (q_old == NULL)
return NULL;
@@ -681,14 +527,8 @@ htmltext_replace(PyObject *self, PyObject *args)
Py_DECREF(q_old);
return NULL;
}
-#if PY_VERSION_HEX >= 0x02050000
rv = PyObject_CallMethod(htmltext_STR(self), "replace", "OOn",
q_old, q_new, maxsplit);
-#else
- rv = PyObject_CallMethod(htmltext_STR(self), "replace", "OOi",
- q_old, q_new, maxsplit);
-#endif
-
Py_DECREF(q_old);
Py_DECREF(q_new);
return htmltext_from_string(rv);
@@ -716,7 +556,6 @@ htmltext_capitalize(PyObject *self)
"capitalize", ""));
}
-#if PY_VERSION_HEX >= 0x02060000
static PyObject *
htmltext_format_method(PyObject *self, PyObject *args, PyObject *kwargs)
{
@@ -755,14 +594,13 @@ htmltext_format_method(PyObject *self, PyObject *args, PyObject *kwargs)
}
}
rv = call_method_kwargs(htmltext_STR(self), "format", wargs, wkwargs);
- if (rv && string_check(rv))
+ if (rv && PyUnicode_Check(rv))
rv = htmltext_from_string(rv);
error:
Py_DECREF(wargs);
Py_XDECREF(wkwargs);
return rv;
}
-#endif
static PyObject *
@@ -791,7 +629,7 @@ static void
template_io_dealloc(TemplateIO_Object *self)
{
Py_DECREF(self->data);
- self->ob_type->tp_free((PyObject *)self);
+ Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyObject *
@@ -799,11 +637,11 @@ template_io_str(TemplateIO_Object *self)
{
static PyObject *empty = NULL;
if (empty == NULL) {
- empty = PyString_FromStringAndSize(NULL, 0);
+ empty = PyUnicode_FromStringAndSize(NULL, 0);
if (empty == NULL)
return NULL;
}
- return _PyString_Join(empty, self->data);
+ return PyUnicode_Join(empty, self->data);
}
static PyObject *
@@ -860,10 +698,8 @@ static PyMethodDef htmltext_methods[] = {
{"lower", (PyCFunction)htmltext_lower, METH_NOARGS, ""},
{"upper", (PyCFunction)htmltext_upper, METH_NOARGS, ""},
{"capitalize", (PyCFunction)htmltext_capitalize, METH_NOARGS, ""},
-#if PY_VERSION_HEX >= 0x02060000
{"format", (PyCFunction)htmltext_format_method,
METH_VARARGS | METH_KEYWORDS, ""},
-#endif
{NULL, NULL}
};
@@ -874,7 +710,7 @@ static PyMemberDef htmltext_members[] = {
static PySequenceMethods htmltext_as_sequence = {
(lenfunc)htmltext_length, /*sq_length*/
- 0, /*sq_concat*/
+ 0, /*sq_concat*/
(ssizeargfunc)htmltext_repeat, /*sq_repeat*/
0, /*sq_item*/
0, /*sq_slice*/
@@ -887,29 +723,11 @@ static PyNumberMethods htmltext_as_number = {
(binaryfunc)htmltext_add, /*nb_add*/
0, /*nb_subtract*/
0, /*nb_multiply*/
- 0, /*nb_divide*/
(binaryfunc)htmltext_format, /*nb_remainder*/
- 0, /*nb_divmod*/
- 0, /*nb_power*/
- 0, /*nb_negative*/
- 0, /*nb_positive*/
- 0, /*nb_absolute*/
- 0, /*nb_nonzero*/
- 0, /*nb_invert*/
- 0, /*nb_lshift*/
- 0, /*nb_rshift*/
- 0, /*nb_and*/
- 0, /*nb_xor*/
- 0, /*nb_or*/
- 0, /*nb_coerce*/
- 0, /*nb_int*/
- 0, /*nb_long*/
- 0, /*nb_float*/
};
static PyTypeObject htmltext_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
"htmltext", /*tp_name*/
sizeof(htmltextObject), /*tp_basicsize*/
0, /*tp_itemsize*/
@@ -918,7 +736,7 @@ static PyTypeObject htmltext_Type = {
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
- 0, /*tp_compare*/
+ 0, /*tp_reserved*/
(unaryfunc)htmltext_repr,/*tp_repr*/
&htmltext_as_number, /*tp_as_number*/
&htmltext_as_sequence, /*tp_as_sequence*/
@@ -926,11 +744,10 @@ static PyTypeObject htmltext_Type = {
htmltext_hash, /*tp_hash*/
0, /*tp_call*/
(unaryfunc)htmltext_str,/*tp_str*/
- 0, /*tp_getattro set to PyObject_GenericGetAttr by module init*/
+ 0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE \
- | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
@@ -947,36 +764,12 @@ static PyTypeObject htmltext_Type = {
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
0, /*tp_init*/
- 0, /*tp_alloc set to PyType_GenericAlloc by module init*/
+ 0, /*tp_alloc*/
htmltext_new, /*tp_new*/
- 0, /*tp_free set to _PyObject_Del by module init*/
+ 0, /*tp_free*/
0, /*tp_is_gc*/
};
-static PyNumberMethods quote_wrapper_as_number = {
- 0, /*nb_add*/
- 0, /*nb_subtract*/
- 0, /*nb_multiply*/
- 0, /*nb_divide*/
- 0, /*nb_remainder*/
- 0, /*nb_divmod*/
- 0, /*nb_power*/
- 0, /*nb_negative*/
- 0, /*nb_positive*/
- 0, /*nb_absolute*/
- 0, /*nb_nonzero*/
- 0, /*nb_invert*/
- 0, /*nb_lshift*/
- 0, /*nb_rshift*/
- 0, /*nb_and*/
- 0, /*nb_xor*/
- 0, /*nb_or*/
- 0, /*nb_coerce*/
- 0, /*nb_int*/
- 0, /*nb_long*/
- 0, /*nb_float*/
-};
-
static PyMappingMethods quote_wrapper_as_mapping = {
0, /*mp_length*/
(binaryfunc)quote_wrapper_subscript, /*mp_subscript*/
@@ -985,104 +778,47 @@ static PyMappingMethods quote_wrapper_as_mapping = {
static PyTypeObject QuoteWrapper_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
"QuoteWrapper", /*tp_name*/
sizeof(QuoteWrapperObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- /* methods */
- (destructor)quote_wrapper_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- (unaryfunc)quote_wrapper_repr,/*tp_repr*/
- "e_wrapper_as_number,/*tp_as_number*/
- 0, /*tp_as_sequence*/
- "e_wrapper_as_mapping,/*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- (unaryfunc)quote_wrapper_str, /*tp_str*/
+ 0,
+ (destructor)quote_wrapper_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (unaryfunc)quote_wrapper_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ "e_wrapper_as_mapping, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ (unaryfunc)quote_wrapper_str, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
};
-static PyTypeObject UnicodeWrapper_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
- "UnicodeWrapper", /*tp_name*/
- sizeof(UnicodeWrapperObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- /* methods */
- (destructor)unicode_wrapper_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- (unaryfunc)unicode_wrapper_repr, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro */
- 0, /*tp_setattro */
- 0, /*tp_as_buffer */
- Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags */
- 0, /*tp_doc */
- 0, /*tp_traverse */
- 0, /*tp_clear */
- 0, /*tp_richcompare */
- 0, /*tp_weaklistoffset */
- 0, /*tp_iter */
- 0, /*tp_iternext */
- 0, /*tp_methods */
- 0, /*tp_members */
- 0, /*tp_getset */
- 0, /*tp_base */
- 0, /*tp_dict */
- 0, /*tp_descr_get */
- 0, /*tp_descr_set */
- 0, /*tp_dictoffset */
- 0, /*tp_init */
- 0, /*tp_alloc */
- (newfunc)unicode_wrapper_new, /*tp_new */
+static PySequenceMethods template_io_as_seq = {
+ 0, /* sq_length */
+ 0, /* sq_concat */
+ 0, /* sq_repeat */
+ 0, /* sq_item */
+ 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ 0, /* sq_contains */
+ (binaryfunc)template_io_iadd, /* sq_inplace_concat */
+ 0, /* sq_inplace_repeat */
};
-
-static PyNumberMethods template_io_as_number = {
- 0, /*nb_add*/
- 0, /*nb_subtract*/
- 0, /*nb_multiply*/
- 0, /*nb_divide*/
- 0, /*nb_remainder*/
- 0, /*nb_divmod*/
- 0, /*nb_power*/
- 0, /*nb_negative*/
- 0, /*nb_positive*/
- 0, /*nb_absolute*/
- 0, /*nb_nonzero*/
- 0, /*nb_invert*/
- 0, /*nb_lshift*/
- 0, /*nb_rshift*/
- 0, /*nb_and*/
- 0, /*nb_xor*/
- 0, /*nb_or*/
- 0, /*nb_coerce*/
- 0, /*nb_int*/
- 0, /*nb_long*/
- 0, /*nb_float*/
- 0, /*nb_oct*/
- 0, /*nb_hex*/
- (binaryfunc)template_io_iadd, /*nb_inplace_add*/
-};
-
static PyMethodDef template_io_methods[] = {
{"getvalue", (PyCFunction)template_io_getvalue, METH_NOARGS, ""},
{NULL, NULL}
};
static PyTypeObject TemplateIO_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
"TemplateIO", /*tp_name*/
sizeof(TemplateIO_Object),/*tp_basicsize*/
0, /*tp_itemsize*/
@@ -1093,8 +829,8 @@ static PyTypeObject TemplateIO_Type = {
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
- &template_io_as_number, /*tp_as_number*/
- 0, /*tp_as_sequence*/
+ 0, /*tp_as_number*/
+ &template_io_as_seq, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
@@ -1168,28 +904,34 @@ static PyMethodDef htmltext_module_methods[] = {
static char module_doc[] = "htmltext string type";
-void
-init_c_htmltext(void)
+static struct PyModuleDef htmltext_module = {
+ PyModuleDef_HEAD_INIT,
+ "_c_htmltext",
+ module_doc,
+ -1,
+ htmltext_module_methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+
+PyMODINIT_FUNC PyInit__c_htmltext(void)
{
- PyObject *m;
-
- /* Create the module and add the functions */
- m = Py_InitModule4("_c_htmltext", htmltext_module_methods, module_doc,
- NULL, PYTHON_API_VERSION);
-
- if (PyType_Ready(&htmltext_Type) < 0)
- return;
- if (PyType_Ready(&QuoteWrapper_Type) < 0)
- return;
- UnicodeWrapper_Type.tp_base = &PyUnicode_Type;
- if (PyType_Ready(&UnicodeWrapper_Type) < 0)
- return;
- if (PyType_Ready(&TemplateIO_Type) < 0)
- return;
- Py_INCREF((PyObject *)&htmltext_Type);
- Py_INCREF((PyObject *)&QuoteWrapper_Type);
- Py_INCREF((PyObject *)&UnicodeWrapper_Type);
- Py_INCREF((PyObject *)&TemplateIO_Type);
- PyModule_AddObject(m, "htmltext", (PyObject *)&htmltext_Type);
- PyModule_AddObject(m, "TemplateIO", (PyObject *)&TemplateIO_Type);
-}
+ PyObject *m = PyModule_Create(&htmltext_module);
+ if (m == NULL)
+ return NULL;
+ if (PyType_Ready(&htmltext_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&QuoteWrapper_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&TemplateIO_Type) < 0)
+ return NULL;
+ Py_INCREF((PyObject *)&htmltext_Type);
+ Py_INCREF((PyObject *)&QuoteWrapper_Type);
+ Py_INCREF((PyObject *)&TemplateIO_Type);
+ PyModule_AddObject(m, "htmltext", (PyObject *)&htmltext_Type);
+ PyModule_AddObject(m, "TemplateIO", (PyObject *)&TemplateIO_Type);
+ return m;
+};
diff --git a/quixote/html/_py_htmltext.py b/quixote/html/_py_htmltext.py
index 0bc7133..e42a77c 100644
--- a/quixote/html/_py_htmltext.py
+++ b/quixote/html/_py_htmltext.py
@@ -13,20 +13,8 @@ def _escape_string(s):
s = s.replace('"', """)
return s
-def stringify(obj):
- """Return 'obj' as a string or unicode object. Tries to prevent
- turning strings into unicode objects.
- """
- tp = type(obj)
- if isinstance(obj, (str, bytes)):
- return obj
- elif hasattr(tp, '__str__'):
- s = tp.__str__(obj)
- if not isinstance(s, str):
- raise TypeError('__str__ did not return a string')
- return s
- else:
- return str(obj)
+# backwards comptibility, unneeded in Python 3
+stringify = str
class htmltext(object):
"""The htmltext string-like type. This type serves as a tag
@@ -37,7 +25,7 @@ class htmltext(object):
__slots__ = ['s']
def __init__(self, s):
- self.s = stringify(s)
+ self.s = str(s)
# XXX make read-only
#def __setattr__(self, name, value):
@@ -98,7 +86,7 @@ class htmltext(object):
quoted_items = []
for item in items:
if isinstance(item, htmltext):
- quoted_items.append(stringify(item))
+ quoted_items.append(str(item))
elif isinstance(item, str):
quoted_items.append(_escape_string(item))
else:
@@ -148,7 +136,7 @@ class _QuoteWrapper(object):
self.value = value
def __str__(self):
- return _escape_string(stringify(self.value))
+ return _escape_string(str(self.value))
def __repr__(self):
return _escape_string(repr(self.value))
@@ -160,11 +148,8 @@ class _QuoteWrapper(object):
def _wraparg(arg):
if isinstance(arg, htmltext):
- # necessary to work around a PyString_Format bug in Python. Should
- # be fixed in Python 2.5
- return stringify(arg)
+ return str(arg)
elif isinstance(arg, str):
- # again, work around PyString_Format bug
return _escape_string(arg)
elif (isinstance(arg, int) or
isinstance(arg, float)):
@@ -184,7 +169,7 @@ def htmlescape(s):
if isinstance(s, htmltext):
return s
else:
- s = stringify(s)
+ s = str(s)
# inline _escape_string for speed
s = s.replace("&", "&") # must be done first
s = s.replace("<", "<")
@@ -213,10 +198,10 @@ class TemplateIO(object):
(self.__class__.__name__, id(self), len(self.data)))
def __str__(self):
- return stringify(self.getvalue())
+ return str(self.getvalue())
def getvalue(self):
if self.html:
return htmltext('').join(map(htmlescape, self.data))
else:
- return ''.join(map(stringify, self.data))
+ return ''.join(map(str, self.data))
diff --git a/quixote/html/test/utest_html.py b/quixote/html/test/utest_html.py
index 07f92dd..4b59903 100755
--- a/quixote/html/test/utest_html.py
+++ b/quixote/html/test/utest_html.py
@@ -5,12 +5,13 @@ from quixote.html import href, url_with_query, url_quote, nl2br
markupchars = '<>&"'
quotedchars = '<>&"'
-unicodechars = '\\u1234'
+unicodechars = '\u1234'
+high_code = '\U000e0030'
# Byte types...
markupbytes = b'<>&"'
quotedbytes = b'<>&"'
-bytebytes = b'\u1234'
+bytebytes = b'\x01'
class Wrapper:
@@ -33,7 +34,7 @@ class Broken:
def __repr__(self):
raise BrokenError('eieee')
-htmltext = escape = htmlescape = TemplateIO = stringify = None
+htmltext = escape = htmlescape = TemplateIO = None
class HTMLTest (UTest):
@@ -56,19 +57,7 @@ class HTMLTest (UTest):
class HTMLTextTest (UTest):
- def _pre(self):
- global htmltext, escape, htmlescape, TemplateIO, stringify
- htmltext = _py_htmltext.htmltext
- escape = _py_htmltext._escape_string
- stringify = _py_htmltext.stringify
- htmlescape = _py_htmltext.htmlescape
- TemplateIO = _py_htmltext.TemplateIO
-
- def _post(self):
- global htmltext, escape, htmlescape, TemplateIO, stringify
- htmltext = escape = htmlescape = TemplateIO = stringify = None
-
- def _check_init(self):
+ def check_init(self):
assert str(htmltext('foo')) == 'foo'
assert str(htmltext(markupchars)) == markupchars
assert str(htmltext(unicodechars)) == unicodechars
@@ -80,20 +69,12 @@ class HTMLTextTest (UTest):
assert 0
except BrokenError: pass
- def check_stringify(self):
- assert stringify(markupchars) is markupchars
- assert stringify(unicodechars) is unicodechars
- assert stringify(Wrapper(unicodechars)) is unicodechars
- assert stringify(Wrapper(markupchars)) is markupchars
- assert stringify(Wrapper) == str(Wrapper)
- assert stringify(None) == str(None)
- assert stringify(markupbytes) is markupbytes
-
def check_escape(self):
assert htmlescape(markupchars) == quotedchars
assert isinstance(htmlescape(markupchars), htmltext)
assert escape(markupchars) == quotedchars
assert escape(unicodechars) == unicodechars
+ assert escape(high_code) == high_code
assert type(escape(markupchars)) == type(markupchars)
assert isinstance(escape(markupchars), str)
assert htmlescape(htmlescape(markupchars)) == quotedchars
@@ -288,14 +269,6 @@ class HTMLTextTest (UTest):
class TemplateTest (UTest):
- def _pre(self):
- global TemplateIO
- TemplateIO = _py_htmltext.TemplateIO
-
- def _post(self):
- global TemplateIO
- TemplateIO = None
-
def check_init(self):
TemplateIO()
TemplateIO(html=True)
@@ -351,36 +324,29 @@ try:
except ImportError:
_c_htmltext = None
-if _c_htmltext:
- class CHTMLTest(HTMLTest):
- def _pre(self):
- # using globals like this is a bit of a hack since it assumes
- # Sancho tests each class individually, oh well
- global htmltext, escape, htmlescape, stringify
- htmltext = _c_htmltext.htmltext
- escape = _c_htmltext._escape_string
- stringify = _py_htmltext.stringify
- htmlescape = _c_htmltext.htmlescape
+def setup_py():
+ global htmltext, escape, htmlescape, TemplateIO
+ htmltext = _py_htmltext.htmltext
+ escape = _py_htmltext._escape_string
+ htmlescape = _py_htmltext.htmlescape
+ TemplateIO = _py_htmltext.TemplateIO
- class CHTMLTextTest(HTMLTextTest):
- def _pre(self):
- global htmltext, escape, htmlescape, stringify
- htmltext = _c_htmltext.htmltext
- escape = _c_htmltext._escape_string
- stringify = _py_htmltext.stringify
- htmlescape = _c_htmltext.htmlescape
- class CTemplateTest(TemplateTest):
- def _pre(self):
- global TemplateIO
- TemplateIO = _c_htmltext.TemplateIO
+def setup_c():
+ global htmltext, escape, htmlescape, TemplateIO
+ htmltext = _c_htmltext.htmltext
+ escape = _c_htmltext._escape_string
+ htmlescape = _c_htmltext.htmlescape
+ TemplateIO = _c_htmltext.TemplateIO
if __name__ == "__main__":
+ setup_py()
HTMLTest()
HTMLTextTest()
TemplateTest()
if _c_htmltext:
- CHTMLTest()
- CHTMLTextTest()
- CTemplateTest()
+ setup_c()
+ HTMLTest()
+ HTMLTextTest()
+ TemplateTest()
diff --git a/quixote/ptl/cimport.c b/quixote/ptl/cimport.c
deleted file mode 100644
index 2224c1b..0000000
--- a/quixote/ptl/cimport.c
+++ /dev/null
@@ -1,487 +0,0 @@
-/* Mostly stolen from Python/import.c. PSF license applies. */
-
-
-#include "Python.h"
-#include "osdefs.h"
-
-#ifdef HAVE_UNISTD_H
-#include
-#endif
-
-#if PY_VERSION_HEX < 0x02050000
-typedef int Py_ssize_t;
-#endif
-
-/* Python function to find and load a module. */
-static PyObject *loader_hook;
-
-
-PyObject *
-call_find_load(char *fullname, char *subname, PyObject *path)
-{
- PyObject *args, *m;
-
- if (!(args = Py_BuildValue("(ssO)", fullname, subname,
- path != NULL ? path : Py_None)))
- return NULL;
-
- m = PyEval_CallObject(loader_hook, args);
-
- Py_DECREF(args);
- return m;
-}
-
-
-/* Forward declarations for helper routines */
-static PyObject *get_parent(PyObject *globals, char *buf, int *p_buflen);
-static PyObject *load_next(PyObject *mod, PyObject *altmod,
- char **p_name, char *buf, int *p_buflen);
-static int mark_miss(char *name);
-static int ensure_fromlist(PyObject *mod, PyObject *fromlist,
- char *buf, int buflen, int recursive);
-static PyObject * import_submodule(PyObject *mod, char *name, char *fullname);
-
-
-static PyObject *
-import_module(char *name, PyObject *globals, PyObject *locals,
- PyObject *fromlist)
-{
- char buf[MAXPATHLEN+1];
- int buflen = 0;
- PyObject *parent, *head, *next, *tail;
-
- parent = get_parent(globals, buf, &buflen);
- if (parent == NULL)
- return NULL;
-
- head = load_next(parent, Py_None, &name, buf, &buflen);
- if (head == NULL)
- return NULL;
-
- tail = head;
- Py_INCREF(tail);
- while (name) {
- next = load_next(tail, tail, &name, buf, &buflen);
- Py_DECREF(tail);
- if (next == NULL) {
- Py_DECREF(head);
- return NULL;
- }
- tail = next;
- }
-
- if (fromlist != NULL) {
- if (fromlist == Py_None || !PyObject_IsTrue(fromlist))
- fromlist = NULL;
- }
-
- if (fromlist == NULL) {
- Py_DECREF(tail);
- return head;
- }
-
- Py_DECREF(head);
- if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) {
- Py_DECREF(tail);
- return NULL;
- }
-
- return tail;
-}
-
-static PyObject *
-get_parent(PyObject *globals, char *buf, int *p_buflen)
-{
- static PyObject *namestr = NULL;
- static PyObject *pathstr = NULL;
- PyObject *modname, *modpath, *modules, *parent;
-
- if (globals == NULL || !PyDict_Check(globals))
- return Py_None;
-
- if (namestr == NULL) {
- namestr = PyString_InternFromString("__name__");
- if (namestr == NULL)
- return NULL;
- }
- if (pathstr == NULL) {
- pathstr = PyString_InternFromString("__path__");
- if (pathstr == NULL)
- return NULL;
- }
-
- *buf = '\0';
- *p_buflen = 0;
- modname = PyDict_GetItem(globals, namestr);
- if (modname == NULL || !PyString_Check(modname))
- return Py_None;
-
- modpath = PyDict_GetItem(globals, pathstr);
- if (modpath != NULL) {
- int len = PyString_GET_SIZE(modname);
- if (len > MAXPATHLEN) {
- PyErr_SetString(PyExc_ValueError,
- "Module name too long");
- return NULL;
- }
- strcpy(buf, PyString_AS_STRING(modname));
- *p_buflen = len;
- }
- else {
- char *start = PyString_AS_STRING(modname);
- char *lastdot = strrchr(start, '.');
- size_t len;
- if (lastdot == NULL)
- return Py_None;
- len = lastdot - start;
- if (len >= MAXPATHLEN) {
- PyErr_SetString(PyExc_ValueError,
- "Module name too long");
- return NULL;
- }
- strncpy(buf, start, len);
- buf[len] = '\0';
- *p_buflen = len;
- }
-
- modules = PyImport_GetModuleDict();
- parent = PyDict_GetItemString(modules, buf);
- if (parent == NULL)
- parent = Py_None;
- return parent;
- /* We expect, but can't guarantee, if parent != None, that:
- - parent.__name__ == buf
- - parent.__dict__ is globals
- If this is violated... Who cares? */
-}
-
-/* altmod is either None or same as mod */
-static PyObject *
-load_next(PyObject *mod, PyObject *altmod, char **p_name, char *buf,
- int *p_buflen)
-{
- char *name = *p_name;
- char *dot = strchr(name, '.');
- size_t len;
- char *p;
- PyObject *result;
-
- if (dot == NULL) {
- *p_name = NULL;
- len = strlen(name);
- }
- else {
- *p_name = dot+1;
- len = dot-name;
- }
- if (len == 0) {
- PyErr_SetString(PyExc_ValueError,
- "Empty module name");
- return NULL;
- }
-
- p = buf + *p_buflen;
- if (p != buf)
- *p++ = '.';
- if (p+len-buf >= MAXPATHLEN) {
- PyErr_SetString(PyExc_ValueError,
- "Module name too long");
- return NULL;
- }
- strncpy(p, name, len);
- p[len] = '\0';
- *p_buflen = p+len-buf;
-
- result = import_submodule(mod, p, buf);
- if (result == Py_None && altmod != mod) {
- Py_DECREF(result);
- /* Here, altmod must be None and mod must not be None */
- result = import_submodule(altmod, p, p);
- if (result != NULL && result != Py_None) {
- if (mark_miss(buf) != 0) {
- Py_DECREF(result);
- return NULL;
- }
- strncpy(buf, name, len);
- buf[len] = '\0';
- *p_buflen = len;
- }
- }
- if (result == NULL)
- return NULL;
-
- if (result == Py_None) {
- Py_DECREF(result);
- PyErr_Format(PyExc_ImportError,
- "No module named %.200s", name);
- return NULL;
- }
-
- return result;
-}
-
-static int
-mark_miss(char *name)
-{
- PyObject *modules = PyImport_GetModuleDict();
- return PyDict_SetItemString(modules, name, Py_None);
-}
-
-static int
-ensure_fromlist(PyObject *mod, PyObject *fromlist, char *buf, int buflen,
- int recursive)
-{
- Py_ssize_t i;
-
- if (!PyObject_HasAttrString(mod, "__path__"))
- return 1;
-
- for (i = 0; ; i++) {
- PyObject *item = PySequence_GetItem(fromlist, i);
- int hasit;
- if (item == NULL) {
- if (PyErr_ExceptionMatches(PyExc_IndexError)) {
- PyErr_Clear();
- return 1;
- }
- return 0;
- }
- if (!PyString_Check(item)) {
- PyErr_SetString(PyExc_TypeError,
- "Item in ``from list'' not a string");
- Py_DECREF(item);
- return 0;
- }
- if (PyString_AS_STRING(item)[0] == '*') {
- PyObject *all;
- Py_DECREF(item);
- /* See if the package defines __all__ */
- if (recursive)
- continue; /* Avoid endless recursion */
- all = PyObject_GetAttrString(mod, "__all__");
- if (all == NULL)
- PyErr_Clear();
- else {
- if (!ensure_fromlist(mod, all, buf, buflen, 1))
- return 0;
- Py_DECREF(all);
- }
- continue;
- }
- hasit = PyObject_HasAttr(mod, item);
- if (!hasit) {
- char *subname = PyString_AS_STRING(item);
- PyObject *submod;
- char *p;
- if (buflen + strlen(subname) >= MAXPATHLEN) {
- PyErr_SetString(PyExc_ValueError,
- "Module name too long");
- Py_DECREF(item);
- return 0;
- }
- p = buf + buflen;
- *p++ = '.';
- strcpy(p, subname);
- submod = import_submodule(mod, subname, buf);
- Py_XDECREF(submod);
- if (submod == NULL) {
- Py_DECREF(item);
- return 0;
- }
- }
- Py_DECREF(item);
- }
-
- /* NOTREACHED */
-}
-
-static PyObject *
-import_submodule(PyObject *mod, char *subname, char *fullname)
-{
- PyObject *modules = PyImport_GetModuleDict();
- PyObject *m;
-
- /* Require:
- if mod == None: subname == fullname
- else: mod.__name__ + "." + subname == fullname
- */
-
- if ((m = PyDict_GetItemString(modules, fullname)) != NULL) {
- Py_INCREF(m);
- }
- else {
- PyObject *path;
-
- if (mod == Py_None)
- path = NULL;
- else {
- path = PyObject_GetAttrString(mod, "__path__");
- if (path == NULL) {
- PyErr_Clear();
- Py_INCREF(Py_None);
- return Py_None;
- }
- }
-
- m = call_find_load(fullname, subname, path);
-
- if (m != NULL && m != Py_None && mod != Py_None) {
- if (PyObject_SetAttrString(mod, subname, m) < 0) {
- Py_DECREF(m);
- m = NULL;
- }
- }
- }
-
- return m;
-}
-
-
-PyObject *
-reload_module(PyObject *m)
-{
- PyObject *modules = PyImport_GetModuleDict();
- PyObject *path = NULL;
- char *name, *subname;
-
- if (m == NULL || !PyModule_Check(m)) {
- PyErr_SetString(PyExc_TypeError,
- "reload_module() argument must be module");
- return NULL;
- }
- name = PyModule_GetName(m);
- if (name == NULL)
- return NULL;
- if (m != PyDict_GetItemString(modules, name)) {
- PyErr_Format(PyExc_ImportError,
- "reload(): module %.200s not in sys.modules",
- name);
- return NULL;
- }
- subname = strrchr(name, '.');
- if (subname == NULL)
- subname = name;
- else {
- PyObject *parentname, *parent;
- parentname = PyString_FromStringAndSize(name, (subname-name));
- if (parentname == NULL)
- return NULL;
- parent = PyDict_GetItem(modules, parentname);
- Py_DECREF(parentname);
- if (parent == NULL) {
- PyErr_Format(PyExc_ImportError,
- "reload(): parent %.200s not in sys.modules",
- name);
- return NULL;
- }
- subname++;
- path = PyObject_GetAttrString(parent, "__path__");
- if (path == NULL)
- PyErr_Clear();
- }
- m = call_find_load(name, subname, path);
- Py_XDECREF(path);
- return m;
-}
-
-
-static PyObject *
-cimport_import_module(PyObject *self, PyObject *args)
-{
- char *name;
- PyObject *globals = NULL;
- PyObject *locals = NULL;
- PyObject *fromlist = NULL;
-
- if (!PyArg_ParseTuple(args, "s|OOO:import_module", &name, &globals,
- &locals, &fromlist))
- return NULL;
- return import_module(name, globals, locals, fromlist);
-}
-
-static PyObject *
-cimport_reload_module(PyObject *self, PyObject *args)
-{
- PyObject *m;
- if (!PyArg_ParseTuple(args, "O:reload_module", &m))
- return NULL;
- return reload_module(m);
-}
-
-static char doc_reload_module[] =
-"reload(module) -> module\n\
-\n\
-Reload the module. The module must have been successfully imported before.";
-
-static PyObject *
-cimport_set_loader(PyObject *self, PyObject *args)
-{
- PyObject *l = NULL;
- if (!PyArg_ParseTuple(args, "O:set_loader", &l))
- return NULL;
- if (!PyCallable_Check(l)) {
- PyErr_SetString(PyExc_TypeError, "callable object needed");
- return NULL;
- }
- Py_XDECREF(loader_hook);
- loader_hook = l;
- Py_INCREF(loader_hook);
- Py_INCREF(Py_None);
- return Py_None;
-}
-static char doc_set_loader[] = "\
-Set the function that will be used to import modules.\n\
-\n\
-The function should should have the signature:\n\
-\n\
- loader(fullname : str, subname : str, path : [str] | None) -> module | None\n\
-\n\
-It should return the initialized module or None if it is not found.\n\
-";
-
-
-static PyObject *
-cimport_get_loader(PyObject *self, PyObject *args)
-{
- if (!PyArg_ParseTuple(args, ":get_loader"))
- return NULL;
- Py_INCREF(loader_hook);
- return loader_hook;
-}
-
-static char doc_get_loader[] = "\
-Get the function that will be used to import modules.\n\
-";
-
-static char doc_import_module[] = "\
-import_module(name, globals, locals, fromlist) -> module\n\
-\n\
-Import a module. The globals are only used to determine the context;\n\
-they are not modified. The locals are currently unused. The fromlist\n\
-should be a list of names to emulate ``from name import ...'', or an\n\
-empty list to emulate ``import name''.\n\
-\n\
-When importing a module from a package, note that import_module('A.B', ...)\n\
-returns package A when fromlist is empty, but its submodule B when\n\
-fromlist is not empty.\n\
-";
-
-
-static PyMethodDef cimport_methods[] = {
- {"import_module", cimport_import_module, 1, doc_import_module},
- {"reload_module", cimport_reload_module, 1, doc_reload_module},
- {"get_loader", cimport_get_loader, 1, doc_get_loader},
- {"set_loader", cimport_set_loader, 1, doc_set_loader},
- {NULL, NULL} /* sentinel */
-};
-
-void
-initcimport(void)
-{
- PyObject *m, *d;
-
- m = Py_InitModule4("cimport", cimport_methods, "",
- NULL, PYTHON_API_VERSION);
- d = PyModule_GetDict(m);
-
-}
diff --git a/quixote/ptl/ihooks_local.py b/quixote/ptl/ihooks_local.py
deleted file mode 100644
index c101bf4..0000000
--- a/quixote/ptl/ihooks_local.py
+++ /dev/null
@@ -1,557 +0,0 @@
-# Based on ihooks.py from the Python 2.6 distribution. Fixes for relative
-# imports applied (see Python issue #6855)
-"""Import hook support.
-
-Consistent use of this module will make it possible to change the
-different mechanisms involved in loading modules independently.
-
-While the built-in module imp exports interfaces to the built-in
-module searching and loading algorithm, and it is possible to replace
-the built-in function __import__ in order to change the semantics of
-the import statement, until now it has been difficult to combine the
-effect of different __import__ hacks, like loading modules from URLs
-by rimport.py, or restricted execution by rexec.py.
-
-This module defines three new concepts:
-
-1) A "file system hooks" class provides an interface to a filesystem.
-
-One hooks class is defined (Hooks), which uses the interface provided
-by standard modules os and os.path. It should be used as the base
-class for other hooks classes.
-
-2) A "module loader" class provides an interface to search for a
-module in a search path and to load it. It defines a method which
-searches for a module in a single directory; by overriding this method
-one can redefine the details of the search. If the directory is None,
-built-in and frozen modules are searched instead.
-
-Two module loader class are defined, both implementing the search
-strategy used by the built-in __import__ function: ModuleLoader uses
-the imp module's find_module interface, while HookableModuleLoader
-uses a file system hooks class to interact with the file system. Both
-use the imp module's load_* interfaces to actually load the module.
-
-3) A "module importer" class provides an interface to import a
-module, as well as interfaces to reload and unload a module. It also
-provides interfaces to install and uninstall itself instead of the
-default __import__ and reload (and unload) functions.
-
-One module importer class is defined (ModuleImporter), which uses a
-module loader instance passed in (by default HookableModuleLoader is
-instantiated).
-
-The classes defined here should be used as base classes for extended
-functionality along those lines.
-
-If a module importer class supports dotted names, its import_module()
-must return a different value depending on whether it is called on
-behalf of a "from ... import ..." statement or not. (This is caused
-by the way the __import__ hook is used by the Python interpreter.) It
-would also do wise to install a different version of reload().
-
-"""
-
-from warnings import warnpy3k, warn
-warnpy3k("the ihooks module has been removed in Python 3.0", stacklevel=2)
-del warnpy3k
-
-import __builtin__
-import imp
-import os
-import sys
-
-__all__ = ["BasicModuleLoader","Hooks","ModuleLoader","FancyModuleLoader",
- "BasicModuleImporter","ModuleImporter","install","uninstall"]
-
-VERBOSE = 0
-
-
-from imp import C_EXTENSION, PY_SOURCE, PY_COMPILED
-from imp import C_BUILTIN, PY_FROZEN, PKG_DIRECTORY
-BUILTIN_MODULE = C_BUILTIN
-FROZEN_MODULE = PY_FROZEN
-
-
-class _Verbose:
-
- def __init__(self, verbose = VERBOSE):
- self.verbose = verbose
-
- def get_verbose(self):
- return self.verbose
-
- def set_verbose(self, verbose):
- self.verbose = verbose
-
- # XXX The following is an experimental interface
-
- def note(self, *args):
- if self.verbose:
- self.message(*args)
-
- def message(self, format, *args):
- if args:
- print(format%args)
- else:
- print(format)
-
-
-class BasicModuleLoader(_Verbose):
-
- """Basic module loader.
-
- This provides the same functionality as built-in import. It
- doesn't deal with checking sys.modules -- all it provides is
- find_module() and a load_module(), as well as find_module_in_dir()
- which searches just one directory, and can be overridden by a
- derived class to change the module search algorithm when the basic
- dependency on sys.path is unchanged.
-
- The interface is a little more convenient than imp's:
- find_module(name, [path]) returns None or 'stuff', and
- load_module(name, stuff) loads the module.
-
- """
-
- def find_module(self, name, path = None):
- if path is None:
- path = [None] + self.default_path()
- for dir in path:
- stuff = self.find_module_in_dir(name, dir)
- if stuff: return stuff
- return None
-
- def default_path(self):
- return sys.path
-
- def find_module_in_dir(self, name, dir):
- if dir is None:
- return self.find_builtin_module(name)
- else:
- try:
- return imp.find_module(name, [dir])
- except ImportError:
- return None
-
- def find_builtin_module(self, name):
- # XXX frozen packages?
- if imp.is_builtin(name):
- return None, '', ('', '', BUILTIN_MODULE)
- if imp.is_frozen(name):
- return None, '', ('', '', FROZEN_MODULE)
- return None
-
- def load_module(self, name, stuff):
- file, filename, info = stuff
- try:
- return imp.load_module(name, file, filename, info)
- finally:
- if file: file.close()
-
-
-class Hooks(_Verbose):
-
- """Hooks into the filesystem and interpreter.
-
- By deriving a subclass you can redefine your filesystem interface,
- e.g. to merge it with the URL space.
-
- This base class behaves just like the native filesystem.
-
- """
-
- # imp interface
- def get_suffixes(self): return imp.get_suffixes()
- def new_module(self, name): return imp.new_module(name)
- def is_builtin(self, name): return imp.is_builtin(name)
- def init_builtin(self, name): return imp.init_builtin(name)
- def is_frozen(self, name): return imp.is_frozen(name)
- def init_frozen(self, name): return imp.init_frozen(name)
- def get_frozen_object(self, name): return imp.get_frozen_object(name)
- def load_source(self, name, filename, file=None):
- return imp.load_source(name, filename, file)
- def load_compiled(self, name, filename, file=None):
- return imp.load_compiled(name, filename, file)
- def load_dynamic(self, name, filename, file=None):
- return imp.load_dynamic(name, filename, file)
- def load_package(self, name, filename, file=None):
- return imp.load_module(name, file, filename, ("", "", PKG_DIRECTORY))
-
- def add_module(self, name):
- d = self.modules_dict()
- if name in d: return d[name]
- d[name] = m = self.new_module(name)
- return m
-
- # sys interface
- def modules_dict(self): return sys.modules
- def default_path(self): return sys.path
-
- def path_split(self, x): return os.path.split(x)
- def path_join(self, x, y): return os.path.join(x, y)
- def path_isabs(self, x): return os.path.isabs(x)
- # etc.
-
- def path_exists(self, x): return os.path.exists(x)
- def path_isdir(self, x): return os.path.isdir(x)
- def path_isfile(self, x): return os.path.isfile(x)
- def path_islink(self, x): return os.path.islink(x)
- # etc.
-
- def openfile(self, *x): return open(*x)
- openfile_error = IOError
- def listdir(self, x): return os.listdir(x)
- listdir_error = os.error
- # etc.
-
-
-class ModuleLoader(BasicModuleLoader):
-
- """Default module loader; uses file system hooks.
-
- By defining suitable hooks, you might be able to load modules from
- other sources than the file system, e.g. from compressed or
- encrypted files, tar files or (if you're brave!) URLs.
-
- """
-
- def __init__(self, hooks = None, verbose = VERBOSE):
- BasicModuleLoader.__init__(self, verbose)
- self.hooks = hooks or Hooks(verbose)
-
- def default_path(self):
- return self.hooks.default_path()
-
- def modules_dict(self):
- return self.hooks.modules_dict()
-
- def get_hooks(self):
- return self.hooks
-
- def set_hooks(self, hooks):
- self.hooks = hooks
-
- def find_builtin_module(self, name):
- # XXX frozen packages?
- if self.hooks.is_builtin(name):
- return None, '', ('', '', BUILTIN_MODULE)
- if self.hooks.is_frozen(name):
- return None, '', ('', '', FROZEN_MODULE)
- return None
-
- def find_module_in_dir(self, name, dir, allow_packages=1):
- if dir is None:
- return self.find_builtin_module(name)
- if allow_packages:
- fullname = self.hooks.path_join(dir, name)
- if self.hooks.path_isdir(fullname):
- stuff = self.find_module_in_dir("__init__", fullname, 0)
- if stuff:
- file = stuff[0]
- if file: file.close()
- return None, fullname, ('', '', PKG_DIRECTORY)
- for info in self.hooks.get_suffixes():
- suff, mode, type = info
- fullname = self.hooks.path_join(dir, name+suff)
- try:
- fp = self.hooks.openfile(fullname, mode)
- return fp, fullname, info
- except self.hooks.openfile_error:
- pass
- return None
-
- def load_module(self, name, stuff):
- file, filename, info = stuff
- (suff, mode, type) = info
- try:
- if type == BUILTIN_MODULE:
- return self.hooks.init_builtin(name)
- if type == FROZEN_MODULE:
- return self.hooks.init_frozen(name)
- if type == C_EXTENSION:
- m = self.hooks.load_dynamic(name, filename, file)
- elif type == PY_SOURCE:
- m = self.hooks.load_source(name, filename, file)
- elif type == PY_COMPILED:
- m = self.hooks.load_compiled(name, filename, file)
- elif type == PKG_DIRECTORY:
- m = self.hooks.load_package(name, filename, file)
- else:
- raise ImportError, "Unrecognized module type (%r) for %s" % \
- (type, name)
- finally:
- if file: file.close()
- m.__file__ = filename
- return m
-
-
-class FancyModuleLoader(ModuleLoader):
-
- """Fancy module loader -- parses and execs the code itself."""
-
- def load_module(self, name, stuff):
- file, filename, (suff, mode, type) = stuff
- realfilename = filename
- path = None
-
- if type == PKG_DIRECTORY:
- initstuff = self.find_module_in_dir("__init__", filename, 0)
- if not initstuff:
- raise ImportError, "No __init__ module in package %s" % name
- initfile, initfilename, initinfo = initstuff
- initsuff, initmode, inittype = initinfo
- if inittype not in (PY_COMPILED, PY_SOURCE):
- if initfile: initfile.close()
- raise ImportError, \
- "Bad type (%r) for __init__ module in package %s" % (
- inittype, name)
- path = [filename]
- file = initfile
- realfilename = initfilename
- type = inittype
-
- if type == FROZEN_MODULE:
- code = self.hooks.get_frozen_object(name)
- elif type == PY_COMPILED:
- import marshal
- file.seek(8)
- code = marshal.load(file)
- elif type == PY_SOURCE:
- data = file.read()
- code = compile(data, realfilename, 'exec')
- else:
- return ModuleLoader.load_module(self, name, stuff)
-
- m = self.hooks.add_module(name)
- if path:
- m.__path__ = path
- m.__file__ = filename
- try:
- exec code in m.__dict__
- except:
- d = self.hooks.modules_dict()
- if name in d:
- del d[name]
- raise
- return m
-
-
-class BasicModuleImporter(_Verbose):
-
- """Basic module importer; uses module loader.
-
- This provides basic import facilities but no package imports.
-
- """
-
- def __init__(self, loader = None, verbose = VERBOSE):
- _Verbose.__init__(self, verbose)
- self.loader = loader or ModuleLoader(None, verbose)
- self.modules = self.loader.modules_dict()
-
- def get_loader(self):
- return self.loader
-
- def set_loader(self, loader):
- self.loader = loader
-
- def get_hooks(self):
- return self.loader.get_hooks()
-
- def set_hooks(self, hooks):
- return self.loader.set_hooks(hooks)
-
- def import_module(self, name, globals={}, locals={}, fromlist=[]):
- name = str(name)
- if name in self.modules:
- return self.modules[name] # Fast path
- stuff = self.loader.find_module(name)
- if not stuff:
- raise ImportError, "No module named %s" % name
- return self.loader.load_module(name, stuff)
-
- def reload(self, module, path = None):
- name = str(module.__name__)
- stuff = self.loader.find_module(name, path)
- if not stuff:
- raise ImportError, "Module %s not found for reload" % name
- return self.loader.load_module(name, stuff)
-
- def unload(self, module):
- del self.modules[str(module.__name__)]
- # XXX Should this try to clear the module's namespace?
-
- def install(self):
- self.save_import_module = __builtin__.__import__
- self.save_reload = __builtin__.reload
- if not hasattr(__builtin__, 'unload'):
- __builtin__.unload = None
- self.save_unload = __builtin__.unload
- __builtin__.__import__ = self.import_module
- __builtin__.reload = self.reload
- __builtin__.unload = self.unload
-
- def uninstall(self):
- __builtin__.__import__ = self.save_import_module
- __builtin__.reload = self.save_reload
- __builtin__.unload = self.save_unload
- if not __builtin__.unload:
- del __builtin__.unload
-
-
-class ModuleImporter(BasicModuleImporter):
-
- """A module importer that supports packages."""
-
- def import_module(self, name, globals=None, locals=None, fromlist=None,
- level=-1):
- parent = self.determine_parent(globals, level)
- q, tail = self.find_head_package(parent, str(name))
- m = self.load_tail(q, tail)
- if not fromlist:
- return q
- if hasattr(m, "__path__"):
- self.ensure_fromlist(m, fromlist)
- return m
-
- def determine_parent(self, globals, level=-1):
- if not globals or not level:
- return None
- pkgname = globals.get('__package__')
- if pkgname is not None:
- if not pkgname and level > 0:
- raise ValueError, 'Attempted relative import in non-package'
- else:
- # __package__ not set, figure it out and set it
- modname = globals.get('__name__')
- if modname is None:
- return None
- if "__path__" in globals:
- # __path__ is set so modname is already the package name
- pkgname = modname
- else:
- # normal module, work out package name if any
- if '.' not in modname:
- if level > 0:
- raise ValueError, ('Attempted relative import in '
- 'non-package')
- globals['__package__'] = None
- return None
- pkgname = modname.rpartition('.')[0]
- globals['__package__'] = pkgname
- if level > 0:
- dot = len(pkgname)
- for x in range(level, 1, -1):
- try:
- dot = pkgname.rindex('.', 0, dot)
- except ValueError:
- raise ValueError('attempted relative import beyond '
- 'top-level package')
- pkgname = pkgname[:dot]
- try:
- return sys.modules[pkgname]
- except KeyError:
- if level < 1:
- warn("Parent module '%s' not found while handling "
- "absolute import" % pkgname, RuntimeWarning, 1)
- return None
- else:
- raise SystemError, ("Parent module '%s' not loaded, cannot "
- "perform relative import" % pkgname)
-
- def find_head_package(self, parent, name):
- if '.' in name:
- i = name.find('.')
- head = name[:i]
- tail = name[i+1:]
- else:
- head = name
- tail = ""
- if parent:
- qname = "%s.%s" % (parent.__name__, head)
- else:
- qname = head
- q = self.import_it(head, qname, parent)
- if q: return q, tail
- if parent:
- qname = head
- parent = None
- q = self.import_it(head, qname, parent)
- if q: return q, tail
- raise ImportError, "No module named '%s'" % qname
-
- def load_tail(self, q, tail):
- m = q
- while tail:
- i = tail.find('.')
- if i < 0: i = len(tail)
- head, tail = tail[:i], tail[i+1:]
- mname = "%s.%s" % (m.__name__, head)
- m = self.import_it(head, mname, m)
- if not m:
- raise ImportError, "No module named '%s'" % mname
- return m
-
- def ensure_fromlist(self, m, fromlist, recursive=0):
- for sub in fromlist:
- if sub == "*":
- if not recursive:
- try:
- all = m.__all__
- except AttributeError:
- pass
- else:
- self.ensure_fromlist(m, all, 1)
- continue
- if sub != "*" and not hasattr(m, sub):
- subname = "%s.%s" % (m.__name__, sub)
- submod = self.import_it(sub, subname, m)
- if not submod:
- raise ImportError, "No module named '%s'" % subname
-
- def import_it(self, partname, fqname, parent, force_load=0):
- if not partname:
- # completely empty module name should only happen in
- # 'from . import' or __import__("")
- return parent
- if not force_load:
- try:
- return self.modules[fqname]
- except KeyError:
- pass
- try:
- path = parent and parent.__path__
- except AttributeError:
- return None
- partname = str(partname)
- stuff = self.loader.find_module(partname, path)
- if not stuff:
- return None
- fqname = str(fqname)
- m = self.loader.load_module(fqname, stuff)
- if parent:
- setattr(parent, partname, m)
- return m
-
- def reload(self, module):
- name = str(module.__name__)
- if '.' not in name:
- return self.import_it(name, name, None, force_load=1)
- i = name.rfind('.')
- pname = name[:i]
- parent = self.modules[pname]
- return self.import_it(name[i+1:], name, parent, force_load=1)
-
-
-default_importer = None
-current_importer = None
-
-def install(importer = None):
- global current_importer
- current_importer = importer or default_importer or ModuleImporter()
- current_importer.install()
-
-def uninstall():
- global current_importer
- current_importer.uninstall()
diff --git a/setup.py b/setup.py
index 081833a..47c8259 100644
--- a/setup.py
+++ b/setup.py
@@ -21,10 +21,6 @@ from quixote import __version__
htmltext = Extension(name="quixote.html._c_htmltext",
sources=["quixote/html/_c_htmltext.c"])
-# faster import hook for PTL modules
-cimport = Extension(name="quixote.ptl.cimport",
- sources=["quixote/ptl/cimport.c"])
-
kw = {'name': "Quixote",
'version': __version__,
'description': "A small and flexible Python Web application framework",
@@ -49,10 +45,7 @@ kw = {'name': "Quixote",
build_extensions = sys.platform != 'win32'
if build_extensions:
- # The _c_htmltext module requires Python 2.2 features.
- if sys.hexversion >= 0x20200a1:
- kw['ext_modules'].append(htmltext)
- kw['ext_modules'].append(cimport)
+ kw['ext_modules'].append(htmltext)
# If we're running Python 2.3, add extra information
if hasattr(core, 'setup_keywords'):