0

File : foo_module.py

#file: foo_module.py
def foo():
    print("Am foo v1")

File : attempt1.py

#file: attempt1.py
import sys
from time import sleep
from importlib import reload
import foo_module  # <-- import the entire module

print(sys.modules['foo_module']) #Lets see if the module is loaded
while True:
    foo_module.foo()

    #simulate a delay or a condition by when foo_module would have changed
    sleep(2)

    #should reload foo_module to get the latest
    reload(foo_module)

Output:

<module 'foo_module' from 'D:\\pyth\\foo_module.py'>
Am foo v1
Am foo v1
Am foo v1 # I go in around this time and change the foo_module print statement to simulate update to a loaded module
Am foo v2 # Voila ! reload works !
Am foo v2
Am foo v2

This is good and works as I expected. But the following doesnt work !

File : attempt2.py

#file: attempt2.py
import sys
from time import sleep
from importlib import reload
from foo_module import foo  # <-- import specific item only

#Lets see if the module is loaded
print(sys.modules['foo_module']) 

while True:
    foo()

    #simulate a delay or a condition by when foo_module would have changed
    sleep(2)

    #try to reload foo_module to get the latest
    reload(foo_module) #FAILS !

Output:

<module 'foo_module' from 'D:/pyth\\foo_module.py'>  # <-- Module is loaded. isnt it ?
Am foo v1
Traceback (most recent call last):
  File "D:/pyth/attempt2.py", line 10, in <module>
    reload(foo_module)
NameError: name 'foo_module' is not defined

But sys.modules does seem to have the entry for the foo_module in it in both cases ! What am i missing ?

2020
  • 2,821
  • 2
  • 23
  • 40

1 Answers1

1

Credits to https://stackoverflow.com/a/46814062/237105.

# Reload via sys.modules as it is not imported directly
reload(sys.modules['foo_module'])
# Then, reimport function
from foo_module import foo

Total code of yours, fixed:

import sys
from time import sleep
from importlib import reload
from foo_module import foo  # <-- import specific item only

print(sys.modules['foo_module'])
while True:
    foo()

    # simulate a delay or a condition by when foo_module would have changed
    sleep(2)

    # reload foo_module via sys.modules as it is not imported directly
    reload(sys.modules['foo_module'])

    # re-import foo to update it.
    from foo_module import foo
Finomnis
  • 18,094
  • 1
  • 20
  • 27
  • 1
    Because foo_module isn't visible in the current scope, you never imported it. That's why the original code fails. Therefore you need to access it via sys.modules. – Finomnis Jul 21 '19 at 16:08
  • If it is not visible directly, how come `from foo_module import foo` worked in a line above the problematic line ? – 2020 Jul 21 '19 at 16:10
  • 2
    I think you misunderstand. It's about what names are usable in the current context. And `from foo_module import foo` only imports the name `foo`, not `foo_module`. Therefore if you would call it via `foo_module.foo()` it would give you the same error. And if `foo_module` is not available as a name in the current scope, you cannot pass it to `reload()`. Nonetheless, you did of course load the module when you imported `foo`, therefore it is available in `sys.modules`. But because it is not available as a name, you have to access it via `sys.modules`. – Finomnis Jul 21 '19 at 16:13
  • so how an import statement resolves a module name is different from how reload resolves a module name ? for reload to resolve a name, the name must already be imported ? – 2020 Jul 21 '19 at 16:17
  • 1
    Yes. `import` *searches* for the module, for `reload` the module needs to be already imported. `import` is a python command, `reload()` is a function. Big difference. – Finomnis Jul 21 '19 at 16:25
  • my expectation was that `reload()` will atleast search within `sys.modules` where all builtin and user imported modules are listed by default. – 2020 Jul 21 '19 at 16:35
  • 1
    Well, it can't. The command never reaches the `reload()` function. If you look carefully, you don't give `reload()` a string, you give it a name: `reload(foo_module)`, **not** `reload('foo_module')`. Python already errors because it doesn't know what `foo_module` should be, before `reload()` gets called. – Finomnis Jul 21 '19 at 16:49