In a linux terminal typing
python script.py
Will run run script.py and exit the python console, but what if I just want to run a part of the script and leave the console open? For example, run script.py until line 15 and leave the console open for further scripting. How would I do this?
Let's say it's possible, then with the console still open and script.py run until line 15, can I then from inside the console call line fragments from other py files?
...something like
python script.py 15 #(opens script and runs lines 1-15 and leaves console open)
Then having the console open, I would like to run lines 25-42 from anotherscript.py
>15 lines of python code run from script.py
> run('anotherscript.py', lines = 25-42)
> print "I'm so happy the console is still open so I can script some more")
I'm so happy the console is still open so I can script some more
>
Your best bet might be pdb, the Python debugger. You can start you script under pdb, set a breakpoint on line 15, and then run your script.
python -m pdb script.py
b 15 # <-- Set breakpoint on line 15
c # "continue" -> run your program
# will break on line 15
You can then inspect your variables and call functions. Since Python 3.2, you can also use the interact command inside pdb to get a regular Python shell at the current execution point!
If that fits your bill and you also like IPython, you can check out IPdb, which is a bit nicer than normal pdb, and drops you into an IPython shell with interact.
if you want to run script.py from line a to line b, simply use this bash snippet:
cat script.py|head -{a+b}|tail -{b-a}|python -i
replace {a+b} and {b-a} with their values
You could use the python -i option to leave the console open at the end of the script.
It lets your script run until it exits, and you can then examine variables, call any function and any Python code, including importing and using other modules.
Of course your script needs to exit first, either at the end or, if your goal is to debug that part of the script, you could add a sys.exit() or os._exit() call where you want it to stop (such as your line 15).
For instance:
import os
print "Script starting"
a=1
def f(x):
return x
print "Exiting on line 8"
os._exit(0) # to avoid the standard SystemExit exception
print "Code continuing"
Usage example:
python -i test_exit.py
Scrit starting
Exiting on line 8
>>> print a
1
>>> f(4)
4
>>>
You cannot do that directly but you can do something similar from inside Python console (or IDLE) with exec :
just open you favorite Python console
load wanted lines into a string and exec them :
script = 'script.py'
txt = ''
with open(script) as sc:
for i, line in enumerate(sc):
if i >= begline and i<= endline:
txt = txt + line
exec(txt)
You can even write your own partial script runner based on that code ...
EDIT
I must admit that above answer alone really deserved to be downvoted. It is technically correct and probably the one that most closely meet what you asked for. But I should have warned you that it is bad pratice. Relying on line numbers to load pieces of source files is error prone and you should avoid it unless you really know what you are doing and why you do it that way. Python debugger at least allows you to control what are the lines you are about to execute.
If you really have to use this solution be sure to always print and double check the lines that you are about to execute. IMHO it is always both simpler and safer to copy and past lines in an IDE like IDLE that is packaged into any standard Python installation.
Related
I would like to simplify running Python scripts from within the Python shell. In Python 2, you could just use execfile(path). But in Python 3 it's harder to remember:
exec(open(path).read())
So I want a function to run a script, as simple as run(path). I can do this from the Python shell:
def run(filename):
source = open(filename).read()
code = compile(source, filename, 'exec')
exec(code)
Then I can just type in run(path). This works great, and now I want to simplify things by defining the run function every time I launch Python 3.
I'd like to configure my ~/.zshenv with a zsh alias or function (say, py) that launches Python and tells it to define the run function. So that's where I'm stumped. What would a such a zsh command look like? I've tried and failed with things like:
py () {
python -c "\
def run(filename): \
source = open(filename).read() \
code = compile(source, filename, 'exec') \
exec(code)" \
}
But that fails miserably:
% py
File "<string>", line 1
def run(filename): source = open(filename).read() code = compile(source, filename, 'exec') exec(code)
IndentationError: unexpected indent
%
And even if it were to work, it would drop back out of the Python shell once the function was defined. Obviously I don't know what I'm doing here. Any pointers?
Also… please don't assume I have asked the right question. Usually on StackOverflow we try to avoid second-guessing posters' assumptions. But go ahead and second-guess mine if there's a better way to get Python to always define a run function when it is launched.
If you need this function only for interactive shells, you can write it in a file and then run python -i file_with_function.py. The -i option will tell the interpreter to drop into an interactive session after whatever is in the file_with_function.py file runs.
If you want it for any .py file that you will run non-interactively then you can do one of the following:
Create a package that contains your run function and install your package on your interpreter. There is a detailed guide on the Python docs (https://packaging.python.org/tutorials/packaging-projects/).
Add the directory that contains a .py file with your function on the PYTHONPATH environmental variable and import it from there.
In the command which you are passing to Python (using python -c), you start the function definition with a couple of spaces. Spaces at the start of a line are significant in Python. You would get the same error, if you would open a Python shell and write
def foo:
with several spaces in front: Python responds with IndentationError: unexpected indent.
In addition, your use of backslash characters makes all the linefeeds disappear, with the effect that you are going to define the complete function in a single line. This is also invalid in Python, so even if you would fix the initial spaces, you would still get SyntaxError: invalid syntax.
Note that you can use the -m option of Python to load initial definition together with starting Python. You can do a
python -h
to get a list of the valid command line options.
I know this question has been asked in various variations but none of them seem to work for my specific case:
(btw all mentioned files are in my PATH)
I have a simple python script called test.py:
import sys
print('Hello world!')
print(sys.argv)
counter = 0
while True:
counter +=1
The counter is just there to keep the command window open so don't worry about that.
When I enter
test.py test test
into cmd I get the following output:
Hello world!
['C:\\Users\\path\\to\\test.py']
For some reason unknown to me the two other commands (sys.argv[1] and sys.argv[2]) are missing.
However when I create a .bat file like this:
#C:\Users\path\to\python.exe C:\Users\path\to\test.py %*
and call it in cmd
test.bat test test
I get my desired output:
Hello world!
['C:\\Users\\path\\to\\test.py', 'test', 'test']
I've read that the
%*
in the .bat file means that all command line arguments are passed to the python script but why are exactly these arguments not passed to the python script when I explicitly call it in cmd?
From what I've read all command line arguments entered after the script name should be passed to said script but for some reason it doesn't work that way.
What am I overlooking here?
I'm guessing that you need to actually run the script through the command line with C:\Users\path\to\python.exe test.py test test.
I'm not sure how Windows handles just test.py test test but from my limited experience it is probably just trying to open all 3 of those files. Since the first one (test.py) has a .py extension, it is opened with the Python Interpreter and is run automatically. The other two are not actually being passed in as an argument.
This question already has answers here:
how to "source" file into python script
(8 answers)
Closed 3 years ago.
I am struggling to execute a shell script from a Python program. The actual issue is the script is a load profile script and runs manually as :
. /path/to/file
The program can't be run as sh script as the calling programs are loading some configuration file and so must need to be run as . /path/to/file
Please do guide how can I integrate the same in my Python script? I am using subprocess.Popen command to run the script and as said the only way it works is to run as . /path/to/file and so not giving the right result.
Without knowledge of the precise reason the script needs to be sourced, this is slightly speculative.
The fundamental problem is this: How do I get a source command to take effect outside the shell script?
Let's say your sourced file does something like
export fnord="value"
This cannot (usefully) be run in a subshell (as a normally executed script would) because the environment variable and its value will be lost when the script terminates. The solution is to source (aka .) this snippet from an already running shell; then the value stays in that shell's environment until that shell terminates.
But Python is not a shell, and there is no general way for Python to execute arbitrary shell script code, short of reimplementing the shell in Python. You can reimplement a small subset of the shell's functionality with something like
with open('/path/to/file') as shell_source:
lines = shell_source.readlines()
for line in lines:
if line.strip().startswith('export '):
var, value = line[7:].strip().split('=', 1)
if value.startswith('"'):
value = value.strip('"')
elif value.startswith("'"):
value = value.strip("'")
os.environ[var] = value
with some very strict restrictions (let's not say naïve assumptions) on the allowable shell script syntax in the file. But what if the file contained something else than a series of variable assignments, or the assignment used something other than trivial quoted strings in the values? (Even the export might or might not be there. Its significance is to make the variable visible to subprocesses of the current shell; maybe that is not wanted or required? Also export variable=value is not portable; proper Bourne shell script syntax would use variable=value; export variable or one of the many variations.)
If you know what exactly your Python script needs from the shell script, maybe do something like
r = subprocess.run('. /path/to/file; printf "%s\n" "$somevariable"',
shell=True, capture_output=True, text=True)
os.environ['somevariable'] = r.stdout.split('\n')[-2]
to source the entire script in a subshell, then print to standard output the part you actually need, and capture that from your Python script (and assign it to an environment variable if that's what you eventually need to accomplish).
Is it possible to run code line by line with Python.
Including running any module code, when used, line by line as well.
I would like to go out and run some code line by line and watch as each of the lines goes through the processing phase and see just what code is getting executed when certain actions occur. I'm curious how certain values are getting passed off to the interpreter.
Just use python -m pdb mycode.py, which will run your code in the python debugger (pdb module).
In the debugger you can execute arbitrary code, watch variables, and jump to different places in the code. Specifically, n will execute the next line and h will show you the debugger help.
To add a breakpoint you can use pdb inline:
import pdb; pdb.set_trace()
From this line bleow you can go step by step and you can enter inside every called function (with s) or jump function execution (with n).
Also, a good tip is to use ipdb instead of pdb because it knows autocomplete (it's an ipython prompt)
import os
import subprocess
import sys
import re
## fname_ext=sys.argv[1]
fname_ext=r"C:\mine\.cs\test.cs"
exe=os.path.splitext(fname_ext)[0]+".exe" # Executable
fdir=os.path.split(fname_ext)[0]
fcontent=open(fname_ext).read()
p_using=re.compile("\s*using\s+((\w+[.]*)+)")
p_namespace=re.compile("\s*namespace\s+(\w+)")
usings=p_using.findall(fcontent)
usings=[x[0] for x in usings]
references=[]
for i in os.listdir(fdir):
path=fdir+"\\"+i
try:
if os.path.isdir(path) or (not path.endswith('cs')):continue
with open(path) as fp:
content=fp.read()
namespaces=p_namespace.findall(content)
for n in namespaces:
if n in usings and 'System' not in n:
references+=[path]
except:
pass
command="csc /nologo "+" ".join(references)+" "+fname_ext
## command=" ".join(references)
#~ ---------------------------------------------------------
# Build:
option=1
if option==0:
# using os.system
print ">>",command
if os.system(command)==0:
os.system(exe)
else:
#~ Using subprocess module
## print type(references)
command=['csc']
## print command,references
command.extend(["/nologo","/out:"+exe])
command.extend(references)
command.append(fname_ext)
## print command
if subprocess.call(command,shell=True)==0:
## print "running %s"%exe
subprocess.call([exe],shell=True)
else:
pass
## print "Failed to run"
#~ ---------------------------------------------------------
I have this code above that is supposed to run a Csharp program from SciTE. It searches
every .cs file in the directory and finds the file with the namespace that the current
file has included. The command to run the file in SciTE is:
command.go.*.cs=python C:\mine\.py\csc.py $(FilePath)
command.go.subsystem.*.cs=0
That program logic part is okay.
The issue is that when hit F5 with sample Csharp code like this:
using System;
using System.Collections;
using MyNamespace;
class Test{
public static void Main(String[] args){
MyObject inst=new MyObject();
MyObject.self_destruct(inst);
}
}
it runs ok. But when I uncomment the second fname_ext and comment the first one
and run the csc.py file, a window opens and keeps running, printing command(this happens
using the os.system option). When you use the subprocess.call option, the same thing
happens but this time only when shell=True. It ran for only 15 seconds and there were 800+
cmd.exe and python.exe processes.I had to wait almost 5 minutes after killing cmd.exe
for the mouse to start responding and 2 minutes more for desktop peek to work.
When shell=False, it runs ok, the same way as when you hit the F5 key from the file.
What is happening here?
What is shell=True doing that makes it behave that way?
The problem is that your sys.argv looks something like this:
['python', r'C:\mine\.py\csc.py', 'whatever.cs']
So, with the fname_ext line uncommented, you set fname_ext to r'C:\mine\.py\csc.py'. Which means your script ends up just running itself—which again runs itself, etc., as fast as possible until your system chokes.
The reason it doesn't happen with shell=False is that you can't actually exec a Python script. Ultimately you end up calling CreateProcess with your script, which tries to interpret it as a .exe file, fails, and returns an error. But with shell=True, you pass your script to cmd.exe to run as a program, and it does the same thing an interactive prompt or Explorer would do: finds the right mapping to execute .py files and uses it. (And os.system does effectively the same thing as shell=True, but with a couple extra layers tossed in for good measure.)
Okay, I'll take a stab at this. If I understand the situation, this script is called csc.py and you want to call the csc c# compiler. When you run csc /nologo (etc...) through cmd.exe, it starts looking for something called 'csc' with a known extension. It finds csc.py in the current directory and since .py is a registered extension, that's what gets executed.
The solution is to rename your python file or call out 'csc.exe' explicitly.