Repository: microsoft/debugpy

Issue:
Reloading modules with relative imports fails
Structure to reproduce:

```
main.py
package/
   module.py
   module1.py
```

main.py:
-----
```
from package.module1 import add_more_text

def main():
    
    while True:
        s = input()
        print(add_more_text(s))

if __name__=="__main__":
    main()
```

module.py
------
```
def add_text(s):
    return s + " foo bar"
```
module1.py:
------
```
from . import module

def add_more_text(s):
    s = module.add_text(s)
    return s + ' zoom'
```

Discussion:
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; ![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=microsoft_debugpy&pullRequest=683&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=microsoft_debugpy&pullRequest=683&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=microsoft_debugpy&pullRequest=683&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=683&metric=coverage&view=list) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=683&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; ![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=microsoft_debugpy&pullRequest=683&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=microsoft_debugpy&pullRequest=683&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=microsoft_debugpy&pullRequest=683&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=microsoft_debugpy&pullRequest=683&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=683&metric=coverage&view=list) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=microsoft_debugpy&pullRequest=683&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_reload.py b/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_reload.py
index b7b897c4..b279eda2 100644
--- a/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_reload.py
+++ b/src/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_reload.py
@@ -193,8 +193,16 @@ class Reload:
 
     def __init__(self, mod, mod_name=None, mod_filename=None):
         self.mod = mod
-        self.mod_name = (mod_name or mod.__name__) if mod_name else None
-        self.mod_filename = (mod_filename or mod.__file__) if mod else None
+        if mod_name:
+            self.mod_name = mod_name
+        else:
+            self.mod_name = mod.__name__ if mod is not None else None
+
+        if mod_filename:
+            self.mod_filename = mod_filename
+        else:
+            self.mod_filename = mod.__file__ if mod is not None else None
+
         self.found_change = False
 
     def apply(self):


Test patch:
diff --git a/src/debugpy/_vendored/pydevd/test_pydevd_reload/test_pydevd_reload.py b/src/debugpy/_vendored/pydevd/test_pydevd_reload/test_pydevd_reload.py
index aad8c66e..067f3da6 100644
--- a/src/debugpy/_vendored/pydevd/test_pydevd_reload/test_pydevd_reload.py
+++ b/src/debugpy/_vendored/pydevd/test_pydevd_reload/test_pydevd_reload.py
@@ -50,7 +50,17 @@ class Test(unittest.TestCase):
             pass
 
     def make_mod(self, name="x", repl=None, subst=None, sample=SAMPLE_CODE):
-        fn = os.path.join(self.tempdir, name + ".py")
+        basedir = self.tempdir
+        if '.' in name:
+            splitted = name.split('.')
+            basedir = os.path.join(self.tempdir, *splitted[:-1])
+            name = splitted[-1]
+            try:
+                os.makedirs(basedir)
+            except:
+                pass
+
+        fn = os.path.join(basedir, name + ".py")
         f = open(fn, "w")
         if repl is not None and subst is not None:
             sample = sample.replace(repl, subst)
@@ -531,3 +541,33 @@ def method():
         # do it).
         assert str(x.global_numpy) == '[1 2 3]'
 
+    def test_reload_relative(self):
+        MODULE_CODE = """
+def add_text(s):
+    return s + " module"
+"""
+        MODULE1_CODE = """
+from . import module
+
+def add_more_text(s):
+    s = module.add_text(s)
+    return s + ' module1'
+"""
+
+        MODULE1_CODE_V2 = """
+from . import module
+
+def add_more_text(s):
+    s = module.add_text(s)
+    return s + ' module1V2'
+"""
+
+        self.make_mod(sample='', name='package.__init__')
+        self.make_mod(sample=MODULE_CODE, name='package.module')
+        self.make_mod(sample=MODULE1_CODE, name='package.module1')
+        from package import module1  # @UnresolvedImport
+        assert module1.add_more_text('1') == '1 module module1'
+
+        self.make_mod(sample=MODULE1_CODE_V2, name='package.module1')
+        pydevd_reload.xreload(module1)
+        assert module1.add_more_text('1') == '1 module module1V2'