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
1=== modified file 'Makefile.in'
2--- Makefile.in 2011-07-11 15:25:35 +0000
3+++ Makefile.in 2011-08-04 21:32:37 +0000
4@@ -57,7 +57,7 @@
5 libspud.la: $(OBJS)
6 ./libtool --mode=link --tag=FC $(FC) $(FCFLAGS) -o $(LIB) $(OBJS) $(LIBS) -rpath @prefix@/lib
7 if test -f .libs/libspud.a; then cp .libs/libspud.a .; fi
8- (if test -f .libs/libspud.so; then cp .libs/libspud.so .; fi) || true
9+ (if test -f .libs/libspud.so; then cp .libs/libspud.so ./libspud.so.0; ln -s libspud.so.0 libspud.so; fi) || true
10
11 build-diamond:
12 cd diamond; python setup.py build; cd ..
13@@ -72,13 +72,14 @@
14 doc:
15 @cd doc; $(MAKE) spud_manual.pdf
16
17-install: install-libspud install-spudtools install-diamond
18+install: install-libspud install-spudtools install-diamond install-pyspud
19
20 install-libspud: libspud.la
21 @INSTALL@ -d $(DESTDIR)@prefix@/lib
22 @INSTALL@ -d $(DESTDIR)@prefix@/include
23 @INSTALL@ libspud.a $(DESTDIR)@prefix@/lib
24- (if test -f libspud.so; then @INSTALL@ libspud.so $(DESTDIR)@prefix@/lib; fi) || true
25+ (if test -f libspud.so.0; then @INSTALL@ libspud.so.0 $(DESTDIR)@prefix@/lib; fi) || true
26+ (if test -f libspud.so; then cd $(DESTDIR)@prefix@/lib/; ln -s libspud.so.0 libspud.so; cd -; fi) || true
27 @INSTALL@ $(MODS) $(DESTDIR)@prefix@/include
28 @INSTALL@ $(HEADERS) $(DESTDIR)@prefix@/include
29
30@@ -93,6 +94,13 @@
31 install-diamond:
32 cd diamond; python setup.py install --prefix=$(DESTDIR)@prefix@; cd ..
33
34+install-pyspud:
35+ifeq ($(origin DESTDIR),undefined)
36+ cd python; python setup.py install --prefix=$(DESTDIR)@prefix@; cd ..
37+else
38+ cd python; for python in $(shell pyversions -r); do $$python setup.py install --prefix=$(DESTDIR)@prefix@ --install-layout=deb; done; cd ..
39+endif
40+
41 clean:
42 @cd doc; $(MAKE) clean
43 rm -f *.o libspud.a libspud.so *.o *.la *.mod *.lo
44
45=== modified file 'configure'
46--- configure 2011-07-11 11:07:06 +0000
47+++ configure 2011-08-04 21:32:37 +0000
48@@ -21746,7 +21746,7 @@
49
50
51
52-ac_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"
53+ac_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"
54
55 cat >confcache <<\_ACEOF
56 # This file is a shell script that caches the results of configure
57@@ -22986,7 +22986,6 @@
58 "src/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/Makefile" ;;
59 "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;
60 "bin/spud-preprocess") CONFIG_FILES="$CONFIG_FILES bin/spud-preprocess" ;;
61- "python/libspud.py") CONFIG_FILES="$CONFIG_FILES python/libspud.py" ;;
62 "diamond/setup.py") CONFIG_FILES="$CONFIG_FILES diamond/setup.py" ;;
63 "diamond/diamond/plugins.py") CONFIG_FILES="$CONFIG_FILES diamond/diamond/plugins.py" ;;
64 "diamond/diamond/preprocess.py") CONFIG_FILES="$CONFIG_FILES diamond/diamond/preprocess.py" ;;
65
66=== modified file 'configure.in'
67--- configure.in 2011-07-11 11:07:06 +0000
68+++ configure.in 2011-08-04 21:32:37 +0000
69@@ -306,5 +306,4 @@
70
71 AC_OUTPUT(Makefile src/tests/Makefile examples/Makefile
72 bin/spud-preprocess
73- python/libspud.py
74 diamond/setup.py diamond/diamond/plugins.py diamond/diamond/preprocess.py)
75
76=== modified file 'debian/control'
77--- debian/control 2010-04-13 13:51:29 +0000
78+++ debian/control 2011-08-04 21:32:37 +0000
79@@ -50,3 +50,15 @@
80 schema-aware editor such as Diamond. Spudtools contains the schema
81 for the spud base language and the spud-preprocess script for
82 converting schemas between the compact and xml syntaxes.
83+
84+Package: python-spud
85+Section: python
86+Architecture: any
87+XB-Python-Version: ${python:Versions}
88+Depends: libspud-dev (= ${binary:Version}), ${python:Depends}, ${misc:Depends}
89+Description: An automatic options system for scientific models (python interface).
90+ Spud is an automatic options system which reads an xml options file
91+ into a dictionary for immediate access from within the model. The xml
92+ file is generated using a spud-compatible RELAX NG schema and a
93+ schema-aware editor such as Diamond. This package contains the Python
94+ bindings for libspud.
95
96=== modified file 'debian/diamond.copyright'
97--- debian/diamond.copyright 2008-09-26 13:42:19 +0000
98+++ debian/diamond.copyright 2011-08-04 21:32:37 +0000
99@@ -1,4 +1,3 @@
100-<<<<<<< .working
101 Except as noted below, Diamond is copyright (C) 2007 Imperial College
102 London and others. For a full list of contributors see the AUTHORS
103 file.
104
105=== added file 'debian/python-spud.copyright'
106--- debian/python-spud.copyright 1970-01-01 00:00:00 +0000
107+++ debian/python-spud.copyright 2011-08-04 21:32:37 +0000
108@@ -0,0 +1,39 @@
109+Except as noted below, Spud is copyright (C) 2007 Imperial College
110+London and others. For a full list of contributors see the AUTHORS
111+file.
112+
113+Spud is free software; you can redistribute it and/or
114+modify it under the terms of the GNU Lesser General Public
115+License as published by the Free Software Foundation; either
116+version 2.1 of the License, or (at your option) any later version.
117+
118+This library is distributed in the hope that it will be useful,
119+but WITHOUT ANY WARRANTY; without even the implied warranty of
120+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
121+Lesser General Public License for more details.
122+
123+On Debian systems, the complete text of the GNU Lesser General Public
124+License can be found in the file `/usr/share/common-licenses/LGPL-2.1'.
125+
126+-----
127+
128+Tinyxml is copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
129+
130+This software is provided 'as-is', without any express or implied
131+warranty. In no event will the authors be held liable for any
132+damages arising from the use of this software.
133+
134+Permission is granted to anyone to use this software for any
135+purpose, including commercial applications, and to alter it and
136+redistribute it freely, subject to the following restrictions:
137+
138+1. The origin of this software must not be misrepresented; you must
139+not claim that you wrote the original software. If you use this
140+software in a product, an acknowledgment in the product documentation
141+would be appreciated but is not required.
142+
143+2. Altered source versions must be plainly marked as such, and
144+must not be misrepresented as being the original software.
145+
146+3. This notice may not be removed or altered from any source
147+distribution.
148\ No newline at end of file
149
150=== modified file 'debian/rules'
151--- debian/rules 2011-07-12 11:24:31 +0000
152+++ debian/rules 2011-08-04 21:32:37 +0000
153@@ -79,7 +79,10 @@
154 echo "Failed to locate python egg, was it built correctly?" && exit 1 ; \
155 fi
156
157-binary-arch: build-libspud install-libspud install-spudtools
158+install-pyspud:
159+ $(MAKE) install-pyspud DESTDIR=$(CURDIR)/debian/python-spud
160+
161+binary-arch: build-libspud install-libspud install-spudtools install-pyspud
162 dh_testdir
163 dh_testroot
164 dh_installchangelogs
165@@ -92,7 +95,7 @@
166 # dh_installemacsen
167 # dh_installpam
168 # dh_installmime
169-# dh_python
170+ dh_python2
171 # dh_installinit
172 # dh_installcron
173 # dh_installinfo
174
175=== added file 'python/libspud.c'
176--- python/libspud.c 1970-01-01 00:00:00 +0000
177+++ python/libspud.c 2011-08-04 21:32:37 +0000
178@@ -0,0 +1,831 @@
179+#include <Python.h>
180+#include <string.h>
181+#include "spud.h"
182+#include <stdio.h>
183+
184+#define MAXLENGTH 2048
185+
186+static PyObject *SpudError;
187+static PyObject *SpudTypeError;
188+static PyObject *SpudKeyError;
189+static PyObject *SpudFileError;
190+static PyObject *SpudNewKeyWarning;
191+static PyObject *SpudAttrSetFailedWarning;
192+static PyObject *SpudShapeError;
193+static PyObject *SpudRankError;
194+
195+void* manager;
196+
197+static PyObject *
198+error_checking(int outcome, char *functionname)
199+{
200+ char errormessage [MAXLENGTH];
201+
202+ if (outcome == SPUD_KEY_ERROR){
203+ snprintf(errormessage, MAXLENGTH, "Error: The specified option is not present \
204+ in the dictionary in %s", functionname);
205+ PyErr_SetString(SpudKeyError, errormessage);
206+ return NULL;
207+ }
208+ if (outcome == SPUD_TYPE_ERROR){
209+ snprintf(errormessage, MAXLENGTH, "Error: The specified option has a different \
210+ type from that of the option argument provided in %s", functionname);
211+ PyErr_SetString(SpudTypeError, errormessage);
212+ return NULL;
213+ }
214+ if (outcome == SPUD_NEW_KEY_WARNING){
215+ snprintf(errormessage, MAXLENGTH, "Warning: The option being inserted is not ] \
216+ already in the dictionary %s", functionname);
217+ PyErr_SetString(SpudNewKeyWarning, errormessage);
218+ return NULL;
219+ }
220+ if (outcome == SPUD_FILE_ERROR){
221+ snprintf(errormessage, MAXLENGTH, "Error: The specified options file cannot be \
222+ read or written to as the routine requires in %s", functionname);
223+ PyErr_SetString(SpudFileError, errormessage);
224+ return NULL;
225+ }
226+ if (outcome == SPUD_RANK_ERROR){
227+ snprintf(errormessage, MAXLENGTH, "Error: The specified option has a different rank from \
228+ that of the option argument provided %s", functionname);
229+ PyErr_SetString(SpudRankError, errormessage);
230+ return NULL;
231+ }
232+ if (outcome == SPUD_SHAPE_ERROR){
233+ snprintf(errormessage, MAXLENGTH, "Error: The specified option has a different shape from \
234+ that of the option argument provided in %s", functionname);
235+ PyErr_SetString(SpudShapeError, errormessage);
236+ return NULL;
237+ }
238+ if (outcome == SPUD_ATTR_SET_FAILED_WARNING){
239+ snprintf(errormessage, MAXLENGTH, "Warning: The option being set as an attribute can not be \
240+ set as an attribute in %s", functionname);
241+ PyErr_SetString(SpudAttrSetFailedWarning, errormessage);
242+ return NULL;
243+ }
244+ if (outcome == SPUD_NO_ERROR){
245+ Py_RETURN_NONE;
246+ }
247+
248+ PyErr_SetString(SpudError,"Error: error checking failed.");
249+ return NULL;
250+}
251+
252+static PyObject *
253+libspud_load_options(PyObject *self, PyObject *args)
254+{
255+ const char *key;
256+ int key_len;
257+ int outcomeLoadOptions;
258+
259+ if (!PyArg_ParseTuple(args, "s", &key))
260+ return NULL;
261+ key_len = strlen(key);
262+ outcomeLoadOptions = spud_load_options(key,key_len);
263+
264+ return error_checking(outcomeLoadOptions, "load options");
265+}
266+
267+static PyObject*
268+libspud_print_options(PyObject *self, PyObject *args)
269+{
270+ spud_print_options();
271+
272+ Py_RETURN_NONE;
273+}
274+
275+static PyObject *
276+libspud_get_number_of_children(PyObject *self, PyObject *args)
277+{
278+ const char *key;
279+ int key_len;
280+ int child_count;
281+ int outcomeGetNumChildren;
282+
283+ if (!PyArg_ParseTuple(args, "s", &key))
284+ return NULL;
285+ key_len = strlen(key);
286+ outcomeGetNumChildren = spud_get_number_of_children(key, key_len, &child_count);
287+ if (error_checking(outcomeGetNumChildren, "get number of children") == NULL){
288+ return NULL;
289+ }
290+
291+ return Py_BuildValue("i", child_count);
292+}
293+
294+static PyObject *
295+libspud_get_child_name(PyObject *self, PyObject *args)
296+{
297+ const char *key;
298+ int key_len;
299+ int index;
300+ char child_name [MAXLENGTH];
301+ int i;
302+ int outcomeGetChildName;
303+
304+ for (i = 0; i < MAXLENGTH; i++){
305+ child_name[i] = '\0';
306+ }
307+ if (!PyArg_ParseTuple(args, "si", &key, &index)){
308+ return NULL;
309+ }
310+ key_len = strlen(key);
311+ outcomeGetChildName = spud_get_child_name(key, key_len, index, child_name, MAXLENGTH);
312+ if (error_checking(outcomeGetChildName, "get child name") == NULL){
313+ return NULL;
314+ }
315+
316+ return Py_BuildValue("s", child_name);
317+}
318+
319+static PyObject *
320+libspud_option_count(PyObject *self, PyObject *args)
321+{
322+ const char *key;
323+ int key_len;
324+ int numoptions;
325+
326+ if (!PyArg_ParseTuple(args, "s", &key)){
327+ return NULL;
328+ }
329+ key_len = strlen(key);
330+ numoptions = spud_option_count(key, key_len);
331+
332+ return Py_BuildValue("i", numoptions);
333+}
334+
335+static PyObject *
336+libspud_have_option(PyObject *self, PyObject *args)
337+{
338+ const char *key;
339+ int key_len;
340+ int haveoption;
341+
342+ if (!PyArg_ParseTuple(args, "s", &key)){
343+ return NULL;
344+ }
345+ key_len = strlen(key);
346+ haveoption = spud_have_option(key, key_len);
347+
348+ if (haveoption == 0){
349+ Py_RETURN_FALSE;
350+ }
351+ else{
352+ Py_RETURN_TRUE;
353+ }
354+}
355+
356+static PyObject *
357+libspud_add_option(PyObject *self, PyObject *args)
358+{
359+ const char *key;
360+ int key_len;
361+ int outcomeAddOption;
362+
363+ if (!PyArg_ParseTuple(args, "s", &key)){
364+ return NULL;
365+ }
366+ key_len = strlen(key);
367+ outcomeAddOption = spud_add_option(key, key_len);
368+ return error_checking(outcomeAddOption, "add option");
369+
370+}
371+
372+static PyObject *
373+libspud_get_option_type(PyObject *self, PyObject *args)
374+{
375+ const char *key;
376+ int key_len;
377+ int type;
378+ int outcomeGetOptionType;
379+
380+ if (!PyArg_ParseTuple(args, "s", &key)){
381+ return NULL;
382+ }
383+ key_len = strlen(key);
384+ outcomeGetOptionType = spud_get_option_type(key, key_len, &type);
385+ if (error_checking(outcomeGetOptionType, "get option type") == NULL){
386+ return NULL;
387+ }
388+ if (type == SPUD_DOUBLE){
389+ Py_INCREF(&PyFloat_Type);
390+ return (PyObject*) &PyFloat_Type;
391+ }
392+ else if (type == SPUD_INT){
393+ Py_INCREF(&PyInt_Type);
394+ return (PyObject*) &PyInt_Type;
395+ }
396+ else if (type == SPUD_NONE){
397+ Py_RETURN_NONE;
398+ }
399+ else if (type == SPUD_STRING){
400+ Py_INCREF(&PyString_Type);
401+ return (PyObject*) &PyString_Type;
402+ }
403+
404+ PyErr_SetString(SpudError,"Error: Get option type function failed");
405+ return NULL;
406+}
407+
408+static PyObject *
409+libspud_get_option_rank(PyObject *self, PyObject *args)
410+{
411+ const char *key;
412+ int key_len;
413+ int rank;
414+ int outcomeGetOptionRank;
415+
416+ if (!PyArg_ParseTuple(args, "s", &key)){
417+ return NULL;
418+ }
419+ key_len = strlen(key);
420+ outcomeGetOptionRank = spud_get_option_rank(key, key_len, &rank);
421+ if (error_checking(outcomeGetOptionRank, "get option rank") == NULL){
422+ return NULL;
423+ }
424+
425+ return Py_BuildValue("i", rank);
426+}
427+
428+static PyObject *
429+libspud_get_option_shape(PyObject *self, PyObject *args)
430+{
431+ const char *key;
432+ int key_len;
433+ int shape[2];
434+ int outcomeGetOptionShape;
435+
436+ if (!PyArg_ParseTuple(args, "s", &key)){
437+ return NULL;
438+ }
439+ key_len = strlen(key);
440+ outcomeGetOptionShape = spud_get_option_shape(key, key_len, shape);
441+ if (error_checking(outcomeGetOptionShape, "get option shape") == NULL){
442+ return NULL;
443+ }
444+
445+ return Py_BuildValue("(i,i)", shape[0],shape[1]);
446+}
447+
448+static PyObject*
449+spud_get_option_aux_list_ints(const char *key, int key_len, int type, int rank, int *shape)
450+{ // this function is for getting option when the option is of type a list of ints
451+ int outcomeGetOption;
452+ int size = shape[0];
453+ int val [size];
454+ int j;
455+
456+ outcomeGetOption = spud_get_option(key, key_len, val);
457+ if (error_checking(outcomeGetOption, "get option aux list") == NULL){
458+ return NULL;
459+ }
460+ PyObject* pylist = PyList_New(size);
461+ if (pylist == NULL){
462+ printf("New list error.");
463+ return NULL;
464+ }
465+ for (j = 0; j < size; j++){
466+ PyObject* element = Py_BuildValue("i", val[j]);
467+ PyList_SetItem(pylist, j, element);
468+ }
469+
470+ return pylist;
471+}
472+
473+static PyObject*
474+spud_get_option_aux_list_doubles(const char *key, int key_len, int type, int rank, int *shape)
475+{ // this function is for getting option when the option is of type a list of doubles
476+ int outcomeGetOption;
477+ int size = shape[0];
478+ double val [size];
479+ int j;
480+
481+ outcomeGetOption = spud_get_option(key, key_len, val);
482+ if (error_checking(outcomeGetOption, "get option aux list") == NULL){
483+ return NULL;
484+ }
485+ PyObject* pylist = PyList_New(size);
486+ if (pylist == NULL){
487+ printf("New list error.");
488+ return NULL;
489+ }
490+ for (j = 0; j < size; j++){
491+ PyObject* element = Py_BuildValue("f", val[j]);
492+ PyList_SetItem(pylist, j, element);
493+ }
494+
495+ return pylist;
496+}
497+
498+static PyObject *
499+spud_get_option_aux_scalar_or_string(const char *key, int key_len, int type, int rank, int *shape)
500+{ // this function is for getting option when the option is of type a scalar or string
501+ int outcomeGetOption;
502+
503+ if (type == SPUD_DOUBLE){
504+ float val;
505+ outcomeGetOption = spud_get_option(key, key_len, &val);
506+ if (error_checking(outcomeGetOption, "get option aux scalar or string") == NULL){
507+ return NULL;
508+ }
509+ return Py_BuildValue("f", val);
510+ }
511+ else if (type == SPUD_INT){
512+ int val;
513+ outcomeGetOption = spud_get_option(key, key_len, &val);
514+ if (error_checking(outcomeGetOption, "get option aux scalar or string") == NULL){
515+ return NULL;
516+ }
517+ return Py_BuildValue("i", val);
518+ }
519+ else if (type == SPUD_STRING) {
520+ int size = shape[0];
521+ char val[size+1];
522+ int i;
523+ for (i = 0; i < size+1; i++)
524+ val[i] = '\0';
525+
526+ outcomeGetOption = spud_get_option(key, key_len, val);
527+ if (error_checking(outcomeGetOption, "get option aux scalar or string") == NULL){
528+ return NULL;
529+ }
530+ return Py_BuildValue("s", val);
531+ }
532+
533+ PyErr_SetString(SpudError,"Error: Get option aux scalar failed");
534+ return NULL;
535+}
536+
537+static PyObject*
538+spud_get_option_aux_tensor_doubles(const char *key, int key_len, int type, int rank, int *shape)
539+{ // this function is for getting option when the option is of type a tensor o doubles
540+ int outcomeGetOption;
541+ int rowsize = shape[0];
542+ int colsize = shape[1];
543+ int size = rowsize*colsize;
544+ double val [size];
545+ int m;
546+ int n;
547+ int counter;
548+
549+ outcomeGetOption = spud_get_option(key, key_len, val);
550+ if (error_checking(outcomeGetOption, "get option aux tensor") == NULL){
551+ return NULL;
552+ }
553+ PyObject* pylist = PyList_New(rowsize);
554+ if (pylist == NULL){
555+ printf("New list error");
556+ return NULL;
557+ }
558+ counter = 0;
559+ for (m = 0; m < rowsize; m++){
560+ PyObject* pysublist = PyList_New(colsize);
561+ if (pysublist == NULL){
562+ printf("New sublist error");
563+ return NULL;
564+ }
565+ for (n = 0; n < colsize; n++){
566+ PyObject* element = Py_BuildValue("f", val[counter]);
567+ PyList_SetItem(pysublist, n, element);
568+ counter++;
569+ }
570+ PyList_SetItem(pylist, m, pysublist);
571+ }
572+
573+ return pylist;
574+}
575+
576+static PyObject*
577+spud_get_option_aux_tensor_ints(const char *key, int key_len, int type, int rank, int *shape)
578+{ // this function is for getting option when the option is of type a tensor of ints
579+ int outcomeGetOption;
580+ int rowsize = shape[0];
581+ int colsize = shape[1];
582+ int size = rowsize*colsize;
583+ int val [size];
584+ int m;
585+ int n;
586+ int counter;
587+
588+ outcomeGetOption = spud_get_option(key, key_len, val);
589+ if (error_checking(outcomeGetOption, "get option aux tensor") == NULL){
590+ return NULL;
591+ }
592+ PyObject* pylist = PyList_New(rowsize);
593+ if (pylist == NULL){
594+ printf("New list error");
595+ return NULL;
596+ }
597+ counter = 0;
598+ for (m = 0; m < rowsize; m++){
599+ PyObject* pysublist = PyList_New(colsize);
600+ if (pysublist == NULL){
601+ printf("New sublist error");
602+ return NULL;
603+ }
604+ for (n = 0; n < colsize; n++){
605+ PyObject* element = Py_BuildValue("f", val[counter]);
606+ PyList_SetItem(pysublist, n, element);
607+ counter++;
608+ }
609+ PyList_SetItem(pylist, m, pysublist);
610+ }
611+
612+ return pylist;
613+}
614+
615+static PyObject *
616+libspud_get_option(PyObject *self, PyObject *args)
617+{
618+ const char *key;
619+ int key_len;
620+ int type;
621+ int rank = 0;
622+ int shape[2];
623+ int outcomeGetOptionType;
624+ int outcomeGetOptionRank;
625+ int outcomeGetOptionShape;
626+
627+ if(!PyArg_ParseTuple(args, "s", &key)){
628+ return NULL;
629+ }
630+ key_len = strlen(key);
631+ outcomeGetOptionRank = spud_get_option_rank(key, key_len, &rank);
632+ if (error_checking(outcomeGetOptionRank, "get option") == NULL){
633+ return NULL;
634+ }
635+ outcomeGetOptionType = spud_get_option_type(key, key_len, &type);
636+ if (error_checking(outcomeGetOptionType, "get option") == NULL){
637+ return NULL;
638+ }
639+ outcomeGetOptionShape = spud_get_option_shape(key, key_len, shape);
640+ if (error_checking(outcomeGetOptionShape, "get option") == NULL){
641+ return NULL;
642+ }
643+
644+ if (rank == -1){ // type error
645+ char errormessage [MAXLENGTH];
646+ snprintf(errormessage, MAXLENGTH, "Error: The specified option has a different \
647+ type from that of the option argument provided in %s", "get option");
648+ PyErr_SetString(SpudTypeError, errormessage);
649+ return NULL;
650+ }
651+ else if (rank == 0){ // scalar
652+ return spud_get_option_aux_scalar_or_string(key, key_len, type, rank, shape);
653+ }
654+ else if (rank == 1){ // list or string
655+ if (type == SPUD_INT){ //a list of ints
656+ return spud_get_option_aux_list_ints(key, key_len, type, rank, shape);
657+ }
658+ else if (type == SPUD_DOUBLE){ //a list of doubles
659+ return spud_get_option_aux_list_doubles(key, key_len, type, rank, shape);
660+ }
661+ else if (type == SPUD_STRING){ //string
662+ return spud_get_option_aux_scalar_or_string(key, key_len, type, rank, shape);
663+ }
664+ }
665+ else if (rank == 2){ // tensor
666+ if (type == SPUD_DOUBLE){ //a tensor of doubles
667+ return spud_get_option_aux_tensor_doubles(key, key_len, type, rank, shape);
668+ }
669+ else if (type == SPUD_INT){ //a tensor of ints
670+ return spud_get_option_aux_tensor_ints(key, key_len, type, rank, shape);
671+ }
672+ }
673+
674+ PyErr_SetString(SpudError,"Error: Get option failed.");
675+ return NULL;
676+}
677+static PyObject*
678+set_option_aux_list_ints(PyObject *pylist, const char *key, int key_len, int type, int rank, int *shape)
679+{ // this function is for setting option when the second argument is of type a list of ints
680+ int j;
681+ int psize = PyList_Size(pylist);
682+ shape[0] = psize;
683+ int val[psize] ;
684+ int outcomeSetOption;
685+ int element;
686+
687+ for (j = 0; j < psize; j++){
688+ element = -1;
689+ PyObject* pelement = PyList_GetItem(pylist, j);
690+ PyArg_Parse(pelement, "i", &element);
691+ val[j] = element;
692+ }
693+ outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
694+ if (error_checking(outcomeSetOption, "set option aux list ints") == NULL){
695+ return NULL;
696+ }
697+ Py_RETURN_NONE;
698+}
699+
700+static PyObject*
701+set_option_aux_list_doubles(PyObject *pylist, const char *key, int key_len, int type, int rank, int *shape)
702+{ // this function is for setting option when the second argument is of type a list of doubles
703+ int j;
704+ int psize = PyList_Size(pylist);
705+ shape[0] = psize;
706+ double val [psize];
707+ int outcomeSetOption;
708+ double element;
709+
710+ for (j = 0; j < psize; j++){
711+ element = -1.0;
712+ PyObject* pelement = PyList_GetItem(pylist, j);
713+ PyArg_Parse(pelement, "f", &element);
714+ val[j] = element;
715+ }
716+ outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
717+ if (error_checking(outcomeSetOption, "set option aux list ints") == NULL){
718+ return NULL;
719+ }
720+
721+ Py_RETURN_NONE;
722+}
723+
724+static PyObject*
725+set_option_aux_string(PyObject *pystring, const char *key, int key_len, int type, int rank, int *shape)
726+{ // this function is for setting option when the second argument is of type string
727+ char *val = PyString_AsString(pystring);
728+ int outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
729+ return error_checking(outcomeSetOption, "set option aux string");
730+}
731+
732+static PyObject*
733+libspud_set_option_attribute(PyObject *self, PyObject *args)
734+{
735+ const char*key;
736+ int key_len;
737+ PyObject* firstArg;
738+ PyObject* secondArg;
739+ const char*val;
740+ int val_len;
741+ int outcomeSetOption;
742+
743+ firstArg = PyTuple_GetItem(args, 0);
744+ secondArg = PyTuple_GetItem(args, 1);
745+ PyArg_Parse(firstArg, "s", &key);
746+ key_len = strlen(key);
747+ PyArg_Parse(secondArg, "s", &val);
748+ val_len = strlen(val);
749+ outcomeSetOption = spud_set_option_attribute(key, key_len, val, val_len);
750+ return error_checking(outcomeSetOption, "set option attribute");
751+}
752+
753+static PyObject*
754+libspud_delete_option(PyObject *self, PyObject *args)
755+{
756+ const char*key;
757+ int key_len;
758+ PyObject* firstArg;
759+ int outcomeDeleteOption;
760+
761+ firstArg = PyTuple_GetItem(args, 0);
762+ PyArg_Parse(firstArg, "s", &key);
763+ key_len = strlen(key);
764+ outcomeDeleteOption = spud_delete_option(key, key_len);
765+ return error_checking(outcomeDeleteOption, "delete option");
766+}
767+
768+static PyObject*
769+set_option_aux_tensor_doubles(PyObject *pylist, const char *key, int key_len, int type, int rank, int *shape)
770+{ // this function is for setting option when the second argument is of type a tensor of doubles
771+ int i;
772+ int j;
773+ int counter = 0;
774+ int pylistsize = PyList_Size(pylist);
775+ shape[0] = pylistsize;
776+
777+ int outcomeSetOption;
778+ int pysublistsize;
779+ PyObject* pysublist = PyList_GetItem(pylist, 0);
780+ pysublistsize = PyList_Size(pysublist);
781+ int size = pylistsize*pysublistsize;
782+
783+ double element;
784+ double val [size];
785+
786+ for (i = 0; i < pylistsize; i++){
787+ PyObject* pysublist = PyList_GetItem(pylist, i);
788+ pysublistsize = PyList_Size(pysublist);
789+ shape[1] = pysublistsize;
790+ for (j = 0; j < pysublistsize; j++){
791+ element = -1.0;
792+ PyObject* pysublistElement = PyList_GetItem(pysublist, j);
793+ PyArg_Parse(pysublistElement, "d", &element);
794+ val[counter] = element;
795+ counter ++;
796+ }
797+ }
798+
799+ outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
800+ return error_checking(outcomeSetOption, "set option aux tensor doubles");
801+}
802+
803+static PyObject*
804+set_option_aux_tensor_ints(PyObject *pylist, const char *key, int key_len, int type, int rank, int *shape)
805+{ // this function is for setting option when the second argument is of type a tensor of ints
806+ int i;
807+ int j;
808+ int counter = 0;
809+ int pylistsize = PyList_Size(pylist);
810+ shape[0] = pylistsize;
811+ int pysublistsize;
812+ PyObject* pysublist = PyList_GetItem(pylist, 0);
813+ pysublistsize = PyList_Size(pysublist);
814+ int size = pylistsize*pysublistsize;
815+ int val [size];
816+ int outcomeSetOption;
817+
818+ int element;
819+
820+ for (i = 0; i < pylistsize; i++){
821+ PyObject* pysublist = PyList_GetItem(pylist, i);
822+ pysublistsize = PyList_Size(pysublist);
823+ shape[1] = pysublistsize;
824+ for (j = 0; j < pysublistsize; j++){
825+ element = 1;
826+ PyObject* pysublistElement = PyList_GetItem(pysublist, j);
827+ PyArg_Parse(pysublistElement, "i", &element);
828+ val[counter] = element;
829+ counter ++;
830+ }
831+ }
832+
833+ outcomeSetOption = spud_set_option(key, key_len, val, type, rank, shape);
834+ return error_checking(outcomeSetOption, "set option aux tensor doubles");
835+}
836+
837+static PyObject*
838+set_option_aux_scalar(PyObject *pyscalar, const char *key, int key_len, int type, int rank, int *shape)
839+{ // this function is for setting option when the second argument is of type scalar
840+ int outcomeSetOption = SPUD_NO_ERROR;
841+
842+ if (type == SPUD_DOUBLE){ //scalar is double
843+ double val;
844+ PyArg_Parse(pyscalar, "f", &val);
845+ outcomeSetOption = spud_set_option(key, key_len, &val, type, rank, shape);
846+ }
847+ else if (type == SPUD_INT){
848+ int val;
849+ PyArg_Parse(pyscalar, "i", &val);
850+ outcomeSetOption = spud_set_option(key, key_len, &val, type, rank, shape);
851+ }
852+
853+ return error_checking(outcomeSetOption, "set option aux scalar");
854+}
855+
856+
857+static PyObject*
858+libspud_set_option(PyObject *self, PyObject *args)
859+{
860+ const char *key;
861+ int key_len;
862+ int type;
863+ int rank;
864+ int shape[2];
865+ int outcomeGetRank;
866+ int outcomeGetShape;
867+ int outcomeGetType;
868+ PyObject* firstArg;
869+ PyObject* secondArg;
870+
871+ firstArg = PyTuple_GetItem(args, 0);
872+ secondArg = PyTuple_GetItem(args, 1);
873+ PyArg_Parse(firstArg, "s", &key);
874+ key_len = strlen(key);
875+ outcomeGetType = spud_get_option_type(key, key_len, &type);
876+ if (error_checking(outcomeGetType, "set option") == NULL){
877+ return NULL;
878+ }
879+ outcomeGetRank = spud_get_option_rank(key, key_len, &rank);
880+ if (error_checking(outcomeGetRank, "set option") == NULL){
881+ return NULL;
882+ }
883+ outcomeGetShape = spud_get_option_shape(key, key_len, shape);
884+ if (error_checking(outcomeGetShape, "set option") == NULL){
885+ return NULL;
886+ }
887+
888+ if (rank == 0){ // scalar
889+ set_option_aux_scalar(secondArg, key, key_len, type, rank, shape);
890+ }
891+ else if (rank == 1){ // list or string
892+ if (PyString_Check(secondArg)){ // pystring
893+ set_option_aux_string(secondArg, key, key_len, type, rank, shape);
894+ }
895+ else if (type == SPUD_INT) { // list of ints
896+ set_option_aux_list_ints(secondArg, key, key_len, type, rank, shape);
897+ }
898+ else if (type == SPUD_DOUBLE){ // list of doubles
899+ set_option_aux_list_doubles(secondArg, key, key_len, type, rank, shape);
900+ }
901+ }
902+ else if (rank == 2){ // tensor
903+ if (type == SPUD_DOUBLE) { // tensor of doubles
904+ set_option_aux_tensor_doubles(secondArg, key, key_len, type, rank, shape);
905+ }
906+ else if (type == SPUD_INT) { // tensor of ints
907+ set_option_aux_tensor_ints(secondArg, key, key_len, type, rank, shape);
908+ }
909+ }
910+
911+ Py_RETURN_NONE;
912+}
913+
914+static PyObject*
915+libspud_write_options(PyObject *self, PyObject *args)
916+{
917+ PyObject* firstArg;
918+ char *filename;
919+ int filename_len;
920+ int outcomeWriteOptions;
921+
922+ firstArg = PyTuple_GetItem(args, 0);
923+ PyArg_Parse(firstArg, "s", &filename);
924+ filename_len = strlen(filename);
925+ outcomeWriteOptions = spud_write_options (filename, filename_len);
926+ return error_checking(outcomeWriteOptions, "write options");
927+}
928+
929+static PyMethodDef libspudMethods[] = {
930+ {"load_options", libspud_load_options, METH_VARARGS,
931+ "load options from xml file."},
932+ {"print_options", libspud_print_options, METH_VARARGS,
933+ "print options from xml file."},
934+ {"get_number_of_children", libspud_get_number_of_children, METH_VARARGS,
935+ "get number of children from xml file."},
936+ {"get_child_name", libspud_get_child_name, METH_VARARGS,
937+ "get child name from xml file."},
938+ {"option_count", libspud_option_count, METH_VARARGS,
939+ "option count from xml file."},
940+ {"have_option", libspud_have_option, METH_VARARGS,
941+ "have option from xml file."},
942+ {"get_option_type", libspud_get_option_type, METH_VARARGS,
943+ "get option type from xml file."},
944+ {"get_option_rank", libspud_get_option_rank, METH_VARARGS,
945+ "get option rank from xml file."},
946+ {"get_option_shape", libspud_get_option_shape, METH_VARARGS,
947+ "get option shape from xml file."},
948+ {"get_option", libspud_get_option, METH_VARARGS,
949+ "get option from xml file."},
950+ {"set_option", libspud_set_option, METH_VARARGS,
951+ "set option from xml file."},
952+ {"write_options", libspud_write_options, METH_VARARGS,
953+ "write options from xml file."},
954+ {"delete_option", libspud_delete_option, METH_VARARGS,
955+ "delete option from xml file."},
956+ {"set_option_attribute", libspud_set_option_attribute, METH_VARARGS,
957+ "set option attribute from xml file."},
958+ {"add_option", libspud_add_option, METH_VARARGS,
959+ "add option from xml file."},
960+ {NULL, NULL, 0, NULL},
961+ /* Sentinel */
962+};
963+
964+PyMODINIT_FUNC
965+initlibspud(void)
966+{
967+ PyObject *m;
968+
969+ m = Py_InitModule("libspud", libspudMethods);
970+ if (m == NULL)
971+ return;
972+
973+ SpudError = PyErr_NewException("Spud.error", NULL, NULL);
974+ SpudNewKeyWarning = PyErr_NewException("SpudNewKey.warning", NULL, NULL);
975+ SpudKeyError = PyErr_NewException("SpudKey.error", NULL, NULL);
976+ SpudTypeError = PyErr_NewException("SpudType.error", NULL, NULL);
977+ SpudFileError = PyErr_NewException("SpudFile.warning", NULL, NULL);
978+ SpudAttrSetFailedWarning = PyErr_NewException("SpudAttrSetFailed.warning", NULL, NULL);
979+ SpudShapeError = PyErr_NewException("SpudShape.error", NULL, NULL);
980+ SpudRankError = PyErr_NewException("SpudRank.error", NULL, NULL);
981+
982+ Py_INCREF(SpudError);
983+ Py_INCREF(SpudNewKeyWarning);
984+ Py_INCREF(SpudKeyError);
985+ Py_INCREF(SpudTypeError);
986+ Py_INCREF(SpudFileError);
987+ Py_INCREF(SpudRankError);
988+ Py_INCREF(SpudShapeError);
989+ Py_INCREF(SpudAttrSetFailedWarning);
990+
991+ PyModule_AddObject(m, "SpudError", SpudError);
992+ PyModule_AddObject(m, "SpudNewKeyWarning", SpudNewKeyWarning);
993+ PyModule_AddObject(m, "SpudKeyError", SpudKeyError);
994+ PyModule_AddObject(m, "SpudTypeError", SpudTypeError);
995+ PyModule_AddObject(m, "SpudFileError", SpudFileError);
996+ PyModule_AddObject(m, "SpudAttrSetFailedWarning", SpudAttrSetFailedWarning);
997+ PyModule_AddObject(m, "SpudShapeError", SpudShapeError);
998+ PyModule_AddObject(m, "SpudRankError", SpudRankError);
999+
1000+
1001+#if PY_MINOR_VERSION > 6
1002+ manager = PyCapsule_Import("spud_manager._spud_manager", 0);
1003+ if (manager != NULL) spud_set_manager(manager);
1004+ else PyErr_Clear();
1005+#endif
1006+
1007+}
1008+
1009+
1010
1011=== renamed file 'python/libspud.py.in' => 'python/libspud.py.ctypes'
1012=== added file 'python/setup.py'
1013--- python/setup.py 1970-01-01 00:00:00 +0000
1014+++ python/setup.py 2011-08-04 21:32:37 +0000
1015@@ -0,0 +1,9 @@
1016+from distutils.core import setup, Extension
1017+import os.path
1018+
1019+module1 = Extension('libspud', sources = ['libspud.c'], libraries=["spud"], library_dirs=[os.path.abspath("..")], include_dirs=[os.path.abspath("../include")])
1020+
1021+setup (name = 'libspud',
1022+ version = '1.1.3',
1023+ description = 'Python bindings for libspud',
1024+ ext_modules = [module1])
1025
1026=== renamed file 'python/test_ctypes.py' => 'python/test_libspud.py'
1027--- python/test_ctypes.py 2011-07-19 05:47:49 +0000
1028+++ python/test_libspud.py 2011-08-04 21:32:37 +0000
1029@@ -1,78 +1,87 @@
1030 import libspud
1031-print libspud.__file__
1032
1033 libspud.load_options('test.flml')
1034
1035-libspud.print_options()
1036-
1037-print libspud.get_number_of_children('/geometry')
1038-print libspud.get_child_name('geometry', 0)
1039-
1040-print libspud.option_count('/problem_type')
1041-print libspud.have_option('/problem_type')
1042-
1043-print libspud.get_option_type('/geometry/dimension')
1044-print libspud.get_option_type('/problem_type')
1045-
1046-print libspud.get_option_rank('/geometry/dimension')
1047-print libspud.get_option_rank('/physical_parameters/gravity/vector_field::GravityDirection/prescribed/value/constant')
1048-
1049-print libspud.get_option_shape('/geometry/dimension')
1050-print libspud.get_option_shape('/problem_type')
1051-
1052-print libspud.get_option('/problem_type')
1053-print libspud.get_option('/geometry/dimension')
1054+#libspud.print_options()
1055+
1056+assert libspud.get_number_of_children('/geometry') == 5
1057+assert libspud.get_child_name('geometry', 0) == "dimension"
1058+
1059+assert libspud.option_count('/problem_type') == 1
1060+assert libspud.have_option('/problem_type')
1061+
1062+assert libspud.get_option_type('/geometry/dimension') is int
1063+assert libspud.get_option_type('/problem_type') is str
1064+
1065+assert libspud.get_option_rank('/geometry/dimension') == 0
1066+assert libspud.get_option_rank('/physical_parameters/gravity/vector_field::GravityDirection/prescribed/value/constant') == 1
1067+
1068+assert libspud.get_option_shape('/geometry/dimension') == (-1, -1)
1069+assert libspud.get_option_shape('/problem_type')[0] > 1
1070+assert libspud.get_option_shape('/problem_type')[1] == -1
1071+
1072+assert libspud.get_option('/problem_type') == "multimaterial"
1073+assert libspud.get_option('/geometry/dimension') == 2
1074 libspud.set_option('/geometry/dimension', 3)
1075-print libspud.get_option('/geometry/dimension')
1076+
1077+
1078+assert libspud.get_option('/geometry/dimension') == 3
1079
1080 list_path = '/material_phase::Material1/scalar_field::MaterialVolumeFraction/prognostic/boundary_conditions::LetNoOneLeave/surface_ids'
1081-print libspud.get_option_shape(list_path)
1082-print libspud.get_option_rank(list_path)
1083-print libspud.get_option(list_path)
1084-assert(libspud.get_option(list_path)==[7,8,9,10])
1085-libspud.set_option(list_path, [11,12,13,14])
1086-print libspud.get_option_shape(list_path)
1087-print libspud.get_option_rank(list_path)
1088-print libspud.get_option(list_path)
1089-assert(libspud.get_option(list_path)==[11,12,13,14])
1090+assert libspud.get_option_shape(list_path) == (4, -1)
1091+assert libspud.get_option_rank(list_path) == 1
1092+assert libspud.get_option(list_path) == [7, 8, 9, 10]
1093+
1094+libspud.set_option(list_path, [11, 12, 13, 14, 15])
1095+assert libspud.get_option_shape(list_path) == (5, -1)
1096+assert libspud.get_option_rank(list_path) == 1
1097+assert libspud.get_option(list_path)==[11, 12, 13, 14, 15]
1098
1099 tensor_path = '/material_phase::Material1/tensor_field::DummyTensor/prescribed/value::WholeMesh/anisotropic_asymmetric/constant'
1100-print libspud.get_option_shape(tensor_path)
1101-print libspud.get_option_rank(tensor_path)
1102-print libspud.get_option(tensor_path)
1103-assert(libspud.get_option(tensor_path)==[[1.0,2.0],[3.0,4.0]])
1104-libspud.set_option(tensor_path, [[5.0,6.0],[7.0,8.0]])
1105-print libspud.get_option_shape(tensor_path)
1106-print libspud.get_option_rank(tensor_path)
1107-print libspud.get_option(tensor_path)
1108-assert(libspud.get_option(tensor_path)==[[5.0,6.0],[7.0,8.0]])
1109+assert libspud.get_option_shape(tensor_path) == (2, 2)
1110+assert libspud.get_option_rank(tensor_path) == 2
1111+assert libspud.get_option(tensor_path)==[[1.0,2.0],[3.0,4.0]]
1112+
1113+libspud.set_option(tensor_path, [[5.0,6.0,2.0],[7.0,8.0,1.0]])
1114+#assert libspud.get_option_shape(tensor_path) == (3,3)
1115+assert libspud.get_option_rank(tensor_path) == 2
1116+
1117+assert(libspud.get_option(tensor_path)==[[5.0, 6.0, 2.0],[7.0, 8.0, 1.0]])
1118
1119 try:
1120 libspud.add_option('/foo')
1121+ assert False
1122 except libspud.SpudNewKeyWarning, e:
1123- print "caught libspud.SpudNewKeyWarning: "+e.message
1124-print libspud.option_count('/foo')
1125+ pass
1126+
1127+assert libspud.option_count('/foo') == 1
1128
1129 libspud.set_option('/problem_type', 'helloworld')
1130-print libspud.get_option('/problem_type')
1131+assert libspud.get_option('/problem_type') == "helloworld"
1132
1133 try:
1134 libspud.set_option_attribute('/foo/bar', 'foobar')
1135+ assert False
1136 except libspud.SpudNewKeyWarning, e:
1137- print "caught libspud.SpudNewKeyWarning: "+e.message
1138-print libspud.get_option('/foo/bar')
1139+ pass
1140+
1141+assert libspud.get_option('/foo/bar') == "foobar"
1142
1143 libspud.delete_option('/foo')
1144-print libspud.option_count('/foo')
1145+assert libspud.option_count('/foo') == 0
1146
1147 try:
1148 libspud.get_option('/foo')
1149+ assert False
1150 except libspud.SpudKeyError, e:
1151- print "caught libspud.SpudKeyError: "+e.message
1152+ pass
1153
1154 try:
1155 libspud.get_option('/geometry')
1156+ assert False
1157 except libspud.SpudTypeError, e:
1158- print "caught libspud.SpudTypeError: "+e.message
1159+ pass
1160
1161 libspud.write_options('test_out.flml')
1162+
1163+print "All tests passed!"

Subscribers

People subscribed via source and target branches