[GRASS-dev] RE: [GRASS-user] Question with Python-SWIG example [SEC=UNCLASSIFIED]

Andrew MacIntyre wrote:

From the SWIG examples I inferred the following type references for
the pointers in question:

CELL* => SWIGTYPE_p_CELL
FCELL* => SWIGTYPE_p_FCELL
DCELL* => SWIGTYPE_p_DCELL

provided that CELL*/FCELL*/DCELL* are typedef'ed.

So I expected that in pyobj_to_ptr() you could do something like

But I still don't see what happens when a function returns a CELL*
which is subsequently passed to a function accepting a void*, or
vice-versa. This is common enough that if SWIG can't handle it, we
need to use something other than SWIG.

But, to be honest, even if SWIG can handle it, I'd prefer something
which generates pure Python wrappers.

> I think that I'm not going to put any more effort into the SWIG
> wrapper unless usable documentation materialises. In the meantime, I'm
> going to look for alternatives.

If you decide to investigate using ctypes, the following links might be
of interest:

- http://starship.python.net/crew/theller/ctypes/old/codegen.html

AFAICT, this has been superseded by ctypeslib:

  http://pypi.python.org/pypi/ctypeslib/

- http://www.language-binding.net/pygccxml/pygccxml.html

I wasn't aware of this one.

I also found ctypesgen:

  http://code.google.com/p/ctypesgen/

--
Glynn Clements <glynn@gclements.plus.com>

Glynn Clements wrote:

I also found ctypesgen:

  http://code.google.com/p/ctypesgen/

I finally got around to looking at this, and it took less than half an
hour to generate working bindings. Obviously, it will need more
testing, but unless any insurmountable problems show up, I intend to
using this in place of SWIG.

Usage is similar to the example posted earlier, except:

1. The library doesn't need to be loaded manually; this is handled by
the wrapper.

2. The GIS_H_VERSION and G_gisinit() macros are wrapped, so you can
just use e.g. "grass.G_gisinit(sys.argv[0])" rather than needing to
extract the version for G__gisinit().

3. The CELL/FCELL/DCELL types are wrapped, so those can be
used instead of c_int, c_float, c_double.

4. The {CELL,FCELL,DCELL}_TYPE constants are wrapped, so those can be
used instead of 0, 1, 2.

The example script is attached.

The wrappers should be largely compatible with those generated by
SWIG, but without the headaches. The automatic type conversions are no
longer there, but converting manually with ctypes is easy enough.
Also, I've discovered that NumPy arrays have conversion methods, e.g.

    p = buf.ctypes.data_as(POINTER(raster.CELL))

One caveat: this *doesn't* appear to increment the reference count, so
if you do e.g.:

    buf = buf.ctypes.data_as(POINTER(raster.CELL))

the array will be gc'd resulting in buf pointing at garbage.

I've already replaced the SWIG bindings in 7.0 with the ctypesgen
version.

Ideally, I'd like to do the same in 6.x in time for 6.4.0, so that we
can forget that the SWIG version ever existed. The main issue there is
the vdigit and nviz modules in the wxPython GUI (which don't work on
Windows in any case). I haven't tried using ctypesgen for C++, though.

--
Glynn Clements <glynn@gclements.plus.com>

(attachments)

example7.py (808 Bytes)

Hi,

2010/5/16 Glynn Clements <glynn@gclements.plus.com>:

[...]

Ideally, I'd like to do the same in 6.x in time for 6.4.0, so that we
can forget that the SWIG version ever existed. The main issue there is
the vdigit and nviz modules in the wxPython GUI (which don't work on
Windows in any case). I haven't tried using ctypesgen for C++, though.

+1

BTW, compiling SWIG in trunk

ctypesgen.py -I/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/include
-I/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/include
-L/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/lib
-L/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/lib
-lgrass_datetime
/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/include/grass/datetime.h
/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/include/grass/P_datetime.h
-o date.py
make[2]: ctypesgen.py: Command not found
make[2]: *** [date.py] Error 127
make[2]: Leaving directory `/usr/local/src/grass_trunk/lib/python/ctypes'
make[1]: *** [default] Error 2
make[1]: Leaving directory `/usr/local/src/grass_trunk/lib/python/ctypes'
make: *** [default] Error 2

Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Martin Landa wrote:

> Ideally, I'd like to do the same in 6.x in time for 6.4.0, so that we
> can forget that the SWIG version ever existed. The main issue there is
> the vdigit and nviz modules in the wxPython GUI (which don't work on
> Windows in any case). I haven't tried using ctypesgen for C++, though.

+1

BTW, compiling SWIG in trunk

ctypesgen.py -I/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/include
-I/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/include
-L/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/lib
-L/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/lib
-lgrass_datetime
/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/include/grass/datetime.h
/usr/local/src/grass_trunk/dist.i686-pc-linux-gnu/include/grass/P_datetime.h
-o date.py
make[2]: ctypesgen.py: Command not found
make[2]: *** [date.py] Error 127
make[2]: Leaving directory `/usr/local/src/grass_trunk/lib/python/ctypes'
make[1]: *** [default] Error 2
make[1]: Leaving directory `/usr/local/src/grass_trunk/lib/python/ctypes'
make: *** [default] Error 2

Building the swig directory is a no-op (the SUBDIRS list is empty).
The above comes from building lib/python. I'll modify it to ignore
errors when building the ctypes subdirectory.

ctypesgen can be obtained via SVN:

svn checkout http://ctypesgen.googlecode.com/svn/trunk/ ctypesgen-read-only

or you can get a tarball from:

http://mirrors.kernel.org/gentoo/distfiles/ctypesgen-0_p72.tar.bz2

To build:

  python setup.py build install

Although it's probably not as widespread as SWIG, it has the advantage
that both ctypesgen itself and the wrappers which it generates are
pure Python code, with no binary components.

I'm also going to look at ctypeslib:

  http://pypi.python.org/pypi/ctypeslib/

I went with ctypesgen first as there's a supported Gentoo package for
it.

--
Glynn Clements <glynn@gclements.plus.com>

Glynn Clements wrote:

Building the swig directory is a no-op (the SUBDIRS list is empty).
The above comes from building lib/python. I'll modify it to ignore
errors when building the ctypes subdirectory.

Done; also, the configure script checks for ctypesgen (not finding it
is a warning rather than an error).

In r42275, I've replaced the binary wxGUI NVIZ module with a Python
version; it seems to be working, although it needs more testing.

Unfortunately, doing the same for the vdigit module would be somewhat
harder, due to the level of integration between the vdigit module and
wxPython (which is heavily SWIG/C++ based), and less useful (there
would still be a C++ component using wxWidgets).

--
Glynn Clements <glynn@gclements.plus.com>

Hi,

2010/5/16 Glynn Clements <glynn@gclements.plus.com>:

I've already replaced the SWIG bindings in 7.0 with the ctypesgen
version.

trying ctypesgen version I have problem with G_find_raster2()

mapset = grass.G_find_raster2("elevation", "")
print mapset

WARNING: Illegal filename <�pT�>. Character <> not allowed.

Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Martin Landa wrote:

> I've already replaced the SWIG bindings in 7.0 with the ctypesgen
> version.

trying ctypesgen version I have problem with G_find_raster2()

mapset = grass.G_find_raster2("elevation", "")
print mapset

WARNING: Illegal filename <�pT�>. Character <> not allowed.

Odd. Can you try it under GDB and check what arguments
G_find_raster2() is getting?

Also, are you calling G_gisinit() first?

--
Glynn Clements <glynn@gclements.plus.com>

Hi,

2010/5/18 Glynn Clements <glynn@gclements.plus.com>:

Odd. Can you try it under GDB and check what arguments
G_find_raster2() is getting?

Also, are you calling G_gisinit() first?

sample script below

---
#!/usr/bin/env python
import os, sys
from grass.lib import grass, raster
from ctypes import *

input = sys.argv[1]

grass.G_gisinit(sys.argv[0])

mapset = grass.G_find_raster2(input, "")
print mapset
---

Running

python example.py elevation

I get

D1/5: G_find_raster2(): name=� ��� mapset=elevation
WARNING: Illegal filename <� ���>. Character <� not allowed.

Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Martin Landa wrote:

> Odd. Can you try it under GDB and check what arguments
> G_find_raster2() is getting?
>
> Also, are you calling G_gisinit() first?

sample script below

---
#!/usr/bin/env python
import os, sys
from grass.lib import grass, raster
from ctypes import *

input = sys.argv[1]

grass.G_gisinit(sys.argv[0])

mapset = grass.G_find_raster2(input, "")
print mapset
---

Running

python example.py elevation

I get

D1/5: G_find_raster2(): name=? ??? mapset=elevation
WARNING: Illegal filename <? ???>. Character <� not allowed.
?

The script works fine for me.

I'm assuming that you added the G_debug() statement, because there
isn't one at present.

What platform, Python version, ctypesgen version?

The G_find_raster2() definition should look like:

# /usr/local/src/grass/7.0/dist.i686-pc-linux-gnu/include/grass/gisdefs.h: 220
if hasattr(_libs['grass_gis'], 'G_find_raster2'):
    G_find_raster2 = _libs['grass_gis'].G_find_raster2
    G_find_raster2.restype = ReturnString
    G_find_raster2.argtypes = [String, String]

Does it work if you use ctypes manually, e.g.:

---
#!/usr/bin/env python
import os, sys
from grass.script import read_command
from ctypes import *
input = sys.argv[1]
grass = CDLL("libgrass_gis.so")
version = read_command("g.version", flags = "r").splitlines()[1].strip().split()[1]
grass.G__gisinit("$Revision: %s $" % version, sys.argv[0])
mapset = grass.G_find_raster2(input, "")
print c_char_p(mapset).value
---

--
Glynn Clements <glynn@gclements.plus.com>

Hi,

2010/5/18 Glynn Clements <glynn@gclements.plus.com>:

What platform, Python version, ctypesgen version?

Debian GNU/Linux unstable, x86-32
Python 2.5.5
ctypesgen from SVN

The G_find_raster2() definition should look like:

# /usr/local/src/grass/7.0/dist.i686-pc-linux-gnu/include/grass/gisdefs.h: 220
if hasattr(_libs['grass_gis'], 'G_find_raster2'):
G_find_raster2 = _libs['grass_gis'].G_find_raster2
G_find_raster2.restype = ReturnString
G_find_raster2.argtypes = [String, String]

I found

dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py: if
hasattr(_lib, 'G_find_raster2'):
dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py:
G_find_raster2 = _lib.G_find_raster2
dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py:
G_find_raster2.restype = String
dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py:
G_find_raster2.argtypes = [String, String]
dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py:
G_find_raster2.errcheck = ReturnString

Does it work if you use ctypes manually, e.g.:

yes, it works.

Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Martin Landa wrote:

2010/5/18 Glynn Clements <glynn@gclements.plus.com>:
> What platform, Python version, ctypesgen version?

Debian GNU/Linux unstable, x86-32
Python 2.5.5
ctypesgen from SVN

FWIW, I'm using Python 2.6.4. I've also checked with the latest SVN
version of ctypesgen, but haven't found any differences.

> The G_find_raster2() definition should look like:
>
> # /usr/local/src/grass/7.0/dist.i686-pc-linux-gnu/include/grass/gisdefs.h: 220
> if hasattr(_libs['grass_gis'], 'G_find_raster2'):
> G_find_raster2 = _libs['grass_gis'].G_find_raster2
> G_find_raster2.restype = ReturnString
> G_find_raster2.argtypes = [String, String]

I found

dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py: if
hasattr(_lib, 'G_find_raster2'):
dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py:
G_find_raster2 = _lib.G_find_raster2
dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py:
G_find_raster2.restype = String
dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py:
G_find_raster2.argtypes = [String, String]
dist.i686-pc-linux-gnu/etc/python/grass/lib/grass.py:
G_find_raster2.errcheck = ReturnString

Okay; I know why this (the code differences) is happening:

Hmm. From ctypesgencore/printer/printer.py:

    def print_fixed_function(self, function):
        self.srcinfo(function.src)
        if function.source_library:
            print >>self.file, "if hasattr(_libs[%r], %r):" % \
                (function.source_library,function.c_name())
            print >>self.file, " %s = _libs[%r].%s" % \
                (function.py_name(),function.source_library,function.c_name())
            print >>self.file, " %s.restype = %s" % \
                (function.py_name(),function.restype.py_string())
            print >>self.file, " %s.argtypes = [%s]" % (function.py_name(),
                ', '.join([a.py_string() for a in function.argtypes]))
        else:
            print >>self.file, "for _lib in _libs.values():"
            print >>self.file, " if hasattr(_lib, %r):" % function.c_name()
            print >>self.file, " %s = _lib.%s" % (function.py_name(),function.c_name())
            print >>self.file, " %s.restype = %s" % (function.py_name(),function.restype.py_string())
            print >>self.file, " %s.argtypes = [%s]" % (function.py_name(),
                ', '.join([a.py_string() for a in function.argtypes]))
            print >>self.file, " break"

I'm getting the first case, while you're getting the second.

The source_library field is only set if it manages to load the
library. I don't use GRASS "sessions"; I just set all of the
environment variables from my ~/.bash_profile, so GRASS commands work
everywhere.

This means that LD_LIBRARY_PATH includes $GISBASE/lib while I'm
building GRASS. If I unset LD_LIBRARY_PATH before building, I get the
second case.

This particular issue should be fixed by r42311. I don't know if this
is related to the problem, but it's something to eliminate.

--
Glynn Clements <glynn@gclements.plus.com>

Hi,

2010/5/19 Glynn Clements <glynn@gclements.plus.com>:

[...]

This particular issue should be fixed by r42311. I don't know if this
is related to the problem, but it's something to eliminate.

right, this issue is eliminated, anyway the reported problem still persists.

Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Martin Landa wrote:

> This particular issue should be fixed by r42311. I don't know if this
> is related to the problem, but it's something to eliminate.

right, this issue is eliminated, anyway the reported problem still persists.

The only other thing which I can suggest is to add print statements to
the functions in $GISBASE/etc/python/grass/lib/ctypesheader.py,
specifically String.__init__ and String.from_param.

--
Glynn Clements <glynn@gclements.plus.com>

Hi,

2010/5/19 Glynn Clements <glynn@gclements.plus.com>:

> This particular issue should be fixed by r42311. I don't know if this
> is related to the problem, but it's something to eliminate.

right, this issue is eliminated, anyway the reported problem still persists.

The only other thing which I can suggest is to add print statements to
the functions in $GISBASE/etc/python/grass/lib/ctypesheader.py,
specifically String.__init__ and String.from_param.

hm, seems to be OK

String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): /home/martin/smetiste/example7.py
String.__init__(): /home/martin/smetiste/example7.py
String.from_param(): elevation
String.__init__(): elevation
String.from_param():
String.__init__():
WARNING: Illegal filename <L�����>. Character <�> not allowed.
String.__init__(): String.from_param(): �
String.from_param(): �

Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Hi,

2010/5/20 Martin Landa <landa.martin@gmail.com>:

hm, seems to be OK

String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): /home/martin/smetiste/example7.py
String.__init__(): /home/martin/smetiste/example7.py
String.from_param(): elevation
String.__init__(): elevation
String.from_param():
String.__init__():
WARNING: Illegal filename <L�����>. Character <�> not allowed.
String.__init__(): String.from_param(): �
String.from_param(): �

I am building GRASS with

        CFLAGS="-g -Wall -Werror-implicit-function-declaration
-fno-common -Wextra -Wunused" \
      CXXFLAGS="-g -Wall" \
      ./configure --prefix=/usr/local \
      --with-tcltk-includes=/usr/include/tcl8.4
--with-tcltk-libs=/usr/lib/tcl8.4 \
      --with-postgres --with-postgres-includes=/usr/include/postgresql \
      --with-mysql --with-mysql-includes=/usr/include/mysql \
      --with-gdal=/usr/local/bin/gdal-config \
      --with-proj \
      --with-motif --with-glw --with-nls --with-readline \
      --with-cxx --enable-largefile \
      --with-freetype --with-freetype-includes=/usr/include/freetype2 \
      --with-sqlite --with-ffmpeg --with-ffmpeg-includes=/usr/include/ffmpeg/ \
      --with-odbc --with-python=/usr/bin/python2.5-config
--with-wxwidgets --with-pthread \
      --with-ffmpeg=no --with-geos=/usr/local/bin/geos-config --with-pthread

Probably it could help. Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Martin Landa wrote:

>> > This particular issue should be fixed by r42311. I don't know if this
>> > is related to the problem, but it's something to eliminate.
>>
>> right, this issue is eliminated, anyway the reported problem still persists.
>
> The only other thing which I can suggest is to add print statements to
> the functions in $GISBASE/etc/python/grass/lib/ctypesheader.py,
> specifically String.__init__ and String.from_param.

hm, seems to be OK

String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): /home/martin/smetiste/example7.py
String.__init__(): /home/martin/smetiste/example7.py
String.from_param(): elevation
String.__init__(): elevation
String.from_param():
String.__init__():
WARNING: Illegal filename <L�����>. Character <�> not allowed.
String.__init__(): String.from_param(): �
String.from_param(): �

This is what I get:

String.from_param('$Revision: 41297 $')
String.__init__('$Revision: 41297 $')
String.from_param('$Revision: 41297 $')
String.__init__('$Revision: 41297 $')
String.from_param('./foo.py')
String.__init__('./foo.py')
String.from_param('elevation.dem')
String.__init__('elevation.dem')
String.from_param('')
String.__init__('')
ReturnString(168559720)
String.from_param(168559720)
String.__init__(<ctypes.LP_c_char object at 0xb7d1e6ec>)
PERMANENT

Does this work:
  ...
  c_input = c_char_p(input)
  c_mapset = c_char_p("")
  mapset = grass.G_find_raster2(c_input, c_mapset)
  ...
?

Or this:
  ...
  grass.G_find_raster2.argtypes = [c_char_p, c_char_p]
  grass.G_find_raster2.restype = c_char_p
  mapset = grass.G_find_raster2(c_input, c_mapset)
  ...
?

The most common issue with ctypes, and the most likely reason why the
underlying function would end up getting garbage data, is that the
ctypes pointer types don't hold a reference to the underlying object,
which can result in it being garbage collected while it is still being
used.

This is mostly an issue when calling functions which store any pointer
arguments, as the pointer may cease to be valid once the function
returns.

This shouldn't be an issue for G_find_raster2() itself, so I suspect
that ctypesgen's String wrapper is passing a pointer to a temporary
value which is being reclaimed before the function is called.

--
Glynn Clements <glynn@gclements.plus.com>

Hi,

2010/5/20 Glynn Clements <glynn@gclements.plus.com>:

[...]

Does this work:
...
c_input = c_char_p(input)
c_mapset = c_char_p("")
mapset = grass.G_find_raster2(c_input, c_mapset)
...

No,

String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): /home/martin/smetiste/example7.py
String.__init__(): /home/martin/smetiste/example7.py
Traceback (most recent call last):
  File "/home/martin/smetiste/example7.py", line 10, in <module>
    mapset = grass.G_find_raster2(c_input, c_mapset)
ctypes.ArgumentError: argument 1: <type 'exceptions.TypeError'>:
cannot concatenate 'str' and 'c_char_p' objects

Or this:
...
grass.G_find_raster2.argtypes = [c_char_p, c_char_p]
grass.G_find_raster2.restype = c_char_p
mapset = grass.G_find_raster2(c_input, c_mapset)

Yes, it's working.

The most common issue with ctypes, and the most likely reason why the
underlying function would end up getting garbage data, is that the
ctypes pointer types don't hold a reference to the underlying object,
which can result in it being garbage collected while it is still being
used.

Yes, it's seems to be a ctypes issue.

Thanks, Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Martin Landa wrote:

> Does this work:
> ...
> c_input = c_char_p(input)
> c_mapset = c_char_p("")
> mapset = grass.G_find_raster2(c_input, c_mapset)
> ...

No,

String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): /home/martin/smetiste/example7.py
String.__init__(): /home/martin/smetiste/example7.py
Traceback (most recent call last):
  File "/home/martin/smetiste/example7.py", line 10, in <module>
    mapset = grass.G_find_raster2(c_input, c_mapset)
ctypes.ArgumentError: argument 1: <type 'exceptions.TypeError'>:
cannot concatenate 'str' and 'c_char_p' objects

That error is coming from your debugging statements; you're probably
doing something like:

  print "String.from_param(): " + obj

Using:

  print "String.from_param(): %s" % obj
or:
  print "String.from_param():" + str(obj)

should work.

> Or this:
> ...
> grass.G_find_raster2.argtypes = [c_char_p, c_char_p]
> grass.G_find_raster2.restype = c_char_p
> mapset = grass.G_find_raster2(c_input, c_mapset)

Yes, it's working.

> The most common issue with ctypes, and the most likely reason why the
> underlying function would end up getting garbage data, is that the
> ctypes pointer types don't hold a reference to the underlying object,
> which can result in it being garbage collected while it is still being
> used.

Yes, it's seems to be a ctypes issue.

Well, the "manual" ctypes version worked earlier, so it appears to be
a problem with the wrappers. The preamble's String type looks
unnecessarily complex; there's probably a reason, but I have doubts as
to whether the benefits outweight the drawbacks.

Can you try r42331? This eliminates most of the preamble, making
String and ReturnString aliases for c_char_p. If there's a need for
something more complex, I'll deal with that if and when it happens.

--
Glynn Clements <glynn@gclements.plus.com>

Hi,

2010/5/21 Glynn Clements <glynn@gclements.plus.com>:

> c_input = c_char_p(input)
> c_mapset = c_char_p("")
> mapset = grass.G_find_raster2(c_input, c_mapset)

[...]

That error is coming from your debugging statements; you're probably
doing something like:

   print &quot;String\.from\_param\(\): &quot; \+ obj

Using:

   print &quot;String\.from\_param\(\): %s&quot; % obj

or:
print "String.from_param():" + str(obj)

should work.

right, sorry for the mess. I am getting

ring.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): $Revision: 41297 $
String.__init__(): $Revision: 41297 $
String.from_param(): example7.py
String.__init__(): example7.py
String.from_param(): c_char_p(3077260516)
String.from_param(): c_char_p(3077423276)
WARNING: Illegal filename <
                           �
         �j�>. Character <
                          > not allowed.
String.from_param(): �

Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa

Hi,

2010/5/21 Glynn Clements <glynn@gclements.plus.com>:

[...]

Yes, it's seems to be a ctypes issue.

Well, the "manual" ctypes version worked earlier, so it appears to be
a problem with the wrappers. The preamble's String type looks
unnecessarily complex; there's probably a reason, but I have doubts as
to whether the benefits outweight the drawbacks.

Can you try r42331? This eliminates most of the preamble, making
String and ReturnString aliases for c_char_p. If there's a need for
something more complex, I'll deal with that if and when it happens.

Sample script:

#!/usr/bin/env python
import os, sys
from grass.lib import grass
from ctypes import *

grass.G_gisinit(sys.argv[0])

mapset = grass.G_find_raster2("elevation", "")
print mapset

Result:

Traceback (most recent call last):
  File "/home/martin/smetiste/example7.py", line 8, in <module>
    mapset = grass.G_find_raster2("elevation", "")
TypeError: __init__ expected at most 1 arguments, got 3

Martin

--
Martin Landa <landa.martin gmail.com> * http://gama.fsv.cvut.cz/~landa