My plugin (currently a single command) needs to make use of the chardet Python library. I have therefore put a copy of the chardet module in a subdirectory of my package:
/*:m][/list:u]/*:m][/list:u]/*:m][/list:u]
Now, inside my_command.py, I import and attempt to use chardet:
import chardet
…
class MyCommandCommand(sublime_plugin.TextCommand):
def run(self, edit):
…
decoded_content = content.decode(chardet.detect(content)'encoding'])
When Sublime Text 2’s Python attempts to run chardet.detect, it fails with this error:
Traceback (most recent call last):
File "./sublime_plugin.py", line 255, in run_
File "./lookup_with_google_and_link.py", line 79, in run
File "./lookup_with_google_and_link.py", line 50, in get_link_with_title
File "./chardet/__init__.py", line 21, in detect
ImportError: No module named universaldetector
The universaldetector.py file exists in the chardet directory. I can see that Python is creating a init.pyc file for init.py, but no .pyc files for any of the other files under chardet.
If I open my system Python interpreter in my My Package directory, I can import and use chardet.detect without incident.
Any idea what could be causing this?
This seems like a hack that shouldn’t be necessary, but I’ve fixed the problem by adding the module’s directory to the system path before importing it:
cmd_folder = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(cmd_folder, 'chardet'))
import chardet
I see, thank you! That’s quite a pitfall!
So if I understand correctly, the correct workaround here would be for my plugin to pre-emptively import every module in the library package to guarantee that it will be already loaded when the time comes.
For large libraries, this could create a huge amount of namespace pollution if these imports were performed at the top level of the plug-in module. I’m thinking of performing the imports inside a function. Would you agree this is probably a “best practice” approach for Sublime Text 2 plug-ins?
# inside the my_command.py plug-in file
def preemptive_imports():
""" needed to ensure access to these classes later, due to the way ST2 loads plug-in modules """
from chardet import big5freq, big5prober, chardistribution …
preemptive_imports()
I’d love to be able to do it with “from package import *”, but I can’t do that within a function.
This would be convenient to be able to do:
# inside my_command.py plug-in file
def preemptive_imports():
from chardet import *
preemptive_imports()
But Python doesn’t permit “import *” within a function.
Using a separate module would work, though.