Repository: microsoft/ptvsd

Issue:
Mix of unicode and str in filename conversion.
Will submit a fix shortly.


Discussion:

Resolving patch:
diff --git a/ptvsd/_vendored/pydevd/conftest.py b/ptvsd/_vendored/pydevd/conftest.py
--- a/ptvsd/_vendored/pydevd/conftest.py
+++ b/ptvsd/_vendored/pydevd/conftest.py
@@ -1,8 +1,14 @@
 import pytest
 import sys
 from _pydevd_bundle.pydevd_constants import IS_JYTHON, IS_IRONPYTHON
+from tests_python.debug_constants import TEST_CYTHON
+from tests_python.debug_constants import TEST_JYTHON
 
 
+def pytest_report_header(config):
+    print('PYDEVD_USE_CYTHON: %s' % (TEST_CYTHON,))
+    print('PYDEVD_TEST_JYTHON: %s' % (TEST_JYTHON,))
+
 # see: http://goo.gl/kTQMs
 SYMBOLS = {
     'customary'     : ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'),
diff --git a/ptvsd/_vendored/pydevd/pydevd_file_utils.py b/ptvsd/_vendored/pydevd/pydevd_file_utils.py
--- a/ptvsd/_vendored/pydevd/pydevd_file_utils.py
+++ b/ptvsd/_vendored/pydevd/pydevd_file_utils.py
@@ -83,7 +83,6 @@
 #   r'd:\temp\temp_workspace_2\test_python\src\hhh\xxx')
 # ]
 
-
 convert_to_long_pathname = lambda filename:filename
 convert_to_short_pathname = lambda filename:filename
 get_path_with_real_case = lambda filename:filename
@@ -104,21 +103,27 @@
         def _convert_to_long_pathname(filename):
             buf = ctypes.create_unicode_buffer(MAX_PATH)
 
-            if IS_PY2:
+            if IS_PY2 and isinstance(filename, str):
                 filename = filename.decode(getfilesystemencoding())
             rv = GetLongPathName(filename, buf, MAX_PATH)
             if rv != 0 and rv <= MAX_PATH:
-                return buf.value
+                filename = buf.value
+            
+            if IS_PY2:
+                filename = filename.encode(getfilesystemencoding())
             return filename
         
         def _convert_to_short_pathname(filename):
             buf = ctypes.create_unicode_buffer(MAX_PATH)
 
-            if IS_PY2:
+            if IS_PY2 and isinstance(filename, str):
                 filename = filename.decode(getfilesystemencoding())
             rv = GetShortPathName(filename, buf, MAX_PATH)
             if rv != 0 and rv <= MAX_PATH:
-                return buf.value
+                filename = buf.value
+                
+            if IS_PY2:
+                filename = filename.encode(getfilesystemencoding())
             return filename
         
         def _get_path_with_real_case(filename):
@@ -152,9 +157,9 @@ def normcase(filename):
         return filename.lower()
     
 else:
-    def normcase(filename):
-        return filename # no-op
 
+    def normcase(filename):
+        return filename  # no-op
 
 _ide_os = 'WINDOWS' if sys.platform == 'win32' else 'UNIX'
 
@@ -312,12 +317,14 @@ def _NormPaths(filename):  # Let's redefine _NormPaths to work with paths that m
 #
 # instead of importing any of those names to a given scope. 
 
+
 def _original_file_to_client(filename, cache={}):
     try:
         return cache[filename]
     except KeyError:
         cache[filename] = get_path_with_real_case(_AbsFile(filename))
     return cache[filename]
+
     
 _original_file_to_server = _NormFile
 


Test patch:
diff --git a/ptvsd/_vendored/pydevd/tests_python/debug_constants.py b/ptvsd/_vendored/pydevd/tests_python/debug_constants.py
new file mode 100644
--- /dev/null
+++ b/ptvsd/_vendored/pydevd/tests_python/debug_constants.py
@@ -0,0 +1,4 @@
+import os
+
+TEST_CYTHON = os.getenv('PYDEVD_USE_CYTHON', None) == 'YES'
+TEST_JYTHON = os.getenv('PYDEVD_TEST_JYTHON', None) == 'YES'
\ No newline at end of file
diff --git a/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py b/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py
--- a/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py
+++ b/ptvsd/_vendored/pydevd/tests_python/test_convert_utilities.py
@@ -1,3 +1,4 @@
+#coding: utf-8
 import os.path
 
 
@@ -8,12 +9,14 @@ def test_convert_utilities(tmpdir):
     test_dir = str(tmpdir.mkdir("Test_Convert_Utilities"))
     if sys.platform == 'win32':
         normalized = pydevd_file_utils.normcase(test_dir)
+        assert isinstance(normalized, str) # bytes on py2, unicode on py3
         assert normalized.lower() == normalized
          
         assert '~' not in normalized
         assert '~' in pydevd_file_utils.convert_to_short_pathname(normalized)
          
         real_case = pydevd_file_utils.get_path_with_real_case(normalized)
+        assert isinstance(real_case, str) # bytes on py2, unicode on py3
         # Note test_dir itself cannot be compared with because pytest may
         # have passed the case normalized.
         assert real_case.endswith("Test_Convert_Utilities")
@@ -27,6 +30,10 @@ def test_convert_utilities(tmpdir):
 
 def test_to_server_and_to_client(tmpdir):
     try:
+        def check(obtained, expected):
+            assert obtained == expected
+            assert isinstance(obtained, str)# bytes on py2, unicode on py3
+            assert isinstance(expected, str)# bytes on py2, unicode on py3
         import pydevd_file_utils
         import sys
         if sys.platform == 'win32':
@@ -40,9 +47,9 @@ def test_to_server_and_to_client(tmpdir):
                 (in_eclipse, in_python)
             ]
             pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON)
-            assert pydevd_file_utils.norm_file_to_server('c:\\foo\\my') == 'c:\\bar\\my'
-            assert pydevd_file_utils.norm_file_to_server('c:\\foo\\my'.upper()) == 'c:\\bar\\my'
-            assert pydevd_file_utils.norm_file_to_client('c:\\bar\\my') == 'c:\\foo\\my'
+            check(pydevd_file_utils.norm_file_to_server('c:\\foo\\my'), 'c:\\bar\\my')
+            check(pydevd_file_utils.norm_file_to_server('c:\\foo\\áéíóú'.upper()), 'c:\\bar\\áéíóú')
+            check(pydevd_file_utils.norm_file_to_client('c:\\bar\\my'), 'c:\\foo\\my')
             
             # Client on unix and server on windows
             pydevd_file_utils.set_ide_os('UNIX')
@@ -52,8 +59,8 @@ def test_to_server_and_to_client(tmpdir):
                 (in_eclipse, in_python)
             ]
             pydevd_file_utils.setup_client_server_paths(PATHS_FROM_ECLIPSE_TO_PYTHON)
-            assert pydevd_file_utils.norm_file_to_server('/foo/my') == 'c:\\bar\\my'
-            assert pydevd_file_utils.norm_file_to_client('c:\\bar\\my') == '/foo/my'
+            check(pydevd_file_utils.norm_file_to_server('/foo/my'), 'c:\\bar\\my')
+            check(pydevd_file_utils.norm_file_to_client('c:\\bar\\my'), '/foo/my')
             
             # Test with 'real' files
             # Client and server are on windows. 
diff --git a/ptvsd/_vendored/pydevd/tests_python/test_debugger.py b/ptvsd/_vendored/pydevd/tests_python/test_debugger.py
--- a/ptvsd/_vendored/pydevd/tests_python/test_debugger.py
+++ b/ptvsd/_vendored/pydevd/tests_python/test_debugger.py
@@ -56,8 +56,8 @@
 if sys.version_info[0] == 3 and sys.version_info[1] == 6:
     IS_PY36 = True
 
-TEST_CYTHON = os.getenv('PYDEVD_USE_CYTHON', None) == 'YES'
-TEST_JYTHON = os.getenv('TEST_JYTHON', None) == 'YES'
+from tests_python.debug_constants import TEST_CYTHON
+from tests_python.debug_constants import TEST_JYTHON
 
 #=======================================================================================================================
 # WriterThreadCaseSetNextStatement