Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ocaml-pyml for openSUSE:Factory checked in at 2021-10-13 18:06:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ocaml-pyml (Old) and /work/SRC/openSUSE:Factory/.ocaml-pyml.new.2443 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ocaml-pyml" Wed Oct 13 18:06:05 2021 rev:3 rq:923490 version:20210924 Changes: -------- --- /work/SRC/openSUSE:Factory/ocaml-pyml/ocaml-pyml.changes 2021-06-25 15:02:01.632202023 +0200 +++ /work/SRC/openSUSE:Factory/.ocaml-pyml.new.2443/ocaml-pyml.changes 2021-10-13 18:10:00.227643006 +0200 @@ -1,0 +2,12 @@ +Sat Sep 25 20:58:01 UTC 2021 - Matej Cepl <[email protected]> + +- Don't use python(abi) construct it is not reliably supported in + openSUSE. Related to bsc#1187262 + +------------------------------------------------------------------- +Sat Sep 11 12:34:56 UTC 2021 - [email protected] + +- Update to version 20210924 + build with dune + +------------------------------------------------------------------- Old: ---- ocaml-pyml-20210226.tar.xz New: ---- ocaml-pyml-20210924.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ocaml-pyml.spec ++++++ --- /var/tmp/diff_new_pack.RnLcsL/_old 2021-10-13 18:10:00.663643689 +0200 +++ /var/tmp/diff_new_pack.RnLcsL/_new 2021-10-13 18:10:00.667643695 +0200 @@ -1,7 +1,7 @@ # # spec file for package ocaml-pyml # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -15,8 +15,9 @@ # Please submit bugfixes or comments via https://bugs.opensuse.org/ # + Name: ocaml-pyml -Version: 20210226 +Version: 20210924 Release: 0 %{?ocaml_preserve_bytecode} Summary: Stdcompat: compatibility module for OCaml standard library @@ -25,19 +26,18 @@ URL: https://opam.ocaml.org/packages/pyml Source0: %{name}-%{version}.tar.xz BuildRequires: ocaml -#uildRequires: ocaml-dune -BuildRequires: ocaml-rpm-macros >= 20210409 +BuildRequires: ocaml-dune >= 2.8 +BuildRequires: ocaml-rpm-macros >= 20210911 BuildRequires: ocamlfind(bigarray) -BuildRequires: ocamlfind(findlib) BuildRequires: ocamlfind(stdcompat) BuildRequires: ocamlfind(unix) # make check -BuildRequires: python(abi) > 3.0 %if 0%{?suse_version} > 1315 BuildRequires: python3-numpy %else BuildRequires: python-numpy %endif +BuildRequires: which %description Stdcompat is a compatibility layer allowing programs to use some recent additions to the OCaml standard library while preserving the ability to be compiled on former versions of OCaml. @@ -46,7 +46,7 @@ Summary: Development files for %{name} Group: Development/Languages/OCaml Requires: %{name} = %{version} - +Requires: which %description devel The %{name}-devel package contains libraries and signature files for @@ -56,33 +56,16 @@ %autosetup -p1 %build -sed -i~ ' -s@^\(HAVE_OCAMLFIND := $(shell \).*@\1 set -x ; \\@ -s@2>&1@@g -' Makefile -diff -u "$_"~ "$_" && exit 1 -%make_build -%if 0 dune_release_pkgs='pyml' %ocaml_dune_setup %ocaml_dune_build -%endif %install -mkdir -vp '%{buildroot}%{ocaml_standard_library}' -export OCAMLFIND_DESTDIR='%{buildroot}%{ocaml_standard_library}' -export OCAMLFIND_LDCONF='ignore' -%make_install STDCOMPAT="$(ocamlfind query stdcompat)" -%ocaml_create_file_list -%if 0 %ocaml_dune_install %ocaml_create_file_list -%endif %check -%if 0 %ocaml_dune_test -%endif %files -f %{name}.files ++++++ _service ++++++ --- /var/tmp/diff_new_pack.RnLcsL/_old 2021-10-13 18:10:00.691643733 +0200 +++ /var/tmp/diff_new_pack.RnLcsL/_new 2021-10-13 18:10:00.695643739 +0200 @@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="disabled"> <param name="filename">ocaml-pyml</param> - <param name="revision">b6608db88f0559f7e59b9be859a649f5bb6812b7</param> + <param name="revision">8521e337944b651db2eb791ef561348d0ecfcf7a</param> <param name="scm">git</param> <param name="submodules">disable</param> <param name="url">https://github.com/thierry-martinez/pyml.git</param> ++++++ ocaml-pyml-20210226.tar.xz -> ocaml-pyml-20210924.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/.gitignore new/ocaml-pyml-20210924/.gitignore --- old/ocaml-pyml-20210226/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-pyml-20210924/.gitignore 2021-09-29 10:00:10.000000000 +0200 @@ -0,0 +1,23 @@ +_build +.merlin +.depend +*.cm[aioxt] +*.cmti +*.cmx[as] +*.[ao] +*.so +*.swp +*~ +*.inc +/generate +/pyml.h +/pyml_libdir.ml +/pyml_compat.ml +/pyml_arch.ml +/pywrappers.mli +/pywrappers.ml +/pymlutop +/pyml_tests.bytecode +/numpy_tests.bytecode +/pyml_tests.native +/numpy_tests.native diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/CHANGES.md new/ocaml-pyml-20210924/CHANGES.md --- old/ocaml-pyml-20210226/CHANGES.md 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/CHANGES.md 2021-09-29 10:00:10.000000000 +0200 @@ -1,5 +1,32 @@ [*] marks changes that break compatibility with previous versions. +# 2021-09-24 + +- Use `dune` as default build system + (dunification done by Laurent Mazare, https://github.com/thierry-martinez/pyml/pull/28) + + This should in particular fix build problems of reverse dependencies + with the byte-code compiler + (reported by @nicoTolly, https://github.com/thierry-martinez/pyml/issues/62) + + - Handle more platforms with dune + (reported by Olaf Hering, https://github.com/thierry-martinez/pyml/issues/68) + + - `pyutils` is no longer used by generate and is shipped with `pyml` package + as it was the case with Makefile-based build system + (reported by Olaf Hering, https://github.com/thierry-martinez/pyml/issues/69) + +- Support for raising exceptions with traceback from OCaml + (implemented by Laurent Mazare, https://github.com/thierry-martinez/pyml/pull/65) + +- Fix soundness bug with `numpy` + (reported by Richard Alligier, https://github.com/thierry-martinez/pyml/pull/65) + +- Fix `Py.Array.numpy` arrays on 32-bit platforms + (reported by Olaf Hering, https://github.com/thierry-martinez/pyml/pull/70) + +- Fix soundness bug on strings with OCaml <4.06 (reported by OCaml CI) + # 2021-02-26 - Compatibility with Python 3.10 (reported by Richard W.M. Jones) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/Makefile new/ocaml-pyml-20210924/Makefile --- old/ocaml-pyml-20210226/Makefile 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/Makefile 2021-09-29 10:00:10.000000000 +0200 @@ -356,3 +356,9 @@ # $(OCAMLMKTOP) -o $@ -thread -linkpkg -package utop -dontlink compiler-libs $^ ocamlfind ocamlc -thread -linkpkg -linkall -predicates create_toploop \ -package compiler-libs.toplevel,utop,stdcompat $^ -o $@ + +pyops.ml: pyops.ml.new + cp $< $@ + +pyops.mli: pyops.mli.new + cp $< $@ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/dune new/ocaml-pyml-20210924/dune --- old/ocaml-pyml-20210226/dune 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/dune 2021-09-29 10:00:10.000000000 +0200 @@ -1,20 +1,14 @@ (library - (name pyml) - (modules numpy py pycaml pyml_arch pytypes pywrappers) - (c_names numpy_stubs pyml_stubs) + (public_name pyml) + (modules numpy py pyops pycaml pyml_arch pytypes pywrappers pyutils) + (foreign_stubs (language c) (names numpy_stubs pyml_stubs)) (wrapped false) - (libraries bigarray stdcompat pyutils)) + (libraries bigarray stdcompat)) (executables (names generate) (modules generate) - (libraries stdcompat pyutils)) - -(library - (name pyutils) - (modules pyutils) - (wrapped false) - (libraries stdcompat unix)) + (libraries stdcompat)) (rule (targets pywrappers.ml pyml.h pyml_dlsyms.inc pyml_wrappers.inc) @@ -22,22 +16,60 @@ (action (run %{gen}))) (rule - (targets pyml_arch.ml) - (deps (:pyml_arch pyml_arch_%{ocaml-config:system}.ml)) - (action (copy %{pyml_arch} pyml_arch.ml))) + (target pyml_arch.ml) + (deps pyml_arch%{ocaml-config:ext_dll}.ml) + (action (copy %{deps} %{target}))) + +(rule + (target pyml_arch.so.ml) + (deps pyml_arch_unix.ml) + (action (copy %{deps} %{target}))) + +(rule + (target pyml_arch.dylib.ml) + (deps pyml_arch_darwin.ml) + (action (copy %{deps} %{target}))) + +(rule + (target pyml_arch.dll.ml) + (deps pyml_arch_cygwin.ml) + (action (copy %{deps} %{target}))) (library (name pyml_tests_common) (modules pyml_tests_common) - (wrapped false) (libraries pyml stdcompat)) (test (name numpy_tests) (modules numpy_tests) - (libraries pyml pyml_tests_common stdcompat pyutils)) + (libraries pyml pyml_tests_common stdcompat)) (test (name pyml_tests) (modules pyml_tests) - (libraries pyml pyml_tests_common stdcompat pyutils)) + (libraries pyml pyml_tests_common stdcompat)) + +(rule + (enabled_if (>= %{ocaml_version} 4.06)) + (target pyops.mli) + (deps pyops.mli.new) + (action (copy %{deps} %{target}))) + +(rule + (enabled_if (>= %{ocaml_version} 4.06)) + (target pyops.ml) + (deps pyops.ml.new) + (action (copy %{deps} %{target}))) + +(rule + (enabled_if (< %{ocaml_version} 4.06)) + (target pyops.mli) + (deps pyops.mli.405) + (action (copy %{deps} %{target}))) + +(rule + (enabled_if (< %{ocaml_version} 4.06)) + (target pyops.ml) + (deps pyops.ml.405) + (action (copy %{deps} %{target}))) \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/dune-project new/ocaml-pyml-20210924/dune-project --- old/ocaml-pyml-20210226/dune-project 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/dune-project 2021-09-29 10:00:10.000000000 +0200 @@ -1 +1 @@ -(lang dune 1.6) +(lang dune 2.5) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/generate.ml new/ocaml-pyml-20210924/generate.ml --- old/ocaml-pyml-20210226/generate.ml 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/generate.ml 2021-09-29 10:00:10.000000000 +0200 @@ -143,10 +143,6 @@ arguments = Fun []; result = Unit; optional = false; }; - { symbol = "PyErr_Restore"; - arguments = Fun [PyObject false; PyObject false; PyObject false]; - result = Unit; - optional = false; }; { symbol = "PyErr_PrintEx"; arguments = Fun [Int]; result = Unit; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/numpy_tests.ml new/ocaml-pyml-20210924/numpy_tests.ml --- old/ocaml-pyml-20210226/numpy_tests.ml 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/numpy_tests.ml 2021-09-29 10:00:10.000000000 +0200 @@ -26,6 +26,37 @@ end) let () = + Pyml_tests_common.add_test ~title:"of_bigarray2" + (fun () -> + if Py.Import.try_import_module "numpy" = None then + Pyml_tests_common.Disabled "numpy is not available" + else + begin + let array = [| [| 1.; 2.; 3. |]; [| -1.23; Stdcompat.Float.nan; 2.72 |] |] in + let array2 = + Bigarray.Array2.of_array (Bigarray.float64) (Bigarray.c_layout) array in + let bigarray = Bigarray.genarray_of_array2 array2 in + let a = Numpy.of_bigarray bigarray in + let m = Py.Import.add_module "test" in + Py.Module.set m "array" a; + assert (Py.Run.simple_string " +from test import array +import numpy + +assert list(array.shape) == [2, 3] +numpy.testing.assert_almost_equal(array[0], [1, 2, 3]) +assert(numpy.isnan(array[1, 1])) +array[0, 0] = 42. +array[0, 1] = 43. +array[1, 1] = 1. +"); + assert (Bigarray.Array2.get array2 0 0 = 42.); + assert (Bigarray.Array2.get array2 0 1 = 43.); + assert (Bigarray.Array2.get array2 1 1 = 1.); + Pyml_tests_common.Passed + end) + +let () = Pyml_tests_common.add_test ~title:"to_bigarray" (fun () -> if Py.Import.try_import_module "numpy" = None then @@ -36,6 +67,7 @@ let callback arg = let bigarray = Numpy.to_bigarray Bigarray.nativeint Bigarray.c_layout arg.(0) in + assert (Bigarray.Genarray.dims bigarray = [| 4 |]); let array1 = Bigarray.array1_of_genarray bigarray in assert (Bigarray.Array1.get array1 0 = 0n); assert (Bigarray.Array1.get array1 1 = 1n); @@ -50,6 +82,46 @@ "); Pyml_tests_common.Passed end) + +let assert_almost_eq ?(eps = 1e-7) f1 f2 = + if Stdcompat.Float.abs (f1 -. f2) > eps then + failwith (Printf.sprintf "%f <> %f" f1 f2) + +let () = + Pyml_tests_common.add_test ~title:"to_bigarray2" + (fun () -> + if Py.Import.try_import_module "numpy" = None then + Pyml_tests_common.Disabled "numpy is not available" + else + begin + let m = Py.Import.add_module "test" in + let callback arg = + let bigarray = + Numpy.to_bigarray Bigarray.float32 Bigarray.c_layout arg.(0) in + assert (Bigarray.Genarray.dims bigarray = [| 2; 4 |]); + let array2 = Bigarray.array2_of_genarray bigarray in + let assert_almost_eq i j v = + assert_almost_eq (Bigarray.Array2.get array2 i j) v in + let assert_is_nan i j = + let v = Bigarray.Array2.get array2 i j in + assert (Stdcompat.Float.is_nan v) in + assert_almost_eq 0 0 0.12; + assert_almost_eq 0 1 1.23; + assert_almost_eq 0 2 2.34; + assert_almost_eq 0 3 3.45; + assert_almost_eq 1 0 (-1.); + assert_is_nan 1 1; + assert_almost_eq 1 2 1.; + assert_almost_eq 1 3 0.; + Py.none in + Py.Module.set m "callback" (Py.Callable.of_function callback); + assert (Py.Run.simple_string " +from test import callback +import numpy +callback(numpy.array([[0.12,1.23,2.34,3.45],[-1.,numpy.nan,1.,0.]], dtype=numpy.float32)) +"); + Pyml_tests_common.Passed + end) let assert_invalid_argument f = try diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/py.ml new/ocaml-pyml-20210924/py.ml --- old/ocaml-pyml-20210226/py.ml 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/py.ml 2021-09-29 10:00:10.000000000 +0200 @@ -34,6 +34,8 @@ -> pyobject = "PyObject_CallMethodObjArgs_wrapper" external pyerr_fetch_internal: unit -> pyobject * pyobject * pyobject = "PyErr_Fetch_wrapper" +external pyerr_restore_internal: pyobject -> pyobject -> pyobject -> unit + = "PyErr_Restore_wrapper" external pystring_asstringandsize: pyobject -> string option = "PyString_AsStringAndSize_wrapper" external pyobject_ascharbuffer: pyobject -> string option @@ -48,6 +50,8 @@ = "Python27_PyCapsule_IsValid_wrapper" external pycapsule_check: Pytypes.pyobject -> int = "pyml_capsule_check" +external pyframe_new : string -> string -> int -> Pytypes.pyobject + = "pyml_pyframe_new" external ucs: unit -> ucs = "py_get_UCS" (* Avoid warning 32. *) @@ -1307,7 +1311,7 @@ let print_ex i = Pywrappers.pyerr_printex i - let restore = Pywrappers.pyerr_restore + let restore = pyerr_restore_internal let restore_tuple (ptype, pvalue, ptraceback) = restore ptype pvalue ptraceback @@ -1328,41 +1332,41 @@ let set_object = Pywrappers.pyerr_setobject + let of_error = function + Exception -> Pywrappers.pyexc_exception () + | StandardError -> + if !version_major_value <= 2 then + Pywrappers.Python2.pyexc_standarderror () + else + Pywrappers.pyexc_exception () + | ArithmeticError -> Pywrappers.pyexc_arithmeticerror () + | LookupError -> Pywrappers.pyexc_lookuperror () + | AssertionError -> Pywrappers.pyexc_assertionerror () + | AttributeError -> Pywrappers.pyexc_attributeerror () + | EOFError -> Pywrappers.pyexc_eoferror () + | EnvironmentError -> Pywrappers.pyexc_environmenterror () + | FloatingPointError -> Pywrappers.pyexc_floatingpointerror () + | IOError -> Pywrappers.pyexc_ioerror () + | ImportError -> Pywrappers.pyexc_importerror () + | IndexError -> Pywrappers.pyexc_indexerror () + | KeyError -> Pywrappers.pyexc_keyerror () + | KeyboardInterrupt -> Pywrappers.pyexc_keyboardinterrupt () + | MemoryError -> Pywrappers.pyexc_memoryerror () + | NameError -> Pywrappers.pyexc_nameerror () + | NotImplementedError -> Pywrappers.pyexc_notimplementederror () + | OSError -> Pywrappers.pyexc_oserror () + | OverflowError -> Pywrappers.pyexc_overflowerror () + | ReferenceError -> Pywrappers.pyexc_referenceerror () + | RuntimeError -> Pywrappers.pyexc_runtimeerror () + | SyntaxError -> Pywrappers.pyexc_syntaxerror () + | SystemExit -> Pywrappers.pyexc_systemerror () + | TypeError -> Pywrappers.pyexc_typeerror () + | ValueError -> Pywrappers.pyexc_valueerror () + | ZeroDivisionError -> Pywrappers.pyexc_zerodivisionerror () + | StopIteration -> Pywrappers.pyexc_stopiteration () + let set_error error msg = - let exc = - match error with - Exception -> Pywrappers.pyexc_exception () - | StandardError -> - if !version_major_value <= 2 then - Pywrappers.Python2.pyexc_standarderror () - else - Pywrappers.pyexc_exception () - | ArithmeticError -> Pywrappers.pyexc_arithmeticerror () - | LookupError -> Pywrappers.pyexc_lookuperror () - | AssertionError -> Pywrappers.pyexc_assertionerror () - | AttributeError -> Pywrappers.pyexc_attributeerror () - | EOFError -> Pywrappers.pyexc_eoferror () - | EnvironmentError -> Pywrappers.pyexc_environmenterror () - | FloatingPointError -> Pywrappers.pyexc_floatingpointerror () - | IOError -> Pywrappers.pyexc_ioerror () - | ImportError -> Pywrappers.pyexc_importerror () - | IndexError -> Pywrappers.pyexc_indexerror () - | KeyError -> Pywrappers.pyexc_keyerror () - | KeyboardInterrupt -> Pywrappers.pyexc_keyboardinterrupt () - | MemoryError -> Pywrappers.pyexc_memoryerror () - | NameError -> Pywrappers.pyexc_nameerror () - | NotImplementedError -> Pywrappers.pyexc_notimplementederror () - | OSError -> Pywrappers.pyexc_oserror () - | OverflowError -> Pywrappers.pyexc_overflowerror () - | ReferenceError -> Pywrappers.pyexc_referenceerror () - | RuntimeError -> Pywrappers.pyexc_runtimeerror () - | SyntaxError -> Pywrappers.pyexc_syntaxerror () - | SystemExit -> Pywrappers.pyexc_systemerror () - | TypeError -> Pywrappers.pyexc_typeerror () - | ValueError -> Pywrappers.pyexc_valueerror () - | ZeroDivisionError -> Pywrappers.pyexc_zerodivisionerror () - | StopIteration -> Pywrappers.pyexc_stopiteration () in - set_object exc (String.of_string msg) + set_object (of_error error) (String.of_string msg) end exception Err of Err.t * string @@ -2017,6 +2021,33 @@ let of_list = of_list_map id end +module Traceback = struct + type frame = + { filename : string + ; function_name : string + ; line_number : int + } + + let create_frame { filename; function_name; line_number } = + check_not_null (pyframe_new filename function_name line_number) + + type t = frame list + + let create t = + let types_module = check_not_null (Pywrappers.pyimport_importmodule "types") in + let tb_type = Object.find_attr_string types_module "TracebackType" in + List.fold_left + (fun acc frame -> + let args = + Tuple.of_array [| acc; create_frame frame; Int.of_int 0; Int.of_int frame.line_number |] + in + Eval.call_object tb_type args) + none + t +end + +exception Err_with_traceback of Err.t * string * Traceback.t + module Callable = struct let check v = Pywrappers.pycallable_check v <> 0 @@ -2025,9 +2056,21 @@ E (errtype, errvalue) -> Err.set_object errtype errvalue; null - | Err (errtype, msg) -> + | Err (errtype, msg) + | Err_with_traceback (errtype, msg, []) -> Err.set_error errtype msg; null + | Err_with_traceback (errtype, msg, traceback) -> + let () = + (* Traceback objects can only be created since Python 3.7. *) + if !version_major_value <= 2 || (!version_major_value == 3 && !version_minor_value < 7) + then + Err.set_error errtype msg + else + let traceback = Traceback.create traceback in + Err.restore (Err.of_error errtype) (String.of_string msg) traceback; + in + null let of_function_as_tuple ?name ?(docstring = "Anonymous closure") f = check_not_null (pywrap_closure name docstring @@ -2119,11 +2162,6 @@ let import_opt = Import.import_module_opt -let option_map f o = - match o with - | None -> None - | Some x -> Some (f x) - module Module = struct let check o = Type.get o = Type.Module @@ -2147,13 +2185,13 @@ let get_function m name = Callable.to_function (get m name) - let get_function_opt m name = option_map Callable.to_function (get_opt m name) + let get_function_opt m name = Option.map Callable.to_function (get_opt m name) let get_function_with_keywords m name = Callable.to_function_with_keywords (get m name) let get_function_with_keywords_opt m name = - option_map Callable.to_function_with_keywords (get_opt m name) + Option.map Callable.to_function_with_keywords (get_opt m name) let set_function m name f = set m name (Callable.of_function f) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/py.mli new/ocaml-pyml-20210924/py.mli --- old/ocaml-pyml-20210226/py.mli 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/py.mli 2021-09-29 10:00:10.000000000 +0200 @@ -861,9 +861,24 @@ instead. *) end +module Traceback : sig + type frame = + { filename : string + ; function_name : string + ; line_number : int + } + + val create_frame : frame -> Object.t + + type t = frame list +end + exception Err of Err.t * string (** Represents an exception to be set with {!Err.set_error} in a callback. *) +exception Err_with_traceback of Err.t * string * Traceback.t +(** Represents an exception with traceback information to be set with {!Err.restore}. *) + module Eval: sig val call_object: Object.t -> Object.t -> Object.t (** See {{:https://docs.python.org/3.0/extending/extending.html} Extending Python with C or C++} *) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pycaml.mli new/ocaml-pyml-20210924/pycaml.mli --- old/ocaml-pyml-20210226/pycaml.mli 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/pycaml.mli 2021-09-29 10:00:10.000000000 +0200 @@ -707,7 +707,6 @@ val pyerr_occurred : unit -> pyobject val pyerr_clear : unit -> unit val pyerr_fetch : pyobject * pyobject * pyobject -> pyobject * pyobject * pyobject -val pyerr_restore : pyobject * pyobject * pyobject -> unit val pyerr_givenexceptionmatches : pyobject * pyobject -> int val pyerr_exceptionmatches : pyobject -> int val pyerr_normalizeexception : pyobject * pyobject * pyobject -> pyobject * pyobject * pyobject diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pyml.opam new/ocaml-pyml-20210924/pyml.opam --- old/ocaml-pyml-20210226/pyml.opam 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/pyml.opam 2021-09-29 10:00:10.000000000 +0200 @@ -5,16 +5,15 @@ bug-reports: "http://github.com/thierry-martinez/pyml/issues" license: "BSD-2-Clause" dev-repo: "git+https://github.com/thierry-martinez/pyml.git" -build: [make "all" "pymltop" "pymlutop" {utop:installed} "PREFIX=%{prefix}%"] -install: [make "install" "PREFIX=%{prefix}%"] -run-test: [make "test"] +build: ["dune" "build" "-p" name "-j" jobs "@install" "@runtest" {with-test} "@doc" {with-doc}] synopsis: "OCaml bindings for Python" description: "OCaml bindings for Python 2 and Python 3" depends: [ "ocaml" {>= "3.12.1"} + "dune" {build & >= "2.8.0"} "ocamlfind" {build} - "stdcompat" {>= "13"} + "stdcompat" {>= "17"} "conf-python-3-dev" {with-test} ] depopts: ["utop"] -version: "20210226" \ No newline at end of file +version: "20210924" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pyml_arch.mli new/ocaml-pyml-20210924/pyml_arch.mli --- old/ocaml-pyml-20210226/pyml_arch.mli 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/pyml_arch.mli 2021-09-29 10:00:10.000000000 +0200 @@ -1,11 +1,25 @@ +(** List of possible names for libpython given major and minor versions. + On Linux, "libpython%d.%d.so"; on Mac OS X, "libpython%d.%d.dylib"; + on Windows, "python%d%d.dll". There may be some variants to try, + like "libpython%d.%dm.so", so we return a list. *) val library_patterns: (int -> int -> string, unit, string) format list +(** Suffix to add to library names returned by pkg-config (".so" on Linux, + ".dylib" on Mac OSX, we don't use pkg-config on Windows) *) val library_suffix: string +(** Ensure that the executable has the ".exe" suffix on Windows, do nothing + on other platforms. *) val ensure_executable_suffix: string -> string +(** The tool to search in PATH: "which" on Unix/Mac OS X; "where" on Windows. *) val which: string +(** Convert a file descriptor index to a file descriptor usable in + OCaml. It is the identity on Unix and Mac OS X, and the stdlib + "win_handle_fd" C stub on Windows. *) val fd_of_int: int -> Unix.file_descr +(** Separator between paths in PATH environment variable. ":" on Unix/Mac OS X; + ";" on Windows. *) val path_separator: string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pyml_stubs.c new/ocaml-pyml-20210924/pyml_stubs.c --- old/ocaml-pyml-20210226/pyml_stubs.c 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/pyml_stubs.c 2021-09-29 10:00:10.000000000 +0200 @@ -200,6 +200,7 @@ /* Wrapped by PyErr_Fetch_wrapper */ static void (*Python_PyErr_Fetch)(PyObject **, PyObject **, PyObject **); +static void (*Python_PyErr_Restore)(PyObject *, PyObject *, PyObject *); static void (*Python_PyErr_NormalizeException) (PyObject **, PyObject **, PyObject **); @@ -222,6 +223,11 @@ /* Internal use only */ static void (*Python_PyMem_Free)(void *); +/* Generate traceback objects. */ +static PyObject *(*Python_PyThreadState_Get)(); +static PyObject *(*Python_PyFrame_New)(PyObject*, PyObject*, PyObject*, PyObject*); +static PyObject *(*Python_PyCode_NewEmpty)(const char*, const char*, int); + static enum UCS { UCS_NONE, UCS2, UCS4 } ucs; /* Single instance of () */ @@ -698,6 +704,7 @@ Python_PyObject_CallMethodObjArgs = resolve("PyObject_CallMethodObjArgs"); Python_PyErr_Fetch = resolve("PyErr_Fetch"); + Python_PyErr_Restore = resolve("PyErr_Restore"); Python_PyErr_NormalizeException = resolve("PyErr_NormalizeException"); Python_PyObject_AsCharBuffer = resolve_optional("PyObject_AsCharBuffer"); Python_PyObject_AsReadBuffer = resolve_optional("PyObject_AsReadBuffer"); @@ -712,6 +719,9 @@ } Python_PyLong_FromString = resolve("PyLong_FromString"); Python_PyMem_Free = resolve("PyMem_Free"); + Python_PyThreadState_Get = resolve("PyThreadState_Get"); + Python_PyFrame_New = resolve("PyFrame_New"); + Python_PyCode_NewEmpty = resolve("PyCode_NewEmpty"); if (version_major >= 3) { Python__Py_wfopen = resolve_optional("_Py_wfopen"); /* Python >=3.10 */ Python__Py_fopen = resolve_optional("_Py_fopen"); @@ -1143,6 +1153,26 @@ CAMLreturn(result); } +// PyErr_Restore steals the references. +// https://docs.python.org/3/c-api/exceptions.html#c.PyErr_Restore +// However the objects can be null, so we do not want to run Py_INCREF if +// this is the case as this would trigger some segfaults. +CAMLprim value +PyErr_Restore_wrapper(value arg0_ocaml, value arg1_ocaml, value arg2_ocaml) +{ + CAMLparam3(arg0_ocaml, arg1_ocaml, arg2_ocaml); + pyml_assert_initialized(); + PyObject *arg0 = pyml_unwrap(arg0_ocaml); + if (arg0) Py_INCREF(arg0); + PyObject *arg1 = pyml_unwrap(arg1_ocaml); + if (arg1) Py_INCREF(arg1); + PyObject *arg2 = pyml_unwrap(arg2_ocaml); + if (arg2) Py_INCREF(arg2); + Python_PyErr_Restore(arg0, arg1, arg2); + CAMLreturn(Val_unit); +} + + CAMLprim value pyml_wrap_string_option(const char *s) { @@ -1355,7 +1385,7 @@ PyObject *c_api = pyml_unwrap(numpy_api_ocaml); void **PyArray_API = pyml_get_pyarray_api(c_api); PyObject *result = PyArray_API[2]; - CAMLreturn(pyml_wrap(result, true)); + CAMLreturn(pyml_wrap(result, false)); } CAMLprim value @@ -1370,6 +1400,9 @@ (PyTypeObject *, int, npy_intp *, int, npy_intp *, void *, int, int, PyObject *) = PyArray_API[93]; npy_intp length = Wosize_val(array_ocaml); + #ifndef ARCH_SIXTYFOUR + length /= 2; + #endif void *data = (double *) array_ocaml; PyTypeObject (*PyArray_SubType) = (PyTypeObject *) pyml_unwrap(array_type_ocaml); @@ -1423,4 +1456,22 @@ CAMLreturn(Val_int(result)); } +CAMLprim value +pyml_pyframe_new(value filename_ocaml, value funcname_ocaml, value lineno_ocaml) { + CAMLparam3(filename_ocaml, funcname_ocaml, lineno_ocaml); + const char *filename = String_val(filename_ocaml); + const char *funcname = String_val(funcname_ocaml); + int lineno = Int_val(lineno_ocaml); + PyObject *code = Python_PyCode_NewEmpty(filename, funcname, lineno); + PyObject *globals = Python_PyDict_New(); + PyObject *result = Python_PyFrame_New( + Python_PyThreadState_Get(), + code, + globals, + NULL); + Py_DECREF(code); + Py_DECREF(globals); + CAMLreturn(pyml_wrap(result, true)); +} + #include "pyml_wrappers.inc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pyml_tests.ml new/ocaml-pyml-20210924/pyml_tests.ml --- old/ocaml-pyml-20210226/pyml_tests.ml 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/pyml_tests.ml 2021-09-29 10:00:10.000000000 +0200 @@ -164,6 +164,54 @@ let () = Pyml_tests_common.add_test + ~title:"ocaml exception with traceback" + (fun () -> + let m = Py.Import.add_module "test" in + let traceback = [ + {Py.Traceback.filename = "file1.ml"; function_name = "func1"; line_number = 1}; + {Py.Traceback.filename = "file2.ml"; function_name = "func2"; line_number = 2} + ] in + let mywrap _ = + raise (Py.Err_with_traceback (Py.Err.Exception, "Great", traceback)) in + Py.Module.set_function m "mywrap" mywrap; + assert (Py.Run.simple_string " +from test import mywrap +import sys +import traceback +try: + mywrap() + raise Exception('No exception raised') +except Exception as err: + if sys.version_info.major == 3 and sys.version_info.minor >= 7: + filenames = [f.filename for f in traceback.extract_tb(err.__traceback__)] + assert filenames == ['<string>', 'file2.ml', 'file1.ml'] + assert str(err) == \"Great\" +"); + Pyml_tests_common.Passed + ) + +let () = + Pyml_tests_common.add_test + ~title:"restore with null" + (fun () -> + try + let _ = Py.Run.eval ~start:Py.File " +raise Exception('Great') +" in + Pyml_tests_common.Failed "uncaught exception" + with Py.E (_, value) -> begin + assert (Py.Object.to_string value = "Great"); + match Py.Err.fetched () with + | None -> Pyml_tests_common.Failed "unexpected none" + | Some (err, _args, _traceback) -> + (* Test that using [Py.Err.restore] on null works fine. *) + Py.Err.restore err Py.null Py.null; + Py.Err.clear (); + Pyml_tests_common.Passed + end) + +let () = + Pyml_tests_common.add_test ~title:"ocaml other exception" (fun () -> let m = Py.Import.add_module "test" in diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pyops.ml new/ocaml-pyml-20210924/pyops.ml --- old/ocaml-pyml-20210226/pyops.ml 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/pyops.ml 1970-01-01 01:00:00.000000000 +0100 @@ -1,27 +0,0 @@ -let ( .@() ) = Py.Object.find_attr - -let ( .@$() ) = Py.Object.find_attr_string - -let ( .@()<- ) = Py.Object.set_attr - -let ( .@$()<- ) = Py.Object.set_attr_string - -let ( .![] ) = Py.Object.find - -let ( .!$[] ) = Py.Object.find_string - -let ( .![]<- ) = Py.Object.set_item - -let ( .!$[]<- ) = Py.Object.set_item_string - -let ( .%[] ) = Py.Dict.find - -let ( .%$[] ) = Py.Dict.find_string - -let ( .%[]<- ) = Py.Dict.set_item - -let ( .%$[]<- ) = Py.Dict.set_item_string - -let ( .&() ) = Py.Module.get_function - -let ( .&()<- ) = Py.Module.set_function diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pyops.ml.new new/ocaml-pyml-20210924/pyops.ml.new --- old/ocaml-pyml-20210226/pyops.ml.new 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-pyml-20210924/pyops.ml.new 2021-09-29 10:00:10.000000000 +0200 @@ -0,0 +1,27 @@ +let ( .@() ) = Py.Object.find_attr + +let ( .@$() ) = Py.Object.find_attr_string + +let ( .@()<- ) = Py.Object.set_attr + +let ( .@$()<- ) = Py.Object.set_attr_string + +let ( .![] ) = Py.Object.find + +let ( .!$[] ) = Py.Object.find_string + +let ( .![]<- ) = Py.Object.set_item + +let ( .!$[]<- ) = Py.Object.set_item_string + +let ( .%[] ) = Py.Dict.find + +let ( .%$[] ) = Py.Dict.find_string + +let ( .%[]<- ) = Py.Dict.set_item + +let ( .%$[]<- ) = Py.Dict.set_item_string + +let ( .&() ) = Py.Module.get_function + +let ( .&()<- ) = Py.Module.set_function diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pyops.mli new/ocaml-pyml-20210924/pyops.mli --- old/ocaml-pyml-20210226/pyops.mli 2021-02-26 23:10:52.000000000 +0100 +++ new/ocaml-pyml-20210924/pyops.mli 1970-01-01 01:00:00.000000000 +0100 @@ -1,42 +0,0 @@ -val ( .@() ) : Py.Object.t -> Py.Object.t -> Py.Object.t -(** Equivalent to {!Py.Object.find_attr}. *) - -val ( .@$() ) : Py.Object.t -> string -> Py.Object.t -(** Equivalent to {!Py.Object.find_attr_string}. *) - -val ( .@()<- ) : Py.Object.t -> Py.Object.t -> Py.Object.t -> unit -(** Equivalent to {!Py.Object.set_attr}. *) - -val ( .@$()<- ) : Py.Object.t -> string -> Py.Object.t -> unit -(** Equivalent to {!Py.Object.set_attr_string}. *) - -val ( .![] ) : Py.Object.t -> Py.Object.t -> Py.Object.t -(** Equivalent to {!Py.Object.find}. *) - -val ( .!$[] ) : Py.Object.t -> string -> Py.Object.t -(** Equivalent to {!Py.Object.find_string}. *) - -val ( .![]<- ) : Py.Object.t -> Py.Object.t -> Py.Object.t -> unit -(** Equivalent to {!Py.Object.set_item}. *) - -val ( .!$[]<- ) : Py.Object.t -> string -> Py.Object.t -> unit -(** Equivalent to {!Py.Object.set_item_string}. *) - -val ( .%[] ) : Py.Object.t -> Py.Object.t -> Py.Object.t -(** Equivalent to {!Py.Dict.find}. *) - -val ( .%$[] ) : Py.Object.t -> string -> Py.Object.t -(** Equivalent to {!Py.Dict.find_string}. *) - -val ( .%[]<- ) : Py.Object.t -> Py.Object.t -> Py.Object.t -> unit -(** Equivalent to {!Py.Dict.set_item}. *) - -val ( .%$[]<- ) : Py.Object.t -> string -> Py.Object.t -> unit -(** Equivalent to {!Py.Dict.set_item_string}. *) - -val ( .&() ) : Py.Object.t -> string -> Py.Object.t array -> Py.Object.t -(** Equivalent to {!Py.Module.get_function}. *) - -val ( .&()<- ) : Py.Object.t -> string -> (Py.Object.t array -> Py.Object.t) - -> unit -(** Equivalent to {!Py.Module.set_function}. *) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-pyml-20210226/pyops.mli.new new/ocaml-pyml-20210924/pyops.mli.new --- old/ocaml-pyml-20210226/pyops.mli.new 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-pyml-20210924/pyops.mli.new 2021-09-29 10:00:10.000000000 +0200 @@ -0,0 +1,42 @@ +val ( .@() ) : Py.Object.t -> Py.Object.t -> Py.Object.t +(** Equivalent to {!Py.Object.find_attr}. *) + +val ( .@$() ) : Py.Object.t -> string -> Py.Object.t +(** Equivalent to {!Py.Object.find_attr_string}. *) + +val ( .@()<- ) : Py.Object.t -> Py.Object.t -> Py.Object.t -> unit +(** Equivalent to {!Py.Object.set_attr}. *) + +val ( .@$()<- ) : Py.Object.t -> string -> Py.Object.t -> unit +(** Equivalent to {!Py.Object.set_attr_string}. *) + +val ( .![] ) : Py.Object.t -> Py.Object.t -> Py.Object.t +(** Equivalent to {!Py.Object.find}. *) + +val ( .!$[] ) : Py.Object.t -> string -> Py.Object.t +(** Equivalent to {!Py.Object.find_string}. *) + +val ( .![]<- ) : Py.Object.t -> Py.Object.t -> Py.Object.t -> unit +(** Equivalent to {!Py.Object.set_item}. *) + +val ( .!$[]<- ) : Py.Object.t -> string -> Py.Object.t -> unit +(** Equivalent to {!Py.Object.set_item_string}. *) + +val ( .%[] ) : Py.Object.t -> Py.Object.t -> Py.Object.t +(** Equivalent to {!Py.Dict.find}. *) + +val ( .%$[] ) : Py.Object.t -> string -> Py.Object.t +(** Equivalent to {!Py.Dict.find_string}. *) + +val ( .%[]<- ) : Py.Object.t -> Py.Object.t -> Py.Object.t -> unit +(** Equivalent to {!Py.Dict.set_item}. *) + +val ( .%$[]<- ) : Py.Object.t -> string -> Py.Object.t -> unit +(** Equivalent to {!Py.Dict.set_item_string}. *) + +val ( .&() ) : Py.Object.t -> string -> Py.Object.t array -> Py.Object.t +(** Equivalent to {!Py.Module.get_function}. *) + +val ( .&()<- ) : Py.Object.t -> string -> (Py.Object.t array -> Py.Object.t) + -> unit +(** Equivalent to {!Py.Module.set_function}. *)
