randy3k / AutomaticPackageReloader

Automatically reload submodules while developing a Sublime Text package.
MIT License
38 stars 13 forks source link

Get package modules #21

Closed Thom1729 closed 5 years ago

Thom1729 commented 6 years ago

When reload_package tries to find all modules belonging to the package Foo, it finds all modules in sys.modules whose name equals Foo or starts with Foo.. This works perfectly most of the time, but it could fail if Foo adds a subdirectory to sys.path and imports modules from that subdirectory whose names don't begin with Foo..

Consider the following case:

TestPackage/
    test.py
    foo_constant.py
    bar/
        bar_constant.py

test.py:

import sublime
import os.path
import sys

def plugin_loaded():
    sys.path.append(
        os.path.join(sublime.packages_path(), 'TestPackage', 'bar')
    )

    global FOO
    global BAR
    from .foo_constant import FOO
    from bar_constant import BAR

foo_constant.py:

FOO = 1

bar_constant.py:

BAR = 2

When AutomaticPackageReloader tries to reload TestPackage, it will reload foo_constant.py because its name is TestPackage.foo_constant, but it won't reload bar_constant.py because its name is merely bar_constant and that doesn't start with TestPackage.. You can observe this by modifying bar_constant.py to BAR = 3, saving (and waiting for AutomaticPackageReloader), typing import TestPackage.test; TestPackage.test.BAR into the console, and seeing the output 2.

This PR instead finds the modules belonging to a package by checking the __file__ and __path__ attributes of each module and comparing them to the package's file paths. This should be reliable even if the package munges sys.path.