Sublime Forum

Is it possible to call a function from a plugin from within another plugin?

#1

I guess the title is pretty self-explanatory. Say that I have plugins A and B with .py files named A.py and B.py respectively. In plugin A I have this function:

def say_hello():
    print("123")

Now in plugin B, I would like at some point to be able to do something like this:

if len(sublime.find_resources("A.py")) > 0:
    from A import say_hello
    say_hello()
else:
    print("456")

I get a runtime error like this:

ImportError: cannot import name say_hello

Is there a way to do something like this?

0 Likes

#2

In your plugin B.py, the import statement needs to be from .A import say_hello, which means, import the function say_hello from the file A.py present in the current directory. With that small change, I think it should work.

0 Likes

#3

I tried your change, I get this error:

ImportError: No module named 'B.A'

Fyi, directory structure is like this:

Packages
    A
        A.py
        Default.sublime-keymap
    B
        B.py
        Default.sublime-keymap
0 Likes

#4

Your original question was lacking the detail that the plugins in question are a part of different packages, which changes how you do the import.

A relative import like from .A import something is what you’d use if something is in a file named A.py that sits alongside whatever the current file is.

In order to import from a module that’s in another package, you need to qualify it with the package name as well; for example, in Package A, you can import something from package B by saying from B.B import something.

Just for clarity here (since both the package and plugins have the same names in your example), here’s another example that shows how you can import the class that represents the internal exec command to subclass it to get your own version of the exec command that you can augment with extra functionality:

import sublime
import sublime_plugin


from Default.exec import ExecCommand

class MyExecCommand(ExecCommand):
    pass

The ExecCommand class lives in the exec.py file in the Default package.

0 Likes

#5

To confirm:

from A.A import say_hello

did work! Thank you both.

(Btw, I’m afraid I don’t quite understand the distinction between “package name” and “plugin name”. Isn’t the name of the folder containing the .py file(s) for the plugin both the “package name” and the “plugin name”?)

0 Likes

#6

As far as I understand, any folder in the Packages directory is a package (Sublime will load all the .py files at the root of any folder in Packages as well as any .py file in Packages). Also packages as I understand are non trivial plugins with a lot of functionality. Whereas plugins might be simple single .py files meant for executing a single piece of functionality (which is usually stored in the Users directory). Of course, anyone is free to correct me if this is wrong :wink:

0 Likes

#7

I think technically speaking, a Package is more akin to a collection of files that are grouped together, but those files can be anything. Here the collection can be the content of a folder in the Packages folder as well as the contents of a sublime-package file (and both of those at the same time, as well).

The logical distinction between the two of them is that a package is a collection of files, both Sublime resource files (like syntaxes, snippets, menu extensions, plugins etc) as well as any other files desired, while plugins are specifically “plugging in” to Sublime to provide additional commands and event based functionality.

For example, it’s possible for a package to contain only a syntax definition for a new language, or a syntax and some snippets to make working with it easier, or even just snippets for a particular purposes. Such a package doesn’t have any plugin’s in it, though.

The API reference talks about the lifecycle of a plugin:

At importing time, plugins may not call any API functions, with the exception of sublime.version(), sublime.platform(), sublime.architecture() and sublime.channel().

If a plugin defines a module level function plugin_loaded(), this will be called when the API is ready to use. Plugins may also define plugin_unloaded(), to get notified just before the plugin is unloaded.

The only types of package resources that can contain a module level function like plugin_loaded() is a .py file, and specifically only one in the root of a package.

1 Like