diff --git a/.travis.yml b/.travis.yml index ab55ba9..25bbfa5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,9 @@ language: python python: + - 3.5 + - 3.4 + - 3.3 - 2.7 - - 2.6 install: - pip install pep8 - pip install nose diff --git a/bin/pythonect b/bin/pythonect index 46aee2b..7314528 100755 --- a/bin/pythonect +++ b/bin/pythonect @@ -52,11 +52,14 @@ import pprint try: - import _preamble + import pythonect._preamble except ImportError: - sys.exc_clear() + try: + sys.exc_clear() + except AttributeError: + pass import pythonect diff --git a/bin/test/foobar.py b/bin/test/foobar.py index eb42ccf..b7993cd 100644 --- a/bin/test/foobar.py +++ b/bin/test/foobar.py @@ -2,8 +2,8 @@ if __name__ == "__main__": - print "Goodbye, world" + print("Goodbye, world") else: - print "Hello, world" + print("Hello, world") diff --git a/bin/test/test_interpreter.py b/bin/test/test_interpreter.py index 736c28b..6dde0c6 100644 --- a/bin/test/test_interpreter.py +++ b/bin/test/test_interpreter.py @@ -41,7 +41,6 @@ import sys import re -import copy import imp import shlex import os diff --git a/examples/palindrome.dia b/examples/palindrome.dia index c1e9ea7..95dd7e5 100644 --- a/examples/palindrome.dia +++ b/examples/palindrome.dia @@ -88,7 +88,7 @@ - #raw_input("Please enter a word or a number: ")# + #six.moves.input("Please enter a word or a number: ")# diff --git a/examples/repl.dia b/examples/repl.dia index 04c859f..28076b9 100644 --- a/examples/repl.dia +++ b/examples/repl.dia @@ -88,7 +88,7 @@ - #raw_input('$ ')# + #six.moves.input('$ ')# diff --git a/pythonect/__init__.py b/pythonect/__init__.py index 9db38d3..1fda2a5 100644 --- a/pythonect/__init__.py +++ b/pythonect/__init__.py @@ -28,9 +28,9 @@ """Parse and execute Pythonect code""" -from _version import __version__ +from pythonect._version import __version__ # API -from internal.eval import eval, parse +from pythonect.internal.eval import eval, parse diff --git a/pythonect/internal/_graph.py b/pythonect/internal/_graph.py index 694dc3e..139eeaf 100644 --- a/pythonect/internal/_graph.py +++ b/pythonect/internal/_graph.py @@ -32,7 +32,7 @@ # Local imports -import _ordereddict +from pythonect.internal import _ordereddict class Graph(networkx.DiGraph): diff --git a/pythonect/internal/eval.py b/pythonect/internal/eval.py index 4262e25..e9086e0 100644 --- a/pythonect/internal/eval.py +++ b/pythonect/internal/eval.py @@ -26,12 +26,11 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import __builtin__ as python +import six.moves.builtins as python import threading import copy import logging import importlib -import site import os import multiprocessing import multiprocessing.dummy @@ -40,13 +39,21 @@ import networkx import re import pprint +import six + + +try: + # Python 3.4+ + import _sitebuiltins as __sitebuiltins +except ImportError: + import site as __sitebuiltins # Local imports -import parsers -import lang -import _graph +from pythonect.internal import parsers +from pythonect.internal import lang +from pythonect.internal import _graph # Consts @@ -112,7 +119,7 @@ def __pickle_safe_dict(locals_or_globals): result = dict(locals_or_globals) - for k, v in locals_or_globals.iteritems(): + for k, v in six.iteritems(locals_or_globals): try: @@ -175,7 +182,7 @@ def _run_next_virtual_nodes(graph, node, globals_, locals_, flags, pool, result) # "Hello, world" or {...} - if isinstance(result, (basestring, dict)) or not __isiter(result): + if isinstance(result, (six.string_types, dict)) or not __isiter(result): not_safe_to_iter = True @@ -292,7 +299,8 @@ def __import_module_from_exception(exception, globals_): # - OR - # NameError: global name 'os' is not defined - mod_name = exception.message[exception.message.index("'") + 1:exception.message.rindex("'")] + exception_message = str(exception) + mod_name = exception_message[exception_message.index("'") + 1:exception_message.rindex("'")] globals_.update({mod_name: importlib.import_module(mod_name)}) @@ -402,7 +410,7 @@ def __node_main(current_value, last_value, globals_, locals_): # Due to eval()? - if (e.message == 'eval() arg 1 must be a string or code object'): + if (str(e) == 'eval() arg 1 must be a string or code object'): return_value = current_value @@ -432,7 +440,7 @@ def __node_main(current_value, last_value, globals_, locals_): # Ignore "copyright", "credits", "license", and "help" - if isinstance(return_value, (site._Printer, site._Helper)): + if isinstance(return_value, (__sitebuiltins._Printer, __sitebuiltins._Helper)): return_value = return_value() @@ -444,7 +452,7 @@ def __node_main(current_value, last_value, globals_, locals_): except TypeError as e: - if e.args[0].find('takes no arguments') != -1: + if any(x in e.args[0] for x in ('takes no arguments', 'takes 0 positional arguments')): return_value = return_value() @@ -464,7 +472,7 @@ def __node_main(current_value, last_value, globals_, locals_): try: - exec current_value in globals_, locals_ + six.exec_(current_value, globals_, locals_) # Autoloader Try & Catch @@ -474,7 +482,7 @@ def __node_main(current_value, last_value, globals_, locals_): __import_module_from_exception(e, globals_) - exec current_value in globals_, locals_ + six.exec_(current_value, globals_, locals_) except Exception as e1: @@ -686,9 +694,9 @@ def __extend_builtins(globals_): # Fix "copyright", "credits", and "license" - setattr(globals_['__builtins__'], 'copyright', site._Printer("copyright", "Copyright (c) 2012-2013 by Itzik Kotler and others.\nAll Rights Reserved.")) - setattr(globals_['__builtins__'], 'credits', site._Printer("credits", "See www.pythonect.org for more information.")) - setattr(globals_['__builtins__'], 'license', site._Printer("license", "See https://github.com/ikotler/pythonect/blob/master/LICENSE", ["LICENSE"], [os.path.abspath(__file__ + "/../../../")])) + setattr(globals_['__builtins__'], 'copyright', __sitebuiltins._Printer("copyright", "Copyright (c) 2012-2013 by Itzik Kotler and others.\nAll Rights Reserved.")) + setattr(globals_['__builtins__'], 'credits', __sitebuiltins._Printer("credits", "See www.pythonect.org for more information.")) + setattr(globals_['__builtins__'], 'license', __sitebuiltins._Printer("license", "See https://github.com/ikotler/pythonect/blob/master/LICENSE", ["LICENSE"], [os.path.abspath(__file__ + "/../../../")])) # Map eval() to Pythonect's eval, and __eval__ to Python's eval @@ -697,7 +705,7 @@ def __extend_builtins(globals_): # Default `iterate_literal_arrays` - if not '__ITERATE_LITERAL_ARRAYS__' in globals_: + if '__ITERATE_LITERAL_ARRAYS__' not in globals_: globals_['__ITERATE_LITERAL_ARRAYS__'] = True @@ -915,7 +923,7 @@ def eval(source, globals_={}, locals_={}): if reduces: - for return_item_idx in xrange(0, len(return_value)): + for return_item_idx in six.moves.range(0, len(return_value)): if isinstance(return_value[return_item_idx], _PythonectLazyRunner): diff --git a/pythonect/internal/lang.py b/pythonect/internal/lang.py index 8c54498..b0dea92 100644 --- a/pythonect/internal/lang.py +++ b/pythonect/internal/lang.py @@ -28,7 +28,7 @@ """This file content extends the Python's __builtins__""" -import __builtin__ +from six.moves import builtins # Functions @@ -41,7 +41,7 @@ def print_(object_): # START OF CRITICAL SECTION - __builtin__.__GIL__.acquire() + builtins.__GIL__.acquire() try: @@ -61,7 +61,7 @@ def print_(object_): sys.stdout.flush() - __builtin__.__GIL__.release() + builtins.__GIL__.release() # END OF CRITICAL SECTION @@ -82,7 +82,7 @@ def __repr__(self): def __call__(self, globals_, locals_): - import eval + from pythonect.internal import eval return eval.eval(self.__expression, globals_, locals_) @@ -125,7 +125,7 @@ def evaluate_host(self, globals_, locals_): self.__host = eval(self.__host, globals_, locals_) - except SyntaxError as e: + except SyntaxError: # CONST? As it is @@ -153,11 +153,11 @@ def __call__(self, *args, **kwargs): elif self.__host.startswith('xmlrpc://'): - import xmlrpclib + from six.moves import xmlrpc_client # xmlrpc:// = http://, xmlrpcs:// = https:// - remote_srv = xmlrpclib.ServerProxy(self.__host.replace('xmlrpc', 'http', 1)) + remote_srv = xmlrpc_client.ServerProxy(self.__host.replace('xmlrpc', 'http', 1)) self.__remote_fcn = getattr(remote_srv, self.__name) diff --git a/pythonect/internal/parsers/dia.py b/pythonect/internal/parsers/dia.py index e38e46f..5bdb2c3 100644 --- a/pythonect/internal/parsers/dia.py +++ b/pythonect/internal/parsers/dia.py @@ -26,11 +26,10 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import networkx import xml.sax import gzip -import StringIO - +import six +from six import BytesIO # Local imports @@ -134,15 +133,17 @@ def parse(self, source): # UTF-8? - try: + if isinstance(source, six.text_type): + + try: - source = source.encode('utf-8') + source = source.encode('utf-8') - except UnicodeDecodeError: + except UnicodeDecodeError: - pass + pass - source = gzip.GzipFile(fileobj=StringIO.StringIO(source), mode='rb').read() + source = gzip.GzipFile(fileobj=BytesIO(source), mode='rb').read() except IOError: diff --git a/pythonect/internal/parsers/p2y.py b/pythonect/internal/parsers/p2y.py index 068da39..414b5db 100644 --- a/pythonect/internal/parsers/p2y.py +++ b/pythonect/internal/parsers/p2y.py @@ -28,7 +28,8 @@ import networkx import tokenize -import StringIO +from six import StringIO +from six.moves import reduce import re @@ -69,7 +70,7 @@ def _make_graph(code, node_prefix='', depth=0, in_brackets=False): graph = pythonect.internal._graph.Graph() - tokens = tokenize.generate_tokens(StringIO.StringIO(code).readline) + tokens = tokenize.generate_tokens(StringIO(code).readline) token_pos = -1 @@ -155,7 +156,7 @@ def _make_graph(code, node_prefix='', depth=0, in_brackets=False): # '->' Operator? - if tokval == '>' and previous_tokval == '-': + if tokval == "->" or tokval == '>' and previous_tokval == '-': meaningful_graph = True diff --git a/pythonect/internal/parsers/test/test_dia.py b/pythonect/internal/parsers/test/test_dia.py index 6c87fb1..606be4d 100644 --- a/pythonect/internal/parsers/test/test_dia.py +++ b/pythonect/internal/parsers/test/test_dia.py @@ -100,7 +100,7 @@ def test_gzipped_odd_expr_atom_op_expr(self): g.add_edge('2', '3') - self.assertEqual(len(pythonect.internal.parsers.dia.PythonectDiaParser().parse(open(TEST_DIR + os.sep + 'dia_examples' + os.sep + 'odd_expr_atom_op_expr_gzipped.dia').read()).edges()) == len(g.edges()), True) + self.assertEqual(len(pythonect.internal.parsers.dia.PythonectDiaParser().parse(open(TEST_DIR + os.sep + 'dia_examples' + os.sep + 'odd_expr_atom_op_expr_gzipped.dia', 'rb').read()).edges()) == len(g.edges()), True) def test_program_expr_list(self): diff --git a/pythonect/internal/parsers/vdx.py b/pythonect/internal/parsers/vdx.py index a72ed61..8f5a9c1 100644 --- a/pythonect/internal/parsers/vdx.py +++ b/pythonect/internal/parsers/vdx.py @@ -28,6 +28,7 @@ import networkx import xml.sax +import six # Local imports @@ -111,11 +112,11 @@ def characters(self, content): if self.node_value.get('CONTENT', None) is None: - if isinstance(content, unicode): + if isinstance(content, six.text_type): # TODO: This is a hack to replace u'\u201cHello, world\u201d to "Hello, world" - content = content.encode('ascii', 'replace').replace('?', '"') + content = content.encode('ascii', 'replace').replace(b'?', b'"') self.node_value.update({'CONTENT': content}) @@ -131,6 +132,18 @@ def parse(self, source): try: + # UTF-8? + + if isinstance(source, six.text_type): + + try: + + source = source.encode('utf-8') + + except UnicodeDecodeError: + + pass + xml.sax.parseString(source, self) # Delete 'OPERATOR' from tail nodes diff --git a/pythonect/test/test_eval.py b/pythonect/test/test_eval.py index ff0c268..11140bf 100644 --- a/pythonect/test/test_eval.py +++ b/pythonect/test/test_eval.py @@ -42,6 +42,7 @@ import os import sys import copy +import six # Local imports @@ -191,11 +192,11 @@ def test_literal_int_sync_dict(self): def test_literal_str_async_autoload(self): - self.assertEqual(pythonect.eval('"Hello world" -> string.split', copy.copy(self.globals_), copy.copy(self.locals_)), ["Hello", "world"]) + self.assertEqual(pythonect.eval('"Hello world" -> six.moves.builtins.str.split', copy.copy(self.globals_), copy.copy(self.locals_)), ["Hello", "world"]) def test_literal_str_sync_autoload(self): - self.assertItemsEqual(pythonect.eval('"Hello world" | string.split', copy.copy(self.globals_), copy.copy(self.locals_)), ["Hello", "world"]) + six.assertCountEqual(self, pythonect.eval('"Hello world" | six.moves.builtins.str.split', copy.copy(self.globals_), copy.copy(self.locals_)), ["Hello", "world"]) def test_literal_int_async_literal_int(self): @@ -207,7 +208,7 @@ def test_literal_int_sync_literal_int(self): def test_literal_int_async_literal_array_int_float(self): - self.assertItemsEqual(pythonect.eval('1 -> [int,float]', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 1.0]) + six.assertCountEqual(self, pythonect.eval('1 -> [int,float]', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 1.0]) def test_literal_int_sync_literal_array_int_float(self): @@ -235,7 +236,7 @@ def test_literal_array_int_int_sync_none(self): def test_literal_array_int_int_async_none(self): - self.assertItemsEqual(pythonect.eval('[1, 2] -> None', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 2]) + six.assertCountEqual(self, pythonect.eval('[1, 2] -> None', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 2]) def test_literal_array_int_int_sync_dict(self): @@ -243,11 +244,11 @@ def test_literal_array_int_int_sync_dict(self): def test_literal_array_int_int_async_dict(self): - self.assertItemsEqual(pythonect.eval('[1, 2] -> {1: "One", 2: "Two"}', copy.copy(self.globals_), copy.copy(self.locals_)), ["One", "Two"]) + six.assertCountEqual(self, pythonect.eval('[1, 2] -> {1: "One", 2: "Two"}', copy.copy(self.globals_), copy.copy(self.locals_)), ["One", "Two"]) def test_literal_array_int_str_async_none(self): - self.assertItemsEqual(pythonect.eval('[1, "Hello"] -> None', copy.copy(self.globals_), copy.copy(self.locals_)), [1, "Hello"]) + six.assertCountEqual(self, pythonect.eval('[1, "Hello"] -> None', copy.copy(self.globals_), copy.copy(self.locals_)), [1, "Hello"]) def test_literal_array_int_str_sync_none(self): @@ -255,7 +256,7 @@ def test_literal_array_int_str_sync_none(self): def test_literal_array_int_str_async_int(self): - self.assertItemsEqual(pythonect.eval('[1, "Hello"] -> 1', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 1]) + six.assertCountEqual(self, pythonect.eval('[1, "Hello"] -> 1', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 1]) def test_literal_array_int_str_sync_int(self): @@ -275,7 +276,7 @@ def test_literal_array_int_int_sync_literal_array_int_int(self): def test_literal_array_int_int_async_literal_array_int_int(self): - self.assertItemsEqual(pythonect.eval('[1, 2] -> [3, 4]', copy.copy(self.globals_), copy.copy(self.locals_)), [3, 3, 4, 4]) + six.assertCountEqual(self, pythonect.eval('[1, 2] -> [3, 4]', copy.copy(self.globals_), copy.copy(self.locals_)), [3, 3, 4, 4]) def test_literal_int_async_stmt_single_return_value_function_async_single_return_value_function(self): @@ -295,7 +296,7 @@ def test_literal_int_sync_stmt_single_return_value_function_sync_single_return_v def test_literal_int_async_stmt_multiple_return_value_function_async_multiple_return_value_function(self): - self.assertItemsEqual(pythonect.eval('1 -> def foobar(x): return [x,x+1] -> foobar', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 2]) + six.assertCountEqual(self, pythonect.eval('1 -> def foobar(x): return [x,x+1] -> foobar', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 2]) def test_literal_int_async_stmt_multiple_return_value_function_sync_multiple_return_value_function(self): @@ -311,7 +312,7 @@ def test_literal_int_sync_stmt_multiple_return_value_function_sync_multiple_retu def test_literal_int_async_stmt_generator_return_value_function_async_generator_return_value_function(self): - self.assertItemsEqual(pythonect.eval('1 -> def foobar(x): yield x; yield x+1 -> foobar', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 2]) + six.assertCountEqual(self, pythonect.eval('1 -> def foobar(x): yield x; yield x+1 -> foobar', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 2]) def test_literal_int_async_stmt_generator_return_value_function_sync_generator_return_value_function(self): @@ -400,13 +401,13 @@ def test_void_function(self): def test_autloader_within_array(self): - self.assertItemsEqual(pythonect.eval('"Hello world" | [string.split]', copy.copy(self.globals_), copy.copy(self.locals_)), ["Hello", "world"]) + six.assertCountEqual(self, pythonect.eval('"Hello world" | [six.moves.builtins.str.split]', copy.copy(self.globals_), copy.copy(self.locals_)), ["Hello", "world"]) # Bug #14 def test_print_like_statement(self): - self.assertItemsEqual(pythonect.eval('range(1,10) -> print("Thread A")', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 2, 3, 4, 5, 6, 7, 8, 9]) + six.assertCountEqual(self, pythonect.eval('range(1,10) -> print("Thread A")', copy.copy(self.globals_), copy.copy(self.locals_)), [1, 2, 3, 4, 5, 6, 7, 8, 9]) def test_multiple_stateful_x_eq_5_statement(self): @@ -414,7 +415,7 @@ def test_multiple_stateful_x_eq_5_statement(self): globals_ = copy.copy(self.globals_) - pythonect.eval('xrange(1, 10) -> x = _', globals_, locals_) + pythonect.eval('range(1, 10) -> x = _', globals_, locals_) self.assertEqual('x' not in locals_ and 'x' not in globals_, True) diff --git a/pythonect/test/test_xmlrpc_app.py b/pythonect/test/test_xmlrpc_app.py index 75ef8bf..ebc3e6b 100644 --- a/pythonect/test/test_xmlrpc_app.py +++ b/pythonect/test/test_xmlrpc_app.py @@ -26,15 +26,12 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from SimpleXMLRPCServer import SimpleXMLRPCServer -from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler +from six.moves.xmlrpc_server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler from select import select import unittest import socket import threading -import os -import sys # Local imports @@ -101,7 +98,7 @@ def inc_function(x): server.register_function(inc_function, 'inc') - print "*** Starting XMLRPCServer on localhost:8000 with registered function \'inc\'" + print("*** Starting XMLRPCServer on localhost:8000 with registered function \'inc\'") # Run the server's main loop (in a thread) @@ -114,7 +111,7 @@ def inc_function(x): def tearDownModule(): - print "*** Shutting down XMLRPCServer (localhost:8000)" + print("*** Shutting down XMLRPCServer (localhost:8000)") server.stop_serving() diff --git a/setup.py b/setup.py index 6988971..6cb7eb4 100644 --- a/setup.py +++ b/setup.py @@ -51,7 +51,7 @@ def _safe_get_version(): # Importing _version.py may raise ImportError due to missing dependencies - execfile('pythonect/_version.py', tmp_globals) + exec(compile(open('pythonect/_version.py').read(), 'pythonect/_version.py', 'exec'), tmp_globals) version = tmp_globals['__version__'] @@ -62,7 +62,7 @@ def _safe_get_version(): if __name__ == "__main__": - dependencies = ['networkx>=1.7', 'nose'] + dependencies = ['networkx>=1.7', 'six', 'nose'] major, minor = sys.version_info[:2]