FAQ sobre Extensão/Incorporação
*******************************


Posso criar minhas próprias funções em C?
=========================================

Sim, você pode construir módulos embutidos contendo funções,
variáveis, exceções e até mesmo novos tipos em C. Isso é explicado no
documento Estendendo e Incorporando o Interpretador Python.

A maioria dos livros intermediários ou avançados em Python também
abordará esse tópico.


Posso criar minhas próprias funções em C++?
===========================================

Sim, usando recursos de compatibilidade encontrados em C++. Coloque
"extern "C" { ... }" em torno dos arquivos de inclusão do Python e
coloque "extern "C"" antes de cada função que será chamada pelo
interpretador do Python. Objetos globais ou estáticos em C++ com
construtores provavelmente não são uma boa ideia.


Escrever C é difícil; há alguma alternativa?
============================================

Há um número de alternativas para escrever suas próprias extensões em
C, dependendo daquilo que você está tentando fazer.

Cython and its relative Pyrex are compilers that accept a slightly
modified form of Python and generate the corresponding C code.  Cython
and Pyrex make it possible to write an extension without having to
learn Python's C API.

If you need to interface to some C or C++ library for which no Python
extension currently exists, you can try wrapping the library's data
types and functions with a tool such as SWIG.  SIP, CXX Boost, or
Weave are also alternatives for wrapping C++ libraries.


Como posso executar instruções arbitrárias de Python a partir de C?
===================================================================

A função mais alto-nível para isso é a "PyRun_SimpleString()", que
recebe como único argumento uma string a ser executada no contexto do
módulo "__main__" e retorna "0" para sucesso e "-1" quando uma exceção
ocorrer (incluindo "SyntaxError").  Se quiser mais controle, use
"PyRun_String()"; veja o código-fonte de "PyRun_SimpleString()" em
"Python/pythonrun.c".


Como posso executar e obter o resultado de uma expressão Python arbitrária a partir de C?
=========================================================================================

Chame a função "PyRun_String()" da pergunta anterior passando
"Py_eval_input" como o símbolo de início; ela faz a análise sintática
de uma expressão, a executa, e retorna o seu valor.


Como extraio valores em C a partir de um objeto Python?
=======================================================

That depends on the object's type.  If it's a tuple, "PyTuple_Size()"
returns its length and "PyTuple_GetItem()" returns the item at a
specified index.  Lists have similar functions, "PyListSize()" and
"PyList_GetItem()".

For bytes, "PyBytes_Size()" returns its length and
"PyBytes_AsStringAndSize()" provides a pointer to its value and its
length.  Note that Python bytes objects may contain null bytes so C's
"strlen()" should not be used.

Para testar o tipo de um objeto, primeiramente se certifique de que
ele não é "NULL", e então use "PyBytes_Check()", "PyTuple_Check()",
"PyList_Check()", etc.

Também existe uma API alto-nível para objetos Python fornecida pela
chamada interface "abstrata" -- leia "Include/abstract.h" para mais
detalhes.  Ela permite interagir com qualquer tipo de sequência Python
usando chamadas como "PySequence_Length()", "PySequence_GetItem()",
etc, além de vários outros protocolos úteis tais como números
("PyNumber_Index()" e outros) e mapeamentos nas APIs PyMapping.


Como posso utilizar Py_BuildValue() para criar uma tupla de comprimento arbitrário?
===================================================================================

Não é possível. Use a função "PyTuple_Pack()" para isso.


Como eu chamo um método de um objeto a partir do C?
===================================================

A função "PyObject_CallMethod()" pode ser usada para chamar um método
arbitrário de um objeto.  Os parâmetros são o objeto, o nome do método
a ser chamado, uma string de formato como a usada em
"Py_BuildValue()", e os valores dos argumentos:

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

Isso funciona para qualquer objeto que tenha métodos -- sejam eles
embutidos ou definidos por usuário. Você fica então responsável por
chamar "Py_DECREF()" no valor de retorno.

Para chamar, por exemplo, o método "seek" de um objeto arquivo com
argumentos 10, 0 (presumindo que "f" é o ponteiro para o objeto
arquivo):

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

Note que a função "PyObject_CallObject()" *sempre* recebe os
argumentos da chamada como uma tupla, de forma que para chamar uma
função sem argumentos deve-se passar "()" como formato, e para chamar
uma função com 1 argumento, coloque-o entre parênteses, por exemplo
"(i)".


Como posso capturar a saída da função PyErr_Print() (ou qualquer outra coisa que escreva para stdout/stderr)?
=============================================================================================================

Com código Python, defina um objeto que suporte o método "write()".
Atribua esse objeto a "sys.stdout" e "sys.stderr".  Chame print_error,
or simplesmente deixe o mecanismo padrão de traceback acontecer.
Assim, a saída irá para onde quer que o seu método "write()" a envie.

O jeito mais fácil de fazer isso é usar a classe "io.StringIO":

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

Um objeto personalizado para fazer a mesma coisa seria esse:

   >>> 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!


Como faço para acessar a partir do C um módulo escrito em Python?
=================================================================

Você pode obter um pointeiro para o objeto de módulo da seguinte
maneira:

   module = PyImport_ImportModule("<modulename>");

Se o módulo ainda não foi importado (isto é, ainda não aparece no
"sys.modules"), essa função vai inicializar o módulo; caso contrário,
ela vai simplesmente retornar o valor de
"sys.modules["<modulename>"]".  Note que ela não adiciona o módulo a
nenhum espaço de nomes -- ela simplesmente garante que ele foi
inicializado e colocado no "sys.modules".

Você pode então acessar os atributos do módulo (isto é, qualquer nome
definido no módulo) assim:

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

Chamar "PyObject_SetAttrString()" para definir variáveis no módulo
também funciona.


Como posso interagir com objetos C++ a partir do Python?
========================================================

Dependendo das suas necessidades, há diversas abordagens.  Para fazer
isso manualmente, comece lendo o documento "Estendendo e
Incorporando".  Note que, para o sistema Python em tempo de execução,
não há muita diferença entre C e C++ -- de forma que a estratégia de
construir um novo tipo Python ao redor de uma estrutura C (ou ponteiro
para uma) também funciona para objetos C++.

Para bibliotecas C++, veja Escrever C é difícil; há alguma
alternativa?.


Adicionei um módulo usando o arquivo de Setup e o make falha; por quê?
======================================================================

O Setup deve terminar com uma quebra de linha; se não houver uma
quebra de linha no final, o processo de compilação falha.  (Consertar
isso requer umas gambiarras feias em shell script, e esse bug é tão
pequeno que o esforço não parece valer a pena.)


Como eu depuro uma extensão?
============================

Ao usar o GDB com extensões carregadas dinamicamente, você não
consegue definir um ponto de interrupção antes da sua extensão ser
carregada.

No seu arquivo ".gdbinit" (ou então interativamente), adicione o
comando:

   br _PyImport_LoadDynamicModule

Então, ao executar o 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


Quero compilar um módulo Python no meu sistema Linux, mas alguns arquivos estão faltando. Por quê?
==================================================================================================

Most packaged versions of Python don't include the
"/usr/lib/python2.*x*/config/" directory, which contains various files
required for compiling Python extensions.

For Red Hat, install the python-devel RPM to get the necessary files.

For Debian, run "apt-get install python-dev".


Como posso distinguir "entrada incompleta" de "entrada inválida"?
=================================================================

Às vezes você quer emular o comportamento do interpretador interativo
do Python, que te dá um prompt de continuação quando a entrada está
incompleta (por exemplo, você digitou o início de uma instrução "if",
ou então não fechou os parênteses ou aspas triplas), mas que te dá um
mensagem de erro de sintaxe imediatamente se a entrada for inválida.

Em Python você pode usar o módulo "codeop", que aproxima
suficientemente o comportamento do analisador sintático.  Por exemplo,
o IDLE o usa.

Em C, a forma mais fácil de fazer isso é chamar
"PyRun_InteractiveLoop()" (talvez em uma thread separada) e deixar o
interpretador do Python tratar a entrada para você. Você tambémm pode
apontar o "PyOS_ReadlineFunctionPointer()" para a sua função de
entrada personalizada. Consulte "Modules/readline.c" e
"Parser/myreadline.c" para mais dicas.

However sometimes you have to run the embedded Python interpreter in
the same thread as your rest application and you can't allow the
"PyRun_InteractiveLoop()" to stop while waiting for user input.  The
one solution then is to call "PyParser_ParseString()" and test for
"e.error" equal to "E_EOF", which means the input is incomplete.
Here's a sample code fragment, untested, inspired by code from 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;
   }

Another solution is trying to compile the received string with
"Py_CompileString()". If it compiles without errors, try to execute
the returned code object by calling "PyEval_EvalCode()". Otherwise
save the input for later. If the compilation fails, find out if it's
an error or just more input is required - by extracting the message
string from the exception tuple and comparing it to the string
"unexpected EOF while parsing".  Here is a complete example using the
GNU readline library (you may want to ignore **SIGINT** while calling
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);
   }


Como encontro os símbolos __builtin_new ou __pure_virtual não-definidos no g++?
===============================================================================

Para carregar dinamicamente módulos de extensão feitos com g++, você
precisa recompilar o Python, usando o g++ como ligador (mude a
constante LINKCC no Makefile dos módulos de extensão do Python), e use
o g++ também como ligador do seu módulo (por exemplo, "g++ -shared -o
mymodule.so mymodule.o").


Posso criar uma classe de objetos com alguns métodos implementados em C e outros em Python (por exemplo, via herança)?
======================================================================================================================

Sim, você pode herdar de classes embutidas como "int", "list", "dict"
etc.

The Boost Python Library (BPL,
http://www.boost.org/libs/python/doc/index.html) provides a way of
doing this from C++ (i.e. you can inherit from an extension class
written in C++ using the BPL).
