Python app to run JasperReport libraries - i.e. no JasperServer - python

I'm looking to try and run Jasper reports (that have been written in iReports and exported to xml) from within a python application, without having to communicate with a JasperServer instance. Is this possible?
I've done some googling and only come across a 2 year old SO question (where the suggested answer actually requires JasperServer):
Run jasper report (created with iReport) from within python without jasperserver?
And something that looks kind of promising, except for the "It is obsolete" in the title:
http://code.activestate.com/recipes/576969-python-jasperreport-integration-it-is-obsolete/
I'm hoping it's obsolete because this is now an officially supported thing (dream on, Dave), but I can't find anything about it, if it is.

Actually Jasper Reports are not implemented in Python, so the only way to have it serving to your Python code is to have Jasper Server running and awaiting Python requests over REST or other remote way of communication.
Simply - no way to have Jasper without Jasper (server) in Python

I used py4j. I had to write a small program in java.
Using this as an example, it was simple.
It was more difficult to configure the build environment and put all the dependencies for printing qr-codes.
Python example:
from py4j.java_gateway import JavaGateway
gateway = JavaGateway()
gateway.entry_point.pdf_from_json('e:/test.jasper', 'e:/test.json', 'e:/test.pdf')
Java example:
package jasper4py;
import py4j.GatewayServer;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JsonDataSource;
import net.sf.jasperreports.engine.util.JRLoader;
public class JasperEntryPoint {
public static void main(String[] args) {
GatewayServer gatewayServer = new GatewayServer(new JasperEntryPoint());
gatewayServer.start();
System.out.println("Gateway Server Started");
}
public void pdf_from_json(String report, String data, String result) throws JRException, IOException {
Map<String, Object> parameters = new HashMap<String, Object>();
JsonDataSource dataSource = new JsonDataSource(JRLoader.getLocationInputStream(data));
JasperPrint jasperPrint = JasperFillManager.fillReport(report, parameters, dataSource);
JasperExportManager.exportReportToPdfFile(jasperPrint, result);
}
}

Related

Pythonnet dotnet core 'No module named'

I am trying to use a .NET Core library inside a Jupyter Notebook python script by using PythonNet. Support for .NET Core was added recently (see https://github.com/pythonnet/pythonnet/issues/984#issuecomment-778786164) but I am still getting a No module named 'TestAppCore' error.
I don't have an issue using a .NET Framework library with PythonNet, only .NET Core. Any help with diagnosing and fixing the issue would be greatly appreciated.
The C# library I'm trying to get working is a simple class library project with no dependencies at all. Below is the entirety of the code:
namespace TestAppCore
{
public class Foo
{
public int ID { get; set; }
public Foo(int id)
{
ID = id;
}
public int Add(int a, int b)
{
return a + b;
}
}
}
Here is the python script:
from clr_loader import get_coreclr
from pythonnet import set_runtime
rt = get_coreclr("D:\src\Test.runtimeconfig.json")
set_runtime(rt)
import clr
import sys
sys.path.append(r"D:\src\TestAppCore")
clr.AddReference(r"TestAppCore")
from TestAppCore import Foo
foo = Foo(5)
print(foo.ID)
res = foo.Add(1, 2)
print(res)
Here is the output:
Finally, here is the runtime config I am using:
{
"runtimeOptions": {
"tfm": "netcoreapp3.1",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "3.1.0"
}
}
}
.NET Core: 3.1
python version: 3.7
pythonnet: 3.0.0.dev1
clr-loader: 0.1.6
I suspect that you are getting the DLL path wrong.
This worked for me:
from clr_loader import get_coreclr
from pythonnet import set_runtime
set_runtime(get_coreclr("pythonnetconfig.json"))
import clr
clr.AddReference("C:/Path/To/Interface.dll")
from Interface import Foo
foo = Foo()
Using
Python 3.8.10
pythonnet 3.0.0a1
clr-loader 0.1.7
C# DLL (Class Library) targeting .NET Core 3.1
pythonnetconfig.json exactly as you posted.
I never got it to work with .NET Core 3.1. For me it worked with .NET Framework 4.8 and pythonnet 2.5.2. See my other answer for more details.
I have a similar problem and found out that if the DLL and the namespace are the same, then it fails. In my case, following pythonnet tutorial:
Calculate.sln contains Calc.cs, with
namespace Calculate; // recommended by VS
class Calc { ... }
Then in Python
clr.AddReference("Calculate") # Assuming sys.path correct setting
from Calculate import Calc
Then:
ImportError: cannot import name 'Calc' from 'Calculate' (unknown location)
But with:
namespace CalculateNS; // different name than Calculate.dll
class Calc { ... }
Then in Python
clr.AddReference("Calculate") # Assuming sys.path correct setting
from CalculateNS import Calc
it works... side effects, pylance known Calculate module but not CalculateNS :-(
Anyone experimented this? I saw lot of answers that have never been tested I guess, only thoughts
Using .NET 6.0 Framework.

Calling C# DLL from Python with "out" parameter

I have a C# piece that generates a DLL which I'm trying to invoke from Python. The C# prototype is as follow:
public Main(NationalInstruments.TestStand.Interop.API.SequenceContext sequenceContext){
public void ShowFullOptions(out bool errorOccurred, out int errorCode, out String errorMsg) {
[...]
}
}
I followed this post which explains how to achieve to pass "out" parameters from python, without success since clr.Reference does not exist and throw me the error:
AttributeError: module 'clr' has no attribute 'Reference'
I have pythonnet installed, version 2.3.
My python code:
import clr
dll_path = R"thatDllPath.dll"
clr.AddReference(dll_path)
from Flamenco_Calibration_Interface import Main
import System
my_instance = Main(None)
v1 = clr.Reference[System.Boolean](False)
v2 = clr.Reference[System.Int64](1)
v3 = clr.Reference[System.String]("")
a = my_instance.ShowFullOptions(v1,v2,v3)
I have checked that the DLL path is good and I am able to successfully call the C# method if I overload "ShowFullOptions" with a version without any arguments.
The main problem resides in that I have the "out" keyword in the C# method prototype.
How do you properly generate argument in python so they are accepted as "out" within C# ?
Any help much appreciated.

PythonKit crashes on start due to dlopen returning nil

I'm trying to use some Python Code in my Swift project with PythonKit. In order to do that, I've downloaded the new Xcode 11 to add PythonKit as Swift Package.
After adding PythonKit with Swift Package, I have these project dependencies right here.
I want to use my Python code at the start of my app, so I put the call for Python code in my App Delegate, in the application function.
import UIKit
import PythonKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let sys = Python.import("sys")
print("Python Version: \(sys.version)")
sys.path.append("/Users/me/Documents/MyProject/MyPackage/my_python_main_file")
let pythonAPI = Python.import("my_python_main_file")
pythonAPI.main_function.call()
return true
}
After running my project, I get the following error :
Fatal error: Python library not found. Set the PYTHON_LIBRARY environment variable with the path to a Python library.
I tried to follow the different steps with Breakpoints to know where the code actually crashes. So here is the different stages the PythonKit goes through :
It goes inside PythonLibrary init() and produces the error :
guard let pythonLibraryHandle = PythonLibrary.loadPythonLibrary() else {
fatalError("""
Python library not found. Set the \(Environment.library.key) \
environment variable with the path to a Python library.
""")
}
After investigation, it is because of the call of dlopen inside of loadPythonLibrary function
static func loadPythonLibrary(at path: String) -> UnsafeMutableRawPointer? {
log("Trying to load library at '\(path)'...")
#if canImport(Darwin) || canImport(Glibc)
// Must be RTLD_GLOBAL because subsequent .so files from the imported python
// modules may depend on this .so file.
let pythonLibraryHandle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)
#elseif os(Windows)
let pythonLibraryHandle = UnsafeMutableRawPointer(LoadLibraryA(path))
#endif
if pythonLibraryHandle != nil {
log("Library at '\(path)' was sucessfully loaded.")
}
return pythonLibraryHandle
}
This functions returns nil, which is due to dlopen function returning nil.
However, I checked the path given as parameter to loadPythonLibrary(at : path) and it appeared to be correct (in Terminal I tried to do cd to the following path and it worked) :
/usr/local/Frameworks/Python.framework/Versions/2.7/Python
I am using Python 2.7 in my code.
Do you know why dlopen would return nil in my case ?
You can do it now using my fork of PythonKit at https://github.com/kewlbear/PythonKit. This package depends on my other package https://github.com/kewlbear/Python-iOS. Ultimately Python will be embedded in the app. Currently Python 3.8 is used.

Calling C++ code via embedded Python

I have successfully created a Python module that appears to work in isolation, but doesn't affect the program that is running it.
I have the following module:
BOOST_PYTHON_MODULE(mandala)
{
class_<state_mgr_t, state_mgr_t*, noncopyable>("states", no_init)
.def("push", &state_mgr_t::push)
.def("pop", &state_mgr_t::pop)
.def("count", &state_mgr_t::count);
scope().attr("states") = boost::python::object(boost::python::ptr(&states));
}
The states object is referencing a global value, states:
extern state_mgr_t states;
I can run the following script lines from within my program:
from mandala import states
states.count()
> 0
All of that is fine and whatnot, but I was expecting that running this python script would affect the actual state of the program that is running it. It appears as though Python is actually just dealing with it's own instance of states and not affecting the parent program.
Now I'm wondering if I've completely misunderstood what Boost.Python is capable of; I was expecting something similar to Lua, where I could modify the C++ program via scripts.
Is this not possible? Or am I doing something very wrong?
Thank you in advance!
If you are embedding Python into your C++ program, it should be possible to access the instance from your script. Obviously, I don't have your full code, but have you tried something like this?
PyImport_AppendInittab("mandala", &initmandala);
Py_Initialize();
try {
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
main_namespace.attr("states") = ptr(&states);
object ignored = exec("print states.count()", main_namespace);
} catch(const error_already_set&) {
PyErr_Print();
}

why is __init__ module in django project loaded twice In the same process?

I'm trying to wrap a c library in a high-level python interface with Boost.Python. One of the client contracts of the c library is that one of the handles can only be allocated once per-process. I was hoping I could enforce this contract on the python side by using a module global.
Here is my django component module's __init__.py. PyGenTL must only be created once per process!
import my_c_mod
import os
print "imager__init__()"
print os.getpid()
ptl = my_c_mod.PyGenTL()
Slightly relevant Boost.Python code
BOOST_PYTHON_MODULE(my_c_mod)
{
using namespace boost::python;
// Create the Python type object for our extension class and define __init__ function.
class_<PyGenTL>("PyGenTL")
.def("sys_info", &PyGenTL::SysInfo)
.def("list_cameras", &PyGenTL::ListCameras) //
.def("start_camera", &PyGenTL::StartCamera) //
;
}
PyGenTL::PyGenTL()
{
try {
std::cout << "PyGenTL ctor(): allocating GenTL Lib." << std::endl;
Detail::ThrowError(GCInitLib());
Detail::ThrowError(TLOpen(&hTL));
} catch (boost::exception& e) {
std::cerr << "PyGenTL ERROR! ";
std::cerr << boost::diagnostic_information(e);
std::cerr << std::endl;
}
}
Note the print statements in the constructor, and os.getpid() in init. Here is the output from the django process. Note that two processes are created at the start of python, which is why two PyGenTLs are created. So far, so good.
C:\work\svn\sw\branches\python\GenTlServer>python manage.py runserver
imager__init__()
2264
PyGenTL ctor(): allocating GenTL Lib.
imager__init__()
2912
PyGenTL ctor(): allocating GenTL Lib.
Validating models...
0 errors found
Django version 1.3, using settings 'GenTlServer.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
Now, during page view, __init__ gets called AGAIN within the same process (2912)
imager__init__()
2912
PyGenTL ctor(): allocating GenTL Lib.
ERROR (-1004): Requested module is in use.
PyGenTL ERROR! Requested module is in use.
[23/Jun/2011 18:02:22] "GET / HTTP/1.1" 500 76537
Sure, there is a work around for my particular problem by enforcing the singleton on the C side, but what is the python way to do it?
Because it's being loaded via two different entries in sys.path. Be consistent about your imports; I recommend importing the module without going through the project, e.g. import <app>.<module>. Configuring a WSGI container so that you're not dependent on manage.py's mangling of sys.path will help.

Categories