How do you pass a value from VBA to python - python

I have a VBA toolbar that i have been working on. It has two buttons, and near the end of the process, it calls a python script.
What I want to do is depending on which of the two buttons is clicked, a certain part of the python script will run, so I want to pass a value that is linked to the button which is then sent to the python script and run.
How do I do this?
Thanks

You can pass command line options to the python script, just like you can with other command line programs. Depending on which button was pressed, pass different switches to your program.
In your case, it may be simplest just to pass in one value on the command line depending on the button that was pressed and pick this from the sys.argv variable:
import sys
def fooClicked():
# Stuff to do when Foo was clicked
def barClicked():
# Stuff to do when Bar was clicked
button = sys.argv[1]
if button == 'foo':
fooClicked()
elif button == 'bar':
barClicked()
(You could use a dict to look up methods but that may be too advanced, don't know how comfortable you are with Python).
So, if you call this script with python.exe H:\Report_v7.py foo the fooClicked function will be called.
If this is going to grow to more than just two buttons, I'd use the optparse module to define your options and run different code paths depending on the options chosen.
If you upgrade to Python 2.7, then use the new (better) argparse module instead.

Related

Invoking another command and getting user input from prompt

I'm trying to build an interactive menu using py-click. Basically just a structure that:
Lists the available commands from the current menu (using a click group)
Present user with a command that prompts for his selection (users enters a # / cmd name)
Invoke the command from within that selection menu
Those command could lead to either another menu or execute application code
Then return to main menu/previous menu as relevant once the code has run
My code:
import click
#click.group(invoke_without_command=True)
#click.pass_context
def main_group(ctx):
""" Lists all the submenu options available"""
cmds = main_group.list_commands(ctx)
click.echo(f"Available options:")
for idx, cmd_str in enumerate(cmds):
click.echo(f"{idx}:{cmd_str}")
click.echo(f"Now that you know all the options, let's make a selection:")
ctx.invoke(main_group.get_command(ctx, "selection"))
#main_group.command()
#click.option('--next_cmd', prompt='Next command:', help="Enter the number corresponding to the desired command")
#click.pass_context
def selection(ctx, next_cmd):
click.echo(f"You've selected {next_cmd}")
# check that selection is valid
# invoke the desired command
# return to parent previous command
#main_group.command()
def submenu_1():
click.echo('A submenu option ')
#main_group.command()
def submenu_2():
click.echo('Another option')
if __name__ == '__main__':
main_group()
However, the output from the above is:
Available options:
0:application-code
1:selection
2:submenu-1
3:submenu-2
Now that you know all the options, let's make a selection:
You've selected None
Process finished with exit code 0
Basically, the prompt from the selection command has no effect. But the selection command itself works, because if I run it directly:
if __name__ == '__main__':
# main_group()
selection()
then I am actually prompted for my selection. So... why is the prompt being ignored? Or is the basic premise behind my approach to building this the issue, e.g. Click isn't meant for that?
EDIT:
Going through a bunch of git repo that uses this library, including the examples they provide, I haven't been able to find any that build a structure somewhat similar to what I want. Basically the paradigm of building a click-application seems to be isolated command that perform action that modify the state of something, not so much a navigation through a menu offering different options. Not to say it's impossible, but it doesn't seem to be supported out of the box either.
No answers given to this question. I've spent some more time on this. I've made a little bit of progress on this but I am still not able to have something such as:
Main Menu
- Option 1
- Option 2
- Option 3
- Submenu 1
and then
Submenu 1
- Option 1
- Option 2
- Submenu 2
- Back to Main
etc. My conclusion is that click isn't the right tool to use for that. In fact, I'm not sure the alternative would necessarily make it much easier either (argparse, docopt, ...). Maybe to do that the best approach would be to just build a class structure yourself.
Or then, go with an approach that's closer to what the shell or docker use, don't bother with any menu navigation and just launch atomic commands that act on the state of the application.

Merge arguments and options of multiple Click commands under a single CLI command

Is there a way to group multiple commands, each with their own different parameters under a single function.
At first glance, a MultiCommand or Group might seem like a natural way of doing what I'd like, i.e. have a single main command act as the Group (and pass the invoke_without_command=True flag) then nest auxiliary Commands beneath it as subcommands. However this doesn't quite have the behavior that I'd want, since I'd like all the options from all commands to be able to be specified without explicitly invoking a subcommand. Additionally, using a Group would also not display the help text of the subcommands without invoking the subcommand on the command line as well.
I guess what I'd ideally like to have is a way to group multiple commands together without the nesting inherent to Click's Group API.
Sorry if this question might be somewhat general. Any help, ideas or tips that can point me in the right direction would be much appreciated.
Here's an outline of what I'd like (file name: cli_test.py):
import click
#click.command()
#click.option('--db-file', type=click.File(mode='r'))
def db_reader(db_file):
click.echo(db_file)
#click.command()
#click.option('--xval', type=float)
#click.option('--yval', type=float)
def get_vals(xval, yval):
return xval, yval
#click.command()
#click.option('--absolutize/--no-absolutize')
def flagger(absolutize):
click.echo(absolutize)
#click.command()
def cli_runner():
db = db_reader.main(standalone_mode=False)
vals = flagger.main(standalone_mode=False)
flag = flagger.main(standalone_mode=False)
if __name__ == '__main__':
cli_runner()
Essentially, I'd like a single command that can be run on the CLI (cli_runner in the above example), which would be able to take the parameters of all Click commands called within it, and then dispatch the processing of them to the appropriate Command instance. However as it stands right now, if I were to invoke on the CLI: $ python cli_test.py --xval 4 I'd get the error Error: no such option: --xval. I have also tried playing around with the pass_context and then ctx.invoke() approach, but the same problem exists.
I suppose I could pass parameters from all contained commands into cli_runner, but that would defeat the purpose of what I want to do, which is to ultimately have 3-4 modular "subcommands", that can then be grouped together in different combinations into larger interfaces that serve slightly different use cases.

Calling functions without making the script launch

The title isnt very accurate i think
Here are my script at the right
Screenshot
It's a bot to automatize some actions. Now i want to add some gui to it but i dont know how.
Like you see at the left, i have " import questions" but cuz of it when I launch the tkinter file, it automatically launches the questions without taking my openBtn code into account.
How can I add gui to each command of my questions.py?
You need to break your questions.py script into actual functions . Python will simply execute all actions in questions.py when the namespace is imported before it reaches the logic below the import statements in testkinter.py.
So in questions.py remove your while True: statements in favor of function definitions like:
def check_database(param):
database check logic here
Then link the functions defined in questions.py to Tkinter button actions in testkinter.py like this:
w = tkinter.Button( fenetre, command=check_database )

How do I keep my code open in the shell with a pass command in the main() function?

I'm trying to learn how to build a web browser bot as half learning half project for someone else and I've hit a snag.
The site I'm using as guide has:
def main():
pass
Which he claims keeps the shell window open do he can run various functions like get x,y cords of the mouse position and take screen shots.
However when I run my code exactly as he has it in the guide it immediately opens and closes.
What I don't want is something like, "make it so pressing enter closes shell instead", what needs to happen is the window stays open so I can enter various functions.
What am I doing wrong? Am I suppose to just import the code in a different shell and run the functions outside it?
The code:
import os
import time
import ImageGrab
x_pad = 0
y_pad = 61
def screenGrab():
box = (x_pad,y_pad,x_pad+1919,y_pad+970)
im = ImageGrab.grab(box)
im.save(os.getcwd() + '\\full_snap__' + str(int(time.time())) + '.png','PNG')
def main():
pass
if __name__ == '__main__':
main()
The guide is: http://code.tutsplus.com/tutorials/how-to-build-a-python-bot-that-can-play-web-games--active-11117
You have three ways:
Start the intepreter with the -i option, as suggested by Ulrich in the comments:
python -i my-script.py
This way, the interpreter will be left open as soon as your script finishes execution and a prompt will be shown.
Use pdb. This is often used for debugging, and has a different interface than the usual Python prompt. If you're not familiar with it, it might not be the best option in your case. Replace pass with these two lines:
import pdb
pdb.set_trace()
Use code. This will give you an interface much more similar to the usual Python shell and can be an alternative to pdb if you're not familiar with it:
import code
code.interact()
By the way, you were not doing anything wrong per se. The pass statement is not meant to "halt Python and start a prompt", it's just needed as a filler for functions or loops with an empty body.

Passing command Line argument to Python script within Eclipse(Pydev)

I am new to Python & Eclipse, and having some difficulties understanding how to pass command line argument to script running within Eclipse(Pydev).
The following link explains how to pass command line argument to python script.
To pass command line argument to module argecho.py(code from link above),
#argecho.py
import sys
for arg in sys.argv: 1
print arg
I would need to type into python console
[you#localhost py]$ python argecho.py
argecho.py
or
[you#localhost py]$ python argecho.py abc def
argecho.py
abc
def
How would I pass same arguments to Python script within Eclipse(Pydev) ???
Thanks !
Click on the play button down arrow in the tool bar -> run configurations -> (double click) Python Run -> Arguments tab on the right hand side.
From there you can fill out the Program Arguments text box:
If you want your program to ask for arguments interactively, then they cease to be commandline arguments, as such. However you could do it something like this (for debugging only!), which will allow you to interactively enter values that the program will see as command line arguments.
import sys
sys.argv = raw_input('Enter command line arguments: ').split()
#Rest of the program here
Note that Andrew's way of doing things is much better. Also, if you are using python 3.*, it should be input instead of raw_input,
Select "Properties" -->> "Run/Debug Settings".
Select the related file in right panel and then click on "Edit" button. It will open properties of selected file. There's an "Arguments" tab.
Years later, and not Eclipse,
but a variant of other answers to run my.py M=11 N=None ... in sh or IPython:
import sys
# parameters --
M = 10
N = 20
...
# to change these params in sh or ipython, run this.py M=11 N=None ...
for arg in sys.argv[1:]:
exec( arg )
...
myfunc( M, N ... )
See One-line-arg-parse-for-flexible-testing-in-python
under gist.github.com/denis-bz .
What I do is:
Open the project in debug perspective.
In the console, whenever the debugger breaks at breakpoint, you can type python command in the "console" and hit return (or enter).
There is no ">>" symbol, so it is hard to discover.
But I wonder why eclipse doesn't have a python shell :(

Categories