Port _c_htmltext module to Python 3.
This commit is contained in:
parent
7f7620e7f4
commit
952aa2748e
|
@ -3,12 +3,6 @@
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
|
|
||||||
#if PY_VERSION_HEX < 0x02050000
|
|
||||||
typedef int Py_ssize_t;
|
|
||||||
typedef intargfunc ssizeargfunc;
|
|
||||||
typedef inquiry lenfunc;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *s;
|
PyObject *s;
|
||||||
|
@ -16,7 +10,7 @@ typedef struct {
|
||||||
|
|
||||||
static PyTypeObject htmltext_Type;
|
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))
|
#define htmltext_STR(v) ((PyObject *)(((htmltextObject *)v)->s))
|
||||||
|
|
||||||
|
@ -27,16 +21,7 @@ typedef struct {
|
||||||
|
|
||||||
static PyTypeObject QuoteWrapper_Type;
|
static PyTypeObject QuoteWrapper_Type;
|
||||||
|
|
||||||
#define QuoteWrapper_Check(v) ((v)->ob_type == &QuoteWrapper_Type)
|
#define QuoteWrapper_Check(v) (Py_TYPE(v) == &QuoteWrapper_Type)
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PyUnicodeObject escaped;
|
|
||||||
PyObject *raw;
|
|
||||||
} UnicodeWrapperObject;
|
|
||||||
|
|
||||||
static PyTypeObject UnicodeWrapper_Type;
|
|
||||||
|
|
||||||
#define UnicodeWrapper_Check(v) ((v)->ob_type == &UnicodeWrapper_Type)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
|
@ -46,7 +31,7 @@ typedef struct {
|
||||||
|
|
||||||
static PyTypeObject TemplateIO_Type;
|
static PyTypeObject TemplateIO_Type;
|
||||||
|
|
||||||
#define TemplateIO_Check(v) ((v)->ob_type == &TemplateIO_Type)
|
#define TemplateIO_Check(v) (Py_TYPE(v) == &TemplateIO_Type)
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -56,41 +41,21 @@ type_error(const char *msg)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
string_check(PyObject *v)
|
|
||||||
{
|
|
||||||
return PyUnicode_Check(v) || PyString_Check(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
stringify(PyObject *obj)
|
stringify(PyObject *obj)
|
||||||
{
|
{
|
||||||
static PyObject *unicodestr = NULL;
|
PyObject *res;
|
||||||
PyObject *res, *func;
|
if (PyUnicode_Check(obj) || PyBytes_Check(obj)) {
|
||||||
if (string_check(obj)) {
|
|
||||||
Py_INCREF(obj);
|
Py_INCREF(obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
if (unicodestr == NULL) {
|
if (Py_TYPE(obj)->tp_str != NULL)
|
||||||
unicodestr = PyString_InternFromString("__unicode__");
|
res = (*Py_TYPE(obj)->tp_str)(obj);
|
||||||
if (unicodestr == NULL)
|
else
|
||||||
return NULL;
|
res = PyObject_Repr(obj);
|
||||||
}
|
|
||||||
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 (res == NULL)
|
if (res == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!string_check(res)) {
|
if (!PyUnicode_Check(res)) {
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
return type_error("string object required");
|
return type_error("string object required");
|
||||||
}
|
}
|
||||||
|
@ -98,153 +63,116 @@ stringify(PyObject *obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
escape_string(PyObject *obj)
|
escape_unicode(PyObject *pystr)
|
||||||
{
|
{
|
||||||
char *s;
|
/* Take a PyUnicode pystr and return a new escaped PyUnicode */
|
||||||
PyObject *newobj;
|
Py_ssize_t i;
|
||||||
Py_ssize_t i, j, extra_space, size, new_size;
|
Py_ssize_t input_chars;
|
||||||
assert (PyString_Check(obj));
|
Py_ssize_t extra_chars;
|
||||||
size = PyString_GET_SIZE(obj);
|
Py_ssize_t chars;
|
||||||
extra_space = 0;
|
PyObject *rval;
|
||||||
for (i=0; i < size; i++) {
|
void *input;
|
||||||
switch (PyString_AS_STRING(obj)[i]) {
|
int kind;
|
||||||
case '&':
|
Py_UCS4 maxchar;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
if (PyUnicode_READY(pystr) == -1)
|
||||||
escape_unicode(PyObject *obj)
|
return NULL;
|
||||||
{
|
|
||||||
Py_UNICODE *u;
|
maxchar = PyUnicode_MAX_CHAR_VALUE(pystr);
|
||||||
PyObject *newobj;
|
input_chars = PyUnicode_GET_LENGTH(pystr);
|
||||||
Py_ssize_t i, j, extra_space, size, new_size;
|
input = PyUnicode_DATA(pystr);
|
||||||
assert (PyUnicode_Check(obj));
|
kind = PyUnicode_KIND(pystr);
|
||||||
size = PyUnicode_GET_SIZE(obj);
|
|
||||||
extra_space = 0;
|
/* Compute the output size */
|
||||||
for (i=0; i < size; i++) {
|
for (i = 0, extra_chars = 0; i < input_chars; i++) {
|
||||||
switch (PyUnicode_AS_UNICODE(obj)[i]) {
|
Py_UCS4 c = PyUnicode_READ(kind, input, i);
|
||||||
|
switch (c) {
|
||||||
case '&':
|
case '&':
|
||||||
extra_space += 4;
|
extra_chars += 4;
|
||||||
break;
|
break;
|
||||||
case '<':
|
case '<':
|
||||||
case '>':
|
case '>':
|
||||||
extra_space += 3;
|
extra_chars += 3;
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
extra_space += 5;
|
extra_chars += 5;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (extra_space == 0) {
|
if (extra_chars > PY_SSIZE_T_MAX - input_chars) {
|
||||||
Py_INCREF(obj);
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
return (PyObject *)obj;
|
"string is too long to escape");
|
||||||
}
|
|
||||||
new_size = size + extra_space;
|
|
||||||
newobj = PyUnicode_FromUnicode(NULL, new_size);
|
|
||||||
if (newobj == NULL) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
u = PyUnicode_AS_UNICODE(newobj);
|
|
||||||
for (i=0, j=0; i < size; i++) {
|
rval = PyUnicode_New(input_chars + extra_chars, maxchar);
|
||||||
switch (PyUnicode_AS_UNICODE(obj)[i]) {
|
if (rval == NULL)
|
||||||
case '&':
|
return NULL;
|
||||||
u[j++] = '&';
|
|
||||||
u[j++] = 'a';
|
kind = PyUnicode_KIND(rval);
|
||||||
u[j++] = 'm';
|
|
||||||
u[j++] = 'p';
|
#define ENCODE_OUTPUT do { \
|
||||||
u[j++] = ';';
|
chars = 0; \
|
||||||
break;
|
for (i = 0; i < input_chars; i++) { \
|
||||||
case '<':
|
Py_UCS4 c = PyUnicode_READ(kind, input, i); \
|
||||||
u[j++] = '&';
|
switch (c) { \
|
||||||
u[j++] = 'l';
|
case '&': \
|
||||||
u[j++] = 't';
|
output[chars++] = '&'; \
|
||||||
u[j++] = ';';
|
output[chars++] = 'a'; \
|
||||||
break;
|
output[chars++] = 'm'; \
|
||||||
case '>':
|
output[chars++] = 'p'; \
|
||||||
u[j++] = '&';
|
output[chars++] = ';'; \
|
||||||
u[j++] = 'g';
|
break; \
|
||||||
u[j++] = 't';
|
case '<': \
|
||||||
u[j++] = ';';
|
output[chars++] = '&'; \
|
||||||
break;
|
output[chars++] = 'l'; \
|
||||||
case '"':
|
output[chars++] = 't'; \
|
||||||
u[j++] = '&';
|
output[chars++] = ';'; \
|
||||||
u[j++] = 'q';
|
break; \
|
||||||
u[j++] = 'u';
|
case '>': \
|
||||||
u[j++] = 'o';
|
output[chars++] = '&'; \
|
||||||
u[j++] = 't';
|
output[chars++] = 'g'; \
|
||||||
u[j++] = ';';
|
output[chars++] = 't'; \
|
||||||
break;
|
output[chars++] = ';'; \
|
||||||
default:
|
break; \
|
||||||
u[j++] = PyUnicode_AS_UNICODE(obj)[i];
|
case '"': \
|
||||||
break;
|
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);
|
assert (chars == input_chars + extra_chars);
|
||||||
return (PyObject *)newobj;
|
#undef ENCODE_OUTPUT
|
||||||
|
|
||||||
|
#ifdef Py_DEBUG
|
||||||
|
assert(_PyUnicode_CheckConsistency(rval, 1));
|
||||||
|
#endif
|
||||||
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
escape(PyObject *obj)
|
escape(PyObject *obj)
|
||||||
{
|
{
|
||||||
if (PyString_Check(obj)) {
|
if (PyUnicode_Check(obj)) {
|
||||||
return escape_string(obj);
|
|
||||||
}
|
|
||||||
else if (PyUnicode_Check(obj)) {
|
|
||||||
return escape_unicode(obj);
|
return escape_unicode(obj);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -257,19 +185,11 @@ quote_wrapper_new(PyObject *o)
|
||||||
{
|
{
|
||||||
QuoteWrapperObject *self;
|
QuoteWrapperObject *self;
|
||||||
if (htmltextObject_Check(o)) {
|
if (htmltextObject_Check(o)) {
|
||||||
/* Necessary to work around a PyString_Format bug. Should be
|
|
||||||
* fixed in Python 2.5. */
|
|
||||||
o = htmltext_STR(o);
|
o = htmltext_STR(o);
|
||||||
Py_INCREF(o);
|
Py_INCREF(o);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
if (PyUnicode_Check(o)) {
|
if (PyFloat_Check(o) ||
|
||||||
/* again, work around PyString_Format bug */
|
|
||||||
return PyObject_CallFunctionObjArgs(
|
|
||||||
(PyObject *)&UnicodeWrapper_Type, o, NULL);
|
|
||||||
}
|
|
||||||
if (PyInt_Check(o) ||
|
|
||||||
PyFloat_Check(o) ||
|
|
||||||
PyLong_Check(o)) {
|
PyLong_Check(o)) {
|
||||||
/* no need for wrapper */
|
/* no need for wrapper */
|
||||||
Py_INCREF(o);
|
Py_INCREF(o);
|
||||||
|
@ -327,54 +247,6 @@ quote_wrapper_subscript(QuoteWrapperObject *self, PyObject *key)
|
||||||
return w;
|
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 *
|
static PyObject *
|
||||||
htmltext_from_string(PyObject *s)
|
htmltext_from_string(PyObject *s)
|
||||||
{
|
{
|
||||||
|
@ -382,7 +254,7 @@ htmltext_from_string(PyObject *s)
|
||||||
PyObject *self;
|
PyObject *self;
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
assert (string_check(s));
|
assert (PyUnicode_Check(s));
|
||||||
self = PyType_GenericAlloc(&htmltext_Type, 0);
|
self = PyType_GenericAlloc(&htmltext_Type, 0);
|
||||||
if (self == NULL) {
|
if (self == NULL) {
|
||||||
Py_DECREF(s);
|
Py_DECREF(s);
|
||||||
|
@ -419,7 +291,7 @@ static void
|
||||||
htmltext_dealloc(htmltextObject *self)
|
htmltext_dealloc(htmltextObject *self)
|
||||||
{
|
{
|
||||||
Py_DECREF(self->s);
|
Py_DECREF(self->s);
|
||||||
self->ob_type->tp_free((PyObject *)self);
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
|
@ -442,7 +314,7 @@ htmltext_repr(htmltextObject *self)
|
||||||
sr = PyObject_Repr((PyObject *)self->s);
|
sr = PyObject_Repr((PyObject *)self->s);
|
||||||
if (sr == NULL)
|
if (sr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
rv = PyString_FromFormat("<htmltext %s>", PyString_AsString(sr));
|
rv = PyUnicode_FromFormat("<htmltext %s>", PyUnicode_AsUTF8(sr));
|
||||||
Py_DECREF(sr);
|
Py_DECREF(sr);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -470,15 +342,8 @@ static PyObject *
|
||||||
htmltext_format(htmltextObject *self, PyObject *args)
|
htmltext_format(htmltextObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
/* wrap the format arguments with QuoteWrapperObject */
|
/* wrap the format arguments with QuoteWrapperObject */
|
||||||
int is_unicode;
|
|
||||||
PyObject *rv, *wargs;
|
PyObject *rv, *wargs;
|
||||||
if (PyUnicode_Check(self->s)) {
|
assert (PyUnicode_Check(self->s));
|
||||||
is_unicode = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
is_unicode = 0;
|
|
||||||
assert (PyString_Check(self->s));
|
|
||||||
}
|
|
||||||
if (PyTuple_Check(args)) {
|
if (PyTuple_Check(args)) {
|
||||||
Py_ssize_t i, n = PyTuple_GET_SIZE(args);
|
Py_ssize_t i, n = PyTuple_GET_SIZE(args);
|
||||||
wargs = PyTuple_New(n);
|
wargs = PyTuple_New(n);
|
||||||
|
@ -497,10 +362,7 @@ htmltext_format(htmltextObject *self, PyObject *args)
|
||||||
if (wargs == NULL)
|
if (wargs == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (is_unicode)
|
rv = PyUnicode_Format(self->s, wargs);
|
||||||
rv = PyUnicode_Format(self->s, wargs);
|
|
||||||
else
|
|
||||||
rv = PyString_Format(self->s, wargs);
|
|
||||||
Py_DECREF(wargs);
|
Py_DECREF(wargs);
|
||||||
return htmltext_from_string(rv);
|
return htmltext_from_string(rv);
|
||||||
}
|
}
|
||||||
|
@ -515,7 +377,16 @@ htmltext_add(PyObject *v, PyObject *w)
|
||||||
Py_INCREF(qv);
|
Py_INCREF(qv);
|
||||||
Py_INCREF(qw);
|
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));
|
assert (htmltextObject_Check(v));
|
||||||
qv = htmltext_STR(v);
|
qv = htmltext_STR(v);
|
||||||
qw = escape(w);
|
qw = escape(w);
|
||||||
|
@ -523,28 +394,14 @@ htmltext_add(PyObject *v, PyObject *w)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_INCREF(qv);
|
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 {
|
else {
|
||||||
Py_INCREF(Py_NotImplemented);
|
Py_INCREF(Py_NotImplemented);
|
||||||
return Py_NotImplemented;
|
return Py_NotImplemented;
|
||||||
}
|
}
|
||||||
if (PyString_Check(qv)) {
|
assert (PyUnicode_Check(qv));
|
||||||
PyString_ConcatAndDel(&qv, qw);
|
rv = PyUnicode_Concat(qv, qw);
|
||||||
rv = qv;
|
Py_DECREF(qv);
|
||||||
}
|
Py_DECREF(qw);
|
||||||
else {
|
|
||||||
assert (PyUnicode_Check(qv));
|
|
||||||
rv = PyUnicode_Concat(qv, qw);
|
|
||||||
Py_DECREF(qv);
|
|
||||||
Py_DECREF(qw);
|
|
||||||
}
|
|
||||||
return htmltext_from_string(rv);
|
return htmltext_from_string(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,7 +434,7 @@ htmltext_join(PyObject *self, PyObject *args)
|
||||||
Py_INCREF(qvalue);
|
Py_INCREF(qvalue);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!string_check(value)) {
|
if (!PyUnicode_Check(value)) {
|
||||||
type_error("join requires a list of strings");
|
type_error("join requires a list of strings");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -589,12 +446,8 @@ htmltext_join(PyObject *self, PyObject *args)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PyUnicode_Check(htmltext_STR(self))) {
|
assert (PyUnicode_Check(htmltext_STR(self)));
|
||||||
rv = PyUnicode_Join(htmltext_STR(self), quoted_args);
|
rv = PyUnicode_Join(htmltext_STR(self), quoted_args);
|
||||||
}
|
|
||||||
else {
|
|
||||||
rv = _PyString_Join(htmltext_STR(self), quoted_args);
|
|
||||||
}
|
|
||||||
Py_DECREF(quoted_args);
|
Py_DECREF(quoted_args);
|
||||||
return htmltext_from_string(rv);
|
return htmltext_from_string(rv);
|
||||||
|
|
||||||
|
@ -607,7 +460,7 @@ static PyObject *
|
||||||
quote_arg(PyObject *s)
|
quote_arg(PyObject *s)
|
||||||
{
|
{
|
||||||
PyObject *ss;
|
PyObject *ss;
|
||||||
if (string_check(s)) {
|
if (PyUnicode_Check(s)) {
|
||||||
ss = escape(s);
|
ss = escape(s);
|
||||||
if (ss == NULL)
|
if (ss == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -634,7 +487,6 @@ htmltext_call_method1(PyObject *self, PyObject *s, char *method)
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x02060000
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
call_method_kwargs(PyObject *self, char *method, PyObject *args,
|
call_method_kwargs(PyObject *self, char *method, PyObject *args,
|
||||||
PyObject *kwargs)
|
PyObject *kwargs)
|
||||||
|
@ -647,7 +499,6 @@ call_method_kwargs(PyObject *self, char *method, PyObject *args,
|
||||||
Py_DECREF(m);
|
Py_DECREF(m);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
htmltext_startswith(PyObject *self, PyObject *s)
|
htmltext_startswith(PyObject *self, PyObject *s)
|
||||||
|
@ -666,13 +517,8 @@ htmltext_replace(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *old, *new, *q_old, *q_new, *rv;
|
PyObject *old, *new, *q_old, *q_new, *rv;
|
||||||
Py_ssize_t maxsplit = -1;
|
Py_ssize_t maxsplit = -1;
|
||||||
#if PY_VERSION_HEX >= 0x02050000
|
|
||||||
if (!PyArg_ParseTuple(args,"OO|n:replace", &old, &new, &maxsplit))
|
if (!PyArg_ParseTuple(args,"OO|n:replace", &old, &new, &maxsplit))
|
||||||
return NULL;
|
return NULL;
|
||||||
#else
|
|
||||||
if (!PyArg_ParseTuple(args,"OO|i:replace", &old, &new, &maxsplit))
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
q_old = quote_arg(old);
|
q_old = quote_arg(old);
|
||||||
if (q_old == NULL)
|
if (q_old == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -681,14 +527,8 @@ htmltext_replace(PyObject *self, PyObject *args)
|
||||||
Py_DECREF(q_old);
|
Py_DECREF(q_old);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#if PY_VERSION_HEX >= 0x02050000
|
|
||||||
rv = PyObject_CallMethod(htmltext_STR(self), "replace", "OOn",
|
rv = PyObject_CallMethod(htmltext_STR(self), "replace", "OOn",
|
||||||
q_old, q_new, maxsplit);
|
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_old);
|
||||||
Py_DECREF(q_new);
|
Py_DECREF(q_new);
|
||||||
return htmltext_from_string(rv);
|
return htmltext_from_string(rv);
|
||||||
|
@ -716,7 +556,6 @@ htmltext_capitalize(PyObject *self)
|
||||||
"capitalize", ""));
|
"capitalize", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_VERSION_HEX >= 0x02060000
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
htmltext_format_method(PyObject *self, PyObject *args, PyObject *kwargs)
|
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);
|
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);
|
rv = htmltext_from_string(rv);
|
||||||
error:
|
error:
|
||||||
Py_DECREF(wargs);
|
Py_DECREF(wargs);
|
||||||
Py_XDECREF(wkwargs);
|
Py_XDECREF(wkwargs);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -791,7 +629,7 @@ static void
|
||||||
template_io_dealloc(TemplateIO_Object *self)
|
template_io_dealloc(TemplateIO_Object *self)
|
||||||
{
|
{
|
||||||
Py_DECREF(self->data);
|
Py_DECREF(self->data);
|
||||||
self->ob_type->tp_free((PyObject *)self);
|
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -799,11 +637,11 @@ template_io_str(TemplateIO_Object *self)
|
||||||
{
|
{
|
||||||
static PyObject *empty = NULL;
|
static PyObject *empty = NULL;
|
||||||
if (empty == NULL) {
|
if (empty == NULL) {
|
||||||
empty = PyString_FromStringAndSize(NULL, 0);
|
empty = PyUnicode_FromStringAndSize(NULL, 0);
|
||||||
if (empty == NULL)
|
if (empty == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return _PyString_Join(empty, self->data);
|
return PyUnicode_Join(empty, self->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -860,10 +698,8 @@ static PyMethodDef htmltext_methods[] = {
|
||||||
{"lower", (PyCFunction)htmltext_lower, METH_NOARGS, ""},
|
{"lower", (PyCFunction)htmltext_lower, METH_NOARGS, ""},
|
||||||
{"upper", (PyCFunction)htmltext_upper, METH_NOARGS, ""},
|
{"upper", (PyCFunction)htmltext_upper, METH_NOARGS, ""},
|
||||||
{"capitalize", (PyCFunction)htmltext_capitalize, METH_NOARGS, ""},
|
{"capitalize", (PyCFunction)htmltext_capitalize, METH_NOARGS, ""},
|
||||||
#if PY_VERSION_HEX >= 0x02060000
|
|
||||||
{"format", (PyCFunction)htmltext_format_method,
|
{"format", (PyCFunction)htmltext_format_method,
|
||||||
METH_VARARGS | METH_KEYWORDS, ""},
|
METH_VARARGS | METH_KEYWORDS, ""},
|
||||||
#endif
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -874,7 +710,7 @@ static PyMemberDef htmltext_members[] = {
|
||||||
|
|
||||||
static PySequenceMethods htmltext_as_sequence = {
|
static PySequenceMethods htmltext_as_sequence = {
|
||||||
(lenfunc)htmltext_length, /*sq_length*/
|
(lenfunc)htmltext_length, /*sq_length*/
|
||||||
0, /*sq_concat*/
|
0, /*sq_concat*/
|
||||||
(ssizeargfunc)htmltext_repeat, /*sq_repeat*/
|
(ssizeargfunc)htmltext_repeat, /*sq_repeat*/
|
||||||
0, /*sq_item*/
|
0, /*sq_item*/
|
||||||
0, /*sq_slice*/
|
0, /*sq_slice*/
|
||||||
|
@ -887,29 +723,11 @@ static PyNumberMethods htmltext_as_number = {
|
||||||
(binaryfunc)htmltext_add, /*nb_add*/
|
(binaryfunc)htmltext_add, /*nb_add*/
|
||||||
0, /*nb_subtract*/
|
0, /*nb_subtract*/
|
||||||
0, /*nb_multiply*/
|
0, /*nb_multiply*/
|
||||||
0, /*nb_divide*/
|
|
||||||
(binaryfunc)htmltext_format, /*nb_remainder*/
|
(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 = {
|
static PyTypeObject htmltext_Type = {
|
||||||
PyObject_HEAD_INIT(NULL)
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
0, /*ob_size*/
|
|
||||||
"htmltext", /*tp_name*/
|
"htmltext", /*tp_name*/
|
||||||
sizeof(htmltextObject), /*tp_basicsize*/
|
sizeof(htmltextObject), /*tp_basicsize*/
|
||||||
0, /*tp_itemsize*/
|
0, /*tp_itemsize*/
|
||||||
|
@ -918,7 +736,7 @@ static PyTypeObject htmltext_Type = {
|
||||||
0, /*tp_print*/
|
0, /*tp_print*/
|
||||||
0, /*tp_getattr*/
|
0, /*tp_getattr*/
|
||||||
0, /*tp_setattr*/
|
0, /*tp_setattr*/
|
||||||
0, /*tp_compare*/
|
0, /*tp_reserved*/
|
||||||
(unaryfunc)htmltext_repr,/*tp_repr*/
|
(unaryfunc)htmltext_repr,/*tp_repr*/
|
||||||
&htmltext_as_number, /*tp_as_number*/
|
&htmltext_as_number, /*tp_as_number*/
|
||||||
&htmltext_as_sequence, /*tp_as_sequence*/
|
&htmltext_as_sequence, /*tp_as_sequence*/
|
||||||
|
@ -926,11 +744,10 @@ static PyTypeObject htmltext_Type = {
|
||||||
htmltext_hash, /*tp_hash*/
|
htmltext_hash, /*tp_hash*/
|
||||||
0, /*tp_call*/
|
0, /*tp_call*/
|
||||||
(unaryfunc)htmltext_str,/*tp_str*/
|
(unaryfunc)htmltext_str,/*tp_str*/
|
||||||
0, /*tp_getattro set to PyObject_GenericGetAttr by module init*/
|
0, /*tp_getattro*/
|
||||||
0, /*tp_setattro*/
|
0, /*tp_setattro*/
|
||||||
0, /*tp_as_buffer*/
|
0, /*tp_as_buffer*/
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE \
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||||
| Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
|
|
||||||
0, /*tp_doc*/
|
0, /*tp_doc*/
|
||||||
0, /*tp_traverse*/
|
0, /*tp_traverse*/
|
||||||
0, /*tp_clear*/
|
0, /*tp_clear*/
|
||||||
|
@ -947,36 +764,12 @@ static PyTypeObject htmltext_Type = {
|
||||||
0, /*tp_descr_set*/
|
0, /*tp_descr_set*/
|
||||||
0, /*tp_dictoffset*/
|
0, /*tp_dictoffset*/
|
||||||
0, /*tp_init*/
|
0, /*tp_init*/
|
||||||
0, /*tp_alloc set to PyType_GenericAlloc by module init*/
|
0, /*tp_alloc*/
|
||||||
htmltext_new, /*tp_new*/
|
htmltext_new, /*tp_new*/
|
||||||
0, /*tp_free set to _PyObject_Del by module init*/
|
0, /*tp_free*/
|
||||||
0, /*tp_is_gc*/
|
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 = {
|
static PyMappingMethods quote_wrapper_as_mapping = {
|
||||||
0, /*mp_length*/
|
0, /*mp_length*/
|
||||||
(binaryfunc)quote_wrapper_subscript, /*mp_subscript*/
|
(binaryfunc)quote_wrapper_subscript, /*mp_subscript*/
|
||||||
|
@ -985,104 +778,47 @@ static PyMappingMethods quote_wrapper_as_mapping = {
|
||||||
|
|
||||||
|
|
||||||
static PyTypeObject QuoteWrapper_Type = {
|
static PyTypeObject QuoteWrapper_Type = {
|
||||||
PyObject_HEAD_INIT(NULL)
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
0, /*ob_size*/
|
|
||||||
"QuoteWrapper", /*tp_name*/
|
"QuoteWrapper", /*tp_name*/
|
||||||
sizeof(QuoteWrapperObject), /*tp_basicsize*/
|
sizeof(QuoteWrapperObject), /*tp_basicsize*/
|
||||||
0, /*tp_itemsize*/
|
0,
|
||||||
/* methods */
|
(destructor)quote_wrapper_dealloc, /* tp_dealloc */
|
||||||
(destructor)quote_wrapper_dealloc, /*tp_dealloc*/
|
0, /* tp_print */
|
||||||
0, /*tp_print*/
|
0, /* tp_getattr */
|
||||||
0, /*tp_getattr*/
|
0, /* tp_setattr */
|
||||||
0, /*tp_setattr*/
|
0, /* tp_reserved */
|
||||||
0, /*tp_compare*/
|
(unaryfunc)quote_wrapper_repr, /* tp_repr */
|
||||||
(unaryfunc)quote_wrapper_repr,/*tp_repr*/
|
0, /* tp_as_number */
|
||||||
"e_wrapper_as_number,/*tp_as_number*/
|
0, /* tp_as_sequence */
|
||||||
0, /*tp_as_sequence*/
|
"e_wrapper_as_mapping, /* tp_as_mapping */
|
||||||
"e_wrapper_as_mapping,/*tp_as_mapping*/
|
0, /* tp_hash */
|
||||||
0, /*tp_hash*/
|
0, /* tp_call */
|
||||||
0, /*tp_call*/
|
(unaryfunc)quote_wrapper_str, /* tp_str */
|
||||||
(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 = {
|
static PySequenceMethods template_io_as_seq = {
|
||||||
PyObject_HEAD_INIT(NULL)
|
0, /* sq_length */
|
||||||
0, /*ob_size*/
|
0, /* sq_concat */
|
||||||
"UnicodeWrapper", /*tp_name*/
|
0, /* sq_repeat */
|
||||||
sizeof(UnicodeWrapperObject), /*tp_basicsize*/
|
0, /* sq_item */
|
||||||
0, /*tp_itemsize*/
|
0, /* sq_slice */
|
||||||
/* methods */
|
0, /* sq_ass_item */
|
||||||
(destructor)unicode_wrapper_dealloc, /*tp_dealloc*/
|
0, /* sq_ass_slice */
|
||||||
0, /*tp_print*/
|
0, /* sq_contains */
|
||||||
0, /*tp_getattr*/
|
(binaryfunc)template_io_iadd, /* sq_inplace_concat */
|
||||||
0, /*tp_setattr*/
|
0, /* sq_inplace_repeat */
|
||||||
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 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[] = {
|
static PyMethodDef template_io_methods[] = {
|
||||||
{"getvalue", (PyCFunction)template_io_getvalue, METH_NOARGS, ""},
|
{"getvalue", (PyCFunction)template_io_getvalue, METH_NOARGS, ""},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyTypeObject TemplateIO_Type = {
|
static PyTypeObject TemplateIO_Type = {
|
||||||
PyObject_HEAD_INIT(NULL)
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
0, /*ob_size*/
|
|
||||||
"TemplateIO", /*tp_name*/
|
"TemplateIO", /*tp_name*/
|
||||||
sizeof(TemplateIO_Object),/*tp_basicsize*/
|
sizeof(TemplateIO_Object),/*tp_basicsize*/
|
||||||
0, /*tp_itemsize*/
|
0, /*tp_itemsize*/
|
||||||
|
@ -1093,8 +829,8 @@ static PyTypeObject TemplateIO_Type = {
|
||||||
0, /*tp_setattr*/
|
0, /*tp_setattr*/
|
||||||
0, /*tp_compare*/
|
0, /*tp_compare*/
|
||||||
0, /*tp_repr*/
|
0, /*tp_repr*/
|
||||||
&template_io_as_number, /*tp_as_number*/
|
0, /*tp_as_number*/
|
||||||
0, /*tp_as_sequence*/
|
&template_io_as_seq, /*tp_as_sequence*/
|
||||||
0, /*tp_as_mapping*/
|
0, /*tp_as_mapping*/
|
||||||
0, /*tp_hash*/
|
0, /*tp_hash*/
|
||||||
0, /*tp_call*/
|
0, /*tp_call*/
|
||||||
|
@ -1168,28 +904,34 @@ static PyMethodDef htmltext_module_methods[] = {
|
||||||
|
|
||||||
static char module_doc[] = "htmltext string type";
|
static char module_doc[] = "htmltext string type";
|
||||||
|
|
||||||
void
|
static struct PyModuleDef htmltext_module = {
|
||||||
init_c_htmltext(void)
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"_c_htmltext",
|
||||||
|
module_doc,
|
||||||
|
-1,
|
||||||
|
htmltext_module_methods,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
PyMODINIT_FUNC PyInit__c_htmltext(void)
|
||||||
{
|
{
|
||||||
PyObject *m;
|
PyObject *m = PyModule_Create(&htmltext_module);
|
||||||
|
if (m == NULL)
|
||||||
/* Create the module and add the functions */
|
return NULL;
|
||||||
m = Py_InitModule4("_c_htmltext", htmltext_module_methods, module_doc,
|
if (PyType_Ready(&htmltext_Type) < 0)
|
||||||
NULL, PYTHON_API_VERSION);
|
return NULL;
|
||||||
|
if (PyType_Ready(&QuoteWrapper_Type) < 0)
|
||||||
if (PyType_Ready(&htmltext_Type) < 0)
|
return NULL;
|
||||||
return;
|
if (PyType_Ready(&TemplateIO_Type) < 0)
|
||||||
if (PyType_Ready(&QuoteWrapper_Type) < 0)
|
return NULL;
|
||||||
return;
|
Py_INCREF((PyObject *)&htmltext_Type);
|
||||||
UnicodeWrapper_Type.tp_base = &PyUnicode_Type;
|
Py_INCREF((PyObject *)&QuoteWrapper_Type);
|
||||||
if (PyType_Ready(&UnicodeWrapper_Type) < 0)
|
Py_INCREF((PyObject *)&TemplateIO_Type);
|
||||||
return;
|
PyModule_AddObject(m, "htmltext", (PyObject *)&htmltext_Type);
|
||||||
if (PyType_Ready(&TemplateIO_Type) < 0)
|
PyModule_AddObject(m, "TemplateIO", (PyObject *)&TemplateIO_Type);
|
||||||
return;
|
return m;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,20 +13,8 @@ def _escape_string(s):
|
||||||
s = s.replace('"', """)
|
s = s.replace('"', """)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def stringify(obj):
|
# backwards comptibility, unneeded in Python 3
|
||||||
"""Return 'obj' as a string or unicode object. Tries to prevent
|
stringify = str
|
||||||
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)
|
|
||||||
|
|
||||||
class htmltext(object):
|
class htmltext(object):
|
||||||
"""The htmltext string-like type. This type serves as a tag
|
"""The htmltext string-like type. This type serves as a tag
|
||||||
|
@ -37,7 +25,7 @@ class htmltext(object):
|
||||||
__slots__ = ['s']
|
__slots__ = ['s']
|
||||||
|
|
||||||
def __init__(self, s):
|
def __init__(self, s):
|
||||||
self.s = stringify(s)
|
self.s = str(s)
|
||||||
|
|
||||||
# XXX make read-only
|
# XXX make read-only
|
||||||
#def __setattr__(self, name, value):
|
#def __setattr__(self, name, value):
|
||||||
|
@ -98,7 +86,7 @@ class htmltext(object):
|
||||||
quoted_items = []
|
quoted_items = []
|
||||||
for item in items:
|
for item in items:
|
||||||
if isinstance(item, htmltext):
|
if isinstance(item, htmltext):
|
||||||
quoted_items.append(stringify(item))
|
quoted_items.append(str(item))
|
||||||
elif isinstance(item, str):
|
elif isinstance(item, str):
|
||||||
quoted_items.append(_escape_string(item))
|
quoted_items.append(_escape_string(item))
|
||||||
else:
|
else:
|
||||||
|
@ -148,7 +136,7 @@ class _QuoteWrapper(object):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return _escape_string(stringify(self.value))
|
return _escape_string(str(self.value))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return _escape_string(repr(self.value))
|
return _escape_string(repr(self.value))
|
||||||
|
@ -160,11 +148,8 @@ class _QuoteWrapper(object):
|
||||||
|
|
||||||
def _wraparg(arg):
|
def _wraparg(arg):
|
||||||
if isinstance(arg, htmltext):
|
if isinstance(arg, htmltext):
|
||||||
# necessary to work around a PyString_Format bug in Python. Should
|
return str(arg)
|
||||||
# be fixed in Python 2.5
|
|
||||||
return stringify(arg)
|
|
||||||
elif isinstance(arg, str):
|
elif isinstance(arg, str):
|
||||||
# again, work around PyString_Format bug
|
|
||||||
return _escape_string(arg)
|
return _escape_string(arg)
|
||||||
elif (isinstance(arg, int) or
|
elif (isinstance(arg, int) or
|
||||||
isinstance(arg, float)):
|
isinstance(arg, float)):
|
||||||
|
@ -184,7 +169,7 @@ def htmlescape(s):
|
||||||
if isinstance(s, htmltext):
|
if isinstance(s, htmltext):
|
||||||
return s
|
return s
|
||||||
else:
|
else:
|
||||||
s = stringify(s)
|
s = str(s)
|
||||||
# inline _escape_string for speed
|
# inline _escape_string for speed
|
||||||
s = s.replace("&", "&") # must be done first
|
s = s.replace("&", "&") # must be done first
|
||||||
s = s.replace("<", "<")
|
s = s.replace("<", "<")
|
||||||
|
@ -213,10 +198,10 @@ class TemplateIO(object):
|
||||||
(self.__class__.__name__, id(self), len(self.data)))
|
(self.__class__.__name__, id(self), len(self.data)))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return stringify(self.getvalue())
|
return str(self.getvalue())
|
||||||
|
|
||||||
def getvalue(self):
|
def getvalue(self):
|
||||||
if self.html:
|
if self.html:
|
||||||
return htmltext('').join(map(htmlescape, self.data))
|
return htmltext('').join(map(htmlescape, self.data))
|
||||||
else:
|
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 = '<>&"'
|
markupchars = '<>&"'
|
||||||
quotedchars = '<>&"'
|
quotedchars = '<>&"'
|
||||||
unicodechars = '\\u1234'
|
unicodechars = '\u1234'
|
||||||
|
high_code = '\U000e0030'
|
||||||
|
|
||||||
# Byte types...
|
# Byte types...
|
||||||
markupbytes = b'<>&"'
|
markupbytes = b'<>&"'
|
||||||
quotedbytes = b'<>&"'
|
quotedbytes = b'<>&"'
|
||||||
bytebytes = b'\u1234'
|
bytebytes = b'\x01'
|
||||||
|
|
||||||
|
|
||||||
class Wrapper:
|
class Wrapper:
|
||||||
|
@ -33,7 +34,7 @@ class Broken:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
raise BrokenError('eieee')
|
raise BrokenError('eieee')
|
||||||
|
|
||||||
htmltext = escape = htmlescape = TemplateIO = stringify = None
|
htmltext = escape = htmlescape = TemplateIO = None
|
||||||
|
|
||||||
class HTMLTest (UTest):
|
class HTMLTest (UTest):
|
||||||
|
|
||||||
|
@ -56,19 +57,7 @@ class HTMLTest (UTest):
|
||||||
|
|
||||||
class HTMLTextTest (UTest):
|
class HTMLTextTest (UTest):
|
||||||
|
|
||||||
def _pre(self):
|
def check_init(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):
|
|
||||||
assert str(htmltext('foo')) == 'foo'
|
assert str(htmltext('foo')) == 'foo'
|
||||||
assert str(htmltext(markupchars)) == markupchars
|
assert str(htmltext(markupchars)) == markupchars
|
||||||
assert str(htmltext(unicodechars)) == unicodechars
|
assert str(htmltext(unicodechars)) == unicodechars
|
||||||
|
@ -80,20 +69,12 @@ class HTMLTextTest (UTest):
|
||||||
assert 0
|
assert 0
|
||||||
except BrokenError: pass
|
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):
|
def check_escape(self):
|
||||||
assert htmlescape(markupchars) == quotedchars
|
assert htmlescape(markupchars) == quotedchars
|
||||||
assert isinstance(htmlescape(markupchars), htmltext)
|
assert isinstance(htmlescape(markupchars), htmltext)
|
||||||
assert escape(markupchars) == quotedchars
|
assert escape(markupchars) == quotedchars
|
||||||
assert escape(unicodechars) == unicodechars
|
assert escape(unicodechars) == unicodechars
|
||||||
|
assert escape(high_code) == high_code
|
||||||
assert type(escape(markupchars)) == type(markupchars)
|
assert type(escape(markupchars)) == type(markupchars)
|
||||||
assert isinstance(escape(markupchars), str)
|
assert isinstance(escape(markupchars), str)
|
||||||
assert htmlescape(htmlescape(markupchars)) == quotedchars
|
assert htmlescape(htmlescape(markupchars)) == quotedchars
|
||||||
|
@ -288,14 +269,6 @@ class HTMLTextTest (UTest):
|
||||||
|
|
||||||
class TemplateTest (UTest):
|
class TemplateTest (UTest):
|
||||||
|
|
||||||
def _pre(self):
|
|
||||||
global TemplateIO
|
|
||||||
TemplateIO = _py_htmltext.TemplateIO
|
|
||||||
|
|
||||||
def _post(self):
|
|
||||||
global TemplateIO
|
|
||||||
TemplateIO = None
|
|
||||||
|
|
||||||
def check_init(self):
|
def check_init(self):
|
||||||
TemplateIO()
|
TemplateIO()
|
||||||
TemplateIO(html=True)
|
TemplateIO(html=True)
|
||||||
|
@ -351,36 +324,29 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_c_htmltext = None
|
_c_htmltext = None
|
||||||
|
|
||||||
if _c_htmltext:
|
def setup_py():
|
||||||
class CHTMLTest(HTMLTest):
|
global htmltext, escape, htmlescape, TemplateIO
|
||||||
def _pre(self):
|
htmltext = _py_htmltext.htmltext
|
||||||
# using globals like this is a bit of a hack since it assumes
|
escape = _py_htmltext._escape_string
|
||||||
# Sancho tests each class individually, oh well
|
htmlescape = _py_htmltext.htmlescape
|
||||||
global htmltext, escape, htmlescape, stringify
|
TemplateIO = _py_htmltext.TemplateIO
|
||||||
htmltext = _c_htmltext.htmltext
|
|
||||||
escape = _c_htmltext._escape_string
|
|
||||||
stringify = _py_htmltext.stringify
|
|
||||||
htmlescape = _c_htmltext.htmlescape
|
|
||||||
|
|
||||||
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 setup_c():
|
||||||
def _pre(self):
|
global htmltext, escape, htmlescape, TemplateIO
|
||||||
global TemplateIO
|
htmltext = _c_htmltext.htmltext
|
||||||
TemplateIO = _c_htmltext.TemplateIO
|
escape = _c_htmltext._escape_string
|
||||||
|
htmlescape = _c_htmltext.htmlescape
|
||||||
|
TemplateIO = _c_htmltext.TemplateIO
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
setup_py()
|
||||||
HTMLTest()
|
HTMLTest()
|
||||||
HTMLTextTest()
|
HTMLTextTest()
|
||||||
TemplateTest()
|
TemplateTest()
|
||||||
if _c_htmltext:
|
if _c_htmltext:
|
||||||
CHTMLTest()
|
setup_c()
|
||||||
CHTMLTextTest()
|
HTMLTest()
|
||||||
CTemplateTest()
|
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",
|
htmltext = Extension(name="quixote.html._c_htmltext",
|
||||||
sources=["quixote/html/_c_htmltext.c"])
|
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",
|
kw = {'name': "Quixote",
|
||||||
'version': __version__,
|
'version': __version__,
|
||||||
'description': "A small and flexible Python Web application framework",
|
'description': "A small and flexible Python Web application framework",
|
||||||
|
@ -49,10 +45,7 @@ kw = {'name': "Quixote",
|
||||||
build_extensions = sys.platform != 'win32'
|
build_extensions = sys.platform != 'win32'
|
||||||
|
|
||||||
if build_extensions:
|
if build_extensions:
|
||||||
# The _c_htmltext module requires Python 2.2 features.
|
kw['ext_modules'].append(htmltext)
|
||||||
if sys.hexversion >= 0x20200a1:
|
|
||||||
kw['ext_modules'].append(htmltext)
|
|
||||||
kw['ext_modules'].append(cimport)
|
|
||||||
|
|
||||||
# If we're running Python 2.3, add extra information
|
# If we're running Python 2.3, add extra information
|
||||||
if hasattr(core, 'setup_keywords'):
|
if hasattr(core, 'setup_keywords'):
|
||||||
|
|
Loading…
Reference in New Issue