From 952aa2748ebe895e1ffe271b6145fed48d23c834 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Tue, 5 Apr 2016 16:13:58 +0000 Subject: [PATCH] Port _c_htmltext module to Python 3. --- quixote/html/_c_htmltext.c | 654 ++++++++++---------------------- quixote/html/_py_htmltext.py | 33 +- quixote/html/test/utest_html.py | 80 ++-- quixote/ptl/cimport.c | 487 ------------------------ quixote/ptl/ihooks_local.py | 557 --------------------------- setup.py | 9 +- 6 files changed, 231 insertions(+), 1589 deletions(-) delete mode 100644 quixote/ptl/cimport.c delete mode 100644 quixote/ptl/ihooks_local.py 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'):