diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7d279f1bc217025f5b13c03bd80c49ab2483220e..3006c7f4e65e6482ecf076825d57e26bbe315c56 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,11 +17,11 @@ variables: &variables DEBIAN_FRONTEND: "noninteractive" DL_LD: g++-8 ## FIXME: drop when Octave version 6 becomes latest DOCTEST_GIT_REPOSITORY: "https://github.com/catch22/octave-doctest.git" - DOCTEST_GIT_TAG: "v0.7.0" + DOCTEST_GIT_TAG: "v0.8.0" DOCTEST_ROOT: "/tmp/doctest" LIBSSL_DEV: "libssl-dev" PYENV_GIT_REPOSITORY: "https://github.com/pyenv/pyenv.git" - PYENV_GIT_TAG: "v2.0.7" + PYENV_GIT_TAG: "v2.3.15" PYENV_ROOT: "/tmp/pyenv" PYTHON_CONFIGURE_OPTS: "--enable-shared" @@ -88,60 +88,11 @@ coverage: dependencies: [] coverage: '/^lines: \d+\.\d+/' -python2.7: - variables: - <<: *variables - PYTHON_VERSION: "2.7" - PYTHON_VERSION_FULL: "2.7.18" - extends: .test:pyenv - -python2.7:devel: - extends: python2.7 - image: registry.gitlab.com/mtmiller/docker-octave:devel - allow_failure: true - -python3.4: - variables: - <<: *variables - LIBSSL_DEV: "libssl1.0-dev" - PYTHON_VERSION: "3.4" - PYTHON_VERSION_FULL: "3.4.10" - extends: .test:pyenv - -python3.4:devel: - extends: python3.4 - image: registry.gitlab.com/mtmiller/docker-octave:devel - allow_failure: true - -python3.5: - variables: - <<: *variables - PYTHON_VERSION: "3.5" - PYTHON_VERSION_FULL: "3.5.10" - extends: .test:pyenv - -python3.5:devel: - extends: python3.5 - image: registry.gitlab.com/mtmiller/docker-octave:devel - allow_failure: true - -python3.6: - variables: - <<: *variables - PYTHON_VERSION: "3.6" - PYTHON_VERSION_FULL: "3.6.15" - extends: .test:pyenv - -python3.6:devel: - extends: python3.6 - image: registry.gitlab.com/mtmiller/docker-octave:devel - allow_failure: true - python3.7: variables: <<: *variables PYTHON_VERSION: "3.7" - PYTHON_VERSION_FULL: "3.7.12" + PYTHON_VERSION_FULL: "3.7.16" extends: .test:pyenv python3.7:devel: @@ -153,7 +104,7 @@ python3.8: variables: <<: *variables PYTHON_VERSION: "3.8" - PYTHON_VERSION_FULL: "3.8.12" + PYTHON_VERSION_FULL: "3.8.16" extends: .test:pyenv python3.8:devel: @@ -165,7 +116,7 @@ python3.9: variables: <<: *variables PYTHON_VERSION: "3.9" - PYTHON_VERSION_FULL: "3.9.7" + PYTHON_VERSION_FULL: "3.9.16" extends: .test:pyenv python3.9:devel: @@ -173,11 +124,29 @@ python3.9:devel: image: registry.gitlab.com/mtmiller/docker-octave:devel allow_failure: true -pkg:python2: +python3.10: variables: <<: *variables - PYTHON_VERSION: 2 - extends: .test:pkg + PYTHON_VERSION: "3.10" + PYTHON_VERSION_FULL: "3.10.10" + extends: .test:pyenv + +python3.10:devel: + extends: python3.10 + image: registry.gitlab.com/mtmiller/docker-octave:devel + allow_failure: true + +python3.11: + variables: + <<: *variables + PYTHON_VERSION: "3.11" + PYTHON_VERSION_FULL: "3.11.2" + extends: .test:pyenv + +python3.11:devel: + extends: python3.11 + image: registry.gitlab.com/mtmiller/docker-octave:devel + allow_failure: true pkg:python3: variables: diff --git a/inst/@py/py.m b/inst/@py/py.m index 1a788ef5ae581615e47b4deac70bbd6e6db107b6..8f3ee9e4efa169ab2e12d3d77b1ba08081be2435 100644 --- a/inst/@py/py.m +++ b/inst/@py/py.m @@ -31,28 +31,11 @@ endfunction %!assert (ischar (char (py.sys.version))) %!test -%! if (double (py.sys.hexversion) >= 0x03000000) -%! assert (isobject (py.int (0))) -%! else -%! assert (py.int (0), int64 (0)) -%! endif +%! assert (isobject (py.int (0))) +%! assert (isa (py.int (0), "pyobject")) %!test -%! if (double (py.sys.hexversion) < 0x03000000) -%! assert (py.int (2147483647), int64 (2147483647)) -%! endif - -%!test -%! if (double (py.sys.hexversion) < 0x03000000) -%! assert (isobject (py.long (0))) -%! endif - -%!test -%! if (double (py.sys.hexversion) >= 0x03000000) -%! assert (isobject (py.int (2^100))) -%! else -%! assert (isobject (py.long (2^100))) -%! endif +%! assert (isobject (py.int (2^100))) ## Cannot use '@' to make a handle to a Python function %!xtest diff --git a/inst/@py/subsref.m b/inst/@py/subsref.m index 9316b670a9ef3a8ca853bd696adc6b7fb002a284..9312f677f19ea77b3d545e86dfb0a153abba393a 100644 --- a/inst/@py/subsref.m +++ b/inst/@py/subsref.m @@ -61,7 +61,7 @@ function varargout = subsref (x, idx) ## is a Python callable, then call it with no arguments to be compatible ## with how Octave functions are evaluated. if (idx(end).type == ".") - if (isa (y, "py.collections.Callable")) + if (isa (y, "py.collections.abc.Callable")) y = pycall (y); endif endif diff --git a/inst/@pyobject/pyobject.m b/inst/@pyobject/pyobject.m index b0e41e014c2a660366060822e1b2cf8fb67fe009..073131d175a5453f83607bd6479ea7a8d452c7a7 100644 --- a/inst/@pyobject/pyobject.m +++ b/inst/@pyobject/pyobject.m @@ -295,8 +295,7 @@ endclassdef %!test %! % ensure "end" works for iterables that are not lists -%! myrange = pyeval ( ... -%! "range if __import__('sys').hexversion >= 0x03000000 else xrange"); +%! myrange = pyeval ("range"); %! R = pycall (myrange, int32 (5), int32 (10), int32 (2)); %! assert (double (R{end}), 9) diff --git a/inst/@pyobject/subsasgn.m b/inst/@pyobject/subsasgn.m index 7bc5e850fde9981201a9a14fcdc21493d4b8ba39..70ceeb67a2203456343f6a970f98a13f8734da1c 100644 --- a/inst/@pyobject/subsasgn.m +++ b/inst/@pyobject/subsasgn.m @@ -51,7 +51,7 @@ function r = subsasgn(x, idx, rhs) ## XXX: doesn't support slices or anything like that yet ## Subtract one from index: do this for lists, numpy arrays, etc - x_is_sequence = any (isa (x, {"py.collections.Sequence", ... + x_is_sequence = any (isa (x, {"py.collections.abc.Sequence", ... "py.numpy.ndarray"})); for i = 1:length (idx.subs) j = idx.subs{i}; diff --git a/inst/@pyobject/subsref.m b/inst/@pyobject/subsref.m index 5b5ae11798df32ef60c7c23f7610a7e5cb7f577d..1f5c82de51df8297543e4b2e5b0a3d53cbb21614 100644 --- a/inst/@pyobject/subsref.m +++ b/inst/@pyobject/subsref.m @@ -43,8 +43,8 @@ function varargout = subsref (x, idx) case "()" ## Determine the types and protocols that we are able to index into - x_is_callable = __py_isinstance__ (x, "py.collections.Callable"); - x_is_sequence = __py_isinstance__ (x, "py.collections.Sequence") ... + x_is_callable = __py_isinstance__ (x, "py.collections.abc.Callable"); + x_is_sequence = __py_isinstance__ (x, "py.collections.abc.Sequence") ... | __py_isinstance__ (x, "py.array.array") ... | __py_isinstance__ (x, "py.numpy.ndarray"); @@ -60,8 +60,8 @@ function varargout = subsref (x, idx) case "{}" ## Determine the types and protocols that we are able to index into - x_is_mapping = __py_isinstance__ (x, "py.collections.Mapping"); - x_is_sequence = __py_isinstance__ (x, "py.collections.Sequence") ... + x_is_mapping = __py_isinstance__ (x, "py.collections.abc.Mapping"); + x_is_sequence = __py_isinstance__ (x, "py.collections.abc.Sequence") ... | __py_isinstance__ (x, "py.array.array") ... | __py_isinstance__ (x, "py.numpy.ndarray"); diff --git a/inst/pyversion.m b/inst/pyversion.m index 51208151ae29e0a38eec15039ce339832cb0d495..677d9c5d468af4790692b2b7b78980472a9052eb 100644 --- a/inst/pyversion.m +++ b/inst/pyversion.m @@ -79,8 +79,10 @@ endfunction %!assert (ischar (pyversion ())) %!test -%! [m, n] = regexp (pyversion (), '^(\d\.\d)$'); -%! assert ([m, n], [1, 3]) +%! [m, n, a, b] = regexp (pyversion (), '^(\d\.\d+)$'); +%! assert (length (a), 1) +%! assert (length (b), 1) +%! assert (b{1}(1:2), '3.') %!test %! [~, ~, v] = pyversion (); diff --git a/src/oct-py-eval.cc b/src/oct-py-eval.cc index b8ff922eefceb795c8795aa11c65bf9284743197..fe7e43a5e36ea9af15460538686e2261f9df7f76 100644 --- a/src/oct-py-eval.cc +++ b/src/oct-py-eval.cc @@ -84,7 +84,7 @@ namespace pythonic PyObject * py_call_function (PyObject *callable, PyObject *args, PyObject *kwargs) { - python_object retval = PyEval_CallObjectWithKeywords (callable, args, kwargs); + python_object retval = PyObject_Call (callable, args, kwargs); if (! retval) error_python_exception (); diff --git a/src/oct-py-init.cc b/src/oct-py-init.cc index 17907f783f5aef90587cdf84f766131c6b9e7a8b..883b4cbd0b6c973daa737cd347b01e25cc47c40c 100644 --- a/src/oct-py-init.cc +++ b/src/oct-py-init.cc @@ -33,7 +33,7 @@ along with Octave Pythonic; see the file COPYING. If not, see namespace pythonic { -#if PY_VERSION_HEX >= 0x03000000 +#if PY_VERSION_HEX < 0x30b0000 static wchar_t sys_argv0[] {L'\0'}; static wchar_t *sys_argv[] {sys_argv0, nullptr}; #else @@ -46,10 +46,19 @@ namespace pythonic { bool is_initialized = Py_IsInitialized (); - Py_Initialize (); - if (! is_initialized) - PySys_SetArgvEx (1, sys_argv, 0); + { +#if PY_VERSION_HEX < 0x30b0000 + Py_Initialize (); + PySys_SetArgvEx (1, sys_argv, 0); +#else + PyConfig config; + PyConfig_InitPythonConfig(&config); + PyConfig_SetBytesArgv(&config, 1, sys_argv); + Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); +#endif + } } } diff --git a/src/oct-py-types.cc b/src/oct-py-types.cc index cbdbe17cabb4a03ecc72bd57467cdd0a1ebed554..58144ea46f96926d66713451c1abe9e4c32fa247 100644 --- a/src/oct-py-types.cc +++ b/src/oct-py-types.cc @@ -103,11 +103,7 @@ namespace pythonic PyObject * make_py_int (int32_t value) { -#if PY_VERSION_HEX >= 0x03000000 return PyLong_FromLong (value); -#else - return PyInt_FromLong (value); -#endif } PyObject * @@ -163,10 +159,10 @@ namespace pythonic return array.release (); } - // Prefer the 'q' and 'Q' typecodes if they are available (if Python 3 and - // built with support for long long integers) + // Prefer the 'q' and 'Q' typecodes if they are available (if built with + // support for long long integers) -#if (PY_VERSION_HEX >= 0x03000000) && defined (HAVE_LONG_LONG) +#if defined (HAVE_LONG_LONG) # define ARRAY_INT64_TYPECODE 'q' # define ARRAY_UINT64_TYPECODE 'Q' #elif (SIZEOF_LONG == 8) @@ -391,10 +387,6 @@ namespace pythonic } return static_cast (value); } -#if PY_VERSION_HEX < 0x03000000 - else if (PyInt_Check (obj)) - return PyInt_AsLong (obj); -#endif else error_conversion_mismatch_python_type ("a signed integer value", "int or long"); @@ -429,10 +421,6 @@ namespace pythonic return static_cast (value); } -#if PY_VERSION_HEX < 0x03000000 - else if (PyInt_Check (obj)) - return static_cast (PyInt_AsLong (obj)); -#endif else error_conversion_mismatch_python_type ("an unsigned integer value", "int or long"); @@ -489,11 +477,7 @@ namespace pythonic PyObject * make_py_str (const std::string& str) { -#if PY_VERSION_HEX >= 0x03000000 return PyUnicode_FromStringAndSize (str.data (), str.size ()); -#else - return PyString_FromStringAndSize (str.data (), str.size ()); -#endif } PyObject * @@ -527,10 +511,6 @@ namespace pythonic { if (PyBool_Check (obj)) return octave_value {extract_py_bool (obj)}; -#if PY_VERSION_HEX < 0x03000000 - else if (PyInt_Check (obj)) - return octave_value {octave_int64 (extract_py_int64 (obj))}; -#endif else if (PyComplex_Check (obj)) return octave_value {extract_py_complex (obj)}; else if (PyFloat_Check (obj)) diff --git a/src/oct-py-util.cc b/src/oct-py-util.cc index e371c228eb7e089860c257a38dfaaeb3f3cc193a..e0ade0972293c32e002dc4da2fcb7f75788b5973 100644 --- a/src/oct-py-util.cc +++ b/src/oct-py-util.cc @@ -44,11 +44,7 @@ namespace pythonic inline std::string py_builtins_module_name () { -#if PY_VERSION_HEX >= 0x03000000 return "builtins"; -#else - return "__builtin__"; -#endif } PyObject * @@ -221,11 +217,7 @@ namespace pythonic PyObject *valtype = PyObject_Type (value); PyObject *valtypename = PyObject_Str (PyObject_GetAttrString (valtype, "__name__")); -#if PY_VERSION_HEX >= 0x03000000 std::string valtypestr = PyUnicode_AsUTF8 (valtypename); -#else - std::string valtypestr = PyString_AsString (valtypename); -#endif Py_DECREF (valtype); Py_DECREF (valtypename); @@ -240,11 +232,7 @@ namespace pythonic s = ""; else { -#if PY_VERSION_HEX >= 0x03000000 s = PyUnicode_AsUTF8 (valuestr); -#else - s = PyString_AsString (valuestr); -#endif Py_DECREF (valuestr); if (s.empty ()) s = ""; diff --git a/src/pycall.cc b/src/pycall.cc index e0756b51ecd05c53b03f6ac5956713e48d1a07ec..e26e4e65baa19b8a040b041d360ef0d2486ccf52 100644 --- a/src/pycall.cc +++ b/src/pycall.cc @@ -214,25 +214,13 @@ r = pycall (s.add, 4) ## Test conversion of integer types from Python %!test -%! if (pyeval ("__import__('sys').hexversion >= 0x03000000")) -%! assert (isa (pycall ("int", 0), "pyobject")) -%! assert (isa (pycall ("int", 2^31-1), "pyobject")) -%! assert (isa (pycall ("int", -2^31), "pyobject")) -%! assert (double (pycall ("int", 0)), 0) -%! assert (double (pycall ("int", 2^31-1)), 2^31-1) -%! assert (double (pycall ("int", -2^31)), -2^31) -%! else -%! assert (pycall ("int", 0), int64 (0)) -%! assert (pycall ("int", 2^31-1), int64 (2^31-1)) -%! assert (pycall ("int", -2^31), int64 (-2^31)) -%! assert (isa (pycall ("long", 0), "pyobject")) -%! assert (isa (pycall ("long", 2^31-1), "pyobject")) -%! assert (isa (pycall ("long", -2^31), "pyobject")) -%! assert (double (pycall ("long", 0)), 0) -%! assert (double (pycall ("long", 2^31-1)), 2^31-1) -%! assert (double (pycall ("long", -2^31)), -2^31) -%! endif -%!assert (isa (pycall ("int", 2^100), "pyobject")) +%! assert (isa (pycall ("int", 0), "pyobject")) +%! assert (isa (pycall ("int", 2^31-1), "pyobject")) +%! assert (isa (pycall ("int", -2^31), "pyobject")) +%! assert (double (pycall ("int", 0)), 0) +%! assert (double (pycall ("int", 2^31-1)), 2^31-1) +%! assert (double (pycall ("int", -2^31)), -2^31) +%! assert (isa (pycall ("int", 2^100), "pyobject")) %!test %! pyexec (["def pyfunc(x):\n" ...