Extendiendo/Embebiendo FAQ
**************************


¿Puedo crear mis propias funciones en C?
========================================

Si, puedes crear módulos incorporados que contengan funciones,
variables, excepciones y incluso nuevos tipos en C. Esto esta
explicado en el documento Ampliación e incrustación del intérprete de
Python.

La mayoría de los libros intermedios o avanzados de Python también
tratan este tema.


¿Puedo crear mis propias funciones en C++?
==========================================

Si, utilizando las características de compatibilidad encontradas en
C++. Coloca "extern "C" { ... }" alrededor los archivos incluidos
Python y pon "extern "C"" antes de cada función que será llamada por
el interprete Python. Objetos globales o estáticos C++ con
constructores no son una buena idea seguramente.


Escribir en C es difícil; ¿no hay otra alternativa?
===================================================

Hay un número de alternativas a escribir tus propias extensiones C,
dependiendo en que estés tratando de hacer.

Cython y su relativo Pyrex son compiladores que aceptan una forma de
Python ligeramente modificada y generan el código C correspondiente.
Cython y *Pyrex* hacen posible escribir una extensión sin tener que
aprender la API de Python C.

Si necesitas hacer una interfaz a alguna biblioteca C o C++ que no
posee aún extensión Python, puedes intentar empaquetar los tipo de
datos de la biblioteca con una herramienta como SWIG.  SIP, CXX Boost,
o Weave también son alternativas para empaquetar bibliotecas C++.


¿Cómo puedo ejecutar declaraciones arbitrarias de Python desde C?
=================================================================

La función de más alto nivel para hacer esto es "PyRun_SimpleString()"
que toma un solo argumento de cadena de caracteres para ser ejecutado
en el contexto del módulo "__main__" y retorna "0" si tiene éxito y
"-1" cuando ocurre una excepción (incluyendo "SyntaxError"). Si
quieres mas control, usa "PyRun_String()"; mira la fuente para
"PyRun_SimpleString()" en "Python/pythonrun.c".


¿Cómo puedo evaluar una expresión arbitraria de Python desde C?
===============================================================

Call the function "PyRun_String()" from the previous question with the
start symbol "Py_eval_input"; it parses an expression, evaluates it
and returns its value.


¿Cómo extraigo valores C de un objeto Python?
=============================================

Eso depende del tipo de objeto. Si es una tupla, "PyTuple_Size()"
retorna su tamaño, y "PyTuple_GetItem()" retorna el ítem del índice
especificado. Las listas tienen funciones similares, "PyListSize()"
and "PyList_GetItem()".

Para bytes "PyBytes_Size()" retorna su tamaño, y
"PyBytes_AsStringAndSize()" proporciona un puntero a su valor y
tamaño. Nota que los objetos byte de Python pueden contener bytes
*null* por lo que la función de C "strlen()" no debe ser utilizada.

Para testear el tipo de un objeto, primero debes estar seguro que no
es "NULL", y luego usa "PyBytes_Check()", "PyTuple_Check()",
"PyList_Check()", etc.

También hay una API de alto nivel para objetos Python que son
provistos por la supuestamente llamada interfaz 'abstracta' -- lee
"Include/abstract.h" para mas detalles. Permite realizar una interfaz
con cualquier tipo de secuencia Python usando llamadas como
"PySequence_Length()", "PySequence_GetItem()", etc. así como otros
protocolos útiles como números ("PyNumber_Index()" et al.) y mapeos en
las *PyMapping APIs*.


¿Cómo utilizo Py_BuildValue() para crear una tupla de un tamaño arbitrario?
===========================================================================

No puedes hacerlo. Utiliza a cambio "PyTuple_Pack()".


¿Cómo puedo llamar un método de un objeto desde C?
==================================================

Se puede utilizar la función "PyObject_CallMethod()" para llamar a un
método arbitrario de un objeto. Los parámetros son el objeto, el
nombre del método a llamar, una cadena de caracteres de formato como
las usadas con  "Py_BuildValue()", y los valores de argumento

   PyObject *
   PyObject_CallMethod(PyObject *object, const char *method_name,
                       const char *arg_format, ...);

Esto funciona para cualquier objeto que tenga métodos -- sean estos
incorporados o definidos por el usuario. Eres responsable si
eventualmente usas "Py_DECREF()" en el valor de retorno."

Para llamar, por ejemplo, un método "seek" de un objeto archivo con
argumentos 10, 0 (considerando que puntero del objeto archivo es "f"):

   res = PyObject_CallMethod(f, "seek", "(ii)", 10, 0);
   if (res == NULL) {
           ... an exception occurred ...
   }
   else {
           Py_DECREF(res);
   }

Note que debido a "PyObject_CallObject()" *siempre* necesita una tupla
para la lista de argumento, para llamar una función sin argumentos,
deberás pasar "()" para el formato, y para llamar a una función con un
solo argumento, encierra el argumento entre paréntesis, por ejemplo
"(i)".


¿Cómo obtengo la salida de PyErr_Print() (o cualquier cosa que se imprime a stdout/stderr)?
===========================================================================================

En código Python, define un objeto que soporta el método "write()".
Asigna este objeto a "sys.stdout" y "sys.stderr". Llama a print_error,
o solo permite que el mecanismo estándar de rastreo funcione. Luego,
la salida se hará cuando invoques "write()".

La manera mas fácil de hacer esto es usar la clase "io.StringIO".

   >>> import io, sys
   >>> sys.stdout = io.StringIO()
   >>> print('foo')
   >>> print('hello world!')
   >>> sys.stderr.write(sys.stdout.getvalue())
   foo
   hello world!

Un objeto personalizado para hacer lo mismo se vería así:

   >>> import io, sys
   >>> class StdoutCatcher(io.TextIOBase):
   ...     def __init__(self):
   ...         self.data = []
   ...     def write(self, stuff):
   ...         self.data.append(stuff)
   ...
   >>> import sys
   >>> sys.stdout = StdoutCatcher()
   >>> print('foo')
   >>> print('hello world!')
   >>> sys.stderr.write(''.join(sys.stdout.data))
   foo
   hello world!


¿Cómo accedo al módulo escrito en Python desde C?
=================================================

Puedes obtener un puntero al módulo objeto de esta manera:

   module = PyImport_ImportModule("<modulename>");

Si el módulo todavía no se importó, (por ejemplo aún no esta presente
en "sys.modules"), esto inicializa el módulo, de otra forma
simplemente retorna el valor de "sys.modules["<modulename>"]". Nota
que no entra el módulo a ningún espacio de nombres (*namespace*)
--solo asegura que fue inicializado y guardado en "sys.modules".

Puedes acceder luego a los atributos del módulo (por ejemplo a
cualquier nombre definido en el módulo) de esta forma:

   attr = PyObject_GetAttrString(module, "<attrname>");

También funciona llamar a "PyObject_SetAttrString()" para asignar a
variables en el módulo.


¿Cómo hago una interface a objetos C++ desde Python?
====================================================

Dependiendo de lo que necesites, hay varias maneras de hacerlo. Para
hacerlo manualmente empieza por leer the "Extending and Embedding"
document.Fíjate que para el sistema de tiempo de ejecución Python, no
hay una gran diferencia entre C y C++, por lo que la estrategia de
construir un nuevo tipo Python alrededor de una estructura de C de
tipo puntero, también funcionará para objetos C++.

Para bibliotecas C++, mira Escribir en C es difícil; ¿no hay otra
alternativa?.


He agregado un módulo usando el archivo de configuración y el *make* falla. ¿Porque?
====================================================================================

La configuración debe terminar en una nueva linea, si esta no está,
entonces el proceso *build* falla. (reparar esto requiere algún truco
de linea de comandos que puede ser no muy prolijo, y seguramente el
error es tan pequeño que no valdrá el esfuerzo.)


¿Cómo puedo depurar una extención?
==================================

When using GDB with dynamically loaded extensions, you can't set a
breakpoint in your extension until your extension is loaded.

En tu archivo ".gdbinit" (o interactivamente), agrega el comando:

   br _PyImport_LoadDynamicModule

Luego, cuando corras GDB:

   $ gdb /local/bin/python
   gdb) run myscript.py
   gdb) continue # repeat until your extension is loaded
   gdb) finish   # so that your extension is loaded
   gdb) br myfunction.c:50
   gdb) continue


Quiero compilar un módulo Python en mi sistema Linux, pero me faltan algunos archivos . ¿Por qué?
=================================================================================================

La mayoría de las versiones empaquetadas de Python no incluyen el
directorio "/usr/lib/python2.*x*/config/", que contiene varios
archivos que son necesarios para compilar las extensiones Python.

Para *Red Hat*, instala el *python-devel RPM* para obtener los
archivos necesarios.

Para Debian, corre "apt-get install python-dev".


How do I tell "incomplete input" from "invalid input"?
======================================================

A veces quieres emular el comportamiento del interprete interactivo de
Python, que te da una continuación del *prompt* cuando la entrada esta
incompleta (por ejemplo si comenzaste tu instrucción "if" o no
cerraste un paréntesis o triples comillas), pero te da un mensaje de
error de sintaxis inmediatamente cuando la entrada es invalida.

In Python you can use the "codeop" module, which approximates the
parser's behavior sufficiently.  IDLE uses this, for example.

La manera mas fácil de hacerlo en C es llamar a
"PyRun_InteractiveLoop()" (quizá en un hilo separado) y dejar que el
interprete Python gestione la entrada por ti. Puedes también
configurar "PyOS_ReadlineFunctionPointer()" para apuntar a tu función
de entrada personalizada.

De todas maneras a veces debes correr el interprete embebido de Python
en el mismo hilo que tu *api rest*, y puedes permitir que
"PyRun_InteractiveLoop()" termine mientras espera por la entrada del
usuario. La primera solución es llamar a "PyParser_ParseString()" y
probar con "e.error" igual a "E_EOF", que significa que la entrada
esta incompleta. Aquí hay un fragmento de código ejemplo, que no esta
probado, inspirado en el código de Alex Farber:

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include <node.h>
   #include <errcode.h>
   #include <grammar.h>
   #include <parsetok.h>
   #include <compile.h>

   int testcomplete(char *code)
     /* code should end in \n */
     /* return -1 for error, 0 for incomplete, 1 for complete */
   {
     node *n;
     perrdetail e;

     n = PyParser_ParseString(code, &_PyParser_Grammar,
                              Py_file_input, &e);
     if (n == NULL) {
       if (e.error == E_EOF)
         return 0;
       return -1;
     }

     PyNode_Free(n);
     return 1;
   }

Otra solución es intentar compilar la cadena de caracteres recibida
con "Py_CompileString()". Si compila sin errores, intenta ejecutar el
objeto código retornado llamando a "PyEval_EvalCode()". De otra manera
salva el ingreso para después. Si la compilación falla, encuentra si
hay algún o si necesita algún ingreso adicional - extrayendo la cadena
de caracteres mensaje de la tupla excepción y comparándola con la
cadena de caracteres "unexpected EOF while parsing". Aquí hay un
ejemplo completo usando la biblioteca *GNU readline* (Seguramente
querrás ignorar **SIGINT** mientras llamas a readline()):

   #include <stdio.h>
   #include <readline.h>

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include <object.h>
   #include <compile.h>
   #include <eval.h>

   int main (int argc, char* argv[])
   {
     int i, j, done = 0;                          /* lengths of line, code */
     char ps1[] = ">>> ";
     char ps2[] = "... ";
     char *prompt = ps1;
     char *msg, *line, *code = NULL;
     PyObject *src, *glb, *loc;
     PyObject *exc, *val, *trb, *obj, *dum;

     Py_Initialize ();
     loc = PyDict_New ();
     glb = PyDict_New ();
     PyDict_SetItemString (glb, "__builtins__", PyEval_GetBuiltins ());

     while (!done)
     {
       line = readline (prompt);

       if (NULL == line)                          /* Ctrl-D pressed */
       {
         done = 1;
       }
       else
       {
         i = strlen (line);

         if (i > 0)
           add_history (line);                    /* save non-empty lines */

         if (NULL == code)                        /* nothing in code yet */
           j = 0;
         else
           j = strlen (code);

         code = realloc (code, i + j + 2);
         if (NULL == code)                        /* out of memory */
           exit (1);

         if (0 == j)                              /* code was empty, so */
           code[0] = '\0';                        /* keep strncat happy */

         strncat (code, line, i);                 /* append line to code */
         code[i + j] = '\n';                      /* append '\n' to code */
         code[i + j + 1] = '\0';

         src = Py_CompileString (code, "<stdin>", Py_single_input);

         if (NULL != src)                         /* compiled just fine - */
         {
           if (ps1  == prompt ||                  /* ">>> " or */
               '\n' == code[i + j - 1])           /* "... " and double '\n' */
           {                                               /* so execute it */
             dum = PyEval_EvalCode (src, glb, loc);
             Py_XDECREF (dum);
             Py_XDECREF (src);
             free (code);
             code = NULL;
             if (PyErr_Occurred ())
               PyErr_Print ();
             prompt = ps1;
           }
         }                                        /* syntax error or E_EOF? */
         else if (PyErr_ExceptionMatches (PyExc_SyntaxError))
         {
           PyErr_Fetch (&exc, &val, &trb);        /* clears exception! */

           if (PyArg_ParseTuple (val, "sO", &msg, &obj) &&
               !strcmp (msg, "unexpected EOF while parsing")) /* E_EOF */
           {
             Py_XDECREF (exc);
             Py_XDECREF (val);
             Py_XDECREF (trb);
             prompt = ps2;
           }
           else                                   /* some other syntax error */
           {
             PyErr_Restore (exc, val, trb);
             PyErr_Print ();
             free (code);
             code = NULL;
             prompt = ps1;
           }
         }
         else                                     /* some non-syntax error */
         {
           PyErr_Print ();
           free (code);
           code = NULL;
           prompt = ps1;
         }

         free (line);
       }
     }

     Py_XDECREF(glb);
     Py_XDECREF(loc);
     Py_Finalize();
     exit(0);
   }


How do I find undefined g++ symbols __builtin_new or __pure_virtual?
====================================================================

Para cargar dinámicamente módulos de extensión g++, debes recompilar
Python, hacer un nuevo *link* usando g++ (cambia LINKCC en el Python
Modules Makefile) y enlaza *link* tu extensión usando g++ (por ejemplo
*g++ -shared -o mymodule.so mymodule.o`*).


¿Puedo crear una clase objeto con algunos métodos implementado en C y otros en Python (por ejemplo a través de la herencia)?
============================================================================================================================

Si, puedes heredar de clases integradas como "int", "list", "dict",
etc.

La biblioteca *Boost Pyhton* (BPL,
http://www.boost.org/libs/python/doc/index.html) provee una manera de
realizar esto desde C++ (por ejemplo puedes heredar de una clase
extensión escrita en C++ usando el BPL).
