This is a follow up question as I'm trying to move forward with Zelle's Python:Programming.
It appears that IDLE 2.7.2 has hang issues when opening graphics windows in interactive mode. But, I can simply run Python interactively in Terminal and don't have any of those issues. So that's a big help. Zelle provides a simplified graphics file called graphics.py, to get up to speed with objects and graphics, before dealing directly with Tkinter.
My question is this. Where should I put graphics.py, so Terminal will see it (when it's called), without including the full path every time? Thanks,
Henry
According to PEP 0370, a good place to put your user packages is in ~/.local/lib/python2.7/site-packages.
Modules in here should be importable.
You can modify your ~/.bashrc to include a PYTHONPATH definition that includes the location of the file.
export PYTHONPATH="/path/to/directory_containing_graphics.py"
Just be careful if it's in your home director to use /Users/[username]/etc/directory_containing_graphics.py, I vaguely recall being bitten by ~ not expanding like I expected one time on OS X.
I went deep down the rabbit hole to get to bottom of this issue. It turns out that bash on OSX has a few quirks, not unexpected with the various flavors of UNIX around. It turns out that when firing up a bash shell, bash looks in .bash_profile for config statements. If you enter bash into bash, you fire up a sub shell, and that's when and only when .bashrc is executed.
To make sure you only have to manage one config file, put:
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
in your .bash_profile. This just tells bash to look into the .bashrc file if it exists. You can then leave that file alone and only modify your .bashrc file and all instances of bash will be modified the same. Once I figured this out, I still had to solve my problem. Here's the best I could do. When Python installed it installed this into my .bash_profile:
PATH="/Library/Frameworks/Python.framework/Versions/2.7/bin:${PATH}"
export PATH
This tells bash where to look for the libraries needed to run Python. So I moved this statement to my .bashrc file after putting the "if" statement into my .bash_profile. I then tried adding a : to the PATH statement with the path to my Python modules, but that didn't work. So, I have settled for a statement like this in .bashrc:
PYTHONPATH=$PYTHONPATH:/Users/ftpbub/Documents/workspace/Python\ Programming\ Modules/src/
export PYTHONPATH
Now I enter python at the command prompt, and when I get to python, I can enter import modulename without the path and it works. If I start a new project in a new directory, I should be able to add it to my PYTHONPATH and be good. I would have liked to be able to enter python modulename right into bash and have the module execute, but I haven't figured out how to do that. Other than that, I think this the best I can do. Ideas for how to go straight to the module from the bash prompt, without entering the path?
Related
I'm new to stackoverflow and really hope to get answers to my question about crontab.
I'm using MacbookAir in BigSur(don't know if it affects)And my crontab just couldn't run python scripts below.
f = open("test_crontab.txt",'w+')
f.write("Success")
f.close()
But I could run this script with Spyder.
I could edit crontab with crontab -e, and my code in vi crontab was
13 01 * * * /bin/zsh /Users/myusername/Documents/Lynn\'s\ Python\ work/shopee/test.py >>/Users/myusername/Desktop/out.log 2>>/Users/tzulingkuo/Desktop/err.log
But it failed to generate txt file.
The messages in err.log were like below:
/Users/*myusername*/Documents/Lynn's Python work/shopee/test.py:5: missing end of string
/Users/*myusername*/Documents/Lynn's Python work/shopee/test.py:6: unknown username ''
I've searched stackoverflow for two nights and couldn't find the solution. I major in finance and I have no friends studying computer science.
Could anyone help me 🥺
Any help is reaaaaally appreciated!
Since that's a python script, you need to run it in python, not /bin/zsh. zsh is trying to interpret it as a shell script, but the syntax is all wrong, so you get errors.
The simplest way to fix this to replace /bin/zsh in your crontab entry with /usr/bin/python (assuming you're using the built-in Python version 2; if you have installed Python version 3 and want to use that, run which python at the command line to find its path).
But it's generally better to add a shebang line to your python script, and let that control how it's run. Add this as the very first line of the script:
#!/usr/bin/python
(Again, if you want to use Python 3, replace the path part with the path for the Python 3 interpreter.) Then make the script executable with chmod +x /Users/myusername/Documents/Lynn\'s\ Python\ work/shopee/test.py, and just remove the /bin/zsh part from the crontab entry.
BTW, you're probably going to have trouble with paths. By default, cron jobs run with their working directory set to your home directory, so when the script opens test_crontab.txt, that's going to be interpreted as /Users/myusername/test_crontab.txt. If you want it down in the Documents/Lynn's Python work/shopee directory, you'll have to specify that explicitly.
You may also run into trouble with missing environment variables. If you're setting any environment variables in your shell initialization scripts that configure Python, add libraries, etc, those won't be set up in the cron job's environment.
I have the following problem: I wrote a bash script for data analysis that works perfectly fine when I run it from the terminal. To further automate the process I wanted to use a python script that runs the bash script (using subprocess.call), changes the working directory, and reruns the script (and so on). This also worked fine when I did it on my MacBook. However, I need to do the analysis on a Linux machine and here the problem occurred. Again, running the script from the terminal worked fine but once I tried doing this with my python script it fails to find the relevant functions for the analysis. The functions are stored inside the anaconda3/bin folder.
(Python does not even find other functions like "pip")
Of course, I could add the path to all the functions in the bash script but this seems very inefficient to me. So my question is: is there any better way of telling python where to look for the functions? And can you maybe explain to me why running the script from the terminal works but not when I use subprocess.call?
Here is the python script:
import subprocess
import os
path_list = ["Path1",
"Path2"
]
for path in path_list:
os.chdir(path)
subprocess.call("Users/.../bash_script", shell=True)
I'm just posting my series of comments as an answer since I think this at least constitutes a reasonable answer for anyone running into a similar issue (your question could definitely be common enough to index from search engine results).
Issue:
...running the script from the terminal worked fine but once I tried doing this with my python script it fails to find the relevant functions for the analysis
In general, you can troubleshoot this kind of problem with:
import subprocess
subprocess.call('echo $PATH', shell=True)
If the directory that contains the relevant binaries/scripts/etc. is not in the output, then you are facing a PATH issue in the shell created by subprocess.call.
The exact problem as confirmed by the OP in comments is that anaconda3/bin is not part of your PATH. Your script works in a regular terminal session because of the Anaconda initialization function that gets added to your .bashrc when installing.
Part of an answer that is very helpful here: Python - Activate conda env through shell script
The problem with your script, though, lies in the fact that the .bashrc is not sourced by the subshell that runs shell scripts (see this answer for more info). This means that even though your non-login interactive shell sees the conda commands, your non-interactive script subshells won't - no matter how many times you call conda init.
Solution 1: Manually use the Anaconda sourcing function in your script
As the OP mentioned in the comments, their workaround was to use the initialization function added to their .bashrc in the script they are trying to run. Although this perhaps feels like not a great solution, this is a "good enough" workaround. Unfortunately I don't use Anaconda on Linux so I don't have an exact snippet of what this looks like. See the next section for a possibly "cleaner" solution.
Solution 2: Use bash -i to run your script
As mentioned in the same answer linked above, you might be able to use:
bash -i Users/.../bash_script
This will tell bash to run in interactive mode, which then properly sources your .bashrc file when creating the shell. As a result, Anaconda and related functions should work properly.
Solution 3: Manually add anaconda3/bin to PATH
You can check out this answer to decide if this is something you want to do. Keep in mind they are speaking about a Windows OS but most of the same applies to Linux.
When you add the directory to your PATH, you are specifically telling your system to always look in that directory for commands when executing by name, e.g. ping or which. This can have unexpected behavior if you have conflicts (e.g. a command is found with the same name in /usr/bin and .../anaconda3/bin), and as such Anaconda does not add its bin folder to your PATH by default.
This is not necessarily "dangerous" per se, it's just not an ideal solution for most people. However, you are the boss of your own system. If you decide this works for your particular workflow, you can just add the export to your script:
export PATH="path/to/anaconda3/bin:$PATH"
This will set the PATH for use in the current shell and sub-processes.
Solution 4: Manually source the conda script (possibly outdated)
As mentioned in this answer, you can also opt to manually source the conda.sh script (keep in mind your conda.sh might be in another directory):
source /opt/anaconda/etc/profile.d/conda.sh
This will essentially run that shell script and add the included functionality to the current shell (e.g the one spawned by subprocess.call).
Keep in mind this answer is quite a bit older (~2013) and may not apply anymore, depending how much conda has changed over the years.
Notes
As I mentioned in the comments, you may want to post some related questions on https://unix.stackexchange.com/. You have an interesting configuration challenge that may be better suited for answers specifically pertaining to Linux, since your issue is sourcing directly from Linux shell behavior.
A common question is "how do I make my python script executable without explicitly calling python on the command line?", and the answer is chmod +x it and then add #!/usr/bin/env python at the start of the script.
That is not the question I'm asking.
What I would like to do is tell bash, or python, or whatever is responsible for file-handling to treat all .py files that have the execute bit set as if they have the shebang at the beginning whether or not they actually do.
I understand that in Windows this can be done, and apparently in Gnome for the use-case where you double-click on a .py script from the GUI. I could have sworn I remembered hearing about an equivalent way of specifying a handler from the shell.
Why I want to know how to do this (if it's actually possible):
Not every system uses shebang and I don't want to clutter up files in a cross-platform project with it.
If I'm submitting a patch to a project I don't own, it's slightly obnoxious for me to put stuff unrelated to the patch into it for my own convenience.
Thanks.
Do you mean binfmt_misc?
binfmt_misc is a capability of the Linux kernel which allows arbitrary executable file formats to be recognized and passed to certain user space applications, such as emulators and virtual machines.
So you want to register an entry to it, so everytime you want to execute a .py file, the kernel will pass it to /usr/bin/python.
You can do it by trying something like this
# load the binfmt_misc module
if [ ! -d /proc/sys/fs/binfmt_misc ]; then
/sbin/modprobe binfmt_misc
fi
if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
fi
echo ':Python:E::py::/usr/bin/python:' > /proc/sys/fs/binfmt_misc/register
If you're using Debian-based distribution, you have to install binfmt-support.
You can add :Python:E::py::/usr/bin/python: to /etc/binfmt.d/python.conf so it's permenent after reboot.
Rio6's answer is correct. Only it is supported on practically no operating systems. You will need binfmt, you can compile it yourself from source at This git address
Yes, I know I can do
python2 cal.py
What I am asking for is a way to execute it on the command line such as:
calpy
and then the command afterwards. I put in in a path and when I write cal.py in the command line:
/usr/bin/cal.py: line 5: print: command not found
I don't want to issue cal.py to run my script, I want it to be issued with calpy
I'm running Arch Linux if that helps, thanks. Sorry for my English.
In order for bash to know to run your script via the Python interpreter, you need to put an appropriate shebang at the start. For example:
#!/usr/bin/python
tells bash to run /usr/bin/python with your script as the first argument. I personally prefer
#!/usr/bin/env python
which is compatible with virtualenv. You also need to ensure that the permissions on your script allow it to be executed:
~$ chmod +x path/to/cal.py
Finally, in order to call cal rather than path/to/cal.py, you need to remove the .py extension and make sure that the directory containing cal is in your command search path. I prefer to add ~/bin to the search path by modifying the $PATH environment variable in ~/.bashrc:
export PATH=$HOME/bin:$PATH
then put my own executables in ~/bin. You could also copy (or symlink) cal to one of the system-wide binary directories (/bin or /usr/bin), but I consider it bad practice to mess with system-wide directories unnecessarily.
Ok, you need a couple of things for achive what you want.
First you have to tell your script "How" is going to execute/interpret it. You can do this writting
#/usr/bin/env python
at the very beggining of the file.
The problem you have is the system is trying to execute the script using bash. And in bash there is no print command.
Second you need give execution privileges to your script. And of course if you want to call your script through the command "calcpy", the script has to be called like that.
Put this (exactly this) as the first line of your script:
#!/usr/bin/env python
I am trying to modify the shell launcher found at "http://inasafe.linfiniti.com/html/id/developer-docs/platform_windows.html" so that I can use it to directly launch any shell I'd like (in my case, I wanna use the default IDLE gui in Python 27 library folder for windows).
My changes didn't bring me to an acceptable result so far. Here is my version of the launcher, where I should change it?
#echo off
SET PyShell=C:\Programmi\Quantum GIS Lisboa
call "%PyShell%"\apps\Python27\Lib\idlelib\PyShell.pyc
#echo off
SET GDAL_DRIVER_PATH=%PyShell%\bin\gdalplugins\1.9
path %PATH%;%PyShell%\apps\qgis\bin
path %PATH%;%PyShell%\apps\grass\grass-6.4.2\lib
path %PATH%;"%PyShell%\apps\Python27\Scripts\"
set PYTHONPATH=%PYTHONPATH%;%PyShell%\apps\qgis\python;
set PYTHONPATH=%PYTHONPATH%;%PyShell%\apps\Python27\Lib\site-packages
set QGIS_PREFIX_PATH=%PyShell%\apps\qgis
start "Quantum GIS Shell" /B "cmd.exe" %*
My OS is Windows XP, the version of Python is 2.7.3, while Qgis is 1.8 (Lisboa).
I am reeeeally new to Python and stuff, so please forgive my big mistakes if there are some (but I'm pretty sure there are).
Finally the solution was int the line where I specify which program to use as shell. In my case, I found bot "Pyshell.pyc" and "idle.pyw". The second seems to be the right to poit at, as everything works fine now.
So, my personal shell launcher looks like this:
#echo off
SET IDLE=C:\PROGRA~1\QUANTU~1
call "%IDLE%"\apps\Python27\Lib\idlelib\idle.pyw
#echo off
SET GDAL_DRIVER_PATH=%IDLE%\bin\gdalplugins\1.9
path %PATH%;%IDLE%\apps\qgis\bin
path %PATH%;%IDLE%\apps\grass\grass-6.4.2\lib
path %PATH%;"%IDLE%\apps\Python27\Scripts\"
set PYTHONPATH=%PYTHONPATH%;%IDLE%\apps\qgis\python;
set PYTHONPATH=%PYTHONPATH%;%IDLE%\apps\Python27\Lib\site-packages
set QGIS_PREFIX_PATH=%IDLE%\apps\qgis
start "Quantum GIS Shell" /B "cmd.exe" %*
Anyway, this was a workaround to set the environment variables to use PyQGIS, as I had difficulties to set them in the "normal" way.
Unfortuntely, I didn't fix my problem, as I'm still getting errors while importing the "qgis.core" module, while using the original shell launcher through cmd.exe it works, but it's not a good IDE though...