diff options
Diffstat (limited to 'sca-cpp/branches/cpp-contrib/modules/python')
15 files changed, 1051 insertions, 0 deletions
diff --git a/sca-cpp/branches/cpp-contrib/modules/python/Makefile.am b/sca-cpp/branches/cpp-contrib/modules/python/Makefile.am new file mode 100644 index 0000000000..5d634a446c --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/Makefile.am @@ -0,0 +1,45 @@ +# 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. + +datadir=$(prefix)/modules/python +libdir=$(prefix)/lib + +if WANT_PYTHON + +noinst_PROGRAMS = python-test python-shell client-test + +lib_LTLIBRARIES = libmod_tuscany_python.la + +nobase_data_DATA = *.xsd + +INCLUDES = -I${PYTHON_INCLUDE} + +libmod_tuscany_python_la_SOURCES = mod-python.cpp +libmod_tuscany_python_la_LDFLAGS = -lxml2 -lcurl -lmozjs -L${PYTHON_LIB} -R${PYTHON_LIB} -lpython2.6 + +python_test_SOURCES = python-test.cpp +python_test_LDFLAGS = -L${PYTHON_LIB} -R${PYTHON_LIB} -lpython2.6 + +python_shell_SOURCES = python-shell.cpp +python_shell_LDFLAGS = -L${PYTHON_LIB} -R${PYTHON_LIB} -lpython2.6 + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +TESTS = python-test server-test + +endif diff --git a/sca-cpp/branches/cpp-contrib/modules/python/client-test.cpp b/sca-cpp/branches/cpp-contrib/modules/python/client-test.cpp new file mode 100644 index 0000000000..b070f6a798 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/client-test.cpp @@ -0,0 +1,46 @@ +/* + * 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 HTTP client functions. + */ + +#include "stream.hpp" +#include "string.hpp" +#include "../server/client-test.hpp" + +namespace tuscany { +namespace server { + +string testURI = "http://localhost:8090/python"; + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::server::testServer(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/cpp-contrib/modules/python/client-test.py b/sca-cpp/branches/cpp-contrib/modules/python/client-test.py new file mode 100644 index 0000000000..47e6cf4bda --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/client-test.py @@ -0,0 +1,35 @@ +# 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. + +# JSON-RPC test case + +def echo(x, ref): + return ref("echo", x) + +# ATOMPub test case + +def get(id, ref): + return ref("get", id) + +def post(collection, item, ref): + return ref("post", collection, item) + +def put(id, item, ref): + return ref("put", id, item) + +def delete(id, ref): + return ref("delete", id) diff --git a/sca-cpp/branches/cpp-contrib/modules/python/domain-test.composite b/sca-cpp/branches/cpp-contrib/modules/python/domain-test.composite new file mode 100644 index 0000000000..c8e92b286e --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/domain-test.composite @@ -0,0 +1,42 @@ +<?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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1" + targetNamespace="http://domain/test" + name="domain-test"> + + <component name="python-test"> + <t:implementation.python script="server-test.py"/> + <service name="test"> + <t:binding.http uri="python"/> + </service> + </component> + + <component name="client-test"> + <t:implementation.python script="client-test.py"/> + <service name="client"> + <t:binding.http uri="client"/> + </service> + <reference name="ref" target="python-test"> + <t:binding.http/> + </reference> + </component> + +</composite> diff --git a/sca-cpp/branches/cpp-contrib/modules/python/driver.hpp b/sca-cpp/branches/cpp-contrib/modules/python/driver.hpp new file mode 100644 index 0000000000..2820201057 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/driver.hpp @@ -0,0 +1,63 @@ +/* + * 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_driver_hpp +#define tuscany_python_driver_hpp + +/** + * Python evaluator main driver loop. + */ + +#include "string.hpp" +#include "stream.hpp" +#include "monad.hpp" +#include "../scheme/driver.hpp" +#include "eval.hpp" + +namespace tuscany { +namespace python { + +const value evalDriverLoop(PyObject* script, istream& in, ostream& out) { + scheme::promptForInput(scheme::evalInputPrompt, out); + value input = scheme::readValue(in); + if (isNil(input)) + return input; + const failable<value> output = evalScript(input, script); + scheme::announceOutput(scheme::evalOutputPrompt, out); + scheme::userPrint(content(output), out); + return evalDriverLoop(script, in, out); +} + +const bool evalDriverRun(const char* path, istream& in, ostream& out) { + PythonRuntime py; + scheme::setupDisplay(out); + ifstream is(path); + failable<PyObject*> script = readScript(path, is); + if (!hasContent(script)) + return true; + evalDriverLoop(content(script), in, out); + Py_DECREF(content(script)); + return true; +} + +} +} +#endif /* tuscany_python_driver_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/modules/python/eval.hpp b/sca-cpp/branches/cpp-contrib/modules/python/eval.hpp new file mode 100644 index 0000000000..855804a5ae --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/eval.hpp @@ -0,0 +1,300 @@ +/* + * 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_eval_hpp +#define tuscany_python_eval_hpp + +/** + * Python script evaluation logic. + */ +#include <python2.6/Python.h> + +#include "list.hpp" +#include "value.hpp" + +namespace tuscany { +namespace python { + +/** + * Represent a Python runtime. + */ +class PythonRuntime { +public: + PythonRuntime() { + if (Py_IsInitialized()) + return; + Py_InitializeEx(0); + } +}; + +/** + * Return the last python error. + */ +const string lastError() { + if(PyErr_Occurred()) { + PyObject* type; + PyObject* val; + PyObject* trace; + PyErr_Fetch(&type, &val, &trace); + if (type != NULL && val != NULL) { + PyObject* stype = PyObject_Str(type); + PyObject* sval = PyObject_Str(val); + string msg = string() + PyString_AsString(stype) + " : " + PyString_AsString(sval); + Py_DECREF(stype); + Py_DECREF(sval); + Py_DECREF(type); + Py_DECREF(val); + Py_XDECREF(trace); + PyErr_Print(); + return msg; + } + PyErr_Print(); + Py_XDECREF(type); + Py_XDECREF(val); + Py_XDECREF(trace); + PyErr_Print(); + return "Unknown Python error"; + } + return ""; +} + +/** + * 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: + return PyString_FromString(c_str(string("'") + v)); + 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; + default: + return Py_None; + } +} + +/** + * Convert a python tuple to a list of values. + */ + +const list<value> pyTupleToValuesHelper(PyObject* o, const int i, const 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)) { + const char* s = PyString_AsString(o); + if (*s == '\'') + return value(s + 1); + return value(string(s)); + } + 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(); +} + +/** + * Evaluate an expression against a script provided as a python object. + */ +const failable<value> evalScript(const value& expr, PyObject* script) { + + // Get the requested function + PyObject* func = PyObject_GetAttrString(script, c_str(car<value>(expr))); + if (func == NULL) { + + // The start, stop, and restart functions are optional + const value fn = car<value>(expr); + if (fn == "start" || fn == "stop") { + PyErr_Clear(); + return value(lambda<value(const list<value>&)>()); + } + + 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; +} + +/** + * 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 an input stream. + */ +const failable<value> evalScript(const value& expr, istream& is) { + failable<PyObject*> script = readScript("script", is); + if (!hasContent(script)) + return mkfailure<value>(reason(script)); + return evalScript(expr, content(script)); +} + +} +} +#endif /* tuscany_python_eval_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/modules/python/mod-python.cpp b/sca-cpp/branches/cpp-contrib/modules/python/mod-python.cpp new file mode 100644 index 0000000000..8561a1fbf4 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/mod-python.cpp @@ -0,0 +1,66 @@ +/* + * 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$ */ + +/** + * HTTPD module used to eval Python component implementations. + */ + +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "../server/mod-cpp.hpp" +#include "../server/mod-eval.hpp" +#include "mod-python.hpp" + +namespace tuscany { +namespace server { +namespace modeval { + +/** + * Apply a lifecycle start or restart event. + */ +const value applyLifecycle(unused const list<value>& params) { + + // Create a Python runtime + new (gc_new<python::PythonRuntime>()) python::PythonRuntime(); + + // Return a nil function as we don't need to handle the stop event + return failable<value>(lambda<value(const list<value>&)>()); +} + +/** + * Evaluate a Python component implementation and convert it to an applicable + * lambda function. + */ +const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, unused const lambda<value(const list<value>&)>& lifecycle) { + const string itype(elementName(impl)); + if (contains(itype, ".python")) + return modpython::evalImplementation(path, impl, px); + if (contains(itype, ".cpp")) + return modcpp::evalImplementation(path, impl, px); + return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype); +} + +} +} +} diff --git a/sca-cpp/branches/cpp-contrib/modules/python/mod-python.hpp b/sca-cpp/branches/cpp-contrib/modules/python/mod-python.hpp new file mode 100644 index 0000000000..d13f2227ab --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/mod-python.hpp @@ -0,0 +1,79 @@ +/* + * 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_modpython_hpp +#define tuscany_modpython_hpp + +/** + * Evaluation functions used by mod-eval to evaluate Python + * component implementations. + */ + +#include "string.hpp" +#include "stream.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "eval.hpp" + +namespace tuscany { +namespace server { +namespace modpython { + +/** + * Apply a Python component implementation function. + */ +struct applyImplementation { + PyObject* impl; + const list<value> px; + applyImplementation(PyObject* impl, const list<value>& px) : impl(impl), px(px) { + } + const value operator()(const list<value>& params) const { + const value expr = append<value>(params, px); + debug(expr, "modeval::python::applyImplementation::input"); + const failable<value> res = python::evalScript(expr, impl); + const value val = !hasContent(res)? mklist<value>(value(), reason(res)) : mklist<value>(content(res)); + debug(val, "modeval::python::applyImplementation::result"); + return val; + } +}; + +/** + * Evaluate a Python component implementation and convert it to an applicable + * lambda function. + */ +const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px) { + const string fpath(path + attributeValue("script", impl)); + ifstream is(fpath); + if (fail(is)) + return mkfailure<lambda<value(const list<value>&)> >(string("Could not read implementation: ") + fpath); + const failable<PyObject*> script = python::readScript(fpath, is); + if (!hasContent(script)) + return mkfailure<lambda<value(const list<value>&)> >(reason(script)); + return lambda<value(const list<value>&)>(applyImplementation(content(script), px)); +} + +} +} +} + +#endif /* tuscany_modpython_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/modules/python/python-conf b/sca-cpp/branches/cpp-contrib/modules/python/python-conf new file mode 100755 index 0000000000..9bc99e2bbe --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/python-conf @@ -0,0 +1,26 @@ +#!/bin/sh + +# 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. + +# Generate a Python server conf +here=`readlink -f $0`; here=`dirname $here` +root=`readlink -f $1` + +cat >>$root/conf/httpd.conf <<EOF +LoadModule mod_tuscany_eval $here/.libs/libmod_tuscany_python.so +EOF diff --git a/sca-cpp/branches/cpp-contrib/modules/python/python-shell.cpp b/sca-cpp/branches/cpp-contrib/modules/python/python-shell.cpp new file mode 100644 index 0000000000..89b47b8d44 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/python-shell.cpp @@ -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 != 2) { + tuscany::cerr << "Usage: python-shell <script.py>" << tuscany::endl; + return 1; + } + tuscany::python::evalDriverRun(argv[1], tuscany::cin, tuscany::cout); + return 0; +} diff --git a/sca-cpp/branches/cpp-contrib/modules/python/python-test.cpp b/sca-cpp/branches/cpp-contrib/modules/python/python-test.cpp new file mode 100644 index 0000000000..c4ffcee57e --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/python-test.cpp @@ -0,0 +1,109 @@ +/* + * 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 string testPythonAdd = + "def add(x, y):\n" + " return x + y\n"; + +bool testEvalExpr() { + gc_scoped_pool pool; + PythonRuntime py; + + 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)); + assert(hasContent(r)); + assert(content(r) == value(5)); + + 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; + PythonRuntime py; + + const value trl = mklist<value>("testReturnLambda"); + istringstream trlis(testReturnLambda); + const failable<value> trlv = evalScript(trl, trlis); + + 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); + 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); + assert(hasContent(tcelv)); + assert(content(tcelv) == value(12)); + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::python::testEvalExpr(); + tuscany::python::testEvalLambda(); + + tuscany::cout << "OK" << tuscany::endl; + return 0; +} diff --git a/sca-cpp/branches/cpp-contrib/modules/python/server-test b/sca-cpp/branches/cpp-contrib/modules/python/server-test new file mode 100755 index 0000000000..fe1ff7a486 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/server-test @@ -0,0 +1,39 @@ +#!/bin/sh + +# 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. + +# Setup +../http/httpd-conf tmp 8090 ../server/htdocs +../server/server-conf tmp +./python-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite domain-test.composite +EOF + +../http/httpd-start tmp +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +../http/httpd-stop tmp +sleep 2 +return $rc diff --git a/sca-cpp/branches/cpp-contrib/modules/python/server-test.py b/sca-cpp/branches/cpp-contrib/modules/python/server-test.py new file mode 100644 index 0000000000..8e6b79b56a --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/server-test.py @@ -0,0 +1,42 @@ +# 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. + +# JSON-RPC test case + +def echo(x): + return x + +# ATOMPub test case + +def get(id): + if id == (): + return ("Sample Feed", "123456789", + ("Item", "111", (("'javaClass", "services.Item"), ("'name", "Apple"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 2.99))), + ("Item", "222", (("'javaClass", "services.Item"), ("'name", "Orange"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 3.55))), + ("Item", "333", (("'javaClass", "services.Item"), ("name", "Pear"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 1.55)))) + + entry = (("'javaClass", "services.Item"), ("'name", "Apple"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 2.99)) + return ("Item", id[0], entry) + +def post(collection, item): + return ("123456789",) + +def put(id, item): + return true + +def delete(id): + return true diff --git a/sca-cpp/branches/cpp-contrib/modules/python/tuscany-sca-1.1-implementation-python.xsd b/sca-cpp/branches/cpp-contrib/modules/python/tuscany-sca-1.1-implementation-python.xsd new file mode 100644 index 0000000000..c811ba6729 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/tuscany-sca-1.1-implementation-python.xsd @@ -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/200912" + xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1" + elementFormDefault="qualified"> + + <import namespace="http://docs.oasis-open.org/ns/opencsa/sca/200912" 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="script" type="anyURI" use="required"/> + <anyAttribute namespace="##any" processContents="lax"/> + </extension> + </complexContent> + </complexType> + +</schema> diff --git a/sca-cpp/branches/cpp-contrib/modules/python/wiring-test b/sca-cpp/branches/cpp-contrib/modules/python/wiring-test new file mode 100755 index 0000000000..a3c85838fd --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/python/wiring-test @@ -0,0 +1,76 @@ +#!/bin/sh + +# 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. + +echo "Testing..." + +# Setup +../http/httpd-conf tmp 8090 ../server/htdocs +../server/server-conf tmp +./python-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite domain-test.composite +EOF + +../http/httpd-start tmp +sleep 2 + +# Test HTTP GET +curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html +diff tmp/index.html ../server/htdocs/index.html +rc=$? + +# Test ATOMPub +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/ >tmp/feed.xml 2>/dev/null + diff tmp/feed.xml ../server/htdocs/feed.xml + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/111 >tmp/entry.xml 2>/dev/null + diff tmp/entry.xml ../server/htdocs/entry.xml + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/ -X POST -H "Content-type: application/atom+xml" --data @../server/htdocs/entry.xml 2>/dev/null + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/111 -X PUT -H "Content-type: application/atom+xml" --data @../server/htdocs/entry.xml 2>/dev/null + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/111 -X DELETE 2>/dev/null + rc=$? +fi + +# Test JSON-RPC +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/ -X POST -H "Content-type: application/json-rpc" --data @../server/htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null + diff tmp/json-result.txt ../server/htdocs/json-result.txt + rc=$? +fi + +# Cleanup +../http/httpd-stop tmp +sleep 2 +if [ "$rc" = "0" ]; then + echo "OK" +fi +return $rc |