Skip to content

Instantly share code, notes, and snippets.

@abhishek72850
Last active September 5, 2023 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abhishek72850/426a6d63274107ecbf04adeafe845b32 to your computer and use it in GitHub Desktop.
Save abhishek72850/426a6d63274107ecbf04adeafe845b32 to your computer and use it in GitHub Desktop.
Sublime Text 3 plugin files reloader for Python 3.7+ and ST3+

Sublime Text Plugin Files Reloader (on update/rename/delete)

Tested on ST3+ with Python 3.7+

Problem

Sublime text editor loads all plugin related files at once on the start and only reloads if there's any change in the .py files located in the root of plugin directory, and to reload any changes made in the sub modules located somewhere in the nested folder in your plugin then you have to close the application and reopen it to load the changes.

Solution

There are other reloader scripts which basically reloads the given plugin modules stored in the sub-directories and they work very well, for eg these:

But it requires you to put module names in the list to load.

Therefore on the same principle wrote this script which it automatically finds all the nested plugin files your main plugin directory have, it just requires you to give your plugin name.

This also handles the scenario if the file/folder is renamed/deleted which was an edge case for these scripts as mentioned here:

How to?

Now with this script whenever you make any changes in any of the root .py files this will reload all and only your plugin files. so when you hit save on any your root .py files where this reloader is imported it will reload all other files in the plugin directory.

  1. Create reloader.py anywhere in your plugin directory, copy below code into it:

    import importlib, os
    from types import ModuleType
    from typing import Optional
    
    
    def import_sub_module(module_path) -> Optional[ModuleType]:
      """
        :module_path -> In form of "Plugin.foo.bar"
      """
      try:
        return importlib.import_module(module_path)
      except ModuleNotFoundError:
        print(f"Unable to import {module_path}")
        return None
    
    def walk_sub_modules(plugin_name, base_path):
      for dir, _, files in os.walk(base_path):
        parent_module_imported = False
        # If its a root directory
        if plugin_name == os.path.basename(dir):
          parent_module_path = plugin_name
        else:
          # This gives result as Plugin.foo.bar
          parent_module_path = f"{plugin_name}{'.'.join(str(dir).split(plugin_name)[-1].split(os.path.sep))}"
        for file in files:
          file_name, extension = os.path.splitext(file)
          if extension == '.py':
            # Importing once only
            if not parent_module_imported:
              # Only trying to import parent once we know it has .py file
              import_sub_module(parent_module_path)
              parent_module_imported = True
            # Importing .py file
            import_sub_module(f"{parent_module_path}.{file_name}")
    
    def reload(plugin_name):
      plugin = importlib.import_module(plugin_name)
      walk_sub_modules(plugin_name, plugin.__path__[0])
  2. Now import the reloader into your plugin command files located in your root directory of plugin:

    If you have multiple .py files in root then import the reloader in all of them

    # Put this on top of the file
    # 
    # Reloads the submodules
    # For eg. if your folder structure is this
    # /
    #    - src/
    #        - reloader.py
    #    - <main plugin file>.py
    # Then in <main plugin file>.py the import should be like this:
    #   from .src import reloader
    from <your_path_to_reloader_file> import reloader
    import importlib
    # Optional: this reloads the reloader, if there's any change
    importlib.reload(reloader)
    # Plugin should match exactly how its shown in sublime text
    reloader.reload("<Your Plugin Name>") # for eg. reloader.reload("GitGutter")
    
    
    # 
    # <your rest of the plugin code goes here...>
    # 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment