Sublime Forum

Cant import a nested submodule from a plugin (ST2)

#1

My plugin (https://github.com/jdc0589/JsFormat/tree/jsbeautifier_upgrade) has a dependency on the jsbeautifier project (https://github.com/einars/js-beautify/tree/master/python). Previously I was able to just copy a single file over from the jsbeautifier project, but they have re-organized the strucure of the jsbeautifier/python submodule. Something about how sublime sets the path up is preventing the ā€˜unpackersā€™ submodule of jsbeautifier from being imported (it cant find it).

the basic structure of my plugin and jsbeautifier is as follows:

JsFormat
> Default (Linux).sublime-keymap
> js_formatter.py
> jsbeautifier
>> __init__.py (not empty)
>> tests
>>> __init__.py
>> unpackers
>>> __init__.py (not empty)

js_formatter.py contains the sublime textcommand for my plugin, which imports and runs jsbeautifier. jsbeautifier/init.py attempts to ā€˜import jsbeautifier.unpackersā€™, which fails, and is the real problem. The import fails on jsbeautifier/init.py line 255. If I fire up a python repl from the root of the plugin directory importing jsbeautifier or jsbeautifier.unpackers works as expected.

I have tried changing the import logic of my plugin as follows, but it has not resolved the problem:

import sublime, sublime_plugin, re, sys, os

directory = os.path.dirname(os.path.realpath(__file__)) + "\\"
jsb_unpackers = directory+"\\jsbeautifier\\unpackers\\"
sys.path.append(jsb_unpackers)

import jsbeautifier

Any suggestions?

1 Like

#2

You are going to kick yourself when you see how easy it is :smile:.

ST3 now treats each plugin folder kind of like it was a python moduleā€¦soā€¦assuming your plugin is found in a folder named JsFormatā€¦

import JsFormat.jsbeautifier as jsbeautifier

Tah dah!

Side note, also initialize your settings object under a function called plugin_loaded (its a ST3 thing)

def plugin_loaded(): global s s = sublime.load_settings("JsFormat.sublime-settings")

1 Like

#3

[quote=ā€œfacelessuserā€]You are going to kick yourself when you see how easy it is :smile:.

ST3 now treats each plugin folder kind of like it was a python moduleā€¦soā€¦assuming your plugin is found in a folder named JsFormatā€¦

import JsFormat.jsbeautifier as jsbeautifier

Tah dah!

Side note, also initialize your settings object under a function called plugin_loaded (its a ST3 thing)

def plugin_loaded(): global s s = sublime.load_settings("JsFormat.sublime-settings")[/quote]

Cool, ill have to try it out in ST3. However this is really in reference to ST2, as thatā€™s where my current userbase is.

0 Likes

#4

Pays to fully read the postā€¦sorryā€¦

Seems to only import globally correctly (top of file)ā€¦weird.

I donā€™t have a good anser off hand. Seems like some kind of ST python environment issue.

0 Likes

#5

I think when python is inside a function it is accessing the jsbeautifier module loaded in sys.modules, and that module does not expose unpackers because you never import it globally.

Here look at this: no unpacker found:

>>print dir(sys.modules'jsbeautifier']) 'Beautifier', 'BeautifierFlags', 'BeautifierOptions', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'beautify', 'beautify_file', 'default_options', 'getopt', 'main', 're', 'string', 'sys', 'usage']

I think when importing globally it isnā€™t looking at the module in sys.module, but using the path to find unpacker.

0 Likes

#6

Havenā€™t read this in great detail ā€¦ but ā€¦

You can get into trouble with run time imports, cause the sublime text 2 does that retarded os.chdir() workaround

You basically have to pre-emptively import everything you wanna use while the current working directory is correct ā€¦

Dunno if that applies here ā€¦

Note also sys.path.append(pth) can give quite different results to sys.path.insert(0, pth) depending on the situation ā€¦

With the former you can still run into runtime import issues

0 Likes

#7

True, inserting at the beginning will ensure you get the module path you want used first instead of something else getting used before what you appended at the end.

0 Likes

#8

Oddly enough it looks like the following path modifications as well as explicitly importin jsbeautifier.unpackers (even though I donā€™t use it directly in my plugin) fixes the issue:

import sublime, sublime_plugin, re, sys, os

directory = os.path.dirname(os.path.realpath(__file__)) + "\\"
sys.path.append(directory+"\\jsbeaufifier")
sys.path.append(directory+"\\jsbeautifier\\unpackers")

import jsbeautifier, jsbeautifier.unpackers

The seems like a pretty bad hackā€¦but if it works reliably then I guess I donā€™t care. Better than being stuck on an outdated version of jsbeautifier.

0 Likes