Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ModuleNotFoundError: No module named 'xxx' and NameError: name 'xxx' is not defined #468

Open
y1y2 opened this issue Jan 15, 2025 · 19 comments

Comments

@y1y2
Copy link

y1y2 commented Jan 15, 2025

I called python in kotlin and started reporting ModuleNotFoundError: No module named 'xxx'.
I added

@y1y2 y1y2 changed the title ModuleNotFoundError: No module named 'xxx' and NameError: name 'TraceContext' is not defined ModuleNotFoundError: No module named 'xxx' and NameError: name 'xxx' is not defined Jan 15, 2025
@msimacek
Copy link
Contributor

I don't understand your file layout, what is xxx? Where is it imported?
Does your python code work under CPython?

There is already a module named java in the standard library, it could be causing problems. Please rename the module or put all your modules into a package to namespace it.

@y1y2
Copy link
Author

y1y2 commented Jan 24, 2025

I tried to modify the file name of java.py for java execution
”context.eval(source)“
No problem, but I use
“ctx.getBindings(mainScriptType).getMember("a").execute()”
Call a function a() in a.py, which calls the b() method in another b.py file with a
“NameError: name 'xxx' is not defined”,
xxx is a reference to a function under b(),
if I move b() to the a.y file, there is no problem, this has been troubling for a long time.

@msimacek
Copy link
Contributor

msimacek commented Feb 4, 2025

Here's what I tried:
a.py:

import b
def a():
    b.b()

b.py:

def b():
    xxx()

def xxx():
    print('hi')

Main.java:

        try (Context context = GraalPyResources.createContext()) {
            context.eval("python", "from a import a");
            context.getBindings("python").getMember("a").execute();
        }

That just prints hi.
What do you do differently? Can you post a modified version of these files that reproduce the problem?

@y1y2
Copy link
Author

y1y2 commented Feb 11, 2025

Attempts to call the boot method in b.py with NameError: name 'stats' is not defined

Main.java:
ctx.getBindings(mainScriptType).getMember("boot").execute()

a.py:

import json

STATS_EXT_PREFIX = "Ext::"

class TraceContext:
    pass

class ScriptStats:

    def addStatsGroup(self, gStr: str):
        pass

stats: ScriptStats

class ScriptBase:
    def traceContext(self) -> TraceContext:
        pass

base: ScriptBase

class ChartGroup:
    def __init__(self, id: str, label: str, displayOrder: int = None, items: list = None):
        self.id = id
        self.label = label
        self.dis

def addStatsGroup(g: ChartGroup):
    stats.addStatsGroup(json.dumps(g))

b.py:

import sys
import os

current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(current_dir)
from a import *
from c import statsGroup


def boot():
    tc = base.traceContext()
    base.logInfo(tc, "this is  boot")

    addStatsGroup(statsGroup)

c.py:

from a import STATS_EXT_PREFIX

statsGroup = {
    "id": "Ext1",
    "label": "Ext1",
    "items": [
        {
            "id": STATS_EXT_PREFIX + "task",
            "label": "task",
        }
    ]
} 

@msimacek
Copy link
Contributor

Well, you really don't define stats, you need to assign something to it. stats: ScriptStats is just a type annotation, it doesn't actually define the variable. You need to do something like stats = ScriptStats().

@y1y2
Copy link
Author

y1y2 commented Feb 11, 2025

a.py is used to prompt, or to execute kotlin methods, because I use
bindings.putMember("stats", ScriptStats)
if you add
stats = ScriptStats(),
it will call the function of py directly, Functions exposed in kotlin are not executed

@msimacek
Copy link
Contributor

The modules have their own independent globals. bindings is the main module globals which is not the same as a module's globals. To set something in a module globals, you can do something like:

context.eval("python", "import a");
Value aModule = bindings.getMember("a");
aModule.putMember("stats", ScriptStats);

@y1y2
Copy link
Author

y1y2 commented Feb 11, 2025

So if it's python, you can't use import in.py files, or you might have problems like mine? If I can't use context. eval("python", "import a ") in kotlin, how can I circumvent this problem?

@msimacek
Copy link
Contributor

Of course you can use import. I showed you how to fix the NameError, what is the problem now?

@y1y2
Copy link
Author

y1y2 commented Feb 11, 2025

Due to software design, I can't use context.eval ("python", "import a ") in kotlin code. At this time, is there any other way to solve this problem I encountered? Can you solve it in .py code?

@msimacek
Copy link
Contributor

But you can import b and you can do import a in b, right? Then get a from b - bindings.getMember("b").getMember("a").putMember("stats", ScriptStats)

@y1y2
Copy link
Author

y1y2 commented Feb 11, 2025

Sorry, I can't add or modify the backend
The code can only control py, so how to avoid this problem?

@msimacek
Copy link
Contributor

Why can't you import a from kotlin? If you have a circular dependency between a and b you should still be able to import a after you imported b.

@y1y2
Copy link
Author

y1y2 commented Feb 11, 2025

The back-end code has context.eval(source) loaded with a.y, but bindings.getMember("a ") Do not understand, is not the query also this function

@msimacek
Copy link
Contributor

So you don't import a, but eval it directly as a file? Can you show a bit more of the java code of how you load and invoke a and b?

@y1y2
Copy link
Author

y1y2 commented Feb 12, 2025

sources is all of py code files

createMainContext().use { ctx ->
      val bindings = ctx.getBindings("python")
      if (!bindings.hasMember("boot")) {
        tc.info(logger, "not hava(boot)")
      } else {
        bindings.getMember("boot").execute()
      }
}

fun createMainContext(): Context = createContext(mainScriptType, sources)

fun createContext(scriptType: String, sources: List<Source>): Context {
  val context = Context.newBuilder(scriptType)
      .allowAllAccess(true)
      .allowHostAccess(HostAccess.ALL)
      .option("log.file", "script.log")
      .option("python.EmulateJython","true")
      .build()
  for (source in sources) {
      context.eval(source)
    }
   val bindings = context.getBindings(scriptType)
   bindings.putMember("stats", ScriptStats)
   return context
}

@msimacek
Copy link
Contributor

Don't eval all the files like this, you end up having the same module evaluated twice because they also import each other. For example, first you eval the source a's file in the global namespace, but then you also eval b which imports a, which will load it second time in it's own namespace. Then you have two independent copies of stuff from a, you see one in bindings, but b module sees a different one.

Instead of evaling the sources, add the directory with the sources to python path and then import them by names.

@y1y2
Copy link
Author

y1y2 commented Feb 12, 2025

I move the addStatsGroup method in a.py to b.py, and it works. why?

@msimacek
Copy link
Contributor

Here's a demo that works with the 3 files you posted:

package com.example;

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

public class Main {

    public static class StatsGroup {
        public void addStatsGroup(String str) {
            System.out.println(str);
        }
    }

    public static class ScriptBase {
        public Object traceContext() {
            return "something";
        }

        public void logInfo(Object tc, String message) {
            System.out.println(message);
        }
    }

    public static void main(String[] args) {
        try (Context context = Context.newBuilder("python")
                .allowAllAccess(true)
                .option("python.PythonPath", System.getProperty("user.dir"))
                .build()) {
            Value bindings = context.getBindings("python");
            context.eval("python", "import a");
            Value aModule = bindings.getMember("a");
            aModule.putMember("stats", new StatsGroup());
            aModule.putMember("base", new ScriptBase());
            context.eval("python", """
                    import b
                    b.boot()
                    """);
        }
    }
}

It looks for the python files in the current directory. If you use the maven or gradle plugins, you can also put them in src/main/resources/org.graalvm.python.vfs/src and then it will package them in your jar and you don't need to set the python path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants