15

Is there a simple way to lauch the systems default editor from a Python command-line tool, like the webbrowser module?

pkit
  • 7,993
  • 6
  • 36
  • 36
  • Which filetype? For .txt and .py, opening with default application is good enough. For other filetypes, you might not get an editor. – u0b34a0f6ae Sep 18 '09 at 11:34
  • In my case I need to edit .xml and normal text (like commit messag in svn). – pkit Sep 18 '09 at 15:43

5 Answers5

19

Under windows you can simply "execute" the file and the default action will be taken:

os.system('c:/tmp/sample.txt')

For this example a default editor will spawn. Under UNIX there is an environment variable called EDITOR, so you need to use something like:

os.system('%s %s' % (os.getenv('EDITOR'), filename))

Weston Ruter
  • 1,041
  • 1
  • 9
  • 21
user175390
  • 214
  • 1
  • 2
  • 1
    Mac users don't get any love? – Mazyod Mar 02 '14 at 17:24
  • And what if `EDITOR` is unset? – exhuma Jul 14 '15 at 06:38
  • 1
    @exhuma if $EDITOR isn't set then you don't have *user-set* default to work with. On OS X you can `subprocess.call(["open, ""])` to use the default application, just like if you used the GUI. On linux you can `subprocess.call(["xdg-open", ""])` like @u0b34a0f6ae suggested. `suprocess` is used here instead of `system` since `subprocess` is intended to replace `system`. It's more secure and provides methods like `Popen` that provide greater flexibility. – conner.xyz Aug 27 '15 at 22:27
  • What if it's not a .txt file? What if you want to edit a .html file using default editor? – niCk cAMel May 05 '17 at 11:56
  • see my answer https://stackoverflow.com/a/74589184/1497139 for addressing some of the comments – Wolfgang Fahl Nov 27 '22 at 10:22
4

The modern Linux way to open a file is using xdg-open; however it does not guarantee that a text editor will open the file. Using $EDITOR is appropriate if your program is command-line oriented (and your users).

u0b34a0f6ae
  • 48,117
  • 14
  • 92
  • 101
3

If you need to open a file for editing, you could be interested in this question.

Community
  • 1
  • 1
Joril
  • 19,961
  • 13
  • 71
  • 88
  • (This caveat also applies to my answer) If viewer and editor are separate, this opens the viewer in 9/10 cases. Call it on a HTML file and the web browser will open it for *viewing*. – u0b34a0f6ae Sep 18 '09 at 11:32
  • You're right, of course :) Maybe the OP will clarify which filetype she needs to handle.. – Joril Sep 18 '09 at 13:04
2

You can actually use the webbrowser module to do this. All the answers given so far for both this and the linked question are just the same things the webbrowser module does behind the hood.

The ONLY difference is if they have $EDITOR set, which is rare. So perhaps a better flow would be:

editor = os.getenv('EDITOR')
if editor:
    os.system(editor + ' ' + filename)
else:
    webbrowser.open(filename)

OK, now that I’ve told you that, I should let you know that the webbrowser module does state that it does not support this case.

Note that on some platforms, trying to open a filename using this function, may work and start the operating system's associated program. However, this is neither supported nor portable.

So if it doesn't work, don’t submit a bug report. But for most uses, it should work.

Nick Humrich
  • 14,905
  • 8
  • 62
  • 85
0

As the committer of the python Y-Principle generator i had the need to check the generated files against the original and wanted to call a diff-capable editor from python. My search pointed me to this questions and the most upvoted answer had some comments and follow-up issue that i'd also want to address:

  • make sure the EDITOR env variable is used if set
  • make sure things work on MacOS (defaulting to Atom in my case)
  • make sure a text can be opened in a temporary file
  • make sure that if an url is opened the html text is extracted by default

You'll find the solution at editory.py and the test case at test_editor.py in my project's repository.

Test Code

'''
Created on 2022-11-27
@author: wf
'''
from tests.basetest import Basetest
from yprinciple.editor import Editor

class TestEditor(Basetest):
    """
    test opening an editor
    """
    
    def test_Editor(self):
        """
        test the editor
        """
        if not self.inPublicCI():
            # open this source file
            Editor.open(__file__)
            Editor.open("https://stackoverflow.com/questions/1442841/lauch-default-editor-like-webbrowser-module")
            Editor.open_tmp_text("A sample text to be opened in a temporary file")

Screenshot Screenshot of Atom Editor

Source Code

'''
Created on 2022-11-27

@author: wf
'''
from sys import platform
import os
import tempfile
from urllib.request import urlopen
from bs4 import BeautifulSoup

class Editor:
    """
    helper class to open the system defined editor
    
    see https://stackoverflow.com/questions/1442841/lauch-default-editor-like-webbrowser-module
    """
    
    @classmethod
    def extract_text(cls,html_text:str)->str:
        """
        extract the text from the given html_text
        
        Args:
            html_text(str): the input for the html text
            
        Returns:
            str: the plain text 
        """
        soup = BeautifulSoup(html_text, features="html.parser")

        # kill all script and style elements
        for script in soup(["script", "style"]):
            script.extract()    # rip it out
        
        # get text
        text = soup.get_text()
        
        # break into lines and remove leading and trailing space on each
        lines = (line.strip() for line in text.splitlines())
        # break multi-headlines into a line each
        chunks = (phrase.strip() for line in lines for phrase in line.split("  "))
        # drop blank lines
        text = '\n'.join(chunk for chunk in chunks if chunk)
        return text

    @classmethod
    def open(cls,file_source:str,extract_text:bool=True)->str:
        """
        open an editor for the given file_source
        
        Args:
            file_source(str): the path to the file
            extract_text(bool): if True extract the text from html sources
            
        Returns:
            str: the path to the file e.g. a temporary file if the file_source points to an url
        """
        # handle urls
        # https://stackoverflow.com/a/45886824/1497139
        if file_source.startswith("http"):
            url_source = urlopen(file_source)
            #https://stackoverflow.com/a/19156107/1497139
            charset=url_source.headers.get_content_charset()
            # if charset fails here you might want to set it to utf-8 as a default!
            text = url_source.read().decode(charset)
            if extract_text:
                # https://stackoverflow.com/a/24618186/1497139
                text=cls.extract_text(text)
                
            return cls.open_tmp_text(text)
            
        editor_cmd=None
        editor_env=os.getenv('EDITOR')
        if editor_env:
            editor_cmd=editor_env
        if platform == "darwin":
            if not editor_env:
                # https://stackoverflow.com/questions/22390709/how-can-i-open-the-atom-editor-from-the-command-line-in-os-x
                editor_cmd="/usr/local/bin/atom"
        os_cmd=f"{editor_cmd} {file_source}"
        os.system(os_cmd)
        return file_source
        
    @classmethod
    def open_tmp_text(cls,text:str)->str:
        """
        open an editor for the given text in a newly created temporary file
        
        Args:
            text(str): the text to write to a temporary file and then open
        
        Returns:
            str: the path to the temp file
        """
        # see https://stackoverflow.com/a/8577226/1497139
        # https://stackoverflow.com/a/3924253/1497139
        with tempfile.NamedTemporaryFile(delete=False) as tmp:
            with open(tmp.name,"w") as tmp_file:
                tmp_file.write(text)
                tmp_file.close()
            return cls.open(tmp.name)

Stackoverflow answers applied

Wolfgang Fahl
  • 15,016
  • 11
  • 93
  • 186