How to create Makefile in Python - python

I have never made a Makefile for Python before and I am struggling to figure it out. I found some sample code online and tried to apply it to my code but it is not working. If I wanted to run the program in command line I would do this: python cryptBreak.py encrypted.txt plain.txt.
Here is what I got for the Makefile so far:
PY=python2
MAIN=main
DIR=$(PWD)
.SUFFIXES: .py
FILES = \
cryptBreak.py encrypted.txt plain.txt
All:
echo " $(PY) $(DIR)/$(FILES) " \"'$$1'\" > cryptBreak
chmod 777 cryptBreak.py

You haven't explained why you need a makefile. But if you just want to have a makefile that will run the command you listed, you just have to put the command in a recipe. There's no need for all that other stuff.
all:
python cryptBreak.py encrypted.txt plain.txt
That's it. Now, in your makefile you seem to show that want to run python2, not python. If you want to do that and make a variable to hold it then you can use:
PY := python2
all:
$(PY) cryptBreak.py encrypted.txt plain.txt
If you need your makefile to do other things or have other requirements, we can't help if you don't specify them in your question.

Related

Check for python3 presence inside the script

In python the first line of the script should be
#!/usr/bin/env/python{3}
Is there a way to do:
if python:
#!/usr/bin/env/python
else:
#!/usr/bin/env/python3
EDIT:
Running python in RHEL7 bring up python-2.7.5 (default).
Only running python3 will execute python3-3.6.8 on my RHEL7.
I can't say I recommend this at all, but it does work:
#!/bin/bash
_=""""
if [[ -x '/usr/bin/python3' ]]
then
exec /usr/bin/python3 "$0" "$#"
elif [[ -x '/usr/bin/python' ]]
then
exec /usr/bin/python "$0" "$#"
else
echo "No python available"
exit 1
fi
"""
import sys
sys.stdout.write("you made it\n")
Can't do from __future__ import print_function because it has to be the first line of python.
Principles here are to use bash to do the executable detection but also make it valid python so you can just re-execute with the python interpreter on the same file.
None of those are correct. The correct command is /usr/bin/env and the argument to that, after a space, is the name of the actual interpreter you want it to look up.
Your question is a bit of a "turtles all the way down" problem. You have to know what command you want to run. You could of course create yet another tool and call it something like py3orpy but then you need to know that that exists in the PATH before you try to ask env to find it.
I would expect us to eventually converge on python; if you can't rely on that, perhaps the least error-prone solution is to figure out what's correct for the target system at installation time, and have the installer write a correct shebang. Or just install a symlink /usr/local/bin/python3 if it doesn't exist already, and hardcode #!/usr/bin/env python3 everywhere.

command not found when using makefile to run batch file on Windows 10

When I try to run a makefile (type "make test" in terminal) which runs a batch file I get the equivalent error:
cd directory_path && test.bat
/bin/sh: test.bat: command not found
make: *** [makefile:58: test] Error 127
The makefile is:
.PHONY: test
test:
cd directory_path && test.bat
python path/test.py
(I changed names of the batch file, the directory path, etc. to try and make things more generic)
I can manually type "cd directory_path" and then "test.bat" and those both work. This makefile works on other systems. It only doesn't work on mine. I think it is an issue with how I installed Cygwin and how I run "make.exe".
I can use make to compile C code, but I also get an error trying to use make to run python scripts. The makefile from before also has a command for python path/test.py. This also isn't working on my system. If I delete the batch file line, but keep the python command it throws the error:
python path/test.py
make: python: No such file or directory
make: *** [makefile:59: test] Error 127.
I don't understand why it throws the error of no such file or directory since the path leads to the file, and if i put the python script in the same working directory as the makefile then it still can't find it.
Any ideas/solutions on these problems? Thank you!
EDIT:
Doug Henderson:
I started a cmd prompt at the place with the make file and entered all of these commands in
uname -a
CYGWIN_NT-10.0 james-mobl2 3.1.6(0.340/5/3) 2020-07-09 08:20 x86_64 Cygwin
which make
/usr/bin/make
make -v
GNU Make 4.3
Built for x86_64-pc-cygwin
Copyright (C) 1988-2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
which python
which: no python in
(/cygdrive/c/Program Files/AdoptOpenJDK/jdk-8.0.252.09-hotspot/bin:
/cygdrive/c/windows/system32:
/cygdrive/c/windows:
/cygdrive/c/windows/System32/Wbem:
/cygdrive/c/windows/System32/WindowsPowerShell/v1.0:
/cygdrive/c/windows/System32/OpenSSH:
/cygdrive/c/Program Files/Git/cmd:
/cygdrive/c/Users/james/AppData/Local/Microsoft/WindowsApps/python:
/cygdrive/c/Program Files/PuTTY:
/usr/bin:
/cygdrive/c/Program Files/AdoptOpenJDK/jdk-8.0.252.09 hotspot/bin:
/cygdrive/c/Users/james/AppData/Local/Microsoft/WindowsApps)
(I cleaned up the output a little to make it more legible). This and which test.bat are the only commands that failed.
python -V
Python 3.8.5
The change directory changed correctly
which test.bat
which: no test.bat in
(/cygdrive/c/Program Files/AdoptOpenJDK/jdk-8.0.252.09-hotspot/bin:
/cygdrive/c/windows/system32:
/cygdrive/c/windows:
/cygdrive/c/windows/System32/Wbem:
/cygdrive/c/windows/System32/WindowsPowerShell/v1.0:
/cygdrive/c/windows/System32/OpenSSH:
/cygdrive/c/Program Files/Git/cmd:
/cygdrive/c/Users/james/AppData/Local/Microsoft/WindowsApps/python:
/cygdrive/c/Program Files/PuTTY:
/usr/bin:
/cygdrive/c/Program Files/AdoptOpenJDK/jdk-8.0.252.09 hotspot/bin:
/cygdrive/c/Users/james/AppData/Local/Microsoft/WindowsApps)
I added cmd /c test.bat to the makefile and it worked, but I've also had the batch file run on different systems without that addition. I also have a lot batch files in the actual makefile so this solution works but isn't ideal. It also didn't fix the python script not running.
I didn't initially have cmd.exe in my path, but I added it before entering those commands.
I'm not sure what you mean by starting my PATH in bash with /usr/bin;/bin;THE_REST
MadScientist:
I was manually entering it into a Windows Terminal. Is it possible to have Cygwin invoke a Windows command.com shell?
What I did was go to directory that contained the makefile. Open a windows terminal by typing 'cmd' in the address bar. I would then type 'make test'. That obviously led to the issues. I then went through and manually entered the commands I thought the makefile was supposed to invoke. So I entered 'cd directory_path && test.bat'. This ran.
Matzeri:
I don't really know. I'm completely new to POSIX, etc. I'm guessing I'm using Windows style, and judging from other responses, I'm trying to use Cygwin to do a non-POSIX style.
Thank you, everyone for responses!
Make sure cygwin is installed with basic packages --> Some basic packages not installed with cygwin try below link to install some basic package, uninstall the cygwin and install it again with following basic package :
https://wiki.usask.ca/display/MESH/Running+Python+from+the+Cygwin+Terminal#RunningPythonfromtheCygwinTerminal-Cygwin
make sure cygwin's bin folder is added to your environment variable (e.g., C:\cygwin64\bin)
If cmd /c test.bat works then . is probably not in your PATH. Always do ./test.bat when you want to run something in the current directory. Never count on the PATH unless you have set it yourself. Also make sure the file is executable. chmod +x test.bat

Sending CMD command prompts using Subprocess (Python)

This is a beginner level question for anyone pro in subprocess.
In Windows, is it possible for me to send the following CMD commands using subprocesssuch that they are executed one after another in a single shell:
cd C:\Users\User\myvirtualenvs\project1
Scripts\activate.bat
Hello.py
Effectively, I am trying to load the Virtualenv without having to manually myself touch CMD prompt.
Thanks in advance :)
Just like mentioned in the Comment with &&:
from subprocess import call
call(r'cd C:\ && echo 123 && dir', shell=True)
Please notice the shell=True argument.
Edit due to comment:
Shell=True is an security issue, if you're passing raw input values to the call. See this example from the docs:
from subprocess import call
filename = input("What file would you like to display?\n")
>>> What file would you like to display?
>>> non_existent; rm -rf / #
call("cat " + filename, shell=True) # Uh-oh. This will end badly...
In initially thought you want to make a small script for personal purposes. If you want to give this code away, think about packaging your code via distutils or setuptools.

Write a makefile with one rule for many targets?

It may seem as a very simple question, but I could not find any way to fix it.
My intention is to convert every ".ui" file into a ".py" file by invoking the pyuic4 command (from PyQt). I tried to manage this with a very short makefile:
%.py: %.ui
pyuic4 $< --output $#
That's all I need at the moment.
The makefile is named "Makefile" and located in the folder where "make" is invoked from, and so are the ".ui" files. "pyuic4(.bat)" is in the system's path (Windows 7), and so are the Unix Utilities where "make" is part of.
When running "make" from the Windows console, it says:
make: *** No targets. Stop.
Invoking pyuic4 from the command line with explicit file names works.
I know I could specify any target file by its own, but if possible I want to avoid this.
Any ideas?
As per kasterma's comment, you need to tell make which target to build, but you've only provided a pattern rule. This can be done in the following way.
UIFILES := $(wildcard *.ui)
PYFILES := $(UIFILES:.ui=.py)
.PHONY: all
all: $(PYFILES)
%.py: %.ui
pyuic4 $< --output $#
As you are obviously using a GNU Makefile syntax, I would advise you to write your rule like this:
UIFILES = $(wildcard *.ui)
.PHONY: ui2py
ui2py: $(UIFILES)
#for uifile in $(UIFILES); do \
pyuic4 $$(uifile) --output $${uifile%.ui}.py; \
done
Although the problem could be solved by either perror's or eriktous' solution, I'm now going the third way as mentioned by eriktous by simply invoking the pyuic4 command with a shell script. It's running quite fast and even if the output will result in identical files, no harm will be done for the source code control.
I encountered a second point, which may have distracted me. The pyuic4 command is really named pyuic4.bat, which is a "batch file" in Windows, similar to shell scripts in a Linux/Unix environment; similar, but not identical. If a batch file is invoked from another batch file it should be invoked with a leading "call" statement to prevent termination of the batch after the first invocation.
If I have three files (the # sign is to prevent the command from being listed during execution)
D:\Projekte\test>type main.cmd
#sub1
#sub2
D:\Projekte\test>type sub1.cmd
#echo This is sub 1
D:\Projekte\test>type sub2.cmd
#echo This is sub 2
... the result is just
D:\Projekte\test>main
This is sub 1
So my "solution" for this very small thing is a simple batch file called "update.cmd", which may be expanded by copies of this line:
call pyuic4 mainwindow.ui --output mainwindow.py
That's not what I initially wanted, but it works for me.
But anyway, thanks for your help :-)

How do I install a script to run anywhere from the command line?

If I have a basic Python script, with it's hashbang and what-not in place, so that from the terminal on Linux I can run
/path/to/file/MyScript [args]
without executing through the interpreter or any file extensions, and it will execute the program.
So would I install this script so that I can type simply
MyScript [args]
anywhere in the system and it will run? Can this be implemented for all users on the system, or must it be redone for each one? Do I simply place the script in a specific directory, or are other things necessary?
The best place to put things like this is /usr/local/bin.
This is the normal place to put custom installed binaries, and should be early in your PATH.
Simply copy the script there (probably using sudo), and it should work for any user.
Walkthrough of making a python script available anywhere:
Make a python script:
cd /home/el/bin
touch stuff.py
chmod +x stuff.py
Find out where your python is:
which python
/usr/bin/python
Put this code in there:
#!/usr/bin/python
print "hi"
Run in it the same directory:
python stuff.py
Go up a directory and it's not available:
cd ..
stuff.py
-bash: stuff.py: command not found
Not found! It's as we expect, add the file path of the python file to the $PATH
vi ~/.bashrc
Add the file:
export PATH=$PATH:/home/el/bin
Save it out, re apply the .bashrc, and retry
source ~/.bashrc
Try again:
cd /home/el
stuff.py
Prints:
hi
The trick is that the bash shell knows the language of the file via the shebang.
you can also use setuptools (https://pypi.org/project/setuptools/)
your script will be:
def hi():
print("hi")
(suppose the file name is hello.py)
also add __init__.py file next to your script (with nothing in it).
add setup.py script, with the content:
#!/usr/bin/env python3
import setuptools
install_requires = [
'WHATEVER PACKAGES YOU NEED GOES HERE'
]
setuptools.setup(
name="some_utils",
version="1.1",
packages=setuptools.find_packages(),
install_requires=install_requires,
entry_points={
'console_scripts': [
'cool_script = hello:hi',
],
},
include_package_data=True,
)
you can now run python setup.py develop in this folder
then from anywhere, run cool_script and your script will run.
Just create ~/bin and put export PATH=$PATH:$HOME/bin in your bashrc/profile. Don't mess with the system, it will bite you back, trust me.
Few more things (relevant to the question but not part of the answer):
The other way export PATH=$HOME/bin:$PATH is NOT safe, for bash will will look into your ~/bin folder for executables, and if their name matches with other executables in your original $PATH you will be surprised by unexpected/non working command execution.
Don't forget to chmod+x when you save your script in ~/bin.
Be aware of what you are putting in your ~/bin folder, if you are just testing something or working on unfinished script, its always better to use ./$SCRIPT_NAME from your CWD to execute the script than putting it under ~/bin.
The quick answer is to symlink your script to any directory included in your system $PATH.
The long answer is described below with a walk through example, (this is what I normally do):
a) Create the script e.g. $HOME/Desktop/myscript.py:
#!/usr/bin/python
print("Hello Pythonista!")
b) Change the permission of the script file to make it executable:
$ chmod +x myscript.py
c) Add a customized directory to the $PATH (see why in the notes below) to use it for the user's scripts:
$ export PATH="$PATH:$HOME/bin"
d) Create a symbolic link to the script as follows:
$ ln -s $HOME/Desktop/myscript.py $HOME/bin/hello
Notice that hello (can be anything) is the name of the command that you will use to invoke your script.
Note:
i) The reason to use $HOME/bin instead of the /usr/local/bin is to separate the local scripts from those of other users (if you wish to) and other installed stuff.
ii) To create a symlink you should use the complete correct path, i.e.
$HOME/bin GOOD ~/bin NO GOOD!
Here is a complete example:
$ pwd
~/Desktop
$ cat > myscript.py << EOF
> #!/usr/bin/python
> print("Hello Pythonista!")
> EOF
$ export PATH="$PATH:$HOME/bin"
$ ln -s $HOME/Desktop/myscript.py $HOME/bin/hello
$ chmod +x myscript.py
$ hello
Hello Pythonista!
Just create symbolic link to your script in /usr/local/bin/:
sudo ln -s /path/to/your/script.py /usr/local/bin/script
Putting the script somewhere in the PATH (like /usr/local/bin) is a good solution, but this forces all the users of your system to use/see your script.
Adding an alias in /etc/profile could be a way to do what you want allowing the users of your system to undo this using the unalias command. The line to be added would be:
alias MyScript=/path/to/file/MyScript
i find a simple alias in my ~/.bash_profile or ~/.zshrc is the easiest:
alias myscript="python path/to/my/script.py"
Type echo $PATH in a shell. Those are the directories searched when you type command, so put it in one of those.
Edit: Apparently don't use /usr/bin, use /usr/local/bin
Acording to FHS, the /usr/local/bin/ is the good place for custom scripts.
I prefer to make them 755 root:root, after copying them there.

Categories

Resources