pynvim icon indicating copy to clipboard operation
pynvim copied to clipboard

Code is run not in __main__ module

Open ZyX-I opened this issue 10 years ago • 4 comments

Consider the following script:

python import sys; print sys.modules['__main__'].__dict__ is globals()

. In Vim this code prints True, in NeoVim it prints False. Using import __main__ can be (and is actually used in powerline) to put some variable into global environment without requiring to specify globals() dictionary, so that code that user needs to run to use powerline is simply

python from powerline.vim import setup as powerline_setup
python powerline_setup()
python del powerline_setup

which is simple and easy.

ZyX-I avatar Feb 08 '15 17:02 ZyX-I

I'm not sure what can be done, I've tried setting the main module in the compatibility module setup:

diff --git a/runtime/autoload/provider/script_host.py b/runtime/autoload/provider/script_host.py
index 1420831..dddded8 100644
--- a/runtime/autoload/provider/script_host.py
+++ b/runtime/autoload/provider/script_host.py
@@ -37,6 +37,7 @@ class ScriptHost(object):
                 neovim.DecodeHook(
                     encoding=nvim.options['encoding'].decode('ascii')))
         sys.modules['vim'] = self.legacy_vim
+        sys.modules['__main__'] = self.legacy_vim

     def setup(self, nvim):
         """Setup import hooks and global streams.

but it doesn't work as expected. Do you have any ideas on how to fix this?

tarruda avatar Feb 09 '15 13:02 tarruda

@tarruda ?! vim module and __main__ are completely different things. To create needed module you may follow two paths:

  1. Create *.py file in sys.path and import it.
  2. Use imp.new_module('__main__') and assign it to sys.modules directly.

I would highly suggest to use the second variant and do two things:

  1. Assign newly created module to sys.modules.
  2. Use __main__.__dict__ as globals argument to exec and eval.

You already do the second thing. But you are not doing the first which is why my script fails:

diff --git a/runtime/autoload/provider/script_host.py b/runtime/autoload/provider/script_host.py
index 1420831..0abb0ae 100644
--- a/runtime/autoload/provider/script_host.py
+++ b/runtime/autoload/provider/script_host.py
@@ -28,6 +28,7 @@ class ScriptHost(object):
         self.setup(nvim)
         # context where all code will run
         self.module = imp.new_module('__main__')
+        sys.modules['__main__'] = self.module
         nvim.script_context = self.module
         # it seems some plugins assume 'sys' is already imported, so do it now
         exec('import sys', self.module.__dict__)

ZyX-I avatar Feb 09 '15 17:02 ZyX-I

By the way, imp.new_module is deprecated since 3.4. Thus

diff --git a/runtime/autoload/provider/script_host.py b/runtime/autoload/provider/script_host.py
index 1420831..df3906e 100644
--- a/runtime/autoload/provider/script_host.py
+++ b/runtime/autoload/provider/script_host.py
@@ -4,6 +4,8 @@ import logging
 import os
 import sys

+from types import ModuleType
+
 import neovim

 __all__ = ('ScriptHost',)
@@ -27,7 +29,8 @@ class ScriptHost(object):
         """Initialize the legacy python-vim environment."""
         self.setup(nvim)
         # context where all code will run
-        self.module = imp.new_module('__main__')
+        self.module = ModuleType('__main__')
+        sys.modules['__main__'] = self.module
         nvim.script_context = self.module
         # it seems some plugins assume 'sys' is already imported, so do it now
         exec('import sys', self.module.__dict__)

This works at least starting from Python-2.6.

ZyX-I avatar Feb 09 '15 17:02 ZyX-I

And the whole imp thing is deprecated as well. But new replacements for find_module and load_module are not that compatible.

ZyX-I avatar Feb 09 '15 17:02 ZyX-I