From cb129532ad5a900b278b09385f7345ebcac97c3a Mon Sep 17 00:00:00 2001 From: Graham Dumpleton Date: Thu, 8 Aug 2013 22:55:44 +0800 Subject: [PATCH] Restructure code base so testing doesn't pick up local source. Add WrapperBase extension module to reduce overheads. --- setup.py | 3 + {wrapt => src}/__init__.py | 0 src/_wrappers.c | 410 ++++++++++++++++++ {wrapt => src}/decorators.py | 0 {wrapt => src}/exceptions.py | 0 {wrapt => src}/six.py | 0 {wrapt => src}/wrappers.py | 9 +- {wrapt/tests => tests}/test_adapter.py | 0 {wrapt/tests => tests}/test_decorators.py | 0 {wrapt/tests => tests}/test_function.py | 0 .../tests => tests}/test_inner_classmethod.py | 0 .../test_inner_staticmethod.py | 0 {wrapt/tests => tests}/test_instancemethod.py | 0 .../tests => tests}/test_nested_function.py | 0 .../tests => tests}/test_outer_classmethod.py | 0 .../test_outer_staticmethod.py | 0 tox.ini | 2 +- wrapt/tests/__init__.py | 0 18 files changed, 422 insertions(+), 2 deletions(-) rename {wrapt => src}/__init__.py (100%) create mode 100644 src/_wrappers.c rename {wrapt => src}/decorators.py (100%) rename {wrapt => src}/exceptions.py (100%) rename {wrapt => src}/six.py (100%) rename {wrapt => src}/wrappers.py (97%) rename {wrapt/tests => tests}/test_adapter.py (100%) rename {wrapt/tests => tests}/test_decorators.py (100%) rename {wrapt/tests => tests}/test_function.py (100%) rename {wrapt/tests => tests}/test_inner_classmethod.py (100%) rename {wrapt/tests => tests}/test_inner_staticmethod.py (100%) rename {wrapt/tests => tests}/test_instancemethod.py (100%) rename {wrapt/tests => tests}/test_nested_function.py (100%) rename {wrapt/tests => tests}/test_outer_classmethod.py (100%) rename {wrapt/tests => tests}/test_outer_staticmethod.py (100%) delete mode 100644 wrapt/tests/__init__.py diff --git a/setup.py b/setup.py index 9d630f7..0931116 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,5 @@ from distutils.core import setup +from distutils.core import Extension setup(name = 'wrapt', version = '0.9.0', @@ -8,4 +9,6 @@ setup(name = 'wrapt', license = 'BSD', url = 'https://github.com/GrahamDumpleton/wrapt', packages = ['wrapt'], + package_dir={'wrapt': 'src'}, + ext_modules = [Extension("wrapt._wrappers", ["src/_wrappers.c"])], ) diff --git a/wrapt/__init__.py b/src/__init__.py similarity index 100% rename from wrapt/__init__.py rename to src/__init__.py diff --git a/src/_wrappers.c b/src/_wrappers.c new file mode 100644 index 0000000..9dfe846 --- /dev/null +++ b/src/_wrappers.c @@ -0,0 +1,410 @@ +/* ------------------------------------------------------------------------- */ + +#include "Python.h" + +#include "structmember.h" + +#ifndef PyVarObject_HEAD_INIT +#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, +#endif + +/* ------------------------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + PyObject *wrapped; + PyObject *wrapper; + PyObject *target; +} WraptWrapperBaseObject; + +PyTypeObject WraptWrapperBase_Type; + +/* ------------------------------------------------------------------------- */ + +static PyObject *WraptWrapperBase_new(PyTypeObject *type, + PyObject *args, PyObject *kwds) +{ + WraptWrapperBaseObject *self; + + self = (WraptWrapperBaseObject *)type->tp_alloc(type, 0); + + if (!self) + return NULL; + + self->wrapped = NULL; + self->wrapper = NULL; + self->target = NULL; + + return (PyObject *)self; +} + +/* ------------------------------------------------------------------------- */ + +static int WraptWrapperBase_init(WraptWrapperBaseObject *self, + PyObject *args, PyObject *kwds) +{ + PyObject *wrapped = NULL; + PyObject *wrapper = NULL; + PyObject *target = Py_None; + + PyObject *name = NULL; + PyObject *object = NULL; + + static char *kwlist[] = { "wrapped", "wrapper", "target", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O:WrapperBase", + kwlist, &wrapped, &wrapper, &target)) { + return -1; + } + + Py_INCREF(wrapped); + Py_INCREF(wrapper); + + self->wrapped = wrapped; + self->wrapper = wrapper; + + if (target == Py_None) { + object = PyObject_GetAttrString(wrapped, "__wrapped__"); + + if (object) { + Py_INCREF(object); + self->target = object; + } + else { + PyErr_Clear(); + + Py_INCREF(wrapped); + self->target = wrapped; + } + + object = PyObject_GetAttrString(wrapped, "__name__"); + + if (object) { +#if PY_MAJOR_VERSION >= 3 + name = PyUnicode_FromString("__name__"); +#else + name = PyString_FromString("__name__"); +#endif + PyObject_GenericSetAttr((PyObject *)self, name, object); + Py_DECREF(name); + } + else + PyErr_Clear(); + + object = PyObject_GetAttrString(wrapped, "__qualname__"); + + if (object) { +#if PY_MAJOR_VERSION >= 3 + name = PyUnicode_FromString("__qualname__"); +#else + name = PyString_FromString("__qualname__"); +#endif + PyObject_GenericSetAttr((PyObject *)self, name, object); + Py_DECREF(name); + } + else + PyErr_Clear(); + } + else { + Py_INCREF(target); + self->target = target; + + object = PyObject_GetAttrString(target, "__name__"); + + if (object) { +#if PY_MAJOR_VERSION >= 3 + name = PyUnicode_FromString("__name__"); +#else + name = PyString_FromString("__name__"); +#endif + PyObject_GenericSetAttr((PyObject *)self, name, object); + Py_DECREF(name); + } + else + PyErr_Clear(); + + object = PyObject_GetAttrString(target, "__qualname__"); + + if (object) { +#if PY_MAJOR_VERSION >= 3 + name = PyUnicode_FromString("__qualname__"); +#else + name = PyString_FromString("__qualname__"); +#endif + PyObject_GenericSetAttr((PyObject *)self, name, object); + Py_DECREF(name); + } + else + PyErr_Clear(); + } + + object = PyObject_GetAttrString(wrapped, "__module__"); + + if (object) { +#if PY_MAJOR_VERSION >= 3 + name = PyUnicode_FromString("__module__"); +#else + name = PyString_FromString("__module__"); +#endif + PyObject_GenericSetAttr((PyObject *)self, name, object); + Py_DECREF(name); + } + else + PyErr_Clear(); + + object = PyObject_GetAttrString(wrapped, "__doc__"); + + if (object) { +#if PY_MAJOR_VERSION >= 3 + name = PyUnicode_FromString("__doc__"); +#else + name = PyString_FromString("__doc__"); +#endif + PyObject_GenericSetAttr((PyObject *)self, name, object); + Py_DECREF(name); + } + else + PyErr_Clear(); + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static void WraptWrapperBase_dealloc(WraptWrapperBaseObject *self) +{ + Py_XDECREF(self->wrapped); + Py_XDECREF(self->wrapper); + Py_XDECREF(self->target); + + Py_TYPE(self)->tp_free(self); +} + +/* ------------------------------------------------------------------------- */ + +static PyObject *WraptWrapperBase_get_wrapped( + WraptWrapperBaseObject *self, void *closure) +{ + if (!self->wrapped) { + Py_INCREF(Py_None); + return Py_None; + } + + Py_INCREF(self->wrapped); + return self->wrapped; +} + +/* ------------------------------------------------------------------------- */ + +static PyObject *WraptWrapperBase_get_wrapper( + WraptWrapperBaseObject *self, void *closure) +{ + if (!self->wrapper) { + Py_INCREF(Py_None); + return Py_None; + } + + Py_INCREF(self->wrapper); + return self->wrapper; +} + +/* ------------------------------------------------------------------------- */ + +static PyObject *WraptWrapperBase_get_target( + WraptWrapperBaseObject *self, void *closure) +{ + if (!self->target) { + Py_INCREF(Py_None); + return Py_None; + } + + Py_INCREF(self->target); + return self->target; +} + +/* ------------------------------------------------------------------------- */ + +static PyObject *WraptWrapperBase_get_class( + WraptWrapperBaseObject *self) +{ + if (!self->wrapped) { + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + return NULL; + } + + return PyObject_GetAttrString(self->wrapped, "__class__"); +} + +/* ------------------------------------------------------------------------- */ + +static PyObject *WraptWrapperBase_getattro( + WraptWrapperBaseObject *self, PyObject *name) +{ + PyObject *object = NULL; + + if (!self->wrapped) { + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + return NULL; + } + + object = PyObject_GenericGetAttr((PyObject *)self, name); + + if (object) + return object; + + PyErr_Clear(); + + return PyObject_GetAttr(self->wrapped, name); +} + +/* ------------------------------------------------------------------------- */ + +static int WraptWrapperBase_setattro( + WraptWrapperBaseObject *self, PyObject *name, PyObject *value) +{ + static PyObject *self_prefix = NULL; + + PyObject *match = NULL; + + if (!self->wrapped) { + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + return -1; + } + + if (!self_prefix) + self_prefix = PyUnicode_FromString("_self_"); + + match = PyEval_CallMethod(name, "startswith", "(O)", self_prefix); + + if (match == Py_True) + return PyObject_GenericSetAttr((PyObject *)self, name, value); + + Py_XDECREF(match); + + return PyObject_SetAttr(self->wrapped, name, value); +} + +/* ------------------------------------------------------------------------- */ + +static PyObject *WraptWrapperBase_iter(WraptWrapperBaseObject *self) +{ + if (!self->wrapped) { + PyErr_SetString(PyExc_ValueError, "wrapper has not been initialised"); + return NULL; + } + + return PyObject_GetIter(self->wrapped); +} + +/* ------------------------------------------------------------------------- */ + +static PyGetSetDef WraptWrapperBase_getset[] = { + { "_self_wrapped", (getter)WraptWrapperBase_get_wrapped, + NULL, 0 }, + { "_self_wrapper", (getter)WraptWrapperBase_get_wrapper, + NULL, 0 }, + { "_self_target", (getter)WraptWrapperBase_get_target, + NULL, 0 }, + { "__class__", (getter)WraptWrapperBase_get_class, + NULL, 0 }, + { NULL }, +}; + +PyTypeObject WraptWrapperBase_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_wrappers.WrapperBase", /*tp_name*/ + sizeof(WraptWrapperBaseObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)WraptWrapperBase_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + (getattrofunc)WraptWrapperBase_getattro, /*tp_getattro*/ + (setattrofunc)WraptWrapperBase_setattro, /*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*/ + (getiterfunc)WraptWrapperBase_iter, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + WraptWrapperBase_getset, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + (initproc)WraptWrapperBase_init, /*tp_init*/ + 0, /*tp_alloc*/ + WraptWrapperBase_new, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +} + +/* ------------------------------------------------------------------------- */; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "_wrappers", /* m_name */ + NULL, /* m_doc */ + -1, /* m_size */ + NULL, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; +#endif + +static PyObject * +moduleinit(void) +{ + PyObject *module; + +#if PY_MAJOR_VERSION >= 3 + module = PyModule_Create(&moduledef); +#else + module = Py_InitModule3("_wrappers", NULL, NULL); +#endif + + if (module == NULL) + return NULL; + + if (PyType_Ready(&WraptWrapperBase_Type) < 0) + return NULL; + + Py_INCREF(&WraptWrapperBase_Type); + PyModule_AddObject(module, "WrapperBase", + (PyObject *)&WraptWrapperBase_Type); + + return module; +} + +#if PY_MAJOR_VERSION < 3 +PyMODINIT_FUNC init_wrappers(void) +{ + moduleinit(); +} +#else +PyMODINIT_FUNC PyInit__wrappers(void) +{ + return moduleinit(); +} +#endif + +/* ------------------------------------------------------------------------- */ diff --git a/wrapt/decorators.py b/src/decorators.py similarity index 100% rename from wrapt/decorators.py rename to src/decorators.py diff --git a/wrapt/exceptions.py b/src/exceptions.py similarity index 100% rename from wrapt/exceptions.py rename to src/exceptions.py diff --git a/wrapt/six.py b/src/six.py similarity index 100% rename from wrapt/six.py rename to src/six.py diff --git a/wrapt/wrappers.py b/src/wrappers.py similarity index 97% rename from wrapt/wrappers.py rename to src/wrappers.py index 8f1630d..e0f96cb 100644 --- a/wrapt/wrappers.py +++ b/src/wrappers.py @@ -2,6 +2,11 @@ import functools from . import six +try: + from ._wrappers import WrapperBase as C_WrapperBase +except ImportError: + C_WrapperBase = None + class WrapperOverrideMethods(object): @property @@ -34,7 +39,7 @@ class WrapperBaseMetaType(type): dictionary.update(vars(WrapperOverrideMethods)) return type.__new__(cls, name, bases, dictionary) -class WrapperBase(six.with_metaclass(WrapperBaseMetaType)): +class PY_WrapperBase(six.with_metaclass(WrapperBaseMetaType)): def __init__(self, wrapped, wrapper, target=None): self._self_wrapped = wrapped @@ -140,6 +145,8 @@ class WrapperBase(six.with_metaclass(WrapperBaseMetaType)): def __iter__(self): return iter(self._self_wrapped) +WrapperBase = C_WrapperBase or PY_WrapperBase + class BoundFunctionWrapper(WrapperBase): def __init__(self, wrapped, instance, wrapper, target=None, params={}): diff --git a/wrapt/tests/test_adapter.py b/tests/test_adapter.py similarity index 100% rename from wrapt/tests/test_adapter.py rename to tests/test_adapter.py diff --git a/wrapt/tests/test_decorators.py b/tests/test_decorators.py similarity index 100% rename from wrapt/tests/test_decorators.py rename to tests/test_decorators.py diff --git a/wrapt/tests/test_function.py b/tests/test_function.py similarity index 100% rename from wrapt/tests/test_function.py rename to tests/test_function.py diff --git a/wrapt/tests/test_inner_classmethod.py b/tests/test_inner_classmethod.py similarity index 100% rename from wrapt/tests/test_inner_classmethod.py rename to tests/test_inner_classmethod.py diff --git a/wrapt/tests/test_inner_staticmethod.py b/tests/test_inner_staticmethod.py similarity index 100% rename from wrapt/tests/test_inner_staticmethod.py rename to tests/test_inner_staticmethod.py diff --git a/wrapt/tests/test_instancemethod.py b/tests/test_instancemethod.py similarity index 100% rename from wrapt/tests/test_instancemethod.py rename to tests/test_instancemethod.py diff --git a/wrapt/tests/test_nested_function.py b/tests/test_nested_function.py similarity index 100% rename from wrapt/tests/test_nested_function.py rename to tests/test_nested_function.py diff --git a/wrapt/tests/test_outer_classmethod.py b/tests/test_outer_classmethod.py similarity index 100% rename from wrapt/tests/test_outer_classmethod.py rename to tests/test_outer_classmethod.py diff --git a/wrapt/tests/test_outer_staticmethod.py b/tests/test_outer_staticmethod.py similarity index 100% rename from wrapt/tests/test_outer_staticmethod.py rename to tests/test_outer_staticmethod.py diff --git a/tox.ini b/tox.ini index 7d77a73..4a4ea02 100644 --- a/tox.ini +++ b/tox.ini @@ -4,4 +4,4 @@ envlist = py26,py27,py33 [testenv] deps = nose commands = - nosetests -v [] + nosetests -v tests diff --git a/wrapt/tests/__init__.py b/wrapt/tests/__init__.py deleted file mode 100644 index e69de29..0000000