From cba8720f2155ad8e93b424ef4aa9ff2bc3241dc6 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Mon, 6 Jun 2016 22:06:37 +0900 Subject: [PATCH 01/11] Do compile sources in _exec_with_pipe --- execjs/_exceptions.py | 6 +++++- execjs/_external_runtime.py | 31 ++++++++++++++++++------------- test_execjs.py | 4 ++-- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/execjs/_exceptions.py b/execjs/_exceptions.py index 876cb22..e11f947 100644 --- a/execjs/_exceptions.py +++ b/execjs/_exceptions.py @@ -3,7 +3,11 @@ class Error(Exception): class RuntimeError(Error): - pass + def __init__(self, status, stdout, stderr): + Error.__init__(self, status, stdout, stderr) + self.status = status + self.stdout = stdout + self.stderr = stderr class ProgramError(Error): diff --git a/execjs/_external_runtime.py b/execjs/_external_runtime.py index dceec83..6489084 100644 --- a/execjs/_external_runtime.py +++ b/execjs/_external_runtime.py @@ -44,7 +44,7 @@ def is_available(self): return self._available def _compile(self, source, cwd=None): - return self.Context(self, source, cwd=cwd, tempfile=tempfile) + return self.Context(self, source, cwd=cwd, tempfile=self._tempfile) def _binary(self): if not hasattr(self, "_binary_cache"): @@ -92,7 +92,10 @@ def _exec_with_pipe(self, source): p = None try: p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=self._cwd, universal_newlines=True) - stdoutdata, stderrdata = p.communicate(input=source) + input = self._compile(source) + if six.PY2: + input = input.encode(sys.getfilesystemencoding()) + stdoutdata, stderrdata = p.communicate(input=input) ret = p.wait() finally: del p @@ -110,7 +113,7 @@ def _exec_with_tempfile(self, source): p = None try: - p = Popen(cmd, stdout=PIPE, stderr=PIPE, cwd=self._cwd) + p = Popen(cmd, stdout=PIPE, stderr=PIPE, cwd=self._cwd, universal_newlines=True) stdoutdata, stderrdata = p.communicate() ret = p.wait() finally: @@ -123,7 +126,7 @@ def _exec_with_tempfile(self, source): def _fail_on_non_zero_status(self, status, stdoutdata, stderrdata): if status != 0: - raise exceptions.RuntimeError("stdout: {}, stderr: {}".format(repr(stdoutdata), repr(stderrdata))) + raise exceptions.RuntimeError(status=status, stdout=stdoutdata, stderr=stderrdata) def _compile(self, source): runner_source = self._runtime._runner_source @@ -145,12 +148,11 @@ def _compile(self, source): return runner_source def _extract_result(self, output): - output = output.decode(self._runtime._encoding) output = output.replace("\r\n", "\n").replace("\r", "\n") output_last_line = output.split("\n")[-2] if not output_last_line: - status = value = None + raise exceptions.ProgramError else: ret = json.loads(output_last_line) if len(ret) == 1: @@ -159,8 +161,6 @@ def _extract_result(self, output): if status == "ok": return value - elif value.startswith('SyntaxError:'): - raise exceptions.RuntimeError(value) else: raise exceptions.ProgramError(value) @@ -241,7 +241,8 @@ def jsc(): return ExternalRuntime( name="JavaScriptCore", command=["/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc"], - runner_source=_runner_sources.JavaScriptCore + runner_source=_runner_sources.JavaScriptCore, + tempfile=True ) @@ -249,7 +250,8 @@ def spidermonkey(): return ExternalRuntime( name="SpiderMonkey", command=["js"], - runner_source=_runner_sources.SpiderMonkey + runner_source=_runner_sources.SpiderMonkey, + tempfile=True ) @@ -267,7 +269,8 @@ def phantomjs(): return ExternalRuntime( name="PhantomJS", command=["phantomjs"], - runner_source=_runner_sources.PhantomJS + runner_source=_runner_sources.PhantomJS, + tempfile=True ) @@ -275,7 +278,8 @@ def slimerjs(): return ExternalRuntime( name="SlimerJS", command=["slimerjs"], - runner_source=_runner_sources.SlimerJS + runner_source=_runner_sources.SlimerJS, + tempfile=True ) @@ -283,5 +287,6 @@ def nashorn(): return ExternalRuntime( name="Nashorn", command=["jjs"], - runner_source=_runner_sources.Nashorn + runner_source=_runner_sources.Nashorn, + tempfile=True ) diff --git a/test_execjs.py b/test_execjs.py index 5e7f815..ac3a145 100755 --- a/test_execjs.py +++ b/test_execjs.py @@ -75,11 +75,11 @@ def test_compile_large_scripts(self): self.assertTrue(self.runtime.exec_(code)) def test_syntax_error(self): - with self.assertRaises(execjs.RuntimeError): + with self.assertRaises(execjs.ProgramError): self.runtime.exec_(")") def test_thrown_exception(self): - with self.assertRaises(execjs.ProgramError): + with self.assertRaises(execjs.RuntimeError): self.runtime.exec_("throw 'hello'") def test_broken_substitutions(self): From 8783e86120ce1b28fb589e66be3b2213434acd93 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Mon, 6 Jun 2016 22:08:48 +0900 Subject: [PATCH 02/11] Added cwd argument to module-level functions --- execjs/__init__.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/execjs/__init__.py b/execjs/__init__.py index 394a357..2b573df 100755 --- a/execjs/__init__.py +++ b/execjs/__init__.py @@ -41,16 +41,16 @@ get_from_environment = execjs._runtimes.get_from_environment -def eval(source): - return get().eval(source) -eval.__doc__= AbstractRuntime.eval.__doc__ +def eval(source, cwd=None): + return get().eval(source, cwd) +eval.__doc__ = AbstractRuntime.eval.__doc__ -def exec_(source): - return get().exec_(source) -exec_.__doc__= AbstractRuntime.exec_.__doc__ +def exec_(source, cwd=None): + return get().exec_(source, cwd) +exec_.__doc__ = AbstractRuntime.exec_.__doc__ -def compile(source): - return get().compile(source) -compile.__doc__= AbstractRuntime.compile.__doc__ +def compile(source, cwd=None): + return get().compile(source, cwd) +compile.__doc__ = AbstractRuntime.compile.__doc__ From 68de4b666855adcfc5bf840fb5019ec03566aaa6 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Sat, 16 Sep 2017 17:16:02 +0900 Subject: [PATCH 03/11] Temporary removed tests with SlimerJS --- .travis.yml | 14 ++++---------- test_execjs.py | 27 ++++++++++++--------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index b4129d7..0949de8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,30 @@ dist: trusty language: python +addons: + firefox: "latest" + python: - "2.7" - "3.3" - "3.4" - "3.5" + - "3.6" env: global: - - "SLIMERJSLAUNCHER=$(which firefox)" - - "DISPLAY=:99.0" - - "PATH=$TRAVIS_BUILD_DIR/slimerjs:$PATH" - "JDK=oracle8" jdk: - oraclejdk8 install: - - "sh -e /etc/init.d/xvfb start" - - "echo 'Installing Slimer'" - - "wget http://download.slimerjs.org/releases/0.9.6/slimerjs-0.9.6-linux-x86_64.tar.bz2" - - "tar xvf slimerjs-*.tar.bz2" - - "rm slimerjs-*.tar.bz2" - - "mv slimerjs-* slimerjs" - "sudo apt-get install -y oracle-java8-installer phantomjs libmozjs-24-bin" - "sudo ln -s /usr/bin/js24 /usr/bin/js" - "./install_development.sh" - "python setup.py install" script: - - "slimerjs --version" - "jjs -v < /dev/null" - "js --help" - "node --version && node --help" diff --git a/test_execjs.py b/test_execjs.py index ac3a145..146865a 100755 --- a/test_execjs.py +++ b/test_execjs.py @@ -25,7 +25,7 @@ def test_nested_context_call(self): def test_context_call_missing_function(self): context = self.runtime.compile("") - with self.assertRaises(execjs.ProgramError): + with self.assertRaises(execjs.Error): context.call("missing") def test_exec(self): @@ -75,11 +75,11 @@ def test_compile_large_scripts(self): self.assertTrue(self.runtime.exec_(code)) def test_syntax_error(self): - with self.assertRaises(execjs.ProgramError): + with self.assertRaises(execjs.Error): self.runtime.exec_(")") def test_thrown_exception(self): - with self.assertRaises(execjs.RuntimeError): + with self.assertRaises(execjs.Error): self.runtime.exec_("throw 'hello'") def test_broken_substitutions(self): @@ -91,20 +91,17 @@ class DefaultRuntimeTest(unittest.TestCase, RuntimeTestBase): def setUp(self): self.runtime = execjs +class NodeRuntimeTest(unittest.TestCase, RuntimeTestBase): + def setUp(self): + self.runtime = execjs.get('Node') -for name, runtime in execjs.runtimes().items(): - if not runtime.is_available(): - continue - class_name = name.capitalize() + "RuntimeTest" - - def f(runtime=runtime): - class RuntimeTest(unittest.TestCase, RuntimeTestBase): - def setUp(self): - self.runtime = runtime - RuntimeTest.__name__ = str(class_name) # 2.x compatibility - return RuntimeTest - exec("{class_name} = f()".format(class_name=class_name)) +class NashornRuntimeTest(unittest.TestCase, RuntimeTestBase): + def setUp(self): + self.runtime = execjs.get('Nashorn') +class PhantomJSRuntimeTest(unittest.TestCase, RuntimeTestBase): + def setUp(self): + self.runtime = execjs.get('PhantomJS') class CommonTest(unittest.TestCase): def test_empty_path_environ(self): From 3006696972fb0420aa24c2c421656208504d6ff0 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Sat, 16 Sep 2017 17:12:06 +0900 Subject: [PATCH 04/11] Fixed wrong use of exception and ambiguous exception names --- execjs/__init__.py | 8 +++++++- execjs/_exceptions.py | 20 +++++++++++++------- execjs/_external_runtime.py | 22 ++++++++++++---------- execjs/_pyv8runtime.py | 2 +- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/execjs/__init__.py b/execjs/__init__.py index 2b573df..98a4bea 100755 --- a/execjs/__init__.py +++ b/execjs/__init__.py @@ -22,7 +22,13 @@ ''' from __future__ import unicode_literals, division, with_statement -from execjs._exceptions import Error, RuntimeError, ProgramError, RuntimeUnavailableError +from execjs._exceptions import ( + Error, + RuntimeError, + ProgramError, + RuntimeUnavailableError, +) + import execjs._runtimes from execjs._external_runtime import ExternalRuntime from execjs._abstract_runtime import AbstractRuntime diff --git a/execjs/_exceptions.py b/execjs/_exceptions.py index e11f947..0723550 100644 --- a/execjs/_exceptions.py +++ b/execjs/_exceptions.py @@ -1,18 +1,24 @@ +# Abstract base error classes class Error(Exception): pass - +# Abstract class that represents errors of runtime engine. +# ex. Specified runtime engine is not installed, runtime engine aborted (by its bugs). +# By the way "RuntimeError" is bad name because it is confusing with the standard exception. class RuntimeError(Error): + pass + +# Concrete runtime error classes +class RuntimeUnavailableError(RuntimeError): pass + +class ProcessExitedWithNonZeroStatus(RuntimeError): def __init__(self, status, stdout, stderr): - Error.__init__(self, status, stdout, stderr) + RuntimeError.__init__(self, status, stdout, stderr) self.status = status self.stdout = stdout self.stderr = stderr - +# Errors due to JS script. +# ex. Script has syntax error, executed and raised exception. class ProgramError(Error): pass - - -class RuntimeUnavailableError(RuntimeError): - pass diff --git a/execjs/_external_runtime.py b/execjs/_external_runtime.py index 6489084..2b05c16 100644 --- a/execjs/_external_runtime.py +++ b/execjs/_external_runtime.py @@ -11,7 +11,12 @@ import six import execjs._json2 as _json2 import execjs._runner_sources as _runner_sources -import execjs._exceptions as exceptions + +from execjs._exceptions import ( + ProcessExitedWithNonZeroStatus, + ProgramError +) + from execjs._abstract_runtime import AbstractRuntime from execjs._abstract_runtime_context import AbstractRuntimeContext from execjs._misc import encode_unicode_codepoints @@ -126,7 +131,7 @@ def _exec_with_tempfile(self, source): def _fail_on_non_zero_status(self, status, stdoutdata, stderrdata): if status != 0: - raise exceptions.RuntimeError(status=status, stdout=stdoutdata, stderr=stderrdata) + raise ProcessExitedWithNonZeroStatus(status=status, stdout=stdoutdata, stderr=stderrdata) def _compile(self, source): runner_source = self._runtime._runner_source @@ -151,18 +156,15 @@ def _extract_result(self, output): output = output.replace("\r\n", "\n").replace("\r", "\n") output_last_line = output.split("\n")[-2] - if not output_last_line: - raise exceptions.ProgramError - else: - ret = json.loads(output_last_line) - if len(ret) == 1: - ret = [ret[0], None] - status, value = ret + ret = json.loads(output_last_line) + if len(ret) == 1: + ret = [ret[0], None] + status, value = ret if status == "ok": return value else: - raise exceptions.ProgramError(value) + raise ProgramError(value) def _is_windows(): diff --git a/execjs/_pyv8runtime.py b/execjs/_pyv8runtime.py index c5edcff..2f93a2c 100644 --- a/execjs/_pyv8runtime.py +++ b/execjs/_pyv8runtime.py @@ -53,7 +53,7 @@ def _exec_(self, source): try: script = engine.compile(source) except js_errors as e: - raise exceptions.RuntimeError(e) + raise exceptions.ProgramError(e) try: value = script.run() except js_errors as e: From 16211f20fa409f9e486763acd6f146d6c15a7940 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Mon, 6 Jun 2016 22:12:27 +0900 Subject: [PATCH 05/11] Version 1.4.1 --- README.md | 5 +++++ README.rst | 7 +++++++ setup.py | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c820530..8baab56 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,11 @@ Released under the MIT license. See `LICENSE` for details. # Changelog +## 1.4.1 +- Fixed arguments of module-level functions. +- Fixed bug of execution with pipe. +- Fixed wrong excption is raised. + ## 1.4.0 - Fixed required libraries. - Fixed order of output of `--print-available-runtimes`. diff --git a/README.rst b/README.rst index e84efa9..79a2e11 100644 --- a/README.rst +++ b/README.rst @@ -101,6 +101,13 @@ Released under the MIT license. See ``LICENSE`` for details. Changelog ========= +1.4.1 +----- + +- Fixed arguments of module-level functions. +- Fixed bug of execution with pipe. +- Fixed wrong excption is raised. + 1.4.0 ----- diff --git a/setup.py b/setup.py index f09e310..4ed25d4 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ import sys import io -version = '1.4.0' +version = '1.4.1' author = "Omoto Kenji" license = "MIT License" author_email = 'doloopwhile@gmail.com' From 47fc67ea9c7494b329b1b9bf0ecab06663bdcf99 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Sun, 17 Sep 2017 11:42:17 +0900 Subject: [PATCH 06/11] Dropped first-class suuports for some runtimes --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8baab56..b9eb9df 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,19 @@ A short example: # Supported runtimes +## First-class support (runtime class is provided and tested) + * [PyV8](http://code.google.com/p/pyv8/) - A python wrapper for Google V8 engine, * [Node.js](http://nodejs.org/) +* [PhantomJS](http://phantomjs.org/) +* [Nashorn](http://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/intro.html#sthref16) - Included with Oracle Java 8 + +## Second-class support (runtime class is privided but not tested) + * Apple JavaScriptCore - Included with Mac OS X -* [Mozilla SpiderMonkey](http://www.mozilla.org/js/spidermonkey/) * [Microsoft Windows Script Host](http://msdn.microsoft.com/en-us/library/9bbdkx3k.aspx) (JScript) * [SlimerJS](http://slimerjs.org/) -* [PhantomJS](http://phantomjs.org/) -* [Nashorn](http://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/intro.html#sthref16) - Included with Oracle Java 8 +* [Mozilla SpiderMonkey](http://www.mozilla.org/js/spidermonkey/) # Installation From 2ce8d692b4071f504ea35d38b1ecfeb7a1750d84 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Tue, 19 Sep 2017 10:03:18 +0900 Subject: [PATCH 07/11] Ease version requirement of six --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4ed25d4..e897014 100755 --- a/setup.py +++ b/setup.py @@ -39,6 +39,6 @@ 'Programming Language :: Python :: 3.5', 'Programming Language :: JavaScript', ], - install_requires=["six==1.10.0"], + install_requires=["six >= 1.10.0"], test_suite="test_execjs", ) From f63beab270411f9b82f19b1a43698ea8e0c920af Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Wed, 8 Nov 2017 13:02:29 +0900 Subject: [PATCH 08/11] Version 1.5.0 --- README.md | 3 +++ README.rst | 20 ++++++++++++++++---- setup.py | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b9eb9df..36454db 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,9 @@ Released under the MIT license. See `LICENSE` for details. # Changelog +## 1.5.0 +- Eased version requirement for six. + ## 1.4.1 - Fixed arguments of module-level functions. - Fixed bug of execution with pipe. diff --git a/README.rst b/README.rst index 79a2e11..c26d955 100644 --- a/README.rst +++ b/README.rst @@ -24,18 +24,25 @@ A short example: Supported runtimes ================== +First-class support (runtime class is provided and tested) +---------------------------------------------------------- + - `PyV8 `__ - A python wrapper for Google V8 engine, - `Node.js `__ +- `PhantomJS `__ +- `Nashorn `__ + - Included with Oracle Java 8 + +Second-class support (runtime class is privided but not tested) +--------------------------------------------------------------- + - Apple JavaScriptCore - Included with Mac OS X -- `Mozilla SpiderMonkey `__ - `Microsoft Windows Script Host `__ (JScript) - `SlimerJS `__ -- `PhantomJS `__ -- `Nashorn `__ - - Included with Oracle Java 8 +- `Mozilla SpiderMonkey `__ Installation ============ @@ -101,6 +108,11 @@ Released under the MIT license. See ``LICENSE`` for details. Changelog ========= +1.5.0 +----- + +- Eased version requirement for six. + 1.4.1 ----- diff --git a/setup.py b/setup.py index e897014..d15dad4 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ import sys import io -version = '1.4.1' +version = '1.5.0' author = "Omoto Kenji" license = "MIT License" author_email = 'doloopwhile@gmail.com' From 998553d04e4226695b8cf7a0b29ea701fe314a24 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Wed, 27 Dec 2017 15:49:10 +0900 Subject: [PATCH 09/11] Removed contextlib.nested --- execjs/_pyv8runtime.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/execjs/_pyv8runtime.py b/execjs/_pyv8runtime.py index 2f93a2c..06ddcb7 100644 --- a/execjs/_pyv8runtime.py +++ b/execjs/_pyv8runtime.py @@ -1,5 +1,4 @@ import json -import contextlib import execjs._exceptions as exceptions from execjs._abstract_runtime import AbstractRuntime @@ -48,7 +47,7 @@ def _exec_(self, source): source = str(source) # backward compatibility - with contextlib.nested(PyV8.JSContext(), PyV8.JSEngine()) as (ctxt, engine): + with PyV8.JSContext() as ctxt, PyV8.JSEngine() as engine: js_errors = (PyV8.JSError, IndexError, ReferenceError, SyntaxError, TypeError) try: script = engine.compile(source) From 025e9fb9d444653fadaca12395835d05c9dd4400 Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Thu, 18 Jan 2018 13:20:05 +0900 Subject: [PATCH 10/11] Version 1.5.1, EOL --- README.md | 12 ++++++++++-- README.rst | 14 ++++++++++++-- setup.py | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 36454db..bf4b296 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,15 @@ -PyExecJS -======== +PyExecJS (EOL) +============== [![Build Status](https://travis-ci.org/doloopwhile/PyExecJS.svg?branch=travis-ci)](https://travis-ci.org/doloopwhile/PyExecJS) +# End of life + +This library is no longer maintananced. Bugs are not be fixed (even if they are trivial or essential). + +We suggest to use other library or to make a fork. + +--- + Run JavaScript code from Python. PyExecJS is a porting of ExecJS from Ruby. diff --git a/README.rst b/README.rst index c26d955..e3a5e83 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,15 @@ -PyExecJS -======== +PyExecJS (EOL) +============== + +End of life +=========== + +This library is no longer maintananced. Bugs are not be fixed (even if +they are trivial or essential). + +We suggest to use other library or to make a fork. + +-------------- Run JavaScript code from Python. diff --git a/setup.py b/setup.py index d15dad4..68689ea 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ import sys import io -version = '1.5.0' +version = '1.5.1' author = "Omoto Kenji" license = "MIT License" author_email = 'doloopwhile@gmail.com' From e300f0a8120c0b7b70eed0758c3c85a9bd1a7b9f Mon Sep 17 00:00:00 2001 From: OMOTO Kenji Date: Mon, 19 Mar 2018 13:15:05 +0900 Subject: [PATCH 11/11] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf4b296..e89124c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ PyExecJS (EOL) # End of life -This library is no longer maintananced. Bugs are not be fixed (even if they are trivial or essential). +This library is no longer maintananced ([Reason](https://gist.github.com/doloopwhile/8c6ec7dd4703e8a44e559411cb2ea221)). +Bugs are not be fixed (even if they are trivial or essential). We suggest to use other library or to make a fork.