From dbda4a4d7bc0d90dfd08fa0b1bab907c035d046c Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Tue, 28 Jun 2016 16:37:36 +0100 Subject: [PATCH] vfs/stream --- packages/python/pl2pl.c | 119 +++++++++++++++++++++++ packages/python/yap_kernel/__init__.py | 3 + packages/python/yap_kernel/__main__.py | 6 ++ packages/python/yap_kernel/images.py | 48 +++++++++ packages/python/yap_kernel/install.py | 44 +++++++++ packages/python/yap_kernel/setup.py | 58 +++++++++++ packages/python/yap_kernel/yap_kernel.py | 86 ++++++++++++++++ 7 files changed, 364 insertions(+) create mode 100644 packages/python/pl2pl.c create mode 100644 packages/python/yap_kernel/__init__.py create mode 100644 packages/python/yap_kernel/__main__.py create mode 100644 packages/python/yap_kernel/images.py create mode 100644 packages/python/yap_kernel/install.py create mode 100644 packages/python/yap_kernel/setup.py create mode 100644 packages/python/yap_kernel/yap_kernel.py diff --git a/packages/python/pl2pl.c b/packages/python/pl2pl.c new file mode 100644 index 000000000..4cd532168 --- /dev/null +++ b/packages/python/pl2pl.c @@ -0,0 +1,119 @@ + +#include "python.h" + +static foreign_t array_to_python_list(term_t addr, term_t type, term_t szt, + term_t py) { + void *src; + Py_ssize_t sz, i; + int is_float; + + if (!PL_get_pointer(addr, &src) || !PL_get_bool(type, &is_float) || + !PL_get_intptr(szt, &sz)) + return false; + PyObject *list = PyList_New(sz); + if (!list) + return false; + if (is_float) { + double *v = (double *)src; + for (i = 0; i < sz; i++) { + PyObject *x = PyFloat_FromDouble(v[i]); + PyList_SET_ITEM(list, i, x); + } + } else { + YAP_Int *v = (YAP_Int *)src; + for (i = 0; i < sz; i++) { + PyObject *x = PyFloat_FromDouble(v[i]); + PyList_SET_ITEM(list, i, x); + } + } + if (PL_is_variable(py)) { + return python_to_ptr(list, py); + } + return assign_to_symbol(py, list); +} + +static foreign_t array_to_python_tuple(term_t addr, term_t type, term_t szt, + term_t py) { + void *src; + Py_ssize_t sz, i; + int is_float; + + if (!PL_get_pointer(addr, &src) || !PL_get_bool(type, &is_float) || + !PL_get_intptr(szt, &sz)) + return false; + PyObject *list = PyTuple_New(sz); + if (!list) + return false; + if (is_float) { + double *v = (double *)src; + + for (i = 0; i < sz; i++) { + PyObject *x; + x = PyFloat_FromDouble(v[i]); + if (PyTuple_SetItem(list, i, x)) { + PyErr_Print(); + return FALSE; + } + } + } else { + int32_t *v = (int32_t *)src; + PyObject *x; + for (i = 0; i < sz; i++) { +#if PY_MAJOR_VERSION < 3 + x = PyInt_FromLong(v[i]); +#else + x = PyLong_FromLong(v[i]); +#endif + if (PyTuple_SetItem(list, i, x)) { + PyErr_Print(); + return FALSE; + } + } + } + if (PL_is_variable(py)) { + return python_to_ptr(list, py); + } + return assign_to_symbol(py, list); +} + +static foreign_t array_to_python_view(term_t addr, term_t type, term_t szt, + term_t colt, term_t py) { + void *src; + Py_ssize_t sz, rows; + int is_float; + Py_ssize_t shape[2]; + + if (!PL_get_pointer(addr, &src) || !PL_get_bool(type, &is_float) || + !PL_get_intptr(szt, &sz) || !PL_get_intptr(colt, &rows)) + return false; + Py_buffer buf; + buf.buf = src; + if (is_float) { + buf.len = sz * sizeof(double); + buf.itemsize = sizeof(double); + } else { + buf.len = sz * sizeof(YAP_Int); + buf.itemsize = sizeof(YAP_Int); + } + buf.readonly = false; + buf.format = NULL; + buf.ndim = 2; + buf.shape = shape; + buf.strides = NULL; + buf.suboffsets = NULL; + PyObject *o = PyMemoryView_FromBuffer(&buf); + if (!o) { + PyErr_Print(); + return false; + } + if (PL_is_variable(py)) { + return python_to_ptr(o, py); + } + return assign_to_symbol(py, o); +} + +install_t install_pl2pl(void) { + PL_register_foreign("array_to_python_list", 4, array_to_python_list, 0); + PL_register_foreign("array_to_python_tuple", 4, array_to_python_tuple, 0); + PL_register_foreign("array_to_python_view", 5, array_to_python_view, 0); +} diff --git a/packages/python/yap_kernel/__init__.py b/packages/python/yap_kernel/__init__.py new file mode 100644 index 000000000..ae45c83a8 --- /dev/null +++ b/packages/python/yap_kernel/__init__.py @@ -0,0 +1,3 @@ +"""A Prolog kernel for Jupyter""" + +__version__ = '0.0.1' diff --git a/packages/python/yap_kernel/__main__.py b/packages/python/yap_kernel/__main__.py new file mode 100644 index 000000000..61e1af4e6 --- /dev/null +++ b/packages/python/yap_kernel/__main__.py @@ -0,0 +1,6 @@ +try: + from ipykernel.kernelapp import IPKernelApp +except ImportError: + from IPython.kernel.zmq.kernelapp import IPKernelApp +from .kernel import YAPKernel +IPKernelApp.launch_instance(kernel_class=YAPKernel) diff --git a/packages/python/yap_kernel/images.py b/packages/python/yap_kernel/images.py new file mode 100644 index 000000000..f7abfbb12 --- /dev/null +++ b/packages/python/yap_kernel/images.py @@ -0,0 +1,48 @@ +import base64 +import imghdr +import os + +#from IPython. + +_TEXT_SAVED_IMAGE = "yap_kernel: saved image data to:" + +image_setup_cmd = """ +display () { + TMPFILE=$(mktemp ${TMPDIR-/tmp}/yap_kernel.XXXXXXXXXX) + cat > $TMPFILE + echo "%s $TMPFILE" >&2 +} +""" % _TEXT_SAVED_IMAGE + +def display_data_for_image(filename): + with open(filename, 'rb') as f: + image = f.read() + os.unlink(filename) + + image_type = imghdr.what(None, image) + if image_type is None: + raise ValueError("Not a valid image: %s" % image) + + image_data = base64.b64encode(image).decode('ascii') + content = { + 'data': { + 'image/' + image_type: image_data + }, + 'metadata': {} + } + return content + + +def extract_image_filenames(output): + output_lines = [] + image_filenames = [] + + for line in output.split("\n"): + if line.startswith(_TEXT_SAVED_IMAGE): + filename = line.rstrip().split(": ")[-1] + image_filenames.append(filename) + else: + output_lines.append(line) + + output = "\n".join(output_lines) + return image_filenames, output diff --git a/packages/python/yap_kernel/install.py b/packages/python/yap_kernel/install.py new file mode 100644 index 000000000..da6ee30dc --- /dev/null +++ b/packages/python/yap_kernel/install.py @@ -0,0 +1,44 @@ +import json +import os +import sys + +try: + from jupyter_client.kernelspec import install_kernel_spec +except ImportError: + from IPython.kernel.kernelspec import install_kernel_spec +from IPython.utils.tempdir import TemporaryDirectory + + +kernel_json = { + "argv": [sys.executable, + "-m", "yap_kernel", + "-f", "{connection_file}"], + "display_name": "yap", + "mimetype": "text/x-prolog", + "language": "prolog", + "name": "yap", +} + +def install_my_kernel_spec(user=False): + with TemporaryDirectory() as td: + os.chmod(td, 0o755) # Starts off as 700, not user readable + with open(os.path.join(td, 'kernel.json'), 'w') as f: + json.dump(kernel_json, f, sort_keys=True) + # TODO: Copy resources once they're specified + + print('Installing IPython kernel spec') + install_kernel_spec(td, 'yap', user=False, replace=True) + +def _is_root(): + return True + try: + return os.geteuid() == 0 + except AttributeError: + return False # assume not an admin on non-Unix platforms + +def main(argv=[]): + user = '--user' in argv or not _is_root() + install_my_kernel_spec(user=user) + +if __name__ == '__main__': + main(argv=sys.argv) diff --git a/packages/python/yap_kernel/setup.py b/packages/python/yap_kernel/setup.py new file mode 100644 index 000000000..9a92eabd5 --- /dev/null +++ b/packages/python/yap_kernel/setup.py @@ -0,0 +1,58 @@ +from distutils.command.install import install +from distutils.core import setup +from distutils import log +import json +import sys +import os + +PY3 = sys.version_info[0] >= 3 + +kernel_json = { + "argv": [sys.executable, + "-m", "yap_kernel", + "-f", "{connection_file}"], + "display_name": "MetaKernel YAP %i" % (3 if PY3 else 2), + "language": "prolog", + "name": "yap_kernel", +} + +class install_with_kernelspec(install): + def run(self): + install.run(self) + from IPython.kernel.kernelspec import install_kernel_spec + from IPython.utils.tempdir import TemporaryDirectory + with TemporaryDirectory() as td: + os.chmod(td, 0o755) # Starts off as 700, not user readable + with open(os.path.join(td, 'kernel.json'), 'w') as f: + json.dump(kernel_json, f, sort_keys=True) + log.info('Installing kernel spec') + try: + install_kernel_spec(td, 'yap_kernel', user=self.user, + replace=True) + except: + install_kernel_spec(td, 'yap_kernel', user=not self.user, + replace=True) + +svem_flag = '--single-version-externally-managed' +if svem_flag in sys.argv: + # Die, setuptools, die. + sys.argv.remove(svem_flag) + +setup(name='yap_kernel', + version='0.0.1', + description='A simple YAP kernel for Jupyter/IPython', + long_description="A simple YAP kernel for Jupyter/IPython, based on MetaKernel", + url="https://github.com/vscosta/yap-6.3", + author='Vitor Santos Costa, based on the metakernel from Douglas Blank', + author_email='vsc@dcc.fc.up.pt', + py_modules=['yap_kernel'], + install_requires=["metakernel","yap"], + cmdclass={'install': install_with_kernelspec}, + classifiers = [ + 'Framework :: IPython', + 'License :: OSI Approved :: BSD License', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 2', + 'Topic :: System :: Shells', + ] +) diff --git a/packages/python/yap_kernel/yap_kernel.py b/packages/python/yap_kernel/yap_kernel.py new file mode 100644 index 000000000..f8c5c9dab --- /dev/null +++ b/packages/python/yap_kernel/yap_kernel.py @@ -0,0 +1,86 @@ +from __future__ import print_function + +from metakernel import MetaKernel + +import signal +import yap + +class MetaKernelyap(MetaKernel): + implementation = 'MetaKernel YAP' + implementation_version = '1.0' + language = 'text' + language_version = '0.1' + banner = "MetaKernel YAP" + language_info = { + 'mimetype': 'text/plain', + 'name': 'text', + # ------ If different from 'language': + 'codemirror_mode': { + "version": 2, + "name": "prolog" + }, + 'pygments_lexer': 'prolog', + 'version' : "0.0.1", + 'file_extension': '.yap', + 'help_links': MetaKernel.help_links, + } + + def __init__(self, **kwargs): + + MetaKernel.__init__(self, **kwargs) + self._start_yap() + + def _start_yap(self): + # Signal handlers are inherited by forked processes, and we can't easily + # reset it from the subprocess. Since kernelapp ignores SIGINT except in + # message handlers, we need to temporarily reset the SIGINT handler here + # so that yap and its children are interruptible. + #sig = signal.signal(signal.SIGINT, signal.SIG_DFL) + #try: + self.engine = yap.YAPEngine() + self.q = None + #engine.query("load_files(library(python), [])").command() + banner = "YAP {0} Kernel".format(self.engine.version()) + + #finally: + # signal.signal(signal.SIGINT, sig) + + # Register Yap function to write image data to temporary file + #self.yapwrapper.run_command(image_setup_cmd) + + def get_usage(self): + return "This is the YAP kernel." + + def do_execute_direct(self, code): + if not code.strip(): + return "" + + interrupted = False + try: + if self.q is None: + self.q = self.engine.query(code.rstrip()) + if self.q.next(): + vs = self.q.namedVars() + if vs: + l = {} + for eq in vs: + l[eq.getArg(1)] = eq.getArg(2) + return l + else: + return 'yes' + else: + return 'no' + except KeyboardInterrupt: + return 'stopped by user' + + + + def repr(self, data): + return repr(data) + +if __name__ == '__main__': + try: + from ipykernel.kernelapp import IPKernelApp + except ImportError: + from IPython.kernel.zmq.kernelapp import IPKernelApp + IPKernelApp.launch_instance(kernel_class=MetaKernelyap)