Forum Archive

Create global variables in pythonista_startup

Matteo

Hi guys, I can't create global variables using pythonista_startup script (that is every time I start Pythonista). Maybe it is an easy thing for you...maybe I can't remember the solution...

My pythonista_startup.py script for test on global variables is:

def test_global():
    global x
    x = 10
    print(x)   

test_global()

global y
y=200
print(y)

Procedure to test the script:
1. exit Pythonista
2. open Pythonista and wait
3. check printed x and y in console
4. write 'x+y' in console to see output '210'

Problem:
point 4. fails and returns : name 'x' is not defined

I use:
1. Pythonista v3.1
2. python 2.7.12 interpreter as default
3. sorry for this
4. my pythonista_startup.py is inside 'site-packages-2'

Can you help me in creating global variables using pythonista_startup?
Thank you
Bye

JonB

Does y still exist in the console, just x missing? (Try dir() in console)

Can you try defining x within the global scope of pythonista_startup? before test_globals (), use x= 0, which will get overridden later.
I'm not sure whether that happens when you use global within a function, if it appears as pythonista_startup.x, which is the requirement pythonista uses for saving globals.

I forget if pythonista_startup is actually imported, vs being run as main. You may need to import pythonista_startup then set the variables there.

I.e,
import pythonista_startup
pythonista_startup.x=x
pythonista_startup.y=y

The other approach is to use double under prefix on globals you want to retain eg __x

Matteo

Hi @JonB, thank you for reply.

After execution of the test script in previous post ('pythonista_startup.py'), the python console can't recognize the two global variables 'x' and 'y'. If I run manually the script 'pythonista_startup.py' Pythonista creates the global variables. So I can understand that the execution of pythonista_startup is not like a normal/manual script execution. Am I wrong?

Also if I add 'x=0' at the beginning of the test script doesn't work.
I tried to use '__x' but I can't create globals that I'd like to use in the console with an interactive mode.

My main purpose is to add actions to user key in your script about programming user keys, and I want to add actions that creates global variables when I touch the corresponding user key (this every time I launch Pythonista, so I need to create globals with pythonista_startup).

I tried also to execute a script with 'execfile(...)' in pythonista_startup but it fails to create globals.

I'm quite optimistic about existence of a solution for this, but for now I have no idea. If in the meantime you succeed, even better.

An approach is to understand what is executed by Pythonista when it is launched with an existing pythonista_startup.py script.

Thank you
Bye

JonB

try placing pythonista_startup in site-packages. I am thinking, perhaps, that site-packages-2 does not retain globals like site-packages, or else globals are cleared in between.

pythonista_startup is imported at startup. simply adding

x=0

in my pythonista_startup does allow x to appear in the console. This works for both 2.7 and 3.6. You can check sys.version for things that you only want run once.

You can always stash variables, functions, etc in modules that you know dont get cleared, such as sys, or __builtins__

import sys
sys.myvariable = 0

(always refer to it as sys.myvariable. adding to __builtins__ ensures it is available everywhere as sort of a global global, but be sure to name it something that won't get stepped on elesewhere )

JonB

okay, if you are trying to create a custom button in pythonista_startup, that sets a global in the console, this becomes a little tricky... im not sure which scope global would point to (the globals of pythonista_startup, or globals of the current context). ui actions get called in a seperate thread, which means it won't have access to the globals seen by the main interpreter, i think. you might try ui.in_background, which runs code in the same thread used for scripts.

Matteo

Hi @JonB , you are right: 'pythonista_startup.py' in folder 'site-packages' can create globals without declaring them as global. If the script is in folder 'site-packages-2', it doesn't work.

I've tried your simple test (content of pythonista_startup.py):

x=0

and after starting Pythonista, python console recognizes the var 'x'.

If I add after x=0:

print(x)

Pythonista prints twice the number 0 in console (why twice?).

Instead of 'print(x)', if I write 'print x' Pythonista prints number 0 one time, even if I use python2.7 as default.

However changing folder from 'site-packages-2' to 'site-packages' gives me some chances to create a set of global variables (that I can use in console after execution of scripts happened several hours before) when I touch user keys of the key_bar at the top of Pythonista.
My next test will be to create a 'pythonista_startup.py' script with full user_keys_bar (by you) and with a set of actions that, after execution, create a set of global variables that I need to use subsequently in python console (especially scientific calculations using sage, sorry, my usage of Pythonista is mostly based on calculus).

Thank you for your help
Bye

dgelessus

(why twice?)

Because the pythonista_startup module is imported by both the Python 2 and 3 interpreters. (Both are started at the same time, even if you only use one.) If you change the code to print x, it will run in Python 2 but cause an exception in Python 3 (and all exceptions from pythonista_startup are silently ignored).

JonB

@dgelessus

@Matteo is trying to create a function defined in pythonista_startup which sets a global in the console. My attempts at this fail, I think because the __globals__ for such functions are actually the pythonista_startup globals. I suspect the objc that initializes the interpreter imports pythonista_startup, then copies its globals to the interpreter thread's globals...

The question is, is there a way (inspect maybe?) to find the current interpreter's globals and set things there...?

dgelessus

I think the Python console uses the globals of the __main__ module, which corresponds to the script that was last run. I'm not sure how exactly the globals from pythonista_startup are initially copied into the console globals, it seems that is done in C rather than in pykit_startup. In any case, I'm guessing this copying only happens once, so if you add globals to pythonista_startup afterwards, they won't appear in the console. However when Pythonista clears the console globals (using pykit_preflight) when running a new script, it does look at pythonista_startup's globals to determine what to keep.

So I think (I haven't tested this) to add console globals after pythonista_startup has finished running, you need to add the global to both the __main__ and pythonista_startup modules. If you're doing this in a function in pythonista_startup, that means you need to declare the variable as global, set it, and also set an attribute on __main__ with the same name.

JonB

yup, that did it: in pythonista startup:

x=0
def set_globals(sender):
    import sys
    sys.modules['__main__'].x=2

then, using that method later, say in a ui button, does set the global as seen in the console.

Matteo

@JonB and @dgelessus Hi and thank you both! JonB script works and solves my issue about global variables in site-packages-2.
Now I can use this code by programming actions that execute external files with global variables creation and available in console.

Thank you again for help.
Regards
Bye

Matteo

Hi, sorry but I have another problem with global variables and Pythonista 3.1 (using interpreter 2.7).

Procedure to reproduce the problem:
1. create a script S1 with following code

global var
var=100
print(var)
  1. create script S2 with print("Hello")

  2. execute script S1: it prints in console number 100, and if you write var in console, it prints again 100 (the global var is alive, ok, that's what I expect).

  3. execute script S2: if you write var in console, interpreter says ... name 'var' is not defined, that is: global variable var no longer exists.

Is it ok or am I wrong with something?

Thanks

ccc

In S2, what happens if you put global var before you use it?

enceladus

I think that it is the expected behaviour. Executing in console is different from executing the script. I think that when you execute a script, existing global variables are removed before start running the script but the global variables are not removed or cleared after the script is run. If you run a script from console global variables are not removed or cleared unless you set the configuration to clear the global variables before running. That is the reason why you see the global variables of previously run script. If you run a new script from outside old global variables are removed before running the new script.

Matteo

@ccc Hi, the problem is not solved with global var at the beginning of script S2. It says: name var not defined.

But do you have the same problem with Pythonista you use?
Thanks

Matteo

@enceladus Hi, thank you for info, but if I want to keep alive the globals I create with different scripts execution, how can I do?

I'm trying to create a global var with execution of a script and another global var with execution of another script in ordert to use the two global variables in python console.

Thanks

enceladus

I do not think that it is possible to keep the global variables live across sesssions. I think you need to save them in a file before exiting and load them from the file at the start of the next session. May be you can use json for this.

Matteo

@enceladus Hi, interesting, thank you for idea. So the solution could be to write a piece of code to insert at the end of any script in order to create a file with content of all global variables and this file is opened by interpreter to read content every time I switch to console window in Pythonista, not only when I launch Pythonista (using pythonista_startup).
Do you have a better idea or an existing working solution created by someonelse?

Thanks

cvp

@Matteo see

I think that if your global variable name begins with double underscore, it will not be cleared.
To be tested

enceladus

Thanks @cvp . Global variables whose names start with double underscores seem to be alive across sessions.

enceladus

You can also initialise these double underscore global variables in pythonista_startup as suggested by @JonB.

sys.modules['__main__'].__var = 2
JonB

There is another option, which is to disable global clearing, using @dgelessus 's pythonista startup

see
https://github.com/dgelessus/pythonista_startup/blob/master/init.py

and uncomment the section indicated. This replaces the pythonista_startup with a fake module that lists all globals, thus preventing clearing.

Matteo

@cvp @enceladus and @JonB , thank you for feedback, it is undoubtedly nice that there is a sharing of ideas and solutions.

So, synthesizing, a solution for my problem is a mix of double __ at the beginning of var name and the use of sys.modules['__main__'].__varname=__varname in external script executed by a user key defined by @JonB script StatusBarMenu.

For those interested, in order to use this script as pythonista_startup with the global variables creation feature using user keys, the procedure is the follow:
1. At line 181 of this script in place of

def a(sender)
    print('action from bar1')

insert

def a(sender)
    import sys, os
    doc_path = os.path.expanduser('~/Documents/tests')   #in folder 'tests' I have my external script to execute by touching user key of JonB script
    os.chdir(doc_path)
    sys.path.append(doc_path)
    execfile('my-script-a.py')   # 'my-script-a.py' is inside folder '/tests'
    app.keyWindow().rootViewController().showAccessoryWithAnimationDuration_(0.5)
  1. Then create my-script-a.py in folder ~/Documents/tests with following content (for example):
import sys
__var = 100
sys.modules['__main__'].__var=__var
print(__var)

Well, now when you touch user key of StatusBarMenu related to action a, Pythonista should execute the script my-script-a.py and the variable __var lives in console also after execution of other external scripts and the var can be used inside other external scripts, as it is 100% global now.

My next step is to adapt this solution for sage_interface in order to be able, using user keys with this, to execute different scripts with remote server by sagemathcell (with scipy and other tools not present in Pythonista) and to use global variables, with different names similar to filename of the executed script by sage (to not overwrite content in variables that could be useful during further calculations), in console or in other scripts. For example, if I must execute remotely with sage a script named 'optimization.py' that calculates A and an other script named 'fit.py' that calculates B, the global variables with output of A and B live in console and the name of the global variables could be '__sage-out--optimization' and '__sage-out--fit', and with the powerful word completion feature of Pythonista them can be recalled easly from python console.

Best regards

JonB

@Matteo If you use the DirAllTheGlobals approach, you can avoid using double underscores, though might still need to set sys.modules['main'].varname from r anythingyou want to save from within startup itself.

Matteo

@JonB Hi JonB, i will try with option you have described, when finish i will post here a working solution,
Regards

ccc

https://docs.python.org/3/library/os.html#os.environ and https://docs.python.org/3/library/os.html#os.getenv might also be worth looking into.

Matteo

@ccc Thank you ccc, I will try to read these info.
Regards

walshmagger

check this one...how to share python global variable