Start Python REPL and execute command [duplicate] - python

I would like to play around in the python interpreter but with a bunch of imports and object setup completed. Right now I'm launching the interpreter on the command line and doing the setup work every time. Is there any way to launch the command line interpreter with all the initialization work done?
Ex:
# Done automatically.
import foo
import baz
l = [1,2,3,4]
# Launch the interpreter.
launch_interpreter()
>> print l
>> [1,2,3,4]

You can create a script with the code you wish to run automatically, then use python -i to run it. For example, create a script (let's call it script.py) with this:
import foo
import baz
l = [1,2,3,4]
Then run the script
$ python -i script.py
>>> print l
[1, 2, 3, 4]
After the script has completed running, python leaves you in an interactive session with the results of the script still around.
If you really want some things done every time you run python, you can set the environment variable PYTHONSTARTUP to a script which will be run every time you start python. See the documentation on the interactive startup file.

I use PYTHONSTARTUP.
My .bash_profile has a path to my home folder .pyrc, which as the import statements in it.
https://docs.python.org/3/using/cmdline.html#envvar-PYTHONSTARTUP

I came across this question when trying to configure a new desk for my research and found that the answers above didn't quite suit my desire: to contain the entire desk configuration within one file (meaning I wouldn't create a separate script.py as suggested by #srgerg).
This is how I ended up achieving my goal:
export PYTHONPATH=$READ_GEN_PATH:$PYTHONPATH
alias prepy="python3 -i -c \"
from naive_short_read_gen import ReadGen
from neblue import neblue\""
In this case neblue is in the CWD (so no path extension is required there), whereas naive_short_read_gen is in an arbitrary directory on my system, which is specified via $READ_GEN_PATH.
You could do this in a single line if necessary: alias prepy=PYTHONPATH=$EXTRA_PATH:$PYTHONPATH python3 -i -c ....

You can use the -s option while starting the command line. The details are given in the documentation here

I think I know what you want to do. You might want to check IPython, because you cannot start the python interpreter without giving the -i option (at least not directly).
This is what I did in my project:
def ipShell():
'''Starts the interactive IPython shell'''
import IPython
from IPython.config.loader import Config
cfg = Config()
cfg.TerminalInteractiveShell.confirm_exit = False
IPython.embed(config=cfg, display_banner=False)
# Then add the following line to start the shell
ipShell()
You need to be careful, though, because the shell will have the namespace of the module that the function ipShell() is defined. If you put the definition in the file you run, then you will be able to access the globals() you want. There could be other workarounds to inject the namespace you want, b̶u̶t̶ ̶y̶o̶u̶ ̶w̶o̶u̶l̶d̶ ̶h̶a̶v̶e̶ ̶t̶o̶ ̶g̶i̶v̶e̶ ̶a̶r̶g̶u̶m̶e̶n̶t̶s̶ ̶t̶o̶ ̶t̶h̶e̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶i̶n̶ ̶t̶h̶a̶t̶ ̶c̶a̶s̶e̶.
EDIT
The following function defaults to caller's namespace (__main__.__dict__).
def ipShell():
'''Starts the interactive IPython shell
with the namespace __main__.__dict__'''
import IPython
from __main__ import __dict__ as ns
from IPython.config.loader import Config
cfg = Config()
cfg.TerminalInteractiveShell.confirm_exit = False
IPython.embed(config=cfg, user_ns=ns, display_banner=False)
without any extra arguments.

Related

Is there a way to keep/transfer bash environment between subprocess invocations in python?

Problem: suppose I have scripts A, B and C1, C2, ... CN.
Script B sources script A which contains several environment variables and functions, and then calls C scripts which rely on them.
Now, let's say I want to replace bash script B with a python program.
How would I best do that if I want to "source" A exactly once (not before every C invocation)?
I want to be able to "process" each C individually, i.e. to run some python code after each C is executed, so creating some big ". A && C1 && C2 ..." command won't do.
I'm not sure this will answer the question as i think it's still unclear in the way you have formulated it but you could use this snippet to parse your bash scripts and run them from python while capturing the output of each line so it might give you a starting point
import subprocess
def start_process(command=''):
return subprocess.Popen(command.split(' '), stdout=subprocess.PIPE, shell=False,
creationflags = 0x08000000)
with open('yourscript.sh','rt') as f:
lines = f.read().split('\n')
output=[str(start_process(line).communicate()[0]) for line in lines]
In this way you may be able to architect a structure where your python script coordinates your bash scripts instead of being on equal footing if that makes sense
Short of embedding a bash interpreter in your Python program (which is not a realistic option; bash wasn't designed to do that), the easiest thing to do is write a wrapper shell script that sources A, then uses exec to run the Python script. After the exec, your Python script keeps the same environment that the wrapper had, including whatever was found in A:
# wrapper script
source A
exec B.py
In B.py, each of the Ci scripts will then inherit the variables defined in A via B.py's environment.
Another option is to port A into a Python module which B.py can import directly. You would change
export x=foo
export y=1
into
import os
os.environ["x"] = "foo"
os.environ["y"] = "1"
Depending on how involved A really is, porting may not be trivial, which is why I would recommend the wrapper using exec first.

How could Python functions of a library be made available as Bash commands?

Let's say I have a large Python library of functions and I want these functions (or some large number of them) to be available as commands in Bash.
First, disregarding Bash command options and arguments, how could I get a function of a Python file containing a number of functions to run using a single word Bash command? I do not want to have the functions available via commands of a command 'suite'. So, let's say I have a function called zappo in this Python file (say, called library1.py). I would want to call this function using a single-word Bash command like zappo, not something like library1 zappo.
Second, how could options and arguments be handled? I was thinking that a nice way could be to capture all of the options and arguments of the Bash command and then use them within the Python functions using docopt parsing *at the function level```.
Yes, but the answer might not be as simple as you hope. No matter what you do, you're going to have to create something in your bash shell for each function you want to run. However, you could have a Python script generate aliases stored in a file which gets sourced.
Here's the basic idea:
#!/usr/bin/python
import sys
import __main__ #<-- This allows us to call methods in __main__
import inspect #<-- This allows us to look at methods in __main__
########### Function/Class.Method Section ##############
# Update this with functions you want in your shell #
########################################################
def takesargs():
#Just an example that reads args
print(str(sys.argv))
return
def noargs():
#and an example that doesn't
print("doesn't take args")
return
########################################################
#Make sure there's at least 1 arg (since arg 0 will always be this file)
if len(sys.argv) > 1:
#This fetches the function info we need to call it
func = getattr(__main__, str(sys.argv[1]), None)
if callable(func):
#Actually call the function with the name we received
func()
else:
print("No such function")
else:
#If no args were passed to this function, just output a list of aliases for this script that can be appended to .bashrc or similar.
funcs = inspect.getmembers(__main__, predicate=inspect.isfunction)
for func in funcs:
print("alias {0}='./suite.py {0}'".format(func[0]))
Obviously, if you're using methods in a class instead of functions in main, change references from __main__ to your class, and change predicate in the inspect to inspect.ismethod. Also, you probably would want to use absolute paths for the aliases, etc.
Sample output:
~ ./suite.py
alias noargs='./suite.py noargs'
alias takesargs='./suite.py takesargs'
~ ./suite.py > ~/pyliases
~ echo ". ~/pyliases" >> ~/.bashrc
~ . ~/.bashrc
~ noargs
doesn't take args
~ takesargs blah
['./suite.py', 'takesargs', 'blah']
If you use the method I've suggested above, you can actually have your .bashrc run ~/suite.py > ~/pyliases before it sources the aliases from the file. Then your environment gets updated every time you log in/start a new terminal session. Just edit your python function file, and then . ~/.bashrc and the functions will be available.

use external python script to open maya and run another script inside maya

Is it possible to call a script from the command prompt in windows (or bash in linux) to open Maya and then subsequently run a custom script (possibly changing each time its run) inside Maya? I am searching for something a bit more elegant than changing the userSetup file and then running Maya.
The goal here is to be able to open a .mb file, run a script to position the scene inside, setup a generic set of lights and then render the scene to a specific place and file type. I want to be able to set this up as a scheduled task to check for any new scene files in a directory and then open maya and go.
Thanks for the help!
For something like this you can use Maya standalone instead of the full blown UI mode. It is faster. It is ideal for batch scheduled jobs like these. Maya standalone is just Maya running without the GUI. Once you have initialized your Maya standalone, you can import and call any scripts you want, as part of the original calling script. To start you off here is an example: (Feel free to use this as a reference/modify it to meet your needs)
In your script you first initialize Maya standalone.
import maya.standalone
maya.standalone.initialize("Python")
import maya.cmds as cmds
cmds.loadPlugin("Mayatomr") # Load all plugins you might need
That will get Maya running. Now we open and/or import all the files necessary (egs. lights, models etc.)
# full path to your Maya file to OPEN
maya_file_to_open = r"C:/Where/Ever/Your/Maya_Scene_Files/Are/your_main_maya_file.mb"
# Open your file
opened_file = cmds.file(maya_file_to_open, o=True)
# full path to your Maya file to IMPORT
maya_file_to_import = r"C:/Where/Ever/Your/Maya_Scene_Files/Are/your_maya_file.mb"
# Have a namespace if you want (recommended)
namespace = "SomeNamespaceThatIsNotAnnoying"
# Import the file. the variable "nodes" will hold the names of all nodes imported, just in case.
nodes = cmds.file(maya_file_to_import, i=True,
renameAll=True,
mergeNamespacesOnClash=False,
namespace=namespace,
returnNewNodes=True,
options="v=0;",
type="mayaBinary" # any file type you want. this is just an example.
)
#TODO: Do all your scene setup/ positioning etc. if needed here...
#Tip: you can use cmds.viewFit(cam_name, fitFactor=1) to fit your camera on to selected objects
Now we save this file out and call Maya Batch renderer to render it out
render_file = "C:/Where/Ever/Your/Maya_Scene_Files/Are/your_RENDER_file.mb"
cmds.file(rename=render_file)
cmds.file(force=True, save=True, options='v=1;p=17', type='mayaBinary')
import sys
from os import path
from subprocess import Popen
render_project = r"C:/Where/Ever/YourRenderProjectFolder"
renderer_folder = path.split(sys.executable)[0]
renderer_exec_name = "Render"
params = [renderer_exec_name]
params += ['-percentRes', '75']
params += ['-alpha', '0']
params += ['-proj', render_project]
params += ['-r', 'mr']
params += [render_file]
p = Popen(params, cwd=renderer_folder)
stdout, stderr = p.communicate()
That's it! Of Course, your script will have to be run using Maya's Python interpreter (Mayapy).
Do check out the docs for all the commands used for more options, esp.:
cmds.file()
cmds.viewFit()
cmds.loadPlugin()
Subprocess and Popen
PLUS, because of the awesomeness of Python, you can use modules like sched (docs) to schedule the running of this method in your Python code.
Hope this was useful. Have fun with this. Cheers.
A lot depends on what you need to do.
If you want to run a script that has access to Maya functionality, you can run a Maya standalone instance as in Kartik's answer. The mayapy binary installed in the same folder as your maya is the Maya python interpreter, you can run it directly the same way you'd run python.exe Mayapy has the same command flags as a regular python interpreter.
Inside a mayapy session, once you call standalone.initialize() you will have a running Maya session - with a few exceptions, it is as if you were running inside a script tab in a regular maya session.
To force Maya to run a particular script on startup, you can call the -c flag, just the way you would in python. For example, you can start up a maya and print out the contents of an empty scene like this (note: I'm assuming mayapy.exe is on your path. You can just CD to the maya bin directory too).
mayapy -c 'import maya.standalone; maya.standalone.initialize(); import maya.cmds as cmds; print cmds.ls()'
>>> [u'time1', u'sequenceManager1', u'renderPartition', u'renderGlobalsList1', u'defaultLightList1', u'defaultShaderList1', u'postProcessList1', u'defaultRenderUtilityList1', u'defaultRenderingList1', u'lightList1', u'defaultTextureList1', u'lambert1', u'particleCloud1', u'initialShadingGroup', u'initialParticleSE', u'initialMaterialInfo', u'shaderGlow1', u'dof1', u'defaultRenderGlobals', u'defaultRenderQuality', u'defaultResolution', u'defaultLightSet', u'defaultObjectSet', u'defaultViewColorManager', u'hardwareRenderGlobals', u'hardwareRenderingGlobals', u'characterPartition', u'defaultHardwareRenderGlobals', u'lightLinker1', u'persp', u'perspShape', u'top', u'topShape', u'front', u'frontShape', u'side', u'sideShape', u'hyperGraphInfo', u'hyperGraphLayout', u'globalCacheControl', u'brush1', u'strokeGlobals', u'ikSystem', u'layerManager', u'defaultLayer', u'renderLayerManager', u'defaultRenderLayer']
You can run mayapy interactively - effectively a command line version of maya - using the -i flag: This will start mayapy and give you a command prompt:
mayapy -i -c \"import maya.standalone; maya.standalone.initialize()\""
which again starts the standalone for you but keeps the session going instead of running a command and quitting.
To run a script file, just pass in the file as an argument. In that case you'd want to do as Kartik suggests and include the standalone.initalize() in the script. Then call it with
mayapy path/to/script.py
To suppress the userSetup, you can create an environmnet variable called MAYA_SKIP_USERSETUP_PY and set it to a non-zero value, that will load maya without running usersetup. You can also change environment varialbes or path variables before running the mayap; for example I can run mayapys from two different environments with these two bash aliases (in windows you'd use SET instead of EXPORT to change the env vars):
alias mp_zip="export MAYA_DEV=;mayapy -i -c \"import maya.standalone; maya.standalone.initialize()\""
alias mp_std="export MAYA_DEV=C:/UL/tools/python/ulmaya;export ZOMBUILD='C:/ul/tools/python/dist/ulmaya.zip';mayapy -i -c \"import maya.standalone; maya.standalone.initialize()\""
This blog post includes a python module for spinning up Mayapy instances with different environments as needed.
If you want to interact with a running maya from another envrionment - say, if you're trying to remote control it from a handheld device or a C program - you can use the Maya commandPort to handle simple requests via TCP. For more complex situations you could set up a basic remoting service like this of your own, or use a pre-exiating python RPC module like RPyC or ZeroMQ

run python command line interpreter with imports loaded automatically

I would like to play around in the python interpreter but with a bunch of imports and object setup completed. Right now I'm launching the interpreter on the command line and doing the setup work every time. Is there any way to launch the command line interpreter with all the initialization work done?
Ex:
# Done automatically.
import foo
import baz
l = [1,2,3,4]
# Launch the interpreter.
launch_interpreter()
>> print l
>> [1,2,3,4]
You can create a script with the code you wish to run automatically, then use python -i to run it. For example, create a script (let's call it script.py) with this:
import foo
import baz
l = [1,2,3,4]
Then run the script
$ python -i script.py
>>> print l
[1, 2, 3, 4]
After the script has completed running, python leaves you in an interactive session with the results of the script still around.
If you really want some things done every time you run python, you can set the environment variable PYTHONSTARTUP to a script which will be run every time you start python. See the documentation on the interactive startup file.
I use PYTHONSTARTUP.
My .bash_profile has a path to my home folder .pyrc, which as the import statements in it.
https://docs.python.org/3/using/cmdline.html#envvar-PYTHONSTARTUP
I came across this question when trying to configure a new desk for my research and found that the answers above didn't quite suit my desire: to contain the entire desk configuration within one file (meaning I wouldn't create a separate script.py as suggested by #srgerg).
This is how I ended up achieving my goal:
export PYTHONPATH=$READ_GEN_PATH:$PYTHONPATH
alias prepy="python3 -i -c \"
from naive_short_read_gen import ReadGen
from neblue import neblue\""
In this case neblue is in the CWD (so no path extension is required there), whereas naive_short_read_gen is in an arbitrary directory on my system, which is specified via $READ_GEN_PATH.
You could do this in a single line if necessary: alias prepy=PYTHONPATH=$EXTRA_PATH:$PYTHONPATH python3 -i -c ....
You can use the -s option while starting the command line. The details are given in the documentation here
I think I know what you want to do. You might want to check IPython, because you cannot start the python interpreter without giving the -i option (at least not directly).
This is what I did in my project:
def ipShell():
'''Starts the interactive IPython shell'''
import IPython
from IPython.config.loader import Config
cfg = Config()
cfg.TerminalInteractiveShell.confirm_exit = False
IPython.embed(config=cfg, display_banner=False)
# Then add the following line to start the shell
ipShell()
You need to be careful, though, because the shell will have the namespace of the module that the function ipShell() is defined. If you put the definition in the file you run, then you will be able to access the globals() you want. There could be other workarounds to inject the namespace you want, b̶u̶t̶ ̶y̶o̶u̶ ̶w̶o̶u̶l̶d̶ ̶h̶a̶v̶e̶ ̶t̶o̶ ̶g̶i̶v̶e̶ ̶a̶r̶g̶u̶m̶e̶n̶t̶s̶ ̶t̶o̶ ̶t̶h̶e̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶i̶n̶ ̶t̶h̶a̶t̶ ̶c̶a̶s̶e̶.
EDIT
The following function defaults to caller's namespace (__main__.__dict__).
def ipShell():
'''Starts the interactive IPython shell
with the namespace __main__.__dict__'''
import IPython
from __main__ import __dict__ as ns
from IPython.config.loader import Config
cfg = Config()
cfg.TerminalInteractiveShell.confirm_exit = False
IPython.embed(config=cfg, user_ns=ns, display_banner=False)
without any extra arguments.

python: run interactive python shell from program

I often have the case that I'll be writing a script, and I'm up to a part of the script where I want to play around with some of the variables interactively. Getting to that part requires running a large part of the script I've already written.
In this case it isn't trivial to run this program from inside the shell. I would have to recreate the conditions of that function somehow.
What I want to do is call a function, like runshell(), which will run the python shell at that point in the program, keeping all variables in scope, allowing me to poke around in it.
How would I go about doing that?
import code
code.interact(local=locals())
But using the Python debugger is probably more what you want:
import pdb
pdb.set_trace()
By far the most convenient method that I have found is:
import IPython
IPython.embed()
You get all your global and local variables and all the creature comforts of IPython: tab completion, auto indenting, etc.
You have to install the IPython module to use it of course:
pip install ipython
For practicality I'd like to add that you can put the debugger trace in a one liner:
import pdb; pdb.set_trace()
Which is a nice line to add to an editor that supports snippets, like TextMate or Vim+SnipMate. I have it set up to expand "break" into the above one liner.
You can use the python debugger (pdb) set_trace function.
For example, if you invoke a script like this:
def whatever():
x = 3
import pdb
pdb.set_trace()
if __name__ == '__main__':
whatever()
You get the scope at the point when set_trace is called:
$ python ~/test/test.py
--Return--
> /home/jterrace/test/test.py(52)whatever()->None
-> pdb.set_trace()
(Pdb) x
3
(Pdb)
Not exactly a perfect source but I've written a few manhole's before, here is one I wrote for an abandoned pet project http://code.google.com/p/devdave/source/browse/pymethius/trunk/webmud/handlers/konsole.py
And here is one from the Twisted Library http://twistedmatrix.com/trac/browser/tags/releases/twisted-8.1.0/twisted/manhole/telnet.py the console logic is in Shell.doCommand

Categories