nifi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ald...@apache.org
Subject [nifi-minifi-cpp] branch master updated: MINIFICPP-741: Allow proper error catching with PyErr_Fetch
Date Sat, 09 Mar 2019 17:39:20 GMT
This is an automated email from the ASF dual-hosted git repository.

aldrin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git


The following commit(s) were added to refs/heads/master by this push:
     new bfcf92c  MINIFICPP-741: Allow proper error catching with PyErr_Fetch
bfcf92c is described below

commit bfcf92cb56b880c2f0cff001c751103ce0e58842
Author: Marc Parisi <phrocker@apache.org>
AuthorDate: Wed Mar 6 12:45:43 2019 -0500

    MINIFICPP-741: Allow proper error catching with PyErr_Fetch
    
    This closes #500.
    
    Signed-off-by: Aldrin Piri <aldrin@apache.org>
---
 extensions/script/README.md                        |  26 +-
 extensions/script/ScriptException.h                |  62 ++++
 .../script/python/ExecutePythonProcessor.cpp       |  28 +-
 extensions/script/python/PythonCreator.h           |   4 +
 extensions/script/python/PythonScriptEngine.cpp    |  49 ++--
 extensions/script/python/PythonScriptEngine.h      |  31 +-
 libminifi/src/FlowController.cpp                   |  37 ++-
 thirdparty/pybind11/include/pybind11/attr.h        |   7 +-
 thirdparty/pybind11/include/pybind11/cast.h        |  22 +-
 .../pybind11/include/pybind11/detail/common.h      |   9 +-
 .../pybind11/include/pybind11/detail/internals.h   |  46 +--
 thirdparty/pybind11/include/pybind11/embed.h       |   8 +-
 thirdparty/pybind11/include/pybind11/iostream.h    |   4 +-
 thirdparty/pybind11/include/pybind11/numpy.h       |   7 +-
 thirdparty/pybind11/include/pybind11/pybind11.h    | 316 ++++++++++++++-------
 thirdparty/pybind11/include/pybind11/pytypes.h     | 107 ++++++-
 thirdparty/pybind11/include/pybind11/stl.h         |  24 +-
 17 files changed, 564 insertions(+), 223 deletions(-)

diff --git a/extensions/script/README.md b/extensions/script/README.md
index c28e373..909c4a9 100644
--- a/extensions/script/README.md
+++ b/extensions/script/README.md
@@ -35,22 +35,36 @@ Methods that are enabled within the processor are  describe, onSchedule, onIniti
 Describe is passed the processor and is a required function. You must set the description like so:
 
 ```python
-	def describe(processor):
-	  processor.setDescription("Adds an attribute to your flow files")
+def describe(processor):
+  processor.setDescription("Adds an attribute to your flow files")
 ```
    
 onInitialize is also passed the processor reference and can be where you set properties. The first argument is the property display name,
 followed by the description, and default value. The last two arguments are booleans describing if the property is required or requires EL.
 
 ```python
-	def onInitialize(processor):
-	  processor.setSupportsDynamicProperties()
-	  processor.addProperty("property name","description","default value", True, False)
+def onInitialize(processor):
+  processor.setSupportsDynamicProperties()
+  processor.addProperty("property name","description","default value", True, False)
 ```
 
 The onSchedule function is passed the context and session factory. This should be where your processor loads and reads properties via
 the getProperty function. onTrigger is executed and passed the processor context and session. You may keep state within your processor.
 
+Much like C++ processors, callbacks may be defined for reading/writing streams of data through the session. Those callback classes will
+have a process function that accepts the input stream. You may use codecs getReader to read that data as in the example, below, from
+VaderSentiment
+
+```python
+class VaderSentiment(object):
+  def __init__(self):
+    self.content = None
+
+  def process(self, input_stream):
+    self.content = codecs.getreader('utf-8')(input_stream).read()
+    return len(self.content)
+```
+
 ## Configuration
 
 To enable python Processor capabilities, the following options need to be provided in minifi.properties
@@ -66,6 +80,6 @@ exist.
    
 ## Sentiment Analysis
 
-The SentimentAnalysis processor will perform a Vder Sentiment Analysis. This requires that you install nltk and VaderSentiment
+The SentimentAnalysis processor will perform a Vader Sentiment Analysis. This requires that you install nltk and VaderSentiment
 		pip install nltk
 		pip install VaderSentiment
diff --git a/extensions/script/ScriptException.h b/extensions/script/ScriptException.h
new file mode 100644
index 0000000..855bfc5
--- /dev/null
+++ b/extensions/script/ScriptException.h
@@ -0,0 +1,62 @@
+/**
+ * @file ScriptException.h
+ * ScriptException class declaration
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __SCRIPT_EXCEPTION_H__
+#define __SCRIPT_EXCEPTION_H__
+
+#include <sstream>
+#include <exception>
+#include <stdexcept>
+#include <errno.h>
+#include <string.h>
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace script {
+/**
+ * Defines an exception that may occur within the confines of a script.
+ */
+class ScriptException : public std::exception {
+ public:
+  // Constructor
+  /*!
+   * Create a new exception
+   */
+  ScriptException(std::string errorMsg)
+      : error_(std::move(errorMsg)) {
+  }
+
+  virtual ~ScriptException() noexcept {
+  }
+
+  virtual const char * what() const noexcept {
+    return error_.c_str();
+  }
+
+ private:
+  std::string error_;
+};
+} /* namespace script */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
+#endif
diff --git a/extensions/script/python/ExecutePythonProcessor.cpp b/extensions/script/python/ExecutePythonProcessor.cpp
index 90fb3b6..249ff09 100644
--- a/extensions/script/python/ExecutePythonProcessor.cpp
+++ b/extensions/script/python/ExecutePythonProcessor.cpp
@@ -22,6 +22,8 @@
 #include <memory>
 #include <set>
 #include <utility>
+#include <exception>
+#include <stdexcept>
 
 #include "ExecutePythonProcessor.h"
 
@@ -60,36 +62,32 @@ void ExecutePythonProcessor::initialize() {
   relationships.insert(Failure);
   setSupportedRelationships(std::move(relationships));
 
-  python::PythonScriptEngine::initialize();
-
   if (!prop.empty()) {
     setProperty(ScriptFile, prop);
     std::shared_ptr<script::ScriptEngine> engine;
     python_logger_ = logging::LoggerFactory<ExecutePythonProcessor>::getAliasedLogger(getName());
-    // Use an existing engine, if one is available
-    if (script_engine_q_.try_dequeue(engine)) {
-      logger_->log_debug("Using available %s script engine instance", script_engine_);
-    } else {
-      logger_->log_info("Creating new %s script instance", script_engine_);
-      logger_->log_info("Approximately %d %s script instances created for this processor", script_engine_q_.size_approx(), script_engine_);
 
-      engine = createEngine<python::PythonScriptEngine>();
+    engine = createEngine<python::PythonScriptEngine>();
 
-      if (engine == nullptr) {
-        throw std::runtime_error("No script engine available");
-      }
-      engine->evalFile(prop);
+    if (engine == nullptr) {
+      throw std::runtime_error("No script engine available");
     }
+
     try {
+      engine->evalFile(prop);
       auto me = shared_from_this();
       triggerDescribe(engine, me);
       triggerInitialize(engine, me);
       valid_init_ = true;
     } catch (std::exception &exception) {
       logger_->log_error("Caught Exception %s", exception.what());
+      engine = nullptr;
+      std::rethrow_exception(std::current_exception());
       valid_init_ = false;
     } catch (...) {
       logger_->log_error("Caught Exception");
+      engine = nullptr;
+      std::rethrow_exception(std::current_exception());
       valid_init_ = false;
     }
 
@@ -132,8 +130,6 @@ void ExecutePythonProcessor::onSchedule(const std::shared_ptr<core::ProcessConte
       }
     }
 
-//    triggerInitialize(engine);
-
     triggerSchedule(engine, context);
 
     // Make engine available for use again
@@ -145,10 +141,8 @@ void ExecutePythonProcessor::onSchedule(const std::shared_ptr<core::ProcessConte
     }
   } catch (std::exception &exception) {
     logger_->log_error("Caught Exception %s", exception.what());
-    //this->yield();
   } catch (...) {
     logger_->log_error("Caught Exception");
-    //this->yield();
   }
 }
 
diff --git a/extensions/script/python/PythonCreator.h b/extensions/script/python/PythonCreator.h
index 8ce9b53..8a0fbff 100644
--- a/extensions/script/python/PythonCreator.h
+++ b/extensions/script/python/PythonCreator.h
@@ -63,6 +63,10 @@ class PythonCreator : public minifi::core::CoreComponent {
   }
 
   virtual void configure(const std::shared_ptr<Configure> &configuration) override {
+
+    python::PythonScriptEngine::initialize();
+
+    auto engine = std::make_shared<python::PythonScriptEngine>();
     std::string pathListings;
 
     // assuming we have the options set and can access the PythonCreator
diff --git a/extensions/script/python/PythonScriptEngine.cpp b/extensions/script/python/PythonScriptEngine.cpp
index ffad3f0..c6fe7f4 100644
--- a/extensions/script/python/PythonScriptEngine.cpp
+++ b/extensions/script/python/PythonScriptEngine.cpp
@@ -27,53 +27,40 @@ namespace nifi {
 namespace minifi {
 namespace python {
 
-std::unique_ptr<py::scoped_interpreter> PythonScriptEngine::guard_;
-std::unique_ptr<py::gil_scoped_release> PythonScriptEngine::gil_release_;
-std::mutex PythonScriptEngine::init_mutex_;
-bool PythonScriptEngine::initialized_;
+Interpreter *getInterpreter() {
+  static Interpreter interpreter;
+  return &interpreter;
+}
 
 PythonScriptEngine::PythonScriptEngine() {
-  {
-    std::lock_guard<std::mutex> lock(init_mutex_);
-
-    if (!initialized_) {
-      throw std::runtime_error("Python is not yet initialized");
-    }
-  }
-
-  {
-    py::gil_scoped_acquire gil{};
-    py::module::import("minifi_native");
-    bindings_.reset(new py::dict());
-    (*bindings_) = py::globals().attr("copy")();
-  }
+  auto intepreter = getInterpreter();
+  py::gil_scoped_acquire gil { };
+  py::module::import("minifi_native");
+  bindings_.reset(new py::dict());
+  (*bindings_) = py::globals().attr("copy")();
 }
 
 void PythonScriptEngine::eval(const std::string &script) {
-  py::gil_scoped_acquire gil{};
+  py::gil_scoped_acquire gil { };
 
   if (script[0] == '\n') {
     py::eval<py::eval_statements>(py::module::import("textwrap").attr("dedent")(script), *bindings_, *bindings_);
   } else {
-     py::eval<py::eval_statements>(script, *bindings_, *bindings_);
+    py::eval<py::eval_statements>(script, *bindings_, *bindings_);
   }
 }
 
 void PythonScriptEngine::evalFile(const std::string &file_name) {
-  py::gil_scoped_acquire gil{};
-  py::eval_file(file_name, *bindings_, *bindings_);
+  py::gil_scoped_acquire gil { };
+  try {
+    py::eval_file(file_name, *bindings_, *bindings_);
+  } catch (const std::exception &e) {
+    throw minifi::script::ScriptException(e.what());
+  }
 }
 
 void PythonScriptEngine::initialize() {
-  std::lock_guard<std::mutex> lock(init_mutex_);
-
-  if (initialized_) {
-    return;
-  }
-
-  initialized_ = true;
-  guard_.reset(new py::scoped_interpreter(false));
-  gil_release_.reset(new py::gil_scoped_release());
+  auto intepreter = getInterpreter();
 }
 
 } /* namespace python */
diff --git a/extensions/script/python/PythonScriptEngine.h b/extensions/script/python/PythonScriptEngine.h
index 238bc42..5a6bc14 100644
--- a/extensions/script/python/PythonScriptEngine.h
+++ b/extensions/script/python/PythonScriptEngine.h
@@ -27,6 +27,7 @@
 #include "../ScriptProcessContext.h"
 #include "PythonProcessor.h"
 #include "PyProcessSession.h"
+#include "../ScriptException.h"
 
 namespace org {
 namespace apache {
@@ -36,6 +37,23 @@ namespace python {
 
 namespace py = pybind11;
 
+struct Interpreter {
+
+  Interpreter()
+      : guard_(false) {
+  }
+
+  ~Interpreter() {
+  }
+
+  Interpreter(const Interpreter &other) = delete;
+
+  py::scoped_interpreter guard_;
+  py::gil_scoped_release gil_release_;
+};
+
+static Interpreter *getInterpreter();
+
 class PythonScriptEngine : public script::ScriptEngine {
  public:
   PythonScriptEngine();
@@ -72,8 +90,12 @@ class PythonScriptEngine : public script::ScriptEngine {
   template<typename ... Args>
   void call(const std::string &fn_name, Args &&...args) {
     py::gil_scoped_acquire gil { };
-    if ((*bindings_).contains(fn_name.c_str()))
-      (*bindings_)[fn_name.c_str()](convert(args)...);
+    try {
+      if ((*bindings_).contains(fn_name.c_str()))
+        (*bindings_)[fn_name.c_str()](convert(args)...);
+    } catch (const std::exception &e) {
+      throw minifi::script::ScriptException(e.what());
+    }
   }
 
   /**
@@ -205,11 +227,6 @@ class PythonScriptEngine : public script::ScriptEngine {
   }
 
  private:
-  static std::unique_ptr<py::scoped_interpreter> guard_;
-  static std::unique_ptr<py::gil_scoped_release> gil_release_;
-
-  static std::mutex init_mutex_;
-  static bool initialized_;
   std::unique_ptr<py::dict> bindings_;
 };
 
diff --git a/libminifi/src/FlowController.cpp b/libminifi/src/FlowController.cpp
index 92a60a2..21beceb 100644
--- a/libminifi/src/FlowController.cpp
+++ b/libminifi/src/FlowController.cpp
@@ -202,23 +202,32 @@ bool FlowController::applyConfiguration(const std::string &source, const std::st
   stop(true);
   waitUnload(30000);
   controller_map_->clear();
+  auto prevRoot = std::move(this->root_);
   this->root_ = std::move(newRoot);
   initialized_ = false;
-  load(this->root_, true);
-  flow_update_ = true;
-  bool started = start() == 0;
-
-  updating_ = false;
-
-  if (started) {
-    auto flowVersion = flow_configuration_->getFlowVersion();
-    if (flowVersion) {
-      logger_->log_debug("Setting flow id to %s", flowVersion->getFlowId());
-      configuration_->set(Configure::nifi_c2_flow_id, flowVersion->getFlowId());
-      configuration_->set(Configure::nifi_c2_flow_url, flowVersion->getFlowIdentifier()->getRegistryUrl());
-    } else {
-      logger_->log_debug("Invalid flow version, not setting");
+  bool started = false;
+  try {
+    load(this->root_, true);
+    flow_update_ = true;
+    started = start() == 0;
+
+    updating_ = false;
+
+    if (started) {
+      auto flowVersion = flow_configuration_->getFlowVersion();
+      if (flowVersion) {
+        logger_->log_debug("Setting flow id to %s", flowVersion->getFlowId());
+        configuration_->set(Configure::nifi_c2_flow_id, flowVersion->getFlowId());
+        configuration_->set(Configure::nifi_c2_flow_url, flowVersion->getFlowIdentifier()->getRegistryUrl());
+      } else {
+        logger_->log_debug("Invalid flow version, not setting");
+      }
     }
+  } catch (...) {
+    this->root_ = std::move(prevRoot);
+    load(this->root_, true);
+    flow_update_ = true;
+    updating_ = false;
   }
 
   return started;
diff --git a/thirdparty/pybind11/include/pybind11/attr.h b/thirdparty/pybind11/include/pybind11/attr.h
index dce875a..8732cfe 100644
--- a/thirdparty/pybind11/include/pybind11/attr.h
+++ b/thirdparty/pybind11/include/pybind11/attr.h
@@ -214,11 +214,14 @@ struct type_record {
     /// How large is the underlying C++ type?
     size_t type_size = 0;
 
+    /// What is the alignment of the underlying C++ type?
+    size_t type_align = 0;
+
     /// How large is the type's holder?
     size_t holder_size = 0;
 
     /// The global operator new can be overridden with a class-specific variant
-    void *(*operator_new)(size_t) = ::operator new;
+    void *(*operator_new)(size_t) = nullptr;
 
     /// Function pointer to class_<..>::init_instance
     void (*init_instance)(instance *, const void *) = nullptr;
@@ -278,7 +281,7 @@ struct type_record {
     }
 };
 
-inline function_call::function_call(function_record &f, handle p) :
+inline function_call::function_call(const function_record &f, handle p) :
         func(f), parent(p) {
     args.reserve(f.nargs);
     args_convert.reserve(f.nargs);
diff --git a/thirdparty/pybind11/include/pybind11/cast.h b/thirdparty/pybind11/include/pybind11/cast.h
index 4084d42..80abb2b 100644
--- a/thirdparty/pybind11/include/pybind11/cast.h
+++ b/thirdparty/pybind11/include/pybind11/cast.h
@@ -571,7 +571,17 @@ public:
         // Lazy allocation for unallocated values:
         if (vptr == nullptr) {
             auto *type = v_h.type ? v_h.type : typeinfo;
-            vptr = type->operator_new(type->type_size);
+            if (type->operator_new) {
+                vptr = type->operator_new(type->type_size);
+            } else {
+                #if defined(PYBIND11_CPP17)
+                    if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+                        vptr = ::operator new(type->type_size,
+                                              (std::align_val_t) type->type_align);
+                    else
+                #endif
+                vptr = ::operator new(type->type_size);
+            }
         }
         value = vptr;
     }
@@ -1601,7 +1611,8 @@ template <typename T> using move_never = none_of<move_always<T>, move_if_unrefer
 // everything else returns a reference/pointer to a local variable.
 template <typename type> using cast_is_temporary_value_reference = bool_constant<
     (std::is_reference<type>::value || std::is_pointer<type>::value) &&
-    !std::is_base_of<type_caster_generic, make_caster<type>>::value
+    !std::is_base_of<type_caster_generic, make_caster<type>>::value &&
+    !std::is_same<intrinsic_t<type>, void>::value
 >;
 
 // When a value returned from a C++ function is being cast back to Python, we almost always want to
@@ -1614,8 +1625,9 @@ template <typename Return, typename SFINAE = void> struct return_value_policy_ov
 template <typename Return> struct return_value_policy_override<Return,
         detail::enable_if_t<std::is_base_of<type_caster_generic, make_caster<Return>>::value, void>> {
     static return_value_policy policy(return_value_policy p) {
-        return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value
-            ? return_value_policy::move : p;
+        return !std::is_lvalue_reference<Return>::value &&
+               !std::is_pointer<Return>::value
+                   ? return_value_policy::move : p;
     }
 };
 
@@ -1843,7 +1855,7 @@ struct function_record;
 
 /// Internal data associated with a single function call
 struct function_call {
-    function_call(function_record &f, handle p); // Implementation in attr.h
+    function_call(const function_record &f, handle p); // Implementation in attr.h
 
     /// The function data:
     const function_record &func;
diff --git a/thirdparty/pybind11/include/pybind11/detail/common.h b/thirdparty/pybind11/include/pybind11/detail/common.h
index 3c67228..5ff7485 100644
--- a/thirdparty/pybind11/include/pybind11/detail/common.h
+++ b/thirdparty/pybind11/include/pybind11/detail/common.h
@@ -27,15 +27,16 @@
 #  endif
 #endif
 
-#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
 #  if __cplusplus >= 201402L
 #    define PYBIND11_CPP14
-#    if __cplusplus > 201402L /* Temporary: should be updated to >= the final C++17 value once known */
+#    if __cplusplus >= 201703L
 #      define PYBIND11_CPP17
 #    endif
 #  endif
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) && __cplusplus == 199711L
 // MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented)
+// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer
 #  if _MSVC_LANG >= 201402L
 #    define PYBIND11_CPP14
 #    if _MSVC_LANG > 201402L && _MSC_VER >= 1910
@@ -476,7 +477,7 @@ template <typename...> struct void_t_impl { using type = void; };
 template <typename... Ts> using void_t = typename void_t_impl<Ts...>::type;
 
 /// Compile-time all/any/none of that check the boolean value of all template types
-#ifdef __cpp_fold_expressions
+#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916))
 template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>;
 template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>;
 #elif !defined(_MSC_VER)
diff --git a/thirdparty/pybind11/include/pybind11/detail/internals.h b/thirdparty/pybind11/include/pybind11/detail/internals.h
index e6f851a..6d7dc5c 100644
--- a/thirdparty/pybind11/include/pybind11/detail/internals.h
+++ b/thirdparty/pybind11/include/pybind11/detail/internals.h
@@ -21,20 +21,28 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
 // The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
 // Thread Specific Storage (TSS) API.
 #if PY_VERSION_HEX >= 0x03070000
-    #define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
-    #define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
-    #define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (tstate))
-    #define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
+#    define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
+#    define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
+#    define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (tstate))
+#    define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
 #else
     // Usually an int but a long on Cygwin64 with Python 3.x
-    #define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
-    #define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
-    #if PY_MAJOR_VERSION < 3
-        #define PYBIND11_TLS_REPLACE_VALUE(key, value) do { PyThread_delete_key_value((key)); PyThread_set_key_value((key), (value)); } while (false)
-    #else
-        #define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))
-    #endif
-    #define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
+#    define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
+#    define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
+#    if PY_MAJOR_VERSION < 3
+#        define PYBIND11_TLS_DELETE_VALUE(key)                               \
+             PyThread_delete_key_value(key)
+#        define PYBIND11_TLS_REPLACE_VALUE(key, value)                       \
+             do {                                                            \
+                 PyThread_delete_key_value((key));                           \
+                 PyThread_set_key_value((key), (value));                     \
+             } while (false)
+#    else
+#        define PYBIND11_TLS_DELETE_VALUE(key)                               \
+             PyThread_set_key_value((key), nullptr)
+#        define PYBIND11_TLS_REPLACE_VALUE(key, value)                       \
+             PyThread_set_key_value((key), (value))
+#    endif
 #endif
 
 // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
@@ -108,7 +116,7 @@ struct internals {
 struct type_info {
     PyTypeObject *type;
     const std::type_info *cpptype;
-    size_t type_size, holder_size_in_ptrs;
+    size_t type_size, type_align, holder_size_in_ptrs;
     void *(*operator_new)(size_t);
     void (*init_instance)(instance *, const void *);
     void (*dealloc)(value_and_holder &v_h);
@@ -130,7 +138,13 @@ struct type_info {
 };
 
 /// Tracks the `internals` and `type_info` ABI version independent of the main library version
-#define PYBIND11_INTERNALS_VERSION 2
+#define PYBIND11_INTERNALS_VERSION 3
+
+#if defined(_DEBUG)
+#   define PYBIND11_BUILD_TYPE "_debug"
+#else
+#   define PYBIND11_BUILD_TYPE ""
+#endif
 
 #if defined(WITH_THREAD)
 #  define PYBIND11_INTERNALS_KIND ""
@@ -139,10 +153,10 @@ struct type_info {
 #endif
 
 #define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \
-    PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__"
+    PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE "__"
 
 #define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \
-    PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__"
+    PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND PYBIND11_BUILD_TYPE "__"
 
 /// Each module locally stores a pointer to the `internals` data. The data
 /// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
diff --git a/thirdparty/pybind11/include/pybind11/embed.h b/thirdparty/pybind11/include/pybind11/embed.h
index 9abc61c..7265588 100644
--- a/thirdparty/pybind11/include/pybind11/embed.h
+++ b/thirdparty/pybind11/include/pybind11/embed.h
@@ -90,8 +90,14 @@ NAMESPACE_END(detail)
     Initialize the Python interpreter. No other pybind11 or CPython API functions can be
     called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
     optional parameter can be used to skip the registration of signal handlers (see the
-    Python documentation for details). Calling this function again after the interpreter
+    `Python documentation`_ for details). Calling this function again after the interpreter
     has already been initialized is a fatal error.
+
+    If initializing the Python interpreter fails, then the program is terminated.  (This
+    is controlled by the CPython runtime and is an exception to pybind11's normal behavior
+    of throwing exceptions on errors.)
+
+    .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
  \endrst */
 inline void initialize_interpreter(bool init_signal_handlers = true) {
     if (Py_IsInitialized())
diff --git a/thirdparty/pybind11/include/pybind11/iostream.h b/thirdparty/pybind11/include/pybind11/iostream.h
index a9c27aa..182e8ee 100644
--- a/thirdparty/pybind11/include/pybind11/iostream.h
+++ b/thirdparty/pybind11/include/pybind11/iostream.h
@@ -34,7 +34,7 @@ private:
             *pptr() = traits_type::to_char_type(c);
             pbump(1);
         }
-        return sync() ? traits_type::not_eof(c) : traits_type::eof();
+        return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
     }
 
     int sync() {
@@ -194,7 +194,7 @@ inline class_<detail::OstreamRedirect> add_ostream_redirect(module m, std::strin
     return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
         .def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
         .def("__enter__", &detail::OstreamRedirect::enter)
-        .def("__exit__", [](detail::OstreamRedirect &self, args) { self.exit(); });
+        .def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); });
 }
 
 NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/thirdparty/pybind11/include/pybind11/numpy.h b/thirdparty/pybind11/include/pybind11/numpy.h
index 0d92af2..37471d8 100644
--- a/thirdparty/pybind11/include/pybind11/numpy.h
+++ b/thirdparty/pybind11/include/pybind11/numpy.h
@@ -1466,7 +1466,10 @@ public:
 private:
     remove_reference_t<Func> f;
 
-    template <size_t Index> using param_n_t = typename pack_element<Index, typename vectorize_arg<Args>::call_type...>::type;
+    // Internal compiler error in MSVC 19.16.27025.1 (Visual Studio 2017 15.9.4), when compiling with "/permissive-" flag
+    // when arg_call_types is manually inlined.
+    using arg_call_types = std::tuple<typename vectorize_arg<Args>::call_type...>;
+    template <size_t Index> using param_n_t = typename std::tuple_element<Index, arg_call_types>::type;
 
     // Runs a vectorized function given arguments tuple and three index sequences:
     //     - Index is the full set of 0 ... (N-1) argument indices;
@@ -1593,7 +1596,7 @@ Helper vectorize(Return (Class::*f)(Args...)) {
     return Helper(std::mem_fn(f));
 }
 
-// Vectorize a class method (non-const):
+// Vectorize a class method (const):
 template <typename Return, typename Class, typename... Args,
           typename Helper = detail::vectorize_helper<decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const>())), Return, const Class *, Args...>>
 Helper vectorize(Return (Class::*f)(Args...) const) {
diff --git a/thirdparty/pybind11/include/pybind11/pybind11.h b/thirdparty/pybind11/include/pybind11/pybind11.h
index e986d00..7fa0f0e 100644
--- a/thirdparty/pybind11/include/pybind11/pybind11.h
+++ b/thirdparty/pybind11/include/pybind11/pybind11.h
@@ -10,7 +10,17 @@
 
 #pragma once
 
-#if defined(_MSC_VER)
+#if defined(__INTEL_COMPILER)
+#  pragma warning push
+#  pragma warning disable 68    // integer conversion resulted in a change of sign
+#  pragma warning disable 186   // pointless comparison of unsigned integer with zero
+#  pragma warning disable 878   // incompatible exception specifications
+#  pragma warning disable 1334  // the "template" keyword used for syntactic disambiguation may only be used within a template
+#  pragma warning disable 1682  // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
+#  pragma warning disable 1786  // function "strdup" was declared deprecated
+#  pragma warning disable 1875  // offsetof applied to non-POD (Plain Old Data) types is nonstandard
+#  pragma warning disable 2196  // warning #2196: routine is both "inline" and "noinline"
+#elif defined(_MSC_VER)
 #  pragma warning(push)
 #  pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter
 #  pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
@@ -19,15 +29,6 @@
 #  pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
 #  pragma warning(disable: 4702) // warning C4702: unreachable code
 #  pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified
-#elif defined(__INTEL_COMPILER)
-#  pragma warning(push)
-#  pragma warning(disable: 68)    // integer conversion resulted in a change of sign
-#  pragma warning(disable: 186)   // pointless comparison of unsigned integer with zero
-#  pragma warning(disable: 878)   // incompatible exception specifications
-#  pragma warning(disable: 1334)  // the "template" keyword used for syntactic disambiguation may only be used within a template
-#  pragma warning(disable: 1682)  // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
-#  pragma warning(disable: 1875)  // offsetof applied to non-POD (Plain Old Data) types is nonstandard
-#  pragma warning(disable: 2196)  // warning #2196: routine is both "inline" and "noinline"
 #elif defined(__GNUG__) && !defined(__clang__)
 #  pragma GCC diagnostic push
 #  pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
@@ -420,8 +421,8 @@ protected:
         using namespace detail;
 
         /* Iterator over the list of potentially admissible overloads */
-        function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr),
-                        *it = overloads;
+        const function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr),
+                              *it = overloads;
 
         /* Need to know how many arguments + keyword arguments there are to pick the right overload */
         const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in);
@@ -477,7 +478,7 @@ protected:
                    result other than PYBIND11_TRY_NEXT_OVERLOAD.
                  */
 
-                function_record &func = *it;
+                const function_record &func = *it;
                 size_t pos_args = func.nargs;    // Number of positional arguments that we need
                 if (func.has_args) --pos_args;   // (but don't count py::args
                 if (func.has_kwargs) --pos_args; //  or py::kwargs)
@@ -509,7 +510,7 @@ protected:
                 // 1. Copy any position arguments given.
                 bool bad_arg = false;
                 for (; args_copied < args_to_copy; ++args_copied) {
-                    argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr;
+                    const argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr;
                     if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) {
                         bad_arg = true;
                         break;
@@ -650,8 +651,13 @@ protected:
                         result = PYBIND11_TRY_NEXT_OVERLOAD;
                     }
 
-                    if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD)
+                    if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) {
+                        // The error reporting logic below expects 'it' to be valid, as it would be
+                        // if we'd encountered this failure in the first-pass loop.
+                        if (!result)
+                            it = &call.func;
                         break;
+                    }
                 }
             }
         } catch (error_already_set &e) {
@@ -703,7 +709,7 @@ protected:
                 " arguments. The following argument types are supported:\n";
 
             int ctr = 0;
-            for (function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
+            for (const function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
                 msg += "    "+ std::to_string(++ctr) + ". ";
 
                 bool wrote_sig = false;
@@ -891,6 +897,7 @@ protected:
         tinfo->type = (PyTypeObject *) m_ptr;
         tinfo->cpptype = rec.type;
         tinfo->type_size = rec.type_size;
+        tinfo->type_align = rec.type_align;
         tinfo->operator_new = rec.operator_new;
         tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size);
         tinfo->init_instance = rec.init_instance;
@@ -982,11 +989,21 @@ template <typename T> struct has_operator_delete_size<T, void_t<decltype(static_
     : std::true_type { };
 /// Call class-specific delete if it exists or global otherwise. Can also be an overload set.
 template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>
-void call_operator_delete(T *p, size_t) { T::operator delete(p); }
+void call_operator_delete(T *p, size_t, size_t) { T::operator delete(p); }
 template <typename T, enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
-void call_operator_delete(T *p, size_t s) { T::operator delete(p, s); }
+void call_operator_delete(T *p, size_t s, size_t) { T::operator delete(p, s); }
 
-inline void call_operator_delete(void *p, size_t) { ::operator delete(p); }
+inline void call_operator_delete(void *p, size_t s, size_t a) {
+    (void)s; (void)a;
+#if defined(PYBIND11_CPP17)
+    if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+        ::operator delete(p, s, std::align_val_t(a));
+    else
+        ::operator delete(p, s);
+#else
+    ::operator delete(p);
+#endif
+}
 
 NAMESPACE_END(detail)
 
@@ -1049,10 +1066,11 @@ public:
         record.name = name;
         record.type = &typeid(type);
         record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
+        record.type_align = alignof(conditional_t<has_alias, type_alias, type>&);
         record.holder_size = sizeof(holder_type);
         record.init_instance = init_instance;
         record.dealloc = dealloc;
-        record.default_holder = std::is_same<holder_type, std::unique_ptr<type>>::value;
+        record.default_holder = detail::is_instantiation<std::unique_ptr, holder_type>::value;
 
         set_operator_new<type>(&record);
 
@@ -1324,7 +1342,10 @@ private:
             v_h.set_holder_constructed(false);
         }
         else {
-            detail::call_operator_delete(v_h.value_ptr<type>(), v_h.type->type_size);
+            detail::call_operator_delete(v_h.value_ptr<type>(),
+                v_h.type->type_size,
+                v_h.type->type_align
+            );
         }
         v_h.value_ptr() = nullptr;
     }
@@ -1360,116 +1381,190 @@ detail::initimpl::pickle_factory<GetState, SetState> pickle(GetState &&g, SetSta
     return {std::forward<GetState>(g), std::forward<SetState>(s)};
 }
 
+NAMESPACE_BEGIN(detail)
+struct enum_base {
+    enum_base(handle base, handle parent) : m_base(base), m_parent(parent) { }
+
+    PYBIND11_NOINLINE void init(bool is_arithmetic, bool is_convertible) {
+        m_base.attr("__entries") = dict();
+        auto property = handle((PyObject *) &PyProperty_Type);
+        auto static_property = handle((PyObject *) get_internals().static_property_type);
+
+        m_base.attr("__repr__") = cpp_function(
+            [](handle arg) -> str {
+                handle type = arg.get_type();
+                object type_name = type.attr("__name__");
+                dict entries = type.attr("__entries");
+                for (const auto &kv : entries) {
+                    object other = kv.second[int_(0)];
+                    if (other.equal(arg))
+                        return pybind11::str("{}.{}").format(type_name, kv.first);
+                }
+                return pybind11::str("{}.???").format(type_name);
+            }, is_method(m_base)
+        );
+
+        m_base.attr("name") = property(cpp_function(
+            [](handle arg) -> str {
+                dict entries = arg.get_type().attr("__entries");
+                for (const auto &kv : entries) {
+                    if (handle(kv.second[int_(0)]).equal(arg))
+                        return pybind11::str(kv.first);
+                }
+                return "???";
+            }, is_method(m_base)
+        ));
+
+        m_base.attr("__doc__") = static_property(cpp_function(
+            [](handle arg) -> std::string {
+                std::string docstring;
+                dict entries = arg.attr("__entries");
+                if (((PyTypeObject *) arg.ptr())->tp_doc)
+                    docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n";
+                docstring += "Members:";
+                for (const auto &kv : entries) {
+                    auto key = std::string(pybind11::str(kv.first));
+                    auto comment = kv.second[int_(1)];
+                    docstring += "\n\n  " + key;
+                    if (!comment.is_none())
+                        docstring += " : " + (std::string) pybind11::str(comment);
+                }
+                return docstring;
+            }
+        ), none(), none(), "");
+
+        m_base.attr("__members__") = static_property(cpp_function(
+            [](handle arg) -> dict {
+                dict entries = arg.attr("__entries"), m;
+                for (const auto &kv : entries)
+                    m[kv.first] = kv.second[int_(0)];
+                return m;
+            }), none(), none(), ""
+        );
+
+        #define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior)                     \
+            m_base.attr(op) = cpp_function(                                            \
+                [](object a, object b) {                                               \
+                    if (!a.get_type().is(b.get_type()))                                \
+                        strict_behavior;                                               \
+                    return expr;                                                       \
+                },                                                                     \
+                is_method(m_base))
+
+        #define PYBIND11_ENUM_OP_CONV(op, expr)                                        \
+            m_base.attr(op) = cpp_function(                                            \
+                [](object a_, object b_) {                                             \
+                    int_ a(a_), b(b_);                                                 \
+                    return expr;                                                       \
+                },                                                                     \
+                is_method(m_base))
+
+        if (is_convertible) {
+            PYBIND11_ENUM_OP_CONV("__eq__", !b.is_none() &&  a.equal(b));
+            PYBIND11_ENUM_OP_CONV("__ne__",  b.is_none() || !a.equal(b));
+
+            if (is_arithmetic) {
+                PYBIND11_ENUM_OP_CONV("__lt__",   a <  b);
+                PYBIND11_ENUM_OP_CONV("__gt__",   a >  b);
+                PYBIND11_ENUM_OP_CONV("__le__",   a <= b);
+                PYBIND11_ENUM_OP_CONV("__ge__",   a >= b);
+                PYBIND11_ENUM_OP_CONV("__and__",  a &  b);
+                PYBIND11_ENUM_OP_CONV("__rand__", a &  b);
+                PYBIND11_ENUM_OP_CONV("__or__",   a |  b);
+                PYBIND11_ENUM_OP_CONV("__ror__",  a |  b);
+                PYBIND11_ENUM_OP_CONV("__xor__",  a ^  b);
+                PYBIND11_ENUM_OP_CONV("__rxor__", a ^  b);
+            }
+        } else {
+            PYBIND11_ENUM_OP_STRICT("__eq__",  int_(a).equal(int_(b)), return false);
+            PYBIND11_ENUM_OP_STRICT("__ne__", !int_(a).equal(int_(b)), return true);
+
+            if (is_arithmetic) {
+                #define PYBIND11_THROW throw type_error("Expected an enumeration of matching type!");
+                PYBIND11_ENUM_OP_STRICT("__lt__", int_(a) <  int_(b), PYBIND11_THROW);
+                PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) >  int_(b), PYBIND11_THROW);
+                PYBIND11_ENUM_OP_STRICT("__le__", int_(a) <= int_(b), PYBIND11_THROW);
+                PYBIND11_ENUM_OP_STRICT("__ge__", int_(a) >= int_(b), PYBIND11_THROW);
+                #undef PYBIND11_THROW
+            }
+        }
+
+        #undef PYBIND11_ENUM_OP_CONV
+        #undef PYBIND11_ENUM_OP_STRICT
+
+        object getstate = cpp_function(
+            [](object arg) { return int_(arg); }, is_method(m_base));
+
+        m_base.attr("__getstate__") = getstate;
+        m_base.attr("__hash__") = getstate;
+    }
+
+    PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) {
+        dict entries = m_base.attr("__entries");
+        str name(name_);
+        if (entries.contains(name)) {
+            std::string type_name = (std::string) str(m_base.attr("__name__"));
+            throw value_error(type_name + ": element \"" + std::string(name_) + "\" already exists!");
+        }
+
+        entries[name] = std::make_pair(value, doc);
+        m_base.attr(name) = value;
+    }
+
+    PYBIND11_NOINLINE void export_values() {
+        dict entries = m_base.attr("__entries");
+        for (const auto &kv : entries)
+            m_parent.attr(kv.first) = kv.second[int_(0)];
+    }
+
+    handle m_base;
+    handle m_parent;
+};
+
+NAMESPACE_END(detail)
+
 /// Binds C++ enumerations and enumeration classes to Python
 template <typename Type> class enum_ : public class_<Type> {
 public:
-    using class_<Type>::def;
-    using class_<Type>::def_property_readonly;
-    using class_<Type>::def_property_readonly_static;
+    using Base = class_<Type>;
+    using Base::def;
+    using Base::attr;
+    using Base::def_property_readonly;
+    using Base::def_property_readonly_static;
     using Scalar = typename std::underlying_type<Type>::type;
 
     template <typename... Extra>
     enum_(const handle &scope, const char *name, const Extra&... extra)
-      : class_<Type>(scope, name, extra...), m_entries(), m_parent(scope) {
-
+      : class_<Type>(scope, name, extra...), m_base(*this, scope) {
         constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value;
+        constexpr bool is_convertible = std::is_convertible<Type, Scalar>::value;
+        m_base.init(is_arithmetic, is_convertible);
 
-        auto m_entries_ptr = m_entries.inc_ref().ptr();
-        def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str {
-            for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
-                if (pybind11::cast<Type>(kv.second[int_(0)]) == value)
-                    return pybind11::str("{}.{}").format(name, kv.first);
-            }
-            return pybind11::str("{}.???").format(name);
-        });
-        def_property_readonly("name", [m_entries_ptr](Type value) -> pybind11::str {
-            for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
-                if (pybind11::cast<Type>(kv.second[int_(0)]) == value)
-                    return pybind11::str(kv.first);
-            }
-            return pybind11::str("???");
-        });
-        def_property_readonly_static("__doc__", [m_entries_ptr](handle self_) {
-            std::string docstring;
-            const char *tp_doc = ((PyTypeObject *) self_.ptr())->tp_doc;
-            if (tp_doc)
-                docstring += std::string(tp_doc) + "\n\n";
-            docstring += "Members:";
-            for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr)) {
-                auto key = std::string(pybind11::str(kv.first));
-                auto comment = kv.second[int_(1)];
-                docstring += "\n\n  " + key;
-                if (!comment.is_none())
-                    docstring += " : " + (std::string) pybind11::str(comment);
-            }
-            return docstring;
-        });
-        def_property_readonly_static("__members__", [m_entries_ptr](handle /* self_ */) {
-            dict m;
-            for (const auto &kv : reinterpret_borrow<dict>(m_entries_ptr))
-                m[kv.first] = kv.second[int_(0)];
-            return m;
-        }, return_value_policy::copy);
         def(init([](Scalar i) { return static_cast<Type>(i); }));
         def("__int__", [](Type value) { return (Scalar) value; });
         #if PY_MAJOR_VERSION < 3
             def("__long__", [](Type value) { return (Scalar) value; });
         #endif
-        def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; });
-        def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; });
-        if (is_arithmetic) {
-            def("__lt__", [](const Type &value, Type *value2) { return value2 && value < *value2; });
-            def("__gt__", [](const Type &value, Type *value2) { return value2 && value > *value2; });
-            def("__le__", [](const Type &value, Type *value2) { return value2 && value <= *value2; });
-            def("__ge__", [](const Type &value, Type *value2) { return value2 && value >= *value2; });
-        }
-        if (std::is_convertible<Type, Scalar>::value) {
-            // Don't provide comparison with the underlying type if the enum isn't convertible,
-            // i.e. if Type is a scoped enum, mirroring the C++ behaviour.  (NB: we explicitly
-            // convert Type to Scalar below anyway because this needs to compile).
-            def("__eq__", [](const Type &value, Scalar value2) { return (Scalar) value == value2; });
-            def("__ne__", [](const Type &value, Scalar value2) { return (Scalar) value != value2; });
-            if (is_arithmetic) {
-                def("__lt__", [](const Type &value, Scalar value2) { return (Scalar) value < value2; });
-                def("__gt__", [](const Type &value, Scalar value2) { return (Scalar) value > value2; });
-                def("__le__", [](const Type &value, Scalar value2) { return (Scalar) value <= value2; });
-                def("__ge__", [](const Type &value, Scalar value2) { return (Scalar) value >= value2; });
-                def("__invert__", [](const Type &value) { return ~((Scalar) value); });
-                def("__and__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; });
-                def("__or__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; });
-                def("__xor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; });
-                def("__rand__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; });
-                def("__ror__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; });
-                def("__rxor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; });
-                def("__and__", [](const Type &value, const Type &value2) { return (Scalar) value & (Scalar) value2; });
-                def("__or__", [](const Type &value, const Type &value2) { return (Scalar) value | (Scalar) value2; });
-                def("__xor__", [](const Type &value, const Type &value2) { return (Scalar) value ^ (Scalar) value2; });
-            }
-        }
-        def("__hash__", [](const Type &value) { return (Scalar) value; });
-        // Pickling and unpickling -- needed for use with the 'multiprocessing' module
-        def(pickle([](const Type &value) { return pybind11::make_tuple((Scalar) value); },
-                   [](tuple t) { return static_cast<Type>(t[0].cast<Scalar>()); }));
+        cpp_function setstate(
+            [](Type &value, Scalar arg) { value = static_cast<Type>(arg); },
+            is_method(*this));
+        attr("__setstate__") = setstate;
     }
 
     /// Export enumeration entries into the parent scope
     enum_& export_values() {
-        for (const auto &kv : m_entries)
-            m_parent.attr(kv.first) = kv.second[int_(0)];
+        m_base.export_values();
         return *this;
     }
 
     /// Add an enumeration entry
     enum_& value(char const* name, Type value, const char *doc = nullptr) {
-        auto v = pybind11::cast(value, return_value_policy::copy);
-        this->attr(name) = v;
-        m_entries[pybind11::str(name)] = std::make_pair(v, doc);
+        m_base.value(name, pybind11::cast(value, return_value_policy::copy), doc);
         return *this;
     }
 
 private:
-    dict m_entries;
-    handle m_parent;
+    detail::enum_base m_base;
 };
 
 NAMESPACE_BEGIN(detail)
@@ -1777,6 +1872,15 @@ public:
         tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
 
         if (!tstate) {
+            /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if
+               calling from a Python thread). Since we use a different key, this ensures
+               we don't create a new thread state and deadlock in PyEval_AcquireThread
+               below. Note we don't save this state with internals.tstate, since we don't
+               create it we would fail to clear it (its reference count should be > 0). */
+            tstate = PyGILState_GetThisThreadState();
+        }
+
+        if (!tstate) {
             tstate = PyThreadState_New(internals.istate);
             #if !defined(NDEBUG)
                 if (!tstate)
@@ -1983,10 +2087,8 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
 
 NAMESPACE_END(PYBIND11_NAMESPACE)
 
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
 #  pragma warning(pop)
-#elif defined(__INTEL_COMPILER)
-/* Leave ignored warnings on */
 #elif defined(__GNUG__) && !defined(__clang__)
 #  pragma GCC diagnostic pop
 #endif
diff --git a/thirdparty/pybind11/include/pybind11/pytypes.h b/thirdparty/pybind11/include/pybind11/pytypes.h
index d280201..3329fda 100644
--- a/thirdparty/pybind11/include/pybind11/pytypes.h
+++ b/thirdparty/pybind11/include/pybind11/pytypes.h
@@ -114,6 +114,35 @@ public:
     bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); }
     /// Equivalent to ``obj is None`` in Python.
     bool is_none() const { return derived().ptr() == Py_None; }
+    /// Equivalent to obj == other in Python
+    bool equal(object_api const &other) const      { return rich_compare(other, Py_EQ); }
+    bool not_equal(object_api const &other) const  { return rich_compare(other, Py_NE); }
+    bool operator<(object_api const &other) const  { return rich_compare(other, Py_LT); }
+    bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); }
+    bool operator>(object_api const &other) const  { return rich_compare(other, Py_GT); }
+    bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); }
+
+    object operator-() const;
+    object operator~() const;
+    object operator+(object_api const &other) const;
+    object operator+=(object_api const &other) const;
+    object operator-(object_api const &other) const;
+    object operator-=(object_api const &other) const;
+    object operator*(object_api const &other) const;
+    object operator*=(object_api const &other) const;
+    object operator/(object_api const &other) const;
+    object operator/=(object_api const &other) const;
+    object operator|(object_api const &other) const;
+    object operator|=(object_api const &other) const;
+    object operator&(object_api const &other) const;
+    object operator&=(object_api const &other) const;
+    object operator^(object_api const &other) const;
+    object operator^=(object_api const &other) const;
+    object operator<<(object_api const &other) const;
+    object operator<<=(object_api const &other) const;
+    object operator>>(object_api const &other) const;
+    object operator>>=(object_api const &other) const;
+
     PYBIND11_DEPRECATED("Use py::str(obj) instead")
     pybind11::str str() const;
 
@@ -124,6 +153,9 @@ public:
     int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
     /// Return a handle to the Python type object underlying the instance
     handle get_type() const;
+
+private:
+    bool rich_compare(object_api const &other, int value) const;
 };
 
 NAMESPACE_END(detail)
@@ -292,7 +324,7 @@ public:
     /// Constructs a new exception from the current Python error indicator, if any.  The current
     /// Python error indicator will be cleared.
     error_already_set() : std::runtime_error(detail::error_string()) {
-        //PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr());
+        PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr());
     }
 
     error_already_set(const error_already_set &) = default;
@@ -356,6 +388,14 @@ inline bool hasattr(handle obj, const char *name) {
     return PyObject_HasAttrString(obj.ptr(), name) == 1;
 }
 
+inline void delattr(handle obj, handle name) {
+    if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) { throw error_already_set(); }
+}
+
+inline void delattr(handle obj, const char *name) {
+    if (PyObject_DelAttrString(obj.ptr(), name) != 0) { throw error_already_set(); }
+}
+
 inline object getattr(handle obj, handle name) {
     PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr());
     if (!result) { throw error_already_set(); }
@@ -427,7 +467,6 @@ object object_or_cast(T &&o);
 // Match a PyObject*, which we want to convert directly to handle via its converting constructor
 inline handle object_or_cast(PyObject *ptr) { return ptr; }
 
-
 template <typename Policy>
 class accessor : public object_api<accessor<Policy>> {
     using key_type = typename Policy::key_type;
@@ -693,6 +732,9 @@ inline bool PyIterable_Check(PyObject *obj) {
 }
 
 inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
+#if PY_MAJOR_VERSION >= 3
+inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; }
+#endif
 
 inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
 
@@ -967,6 +1009,14 @@ public:
     none() : object(Py_None, borrowed_t{}) { }
 };
 
+#if PY_MAJOR_VERSION >= 3
+class ellipsis : public object {
+public:
+    PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check)
+    ellipsis() : object(Py_Ellipsis, borrowed_t{}) { }
+};
+#endif
+
 class bool_ : public object {
 public:
     PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool)
@@ -1140,6 +1190,7 @@ public:
     }
     size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
     detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
+    detail::item_accessor operator[](handle h) const { return object::operator[](h); }
     detail::tuple_iterator begin() const { return {*this, 0}; }
     detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
 };
@@ -1177,6 +1228,7 @@ public:
     PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)
     size_t size() const { return (size_t) PySequence_Size(m_ptr); }
     detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
+    detail::item_accessor operator[](handle h) const { return object::operator[](h); }
     detail::sequence_iterator begin() const { return {*this, 0}; }
     detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
 };
@@ -1189,6 +1241,7 @@ public:
     }
     size_t size() const { return (size_t) PyList_Size(m_ptr); }
     detail::list_accessor operator[](size_t index) const { return {*this, index}; }
+    detail::item_accessor operator[](handle h) const { return object::operator[](h); }
     detail::list_iterator begin() const { return {*this, 0}; }
     detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
     template <typename T> void append(T &&val) const {
@@ -1331,5 +1384,55 @@ str_attr_accessor object_api<D>::doc() const { return attr("__doc__"); }
 template <typename D>
 handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); }
 
+template <typename D>
+bool object_api<D>::rich_compare(object_api const &other, int value) const {
+    int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value);
+    if (rv == -1)
+        throw error_already_set();
+    return rv == 1;
+}
+
+#define PYBIND11_MATH_OPERATOR_UNARY(op, fn)                                   \
+    template <typename D> object object_api<D>::op() const {                   \
+        object result = reinterpret_steal<object>(fn(derived().ptr()));        \
+        if (!result.ptr())                                                     \
+            throw error_already_set();                                         \
+        return result;                                                         \
+    }
+
+#define PYBIND11_MATH_OPERATOR_BINARY(op, fn)                                  \
+    template <typename D>                                                      \
+    object object_api<D>::op(object_api const &other) const {                  \
+        object result = reinterpret_steal<object>(                             \
+            fn(derived().ptr(), other.derived().ptr()));                       \
+        if (!result.ptr())                                                     \
+            throw error_already_set();                                         \
+        return result;                                                         \
+    }
+
+PYBIND11_MATH_OPERATOR_UNARY (operator~,   PyNumber_Invert)
+PYBIND11_MATH_OPERATOR_UNARY (operator-,   PyNumber_Negative)
+PYBIND11_MATH_OPERATOR_BINARY(operator+,   PyNumber_Add)
+PYBIND11_MATH_OPERATOR_BINARY(operator+=,  PyNumber_InPlaceAdd)
+PYBIND11_MATH_OPERATOR_BINARY(operator-,   PyNumber_Subtract)
+PYBIND11_MATH_OPERATOR_BINARY(operator-=,  PyNumber_InPlaceSubtract)
+PYBIND11_MATH_OPERATOR_BINARY(operator*,   PyNumber_Multiply)
+PYBIND11_MATH_OPERATOR_BINARY(operator*=,  PyNumber_InPlaceMultiply)
+PYBIND11_MATH_OPERATOR_BINARY(operator/,   PyNumber_TrueDivide)
+PYBIND11_MATH_OPERATOR_BINARY(operator/=,  PyNumber_InPlaceTrueDivide)
+PYBIND11_MATH_OPERATOR_BINARY(operator|,   PyNumber_Or)
+PYBIND11_MATH_OPERATOR_BINARY(operator|=,  PyNumber_InPlaceOr)
+PYBIND11_MATH_OPERATOR_BINARY(operator&,   PyNumber_And)
+PYBIND11_MATH_OPERATOR_BINARY(operator&=,  PyNumber_InPlaceAnd)
+PYBIND11_MATH_OPERATOR_BINARY(operator^,   PyNumber_Xor)
+PYBIND11_MATH_OPERATOR_BINARY(operator^=,  PyNumber_InPlaceXor)
+PYBIND11_MATH_OPERATOR_BINARY(operator<<,  PyNumber_Lshift)
+PYBIND11_MATH_OPERATOR_BINARY(operator<<=, PyNumber_InPlaceLshift)
+PYBIND11_MATH_OPERATOR_BINARY(operator>>,  PyNumber_Rshift)
+PYBIND11_MATH_OPERATOR_BINARY(operator>>=, PyNumber_InPlaceRshift)
+
+#undef PYBIND11_MATH_OPERATOR_UNARY
+#undef PYBIND11_MATH_OPERATOR_BINARY
+
 NAMESPACE_END(detail)
 NAMESPACE_END(PYBIND11_NAMESPACE)
diff --git a/thirdparty/pybind11/include/pybind11/stl.h b/thirdparty/pybind11/include/pybind11/stl.h
index faa7087..32f8d29 100644
--- a/thirdparty/pybind11/include/pybind11/stl.h
+++ b/thirdparty/pybind11/include/pybind11/stl.h
@@ -16,6 +16,7 @@
 #include <unordered_map>
 #include <iostream>
 #include <list>
+#include <deque>
 #include <valarray>
 
 #if defined(_MSC_VER)
@@ -83,7 +84,8 @@ template <typename Type, typename Key> struct set_caster {
 
     template <typename T>
     static handle cast(T &&src, return_value_policy policy, handle parent) {
-        policy = return_value_policy_override<Key>::policy(policy);
+        if (!std::is_lvalue_reference<T>::value)
+            policy = return_value_policy_override<Key>::policy(policy);
         pybind11::set s;
         for (auto &&value : src) {
             auto value_ = reinterpret_steal<object>(key_conv::cast(forward_like<T>(value), policy, parent));
@@ -119,8 +121,12 @@ template <typename Type, typename Key, typename Value> struct map_caster {
     template <typename T>
     static handle cast(T &&src, return_value_policy policy, handle parent) {
         dict d;
-        return_value_policy policy_key = return_value_policy_override<Key>::policy(policy);
-        return_value_policy policy_value = return_value_policy_override<Value>::policy(policy);
+        return_value_policy policy_key = policy;
+        return_value_policy policy_value = policy;
+        if (!std::is_lvalue_reference<T>::value) {
+            policy_key = return_value_policy_override<Key>::policy(policy_key);
+            policy_value = return_value_policy_override<Value>::policy(policy_value);
+        }
         for (auto &&kv : src) {
             auto key = reinterpret_steal<object>(key_conv::cast(forward_like<T>(kv.first), policy_key, parent));
             auto value = reinterpret_steal<object>(value_conv::cast(forward_like<T>(kv.second), policy_value, parent));
@@ -138,7 +144,7 @@ template <typename Type, typename Value> struct list_caster {
     using value_conv = make_caster<Value>;
 
     bool load(handle src, bool convert) {
-        if (!isinstance<sequence>(src))
+        if (!isinstance<sequence>(src) || isinstance<str>(src))
             return false;
         auto s = reinterpret_borrow<sequence>(src);
         value.clear();
@@ -161,7 +167,8 @@ private:
 public:
     template <typename T>
     static handle cast(T &&src, return_value_policy policy, handle parent) {
-        policy = return_value_policy_override<Value>::policy(policy);
+        if (!std::is_lvalue_reference<T>::value)
+            policy = return_value_policy_override<Value>::policy(policy);
         list l(src.size());
         size_t index = 0;
         for (auto &&value : src) {
@@ -179,6 +186,9 @@ public:
 template <typename Type, typename Alloc> struct type_caster<std::vector<Type, Alloc>>
  : list_caster<std::vector<Type, Alloc>, Type> { };
 
+template <typename Type, typename Alloc> struct type_caster<std::deque<Type, Alloc>>
+ : list_caster<std::deque<Type, Alloc>, Type> { };
+
 template <typename Type, typename Alloc> struct type_caster<std::list<Type, Alloc>>
  : list_caster<std::list<Type, Alloc>, Type> { };
 
@@ -199,9 +209,9 @@ private:
 
 public:
     bool load(handle src, bool convert) {
-        if (!isinstance<list>(src))
+        if (!isinstance<sequence>(src))
             return false;
-        auto l = reinterpret_borrow<list>(src);
+        auto l = reinterpret_borrow<sequence>(src);
         if (!require_size(l.size()))
             return false;
         size_t ctr = 0;


Mime
View raw message