473,587 Members | 2,487 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Type checking inside a C extension

I have a C extension function into which I pass a list of lists
of tuples:

[
[ ("A",1), ("B",2) ("C",3) ],
[ ("A",1), ("B",2) ("C",3) ],
[ ("A",1), ("B",2) ("C",3) ],
]

I then unpack the values (down to the tuple elements) into their C
values using:

PyLong_AsLong(P yTuple_GetItem( tupl,0))

to extract the int from the first element of the tuple and

PyString_AsStri ng(PyTuple_GetI tem(tupl,1))[0]

to get the char from the second element.
The problem is that neither PyLong_AsLong() nor PyString_AsStri ng()
does any type checking so the interpreter crashes when I try to use
the values returned by PyLong_AsLong() and PyString_AsStri ng() if
they happen to be fed objects - the tuple elements in this case - of
the wrong type.

I could certainly do a type check using PyLong_Check() and
PyString_Check( ) on the tuple items and raise a TypeError exception
to avoid leading to a crash, but I am concerned about the speed hit
as this is the innermost loop of a routine which gets called
really often (I use it for text block transfers).

Is there a less expensive way to check the type, or somehow
avoid a crashing situation (i.e. an exception gets properly raised)
without calling PyLong_Check() and PyString_Check( ) the elements
of each and every tuple?
Jul 18 '05 #1
9 3651
Jon Perez wrote:

The problem is that neither PyLong_AsLong() nor
PyString_AsStri ng() does any type checking so the
interpreter crashes when I try to use the values
returned by PyLong_AsLong() and PyString_AsStri ng() if
they happen to be fed objects - the tuple elements in
this case - of the wrong type.
It isn't true that PyLong_AsLong does no type checking. It does. It
reports problems through the standard Python exception system.
I could certainly do a type check using PyLong_Check() and
PyString_Check( ) on the tuple items and raise a TypeError exception
to avoid leading to a crash, but I am concerned about the speed hit
as this is the innermost loop of a routine which gets called really
often (I use it for text block transfers).

PyLong_Check is pretty cheap:

#define PyObject_TypeCh eck(ob, tp) \
((ob)->ob_type == (tp) || PyType_IsSubtyp e((ob)->ob_type, (tp)))
#define PyLong_Check(op ) PyObject_TypeCh eck(op, &PyLong_Type )

Note that it is basically just a dereference and comparison check. I
wouldn't worry about that even in an inner loop.
Is there a less expensive way to check the type, or somehow
avoid a crashing situation (i.e. an exception gets properly raised)
without calling PyLong_Check() and PyString_Check( ) the elements
of each and every tuple?


I would usually use Pyrex for a job like this. But barring that, I often
use its output to remember how to do little Python/C things. Given this
input program:

def foo(b):
cdef int a
a = b

it generates code like this:

/* "/private/tmp/foo.pyx":3 */
__pyx_1 = PyInt_AsLong(__ pyx_v_b);
if (PyErr_Occurred ()) {error handling and return}

By PyErr_Occurred( ) is a real function call and is probably slower than
PyLong_Check.

Paul Prescod

Jul 18 '05 #2
On Mon, 5 Apr 2004, Jon Perez wrote:
Is there a less expensive way to check the type, or somehow
avoid a crashing situation (i.e. an exception gets properly raised)
without calling PyLong_Check() and PyString_Check( ) the elements
of each and every tuple?


It might be expensive, but perhaps PyArg_ParseTupl e() might be able to do
the decoding of your tuples more neatly than the various PyXX_Check()
calls.

--
Andrew I MacIntyre "These thoughts are mine alone..."
E-mail: an*****@bullsey e.apana.org.au (pref) | Snail: PO Box 370
an*****@pcug.or g.au (alt) | Belconnen ACT 2616
Web: http://www.andymac.org/ | Australia

Jul 18 '05 #3
Paul Prescod wrote:
It isn't true that PyLong_AsLong does no type checking. It does. It
reports problems through the standard Python exception system.
This illustrates a case where a crash occurs instead of an
exception being thrown. Feed spam.getstring( ) something besides a
string:

static PyObject *spam_getstring (PyObject *self, PyObject *args) {
PyObject *tup, *a, *b;

char strstr[100];

if (!PyArg_ParseTu ple(args, "O", &strobj))
return NULL;

// PyString_AsStri ng(strobj); // raises exception
strcpy(strstr,P yString_AsStrin g(strobj)); /* crashes!! */

Py_INCREF(Py_No ne);
return Py_None;
}

What gives? Shouldn't the exception be raised within PyString_AsStri ng()
before it even gets a chance to return a value to strcpy()? (Note:
I have been using IDLE - in the default separate subprocess mode - to observe
this behaviour)
Assuming I am resigned to calling PyString_Check( ) myself, can I
avoid the redundant PyString_Check( ) that PyString_AsStri ng() is
probably calling?
PyLong_Check is pretty cheap:

#define PyObject_TypeCh eck(ob, tp) \
((ob)->ob_type == (tp) || PyType_IsSubtyp e((ob)->ob_type, (tp)))
#define PyLong_Check(op ) PyObject_TypeCh eck(op, &PyLong_Type )
Kewl...
it generates code like this:

/* "/private/tmp/foo.pyx":3 */
__pyx_1 = PyInt_AsLong(__ pyx_v_b);
if (PyErr_Occurred ()) {error handling and return}

By PyErr_Occurred( ) is a real function call and is probably slower than
PyLong_Check.


Is PyType_IsSubtyp e((ob)->ob_Type,(tp) )) a real function call as well though?

Jul 18 '05 #4
On Tue, 6 Apr 2004, Jon Perez wrote:
// PyString_AsStri ng(strobj); // raises exception
strcpy(strstr,P yString_AsStrin g(strobj)); /* crashes!! */

Py_INCREF(Py_No ne);
return Py_None;
}

What gives? Shouldn't the exception be raised within PyString_AsStri ng()
before it even gets a chance to return a value to strcpy()?


First rule of using the Python C API: _always_ check the return value of
API functions.

In the case you exhibit, if the return value of PyString_AsStri ng is NULL,
a TypeError exception will have been set and you should immediately
return NULL.

When the interpreter gets a NULL return from a called function, it checks
for an exception. If you don't return NULL, it can't detect the exception
until some other unrelated event turns it up.

--
Andrew I MacIntyre "These thoughts are mine alone..."
E-mail: an*****@bullsey e.apana.org.au (pref) | Snail: PO Box 370
an*****@pcug.or g.au (alt) | Belconnen ACT 2616
Web: http://www.andymac.org/ | Australia

Jul 18 '05 #5
On Tue, 06 Apr 2004 11:54:30 +0800, Jon Perez <jb********@yah oo.com>
wrote:
Paul Prescod wrote:
It isn't true that PyLong_AsLong does no type checking. It does. It
reports problems through the standard Python exception system.


This illustrates a case where a crash occurs instead of an
exception being thrown. Feed spam.getstring( ) something besides a
string:

static PyObject *spam_getstring (PyObject *self, PyObject *args) {
PyObject *tup, *a, *b;

char strstr[100];

if (!PyArg_ParseTu ple(args, "O", &strobj))
return NULL;

// PyString_AsStri ng(strobj); // raises exception
strcpy(strstr,P yString_AsStrin g(strobj)); /* crashes!! */

Py_INCREF(Py_No ne);
return Py_None;
}

What gives? Shouldn't the exception be raised within PyString_AsStri ng()
before it even gets a chance to return a value to strcpy()?


I assume you're talking about when the PyString_AsStri ng *isn't*
commented out ;-)
Python exceptions aren't converted to C exceptions, and the Python C
API doesn't use C exceptions at all. There is a good reason for this.
C doesn't have exceptions - C++ does, but this is a C API.

Given that C lacks exceptions, there is no practical (and portable)
way to forcibly unwind the stack. Even if something could be done with
longjump, for instance, there would be the issue of how your function
gets to do its cleanup.

Therefore, the simplest way for a Python C API function to propogate a
Python exception is by returning an error return value to the caller,
and keeping associated data in global variables. The caller then takes
on the responsibility for propogating the exception up to its caller
and so on. Which is precisely what Python appears to do. The caller
needs to check for the error value, do any neccessary cleanup, and
then propogate the error out of the function.

Python C API functions often return zero for error IIRC, so...

if (PyString_AsStr ing(strobj) == 0) { return 0; }

Should ensure that the Python exception raised by PyString_AsStri ng is
propogated correctly.
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #6
Stephen Horne wrote:
Python exceptions aren't converted to C exceptions, and the Python C
API doesn't use C exceptions at all. There is a good reason for this.
C doesn't have exceptions - C++ does, but this is a C API.
Ah... now I get this seemingly mysterious behaviour.

If PyString_AsStri ng() attempts to convert a non-string Python object to a
C string, the exception is not thrown from within it, it only sets a flag
indicating that such an exception should eventually be thrown.

While the C extension function itself does need to return a NULL for said
exception occur, it does need to to return to Python runtime first to
trigger the exception.

Python C API functions often return zero for error IIRC, so...

if (PyString_AsStr ing(strobj) == 0) { return 0; }

Should ensure that the Python exception raised by PyString_AsStri ng is
propogated correctly.


This also answers my earlier question. So there is no need to do a
PyString_Check( ) before feeding a value to PyString_AsStri ng(), just
check the return value of PyString_AsStri ng()...

Thanks everyone.
Jul 18 '05 #7
Andrew MacIntyre wrote:
First rule of using the Python C API: _always_ check the return value of
API functions.


This only applies to API functions which return PyObject*, right?
Jul 18 '05 #8
Jon Perez wrote:
Andrew MacIntyre wrote:
First rule of using the Python C API: _always_ check the return value of
API functions.


This only applies to API functions which return PyObject*, right?


....because it is not hard to find instances in the source code for
the modules that come with Python where, for example, PyTuple_SetItem ()'s
return value is not checked for.
Jul 18 '05 #9
On Wed, 07 Apr 2004 11:50:05 +0800, Jon Perez <jb********@yah oo.com>
wrote:
Andrew MacIntyre wrote:
First rule of using the Python C API: _always_ check the return value of
API functions.


This only applies to API functions which return PyObject*, right?


It isn't that simple. There are API functions returning an int, IIRC,
where that int can indicate an error condition.

However, if you can ensure that an error cannot exist OR if you can
arrange things such that the error is naturally handled, THEN you
don't need an explicit check.

For instance, sometimes you can just return the result of an API
function. If the API function returns a valid result, so does your
function. If the API function returns NULL, your function does so too
so the exception is propogated. If you don't need any further
processing or cleanup, why make a fuss?

"_always_ check the return value" is a very good principle, however,
even if not quite literally correct.
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
2108
by: Vinodh Kumar P | last post by:
Whenever I read any C++ literature I find the words "C++ is statically type checked".OK.Agreed. Is there any language that supports "Dynamic type checking"? In such a case any type can be assigned to any other type during compile time?
0
1109
by: Pedro Werneck | last post by:
Hi list I'm trying to implement a new type in a C extension and it must support some binary operators, like &, |, ^, << and >>. With &, | and ^, the method must receive another object of the same type, perform the operation with an attribute of both, create a new object with the result as the attribute and return it. Everything works perfectly with &, | and ^, but with << and >> I need
4
2053
by: Mark | last post by:
Hi.. I have a c# class that i'm using to implement some extension functions and one of those functions is a simple push/pop stack. I made the c# code fairly generic, taking and returning objects - i.e public void push (object val { stack.Push (val) public object pop ( { return stack.Pop()
0
966
by: Brian Henry | last post by:
I am using the following code to get the "Type" of a file Imports System.Runtime.InteropServices Public Class ShellAPI Public Declare Auto Function SHGetFileInfo Lib "shell32.dll" ( _ ByVal pszPath As String, _
3
4079
by: Mark Rae | last post by:
Hi, I've been asked to write a WinForms app which will create reports as PDF documents. The client has agreed that all desktops (WinXP Pro, 32-bit Vista Business) *will* have Adobe Acrobat Reader installed but, in the interests of robustness, I want to check for this when the app loads. Would you recommend checking for the Adobe Acrobat Reader specifically, or
14
34063
by: GeezerButler | last post by:
For any given type i want to know its default value. There is a neat keyword called default for doing this like object x = default(DateTime); but I have an instance of Type (called someType) and something like this cant work object x = default(someType); Is there any nice way of doing this? I dont really want to write a huge switch block enumerating all types in .NET !
6
6241
by: Mad Hatter | last post by:
Hi folks I'm a bit confused with an upload script that I've written. I want to be able to check the file type of an upload by checking the mime type but I'm not getting the results that I thought I should. According to what I've read .zip files should return something like 'application/zip' or 'application/x-zip-compressed', RAR should return 'application/x-rar-compressed' but both return 'application/octet-stream'. I'm getting the...
2
2783
by: Paul Moore | last post by:
I'm trying to implement an extension type with a power operator. The operator is unusual in that I want to allow my objects to be raised to an integer power: p = Pattern() p3 = p ** 3 I've implemented the code for a nb_power slot, it converts the "other" argument to a C long using PyInt_AsLong().
1
2856
by: sasimca007 | last post by:
Hai friends, I have a doubt that if we are having a page which having the functionality to upload a file, then if we want to restrict to some types of files only have to be uploaded ex:- jpg,png.... .Then i am using Apache2::Upload module in which we can get the type of file using type function. But the users are very smart than me. They changed the extension of pdf file into jpg and they are uploading...
0
7923
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
7852
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8216
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8349
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
7974
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
5395
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
3882
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1455
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
1192
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.