Merge lp:~spud/spud/c-python-binding into lp:spud

Proposed by Patrick Farrell
Status: Merged
Approved by: Cian Wilson
Approved revision: 452
Merged at revision: 448
Proposed branch: lp:~spud/spud/c-python-binding
Merge into: lp:spud
Diff against target: 1163 lines (+964/-56)
10 files modified
Makefile.in (+11/-3)
configure (+1/-2)
configure.in (+0/-1)
debian/control (+12/-0)
debian/diamond.copyright (+0/-1)
debian/python-spud.copyright (+39/-0)
debian/rules (+5/-2)
python/libspud.c (+831/-0)
python/setup.py (+9/-0)
python/test_libspud.py (+56/-47)
To merge this branch: bzr merge lp:~spud/spud/c-python-binding
Reviewer Review Type Date Requested Status
Cian Wilson Approve
Patrick Farrell Needs Fixing
Review via email: mp+70000@code.launchpad.net

Description of the change

This branch changes the default Python binding for libspud from python/ctypes to the C api.

The reason for this change is that the C api can do things that python/ctypes can't. In particular, it can access capsules that have been registered through the C api somewhere else. This functionality is exploited with a special case for when this module is ran inside of fluidity's python diagnostics: with a bit of void* shuffling, we can now use this C module to access fluidity's spud tree inside Python.

The first step was to convert the Python wrapper test into something executable. Then, the C module was extended incrementally until it passed all of the tests. So I think that the C module shouldn't make any difference to people who are using the libspud python bindings.

Cian Wilson: while this C module has a very small chunk that is fluidity specific, it is orthogonal to the rest of the code. From your perspective, this commit should (ideally) make no change whatsoever.

The C module was largely written by Nan Mao.

To post a comment you must log in.
lp:~spud/spud/c-python-binding updated
447. By Patrick Farrell

Get rid of a malloc that didn't have a corresponding free

Revision history for this message
Cian Wilson (cwilson) wrote :

Where is the libspud module meant to be imported from now?

cwilson@uisce:python$ pwd
/home/cwilson/spud/bzr-repo/c-python-binding/python

cwilson@uisce:python$ echo $PYTHONPATH
/home/cwilson/spud/bzr-repo/c-python-binding/python

cwilson@uisce:python$ python test_libspud.py
Traceback (most recent call last):
  File "test_libspud.py", line 1, in <module>
    import libspud
ImportError: No module named libspud

review: Needs Information
Revision history for this message
Patrick Farrell (pefarrell) wrote :

Ah, apologies, I agree it isn't obvious.

The way I was testing it was

python setup.py build
ln -s build/lib*/libspud.so
python test_libspud.py

I didn't add code to install the python bindings because there was no code to install the old ctypes bindings, either. But perhaps I should make a python-spud package too ...

review: Needs Fixing
Revision history for this message
Cian Wilson (cwilson) wrote :

A python-spud package would be *very* useful indeed.

Can I ask you to explain the fluidity_api PyCapsule import to me? I can't find anything called fluidity_api in fluidity or in spud so I'm guessing I'm misunderstanding what this is doing. Is this really fluidity specific or could it be used in any model with embedded python? Within fluidity itself does this allow libspud to be used in both python state and the more traditional def val calls?

Revision history for this message
Patrick Farrell (pefarrell) wrote :

I will make a python-spud package later, then.

Sure. Capsules are an idea introduced in python 3.1/2.7; there's more information about them in the "What's New" for 2.7. The basic idea is that a capsule contains a void* pointer, and you can register them to store them in a module. It's a mechanism for passing data between different C modules that interact with python; it's a way of passing stuff C -> Python -> different C again.

You can see how I plan to use them in the merge request for get-set-manager:
https://code.launchpad.net/~spud/spud/get-set-manager/+merge/69652

As this whole setup involves changes to libspud, to the python bindings, and to fluidity, I thought I would do them in a logical order. That's why you can't see the corresponding calls for setting PyCapsules in fluidity; it's not in the trunk yet. But you can take a look at
http://bazaar.launchpad.net/~pefarrell/fluidity/diagnostic-python-spud/view/head:/femtools/python_statec.c
to see the other half.

As for its fluidity-specific nature: the whole idea is not specific to fluidity. So we could make it the python-spud convention that you have to register a void* to the manager at "spud_api._spud_manager" instead of "fluidity_api._spud_manager", if you like.

Yes, this means that libspud can be used both in the python state and the def val calls. The fluidity side of it happens in python_init, which is called at the start of the model setup and works for both.

lp:~spud/spud/c-python-binding updated
448. By Patrick Farrell

Make a python-spud Debian package.

Revision history for this message
Patrick Farrell (pefarrell) wrote :

I've made a Debian package of the Python bindings, python-spud.

Revision history for this message
Cian Wilson (cwilson) wrote :

Thanks for the python package. Surprisingly /usr/lib/python2.7/site-packages doesn't appear to be searched automatically by python so I couldn't find it at first but happily all of my tests run with it now I've added it to my PYTHONPATH.

My preference would be to have a more general spud_api for two reasons:
 - my traditional abhorrence of anything fluidity, however small, being in spud, particularly if it would be useful to other programs
 - I have python instances in my code too so this functionality would be useful if it were more generally available

If this is reasonably easily doable then I'd be happier.

lp:~spud/spud/c-python-binding updated
449. By Patrick Farrell

Fix the python-spud package; thanks Cian.

450. By Patrick Farrell

s/fluidity_api/spud_manager

Revision history for this message
Patrick Farrell (pefarrell) wrote :

Excellent, I'm glad that the C python module passes all of your tests.

You pointed out a flaw in the Debian packaging of python-spud; I needed to add an --install-layout=deb to the setup.py install command, and to call the dh_python2 helper during the debian package creation.

I've also changed the "fluidity_api". Now, model code that wants to expose its internal manager should encapsulate it and set it as "spud_manager._spud_manager".

Revision history for this message
Cian Wilson (cwilson) wrote :

Um, the package no longer seems to install /usr/lib/python2.7/site-packages/libspud.so. Is this expected and if so where should I be looking now? The only install path that appears in the debian/python-spud directory is usr/share/doc/python-spud/

Thanks for generalising the api. I look forward to using this in my other code.

Revision history for this message
Patrick Farrell (pefarrell) wrote :

Yes, site-packages is the wrong place to put it (according to Debian). If you take a look at

dpkg -c ../python-spud_1.1.3_amd64.deb

it tells you the contents of the package:

drwxr-xr-x root/root 0 2011-08-04 18:18 ./
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/lib/
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/lib/python2.6/
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/lib/python2.6/dist-packages/
-rw-r--r-- root/root 23120 2011-08-04 18:18 ./usr/lib/python2.6/dist-packages/libspud.so
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/lib/pyshared/
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/lib/pyshared/python2.6/
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/share/
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/share/pyshared/
-rw-r--r-- root/root 201 2011-08-04 18:18 ./usr/share/pyshared/libspud-1.1.3.egg-info
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/share/doc/
drwxr-xr-x root/root 0 2011-08-04 18:18 ./usr/share/doc/python-spud/
-rw-r--r-- root/root 1656 2011-08-03 11:41 ./usr/share/doc/python-spud/copyright
-rw-r--r-- root/root 2498 2011-07-29 11:33 ./usr/share/doc/python-spud/changelog.gz
lrwxrwxrwx root/root 0 2011-08-04 18:18 ./usr/lib/python2.6/dist-packages/libspud-1.1.3.egg-info -> ../../../share/pyshared/libspud-1.1.3.egg-info
lrwxrwxrwx root/root 0 2011-08-04 18:18 ./usr/lib/pyshared/python2.6/libspud.so -> ../../python2.6/dist-packages/libspud.so

If you install it and ask Python where it's getting it, it replies:

[pef@caoimhe:/data/pfarrell/src]$ python -v -c "import libspud" 2>&1 | grep libspud
dlopen("/usr/lib/python2.6/dist-packages/libspud.so", 2);
import libspud # dynamically loaded from /usr/lib/python2.6/dist-packages/libspud.so

Revision history for this message
Cian Wilson (cwilson) wrote :

I get:

cwilson@uisce:c-python-binding$ dpkg -c ../python-spud_1.1.3_amd64.deb
drwxr-xr-x root/root 0 2011-08-04 11:10 ./
drwxr-xr-x root/root 0 2011-08-04 11:10 ./usr/
drwxr-xr-x root/root 0 2011-08-04 11:10 ./usr/share/
drwxr-xr-x root/root 0 2011-08-04 11:10 ./usr/share/doc/
drwxr-xr-x root/root 0 2011-08-04 11:10 ./usr/share/doc/python-spud/
-rw-r--r-- root/root 1656 2011-08-03 09:02 ./usr/share/doc/python-spud/copyright
-rw-r--r-- root/root 2498 2011-08-01 14:56 ./usr/share/doc/python-spud/changelog.gz

and nothing else (I would expect the paths to be slightly different for me as I'm on python 2.7).

Just to be clear, what I've done in the branch is:
./configure && make clean && make && debuild -uc -us
some of which are probably superfluous but I was trying to be thorough.

lp:~spud/spud/c-python-binding updated
451. By Patrick Farrell

Some more work on python-spud for natty

452. By Patrick Farrell

A grand game of whack-a-mole. This fixes the maverick build. We'll keep iterating until they all work ...

Revision history for this message
Patrick Farrell (pefarrell) wrote :

You only need to debuild: it calls the configure and make.

It should be fixed now. There were a few problems with the natty build. I've also made it so that the package now supplies libspud bindings for all supported python versions (2.6 and 2.7 on maverick and natty).

[pef@doodson:/tmp/c-python-binding]$ dpkg -c ../python-spud_1.1.3_amd64.deb
drwxr-xr-x root/root 0 2011-08-04 22:32 ./
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/share/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/share/pyshared/
-rw-r--r-- root/root 201 2011-08-04 22:32 ./usr/share/pyshared/libspud-1.1.3.egg-info
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/share/doc/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/share/doc/python-spud/
-rw-r--r-- root/root 2498 2011-08-04 22:04 ./usr/share/doc/python-spud/changelog.gz
-rw-r--r-- root/root 1656 2011-08-04 22:04 ./usr/share/doc/python-spud/copyright
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/lib/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/lib/pyshared/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/lib/pyshared/python2.6/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/lib/pyshared/python2.7/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/lib/python2.6/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/lib/python2.6/dist-packages/
-rw-r--r-- root/root 23120 2011-08-04 22:32 ./usr/lib/python2.6/dist-packages/libspud.so
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/lib/python2.7/
drwxr-xr-x root/root 0 2011-08-04 22:32 ./usr/lib/python2.7/dist-packages/
-rw-r--r-- root/root 23120 2011-08-04 22:32 ./usr/lib/python2.7/dist-packages/libspud.so
lrwxrwxrwx root/root 0 2011-08-04 22:32 ./usr/lib/pyshared/python2.6/libspud.so -> ../../python2.6/dist-packages/libspud.so
lrwxrwxrwx root/root 0 2011-08-04 22:32 ./usr/lib/pyshared/python2.7/libspud.so -> ../../python2.7/dist-packages/libspud.so
lrwxrwxrwx root/root 0 2011-08-04 22:32 ./usr/lib/python2.6/dist-packages/libspud-1.1.3.egg-info -> ../../../share/pyshared/libspud-1.1.3.egg-info
lrwxrwxrwx root/root 0 2011-08-04 22:32 ./usr/lib/python2.7/dist-packages/libspud-1.1.3.egg-info -> ../../../share/pyshared/libspud-1.1.3.egg-info

Revision history for this message
Cian Wilson (cwilson) wrote :

Thanks Patrick. That works for me now and I've run it manually (and successfully) through my tests again.

Shame about lucid, which is what my buildbot is on (hence the manual bit). Out of curiosity, how were python packages built before dh_python2? I'm guessing upgrading that computer will be easier than backporting.

review: Approve
Revision history for this message
Patrick Farrell (pefarrell) wrote :

It could have been dh_python, dh_pycentral or dh_pysupport. dh_python2 supplanted them all. You could try one of those? (I don't have a lucid machine to try it out on.)

In the mean time, I'll merge!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile.in'
--- Makefile.in 2011-07-11 15:25:35 +0000
+++ Makefile.in 2011-08-04 21:32:37 +0000
@@ -57,7 +57,7 @@
57libspud.la: $(OBJS)57libspud.la: $(OBJS)
58 ./libtool --mode=link --tag=FC $(FC) $(FCFLAGS) -o $(LIB) $(OBJS) $(LIBS) -rpath @prefix@/lib 58 ./libtool --mode=link --tag=FC $(FC) $(FCFLAGS) -o $(LIB) $(OBJS) $(LIBS) -rpath @prefix@/lib
59 if test -f .libs/libspud.a; then cp .libs/libspud.a .; fi59 if test -f .libs/libspud.a; then cp .libs/libspud.a .; fi
60 (if test -f .libs/libspud.so; then cp .libs/libspud.so .; fi) || true60 (if test -f .libs/libspud.so; then cp .libs/libspud.so ./libspud.so.0; ln -s libspud.so.0 libspud.so; fi) || true
6161
62build-diamond:62build-diamond:
63 cd diamond; python setup.py build; cd ..63 cd diamond; python setup.py build; cd ..
@@ -72,13 +72,14 @@
72doc: 72doc:
73 @cd doc; $(MAKE) spud_manual.pdf73 @cd doc; $(MAKE) spud_manual.pdf
7474
75install: install-libspud install-spudtools install-diamond75install: install-libspud install-spudtools install-diamond install-pyspud
7676
77install-libspud: libspud.la77install-libspud: libspud.la
78 @INSTALL@ -d $(DESTDIR)@prefix@/lib78 @INSTALL@ -d $(DESTDIR)@prefix@/lib
79 @INSTALL@ -d $(DESTDIR)@prefix@/include79 @INSTALL@ -d $(DESTDIR)@prefix@/include
80 @INSTALL@ libspud.a $(DESTDIR)@prefix@/lib80 @INSTALL@ libspud.a $(DESTDIR)@prefix@/lib
81 (if test -f libspud.so; then @INSTALL@ libspud.so $(DESTDIR)@prefix@/lib; fi) || true81 (if test -f libspud.so.0; then @INSTALL@ libspud.so.0 $(DESTDIR)@prefix@/lib; fi) || true
82 (if test -f libspud.so; then cd $(DESTDIR)@prefix@/lib/; ln -s libspud.so.0 libspud.so; cd -; fi) || true
82 @INSTALL@ $(MODS) $(DESTDIR)@prefix@/include83 @INSTALL@ $(MODS) $(DESTDIR)@prefix@/include
83 @INSTALL@ $(HEADERS) $(DESTDIR)@prefix@/include84 @INSTALL@ $(HEADERS) $(DESTDIR)@prefix@/include
8485
@@ -93,6 +94,13 @@
93install-diamond:94install-diamond:
94 cd diamond; python setup.py install --prefix=$(DESTDIR)@prefix@; cd ..95 cd diamond; python setup.py install --prefix=$(DESTDIR)@prefix@; cd ..
9596
97install-pyspud:
98ifeq ($(origin DESTDIR),undefined)
99 cd python; python setup.py install --prefix=$(DESTDIR)@prefix@; cd ..
100else
101 cd python; for python in $(shell pyversions -r); do $$python setup.py install --prefix=$(DESTDIR)@prefix@ --install-layout=deb; done; cd ..
102endif
103
96clean:104clean:
97 @cd doc; $(MAKE) clean105 @cd doc; $(MAKE) clean
98 rm -f *.o libspud.a libspud.so *.o *.la *.mod *.lo106 rm -f *.o libspud.a libspud.so *.o *.la *.mod *.lo
99107
=== modified file 'configure'
--- configure 2011-07-11 11:07:06 +0000
+++ configure 2011-08-04 21:32:37 +0000
@@ -21746,7 +21746,7 @@
2174621746
2174721747
2174821748
21749ac_config_files="$ac_config_files Makefile src/tests/Makefile examples/Makefile bin/spud-preprocess python/libspud.py diamond/setup.py diamond/diamond/plugins.py diamond/diamond/preprocess.py"21749ac_config_files="$ac_config_files Makefile src/tests/Makefile examples/Makefile bin/spud-preprocess diamond/setup.py diamond/diamond/plugins.py diamond/diamond/preprocess.py"
2175021750
21751cat >confcache <<\_ACEOF21751cat >confcache <<\_ACEOF
21752# This file is a shell script that caches the results of configure21752# This file is a shell script that caches the results of configure
@@ -22986,7 +22986,6 @@
22986 "src/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/Makefile" ;;22986 "src/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/Makefile" ;;
22987 "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;22987 "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;
22988 "bin/spud-preprocess") CONFIG_FILES="$CONFIG_FILES bin/spud-preprocess" ;;22988 "bin/spud-preprocess") CONFIG_FILES="$CONFIG_FILES bin/spud-preprocess" ;;
22989 "python/libspud.py") CONFIG_FILES="$CONFIG_FILES python/libspud.py" ;;
22990 "diamond/setup.py") CONFIG_FILES="$CONFIG_FILES diamond/setup.py" ;;22989 "diamond/setup.py") CONFIG_FILES="$CONFIG_FILES diamond/setup.py" ;;
22991 "diamond/diamond/plugins.py") CONFIG_FILES="$CONFIG_FILES diamond/diamond/plugins.py" ;;22990 "diamond/diamond/plugins.py") CONFIG_FILES="$CONFIG_FILES diamond/diamond/plugins.py" ;;
22992 "diamond/diamond/preprocess.py") CONFIG_FILES="$CONFIG_FILES diamond/diamond/preprocess.py" ;;22991 "diamond/diamond/preprocess.py") CONFIG_FILES="$CONFIG_FILES diamond/diamond/preprocess.py" ;;
2299322992
=== modified file 'configure.in'
--- configure.in 2011-07-11 11:07:06 +0000
+++ configure.in 2011-08-04 21:32:37 +0000
@@ -306,5 +306,4 @@
306306
307AC_OUTPUT(Makefile src/tests/Makefile examples/Makefile307AC_OUTPUT(Makefile src/tests/Makefile examples/Makefile
308 bin/spud-preprocess308 bin/spud-preprocess
309 python/libspud.py
310 diamond/setup.py diamond/diamond/plugins.py diamond/diamond/preprocess.py)309 diamond/setup.py diamond/diamond/plugins.py diamond/diamond/preprocess.py)
311310
=== modified file 'debian/control'
--- debian/control 2010-04-13 13:51:29 +0000
+++ debian/control 2011-08-04 21:32:37 +0000
@@ -50,3 +50,15 @@
50 schema-aware editor such as Diamond. Spudtools contains the schema50 schema-aware editor such as Diamond. Spudtools contains the schema
51 for the spud base language and the spud-preprocess script for51 for the spud base language and the spud-preprocess script for
52 converting schemas between the compact and xml syntaxes.52 converting schemas between the compact and xml syntaxes.
53
54Package: python-spud
55Section: python
56Architecture: any
57XB-Python-Version: ${python:Versions}
58Depends: libspud-dev (= ${binary:Version}), ${python:Depends}, ${misc:Depends}
59Description: An automatic options system for scientific models (python interface).
60 Spud is an automatic options system which reads an xml options file
61 into a dictionary for immediate access from within the model. The xml
62 file is generated using a spud-compatible RELAX NG schema and a
63 schema-aware editor such as Diamond. This package contains the Python
64 bindings for libspud.
5365
=== modified file 'debian/diamond.copyright'
--- debian/diamond.copyright 2008-09-26 13:42:19 +0000
+++ debian/diamond.copyright 2011-08-04 21:32:37 +0000
@@ -1,4 +1,3 @@
1<<<<<<< .working
2Except as noted below, Diamond is copyright (C) 2007 Imperial College1Except as noted below, Diamond is copyright (C) 2007 Imperial College
3London and others. For a full list of contributors see the AUTHORS2London and others. For a full list of contributors see the AUTHORS
4file.3file.
54
=== added file 'debian/python-spud.copyright'
--- debian/python-spud.copyright 1970-01-01 00:00:00 +0000
+++ debian/python-spud.copyright 2011-08-04 21:32:37 +0000
@@ -0,0 +1,39 @@
1Except as noted below, Spud is copyright (C) 2007 Imperial College
2London and others. For a full list of contributors see the AUTHORS
3file.
4
5Spud is free software; you can redistribute it and/or
6modify it under the terms of the GNU Lesser General Public
7License as published by the Free Software Foundation; either
8version 2.1 of the License, or (at your option) any later version.
9
10This library is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13Lesser General Public License for more details.
14
15On Debian systems, the complete text of the GNU Lesser General Public
16License can be found in the file `/usr/share/common-licenses/LGPL-2.1'.
17
18-----
19
20Tinyxml is copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
21
22This software is provided 'as-is', without any express or implied
23warranty. In no event will the authors be held liable for any
24damages arising from the use of this software.
25
26Permission is granted to anyone to use this software for any
27purpose, including commercial applications, and to alter it and
28redistribute it freely, subject to the following restrictions:
29
301. The origin of this software must not be misrepresented; you must
31not claim that you wrote the original software. If you use this
32software in a product, an acknowledgment in the product documentation
33would be appreciated but is not required.
34
352. Altered source versions must be plainly marked as such, and
36must not be misrepresented as being the original software.
37
383. This notice may not be removed or altered from any source
39distribution.
0\ No newline at end of file40\ No newline at end of file
141
=== modified file 'debian/rules'
--- debian/rules 2011-07-12 11:24:31 +0000
+++ debian/rules 2011-08-04 21:32:37 +0000
@@ -79,7 +79,10 @@
79 echo "Failed to locate python egg, was it built correctly?" && exit 1 ; \79 echo "Failed to locate python egg, was it built correctly?" && exit 1 ; \
80 fi80 fi
8181
82binary-arch: build-libspud install-libspud install-spudtools82install-pyspud:
83 $(MAKE) install-pyspud DESTDIR=$(CURDIR)/debian/python-spud
84
85binary-arch: build-libspud install-libspud install-spudtools install-pyspud
83 dh_testdir86 dh_testdir
84 dh_testroot87 dh_testroot
85 dh_installchangelogs 88 dh_installchangelogs
@@ -92,7 +95,7 @@
92# dh_installemacsen95# dh_installemacsen
93# dh_installpam96# dh_installpam
94# dh_installmime97# dh_installmime
95# dh_python98 dh_python2
96# dh_installinit99# dh_installinit
97# dh_installcron100# dh_installcron
98# dh_installinfo101# dh_installinfo
99102
=== added file 'python/libspud.c'
--- python/libspud.c 1970-01-01 00:00:00 +0000
+++ python/libspud.c 2011-08-04 21:32:37 +0000
@@ -0,0 +1,831 @@
1#include <Python.h>
2#include <string.h>
3#include "spud.h"
4#include <stdio.h>
5
6#define MAXLENGTH 2048
7
8static PyObject *SpudError;
9static PyObject *SpudTypeError;
10static PyObject *SpudKeyError;
11static PyObject *SpudFileError;
12static PyObject *SpudNewKeyWarning;
13static PyObject *SpudAttrSetFailedWarning;
14static PyObject *SpudShapeError;
15static PyObject *SpudRankError;
16
17void* manager;
18
19static PyObject *
20error_checking(int outcome, char *functionname)
21{
22 char errormessage [MAXLENGTH];
23
24 if (outcome == SPUD_KEY_ERROR){
25 snprintf(errormessage, MAXLENGTH, "Error: The specified option is not present \
26 in the dictionary in %s", functionname);
27 PyErr_SetString(SpudKeyError, errormessage);
28 return NULL;
29 }
30 if (outcome == SPUD_TYPE_ERROR){
31 snprintf(errormessage, MAXLENGTH, "Error: The specified option has a different \
32 type from that of the option argument provided in %s", functionname);
33 PyErr_SetString(SpudTypeError, errormessage);
34 return NULL;
35 }
36 if (outcome == SPUD_NEW_KEY_WARNING){
37 snprintf(errormessage, MAXLENGTH, "Warning: The option being inserted is not ] \
38 already in the dictionary %s", functionname);
39 PyErr_SetString(SpudNewKeyWarning, errormessage);
40 return NULL;
41 }
42 if (outcome == SPUD_FILE_ERROR){
43 snprintf(errormessage, MAXLENGTH, "Error: The specified options file cannot be \
44 read or written to as the routine requires in %s", functionname);
45 PyErr_SetString(SpudFileError, errormessage);
46 return NULL;
47 }
48 if (outcome == SPUD_RANK_ERROR){
49 snprintf(errormessage, MAXLENGTH, "Error: The specified option has a different rank from \
50 that of the option argument provided %s", functionname);
51 PyErr_SetString(SpudRankError, errormessage);
52 return NULL;
53 }
54 if (outcome == SPUD_SHAPE_ERROR){
55 snprintf(errormessage, MAXLENGTH, "Error: The specified option has a different shape from \
56 that of the option argument provided in %s", functionname);
57 PyErr_SetString(SpudShapeError, errormessage);
58 return NULL;
59 }
60 if (outcome == SPUD_ATTR_SET_FAILED_WARNING){
61 snprintf(errormessage, MAXLENGTH, "Warning: The option being set as an attribute can not be \
62 set as an attribute in %s", functionname);
63 PyErr_SetString(SpudAttrSetFailedWarning, errormessage);
64 return NULL;
65 }
66 if (outcome == SPUD_NO_ERROR){
67 Py_RETURN_NONE;
68 }
69
70 PyErr_SetString(SpudError,"Error: error checking failed.");
71 return NULL;
72}
73
74static PyObject *
75libspud_load_options(PyObject *self, PyObject *args)
76{
77 const char *key;
78 int key_len;
79 int outcomeLoadOptions;
80
81 if (!PyArg_ParseTuple(args, "s", &key))
82 return NULL;
83 key_len = strlen(key);
84 outcomeLoadOptions = spud_load_options(key,key_len);
85
86 return error_checking(outcomeLoadOptions, "load options");
87}
88
89static PyObject*
90libspud_print_options(PyObject *self, PyObject *args)
91{
92 spud_print_options();
93
94 Py_RETURN_NONE;
95}
96
97static PyObject *
98libspud_get_number_of_children(PyObject *self, PyObject *args)
99{
100 const char *key;
101 int key_len;
102 int child_count;
103 int outcomeGetNumChildren;
104
105 if (!PyArg_ParseTuple(args, "s", &key))
106 return NULL;
107 key_len = strlen(key);
108 outcomeGetNumChildren = spud_get_number_of_children(key, key_len, &child_count);
109 if (error_checking(outcomeGetNumChildren, "get number of children") == NULL){
110 return NULL;
111 }
112
113 return Py_BuildValue("i", child_count);
114}
115
116static PyObject *
117libspud_get_child_name(PyObject *self, PyObject *args)
118{
119 const char *key;
120 int key_len;
121 int index;
122 char child_name [MAXLENGTH];
123 int i;
124 int outcomeGetChildName;
125
126 for (i = 0; i < MAXLENGTH; i++){
127 child_name[i] = '\0';
128 }
129 if (!PyArg_ParseTuple(args, "si", &key, &index)){
130 return NULL;
131 }
132 key_len = strlen(key);
133 outcomeGetChildName = spud_get_child_name(key, key_len, index, child_name, MAXLENGTH);
134 if (error_checking(outcomeGetChildName, "get child name") == NULL){
135 return NULL;
136 }
137
138 return Py_BuildValue("s", child_name);
139}
140
141static PyObject *
142libspud_option_count(PyObject *self, PyObject *args)
143{
144 const char *key;
145 int key_len;
146 int numoptions;
147
148 if (!PyArg_ParseTuple(args, "s", &key)){
149 return NULL;
150 }
151 key_len = strlen(key);
152 numoptions = spud_option_count(key, key_len);
153
154 return Py_BuildValue("i", numoptions);
155}
156
157static PyObject *
158libspud_have_option(PyObject *self, PyObject *args)
159{
160 const char *key;
161 int key_len;
162 int haveoption;
163
164 if (!PyArg_ParseTuple(args, "s", &key)){
165 return NULL;
166 }
167 key_len = strlen(key);
168 haveoption = spud_have_option(key, key_len);
169
170 if (haveoption == 0){
171 Py_RETURN_FALSE;
172 }
173 else{
174 Py_RETURN_TRUE;
175 }
176}
177
178static PyObject *
179libspud_add_option(PyObject *self, PyObject *args)
180{
181 const char *key;
182 int key_len;
183 int outcomeAddOption;
184
185 if (!PyArg_ParseTuple(args, "s", &key)){
186 return NULL;
187 }
188 key_len = strlen(key);
189 outcomeAddOption = spud_add_option(key, key_len);
190 return error_checking(outcomeAddOption, "add option");
191
192}
193
194static PyObject *
195libspud_get_option_type(PyObject *self, PyObject *args)
196{
197 const char *key;
198 int key_len;
199 int type;
200 int outcomeGetOptionType;
201
202 if (!PyArg_ParseTuple(args, "s", &key)){
203 return NULL;
204 }
205 key_len = strlen(key);
206 outcomeGetOptionType = spud_get_option_type(key, key_len, &type);
207 if (error_checking(outcomeGetOptionType, "get option type") == NULL){
208 return NULL;
209 }
210 if (type == SPUD_DOUBLE){
211 Py_INCREF(&PyFloat_Type);
212 return (PyObject*) &PyFloat_Type;
213 }
214 else if (type == SPUD_INT){
215 Py_INCREF(&PyInt_Type);
216 return (PyObject*) &PyInt_Type;
217 }
218 else if (type == SPUD_NONE){
219 Py_RETURN_NONE;
220 }
221 else if (type == SPUD_STRING){
222 Py_INCREF(&PyString_Type);
223 return (PyObject*) &PyString_Type;
224 }
225
226 PyErr_SetString(SpudError,"Error: Get option type function failed");
227 return NULL;
228}
229
230static PyObject *
231libspud_get_option_rank(PyObject *self, PyObject *args)
232{
233 const char *key;
234 int key_len;
235 int rank;
236 int outcomeGetOptionRank;
237
238 if (!PyArg_ParseTuple(args, "s", &key)){
239 return NULL;
240 }
241 key_len = strlen(key);
242 outcomeGetOptionRank = spud_get_option_rank(key, key_len, &rank);
243 if (error_checking(outcomeGetOptionRank, "get option rank") == NULL){
244 return NULL;
245 }
246
247 return Py_BuildValue("i", rank);
248}
249
250static PyObject *
251libspud_get_option_shape(PyObject *self, PyObject *args)
252{
253 const char *key;
254 int key_len;
255 int shape[2];
256 int outcomeGetOptionShape;
257
258 if (!PyArg_ParseTuple(args, "s", &key)){
259 return NULL;
260 }
261 key_len = strlen(key);
262 outcomeGetOptionShape = spud_get_option_shape(key, key_len, shape);
263 if (error_checking(outcomeGetOptionShape, "get option shape") == NULL){
264 return NULL;
265 }
266
267 return Py_BuildValue("(i,i)", shape[0],shape[1]);
268}
269
270static PyObject*
271spud_get_option_aux_list_ints(const char *key, int key_len, int type, int rank, int *shape)
272{ // this function is for getting option when the option is of type a list of ints
273 int outcomeGetOption;
274 int size = shape[0];
275 int val [size];
276 int j;
277
278 outcomeGetOption = spud_get_option(key, key_len, val);
279 if (error_checking(outcomeGetOption, "get option aux list") == NULL){
280 return NULL;
281 }
282 PyObject* pylist = PyList_New(size);
283 if (pylist == NULL){
284 printf("New list error.");
285 return NULL;
286 }
287 for (j = 0; j < size; j++){
288 PyObject* element = Py_BuildValue("i", val[j]);
289 PyList_SetItem(pylist, j, element);
290 }
291
292 return pylist;
293}
294
295static PyObject*
296spud_get_option_aux_list_doubles(const char *key, int key_len, int type, int rank, int *shape)
297{ // this function is for getting option when the option is of type a list of doubles
298 int outcomeGetOption;
299 int size = shape[0];
300 double val [size];
301 int j;
302
303 outcomeGetOption = spud_get_option(key, key_len, val);
304 if (error_checking(outcomeGetOption, "get option aux list") == NULL){
305 return NULL;
306 }
307 PyObject* pylist = PyList_New(size);
308 if (pylist == NULL){
309 printf("New list error.");
310 return NULL;
311 }
312 for (j = 0; j < size; j++){
313 PyObject* element = Py_BuildValue("f", val[j]);
314 PyList_SetItem(pylist, j, element);
315 }
316
317 return pylist;
318}
319
320static PyObject *
321spud_get_option_aux_scalar_or_string(const char *key, int key_len, int type, int rank, int *shape)
322{ // this function is for getting option when the option is of type a scalar or string
323 int outcomeGetOption;
324
325 if (type == SPUD_DOUBLE){
326 float val;
327 outcomeGetOption = spud_get_option(key, key_len, &val);
328 if (error_checking(outcomeGetOption, "get option aux scalar or string") == NULL){
329 return NULL;
330 }
331 return Py_BuildValue("f", val);
332 }
333 else if (type == SPUD_INT){
334 int val;
335 outcomeGetOption = spud_get_option(key, key_len, &val);
336 if (error_checking(outcomeGetOption, "get option aux scalar or string") == NULL){
337 return NULL;
338 }
339 return Py_BuildValue("i", val);
340 }
341 else if (type == SPUD_STRING) {
342 int size = shape[0];
343 char val[size+1];
344 int i;
345 for (i = 0; i < size+1; i++)
346 val[i] = '\0';
347
348 outcomeGetOption = spud_get_option(key, key_len, val);
349 if (error_checking(outcomeGetOption, "get option aux scalar or string") == NULL){
350 return NULL;
351 }
352 return Py_BuildValue("s", val);
353 }
354
355 PyErr_SetString(SpudError,"Error: Get option aux scalar failed");
356 return NULL;
357}
358
359static PyObject*
360spud_get_option_aux_tensor_doubles(const char *key, int key_len, int type, int rank, int *shape)
361{ // this function is for getting option when the option is of type a tensor o doubles
362 int outcomeGetOption;
363 int rowsize = shape[0];
364 int colsize = shape[1];
365 int size = rowsize*colsize;
366 double val [size];
367 int m;
368 int n;
369 int counter;
370
371 outcomeGetOption = spud_get_option(key, key_len, val);
372 if (error_checking(outcomeGetOption, "get option aux tensor") == NULL){
373 return NULL;
374 }
375 PyObject* pylist = PyList_New(rowsize);
376 if (pylist == NULL){
377 printf("New list error");
378 return NULL;
379 }
380 counter = 0;
381 for (m = 0; m < rowsize; m++){
382 PyObject* pysublist = PyList_New(colsize);
383 if (pysublist == NULL){
384 printf("New sublist error");
385 return NULL;
386 }
387 for (n = 0; n < colsize; n++){
388 PyObject* element = Py_BuildValue("f", val[counter]);
389 PyList_SetItem(pysublist, n, element);
390 counter++;
391 }
392 PyList_SetItem(pylist, m, pysublist);
393 }
394
395 return pylist;
396}
397
398static PyObject*
399spud_get_option_aux_tensor_ints(const char *key, int key_len, int type, int rank, int *shape)
400{ // this function is for getting option when the option is of type a tensor of ints
401 int outcomeGetOption;
402 int rowsize = shape[0];
403 int colsize = shape[1];
404 int size = rowsize*colsize;
405 int val [size];
406 int m;
407 int n;
408 int counter;
409
410 outcomeGetOption = spud_get_option(key, key_len, val);
411 if (error_checking(outcomeGetOption, "get option aux tensor") == NULL){
412 return NULL;
413 }
414 PyObject* pylist = PyList_New(rowsize);
415 if (pylist == NULL){
416 printf("New list error");
417 return NULL;
418 }
419 counter = 0;
420 for (m = 0; m < rowsize; m++){
421 PyObject* pysublist = PyList_New(colsize);
422 if (pysublist == NULL){
423 printf("New sublist error");
424 return NULL;
425 }
426 for (n = 0; n < colsize; n++){
427 PyObject* element = Py_BuildValue("f", val[counter]);
428 PyList_SetItem(pysublist, n, element);
429 counter++;
430 }
431 PyList_SetItem(pylist, m, pysublist);
432 }
433
434 return pylist;
435}
436
437static PyObject *
438libspud_get_option(PyObject *self, PyObject *args)
439{
440 const char *key;
441 int key_len;
442 int type;
443 int rank = 0;
444 int shape[2];
445 int outcomeGetOptionType;
446 int outcomeGetOptionRank;
447 int outcomeGetOptionShape;
448
449 if(!PyArg_ParseTuple(args, "s", &key)){
450 return NULL;
451 }
452 key_len = strlen(key);
453 outcomeGetOptionRank = spud_get_option_rank(key, key_len, &rank);
454 if (error_checking(outcomeGetOptionRank, "get option") == NULL){
455 return NULL;
456 }
457 outcomeGetOptionType = spud_get_option_type(key, key_len, &type);
458 if (error_checking(outcomeGetOptionType, "get option") == NULL){
459 return NULL;
460 }
461 outcomeGetOptionShape = spud_get_option_shape(key, key_len, shape);
462 if (error_checking(outcomeGetOptionShape, "get option") == NULL){
463 return NULL;
464 }
465
466 if (rank == -1){ // type error
467 char errormessage [MAXLENGTH];
468 snprintf(errormessage, MAXLENGTH, "Error: The specified option has a different \
469 type from that of the option argument provided in %s", "get option");
470 PyErr_SetString(SpudTypeError, errormessage);
471 return NULL;
472 }
473 else if (rank == 0){ // scalar
474 return spud_get_option_aux_scalar_or_string(key, key_len, type, rank, shape);
475 }
476 else if (rank == 1){ // list or string
477 if (type == SPUD_INT){ //a list of ints
478 return spud_get_option_aux_list_ints(key, key_len, type, rank, shape);
479 }
480 else if (type == SPUD_DOUBLE){ //a list of doubles
481 return spud_get_option_aux_list_doubles(key, key_len, type, rank, shape);
482 }
483 else if (type == SPUD_STRING){ //string
484 return spud_get_option_aux_scalar_or_string(key, key_len, type, rank, shape);
485 }
486 }
487 else if (rank == 2){ // tensor
488 if (type == SPUD_DOUBLE){ //a tensor of doubles
489 return spud_get_option_aux_tensor_doubles(key, key_len, type, rank, shape);
490 }
491 else if (type == SPUD_INT){ //a tensor of ints
492 return spud_get_option_aux_tensor_ints(key, key_len, type, rank, shape);
493 }
494 }
495
496 PyErr_SetString(SpudError,"Error: Get option failed.");
497 return NULL;
498}
499static PyObject*
500set_option_aux_list_ints(PyObject *pylist, const char *key, int key_len, int type, int rank, int *shape)
501{ // this function is for setting option when the second argument is of type a list of ints
502 int j;
503 int psize = PyList_Size(pylist);
504 shape[0] = psize;
505 int val[psize] ;
506 int outcomeSetOption;
507 int element;
508
509 for (j = 0; j < psize; j++){
510 element = -1;
511 PyObject* pelement = PyList_GetItem(pylist, j);
512 PyArg_Parse(pelement, "i", &element);
513 val[j] = element;
514 }
515 outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
516 if (error_checking(outcomeSetOption, "set option aux list ints") == NULL){
517 return NULL;
518 }
519 Py_RETURN_NONE;
520}
521
522static PyObject*
523set_option_aux_list_doubles(PyObject *pylist, const char *key, int key_len, int type, int rank, int *shape)
524{ // this function is for setting option when the second argument is of type a list of doubles
525 int j;
526 int psize = PyList_Size(pylist);
527 shape[0] = psize;
528 double val [psize];
529 int outcomeSetOption;
530 double element;
531
532 for (j = 0; j < psize; j++){
533 element = -1.0;
534 PyObject* pelement = PyList_GetItem(pylist, j);
535 PyArg_Parse(pelement, "f", &element);
536 val[j] = element;
537 }
538 outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
539 if (error_checking(outcomeSetOption, "set option aux list ints") == NULL){
540 return NULL;
541 }
542
543 Py_RETURN_NONE;
544}
545
546static PyObject*
547set_option_aux_string(PyObject *pystring, const char *key, int key_len, int type, int rank, int *shape)
548{ // this function is for setting option when the second argument is of type string
549 char *val = PyString_AsString(pystring);
550 int outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
551 return error_checking(outcomeSetOption, "set option aux string");
552}
553
554static PyObject*
555libspud_set_option_attribute(PyObject *self, PyObject *args)
556{
557 const char*key;
558 int key_len;
559 PyObject* firstArg;
560 PyObject* secondArg;
561 const char*val;
562 int val_len;
563 int outcomeSetOption;
564
565 firstArg = PyTuple_GetItem(args, 0);
566 secondArg = PyTuple_GetItem(args, 1);
567 PyArg_Parse(firstArg, "s", &key);
568 key_len = strlen(key);
569 PyArg_Parse(secondArg, "s", &val);
570 val_len = strlen(val);
571 outcomeSetOption = spud_set_option_attribute(key, key_len, val, val_len);
572 return error_checking(outcomeSetOption, "set option attribute");
573}
574
575static PyObject*
576libspud_delete_option(PyObject *self, PyObject *args)
577{
578 const char*key;
579 int key_len;
580 PyObject* firstArg;
581 int outcomeDeleteOption;
582
583 firstArg = PyTuple_GetItem(args, 0);
584 PyArg_Parse(firstArg, "s", &key);
585 key_len = strlen(key);
586 outcomeDeleteOption = spud_delete_option(key, key_len);
587 return error_checking(outcomeDeleteOption, "delete option");
588}
589
590static PyObject*
591set_option_aux_tensor_doubles(PyObject *pylist, const char *key, int key_len, int type, int rank, int *shape)
592{ // this function is for setting option when the second argument is of type a tensor of doubles
593 int i;
594 int j;
595 int counter = 0;
596 int pylistsize = PyList_Size(pylist);
597 shape[0] = pylistsize;
598
599 int outcomeSetOption;
600 int pysublistsize;
601 PyObject* pysublist = PyList_GetItem(pylist, 0);
602 pysublistsize = PyList_Size(pysublist);
603 int size = pylistsize*pysublistsize;
604
605 double element;
606 double val [size];
607
608 for (i = 0; i < pylistsize; i++){
609 PyObject* pysublist = PyList_GetItem(pylist, i);
610 pysublistsize = PyList_Size(pysublist);
611 shape[1] = pysublistsize;
612 for (j = 0; j < pysublistsize; j++){
613 element = -1.0;
614 PyObject* pysublistElement = PyList_GetItem(pysublist, j);
615 PyArg_Parse(pysublistElement, "d", &element);
616 val[counter] = element;
617 counter ++;
618 }
619 }
620
621 outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
622 return error_checking(outcomeSetOption, "set option aux tensor doubles");
623}
624
625static PyObject*
626set_option_aux_tensor_ints(PyObject *pylist, const char *key, int key_len, int type, int rank, int *shape)
627{ // this function is for setting option when the second argument is of type a tensor of ints
628 int i;
629 int j;
630 int counter = 0;
631 int pylistsize = PyList_Size(pylist);
632 shape[0] = pylistsize;
633 int pysublistsize;
634 PyObject* pysublist = PyList_GetItem(pylist, 0);
635 pysublistsize = PyList_Size(pysublist);
636 int size = pylistsize*pysublistsize;
637 int val [size];
638 int outcomeSetOption;
639
640 int element;
641
642 for (i = 0; i < pylistsize; i++){
643 PyObject* pysublist = PyList_GetItem(pylist, i);
644 pysublistsize = PyList_Size(pysublist);
645 shape[1] = pysublistsize;
646 for (j = 0; j < pysublistsize; j++){
647 element = 1;
648 PyObject* pysublistElement = PyList_GetItem(pysublist, j);
649 PyArg_Parse(pysublistElement, "i", &element);
650 val[counter] = element;
651 counter ++;
652 }
653 }
654
655 outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
656 return error_checking(outcomeSetOption, "set option aux tensor doubles");
657}
658
659static PyObject*
660set_option_aux_scalar(PyObject *pyscalar, const char *key, int key_len, int type, int rank, int *shape)
661{ // this function is for setting option when the second argument is of type scalar
662 int outcomeSetOption = SPUD_NO_ERROR;
663
664 if (type == SPUD_DOUBLE){ //scalar is double
665 double val;
666 PyArg_Parse(pyscalar, "f", &val);
667 outcomeSetOption = spud_set_option(key, key_len, &val, type, rank, shape);
668 }
669 else if (type == SPUD_INT){
670 int val;
671 PyArg_Parse(pyscalar, "i", &val);
672 outcomeSetOption = spud_set_option(key, key_len, &val, type, rank, shape);
673 }
674
675 return error_checking(outcomeSetOption, "set option aux scalar");
676}
677
678
679static PyObject*
680libspud_set_option(PyObject *self, PyObject *args)
681{
682 const char *key;
683 int key_len;
684 int type;
685 int rank;
686 int shape[2];
687 int outcomeGetRank;
688 int outcomeGetShape;
689 int outcomeGetType;
690 PyObject* firstArg;
691 PyObject* secondArg;
692
693 firstArg = PyTuple_GetItem(args, 0);
694 secondArg = PyTuple_GetItem(args, 1);
695 PyArg_Parse(firstArg, "s", &key);
696 key_len = strlen(key);
697 outcomeGetType = spud_get_option_type(key, key_len, &type);
698 if (error_checking(outcomeGetType, "set option") == NULL){
699 return NULL;
700 }
701 outcomeGetRank = spud_get_option_rank(key, key_len, &rank);
702 if (error_checking(outcomeGetRank, "set option") == NULL){
703 return NULL;
704 }
705 outcomeGetShape = spud_get_option_shape(key, key_len, shape);
706 if (error_checking(outcomeGetShape, "set option") == NULL){
707 return NULL;
708 }
709
710 if (rank == 0){ // scalar
711 set_option_aux_scalar(secondArg, key, key_len, type, rank, shape);
712 }
713 else if (rank == 1){ // list or string
714 if (PyString_Check(secondArg)){ // pystring
715 set_option_aux_string(secondArg, key, key_len, type, rank, shape);
716 }
717 else if (type == SPUD_INT) { // list of ints
718 set_option_aux_list_ints(secondArg, key, key_len, type, rank, shape);
719 }
720 else if (type == SPUD_DOUBLE){ // list of doubles
721 set_option_aux_list_doubles(secondArg, key, key_len, type, rank, shape);
722 }
723 }
724 else if (rank == 2){ // tensor
725 if (type == SPUD_DOUBLE) { // tensor of doubles
726 set_option_aux_tensor_doubles(secondArg, key, key_len, type, rank, shape);
727 }
728 else if (type == SPUD_INT) { // tensor of ints
729 set_option_aux_tensor_ints(secondArg, key, key_len, type, rank, shape);
730 }
731 }
732
733 Py_RETURN_NONE;
734}
735
736static PyObject*
737libspud_write_options(PyObject *self, PyObject *args)
738{
739 PyObject* firstArg;
740 char *filename;
741 int filename_len;
742 int outcomeWriteOptions;
743
744 firstArg = PyTuple_GetItem(args, 0);
745 PyArg_Parse(firstArg, "s", &filename);
746 filename_len = strlen(filename);
747 outcomeWriteOptions = spud_write_options (filename, filename_len);
748 return error_checking(outcomeWriteOptions, "write options");
749}
750
751static PyMethodDef libspudMethods[] = {
752 {"load_options", libspud_load_options, METH_VARARGS,
753 "load options from xml file."},
754 {"print_options", libspud_print_options, METH_VARARGS,
755 "print options from xml file."},
756 {"get_number_of_children", libspud_get_number_of_children, METH_VARARGS,
757 "get number of children from xml file."},
758 {"get_child_name", libspud_get_child_name, METH_VARARGS,
759 "get child name from xml file."},
760 {"option_count", libspud_option_count, METH_VARARGS,
761 "option count from xml file."},
762 {"have_option", libspud_have_option, METH_VARARGS,
763 "have option from xml file."},
764 {"get_option_type", libspud_get_option_type, METH_VARARGS,
765 "get option type from xml file."},
766 {"get_option_rank", libspud_get_option_rank, METH_VARARGS,
767 "get option rank from xml file."},
768 {"get_option_shape", libspud_get_option_shape, METH_VARARGS,
769 "get option shape from xml file."},
770 {"get_option", libspud_get_option, METH_VARARGS,
771 "get option from xml file."},
772 {"set_option", libspud_set_option, METH_VARARGS,
773 "set option from xml file."},
774 {"write_options", libspud_write_options, METH_VARARGS,
775 "write options from xml file."},
776 {"delete_option", libspud_delete_option, METH_VARARGS,
777 "delete option from xml file."},
778 {"set_option_attribute", libspud_set_option_attribute, METH_VARARGS,
779 "set option attribute from xml file."},
780 {"add_option", libspud_add_option, METH_VARARGS,
781 "add option from xml file."},
782 {NULL, NULL, 0, NULL},
783 /* Sentinel */
784};
785
786PyMODINIT_FUNC
787initlibspud(void)
788{
789 PyObject *m;
790
791 m = Py_InitModule("libspud", libspudMethods);
792 if (m == NULL)
793 return;
794
795 SpudError = PyErr_NewException("Spud.error", NULL, NULL);
796 SpudNewKeyWarning = PyErr_NewException("SpudNewKey.warning", NULL, NULL);
797 SpudKeyError = PyErr_NewException("SpudKey.error", NULL, NULL);
798 SpudTypeError = PyErr_NewException("SpudType.error", NULL, NULL);
799 SpudFileError = PyErr_NewException("SpudFile.warning", NULL, NULL);
800 SpudAttrSetFailedWarning = PyErr_NewException("SpudAttrSetFailed.warning", NULL, NULL);
801 SpudShapeError = PyErr_NewException("SpudShape.error", NULL, NULL);
802 SpudRankError = PyErr_NewException("SpudRank.error", NULL, NULL);
803
804 Py_INCREF(SpudError);
805 Py_INCREF(SpudNewKeyWarning);
806 Py_INCREF(SpudKeyError);
807 Py_INCREF(SpudTypeError);
808 Py_INCREF(SpudFileError);
809 Py_INCREF(SpudRankError);
810 Py_INCREF(SpudShapeError);
811 Py_INCREF(SpudAttrSetFailedWarning);
812
813 PyModule_AddObject(m, "SpudError", SpudError);
814 PyModule_AddObject(m, "SpudNewKeyWarning", SpudNewKeyWarning);
815 PyModule_AddObject(m, "SpudKeyError", SpudKeyError);
816 PyModule_AddObject(m, "SpudTypeError", SpudTypeError);
817 PyModule_AddObject(m, "SpudFileError", SpudFileError);
818 PyModule_AddObject(m, "SpudAttrSetFailedWarning", SpudAttrSetFailedWarning);
819 PyModule_AddObject(m, "SpudShapeError", SpudShapeError);
820 PyModule_AddObject(m, "SpudRankError", SpudRankError);
821
822
823#if PY_MINOR_VERSION > 6
824 manager = PyCapsule_Import("spud_manager._spud_manager", 0);
825 if (manager != NULL) spud_set_manager(manager);
826 else PyErr_Clear();
827#endif
828
829}
830
831
0832
=== renamed file 'python/libspud.py.in' => 'python/libspud.py.ctypes'
=== added file 'python/setup.py'
--- python/setup.py 1970-01-01 00:00:00 +0000
+++ python/setup.py 2011-08-04 21:32:37 +0000
@@ -0,0 +1,9 @@
1from distutils.core import setup, Extension
2import os.path
3
4module1 = Extension('libspud', sources = ['libspud.c'], libraries=["spud"], library_dirs=[os.path.abspath("..")], include_dirs=[os.path.abspath("../include")])
5
6setup (name = 'libspud',
7 version = '1.1.3',
8 description = 'Python bindings for libspud',
9 ext_modules = [module1])
010
=== renamed file 'python/test_ctypes.py' => 'python/test_libspud.py'
--- python/test_ctypes.py 2011-07-19 05:47:49 +0000
+++ python/test_libspud.py 2011-08-04 21:32:37 +0000
@@ -1,78 +1,87 @@
1import libspud1import libspud
2print libspud.__file__
32
4libspud.load_options('test.flml')3libspud.load_options('test.flml')
54
6libspud.print_options()5#libspud.print_options()
76
8print libspud.get_number_of_children('/geometry')7assert libspud.get_number_of_children('/geometry') == 5
9print libspud.get_child_name('geometry', 0)8assert libspud.get_child_name('geometry', 0) == "dimension"
109
11print libspud.option_count('/problem_type')10assert libspud.option_count('/problem_type') == 1
12print libspud.have_option('/problem_type')11assert libspud.have_option('/problem_type')
1312
14print libspud.get_option_type('/geometry/dimension')13assert libspud.get_option_type('/geometry/dimension') is int
15print libspud.get_option_type('/problem_type')14assert libspud.get_option_type('/problem_type') is str
1615
17print libspud.get_option_rank('/geometry/dimension')16assert libspud.get_option_rank('/geometry/dimension') == 0
18print libspud.get_option_rank('/physical_parameters/gravity/vector_field::GravityDirection/prescribed/value/constant')17assert libspud.get_option_rank('/physical_parameters/gravity/vector_field::GravityDirection/prescribed/value/constant') == 1
1918
20print libspud.get_option_shape('/geometry/dimension')19assert libspud.get_option_shape('/geometry/dimension') == (-1, -1)
21print libspud.get_option_shape('/problem_type')20assert libspud.get_option_shape('/problem_type')[0] > 1
2221assert libspud.get_option_shape('/problem_type')[1] == -1
23print libspud.get_option('/problem_type')22
24print libspud.get_option('/geometry/dimension')23assert libspud.get_option('/problem_type') == "multimaterial"
24assert libspud.get_option('/geometry/dimension') == 2
25libspud.set_option('/geometry/dimension', 3)25libspud.set_option('/geometry/dimension', 3)
26print libspud.get_option('/geometry/dimension')26
27
28assert libspud.get_option('/geometry/dimension') == 3
2729
28list_path = '/material_phase::Material1/scalar_field::MaterialVolumeFraction/prognostic/boundary_conditions::LetNoOneLeave/surface_ids'30list_path = '/material_phase::Material1/scalar_field::MaterialVolumeFraction/prognostic/boundary_conditions::LetNoOneLeave/surface_ids'
29print libspud.get_option_shape(list_path)31assert libspud.get_option_shape(list_path) == (4, -1)
30print libspud.get_option_rank(list_path)32assert libspud.get_option_rank(list_path) == 1
31print libspud.get_option(list_path)33assert libspud.get_option(list_path) == [7, 8, 9, 10]
32assert(libspud.get_option(list_path)==[7,8,9,10])34
33libspud.set_option(list_path, [11,12,13,14])35libspud.set_option(list_path, [11, 12, 13, 14, 15])
34print libspud.get_option_shape(list_path)36assert libspud.get_option_shape(list_path) == (5, -1)
35print libspud.get_option_rank(list_path)37assert libspud.get_option_rank(list_path) == 1
36print libspud.get_option(list_path)38assert libspud.get_option(list_path)==[11, 12, 13, 14, 15]
37assert(libspud.get_option(list_path)==[11,12,13,14])
3839
39tensor_path = '/material_phase::Material1/tensor_field::DummyTensor/prescribed/value::WholeMesh/anisotropic_asymmetric/constant'40tensor_path = '/material_phase::Material1/tensor_field::DummyTensor/prescribed/value::WholeMesh/anisotropic_asymmetric/constant'
40print libspud.get_option_shape(tensor_path)41assert libspud.get_option_shape(tensor_path) == (2, 2)
41print libspud.get_option_rank(tensor_path)42assert libspud.get_option_rank(tensor_path) == 2
42print libspud.get_option(tensor_path)43assert libspud.get_option(tensor_path)==[[1.0,2.0],[3.0,4.0]]
43assert(libspud.get_option(tensor_path)==[[1.0,2.0],[3.0,4.0]])44
44libspud.set_option(tensor_path, [[5.0,6.0],[7.0,8.0]])45libspud.set_option(tensor_path, [[5.0,6.0,2.0],[7.0,8.0,1.0]])
45print libspud.get_option_shape(tensor_path)46#assert libspud.get_option_shape(tensor_path) == (3,3)
46print libspud.get_option_rank(tensor_path)47assert libspud.get_option_rank(tensor_path) == 2
47print libspud.get_option(tensor_path)48
48assert(libspud.get_option(tensor_path)==[[5.0,6.0],[7.0,8.0]])49assert(libspud.get_option(tensor_path)==[[5.0, 6.0, 2.0],[7.0, 8.0, 1.0]])
4950
50try:51try:
51 libspud.add_option('/foo')52 libspud.add_option('/foo')
53 assert False
52except libspud.SpudNewKeyWarning, e:54except libspud.SpudNewKeyWarning, e:
53 print "caught libspud.SpudNewKeyWarning: "+e.message55 pass
54print libspud.option_count('/foo')56
57assert libspud.option_count('/foo') == 1
5558
56libspud.set_option('/problem_type', 'helloworld')59libspud.set_option('/problem_type', 'helloworld')
57print libspud.get_option('/problem_type')60assert libspud.get_option('/problem_type') == "helloworld"
5861
59try:62try:
60 libspud.set_option_attribute('/foo/bar', 'foobar')63 libspud.set_option_attribute('/foo/bar', 'foobar')
64 assert False
61except libspud.SpudNewKeyWarning, e:65except libspud.SpudNewKeyWarning, e:
62 print "caught libspud.SpudNewKeyWarning: "+e.message66 pass
63print libspud.get_option('/foo/bar')67
68assert libspud.get_option('/foo/bar') == "foobar"
64 69
65libspud.delete_option('/foo')70libspud.delete_option('/foo')
66print libspud.option_count('/foo')71assert libspud.option_count('/foo') == 0
6772
68try:73try:
69 libspud.get_option('/foo')74 libspud.get_option('/foo')
75 assert False
70except libspud.SpudKeyError, e:76except libspud.SpudKeyError, e:
71 print "caught libspud.SpudKeyError: "+e.message77 pass
7278
73try:79try:
74 libspud.get_option('/geometry')80 libspud.get_option('/geometry')
81 assert False
75except libspud.SpudTypeError, e:82except libspud.SpudTypeError, e:
76 print "caught libspud.SpudTypeError: "+e.message83 pass
7784
78libspud.write_options('test_out.flml')85libspud.write_options('test_out.flml')
86
87print "All tests passed!"

Subscribers

People subscribed via source and target branches