From f00091f340122f3fc0a3c6d7da2aff8a83f5506d Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sun, 16 Aug 2009 00:25:59 -0700 Subject: Beginnings of a Python extension. --- lang_ext/python/definition.c | 253 +++++++++++++++++++++++++++++++++++++++++++ lang_ext/python/definition.h | 34 ++++++ lang_ext/python/setup.py | 11 ++ 3 files changed, 298 insertions(+) create mode 100644 lang_ext/python/definition.c create mode 100644 lang_ext/python/definition.h create mode 100644 lang_ext/python/setup.py (limited to 'lang_ext/python') diff --git a/lang_ext/python/definition.c b/lang_ext/python/definition.c new file mode 100644 index 0000000..04e377a --- /dev/null +++ b/lang_ext/python/definition.c @@ -0,0 +1,253 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + * + * This file defines the Python module upb.definition. This module + * defines the following Python classes, which wrap upb's internal + * definitions: + * + * - upb.definition.MessageDefintion + * - upb.definition.EnumDefinition (TODO) + * - upb.definition.ServiceDefinition (TODO) + * + * We also define a class upb.definition.Context, which provides the + * mechanism for loading the above definitions from .proto files or + * from binary descriptors. + * + * Once these definitions are loaded, we can use them to create + * the Python types for each .proto message type. That is covered + * in other files. + */ + +#include "definition.h" +#include "upb_context.h" + +#if PY_MAJOR_VERSION > 3 +const char *bytes_format = "y#"; +#else +const char *bytes_format = "s#"; +#endif + + +/* upb.def.MessageDefinition **************************************************/ + +#if 0 +/* Not implemented yet, but these methods will expose information about the + * message definition (the upb_msgdef). */ +static PyMethodDef PyUpb_MessageDefinitionMethods[] = { +}; + +PyTypeObject PyUpb_MessageDefinitionType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "upb.definition.MessageDefinition", /* tp_name */ + sizeof(PyUpb_MessageDefinition), /* tp_basicsize */ + 0, /* tp_itemsize */ + msgdef_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 */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + msgdef_methods, /* 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 */ + 0, /* Can't be created in Python. */ /* tp_new */ + 0, /* tp_free */ +}; +#endif + +/* upb.Context ****************************************************************/ + +typedef struct { + PyObject_HEAD + struct upb_context *context; +} PyUpb_Context; + +static PyTypeObject PyUpb_ContextType; /* forward decl. */ + +#define CheckContext(obj) \ + (void*)obj; do { \ + if(!PyObject_TypeCheck(obj, &PyUpb_ContextType)) { \ + PyErr_SetString(PyExc_TypeError, "Must be a upb.Context"); \ + return NULL; \ + } \ + } while(0) + +static PyObject *context_parsefds(PyObject *_context, PyObject *args) +{ + PyUpb_Context *context = CheckContext(_context); + struct upb_string str; + if(!PyArg_ParseTuple(args, bytes_format, &str.ptr, &str.byte_len)) + return NULL; + str.byte_size = 0; /* We don't own that mem. */ + + if(!upb_context_parsefds(context->context, &str)) { + /* TODO: an appropriate error. */ + PyErr_SetString(PyExc_TypeError, "Failed to parse."); \ + return NULL; \ + } + Py_RETURN_NONE; +} + +//static PyObject *context_lookup(PyObject *self, PyObject *args) +//{ +// PyUpb_Context *context = CheckContext(self); +// struct upb_string str; +// if(!PyArg_ParseTuple(args, "s#", &str.ptr, &str.byte_len)) +// return NULL; +// str.byte_size = 0; /* We don't own that mem. */ +// +// struct upb_symtab_entry e; +// if(upb_context_lookup(context->context, &str, &e)) { +// return get_or_create_def(&e); +// } else { +// Py_RETURN_NONE; +// } +//} +// +//static PyObject *context_resolve(PyObject *self, PyObject *args) +//{ +// PyUpb_Context *context = CheckContext(self); +// struct upb_string str; +// if(!PyArg_ParseTuple(args, "s#", &str.ptr, &str.byte_len)) +// return NULL; +// str.byte_size = 0; /* We don't own that mem. */ +// +// struct upb_symtab_entry e; +// if(upb_context_resolve(context->context, &str, &e)) { +// return get_or_create_def(&e); +// } else { +// Py_RETURN_NONE; +// } +//} + +static void add_string(void *udata, struct upb_symtab_entry *entry) +{ + PyObject *list = udata; + struct upb_string *s = &entry->e.key; + /* TODO: check return. */ + PyObject *str = PyString_FromStringAndSize(s->ptr, s->byte_len); + PyList_Append(list, str); +} + +static PyObject *context_symbols(PyObject *self, PyObject *args) +{ + PyUpb_Context *context = CheckContext(self); + PyObject *list = PyList_New(0); /* TODO: check return. */ + upb_context_enumerate(context->context, add_string, list); + return list; +} + +static PyMethodDef context_methods[] = { + {"parse_file_descriptor_set", context_parsefds, METH_VARARGS, + "Parses a string containing a serialized FileDescriptorSet and adds its " + "definitions to the context." + }, + //{"lookup", context_lookup, METH_VARARGS, + // "Finds a symbol by fully-qualified name (eg. foo.bar.MyType)." + //}, + //{"resolve", context_resolve, METH_VARARGS, + // "Finds a symbol by a possibly-relative name, which will be interpreted " + // "in the context of the given base." + //} + {"symbols", context_symbols, METH_NOARGS, + "Returns a list of symbol names that are defined in this context." + }, + {NULL, NULL} +}; + +static PyObject *context_new(PyTypeObject *subtype, + PyObject *args, PyObject *kwds) +{ + PyUpb_Context *obj = (void*)subtype->tp_alloc(subtype, 0); + obj->context = upb_context_new(); + return (void*)obj; +} + +static void context_dealloc(PyObject *obj) +{ + PyUpb_Context *c = (void*)obj; + upb_context_unref(c->context); +} + +static PyTypeObject PyUpb_ContextType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "upb.definition.Context", /* tp_name */ + sizeof(PyUpb_Context), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)context_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 */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + context_methods, /* 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 */ + context_new, /* tp_new */ + 0, /* tp_free */ +}; + +PyMethodDef methods[] = { +}; + +PyMODINIT_FUNC +initdefinition(void) +{ + if(PyType_Ready(&PyUpb_ContextType) < 0) return; + Py_INCREF(&PyUpb_ContextType); /* TODO: necessary? */ + + PyObject *mod = Py_InitModule("upb.definition", methods); + PyModule_AddObject(mod, "Context", (PyObject*)&PyUpb_ContextType); +} diff --git a/lang_ext/python/definition.h b/lang_ext/python/definition.h new file mode 100644 index 0000000..8731b8a --- /dev/null +++ b/lang_ext/python/definition.h @@ -0,0 +1,34 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + * + * See def.h for a general description. These definitions + * must be shared so that specific Python message types (for the + * different proto APIs) can have access to the C definitions. */ + +#ifndef UPB_PYTHON_DEFINITION_H_ +#define UPB_PYTHON_DEFINITION_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + struct upb_msgdef *def; +} PyUpb_MessageDefinition; + +extern PyTypeObject PyUpb_MessageDefinitionType; + +/* What format string should be passed to PyArg_ParseTuple to get just a raw + * string of bytes and a length. */ +extern const char *bytes_format; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/lang_ext/python/setup.py b/lang_ext/python/setup.py new file mode 100644 index 0000000..de937c4 --- /dev/null +++ b/lang_ext/python/setup.py @@ -0,0 +1,11 @@ +from distutils.core import setup, Extension +setup(name='upb', + version='0.1', + ext_modules=[Extension('upb.definition', ['definition.c'], + include_dirs=['../../src'], + define_macros=[("UPB_USE_PTHREADS", 1), + ("UPB_UNALIGNED_READS_OK", 1)], + library_dirs=['../../src'], + libraries=['upb'] + )], + ) -- cgit v1.2.3