How can I write Nautilus scripts in Python?

I want to write a Nautilus script in Python. Is that possible? If it is possible, how can I do that?

Asked By: DandyWalker

||

Nautilus Scripts

Nautilus scripts can be written in any programming language, including python. You just need to make your python source file executable and copy it to ~/.gnome2/nautilus-scripts in Ubuntu versions prior to 14.04. For Ubuntu 14.04 and newer the directory is different: ~/.local/share/nautilus/scripts

You will also need to add #!/usr/bin/env python as the first line of the file. Note that by default #!/usr/bin/env python points to Python2. If you need Python 3 specifically, use #!/usr/bin/env python3.

Once you have done all this, the script will be accessible from the scripts sub-menu of the right click menu in Nautilus.

nautilus scripts menu

See also:https://help.ubuntu.com/community/NautilusScriptsHowto

Nautilus Extensions

Nautilus extensions have more flexibility than scripts – eg. they can be used to add an item directly to the context menu. There is are python bindings available (python-nautilus).

Visit the web page of this library and view the documentation for more information.

Answered By: dv3500ea

Here is a script template and an extension template.

To restart Nautilus and reload your code, execute nautilus -q && nautilus ~.

Scripts

This will log the environment variables which Nautilus sets for scripts to ~/script.log. It will also log raisable errors (no syntax errors).

myscript.py

#!/usr/bin/python3

import os, logging

logpath = os.path.expanduser('~/script.log')

logging.basicConfig(
    filename=logpath,
    encoding='utf-8',
    level=logging.DEBUG,
    format='%(message)s',
)

def logenv(env):
    logging.debug(os.environ[env].strip())

try:
    logenv('NAUTILUS_SCRIPT_SELECTED_FILE_PATHS')
    logenv('NAUTILUS_SCRIPT_SELECTED_URIS')
    logenv('NAUTILUS_SCRIPT_CURRENT_URI')
    #~ logenv('NAUTILUS_SCRIPT_WINDOW_GEOMETRY')  # seems to be not supported any more.
except:
    from traceback import format_exc as exception_as_string
    logging.debug(exception_as_string())

Put the script into ~/.local/share/nautilus/scripts. Make it executable. Restart Nautilus (see above). Select some files or folders in Nautilus and right click. The script appears under the "Scripts" menu entry.

Extensions

Extensions are a little bit more complex, but one can do more with them, e.g. chained menus are possible.

First install nautilus-python using your package manager.

  • Fedora: sudo dnf install nautilus-python <- can confirm, works
  • Debian: sudo apt install nautilus-python
  • Arch: sudo pacman -Sy python-nautilus

Source

Every extension needs to create a class which extends GObject.GObject and Nautilus.MenuProvider.

myextension.py

#!/usr/bin/python3

import os, logging

logpath = '~/extension.log'

logging.basicConfig(
    filename=os.path.expanduser(logpath),
    encoding='utf-8',
    level=logging.DEBUG,
    format='%(message)s',
)

d = logging.debug

try:

    from gi.repository import Nautilus, GObject

    class MyInspectExtension(GObject.GObject, Nautilus.MenuProvider):

        def __init__(self):
            super().__init__()
            d("extension initialized")

        # Hmm. This gets constantly called.
        def get_file_items(self, entries):
            d("---nInspect selected entries")
            if len(entries) < 1:
                d("nothing selected")
                return []
            item = Nautilus.MenuItem(
                name="MyInspectExtension::inspect_selected_entries",
                label="Inspect selected entries",
                tip=f"Write infos about the `entries` parameter to {logpath}",
            )
            item.connect("activate", inspect, entries)
            return [item]

        # Dito.
        def get_background_items(self, folder):
            logging.debug("---nInspect current folder")
            item = Nautilus.MenuItem(
                name="MyInspectExtension::inspect_current_folder",
                label="Inspect current folder",
                tip=f"write infos about the `folder` parameter to {logpath}",
            )
            item.connect("activate", inspect, [folder])
            return [item]

    def inspect(menu, entries):
        for thing in entries:
            d('---')
            for attrname in dir(thing):
                if attrname.startswith('get_') or attrname.startswith('is_'):
                    attr = getattr(thing, attrname)
                    try:
                        if callable(attr):
                            d(f'{attrname}(): {attr()}')
                        else:
                            d(f'{attrname}: {attr}')
                    except:
                        pass

except:
    from traceback import format_exc
    d(format_exc())

Put the extension script into ~/.local/share/nautilus-python/extensions. (Notice, nautilus-python, not nautilus). Make it executable. Restart Nautilus (see above).

Then, when you right-click on selected files/folders, MyInspectExtension.get_file_items is called, when you right-click on the background, MyInspectExtension.get_background_items is called. Both install their menu entry, and, in this case, forward to inspect.

More extension examples can be found in the nautilus-python repo.

Nautilus seems to constantly reload extensions, every second or so. You can see this in the log, when a Nautilus instance is open. I don’t know why that is so, but it may indicate that one may not install too many and too heavy extensions.

Answered By: Nils Lindemann
Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.