pybind / pybind/pybind11

[BUG]: NumPy ImportError with Embedded Interpreter in Adobe After Effects Plugin Using pybind11

Open
#5,282 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

triage
Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

Required prerequisites
What version (or hash if on master) of pybind11 are you using?

2.11.1

Problem description
Problem Description

I'm experiencing an issue with importing NumPy when using an embedded Python interpreter in an Adobe After Effects plugin built with pybind11. The standalone Python interpreter can import NumPy without issues, but the embedded interpreter throws an ImportError related to NumPy's C-extensions.

Expected Behavior

The embedded Python interpreter should import NumPy without any ImportError, as it does in the standalone Python interpreter.

Actual Behavior

When attempting to import NumPy in the embedded interpreter, the following error occurs:

ImportError: Error importing numpy: you should not try to import numpy from its source directory; please exit the numpy source tree, and relaunch your python interpreter from there.
Here is the detailed error output captured:
Captured stdout:

Captured stderr:
Traceback (most recent call last):
  File "C:\Users\tjerf\AppData\Local\Programs\Python\Python311\Lib\site-packages\numpy\core\__init__.py", line 24, in <module>
    from . import multiarray
  File "C:\Users\tjerf\AppData\Local\Programs\Python\Python311\Lib\site-packages\numpy\core\multiarray.py", line 10, in <module>
    from . import overrides
  File "C:\Users\tjerf\AppData\Local\Programs\Python\Python311\Lib\site-packages\numpy\core\overrides.py", line 8, in <module>
    from numpy.core._multiarray_umath import (
ModuleNotFoundError: No module named 'numpy.core._multiarray_umath'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\tjerf\AppData\Local\Programs\Python\Python311\Lib\site-packages\numpy\__init__.py", line 144, in <module>
    from numpy.__config__ import show as show_config
  File "C:\Users\tjerf\AppData\Local\Programs\Python\Python311\Lib\site-packages\numpy\__config__.py", line 4, in <module>
    from numpy.core._multiarray_umath import (
  File "C:\Users\tjerf\AppData\Local\Programs\Python\Python311\Lib\site-packages\numpy\core\__init__.py", line 50, in <module>
    raise ImportError(msg)
ImportError: 

IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!

Importing the numpy C-extensions failed. This error can happen for
many reasons, often due to issues with your setup or how NumPy was
installed.

We have compiled some common reasons and troubleshooting tips at:

    https://numpy.org/devdocs/user/troubleshooting-importerror.html

Please note and check the following:

  * The Python version is: Python3.11 from "C:\Program Files\Adobe\Adobe After Effects 2023\Support Files\AfterFX.exe"
  * The NumPy version is: "1.26.1"

and make sure that they are the versions you expect.
Please carefully study the documentation linked above for further help.

Original error was: No module named 'numpy.core._multiarray_umath'


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 27, in <module>
  File "C:\Users\tjerf\AppData\Local\Programs\Python\Python311\Lib\site-packages\numpy\__init__.py", line 149, in <module>
    raise ImportError(msg) from e
ImportError: Error importing numpy: you should not try to import numpy from
        its source directory; please exit the numpy source tree, and relaunch
        your python interpreter from there.
        ```
        
#### Already Checked:
- Sys.path,
- different numpy versions
- different python versions
- trying in a shell, which works fine. 

### Reproducible example code

```text
Repo with Plugin can be found at https://github.com/Trentonom0r3/AE-Pybind-Error.


#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#include <iostream>

namespace py = pybind11;

int main() {
    try {
        py::scoped_interpreter guard{};  // Start the interpreter

        // Add the path to site-packages and capture environment information
        py::exec(R"(
        import sys
        import os
        from io import StringIO
        import sysconfig

        # Dynamically get site-packages path
        site_packages_path = sysconfig.get_paths()['purelib']

        # Add the site-packages directory to sys.path
        if site_packages_path not in sys.path:
            sys.path.insert(0, site_packages_path)

        # Collect environment information
        environment_info = {
            'sys.executable': sys.executable,
            'sys.version': sys.version,
            'sys.path': sys.path,
            'os.environ': dict(os.environ),
        }

        # Redirect stdout and stderr
        old_stdout = sys.stdout
        old_stderr = sys.stderr
        sys.stdout = StringIO()
        sys.stderr = StringIO()

        try:
            import numpy as np
            print("NumPy version:", np.__version__)
        except Exception as e:
            import traceback
            traceback.print_exc()

        # Get the captured output
        stdout_output = sys.stdout.getvalue()
        stderr_output = sys.stderr.getvalue()

        # Restore stdout and stderr
        sys.stdout = old_stdout
        sys.stderr = old_stderr
        )");

        // Retrieve the captured output from the Python execution
        py::object main_module = py::module::import("__main__");
        py::object stdout_output = main_module.attr("stdout_output");
        py::object stderr_output = main_module.attr("stderr_output");
        py::object environment_info = main_module.attr("environment_info");

        // Convert the captured output and environment information to strings
        std::string stdout_str = stdout_output.cast<std::string>();
        std::string stderr_str = stderr_output.cast<std::string>();
        auto env_info_dict = environment_info.cast<py::dict>();

        std::string env_info_str;
        for (auto item : env_info_dict) {
            env_info_str += item.first.cast<std::string>() + ": ";
            if (py::isinstance<py::str>(item.second)) {
                env_info_str += item.second.cast<std::string>() + "\n";
            } else if (py::isinstance<py::list>(item.second)) {
                auto list = item.second.cast<py::list>();
                env_info_str += "[";
                for (auto elem : list) {
                    env_info_str += elem.cast<std::string>() + ", ";
                }
                env_info_str += "]\n";
            } else if (py::isinstance<py::dict>(item.second)) {
                auto dict = item.second.cast<py::dict>();
                env_info_str += "{";
                for (auto elem : dict) {
                    env_info_str += elem.first.cast<std::string>() + ": " + elem.second.cast<std::string>() + ", ";
                }
                env_info_str += "}\n";
            }
        }

        // Output the information as a single string for debugging
        std::string debug_info = "Captured stdout:\n" + stdout_str + "\nCaptured stderr:\n" + stderr_str + "\nPython Environment Information:\n" + env_info_str;
        std::cout << debug_info << std::endl;

    } catch (const py::error_already_set& e) {
        std::string error_str = "Error in Python execution: " + std::string(e.what());
        std::cout << error_str << std::endl;
    } catch (const std::exception& e) {
        std::string error_str = "Error in Python execution: " + std::string(e.what());
        std::cout << error_str << std::endl;
    } catch (...) {
        std::string error_str = "Error in Python execution: Unknown exception";
        std::cout << error_str << std::endl;
    }

    return 0;
}
Is this a regression? Put the last known working version here if it is.

Not a regression

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the embedded-interpreter example from the issue and the linked AE-Pybind-Error repository, then compare its sys.path, Python version, and NumPy version with the standalone interpreter. Trace the missing numpy.core._multiarray_umath import to determine whether the cause is pybind11, the embedded host, or the environment; done means a confirmed cause and an actionable fix or documentation update.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, numpy, python
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.