Python: which directory to work from - python-3.x

I'm on Windows 7 and using Python 3.6. The PATH has C:\Python36-32 and C:\Python36-32\scripts. This is my first foray into Python and I am working with a one line script which is merely:
print("hello")
and I'm already running into trouble.
I installed Python into C:\Python36-32. I saved hello.py to C:\Users\shea\Documents. If I open IDLE and try
>>> C:\Python36-32\python.exe C:\Users\shea\Documents\hello.py
SyntaxError: unexpected character after line continuation character
or
>>> python.exe hello.py
SyntaxError: invalid syntax
The first attempt came from a question or other reading somewhere else, I've been searching for over 2 hours for this question, that said that the complete path to the program needs to be given. Apparently, I need to add something else to another PATH to get to just using python ..., but I'm not worried about that at the moment. The 2nd attempt is just me trying something apparently easy out of frustration and that doesn't work either. I get the same problems with cmd. I don't know what is behind either problem. From the questions I've looked at, Python doesn't like more text after "\", but I don't know how I'd say what the name of the script is that I want to run with python.exe.
I think part of the problem is that the script is not in the same directory as python.exe, but I am not sure of that. Can I work with Python this way? If so, what is the right syntax to get Python to return the simple "hello" in IDLE or the cmd terminal?

The IDLE is not the same as a terminal shell.
You can do: File -> Open and open your file then Run it from Run menu or by pressing F5.

When you run IDLE you are running the python interpreter, not a regular shell. The python interpreter works on a specific directory, which you can check by doing:
>>> import os
>>> os.getcwd()
The directory it will output it's the directory the interpreter is currently in. You can change the directory the interpreter is currently in by doing:
>>> os.chdir(r'C:\Users')
In this case i changed the directory to 'C:\Users'. You can run os.getcwd() again to confirm the directory changed.
Withing the interpreter, you can run scripts using the import(<path_to_script>) call:
>>> import(r'myscript.py')
Since i only gave the name of the file, it will search for the file on the directory the interpreter is in. Since i put the interpreter in 'C:\Users', it'll look for a 'C:\Users\myscript.py' file and run the code in it. You can also pass the complete path to the import call, in which case it'll run the script no matter where the interpreter is currently in. The r before the string just tells python to take the string as it is and to not look for special characters. This is important because if you indicate your paths using \ then python would take the next letter after every \ as a special character, and would not read the path correctly (for instance, \n is a special character which indicates a new line).
If you import a script, and then do changes to it, to run it again, use the reload call:
>>> reload(r'myscript.py')
If you just want to run this on a regular terminal you just need to do:
python <script_file>
Provided the folder to the python binary is already in the environment variable PATH of Windows. In a regular shell, what you have to put on <script_file> follows the same rules as if it were on the python interpreter: if your command shell is already in directory of your script, then give just the name of the file, otherwise give the complete path, using "" and /.

Related

How to execute a shell program taking inputs with python?

First of all, I'm using Ubuntu 20.04 and Python 3.8.
I would like to run a program that takes command line inputs. I managed to start the program from python with the os.system() command, but after starting the program it is impossible to send the inputs. The program in question is a product interface application that uses the CubeSat Space Protocol (CSP) as a language. However, the inputs used are encoded in a .c file with their corresponding .h header.
In the shell, it looks like this:
starting the program
In python, it looks like this:
import os
os.chdir('/home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1')
os.system('./waf')
os.system('./build/csp-client -k/dev/ttyUSB1')
os.system('cmp ident') #cmp ident is typically the kind of command that does not work on python
The output is the same as in the shell but without the "cmp ident output", that is to say it's impossible for me to use the csp-client#
As you can probably see, I'm a real beginner trying to be as clear and precise as possible. I can of course try to give more information if needed. Thanks for your help !
It sounds like the pexpect module might be what you're looking for rather than using os.system it's designed for controlling other applications and interacting with them like a human is using them. The documentation for it is available here. But what you want will probably look something like this:
import pexpect
p = pexpect.spawnu("/home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1/build/csp-client -k/dev/ttyUSB1")
p.expect("csp-client")
p.sendline("cmp indent")
print(p.read())
p.close()
I'll try and give you some hints to get you started - though bear in mind I do not know any of your tools, i.e. waf or csp-client, but hopefully that will not matter.
I'll number my points so you can refer to the steps easily.
Point 1
If waf is a build system, I wouldn't keep running that every time you want to run your csp-client. Just use waf to rebuild when you have changed your code - that should save time.
Point 2
When you change directory to /home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1 and then run ./build/csp-client you are effectively running:
/home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1/build/csp-client -k/dev/ttyUSB1
But that is rather annoying, so I would make a symbolic link to that that from /usr/local/bin so that you can run it just with:
csp-client -k/dev/ttyUSB1
So, I would make that symlink with:
ln -s /home/augustin/workspaceGS/gs-sw-nanosoft-product-interface-application-2.5.1/build/csp-client /usr/local/bin/csp-client
You MAY need to put sudo at the start of that command. Once you have that, you should be able to just run:
csp-client -k/dev/ttyUSB1
Point 3
Your Python code doesn't work because every os.system() starts a completely new shell, unrelated to the previous line or shell. And the shell that it starts then exits before your next os.system() command.
As a result, the cmp ident command never goes to the csp-client. You really need to send the cmp ident command on the stdin or "standard input" of csp-client. You can do that in Python, it is described here, but it's not all that easy for a beginner.
Instead of that, if you just have aa few limited commands you need to send, such as "take a picture", I would make and test complete bash scripts in the Terminal, till I got them right and then just call those from Python. So, I would make a bash script in your HOME directory called, say csp-snap and put something like this in it:
#/bin/bash
# Extend PATH so we can find "/usr/local/bin/csp-client"
PATH=$PATH:/usr/local/bin
{
# Tell client to take picture
echo "nanoncam snap"
# Exit csp-client
echo exit
} | csp-client -k/dev/ttyUSB1
Now make that executable (only necessary once) with:
chmod +x $HOME/csp-snap
And then you can test it with:
$HOME/csp-snap
If that works, you can copy the script to /usr/local/bin with:
cp $HOME/csp-snap /usr/local/bin
You may need sudo at the start again.
Then you should be able to take photos from anywhere just with:
csp-snap
Then your Python code becomes easy:
os.system('/usr/local/bin/csp-snap')

Having issues with a shell command in Python

I am currently studying Python. In my course I have got to reading files. My tutor is showing me the following syntax....
!cat data_file/sample.txt
When he executes this command on screen it lets him view the text contents of the file.
When I execute the code it gives me an error of cat not recognized as a valid shell command in Python.
I have read through as much Python documentation as I can and have come up with nothing!
Can anyone please help??
Its not a python specific functionality. Please use Jupyter (Ipython).
Your tutor is probably using jupyter, which in turn uses IPython.
The bang (!) means that Ipython will execute a system shell command, like:
!cat data_file/sample.txt
In this case output the contents of a txt file. This functionality is documented here

Python shebang line with Python3

I have the following python file:
vagrant#vagrant-ubuntu-trusty-64:~/my_app$ cat version_py3.py
#!/usr/bin/env python3
print "Python 2 print statement"
and I thought python version_py3.py will enforce the use of python3. But the code ran fine. and python3 version_py3.py gives expected error.
vagrant#vagrant-ubuntu-trusty-64:~/my_app$ python3 version_py3.py
File "version_py3.py", line 3
print "Python 2 print statement"
^
Also, there is no /usr/bin/env folder on my linux. Am I missing something here with the shebang right, but Python 2 and Python 3 are both installed on my computer.
vagrant#vagrant-ubuntu-trusty-64:~/my_app$ python -V
Python 2.7.6
vagrant#vagrant-ubuntu-trusty-64:~/my_app$ python3 -V
Python 3.4.3
vagrant#vagrant-ubuntu-trusty-64:~/my_app$
When you execute a script and you want have the shebang line respected, you may not prepend "python" in the command. A binary executable as the head of a command, which could work in she-bang as well, any given she-bang is ignored because the command executable is always preferred by the kernel.
Example: So let's assume you have a little python script, but with cat in the shebang. What happens when you set the executable bit of the script and call it as the command head is that the system first reads the first line, strips off the initial two bytes and tries to execute the (mandatorily binary) executable and feed it the script file.
$ /tmp/getver
#!/bin/cat
import sys
print( sys.version )
And now try and see yourself prepending python, python2 and/or python3.
Trivia: The interpreter may choose to process the shebang another time, on its own. E.g. perl used to respect any flags like -w given, whether it is given on the shebang or on the command, no matter if perl is the command head.
Try to located the python installation with locate for example, and set it in your shebang, like #!/usr/bin/python3.6 . I bet it's here.
I am not sure if you have found the solution. In python3, the syntax for print is different. The message has to be inside the parenthesis.
Try print("Python 2 print statement")

"mode" doesn't run in python 3.5 subprocess

I have encountered a bit of a conundrum while working on an automation project.
When I try to run:
program = subprocess.run("mode")
I get:
FileNotFoundError: [WinError 2] The system cannot find the file specified
However, when I replace mode with ipconfig:
program = subprocess.run("ipconfig")
it runs perfectly fine.
Anyone got an explanation? I am currently using a batch file to run the mode command, but I would like to change the arguments without editing a batch file.
Edit 1:
I also just tried using os.system:
os.system("mode")
and that also worked.
Edit 2:
Now I would just like answer to the original problem just to understand what was going on.
In Actual meaning of 'shell=True' in subprocess it pretty much says that shell=True is something that you should shy away from.
FileNotFoundError: [WinError 2] The system cannot find the file specified
Is what tipped me off that you might want shell=True in your subprocess call. If the file can't be found that means one of two things:
It's not on your path.
It's not actually a file.
For instance, in Linux:
$ which echo
echo: shell built-in command
That makes it pretty obvious that there is no echo file. It's just a command that's built into the shell. This may be the same thing when it comes to mode on Windows. Though this site seems to suggest that it's a MODE.COM file. You may try invoking that, as in
subprocess.run('MODE.COM')
That may work - at least according to one of the answers that I linked to
Invoking via the shell does allow you to expand environment variables and file globs according to the shell's usual mechanism. On POSIX systems, the shell expands file globs to a list of files. On Windows, a file glob (e.g., ".") is not expanded by the shell, anyway (but environment variables on a command line are expanded by cmd.exe).
So in your case, perhaps mode isn't a file, but MODE.COM is, and since Windows has a spotty relationship with casing, it seems possible that by passing shell=True, the Windows shell happily takes mode and converts it to MODE.COM for you, but without it, it tries to execute the file literally named mode, which doesn't exist.

Default file ending in Mac, Linux and Windows to run executable in the shell/terminal

I created executables of a python script (via pyinstaller) for Mac, Windows and Linux. For Linux and Mac, I am running them in the shell since it doesn't have an own interface: just open a shell and type the name of the program.
I am wondering if there is a way to use certain file ending so if the user clicks on the program, it will be automatically executed in the shell or terminal. Alternatively, I would appreciate any other ideas of how to do this.
The way to do this is not to append a certain file ending, but, as pointed out in the comment, make the file executable (chmod +x <file>) and add the magic bytes to the beginning of the file that tell the system how to execute it.
The magic bytes are #! and are followed by the path to executable. So for a python script you would put something like the following at the top of the file:
#!/usr/bin/env python
Okay, now I finally found out the solution to my question. All you have to do to execute the program upon clicking on it in the file browser is to add the ending .command and make it executable
E.g., exampleprogram.command. Clicking on it will execute the program in the shell

Resources