Find the default application name for a given file
Question: In Linux, is there a way to ask any xdg services, or gtk services, which
application is the default application for a given file?

I realize that **xdg-open** will in fact, launch the correct application.
However, I want to be able to display the application's name in a context
menu. So that when the user clicks on the menu item, it will then launch xdg-
open, which will launch that app.

On OSX I can use LaunchServices for this:

    
    
    def getDefaultDarwinApplication(path):
        import LaunchServices
        import CoreData
        import urllib
    
        url = CoreData.CFURLRef.URLWithString_("file://"+urllib.quote(path))
        os_status, app_ref, appurl = LaunchServices.LSGetApplicationForURL(url, LaunchServices.kLSRolesAll, None, None)
        if os_status != 0:
            return ""
        apppath = app_ref.as_pathname()
        name = os.path.basename(apppath).replace(".app", "")
        return name
    

The hope is that there is something similar on Linux I can use. A builtin
python module would be best, but even screen scraping would work.


Answer: Use the `xdg-mime` command. It allows you to query for a mimetype, and then
get the program associated, without executing it.

Note that this returns the name of the associated `.desktop` file. Then you
have to locate the actual file and further parse it to get the real name of
the program, even localized in any language you want, path of the binary in
the disk, etc.

Here's the full code:

    
    
    import os
    import subprocess
    import codecs
    import ConfigParser
    
    class XDGError(Exception): pass
    class FileNotFoundError(Exception): pass
    
    def _get_app_paths():
        paths = os.environ.get('XDG_DATA_HOME', 
            os.path.expanduser('~/.local/share/')).split(os.path.pathsep)
        paths.extend(os.environ.get('XDG_DATA_DIRS', 
            '/usr/local/share/:/usr/share/').split(os.path.pathsep))
        return paths
    
    def xdg_query(command, parameter):
        p = subprocess.Popen(['xdg-mime', 'query', command, parameter], 
                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output, errors = p.communicate()
        if p.returncode or errors:
            raise XDGError('xdg-mime returned error code %d: %s' % 
                (p.returncode, errors.strip()))
        return output.strip()
    
    def locate_desktop_file(filename, mode='r', encoding='utf-8', 
            _paths=_get_app_paths()):
        for path in _paths:
            for thispath, dirs, files in os.walk(os.path.join(path, 'applications')):
                if filename not in files:
                    continue
                fullname = os.path.join(thispath, filename)
                try:
                    return codecs.open(fullname, mode, encoding)
                except IOError:
                    pass
        else:
            raise FileNotFoundError(filename)
    
    def get_defaults(filename):
        filetype = xdg_query('filetype', filename)
        desktop_filename = xdg_query('default', filetype)
        with locate_desktop_file(desktop_filename) as desktop_file:
            parser = ConfigParser.ConfigParser()
            parser.readfp(desktop_file, desktop_filename)
        return dict(parser.items(parser.sections()[0]))
    

Example usage:

    
    
    p = get_defaults('index.html')
    print p['name'], p['comment']
    

