Search code examples
javapythonmodulejythoncallable

"TypeError: 'module' object is not callable" using Jython


I have a python module, consisting of import_ical.py and __init__.py in my directory . Calling this module from console works, when using: python -m .import_ical .import_ical.py

When I call the same module using Jython, I get:

TypeError: 'module' object is not callable
  at org.python.core.Py.TypeError(Py.java:263)
  at org.python.core.PyObject.__call__(PyObject.java:390)
  at org.python.core.PyObject.__call__(PyObject.java:496)
  at services.imports.CalendarImporter.importFromUrl(CalendarImporter.java:53)
  at services.imports.CalendarImporterTest.testMultipleEventsImport(CalendarImporterTest.java:21)
  [...]

CalendarImporter.importFromUrl() does the following:

PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("import sys");
interpreter.exec("sys.path.append('<dir>')");
interpreter.exec("sys.path.append('/home/<user>/.local/lib/python2.7/site-packages')");
interpreter.exec("import import_ical");
PyObject importIcalPy = interpreter.get("import_ical");
PyObject pythonResult = importIcalPy.__call__(<parameters go here>);

When I execute my JUnit test (CalendarImporterTest) that executes this Jython code, a class file is generated in my module directory, named import_ical$py.class. It contains the following lines (amongst others):

@Filename("<dir>/import_ical.py")
public class import_ical$py extends PyFunctionTable implements PyRunnable {
  [....]
  static final PyCode __call__$20;
  [....]

  public PyObject __call__$20(PyFrame var1, ThreadState var2) {
    var1.setline(243);
    PyObject var3 = var1.getglobal("import_ical").__call__(var2, var1.getlocal(0), var1.getlocal(1), var1.getlocal(2));
    var1.f_lasti = -1;
    return var3;
  }
}

Debugging to the last line of my CalendarImporter Java code shown above gives me the following variables states:

interpreter = {PythonInterpreter}
  [...]
  globals = {PyStringMap}
    table
      [...]
      1 = {ConcurrentHashMap$MapEntry} "import_ical" -> "<module 'import_ical' from '<dir>/import_ical$py.class'>"
      [...]
    [...]
  [...]
importIcalPy = {PyModule}
  [...]
  __dict__ = {PyStringMap}
    table
      [...]
      19 = {ConcurrentHashMap$MapEntry} "import_ical" -> "<function import_ical at 0xc>"
      [...]
      32 = {ConcurrentHashMap$MapEntry} "__call__" -> "<function __call__ at 0x13>"
      [...]
    [...]
  [...]

As a python newbie, I cannot detect anything that would arouse my scepticism with regards to the generated class file of the module and even the variables' state shown above seems to tell me that there is a proper function __call__ within in my python module importIcalPy.

Note: I had already added the function __call__ to my python module to make the module by "callable" from Jython and catch this error - obviously without success.

So can anyone please tell me: why do I get that "not callable" error? And what can I do to prevent it? Any help is greatly appreciated - thank you!

[Comment: I have intensely searched for a solution both, in Stackoverflow and using a big search engine, but all search results lead me to another problem where a python module could not call another python module.]


Solution

  • Finally, and thanks to the hints of user2357112, I've found a fix. Replace the content of CalendarImporter.importFromUrl() shown above with the following code:

    PythonInterpreter.initialize(System.getProperties(), System.getProperties(), new String[0]);
    PythonInterpreter interpreter = new PythonInterpreter();
    interpreter.exec("import sys");
    interpreter.exec("sys.path.append('<dir>')");
    interpreter.exec("sys.path.append('/home/<user>/.local/lib/python2.7/site-packages')");
    interpreter.exec("import import_ical");
    // set variables if necessary in script:
    // interpreter.set("__file__", <myFile>);
    // set system argument variables (one append per variable):
    interpreter.exec("sys.argv.append('".concat("<myVar>").concat("')"));
    interpreter.execfile("<fileWithQualifiedPath>");
    PyObject importIcalPy = interpreter.get("import_ical");
    PyObject pythonResult = importIcalPy.__call__(new PyString("<myScriptArgument>"));
    

    Hope, it will help someone.