Port _c_htmltext module to Python 3.
This commit is contained in:
parent
7f7620e7f4
commit
952aa2748e
|
@ -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*/
|
||||
"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;
|
||||
};
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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()
|
9
setup.py
9
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'):
|
||||
|
|
Loading…
Reference in New Issue