I have a Python function that I want to run from the context-menu. I am using the Windows Registry to call the function when a file is right clicked, and I want the function to receive the file selected.
The context menu item looks something like the Random Commands option.
The function I wish to run is foo1() in the file test1:
# in script test1.py
def foo1():
import sys
print(sys.argv)
I tried approaching the problem using the python -c switch to directly call the function:
python -c "import test1; test1.foo1()" %1
However, the value of sys.argv after selecting the file and executing is ['-c'], which doesn't include the file selected.
I also tried using an argument parser to dynamically import and run the function:
# in file registry_parser.py
import argparse
import os
import sys
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--func_name')
parser.add_argument('-f', '--file_name')
parser.add_argument('-p', '--file_path')
args = vars(parser.parse_args())
sys.path.insert(0, args['file_path'])
exec(f"import {args['file_name']}")
exec(f"{args['file_name']}.{args['func_name']}(sys.argv)")
And the function I would call from the registry is (paths simplified):
registry_parser.py --func_name foo1 --file_name test1 --file_path "[PATH TO registry_parser.py]" %1
However, I either get an error registry_parser.py: error: unrecognized arguments: %1 or the "%1" is parsed quite literally and ends up as a value in sys.argv.
Any help is appreciated.
So on all the forums I asked I never received a correct answer, but I found this Reddit Post that has an example to a solution. Hope this helps someone else.
Related
I am trying to write multiple files for specific tasks and in the end I would like to be able to use those functionalities in those files by importing them. But in the mean time, I also want to make other files runnable on their own. Therefore, for each file I have added options to them. But when I tried to run main where I imported all of the files, I saw that option parser of a file, overrides the option parser of the main. Code below is showing a similar case.
import optparse
def get_user_input():
parse_object = optparse.OptionParser()
parse_object.add_option("-t","--test",dest="test",help="test")
(user_input,arguments) = parse_object.parse_args()
return user_input
def test_func1():
print("hello")
def test11():
user_input = get_user_input()
test11()
This is the test1.py.
import optparse
import test1
def get_input():
sample = "[sudo] python3 main.py -[option] [argument]"
parse_object = optparse.OptionParser(usage=sample)
parse_object.add_option("-d","--discovery",dest="network_discovery",help="dd.")
parse_object.add_option("-p","--all-ports",dest = "all_ports",help = "pp")
parse_object.add_option("-i","--ip",dest="ip",help="ii.")
parse_object.add_option("-l","--list",dest="ip_list",help="ll")
parse_object.add_option("-o","--output",dest="save_output",help="oo")
parse_object.add_option("-c","--icmp",dest="icmp_scan",help="icmp")
(user_input,arguments) = parse_object.parse_args()
return user_input
user_input = get_input()
And this is the main.py.
I have realized that when I do not test11() in test1.py it does not override which simply means that when I don't call get_user_input(). But when I run main.py with help function the output is as below.
Usage: main.py [options]
Options:
-h, --help show this help message and exit
-t TEST, --test=TEST test
But the expected output is as follows:
Usage: [sudo] python3 main.py -[option] [argument]
Options:
-h, --help show this help message and exit
-d NETWORK_DISCOVERY, --discovery=NETWORK_DISCOVERY
dd.
-p ALL_PORTS, --all-ports=ALL_PORTS
pp
-i IP, --ip=IP ii.
-l IP_LIST, --list=IP_LIST
ll
-o SAVE_OUTPUT, --output=SAVE_OUTPUT
oo
-c ICMP_SCAN, --icmp=ICMP_SCAN
icmp
As I mentioned, this is just an example case. In the real project, I have six files which can be run individually and one main function to run all of them in a specific way and all files have option parser.
So far, I have tried test1.get_user_input = get_input, from test1 import test_func1 to see if I could exclude that call. This is the last stage of the project. So, If you could help me out it will be much appreciated.
I have a script saved as workspace.py
import argparse
import os
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('title', type=str, help="Will be displayed as the title")
parser.add_argument('-f', '--folder', help='Point to the folder you want to read from (defaults to current folder in command prompt)', type=str, default=os.getcwd())
args = parser.parse_args()
print(args)
someFunction(args.folder, args.title)
Which I call from terminal with:
workspace.py myTitle
Resulting in the error
workspace.py: error: the following arguments are required: title
I have no idea why this is happening because I supply "myTitle" in the terminal. If I specify a default= for the title argument it works perfectly with that value. The part that is throwing me is it doesn't even get to the print(args) so I cannot see what the program thinks is what, but instead fails at args = parser.parse_args()
I tried to even redo the exact example at: https://docs.python.org/2/howto/argparse.html#introducing-positional-arguments (copied below)
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo the string you use here")
args = parser.parse_args()
print args.echo
Running
workspace.py hello
Results in (after adding parenthesis to the print for 3.X)
workspace.py: error: the following arguments are required: echo
Is there something I'm missing? Why does it not just print "hello"? Is there some Python 3 specific syntax I'm missing or something?
I've gotten it to work if I run python workspace.py someString instead of workspace.py someString. I do not understand why this version works, since command prompt obviously recognizes it as Python and runs it correctly until args = parser.parse_args(). There were no errors like 'workspace.py' is not recognized as an internal or external command, operable program or batch file. There was no problem importing modules either. Consider the below command prompt session if you are running into a similar error. Maybe you will simply have to include python in your commands like I have to...
C:\Users\rparkhurst\PycharmProjects\Workspace>workspace.py MyTitle
usage: workspace.py [-h] [-f FOLDER] title
workspace.py: error: the following arguments are required: title
C:\Users\rparkhurst\PycharmProjects\Workspace>python workspace.py MyTitle
Namespace(folder='C:\\Users\\rparkhurst\\PycharmProjects\\Workspace', title='MyTitle')
May I know what is the best practice to debug an argpars function.
Say I have a py file test_file.py with the following lines
# Script start
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument(“–output_dir”, type=str, default=”/data/xx”)
args = parser.parse_args()
os.makedirs(args.output_dir)
# Script stop
The above script can be executed from terminal by:
python test_file.py –output_dir data/xx
However, for debugging process, I would like to avoid using terminal. Thus the workaround would be
# other line were commented for debugging process
# Thus, active line are
# Script start
import os
args = {“output_dir”:”data/xx”}
os.makedirs(args.output_dir)
#Script stop
However, I am unable to execute the modified script. May I know what have I miss?
When used as a script, parse_args will produce a Namespace object, which displays as:
argparse.Namespace(output_dir='data/xx')
then
args.output_dir
will be the value of that attribute
In the test you could do one several things:
args = parser.parse_args([....]) # a 'fake' sys.argv[1:] list
args = argparse.Namespace(output_dir= 'mydata')
and use args as before. Or simply call the
os.makedirs('data/xx')
I would recommend organizing the script as:
# Script start
import argparse
import os
# this parser definition could be in a function
parser = argparse.ArgumentParser()
parser.add_argument(“–output_dir”, type=str, default=”/data/xx”)
def main(args):
os.makedirs(args.output_dir)
if __name__=='__main__':
args = parser.parse_args()
main(args)
That way the parse_args step isn't run when the file is imported. Whether you pass the args Namespace to main or pass values like args.output_dir, or a dictionary, etc. is your choice.
You can write it in a shell script to do what you want
bash:
#!/usr/bin/
cd /path/to/my/script.py
python script.py --output_dir data/xx
If that is insufficient, you can store your args in a json config file
configs.json
{"output_dir": "data/xx"}
To grab them:
import json
with open('configs.json', 'rb') as fh:
args = json.loads(fh.read())
output_dir = args.get('output_dir')
# 'data/xx'
Do take note of the double quotes around your keys and values in the json file
I'm trying to parse the command line arguments in a very simple way:
$ python main.py --path /home/me/123
or
$ python main.py --path=/home/me/123
And then:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--path')
args = parser.parse_args()
And args returns nothings:
(Pdb) args
(Pdb) args.path
How can I access the value of --path?
You can print args.path and it will show your line argument. For more details you can check the below link for more details about argparse
Argparse Tutorial
You can also use sys to parse your command line arguments, such as
>>> import sys
>>> path = sys.argv[1] # sys.argv always start at 1
>>> print path
Check the below link for more details.
Python Command Line Arguments
Hope it helps.
It works fine for me...
>>> args
Namespace(path='/home/me/123')
So you can access it via args.path
I have a added .PY files to my System Environment PATHEXT variable on Windows 7. I have also added C:\scripts to my PATH variable.
Consider I have a very simple Python file C:\Scripts\helloscript.py
print "hello"
Now I can call Python scripts from my Console using:
C:\>helloscript
And the output is:
hello
If I change the script to be more dynamic, say take a first name as a second parameter on the Console and print it out along with the salutation:
import sys
print "hello,", sys.argv[1]
The output is:
c:\>helloscript brian
Traceback (most recent call last):
File "C:\Scripts\helloscript.py", line 2, in <module>
print sys.argv[1]
IndexError: list index out of range
sys.argv looks like:
['C:\\Scripts\\helloscript.py']
If I call the script explicitly the way I would normally:
C:\>python C:\Scripts\helloscript.py brian
The output is:
hello, brian
If I try to use optparse the result is similar although I can avoid getting an error:
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-f", "--firstname", action="store", type="string", dest="firstname")
(options, args) = parser.parse_args()
print "hello,", options.firstname
The output is:
hello, None
Again, the script works fine if I call it explicitly.
Here's the question. What's going on? Why doesn't sys.argv get populated with more than just the script name when calling my script implicitly?
It turns out I had to manually edit the registry:
HKEY_CLASSES_ROOT\Applications\python.exe\shell\open\command was:
"C:\Python27\python.exe" "%1"
And should have been:
"C:\Python27\python.exe" "%1" %*