Why use `exec_statement` when writing PyInstaller hooks? - pyinstaller

In the PyInstaller docs they demonstrate the use of eval_statement() and exec_statement() which call eval() or exec() in a new instance of Python. But they don't say why you would want to run your code in a separate instance.
For example, why couldn't their example of:
from PyInstaller.utils.hooks import exec_statement
mpl_data_dir = exec_statement(
"import matplotlib; print(matplotlib._get_data_path())"
)
datas = [ (mpl_data_dir, "") ]
not just be:
import matplotlib
datas = [(matplotlib._get_data_path(), "")]
I've tried doing this with my own library and it doesn't seem to do it any harm. So why the extra complexity? Why do all the other hooks included in PyInstaller use the 1st method?

All the hooks use the first method in case of path and environment manipulations. What happens if matplotlib changes sys.path or some other environmental manipulation that could mess with the build process? Using a separate python instance means this won't happen.

Related

How to create a sys image that has multiple packages with their precompiled functions cached in julia?

Let's say we have a symbol array of packages packages::Vector{Symbol} = [...] and we want to create a sys image using PackageCompiler.jl. We could simply use
using PackageCompiler
create_sysimage(packages; incremental = false, sysimage_path = "custom_sys.dll"
but without a precompile_execution_file, this isn't going to be worth it.
Note: sysimage_path = "custom_sys.so" on Linux and "custom_sys.dylib" on macOS...
For the precompile_execution_file, I thought running the test for each package might do it so I did something like this:
precompilation.jl
packages = [...]
#assert typeof(packages) == Vector{Symbol}
import Pkg
m = Module()
try Pkg.test.(Base.require.(m, packages)) catch ; end
The try catch is for when some tests give an error and we don't want it to fail.
Then, executing the following in a shell,
using PackageCompiler
packages = [...]
Pkg.add.(String.(packages))
Pkg.update()
Pkg.build.(String.(packages))
create_sysimage(packages; incremental = false,
sysimage_path = "custom_sys.dll",
precompile_execution_file = "precompilation.jl")
produced a sys image dynamic library which loaded without a problem. When I did using Makie, there was no delay so that part's fine but when I did some plotting with Makie, there still was the first time plot delay so I am guessing the precompilation script didn't do what I thought it would do.
Also when using tab to get suggestions in the repl, it would freeze the first time but I am guessing this is an expected side effect.
There are a few problems with your precompilation.jl script, that make tests throw errors which you don't see because of the try...catch.
But, although running the tests for each package might be a good idea to exercise precompilation, there are deeper reasons why I don't think it can work so simply:
Pkg.test spawns a new process in which tests actually run. I don't think that PackageCompiler can see what happens in this separate process.
To circumvent that, you might want to simply include() every package's test/runtests.jl file. But this is likely to fail too, because of missing test-specific dependencies.
So I would say that, for this to work reliably and systematically for all packages, you'd have to re-implement (or re-use, if you can) some of the internal logic of Pkg.test in order to add all test-specific dependencies to the current environment.
That being said, some packages have ready-to-use precompilation scripts helping to do just this. This is the case for Makie, which suggests in its documentation to use the following file to build system images:
joinpath(pkgdir(Makie), "test", "test_for_precompile.jl")

Test if include/import has been already done

I have the following include/import in my "main.jl" file:
include("Global.jl")
import .Global
As importing this module takes some time and it is always the same on every execution, I would like test in advance if .Global exists so I can bypass the include/import.
The idea is that I can edit all changes in my text editor and use the interactive console to reload the whole program but waiving that step if it is already there.
import X is already basically a no-op if X has already been imported.
The problem is when you do the include you are defining a new module also called X so import tries and loads the new one.
I suggest thus converting your module into a package,
adding it to your environment, then just doing import X
You can use isdefined(Main, :ModuleName) (don't forget the colon).
if !isdefined(Main, :Global)
include("Global.jl")
import .Global
end
For the same question when you are using a package named "MyPackage":
if !isdefined(Main, :MyPackage)
using MyPackage
end

How can I use built-in variables in the variable file in Robot Framework [duplicate]

I have some settings-type global vars that I'd like to be able to access from Python code. For example:
pybot --variable RESULTS_PATH:/wherever/this/points test.txt
Now, my module logger.py file needs to know the results_path to set up properly.
I know that I can initialize the logger with a variable, like
***Settings***
Library logger ${RESULTS_PATH}
And then in logger I'll be passed results_path:
def __init__(self, results_path):
# Whatever
However the problem with doing it this way for me is that I want to access and use the logger from both Python code and within test cases. So if I set it up this way, if I want to use the logger from Python code I run into the same problem of needing results_path to initialize the logger properly.
Are there any functions in the robot framework library that would allow me to grab the value of ${RESULTS_PATH} from Python code? What is the proper way to do something like this?
Right now, my workaround for the issue is to set RESULTS_PATH as an environment variable. So I have something like:
Run like:
RESULTS_PATH=/wherever/this/points pybot test.txt
File test.txt:
***Settings***
Library logger
...
File logger.py:
results_path = os.environ["RESULTS_PATH"]
# Other set up stuff
You will want to use rf's BuiltIn library, for reference read the documentation as found here. This provides the keywords that are built into Robot Framework and so should reliably stay usable:
from robot.libraries.BuiltIn import BuiltIn
results_path = BuiltIn().get_variable_value("${RESULTS_PATH}")

Sikuli - NameError: global name 'openApp' is not defined

I'm calling a sikuli function, inside Sikuli IDE, but I get this error "NameError: global name 'openApp' is not defined"...
If I try to do openApp('calc') in a new Sikuli blank file, it works, but if I use in another .sikuli file like:
def sample():
import myLib
# my Lib is .py file that I've created and put it on sikuli-script.jar
var = somevalue
myLib.myFunction(something)
openApp('calc')
I get the error with "openApp" and other sikuli funcions like "Key" (ex: Key.ENTER) too...
Hope I had explained that well
By default, Sikuli will insert a from sikuli import * into all main files. This error tends to occur when you import sikuli modules. If you are importing modules, you will need to add the import manually. See the documentation for more advice.
If your tests are in the same folder basically you can do,
import testName
reload(testName)
from testName import *
This will import your test and execute it's content.
testName should be name of the file without .sikuli extension
I ran into a similar problem was solved by putting from sikuli import * at the first line of any file you are importing. I hope this helps!
I only mentioned this, because with the imported files, I had the greatest overall success with this one, and it became habit to make this the first line.

How can you programmatically tell the CPython interpreter to enter interactive mode when done?

If you invoke the cpython interpreter with the -i option, it will enter the interactive mode upon completing any commands or scripts it has been given to run. Is there a way, within a program to get the interpreter to do this even when it has not been given -i? The obvious use case is in debugging by interactively inspecting the state when an exceptional condition has occurred.
You want the code module.
#!/usr/bin/env python
import code
code.interact("Enter Here")
Set the PYTHONINSPECT environment variable. This can also be done in the script itself:
import os
os.environ["PYTHONINSPECT"] = "1"
For debugging unexpected exceptions, you could also use this nice recipe http://code.activestate.com/recipes/65287/
The recipe metioned in the other answer using sys.excepthook, sounds like what you want. Otherwise, you could run code.interact on program exit:
import code
import sys
sys.exitfunc = code.interact
The best way to do this that I know of is:
from IPython import embed
embed()
which allows access to variables in the current scope and brings you the full power of IPython.

Resources