Adding context menu option through Python - python

I'm trying to make a small Python script that is executed by clicking an option in a file's context menu. It would execute something like "path_to_script %L", where %L is (I think) the location of the file the user has right-clicked. I know I have to add something to the registry for that option to appear, but _winreg is getting confusing. What do I have to do to add a registry entry (through Python) so my script can be called like that?

I dont know how you can remove from registry (probably manually or _winreg) but you can follow a way like that per your custom python script to registration to windows.
registerOne.reg
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\*\shell\One]
[HKEY_CLASSES_ROOT\*\shell\One\command]
#="python.exe one.py \"%1\""
one.py
def registerScriptToContextMenu ():
# http://support.microsoft.com/kb/310516
cmdLine = 'regedit.exe registerOne.reg'
import os
os.system(cmdLine)
def one_main (*args):
pass

Related

how to run libreoffice python script using scriptforge

I am trying to organize my python project that currently only adds a menu to a libreoffice calc menu bar:
# this file is called AddMenu.py which is located in 'C:\Program Files\LibreOffice\share\Scripts\python'
def create_menu(args=None):
o_doc = CreateScriptService("Document")
o_menu = o_doc.CreateMenu("Test Menu")
o_menu.AddItem("About", command="About")
o_menu.AddItem("Testing",
script="vnd.sun.star.script:AddMenu.py$item_b_listener?language=Python&location=user")
def item_b_listener(args):
bas = CreateScriptService("Basic")
s_args = args.split(",")
msg = f"Menu name: {s_args[0]}\n"
msg += f"Menu item: {s_args[1]}\n"
msg += f"Item ID: {s_args[2]}\n"
msg += f"Item status: {s_args[3]}"
bas.MsgBox(msg)
The menu and buttons are added as expected, and About works fine. However, when I click on the "Test Menu" I get an error:
Library : ScriptForge
Service : Session
Method : ExecutePythonScript
Arguments: [Scope], Script, arg0[, arg1] ...
A serious error has been detected in your code on argument : « Script ».
The requested Python script could not be located in the given libraries and modules.
« Scope » = user
« Script » = AddMenu.py$item_b_listener
THE EXECUTION IS CANCELLED.
Do you want to receive more information about the 'ExecutePythonScript' method ?
Any suggestions?
Follow up question: how do I run a python script when calc starts? Since the menu doesn't persist on restarting calc, I need to run the macro to reinstall it
&location=user
That indicates the LibreOffice user profile directory, for example C:\Users\(your username)\AppData\Roaming\LibreOffice\4\user\Scripts\python.
So either change that part to &location=application or move the script to the user profile directory.
https://help.libreoffice.org/latest/sq/text/sbasic/python/python_locations.html
It looks like the script is unable to locate the item_b_listener function. The script that is trying to call the function item_b_listener is located in a different location than the definition of the function. To resolve this issue, you need to make sure that the script is able to locate the function.
One way to do this is to create a separate Python module (file) containing the item_b_listener function, and then import that module into AddMenu.py.
Regarding your follow-up question, you can run a python script when LibreOffice Calc starts by adding it to the Calc startup macro. To do this, follow these steps:
Go to the Tools menu and select Macros > Organize Macros > Python.
In the Python macro dialog, select your script and click on the Edit button.
In the Python macro editor, add the following code to the global section of the script:
def Main():
# your script code here
Save and close the macro editor.
In the Python macro dialog, click on the Run button to test your script.
To make sure your script runs every time Calc starts, go to Tools > Options > LibreOffice > Advanced and check the box for "Run macro from an autoexec section."
Save the options and restart Calc.
Now, your script should run every time Calc starts.

Python: Passing values from GUI to other python script

I have a python script (we'll say "script.py") that I want to grab values from using a separate GUI python script ("GUI.py"). When I run my GUI.py script, I want to have these text fields in the GUI sent over to script.py after clicking a button in the GUI. I am thinking that my best solution might be to have the GUI.py create another script ("lib.py") that holds all these values and it just writes to it. It then runs the "script.py" script. So all in all the GUI.py will have a function that when called will look something like this:
def on_button(self):
username = self.usernameInput.get()
file = open(“lib.py”,”w”)
file.write(“username = ” + username)
os.system("script.py")
I think this will work, but I am just wondering, does this seem like a practical solution? Let me know what you guys think.
No, I don't think this is the practical solution.
Do you consider instead making the python script you want to run into a module or package that you can call directly inside your GUI? I think that is the cleanest approach. For using your scripts as modules, see the docs or for 2.7.
Basically a module is a python file, script.py, and as long as it is in the python path (say, your current directory), you can import it:
from script import action
So you could try:
def on_button(self):
username = self.usernameInput.get()
result = action(username) # and any other args you want to pass
print(result)
That is, if the script in question uses a if __name__ == "__main__": statement (or can otherwise be run from the command line), try putting the operations in some def action(args): function and importing it into your GUI.

Access a script's variables and functions in interpreter after runtime

So let's say I have a script script1. Is there a way to interact with script1's variables and functions like an interpreter after or during its runtime?
I'm using IDLE and Python 2.7, but I'm wondering if I could do this in any interpreter not just IDLE's.
Say in my script, get = requests.get("example.com"). I'd like to hit F5 or whatever to run my script, and then instead of the console unloading all of the variables from memory, I'd like to be able to access the same get variable.
Is this possible?
That's a serious question. You might need to consult this page:
https://docs.python.org/2/using/cmdline.html#miscellaneous-options
Note the -i option, it makes interpreter enter interactive mode after executing given script.
you can do like this:
#file : foo.py
import requests
def req():
get = requests.get("example.com")
return get
and then run the script from a console
import foo
get = foo.req()

Detect where Python code is running (e.g., in Spyder interpreter vs. IDLE vs. cmd)

Is there a way in Python to detect, within a process, where that process is being executed? I have some code that includes the getpass.getpass() function, which is broken in Spyder, and it's annoying to go back and forth between the command line and the IDE all the time. It would be useful if I could add code like:
if not being run from Spyder:
use getpass
else:
use alternative
Here is the solution I ended up using. After reading Markus's answer, I noticed that Spyder adds half a dozen or so environment variables to os.environ with names like SPYDER_ENCODING, SPYDER_SHELL_ID, etc. Detecting the presence of any of these seems relatively unambiguous, compared to detecting the absence of a variable with as generic a name as 'PYTHONSTARTUP'. The code is simple, and works independently of Spyder's startup script (as far as I can tell):
if any('SPYDER' in name for name in os.environ)
# use alternative
else:
# use getpass
Since the string is at the beginning of each environment variable name, you could also use str.startswith, but it's less flexible, and a little bit slower (I was curious):
>>> import timeit
>>> s = timeit.Timer("[name.startswith('SPYDER') for name in os.environ]", "import os")
>>> i = timeit.Timer("['SPYDER' in name for name in os.environ]", "import os")
>>> s.timeit()
16.18333065883474
>>> i.timeit()
6.156869294143846
The sys.executable method may or may not be useful depending on your installation. I have a couple WinPython installations and a separate Python 2.7 installation, so I was able to check the condition sys.executable.find('WinPy') == -1 to detect a folder name in the path of the executable Spyder uses. Since the warning that shows in IDLE when you try to use getpass is less "loud" than it could be, in my opinion, I ended up also checking the condition sys.executable.find('pythonw.exe') == -1 to make it slightly louder. Using sys.executable only, that method looks like:
if sys.executable.find('pythonw.exe') == sys.executable.find('WinPy') == -1:
# use getpass
else:
# use alternative
But since I want this to work on other machines, and it's much more likely that another user would modify their WinPython installation folder name than that they would rename their IDLE executable, my final code uses sys.executable to detect IDLE and os.environ to detect Spyder, providing a "louder" warning in either case and keeping the code from breaking in the latter.
if any('SPYDER' in name for name in os.environ) \
or 'pythonw.exe' in sys.executable:
password = raw_input('WARNING: PASSWORD WILL BE SHOWN ON SCREEN\n\n' * 3
+ 'Please enter your password: ')
else:
password = getpass.getpass("Please enter your password: ")
By default, Spyder uses a startup scrip, see Preferences -> Console -> Adanced setting. This option is usually set to the scientific_startup.py file that loads pylab et al.
The easiest solution is to just add a global variable to the file and then use that in your if statement, e.g. add this line at the end of scientific_startup.py:
SPYDER_IDE_ACTIVE = True
In your script:
if not 'SPYDER_IDE_ACTIVE' in globals():
use getpass
else:
use alternative
This will work without throwing an error. You can also use exceptions if you like that more.
A second solution would be (if you cannot modify that file for some reason) to just check if the environment variable PYTHONSTARTUP is set. On my machine (using the Anaconda Python stack), it is not set for a regular Python shell. You could do
import os
if not 'PYTHONSTARTUP' in os.environ:
use getpass
else:
use alternative
Spyder provides the option of executing the current editor script in a native system terminal. This would produce identical behavior as if you were running from the command line. To set this up, open the Run Settings dialog by hitting F6. Then select the radio button "Execute in an external System terminal". Now run the script as usual by hitting F5. You should be able to use getpass in the normal fashion with this approach.
You could add env variable when running in Spyder and check it in code.

Open specific file type with Python script?

How can I make a Python script to be a specific file type's (e.g., *.foo) default application? As in, when I double click the file in the Finder / Explorer I want the file to open in the Python script.
Is this possible to do in Win and/or OS X? The application is a PySide app if that matters.
Mac OS X
On Mac OS X you can use Automator to create an application that calls your python app and passes the input file path as a string argument. In the application workflow wizard, add action "Run Shell Script", select Pass input: as as arguments, and in the text box add:
python /path/to/my/app/myapp.py "$#"
The "$#" passes along whatever arguments were in the input (aka the selected file) as strings. As long as your script is set up to deal with the input (sys.argv) as a list of strings (the first one being the python app path), then it will work.
When you save that Automator workflow, it is treated by OS X like any other app, and you can set that app as the default for files of type "*.foo". To associate "*.foo" with that app, right click a .foo file, Get Info, Open with: Other..., choose the app you created in Automator, then click the Change All... button.
Windows
A similar but hopefully less-involved approach might work in Windows. You could probably create a batch file (.bat) with the following:
python C:\path\to\my\app\myapp.py %*
The %* expands to all arguments.
As long as you can associate a file extension with that batch file, then you could do that, and that's your solution. However, I haven't tried this Windows solution, so take it with a grain of salt. The Mac solution, on the other hand, I have tested.
By example, here's a universal solution I wrote for:
1) opening a Windows desktop link (*.URL) that's been copied to a Linux box.
Or
2) opening a Linux .Desktop link that's been copied to a Windows box.
Here's the Python script that handles both cases:
# UseDesktopLink.py
import sys
import webbrowser
script, filename = sys.argv
file_object = open(filename,'r')
for line in file_object:
if line[0:4]=="URL=":
url=line[4:]
webbrowser.open_new(url)
file_object.close()
On Windows, use Scott H's method (via a bat file) to handle the association.
On Linux, right-click a Windows URL file. Choose Properties, and Open With. Click Add to add a new application. Then at the bottom of the "Add Application" window, click "Use a custom command". Then browse to the UseDesktopLink.py file and click Open. But before you click Add, in the textbox below "Use a custom command", put "python " before the filename (without the quotes). Then click Add and Close.
Hope that helps.
Find any file of type foo
right-click -> Get Info or Click on the file icon,then click Get info or click on the file and hit Command+I
In the Open With pane that shows up, select the path to the python binary
Once selected, You can click the change All button
It'll ask for confirmation, just say continue
I found this old question while looking for an answer myself, and I thought I would share my solution. I used a simple c program to direct the arguments to a python script, allowing the python script to stay a script instead of needing to compile it to make things work. Here is my c program:
int main(int argc, char *argv[]){
char cmd[0xFF];
// For me, argv[1] is the location of the file that is being opened. I'm not sure if this is different on other OSes
snprintf(cmd,sizeof cmd,"python YOUR_PYTHON_SCRIPT_HERE.py -a %s", argv[1]);
system(cmd);
return 0;
}
I then compiled the c program and set that as the default application for the file extension.
Then, in the python script YOUR_PYTHON_SCRIPT_HERE.py, I receive the argument like this:
import sys
assert len(sys.argv) > 2 # Breaks if you call the script without the arguments
theFile = " ".join(sys.argv[2:]) # What the c program gives us
print(theFile) # Print it out to prove that it works
theFile will contain the location of the file that is being opened
Get the contents of the file by using:
with open(theFile,"r") as f:
fileContents = f.read()
On Windows:
Right click the file (I used a .docx file for this example)
Select Open with...
From the applications list, select python
Optional: Select the Always use the selected program to open this kind of file.
Note: this will run the contents of the .docx file in context of the python shell. It will immediately close once it is finished evaluating the contents of the file. If you'd like to edit the file in a word processor, perhaps you should download notepad++, and select that application as the default.

Categories

Resources