Skip to content

Commit 0b5768c

Browse files
committed
Improves debugging in IDE.
1 parent 4385e0b commit 0b5768c

File tree

2 files changed

+37
-36
lines changed

2 files changed

+37
-36
lines changed

doc/sphinx/source/debugging/debug_in_ide.rst

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Debuging Python C Extensions in an IDE
1717

1818
The basic idea is to compile/link your C extension in your IDE and get ``main()`` to call a function ``int import_call_execute(int argc, const char *argv[])`` that embeds the Python interpreter which then imports a Python module, say a unit test, that exercises your C extension code.
1919

20-
This ``import_call_execute()`` entry point is fairly generic and takes the standard arguments to ``main()``.
20+
This ``import_call_execute()`` entry point is fairly generic and takes the standard arguments to ``main()`` so it can be in its own .h/.c file.
2121

2222
------------------------------------------------
2323
Creating a Python Unit Test to Execute
@@ -39,38 +39,34 @@ Suppose you have a Python extension ``ScList`` that sub-classes a list and count
3939
Writing a C Function to call any Python Unit Test
4040
-------------------------------------------------------
4141

42-
We write the ``import_call_execute()`` function to take that same arguments as ``main()`` and ``import_call_execute()`` expects 4 arguments:
42+
We create the ``import_call_execute()`` function that takes that same arguments as ``main()`` which can forward its arguments. ``import_call_execute()`` expects 4 arguments:
4343

4444
* ``argc[0]`` - Name of the executable.
4545
* ``argc[1]`` - Path to the directory that the Python module is in.
4646
* ``argc[2]`` - Name of the Python module to be imported. This could be a unit test module for example.
4747
* ``argc[3]`` - Name of the Python function in the Python module (no arguments will be supplied, the return value is ignored). This could be a particular unit test.
4848

49-
The ``import_call_execute()`` function does this, in this particular case:
49+
The ``import_call_execute()`` function does this:
5050

5151
#. Check the arguments and initialises the Python interpreter
52-
#. Add the path to the ``test_sclist.py`` to ``sys.paths``.
53-
#. Import ``test_sclist``.
54-
#. Find the function ``test()`` in module ``test_sclist`` and call it.
52+
#. Add the path to the ``argc[1]`` to ``sys.paths``.
53+
#. Import ``argc[2]``.
54+
#. Find the function ``argc[3]`` in module ``argc[2]`` and call it.
5555
#. Clean up.
5656

5757

5858
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5959
Code Walk Through
6060
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6161

62-
So ``import_call_execute()`` is quite generic, here is a walk through of the code, the whole code is below.
62+
``import_call_execute()`` is quite generic and could be implemented in, say, ``py_import_call_execute.c``.
63+
64+
Here is a walk through of the implementation code:
6365

6466
Step 1: Check the arguments and initialise the Python interpreter
6567

6668
.. code-block:: c
6769
68-
#include <Python.h>
69-
70-
/** This should be the name of your executable.
71-
* It is just used for error messages. */
72-
#define EXECUTABLE_NAME "pyxcode"
73-
7470
/** This imports a Python module and calls a specific function in it.
7571
* It's arguments are similar to main():
7672
* argc - Number of strings in argv
@@ -96,7 +92,7 @@ Step 1: Check the arguments and initialise the Python interpreter
9692
if (argc != 4) {
9793
fprintf(stderr,
9894
"Wrong arguments!"
99-
" Usage: " EXECUTABLE_NAME " package_path module function\n");
95+
" Usage: %s package_path module function\n", argv[0]);
10096
return_value = -1;
10197
goto except;
10298
}
@@ -204,28 +200,33 @@ Step 5: Clean up.
204200
return return_value;
205201
}
206202
203+
And then we need ``main()`` to call this, thus:
204+
205+
.. code-block:: c
206+
207+
#include "py_import_call_execute.h"
208+
209+
int main(int argc, const char *argv[]) {
210+
return import_call_execute(argc, argv);
211+
}
212+
213+
207214
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
208215
Complete Code
209216
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
210217

211-
The complete code for the file is here:
218+
The complete code for ``py_import_call_execute.c`` is here:
212219

213220
.. code-block:: c
214221
215-
//
216-
// main.c
217-
// PythonSubclassList
218-
//
219-
// Created by Paul Ross on 01/05/2016.
220-
// Copyright (c) 2016 Paul Ross. All rights reserved.
221-
//
222+
#include "py_import_call_execute.h"
222223
223224
#include <Python.h>
224225
225-
/** This should be the name of your executable.
226-
* It is just used for error messages. */
227-
#define EXECUTABLE_NAME "pyxcode"
228-
226+
#ifdef __cplusplus
227+
extern "C" {
228+
#endif
229+
229230
/** Takes a path and adds it to sys.paths by calling PyRun_SimpleString.
230231
* This does rather laborious C string concatenation so that it will work in
231232
* a primitive C environment.
@@ -282,7 +283,7 @@ The complete code for the file is here:
282283
if (argc != 4) {
283284
fprintf(stderr,
284285
"Wrong arguments!"
285-
" Usage: " EXECUTABLE_NAME " package_path module function\n");
286+
" Usage: %s package_path module function\n", argv[0]);
286287
return_value = -1;
287288
goto except;
288289
}
@@ -295,31 +296,31 @@ The complete code for the file is here:
295296
pModule = PyImport_ImportModule(argv[2]);
296297
if (! pModule) {
297298
fprintf(stderr,
298-
EXECUTABLE_NAME ": Failed to load module \"%s\"\n", argv[2]);
299+
"%s: Failed to load module \"%s\"\n", argv[0], argv[2]);
299300
return_value = -3;
300301
goto except;
301302
}
302303
pFunc = PyObject_GetAttrString(pModule, argv[3]);
303304
if (! pFunc) {
304305
fprintf(stderr,
305-
EXECUTABLE_NAME ": Can not find function \"%s\"\n", argv[3]);
306+
"%s: Can not find function \"%s\"\n", argv[0], argv[3]);
306307
return_value = -4;
307308
goto except;
308309
}
309310
if (! PyCallable_Check(pFunc)) {
310311
fprintf(stderr,
311-
EXECUTABLE_NAME ": Function \"%s\" is not callable\n", argv[3]);
312+
"%s: Function \"%s\" is not callable\n", argv[0], argv[3]);
312313
return_value = -5;
313314
goto except;
314315
}
315316
pResult = PyObject_CallObject(pFunc, NULL);
316317
if (! pResult) {
317-
fprintf(stderr, EXECUTABLE_NAME ": Function call failed\n");
318+
fprintf(stderr, "%s: Function call failed\n", argv[0]);
318319
return_value = -6;
319320
goto except;
320321
}
321322
#ifdef DEBUG
322-
printf(EXECUTABLE_NAME ": PyObject_CallObject() succeeded\n");
323+
printf("%s: PyObject_CallObject() succeeded\n", argv[0]);
323324
#endif
324325
assert(! PyErr_Occurred());
325326
goto finally;
@@ -333,10 +334,10 @@ The complete code for the file is here:
333334
Py_Finalize();
334335
return return_value;
335336
}
336-
337-
int main(int argc, const char *argv[]) {
338-
return import_call_execute(argc, argv);
339-
}
337+
338+
#ifdef __cplusplus
339+
// extern "C" {
340+
#endif
340341
341342
342343
--------------------------------------------

0 commit comments

Comments
 (0)