1. 13 Aug, 2017 1 commit
  2. 05 Aug, 2017 1 commit
    • Jason Rhinelander's avatar
      Made module_local types take precedence over global types · 4b159230
      Jason Rhinelander authored
      Attempting to mix py::module_local and non-module_local classes results
      in some unexpected/undesirable behaviour:
      
      - if a class is registered non-local by some other module, a later
        attempt to register it locally fails.  It doesn't need to: it is
        perfectly acceptable for the local registration to simply override
        the external global registration.
      - going the other way (i.e. module `A` registers a type `T` locally,
        then `B` registers the same type `T` globally) causes a more serious
        issue: `A.T`'s constructors no longer work because the `self` argument
        gets converted to a `B.T`, which then fails to resolve.
      
      Changing the cast precedence to prefer local over global fixes this and
      makes it work more consistently, regardless of module load order.
      4b159230
  3. 04 Aug, 2017 3 commits
    • Jason Rhinelander's avatar
      Add py::module_local() attribute for module-local type bindings · 7437c695
      Jason Rhinelander authored
      This commit adds a `py::module_local` attribute that lets you confine a
      registered type to the module (more technically, the shared object) in
      which it is defined, by registering it with:
      
          py::class_<C>(m, "C", py::module_local())
      
      This will allow the same C++ class `C` to be registered in different
      modules with independent sets of class definitions.  On the Python side,
      two such types will be completely distinct; on the C++ side, the C++
      type resolves to a different Python type in each module.
      
      This applies `py::module_local` automatically to `stl_bind.h` bindings
      when the container value type looks like something global: i.e. when it
      is a converting type (for example, when binding a `std::vector<int>`),
      or when it is a registered type itself bound with `py::module_local`.
      This should help resolve potential future conflicts (e.g. if two
      completely unrelated modules both try to bind a `std::vector<int>`.
      Users can override the automatic selection by adding a
      `py::module_local()` or `py::module_local(false)`.
      
      Note that this does mildly break backwards compatibility: bound stl
      containers of basic types like `std::vector<int>` cannot be bound in one
      module and returned in a different module.  (This can be re-enabled with
      `py::module_local(false)` as described above, but with the potential for
      eventual load conflicts).
      7437c695
    • Jason Rhinelander's avatar
      Fix builtin exception handlers to work across modules · d5981729
      Jason Rhinelander authored
      The builtin exception handler currently doesn't work across modules
      under clang/libc++ for builtin pybind exceptions like
      `pybind11::error_already_set` or `pybind11::stop_iteration`: under
      RTLD_LOCAL module loading clang considers each module's exception
      classes distinct types.  This then means that the base exception
      translator fails to catch the exceptions and the fall through to the
      generic `std::exception` handler, which completely breaks things like
      `stop_iteration`: only the `stop_iteration` of the first module loaded
      actually works properly; later modules raise a RuntimeError with no
      message when trying to invoke their iterators.
      
      For example, two modules defined like this exhibit the behaviour under
      clang++/libc++:
      
      z1.cpp:
          #include <pybind11/pybind11.h>
          #include <pybind11/stl_bind.h>
          namespace py = pybind11;
          PYBIND11_MODULE(z1, m) {
              py::bind_vector<std::vector<long>>(m, "IntVector");
          }
      
      z2.cpp:
          #include <pybind11/pybind11.h>
          #include <pybind11/stl_bind.h>
          namespace py = pybind11;
          PYBIND11_MODULE(z2, m) {
              py::bind_vector<std::vector<double>>(m, "FloatVector");
          }
      
      Python:
          import z1, z2
          for i in z2.FloatVector():
              pass
      
      results in:
          Traceback (most recent call last):
            File "zs.py", line 2, in <module>
              for i in z2.FloatVector():
          RuntimeError
      
      This commit fixes the issue by adding a new exception translator each
      time the internals pointer is initialized from python builtins: this
      generally means the internals data was initialized by some other
      module.  (The extra translator(s) are skipped under libstdc++).
      d5981729
    • Jason Rhinelander's avatar
      Add cross-module test plugin · 0bd5979c
      Jason Rhinelander authored
      This adds the infrastructure for a separate test plugin for cross-module
      tests.  (This commit contains no tests that actually use it, but the
      following commits do; this is separated simply to provide a cleaner
      commit history).
      0bd5979c