Port _c_htmltext module to Python 3.

This commit is contained in:
Neil Schemenauer 2016-04-05 16:13:58 +00:00
parent 7f7620e7f4
commit 952aa2748e
6 changed files with 231 additions and 1589 deletions

View File

@ -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("<htmltext %s>", PyString_AsString(sr));
rv = PyUnicode_FromFormat("<htmltext %s>", 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*/
&quote_wrapper_as_number,/*tp_as_number*/
0, /*tp_as_sequence*/
&quote_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 */
&quote_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;
};

View File

@ -13,20 +13,8 @@ def _escape_string(s):
s = s.replace('"', "&quot;")
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("&", "&amp;") # must be done first
s = s.replace("<", "&lt;")
@ -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))

View File

@ -5,12 +5,13 @@ from quixote.html import href, url_with_query, url_quote, nl2br
markupchars = '<>&"'
quotedchars = '&lt;&gt;&amp;&quot;'
unicodechars = '\\u1234'
unicodechars = '\u1234'
high_code = '\U000e0030'
# Byte types...
markupbytes = b'<>&"'
quotedbytes = b'&lt;&gt;&amp;&quot;'
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()

View File

@ -1,487 +0,0 @@
/* Mostly stolen from Python/import.c. PSF license applies. */
#include "Python.h"
#include "osdefs.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#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);
}

View File

@ -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()

View File

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