Issuing commands to the command line in Python - python

This is my code. I'm pretty new to this.
from subprocess import call
call(["cd", "/etc/apache2/"])
However, when this function is run, I get
Errno 2: No such file or directory
I am running Django within Apache*. This is my views.py file. Ask for additional code, and you shall receive.
edit - It should be noted that /etc/apache2/ does indeed exist.

If you want to change the working directory of the Python process you can use chdir from the os module:
import os
os.chdir('/etc/apache2')

First of all, you will not get what you expect if you run this. Try
import os
os.chdir('/etc/apache2')
Second, try /path/to/cd as process may not know cd alias.

Related

Python/Linux/Streamlit: executing subprocess for linux script

I'm a bit turned around on how to execute a shell script file in a Linux environment via Python's subprocess command in Streamlit. Any assistance on what I'm missing is appreciated.
I'm using a shell script called 0_texts.sh to run Pylanguagetool for a grammar check of one text file and return corrections in another text file, like so:
cd /home/user/dir/TXTs/
pylanguagetool text_0.txt > comments_0.txt
This script runs correctly in the Linux terminal, writing a comments_0.txt with appropriate grammar checks from text_0.txt.
I need to create a Python/Streamlit app that runs these shell scripts. In attempting to run this shell script, I've written script.py below:
import os
import subprocess
import sys
subprocess.run(['bash','/home/user/dir/Scripts/0_texts.sh'])
I then run script.py in Streamlit via the code below, keeping with Streamlit's documentation on using subprocess here.
import streamlit as st
import os
import subprocess
import sys
def app():
button1 = st.button("Click me")
if button1:
p = subprocess.run([f"{sys.executable}", "/home/user/dir/pages/script.py"])
st.write(p)
When I execute the script.py via Streamlit, the 0_txts.sh script executes, writing comments_0.txt in the correct directory and providing the following traceback: CompletedProcess(args=['/usr/bin/python3', '/home/user/dir/pages/script.py'], returncode=0). However, the comments_0.txt output contains the error input file is required, as if it can't properly access or read text_0.txt. I've tinkered around trying to find the problem, but have hit a brick wall.
Any suggestions on what I'm missing, or paths forward? Any help greatly appreciated.

Import on shared object fails with ModuleNotFound only when script is executed from command line

ran into a weird problem where there is a shared-object import error only when I run the script from command line. It succeed if i run the script in the python console using exec(...)
I have a class that needs a shared object: foo.py:
import os
cur_dir = os.curdir()
os.chdir('/tmp/dir_with_shared_object/')
import shared_object_class
os.chdir(cur_dir)
class Useful:
... # use the shared object import
Then there is a script like this:
from foo import Useful
If I enter python console and run:
exec(open('script.py').read())
Everything works fine.
If I run this on command line:
python script.py
I will get
ModuleNotFoundError: No module named 'shared_object_class'
The python is the same. It is 3.7.3, GCC 7.3.0 Anaconda. Anyone knows what is causing this discrepancy in behavior for shared object import?
A standard way of importing from a custom directory would be to include it in the PYTHONPATH environmental variable, with export PYTHONPATH=/tmp/dir_with_shared_object/.
update
It could also be done dynamically with
import sys
p = '/tmp/dir_with_shared_object/'
sys.path.insert(0, p)
PS
I think I have an explanation for why OP's original code didn't work. According to this python reference page, the import system searches, inter alia, in "[t]he directory containing the input script (or the current directory when no file is specified)." So the behavior in the REPL loop is different from how it is when running a script. Apparently the current directory is evaluated each time an import statement is encountered, while the directory containing the input script doesn't change.

Use Python in ubuntu to show contents of a directory

I have a .py file in the home directory which contains these three lines:
import os
os.system("cd Desktop/")
os.system("ls")
and I want it to "ls" from the "Desktop" directory but it shows contents of the /home directory.
I looked at these pages:
Calling an external command in Python
http://ubuntuforums.org/showthread.php?t=729192
but I could not understand what to do. Can anybody help me?
The two calls are separate from each other. There is no context kept between successive invocations of os.system because a new shell is spawned for every call. First os.system("cd Desktop/") switches directories to Desktop and exits. Then a new shell executes ls in the original folder.
Try chaining your commands with &&:
import os
os.system("cd Desktop/ && ls")
This will show the contents of directory Desktop.
Fabric
If your application is going to be heavy on os usage you might consider using python-fabric. It allows you to use higher level language constructs like contextmanagers to make command line invocations easier:
from fabric.operations import local
from fabric.context_managers import lcd
with lcd("Desktop/"): # Prefixes all commands with `cd Desktop && `
contents=local("ls", capture=True)
You have to consider that os.system executes the commands in a sub-shell. Hence 1) python starts a sub-shell, 2) the directory is changed, 3) then the sub-shell is completed, 4) return to previous state.
To force the current directory change you should do:
os.chdir("Desktop")
Always try and do it by other means that through os.system (os.listdir), or also by doing other than subprocess (which is an excellent module for command control in the shell)

Crontab Python Script Execution (Can't find settings config file)

My Crontab -l
# m h dom mon dow command
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
00 8,20 * * * python /home/tomi/amaer/controller.py >>/tmp/out.txt 2>&1
My controller.py has config file settings.cfg also it uses other script in the folder it's located (I chmoded only controller.py)
The error
1;31mIOError^[[0m: [Errno 2] No such file or directory: 'settings.cfg'
I have no idea how to fix this? Please help me?
Edit: The part that read the config file
def main():
config=ConfigParser.ConfigParser()
config.readfp(open("settings.cfg"),"r")
As I initially wrote in my comment, this is because you are using relative path to the current working directory. However, that is not going to be the same when running all this via the cron executable rather than the python interpreter directly via the shebang.
Your current code would look for the "settings.cfg" in the current working directory which is where the cron executable resides, and not your script. Hence, you would need to change your code logic to using absolute paths by the help of the "os" built-in standard module.
Try to following line:
import os
...
def main():
config = ConfigParser.ConfigParser()
scriptDirectory = os.path.dirname(os.path.realpath(__file__))
settingsFilePath = os.path.join(scriptDirectory, "settings.cfg")
config.readfp(open(settingsFilePath,"r"))
This will get your the path of your script and then appends the "settings.cfg" with the appropriate dir separator for your operating system which is Linux in this particular case.
If the location of the config file changes any time in the future, you could use the argparse module for processing a command line argument to handle the config location properly, or even without it simply just using the first argument after the script name like sys.argv[1].
Your code is looking for settings.cfg in its current working directory.
This working directory will not be the same when cron executes the job, hence the error
You have two "easy" solutions:
Use an absolute path to the config file in your script (/home/tomi/amaer/config.cfg)
CD to the appropriate directory first in your crontab (cd /home/tomi/amaer/ && python /home/tomi/amaer/controller.py)
The "right" solution, though, would be to pass your script a parameter (or environment variable) that tells it where to look for the config file.
It's not exactly good practice to assume your config file will always be lying just next to your script.
You might want to have alook at this question: https://unix.stackexchange.com/questions/38951/what-is-the-working-directory-when-cron-executes-a-job

Run python script from python using different python

I have a software that has python 2.5.5. I want to send a command that would start a script in python 2.7.5 and then proceed with the script.
I tried using
#!python2.7.5
and http://redsymbol.net/articles/env-and-python-scripts-version/
But I cant get it to work...
In my python 2.5.5 I can execute script as
execfile("c:/script/test.py")
The problem is that the 2.7.5 has a module comtypes + few other. I dont know how to install it for my 2.5.5 so I'm trying to start a separate script and run it under python27. Now another reason why I want it its because I want to take the load off program. I have 2 heavy tasks to perform. The second task is the one that need comptypes so sending it to external shell/app would do perfect trick. Is there a way to do it ?
I wish I could just type run("C:/Python27/python.exe % C:/script/test,py")
Thanks, bye.
Little update. I try to run
import os
os.system("\"C:\Python27\python.exe\" D:\test\runTest.py")
But I'm getting a quick pop up and close window saying that
Import Error : no module named site...
This works if I run from external shell but not from here :(
So I've tried another approach this time to add modules to python... in any case I run this :
import os
import sys
sys.path.append("C:/python27")
sys.path.append("C:/Python27/libs")
sys.path.append("C:/Python27/Lib")
sys.path.append("C:/Python27/Lib/logging")
sys.path.append("C:/Python27/Lib/site-packages")
sys.path.append("C:/Python27/Lib/ctypes")
sys.path.append("C:/Python27/DLLs")
import PyQt4
print PyQt4
import comtypes
import logging
but it crashes with C error...
Runtime Error :
Program: c:\Pr...
R6034
An application has made attempt to load the C runtime library incorectly.
blablabla....
How can I import it ? Maybe if I can import it I can run it directly from my app rather than starting separate python...
Traceback (most recent call last):
File "<string>", line 18, in <module>
File "C:\Python27\Lib\site-packages\comtypes\__init__.py", line 22, in <module>
from ctypes import *
File "C:\Python27\Lib\ctypes\__init__.py", line 10, in <module>
from _ctypes import Union, Structure, Array
ImportError: DLL load failed: A dynamic link library (DLL) initialization routine failed.
Another update to isseu
so I run now
import os
os.system("start cmd {D:\test\runTest.py}")
now this works and he open CMD with c:\Python27 as directory but he dont run the file... any hitns how to fix it?
Use "raw" strings so that you don't need to escape as much; I think the backslashes are what was breaking your code since backslash is considered an escape character except in raw strings.
Also, use the subprocess module. It makes it easy to avoid manually making a safe command string (the module takes care of that for you). All you need to do is pass it a list of arguments.
Your code would then look something like this:
import subprocess
proc = subprocess.Popen([r"C:\Python27\python.exe", r"D:\test\runTest.py"])
# then either do this
proc.wait() # wait until the process finishes
# or this
while True:
# NOTE: do something else here
# poll the process until it is done
if proc.poll() is not None:
break # break out of loop
See subprocess docs for Python 2 here. Be sure to check if a feature was added after Python 2.5 (the 2.5 docs aren't available online anymore AFAIK).
UPDATE:
I just noticed that you tried to use the Python 2.7 libraries and modules in your 2.5 code. This probably won't work due to new features added after 2.5. But it got me thinking how you might be able to make 2.7 work.
It may be that your Python2.7 install can't find its libraries; this is probably why you get the error Import Error : no module named site. You can do something like the above and modify the PYTHONPATH environment variable before starting the subprocess, like this:
import os
import subprocess
paths = [r"C:\python27", r"C:\python27\libs", r"C:\python27\Lib\site-packages", r"C:\python27\DLLs"]
paths += os.environ.get('PYTHONPATH', '').split(os.pathsep)
env27 = dict(os.environ)
env27['PYTHONPATH'] = os.pathsep.join(paths)
proc = subprocess.Popen([r"C:\Python27\python.exe", r"D:\test\runTest.py"], env=env27)

Categories