Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalize debugger temp file paths on Windows #838

Merged
merged 3 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions ipykernel/compiler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from IPython.core.compilerop import CachingCompiler
import tempfile
import os
import sys


def murmur2_x86(data, seed):
Expand Down Expand Up @@ -36,11 +37,35 @@ def murmur2_x86(data, seed):

return h

convert_to_long_pathname = lambda filename:filename

if sys.platform == 'win32':
try:
import ctypes
from ctypes.wintypes import MAX_PATH, LPCWSTR, LPWSTR, DWORD

_GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
_GetLongPathName.argtypes = [LPCWSTR, LPWSTR, DWORD]
_GetLongPathName.restype = DWORD

def _convert_to_long_pathname(filename):
buf = ctypes.create_unicode_buffer(MAX_PATH)
rv = _GetLongPathName(filename, buf, MAX_PATH)
if rv != 0 and rv <= MAX_PATH:
filename = buf.value
return filename

# test that it works so if there are any issues we fail just once here
_convert_to_long_pathname(__file__)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add this as a test in test_debugger.py instead of inline here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add it there to test as well. The intent with adding it here is to catch any errors with e.g. DLL references early so we can fail just once up front and fallback to not normalizing, rather than failing every time we get the path below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a test, and clarified the inline comment. Note that debugpy (or rather pydevd) does a similar runtime check here.

except:
pass
else:
convert_to_long_pathname = _convert_to_long_pathname

def get_tmp_directory():
tmp_dir = tempfile.gettempdir()
tmp_dir = convert_to_long_pathname(tempfile.gettempdir())
pid = os.getpid()
return tmp_dir + '/ipykernel_' + str(pid)
return tmp_dir + os.sep + 'ipykernel_' + str(pid)


def get_tmp_hash_seed():
Expand All @@ -52,7 +77,7 @@ def get_file_name(code):
cell_name = os.environ.get("IPYKERNEL_CELL_NAME")
if cell_name is None:
name = murmur2_x86(code, get_tmp_hash_seed())
cell_name = get_tmp_directory() + '/' + str(name) + '.py'
cell_name = get_tmp_directory() + os.sep + str(name) + '.py'
return cell_name


Expand Down
2 changes: 1 addition & 1 deletion ipykernel/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ async def debugInfo(self, message):
'isStarted': self.is_started,
'hashMethod': 'Murmur2',
'hashSeed': get_tmp_hash_seed(),
'tmpFilePrefix': get_tmp_directory() + '/',
'tmpFilePrefix': get_tmp_directory() + os.sep,
'tmpFileSuffix': '.py',
'breakpoints': breakpoint_list,
'stoppedThreads': self.stopped_threads,
Expand Down
6 changes: 6 additions & 0 deletions ipykernel/tests/test_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,9 @@ def test_rich_inspect_at_breakpoint(kernel_with_debug):
)

assert reply["body"]["data"] == {"text/plain": locals_[0]["value"]}


def test_convert_to_long_pathname():
if sys.platform == 'win32':
from ipykernel.compiler import _convert_to_long_pathname
_convert_to_long_pathname(__file__)