PyArg_ParseTupleAndKeywords in Python3.1

J

Joachim Dahl

I am updating an extension module from Python2.6 to Python3.

I used to pass character codes to the extension module, for example, I
would write:
with the corresponding C extension routine defined as follows:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
char foo;
char *kwlist[] = {"foo", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist, &foo))
return NULL;
...


In Python3.0 this also works, but in Python3.1 I get the following
error:
TypeError: argument 1 must be a byte string of length 1, not str

and I seem to be supposed to writeinstead. From the Python C API, I have not been able to explain this
new behavior.
What is the correct way to pass a single character argument to
Python3.1
extension modules?
 
J

Joachim Dahl

Obviously the name of the C function and the char variable cannot both
be foo,
so the C code should be:

static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
char foochar;
char *kwlist[] = {"foochar", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist,
&foochar))
return NULL;
...


The question remains the same: why can't I pass a single character
argument to this function under Python3.1?

Thanks.
Joachim

I am updating an extension module from Python2.6 to Python3.

I used to pass character codes to the extension module, for example, I
would write:

with the corresponding C extension routine defined as follows:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foo;
  char *kwlist[] = {"foo", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist, &foo))
    return NULL;
  ...

In Python3.0 this also works, but in Python3.1 I get the following
error:
TypeError: argument 1 must be a byte string of length 1, not str

and I seem to be supposed to write>>> foo(b'X')

instead. From the Python C API, I have not been able to explain this
new behavior.
What is the correct way to pass a single character argument to
Python3.1
extension modules?
 
C

casevh

Obviously the name of the C function and the char variable cannot both
be foo,
so the C code should be:

static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foochar;
  char *kwlist[] = {"foochar", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist,
&foochar))
    return NULL;
  ...

The question remains the same: why can't I pass a single character
argument to this function under Python3.1?

Thanks.
Joachim

I am updating an extension module from Python2.6 to Python3.
I used to pass character codes to the extension module, for example, I
would write:
with the corresponding C extension routine defined as follows:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foo;
  char *kwlist[] = {"foo", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist, &foo))
    return NULL;
  ...
In Python3.0 this also works, but in Python3.1 I get the following
error:
TypeError: argument 1 must be a byte string of length 1, not str
and I seem to be supposed to write>>> foo(b'X')
instead. From the Python C API, I have not been able to explain this
new behavior.
What is the correct way to pass a single character argument to
Python3.1
extension modules?- Hide quoted text -

- Show quoted text -

Python 3.1 uses "c" (lowercase c) to parse a single character from a
byte-string and uses "C" (uppercase c) to parse a single character
from a Unicode string. I don't think there is an easy way to accept a
character from both.

HTH,

casevh
 
J

Joachim Dahl

I think that "C" encoding is what I need, however I run into an odd
problem.
If I use the following C code

static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
char a, b;
char *kwlist[] = {"a", "b", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwrds, "|CC", kwlist, &a,
&b))
return NULL;
...

then the following works:
but the following fails:RuntimeError: impossible<bad format char>: 'CC'

Is this error-message expected?

Obviously the name of the C function and the char variable cannot both
be foo,
so the C code should be:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foochar;
  char *kwlist[] = {"foochar", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist,
&foochar))
    return NULL;
  ...
The question remains the same: why can't I pass a single character
argument to this function under Python3.1?
Thanks.
Joachim

I am updating an extension module from Python2.6 to Python3.
I used to pass character codes to the extension module, for example, I
would write:
foo('X')
with the corresponding C extension routine defined as follows:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foo;
  char *kwlist[] = {"foo", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist, &foo))
    return NULL;
  ...
In Python3.0 this also works, but in Python3.1 I get the following
error:
TypeError: argument 1 must be a byte string of length 1, not str
and I seem to be supposed to write>>> foo(b'X')
instead. From the Python C API, I have not been able to explain this
new behavior.
What is the correct way to pass a single character argument to
Python3.1
extension modules?- Hide quoted text -
- Show quoted text -

Python 3.1 uses "c" (lowercase c) to parse a single character from a
byte-string and uses "C" (uppercase c) to parse a single character
from a Unicode string. I don't think there is an easy way to accept a
character from both.

HTH,

casevh
 
C

casevh

I think that "C" encoding is what I need, however I run into an odd
problem.
If I use the following C code

static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char a, b;
  char *kwlist[] = {"a", "b", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "|CC", kwlist, &a,
&b))
    return NULL;
  ...

then the following works:

but the following fails:>>> foo(b='b')

RuntimeError: impossible<bad format char>: 'CC'

Is this error-message expected?

Nope. It appears to be a bug in Python. The format code 'C' is missing
in the switch statement in skipitem() in getargs.c. I added "case
'C': /* int */" after "case 'c': /* char */" and then example worked
for me.

I'll open a bug report.

casevh
Obviously the name of the C function and the char variable cannot both
be foo,
so the C code should be:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foochar;
  char *kwlist[] = {"foochar", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist,
&foochar))
    return NULL;
  ...
The question remains the same: why can't I pass a single character
argument to this function under Python3.1?
Thanks.
Joachim
I am updating an extension module from Python2.6 to Python3.
I used to pass character codes to the extension module, for example, I
would write:
foo('X')
with the corresponding C extension routine defined as follows:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foo;
  char *kwlist[] = {"foo", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist, &foo))
    return NULL;
  ...
In Python3.0 this also works, but in Python3.1 I get the following
error:
TypeError: argument 1 must be a byte string of length 1, not str
and I seem to be supposed to write>>> foo(b'X')
instead. From the Python C API, I have not been able to explain this
new behavior.
What is the correct way to pass a single character argument to
Python3.1
extension modules?- Hide quoted text -
- Show quoted text -
Python 3.1 uses "c" (lowercase c) to parse a single character from a
byte-string and uses "C" (uppercase c) to parse a single character
from a Unicode string. I don't think there is an easy way to accept a
character from both.

casevh
 
J

Joachim Dahl

thanks - the patch fixed my problem.

Joachim

I think that "C" encoding is what I need, however I run into an odd
problem.
If I use the following C code
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char a, b;
  char *kwlist[] = {"a", "b", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "|CC", kwlist, &a,
&b))
    return NULL;
  ...
then the following works:

but the following fails:>>> foo(b='b')
RuntimeError: impossible<bad format char>: 'CC'
Is this error-message expected?

Nope. It appears to be a bug in Python. The format code 'C' is missing
in the switch statement in skipitem() in getargs.c. I added "case
'C': /* int */" after "case 'c': /* char */" and then example worked
for me.

I'll open a bug report.

casevh




Obviously the name of the C function and the char variable cannot both
be foo,
so the C code should be:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foochar;
  char *kwlist[] = {"foochar", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist,
&foochar))
    return NULL;
  ...
The question remains the same: why can't I pass a single character
argument to this function under Python3.1?
Thanks.
Joachim
I am updating an extension module from Python2.6 to Python3.
I used to pass character codes to the extension module, for example, I
would write:
foo('X')
with the corresponding C extension routine defined as follows:
static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
  char foo;
  char *kwlist[] = {"foo", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwrds, "c", kwlist, &foo))
    return NULL;
  ...
In Python3.0 this also works, but in Python3.1 I get the following
error:
TypeError: argument 1 must be a byte string of length 1, not str
and I seem to be supposed to write>>> foo(b'X')
instead. From the Python C API, I have not been able to explain this
new behavior.
What is the correct way to pass a single character argument to
Python3.1
extension modules?- Hide quoted text -
- Show quoted text -
Python 3.1 uses "c" (lowercase c) to parse a single character from a
byte-string and uses "C" (uppercase c) to parse a single character
from a Unicode string. I don't think there is an easy way to accept a
character from both.
HTH,
casevh
 
J

Joachim Dahl

In the Ubuntu 9.10 version of Python 3.1 (using your patch), there's a
related bug:

will set the value of a in the extension module to zero, thus clearing
whatever
default value it may have had. In other words, the optional character
arguments
that are skipped seem to be nulled by PyArg_ParseTupleAndKeywords().
 
C

casevh

In the Ubuntu 9.10 version of Python 3.1 (using your patch), there's a
related bug:


will set the value of a in the extension module to zero, thus clearing
whatever
default value it may have had.  In other words, the optional character
arguments
that are skipped seem to be nulled by PyArg_ParseTupleAndKeywords().

The following code seems to work fine for me:

static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
int a=65, b=66;
char *kwlist[] = {"a", "b", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwrds, "|CC", kwlist, &a,
&b))
return NULL;
return Py_BuildValue("(CC)", a, b);
}

The default values seem to remain as 'A' and 'B'.

casevh
 
C

Case Vanhorsen

Case,
Thanks so much! However, I am still confused. This is what I understood;
foo (a = "a", b = "b") so function , foo,  has default values which are "a"
and "b". pointer kwlist[] is a way of specifying default values .
Regards,
Emeka
kwlist just specifies the names. The default values are specified by
"int a=65, b=66;". 65 is equivalent to 'A' and 66 is equivalent to
'B'.

casevh
   char *kwlist[] = {"a", "b", NULL};
   if (!PyArg_ParseTupleAndKeywords(args, kwrds, "|CC", kwlist, &a,
&b))
I am yet to understand what pointer kwlist[] does and why it is needed?
Regards,
Emeka

foo is designed to accept two arguments that can be specified by
either position or name. kwlist contains the legal keyword names. In
this example, the legal keywords are 'a' and 'b'. That they match the
names of the C variables is just a lucky coincidence. If you want to
change the keyword names to 'foo' and 'bar', you would just use char
*kwlist[]={"foo", "bar", NULL}.

casevh
In the Ubuntu 9.10 version of Python 3.1 (using your patch), there's
a
related bug:

foo(b='b')

will set the value of a in the extension module to zero, thus
clearing
whatever
default value it may have had.  In other words, the optional
character
arguments
that are skipped seem to be nulled by PyArg_ParseTupleAndKeywords()..

The following code seems to work fine for me:

static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
   int a=65, b=66;
   char *kwlist[] = {"a", "b", NULL};
   if (!PyArg_ParseTupleAndKeywords(args, kwrds, "|CC", kwlist, &a,
&b))
       return NULL;
   return Py_BuildValue("(CC)", a, b);
}

The default values seem to remain as 'A' and 'B'.

foo()
('A', 'B')
foo(b='b')
('A', 'b')
foo()
('A', 'B')
foo('a')
('a', 'B')
foo('a', b='b')
('a', 'b')
foo()
('A', 'B')


casevh
 
J

Joachim Dahl

My mistake seems to be that I declared

char a, b;

instead of

int a, b;

Thank you for sorting this out.

Joachim
 
G

Gabriel Genellina

Okay if that is the case, why do we need it? By having int a = 65, b =
66 ,
why should we also have *kwlist[]?



static PyObject* foo(PyObject *self, PyObject *args, PyObject *kwrds)
{
int a=65, b=66;
char *kwlist[] = {"a", "b", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwrds, "|CC", kwlist, &a,
&b))
return NULL;
return Py_BuildValue("(CC)", a, b);
}

It's not related to default values. foo(x=30) should raise an error; the
allowed parameter names are only 'a' and 'b', not 'x'.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,835
Latest member
lila30

Latest Threads

Top