Integrated python 2.6 interpreter in modules/python. The integration is much simpler than before as it now uses kernel dynamic values and lambda functions to call from/to python.

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@895953 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
jsdelfino 2010-01-05 09:16:29 +00:00
commit aea45d9976
8 changed files with 806 additions and 2 deletions

View file

@ -124,6 +124,20 @@ AC_ARG_WITH([httpd], [AC_HELP_STRING([--with-httpd=PATH], [path to installed htt
])
AC_SUBST(HTTPD_INCLUDE)
# Configure PYTHON_INCLUDE and PYTHON_LIB
AC_MSG_CHECKING([for python])
AC_ARG_WITH([curl], [AC_HELP_STRING([--with-python=PATH], [path to installed python 2.6 [default=/usr]])], [
PYTHON_INCLUDE="${withval}/include"
PYTHON_LIB="${withval}/lib"
AC_MSG_RESULT("${withval}")
], [
PYTHON_INCLUDE="/usr/include"
PYTHON_LIB="/usr/lib"
AC_MSG_RESULT(/usr)
])
AC_SUBST(PYTHON_INCLUDE)
AC_SUBST(PYTHON_LIB)
# Checks for libraries.
original_LIBS="${LIBS}"
AC_MSG_NOTICE([checking for libraries])
@ -138,6 +152,8 @@ AC_CHECK_LIB([xml2], [xmlInitParser], [], [AC_MSG_ERROR([couldn't find a suitabl
LIBS="-L${APR_LIB} ${original_LIBS}"
AC_CHECK_LIB([apr-1], [apr_pool_initialize], [], [AC_MSG_ERROR([couldn't find a suitable libapr-1, use --with-apr=PATH])])
AC_CHECK_LIB([aprutil-1], [apr_memcache_replace], [], [AC_MSG_ERROR([couldn't find a suitable libaprutil-1, use --with-apr=PATH])])
LIBS="-L${PYTHON_LIB} ${original_LIBS}"
AC_CHECK_LIB([python2.6], [Py_Initialize], [], [AC_MSG_ERROR([couldn't find a suitable libpython2.6, use --with-python=PATH])])
LIBS="${original_LIBS}"
# Checks for header files.
@ -175,7 +191,7 @@ AC_ARG_ENABLE(maintainer-mode, [AS_HELP_STRING([--enable-maintainer-mode], [comp
esac ],
[ AC_MSG_RESULT(no)])
if test "${want_maintainer_mode}" = "true"; then
cxxflags="${cxxflags} -D_DEBUG -O0 -g3 -Werror -Wall -Wextra -Wno-ignored-qualifiers -Winit-self -Wmissing-include-dirs -Wcast-qual -Wcast-align -Wwrite-strings -Wpointer-arith -Wconversion -Waddress -Wlogical-op -Wredundant-decls -std=c++0x -fmessage-length=0"
cxxflags="${cxxflags} -D_DEBUG -O0 -ggdb -g3 -Werror -Wall -Wextra -Wno-ignored-qualifiers -Winit-self -Wmissing-include-dirs -Wcast-qual -Wcast-align -Wwrite-strings -Wpointer-arith -Wconversion -Waddress -Wlogical-op -Wredundant-decls -std=c++0x -fmessage-length=0"
ldflags="${ldflags} -pg"
else
cxxflags="${cxxflags} -O3 -std=c++0x -fmessage-length=0"
@ -256,9 +272,10 @@ AC_CONFIG_FILES([Makefile
kernel/Makefile
modules/Makefile
modules/atom/Makefile
modules/eval/Makefile
modules/scheme/Makefile
modules/http/Makefile
modules/json/Makefile
modules/python/Makefile
modules/scdl/Makefile
modules/server/Makefile
components/Makefile

View file

@ -0,0 +1,31 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
noinst_PROGRAMS = python-test python-shell
datadir=$(prefix)/modules/python
nobase_data_DATA = *.xsd
INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} -I${APR_INCLUDE} -I${PYTHON_INCLUDE}
python_test_SOURCES = python-test.cpp
python_test_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${PYTHON_LIB} -lpython2.6
python_shell_SOURCES = python-shell.cpp
python_shell_LDADD = -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${PYTHON_LIB} -lpython2.6
TESTS = python-test

View file

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* $Rev$ $Date$ */
#ifndef tuscany_python_pydriver_hpp
#define tuscany_python_pydriver_hpp
/**
* Python evaluator main driver loop.
*/
#include "string.hpp"
#include "stream.hpp"
#include "monad.hpp"
#include "eval.hpp"
namespace tuscany {
namespace python {
const string evalOutputPrompt("; ");
const string evalInputPrompt("=> ");
const bool promptForInput(const string& str, ostream& out) {
out << endl << endl << str;
return true;
}
const bool announceOutput(const string str, ostream& out) {
out << endl << str;
return true;
}
const bool userPrint(const value val, ostream& out) {
writeValue(val, out);
return true;
}
const value evalDriverLoop(PyObject* script, istream& in, ostream& out, const gc_pool& pool) {
promptForInput(evalInputPrompt, out);
value input = readValue(in);
if (isNil(input))
return input;
const value output = evalScript(input, script, pool);
announceOutput(evalOutputPrompt, out);
userPrint(output, out);
return evalDriverLoop(script, in, out, pool);
}
const bool evalDriverRun(istream& in, ostream& out, const gc_pool& pool) {
setupDisplay(out);
evalDriverLoop(builtin(pythonRuntime), in, out, pool);
return true;
}
const bool evalDriverRun(const char* path, istream& in, ostream& out, const gc_pool& pool) {
setupDisplay(out);
ifstream is(path);
failable<PyObject*> script = readScript(path, is);
if (!hasContent(script))
return true;
evalDriverLoop(content(script), in, out, pool);
Py_DECREF(content(script));
return true;
}
}
}
#endif /* tuscany_scheme_pydriver_hpp */

View file

@ -0,0 +1,286 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* $Rev$ $Date$ */
#ifndef tuscany_python_pyeval_hpp
#define tuscany_python_pyeval_hpp
/**
* Python script evaluation logic.
*/
#include <python2.6/Python.h>
#include "list.hpp"
#include "value.hpp"
#include "io.hpp"
namespace tuscany {
namespace python {
/**
* Initialize the Python runtime.
*/
class PythonRuntime {
public:
PythonRuntime() {
Py_Initialize();
// Import the builtin module
PyObject* p = PyString_FromString("__builtin__");
builtin = PyImport_Import(p);
Py_DECREF(p);
setupIO();
}
~PythonRuntime() {
Py_DECREF(builtin);
}
private:
friend PyObject* builtin(const PythonRuntime& r);
PyObject* builtin;
} pythonRuntime;
PyObject* builtin(const PythonRuntime& r) {
return r.builtin;
}
/**
* Declare conversion functions.
*/
PyObject* valueToPyObject(const value& v);
const value pyObjectToValue(PyObject *o);
PyObject* valuesToPyTuple(const list<value>& v);
const list<value> pyTupleToValues(PyObject* o);
/**
* Callable python type used to represent a lambda expression.
*/
typedef struct {
PyObject_HEAD
lambda<value(const list<value>&)> func;
} pyLambda;
void pyLambda_dealloc(PyObject* self) {
PyMem_DEL(self);
}
PyObject* pyLambda_call(PyObject* self, PyObject* args, unused PyObject* kwds) {
const pyLambda* pyl = (pyLambda*)self;
const value result = pyl->func(pyTupleToValues(args));
Py_DECREF(args);
PyObject *pyr = valueToPyObject(result);
return pyr;
}
PyTypeObject pyLambda_type = {
PyObject_HEAD_INIT(0)
0,
"lambda",
sizeof(pyLambda),
0,
(destructor)pyLambda_dealloc,
0, 0, 0, 0, 0, 0, 0, 0, 0,
(ternaryfunc)pyLambda_call,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0
};
/**
* Create a new python object representing a lambda expression.
*/
PyObject *mkPyLambda(const lambda<value(const list<value>&)> l) {
pyLambda* pyl = NULL;
pyl = PyObject_NEW(pyLambda, &pyLambda_type);
if (pyl != NULL)
pyl->func = l;
return (PyObject *)pyl;
}
/**
* Convert a list of values to a python list.
*/
PyObject* valuesToPyListHelper(PyObject* l, const list<value>& v) {
if (isNil(v))
return l;
PyList_Append(l, valueToPyObject(car(v)));
return valuesToPyListHelper(l, cdr(v));
}
PyObject* valuesToPyTuple(const list<value>& v) {
return PyList_AsTuple(valuesToPyListHelper(PyList_New(0), v));
}
/**
* Convert a value to a python object.
*/
PyObject* valueToPyObject(const value& v) {
switch (type(v)) {
case value::List:
return valuesToPyTuple(v);
case value::Lambda:
return mkPyLambda(v);
case value::Symbol:
case value::String:
return PyString_FromString(c_str(v));
case value::Number:
return PyFloat_FromDouble((double)v);
case value::Bool:
return (bool)v? Py_True : Py_False;
case value::Char:
return PyInt_FromLong((long)((char)v));
case value::Ptr:
return NULL;
default:
return NULL;
}
}
/**
* Convert a python tuple to a list of values.
*/
const list<value> pyTupleToValuesHelper(PyObject* o, int i, int size) {
if (i == size)
return list<value>();
return cons(pyObjectToValue(PyTuple_GetItem(o, i)), pyTupleToValuesHelper(o, i + 1, size));
}
const list<value> pyTupleToValues(PyObject* o) {
return pyTupleToValuesHelper(o, 0, PyTuple_Size(o));
}
/**
* Lambda function used to represent a python callable object.
*/
struct pyCallable {
PyObject* func;
pyCallable(PyObject* func) : func(func) {
Py_INCREF(func);
}
~pyCallable() {
Py_DECREF(func);
}
const value operator()(const list<value>& args) const {
PyObject* pyargs = valuesToPyTuple(args);
PyObject* result = PyObject_CallObject(func, pyargs);
Py_DECREF(pyargs);
const value v = pyObjectToValue(result);
Py_DECREF(result);
return v;
}
};
/**
* Convert a python object to a value.
*/
const value pyObjectToValue(PyObject *o) {
if (PyString_Check(o))
return value(string(PyString_AsString(o)));
if (PyBool_Check(o))
return value(o == Py_True);
if (PyInt_Check(o))
return value((double)PyInt_AsLong(o));
if (PyLong_Check(o))
return value((double)PyLong_AsLong(o));
if (PyFloat_Check(o))
return value((double)PyFloat_AsDouble(o));
if (PyTuple_Check(o))
return pyTupleToValues(o);
if (PyCallable_Check(o))
return lambda<value(const list<value>&)>(pyCallable(o));
return value();
}
/**
* Read a python script from an input stream.
*/
const failable<PyObject*> readScript(const string& path, istream& is) {
const list<string> ls = streamList(is);
ostringstream os;
write(ls, os);
PyObject* code = Py_CompileStringFlags(c_str(str(os)), c_str(path), Py_file_input, NULL);
if (code == NULL)
return mkfailure<PyObject*>(string("Couldn't compile script: ") + path + " : " + lastError());
PyObject* mod = PyImport_ExecCodeModule(const_cast<char*>(c_str(path)), code);
if (mod == NULL)
return mkfailure<PyObject*>(string("Couldn't import module: ") + path + " : " + lastError());
return mod;
}
/**
* Evaluate an expression against a script provided as a python object.
*/
const failable<value> evalScript(const value& expr, PyObject* script, unused const gc_pool& pool) {
// Get the requested function
PyObject* func = PyObject_GetAttrString(script, c_str(car<value>(expr)));
if (func == NULL)
return mkfailure<value>(string("Couldn't find function: ") + car<value>(expr) + " : " + lastError());
if (!PyCallable_Check(func)) {
Py_DECREF(func);
return mkfailure<value>(string("Couldn't find callable function: ") + car<value>(expr));
}
// Convert args to python objects
PyObject* args = valuesToPyTuple(cdr<value>(expr));
// Call the function
PyObject* result = PyObject_CallObject(func, args);
Py_DECREF(args);
Py_DECREF(func);
if (result == NULL)
return mkfailure<value>(string("Function call failed: ") + car<value>(expr) + " : " + lastError());
// Convert python result to a value
const value v = pyObjectToValue(result);
Py_DECREF(result);
return v;
}
/**
* Evaluate an expression against a script provided as an input stream.
*/
const failable<value> evalScript(const value& expr, istream& is, unused const gc_pool& pool) {
failable<PyObject*> script = readScript("script", is);
if (!hasContent(script))
return mkfailure<value>(reason(script));
return evalScript(expr, content(script), pool);
}
/**
* Evaluate an expression against the python builtin module, no script is provided.
*/
const failable<value> evalExpr(const value& expr, const gc_pool& pool) {
return evalScript(expr, builtin(pythonRuntime), pool);
}
}
}
#endif /* tuscany_python_pyeval_hpp */

View file

@ -0,0 +1,167 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* $Rev$ $Date$ */
#ifndef tuscany_python_pyio_hpp
#define tuscany_python_pyio_hpp
/**
* Hooks used to capture python stdout and stderr.
*/
#include <python2.6/Python.h>
#include "stream.hpp"
#include "../scheme/io.hpp"
namespace tuscany {
namespace python {
#ifdef _REENTRANT
__thread
#endif
ostream* displayOutStream = NULL;
#ifdef _REENTRANT
__thread
#endif
ostream* logOutStream = NULL;
/**
* Setup the display stream.
*/
const bool setupDisplay(ostream& out) {
scheme::setupDisplay(out);
displayOutStream = &out;
return true;
}
ostream& displayStream() {
if (displayOutStream == NULL)
return cout;
return *displayOutStream;
}
/**
* Setup the log stream.
*/
const bool setupLog(ostream& out) {
scheme::setupLog(out);
logOutStream = &out;
return true;
}
ostream& logStream() {
if (logOutStream == NULL)
return cerr;
return *logOutStream;
}
/**
* Hook method used to redirect python output to a stream.
*/
PyObject* display(unused PyObject* self, PyObject* args) {
char* s = NULL;
if (!PyArg_ParseTuple(args, "s", &s))
return NULL;
displayStream() << s;
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef displayHookMethods[] = {
{"display", display, METH_VARARGS, "Redirects stdout"},
{NULL, NULL, 0, NULL}};
/**
* Hook method used to redirect python errors to a stream.
*/
PyObject* log(unused PyObject* self, PyObject* args) {
char* s = NULL;
if (!PyArg_ParseTuple(args, "s", &s))
return NULL;
logStream() << s;
Py_INCREF(Py_None);
return Py_None;
}
PyMethodDef logHookMethods[] = {
{"log", log, METH_VARARGS, "Redirects stdout"},
{NULL, NULL, 0, NULL}};
/**
* Setup the display and log hooks.
*/
bool setupIO() {
Py_InitModule("displayhook", displayHookMethods);
PyRun_SimpleString(
"import sys\n"
"import displayhook\n"
"\n"
"class DisplayHook:\n"
" def write(self, text):\n"
" displayhook.display(text)\n"
"\n"
"sys.stdout = DisplayHook()\n");
Py_InitModule("loghook", logHookMethods);
PyRun_SimpleString(
"import sys\n"
"import loghook\n"
"\n"
"class LogHook:\n"
" def write(self, text):\n"
" loghook.log(text)\n"
"\n"
"sys.stderr = LogHook()\n");
return true;
}
/**
* Return the last python error.
*/
const string lastError() {
ostream* pos = logOutStream;
ostringstream eos;
logOutStream = &eos;
if (PyErr_Occurred())
PyErr_Print();
logOutStream = pos;
return str(eos);
}
/**
* Read and write values (using the scheme representation as it's the canonical
* representation used throughout the runtime.)
*/
const value readValue(istream& in) {
return scheme::readValue(in);
}
const bool writeValue(const value& val, ostream& out) {
return scheme::writeValue(val, out);
}
}
}
#endif /* tuscany_python_pyio_hpp */

View file

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* $Rev$ $Date$ */
/**
* Python script evaluator shell, used for interactive testing of scripts.
*/
#include <assert.h>
#include "gc.hpp"
#include "stream.hpp"
#include "string.hpp"
#include "driver.hpp"
int main(const int argc, char** argv) {
tuscany::gc_scoped_pool pool;
if (argc == 1) {
tuscany::python::evalDriverRun(tuscany::cin, tuscany::cout, pool);
return 0;
}
tuscany::python::evalDriverRun(argv[1], tuscany::cin, tuscany::cout, pool);
return 0;
}

View file

@ -0,0 +1,135 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* $Rev$ $Date$ */
/**
* Test Python script evaluator.
*/
#include <assert.h>
#include "stream.hpp"
#include "string.hpp"
#include "driver.hpp"
namespace tuscany {
namespace python {
const value evalBuiltin(const string& py, const gc_pool& pool) {
istringstream is(py);
ostringstream os;
evalDriverRun(is, os, pool);
return str(os);
}
const string testPythonPrint(
"(print \"testPrint ok\")");
bool testEval() {
gc_scoped_pool pool;
assert(contains(evalBuiltin(testPythonPrint, pool), "testPrint ok"));
return true;
}
const string testPythonAdd =
"def add(x, y):\n"
" return x + y\n";
bool testEvalExpr() {
gc_scoped_pool pool;
{
const value exp = mklist<value>("abs", -5);
const failable<value> r = evalExpr(exp, pool);
assert(hasContent(r));
assert(content(r) == value(5));
}
{
istringstream is(testPythonAdd);
failable<PyObject*> script = readScript("script", is);
assert(hasContent(script));
const value exp = mklist<value>("add", 2, 3);
const failable<value> r = evalScript(exp, content(script), pool);
assert(hasContent(r));
assert(content(r) == value(5));
}
return true;
}
bool testEvalRun() {
gc_scoped_pool pool;
evalDriverRun(cin, cout, pool);
return true;
}
const value mult(const list<value>& args) {
const double x = car(args);
const double y = cadr(args);
return x * y;
}
const string testReturnLambda(
"def mul(x, y):\n"
" return x * y\n"
"\n"
"def testReturnLambda():\n"
" return mul\n");
const string testCallLambda(
"def testCallLambda(l, x, y):\n"
" return l(x, y)\n");
bool testEvalLambda() {
gc_scoped_pool pool;
const value trl = mklist<value>("testReturnLambda");
istringstream trlis(testReturnLambda);
const failable<value> trlv = evalScript(trl, trlis, pool);
assert(hasContent(trlv));
assert(isLambda(content(trlv)));
const lambda<value(const list<value>&)> trll(content(trlv));
assert(trll(mklist<value>(2, 3)) == value(6));
istringstream tclis(testCallLambda);
const value tcl = mklist<value>("testCallLambda", content(trlv), 2, 3);
const failable<value> tclv = evalScript(tcl, tclis, pool);
assert(hasContent(tclv));
assert(content(tclv) == value(6));
istringstream tcelis(testCallLambda);
const value tcel = mklist<value>("testCallLambda", lambda<value(const list<value>&)>(mult), 3, 4);
const failable<value> tcelv = evalScript(tcel, tcelis, pool);
assert(hasContent(tcelv));
assert(content(tcelv) == value(12));
return true;
}
}
}
int main() {
tuscany::cout << "Testing..." << tuscany::endl;
tuscany::python::testEval();
tuscany::python::testEvalExpr();
tuscany::python::testEvalLambda();
tuscany::cout << "OK" << tuscany::endl;
return 0;
}

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://tuscany.apache.org/xmlns/sca/1.1"
xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200903"
xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
elementFormDefault="qualified">
<import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200903" schemaLocation="sca-1.1-cd04.xsd"/>
<element name="implementation.python" type="t:PythonImplementation" substitutionGroup="sca:implementation"/>
<complexType name="PythonImplementation">
<complexContent>
<extension base="sca:Implementation">
<sequence>
<any namespace="##targetNamespace" processContents="lax"
minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="location" type="anyURI" use="required"/>
<anyAttribute namespace="##any" processContents="lax"/>
</extension>
</complexContent>
</complexType>
</schema>