Python Kodi - Force Python handling .pyo like .py - python

Hey guys i definitely getting crazy
i want to force Python to handle a .pyo like a .py
i got kodi xbmc forked and getting crazy
i already tried out and changed multiple lines and nothing changed?
i linked them here:
const std::string ADDON_PYTHON_EXT = "*.py";
changed this line to *.pyo
return URIUtils::HasExtension(m_strPath, ".py"); changed this line to. .pyo
i thought that would be enough after compiling, still nothing happens when try to open a add-on
still python does not load .pyo files and does not handle them as .py
btw: i figured out deleting all .py files in the folder and just let the first loaded .py file there so 1 -> .py and the others are all .pyo the add-on works.
but when deleting this firstly loaded .py and using this as a .pyo
it fails.
So what do i have to change that it always use .pyo
First UPDATE:
i tried it out,
it does indeed work as a workaround
Created a dummy -> include.py
with just 1 line import service was enough.
But i want to fix this directly in kodi.
in documentions
"If there is a current pyc file, this is taken as the compiled version, so no compile step has to be taken before running the command. Otherwise the py file is read, the compiler has to compile it"
So easy said,
execute .py if not available check if .pyo
but i cannot find where to change / add this method
i cannot find even the method right for the execution
Second Update:
i added these lines in githublink to file
//pyoextension == script
std::string pyoextension = script;
//Check if the file does exist
if (!CFile::Exists(script, false))
{
//pyoextension append o to get -> .pyo
pyoextension = script + "o";
//Check if pyoextension exist -> .pyo
//if not nothing exist throw error
if (!CFile::Exists(pyoextension, false)){
CLog::Log(LOGERROR, "%s - Not executing non-existing script %s", __FUNCTION__, script.c_str());
return -1;
}
LanguageInvokerPtr invoker = GetLanguageInvoker(pyoextension);
return ExecuteAsync(pyoextension, invoker, addon, arguments);
}
LanguageInvokerPtr invoker = GetLanguageInvoker(script);
return ExecuteAsync(script, invoker, addon, arguments);
Checking if the the add-on does not exist as a .py file checking if the .pyo file is there, and execute that instead. But still the checking does work, but it still throws an error out that it cannot start the script

Changing such line (const std::string ADDON_PYTHON_EXT = "*.py"; changed this line to *.pyo) is not a good solution
Main reason is that the kodi is configured to use .py extension to be load from addon.xml file which tradition is followed by all the addon. Changing such headers file will only result to work addon only in your custom build kodi and you have to modify all other addon along with it.
The solution I prefer most is you should follow below steps:
Create a function in your python script (let's call it as function named service() which execute all the necessary code from your file named service.py)
Now create a python file (include.py) to include it in addon.xml containing code as below:
include.py
import service
service.service()

It might not even be worth it, Kodi is moving to python3 soon, and python3 dropped pyo files. It might use pyc then, but that's not sure right now.

Related

What does it mean to "initialize the Julia runtime" when exporting compiled .dll or .so files for use in other langauges?

I'm trying to compile a usable .dll file from Julia to be used in Python as I've already written a large GUI in Python and need some fast optimization work done. Normally I would just call PyJulia or some "live" call, however this program needs to be compiled to distribute within my research team, so whatever solution I end up with needs to be able to run on its own (without Julia or Python actually installed).
Right now I'm able to create .dll files via PackageCompiler.jl, something I learned from previous posts on StackOverflow, however when trying to run these files in Python via the following code
Julia mock package
module JuliaFunctions
# Pkg.add("BlackBoxOptim")
Base.#ccallable function my_main_function(x::Cfloat,y::Cfloat)::Cfloat
z = 0
for i in 1:x
z += i ^ y
end
return z
end
# function julia_main()
# print("Hello from a compiled executable!")
# end
export my_main_function
end # module
Julia script to use PackageCompiler
# using PackageCompiler
using Pkg
# Pkg.develop(path="JuliaFunctions") # This is how you add a local package
# include("JuliaFunctions/src/JuliaFunctions.jl") # this is how you add a local module
using PackageCompiler
# Pkg.add(path="JuliaFunctions")
#time create_sysimage(:JuliaFunctions, sysimage_path="JuliaFunctions.dll")
Trying to use the resulting .dll in CTypes in Python
import ctypes
from ctypes.util import find_library
from ctypes import *
path = os.path.dirname(os.path.realpath(__file__)) + '\\JuliaFunctions.dll'
# _lib = cdll.LoadLibrary(ctypes.util.find_library(path)) # same error
# hllDll = ctypes.WinDLL(path, winmode=0) # same error
with os.add_dll_directory(os.path.dirname(os.path.realpath(__file__))):
_lib = ctypes.CDLL(path, winmode=0)
I get
OSError: [WinError 127] The specified procedure could not be found
With my current understanding, this means that CTypes found the dll and imported it, but didn't find.. something? I've yet to fully grasp how this behaves.
I've verified the function my_main_function is exported in the .dll file via Nirsoft's DLL Export Viewer. Users from previous similar issues have noted that this sysimage is already callable and should work, but they always add at the end something along the lines of "Note that you will also in general need to initialize the Julia runtime."
What does this mean? Is this even something that can be done independently from the Julia installation? The dev docs in PackageCompiler mention this, however they just mention that julia_main is automatically included in the .dll file and gets called as a sort of launch point. This function is also being exported correctly into the .dll file the above code creates. Below is an image of the Nirsoft export viewer output for reference.
Edit 1
Inexplicably, I've rebuilt this .dll on another machine and made progress. Now, the dll is imported correctly. I'm not sure yet why this worked on a fresh Julia install + Python venv, but I'm going to reinstall them on the other one and update this if anything changes. For anyone encountering this, also note you need to specify the expected output, whatever it may be. In my case this is done by adding (after the import):
_lib.testmethod1.restype = c_double # switched from Cfloat earlier, a lot has changed.
_lib.testmethod1.argtypes = [c_double, c_double] # (defined by ctypes)
The current error is now OSError: exception: access violation writing 0x0000000000000024 when trying to actually use the function, which is specific to Python. Any help on this would also be appreciated.

Running Fortran executable within Python script

I am writing a Python script with the following objectives:
Starting from current working directory, change directory to child directory 'A'
Make slight adjustments to a fort.4 file
Run a Fortran binary file (the syntax of which is ../../../../ continuing until I hit the folder containing the binary); return to 2. until my particular objective is complete, then
Back out of child directory to parent, then enter another child directory and return to 2. until I have iterated through all the folders in question.
The code is coming along well. I am having to rely heavily upon Python's OS module for the directory work. However, I have never had any experience a) making minor adjustments of a file using python and b) running an executable. Could you guys give me some ideas on Python modules, direct me to a similar stack source etc, or perhaps give ways that this can be accomplished? I understand this is a vague question, so please ask if you do not understand what I am asking and I will elaborate. Also, the changes I have to make to this fort.4 file are repetitive in nature; they all happen at the same position in the file.
Cheers
EDIT::
entire fort.4 file:
file_name
movie1.dat !name of a general file the binary reads
nbr_box ! line3-8 is general info
2
this_box
1
lrdf_bead
.true.
beadid1
C1 !this is the line I must change
beadid2
F4 !This is a second line I must change
lrdf_com
.false.
bin_width
0.04
rcut
7
So really, I need to change "C1" to "C2" for example. The changes are very insignificant to make, but I must emphasize the fact that the main fortran executable reads this fort.4, as well as this movie1.dat file that I have already created. Hope this helps
Ok so there is a few important things here, first we need to be able to manage our cwd, for that we will use the os module
import os
whenever a method operates on a folder it is important to change directories into the folder and back to the parent folder. This can also be achieved with the os module.
def operateOnFolder(folder):
os.chdir(folder)
...
os.chdir("..")
Now we need to do some method for each directory, that comes with this,
for k in os.listdir(".") if os.path.isdir(k):
operateOnFolder(k)
Finally in order to operate on some preexisting FORTRAN file we can use the builtin file operators.
fileSource = open("someFile.f","r")
fileText = fileSource.read()
fileSource.close()
fileLines = fileText.split("\n")
# change a line in the file with -> fileLines[42] = "the 42nd line"
fileText = "\n".join(fileLines)
fileOutput = open("someFile.f","w")
fileOutput.write(fileText)
You can create and run your executable output.fx from source.f90::
subprocess.call(["gfortran","-o","output.fx","source.f90"])#create
subprocess.call(["output.fx"]) #execute

Exchanging info between running C++ code and python script

I have a python script that is called inside a C++ program. The python script creates a directory based on the current time, puts files in there, and then execution returns to C++. I want to save a parameters file into the directory created in the python program.
I figure my options are:
Pass in the text to save in the parameters file to the Python program and have it create and save the file
Return the location of the directory to C++ from python so it knows where to save the file
Use C++ to locate the most recently created directory after execution of the python script and put file there
I'm not sure how to do any of this. My python script is not embedded. I use
std::string test = "python analyzeData2.py";
system(test.c_str());
to call a python script.
Any ideas how to do this?
I'd go with option B -- return the location of the directory to c++ from python so it knows where to save the file.
If you plan on using system(), something like this:
char* dirname[64];
FILE* fin;
system("python analyzeData2.py > created.log");
fin = fopen("created.log", "r");
fgets(dirname, sizeof(dirname), fin);
fclose(fin);
/* dirname has contents of created.log */
...

Python C API - Call C function from embedded python (callback)

I have a .cpp file loading python file and calling a function. I have a logger class in the .cpp and I want to use it from .py file.
Example:
# python-file.py
def FunctionCalledFromC_API():
log("some string")
log("some error", error)
log("some debug info", debug)
# etc...
And the .cpp
// cpp-file.cpp
// Load python file, do stuff...
PyObject *args = PyTuple_New(0);
PyObject_CallObject(pFunctionCalledFromC_API, args);
Py_DECREF(args);
I want that the log("some string") function of the .py file calls my logger.log(...) function from the C++ application.
As Markku K. suggested, I made all my app a DLL and I'll try soon.
That's what I'll do (for people with the same question):
Make my app a single DLL
Make an executable to run it (obvious)
Make a Python file containing the functions (example: logger.log()). That functions should call the DLL's equivalent functions.
Do "trial&error" until it works ;)
EDIT:
After a lot of "trial&error", I've found a way to do it!
Using boost::python to expose my API and the standard Python API to load the .py file I made this work!
But I'll have to start the application with a python file importing the shared object and calling the main function :(
Anyway, Thanks Markku K. for your help!

Python script and class in the same file

I have a Python class that supposes to perform some tasks in the background by submitting itself to a cluster environment. e.g.
class AwesomeTaskController(object):
def run(bunch_of_tasks):
for task in bunch_of_tasks:
cmd = "%s %s" % (os.path.abspath(__file__), build_cli_paramters(task))
# call the API to submit the cmd
if __name__ == "__main__":
#blah blah do stuff with given parameters
All is well for the first time that this class was run. When it was run the first time, a pyc file is created. This pyc file isn't executable (permission wise).
So the 2nd time I use this class, the command will use the pyc directly and complains that permission is denied. Perhaps I am approaching this from the wrong angle?
.pyc files aren't executable themselves; you always have to execute the .py file. The .pyc file is just a compiled version of the .py file that Python generates on the fly to save itself some time the next time you run the .py file.
In your case, all you should need to do is check to see if __file__ ends with ".pyc" and remove the trailing "c". You could do that by, say, replacing __file__ in your script with:
(__file__[:-1] if __file__.endswith(".pyc") else __file__)
and that should solve your problem.

Categories

Resources