Run external python script from Sublime Text passing active file as argument - python

I have a some python script called spc.py somewhere on the disk, which is for processing text file in some way (and it uses more external libraries). Now I call it from console with passing a filename as argument.
Because I'm running this script often, during the editing the document itself, I would like to be able to call the script straight from the Sublime Text, passing active file as argument, so I can call it by one click without leaving the window.
But I haven't found a way how to call external python script from Sublime Text plugin. Can you give me a clue? Is that even possible?

One of way to doing this is by calling python with arguments through cmd.exe using subprocess module, with sending the file name of active file as argument for python program.
import sublime, sublime_plugin
import subprocess
class ExecuteExternalProgramCommand(sublime_plugin.TextCommand):
def run(self, edit):
exec_file = "C:\Path\To\My\Program\spc.py"
command = ["cmd.exe", "/c", "python", exec_file, self.view.file_name()]
subprocess.Popen(command)
Save it to your Sublime Text User plugins folder and then put keyboard shortcut to your User Keymap, for example
{"keys": ["ctrl+shift+e"], "command": "execute_external_program"},

You can:
Create a custom build system which accepts the current file as an argument.
Create a plugin which executes text from the current file.

You can use the answer provided here to get the file name of the current sublime window. Now beyond that you just need a method that accepts a path as an input argument and from there do what you need to do.
import sublime, sublime_plugin
import re, os, os.path
class OpenrelCommand(sublime_plugin.WindowCommand):
def run(self):
print self.active_view()

Related

open and show any file in python [duplicate]

This question already has answers here:
Open document with default OS application in Python, both in Windows and Mac OS
(17 answers)
Closed 8 years ago.
I'm wondering how to open files in programs such as Notepad and Picture Viewer depending on the extension the file has. I'm using Python 3.3 on Windows.
I've done some research and people have mentioned a module named Image, but when I try and import this module I get an ImportError.
Here's what I have so far:
def openFile():
fileName = listbox_1.get(ACTIVE)
if fileName.endswith(".jpg"):
fileName.open()
I will also have HTML and JSON files that I will need to open in Notepad.
On Windows you could use os.startfile() to open a file using default application:
import os
os.startfile(filename)
There is no shutil.open() that would do it cross-platform. The close approximation is webbrowser.open():
import webbrowser
webbrowser.open(filename)
that might use automatically open command on OS X, os.startfile() on Windows, xdg-open or similar on Linux.
If you want to run a specific application then you could use subprocess module e.g., Popen() allows to start a program without waiting for it to complete:
import subprocess
p = subprocess.Popen(["notepad.exe", fileName])
# ... do other things while notepad is running
returncode = p.wait() # wait for notepad to exit
There are many ways to use the subprocess module to run programs e.g., subprocess.check_call(command) blocks until the command finishes and raises an exception if the command finishes with a nonzero exit code.
Use this to open any file with the default program:
import os
def openFile():
fileName = listbox_1.get(ACTIVE)
os.system("start " + fileName)
If you really want to use a certain program, such as notepad, you can do it like this:
import os
def openFile():
fileName = listbox_1.get(ACTIVE)
os.system("notepad.exe " + fileName)
Also if you need some if checks before opening the file, feel free to add them. This only shows you how to open the file.
Expanding on FatalError's suggestion with an example.
One additional benefit of using subprocessing rather than os.system is that it uses the same syntax cross-platform (os.system on Windows requires a "start" at the beginning, whereas OS X requires an "open". Not a huge deal, but one less thing to remember).
Opening a file with subprocess.call.
All you need to do to launch a program is call subprocess.call() and pass in a list of arguments where the first is the path to the program, and the rest are additional arguments that you want to supply to the program you're launching.
For instance, to launch Notepad.exe
import subprocess
path_to_notepad = 'C:\\Windows\\System32\\notepad.exe'
path_to_file = 'C:\\Users\\Desktop\\hello.txt'
subprocess.call([path_to_notepad, path_to_file])
Passing multiple arguments and paths is equally as simple. Just add additional items to the list.
Launching with multiple arguments
This, for example, launches a JAR file using a specific copy of the Java runtime environment.
import subprocess
import os
current_path = os.getcwd()
subprocess.call([current_path + '/contents/home/bin/java', # Param 1
'-jar', #Param2
current_path + '/Whoo.jar']) #param3
Argument 1 targets the program I want to launch. Argument2 supplies an argument to that program telling it that it's going to run a JAR, and finally Argument3 tells the target program where to find the file to open.

Pass a file to Python via the Right-Click 'Open With' context menu in windows, to then open in another program

I use a piece of software that when you close, saves your current configuration, however, next time I open the software by clicking on a file associated with it, it tries to run that file through the same configuration, which I don't want. I have therefore created a python script to first open up the app data for that program, reset the configuration back to default, and then open the program again.
This works fine if I just try to load the program without a file, but I would like to be able to click on a file associated with that program (usually I can just double click on the file to open it in the program), then use the 'open with' function in windows to select my script, and then open the file in the program once my script has cleared out the last configuration.
Currently, if I do this, it clears the configuration and opens the program but with no file loaded.
Essentially I am asking how I can pass the file to python, and then get python to pass that file to the third party application.
I am using the 'os.startfile('link to .exe') function to open the program, but how do I get the file path into python as an argument/string by clicking on the file and opening it with my script?
path = 'path/to/file/selected' # passed to python from selecting the file in windows explorer before starting script
# execute some code
os.startfile('path')
I'm a bit of a beginner when it comes to python so any help would be appreciated!
Using python 3.6 on windows 10
You can access command line arguments passed to your script using sys.argv. As long as you want to pass these arguments to some third-party application(which is an executable binary) you should use the subprocess module as os.startfile is meant to start a file with its associated application.
import sys
import subprocess
def main():
if len(sys.argv) == 1:
path = sys.argv[0]
subprocess.run(['/path/to/my.exe', path])
else:
print('Usage myscript.py <path>')
if __name__ == "__main__":
main()
If I understand your question correctly it could be done in the following fashion, relying on the subprocess module:
subprocess.Popen(["/path/to/application", "/path/to/file/to/open"])
See documentation for more details.

How to access a file from python when the OS opens the script to handle opening that file?

When I open an HTML file, for instance, I have it set such that it opens in Chrome. Now if I set a given python script to be the thing that opens a given filetype, how do I access this file in the script? Where is it available from?
When opening a file, the operating system starts the responsible opener program and passes the file(s) to be opened as command line arguments:
path/to/opener_executable path/to/file1_to_be_opened path/to/file2_to_be_opened ...
You can access the command line arguments through sys.argv in your python script. A minimal example:
import sys
print("I'm supposed to open the following file(s):")
print('\n'.join(sys.argv[1:]))
To prove Rawing's point, on Linux, you "open with Other Application" and select your python script, which you made executable.
sys.argv provides the name of the script as argument 0 and thereafter a list of any other parameters.
myopener.py
#!/usr/bin/env python
import sys, os
x=os.open('/home/rolf/myopener.output',os.O_RDWR|os.O_CREAT)
xx = os.fdopen(x,'w+')
y=str(sys.argv)
xx.write(y)
xx.close()
Opening the file abc.ddd with myopener.py creates the file myopener.output contents:
['/home/rolf/myopener.py', '/home/rolf/abc.ddd']

How to run a python script that takes command line arguments with a double click

As a personal project to improve my python skills I created a script that retrieves weather data. It takes multiple command line arguments to specify the location and what specific information is wanted.
I'd like to make a second file to run it with specific command line arguments using a double click. I already learned how to make it into an executable/make a second file execute it. However, I don't know how to run it with command line arguments.
Currently my secondary file (wrapper?.. unsure of terminology) looks like this:
#! /usr/bin/env python
import weather
weather.main()
This runs but I don't know how to create command line arguments for it without running from the shell. I'd like to have a simple executable to run the weather for where I am quickly.
Well, you can call a shell process using the os.system or the subprocess module.
os.system takes a string and passes it as a command to a shell.
import os
os.system("ls -1")
Whereas subprocess takes a list of all the arguments (the program itself being the first argument) and passes it as a command.
import subprocess
# Simple command
subprocess.call(['ls', '-1'], shell=True)
Seeing these examples, it's easy to tell that you want the executable program to call either one of these (os.system or subprocess). I recommend using the latter, as it offers more variety.
If you want more information, I suggest you read the review of subprocess on Python Module of the Week..
Add to your wrapper script:
import sys
sys.argv[1:] = ['what', 'ever', 'u', 'want']
before the call to weather.main().

Running python from mel callback with Render command

I need to run a batch render command via terminal, and use the mel callbacks, to run a python module.
The terminal command I'm using is this:
Render -preRender "python(\"import sys\nsys.path.append(\"/Volumes/raid/farm_script/\")\nfrom run_os import Farm\nFarm()\")" "/path/to/scene.mb";
Essentially, the command in the escaped string should be read like this:
import sys
sys.path.append("/Volumes/raid/farm_script/")
from run_os import Farm
Farm()
In Maya's script editor, running the above command in a python tab, does print out data.
Running the exact same script, in a mel tab but wrapped in a python function, also works fine!
In the 'Farm' class located under /Volumes/raid/farm_scripts/run_os.py, I have this tiny little script.
class Farm():
def __init__(self):
self.run()
def run(self, *args):
print "=== TEST ===\n"
Which I'm seeing my print test in the script editor, however running this command, using the MEL callbacks in the batch render terminal, leaves me with an 'unexpected indentation error', after vigorous testing, I've found that it's coming from the from run_os import Farm, so my question is, why does this line create the indentation error, there's no indentation at all as i'm using the \n (newline) flag, unless I'm seriously mistaken!
It's probably because you're asking a shell command to run an argument which includes a newline. Try putting the script into a mel file (in the rendering machine's script dir) and then just sourcing that. Or, failing that, make sure that the rendering machine has the correct sys path by editing your environment vars or setting it in Maya.env.
If things are more complex than that you can do the whole thing from Python by starting up a Maya.standalone and controlling it from the outside. If you go that route you can add a simple server that uses sockets or wsgi1 to accept commands over a network or locally.

Categories