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

When using editable_mode=strict, breakpoints only hit for symlinked code in build/**, not original code #1152

Closed
mcrumiller opened this issue Dec 13, 2022 · 12 comments

Comments

@mcrumiller
Copy link

This is related to microsoft/pylance-release#3473. Let me know if I should open this issue in the vscode-python repository instead of Pylance.

When using editable installs with a pure pyproject.toml installation (i.e. no setup.py available) as per PEP 660, installation requires ediable_mode=strict:

pip install -e <package> --config-settings editable_mode=strict

This in turn creates a build/__editable__.<package>-<version>-py3-none-any/<package>/ directory of symbolically linked files to the actual code itself.

In order to activate breakpoints when debugging, breakpoints must be set on the code in the build/** directory; breakpoints on the original source code do not activate. This is a bit cumbersome, as the symbolic links are prone to break, which makes working directly on the build/** files dangerous: changes made to these files may not be reflected in the actual package code.

Environment data

  • Language Server version: 2022.12.20 (pyright 621d886b)
  • OS and version: Windows 10
  • Python version (& distribution if applicable, e.g. Anaconda): 3.9

Repro Steps

  1. Install a local package in editable mode using pip install -e . --config-settings editable_mode=strict.
  2. Set a breakpoint in your original code.
  3. Run the code in debug mode.

Expected behavior

Debugger should hit breakpoint.

Actual behavior

Debugger does not hit breakpoint

@rchiodo
Copy link
Contributor

rchiodo commented Dec 13, 2022

Pylance doesn't implement a debugger. Did you mean to open this on the debugpy repo?

@rchiodo rchiodo transferred this issue from microsoft/pylance-release Dec 13, 2022
@rchiodo
Copy link
Contributor

rchiodo commented Dec 13, 2022

Transferred to debugpy.

My guess is that debugpy can't (or doesn't try to) follow symbolic links when matching up breakpoint paths.

@int19h do you know if pydevd would use os.path.realpath on files while matching against breakpoint paths?

@mcrumiller As a workaround, I believe you could use this to map paths between the build directory and real folder in your launch.json:

        {
            "name": "Python current file",
            "type": "python",
            "request": "launch",
            "args": [
                "${file}"
            ],
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "build/__editable__.<package>-<version>-py3-none-any/"
                }
            ],
        }

There's an example described in the VS code docs around remote debugging.

@fabioz
Copy link
Collaborator

fabioz commented Dec 13, 2022

@mcrumiller if you want symlinks resolved, please set the following environment variable in your launch:

PYDEVD_RESOLVE_SYMLINKS=1

@fabioz
Copy link
Collaborator

fabioz commented Dec 13, 2022

Actually, the debugger should actually resolve symlinks when matching breakpoints by default (that setting is just so that the match given to the client would also be translated), so, I'll have to investigate more why it's not matching it in this case (a question: are you sure it's a symbolic link and not a hard link?)

@fabioz
Copy link
Collaborator

fabioz commented Dec 13, 2022

As a reference, the code in https://github.com/microsoft/debugpy/blob/v1.6.4/src/debugpy/_vendored/pydevd/pydevd_file_utils.py#L444 does os.path.realpath (which should resolve links -- on Windows it should work properly since Python 3.8).

@mcrumiller
Copy link
Author

Thanks @rchiodo for transferring to the appropriate repo.

@fabioz I'm not sure if it's a hard or symbolic link. I can find a lot of documentation on how to create either, but I'm not sure how to test whether an existing file is a hard or symbolic link. Does anybody have any suggestions?

@fabioz
Copy link
Collaborator

fabioz commented Dec 13, 2022

If you open a python shell and do import os;print(os.path.realpath(path)) with that path, does it resolve the path to the original path or does it keep the same path?

@mcrumiller
Copy link
Author

@fabioz it reports the separate path for each item:

original path:

>>> os.path.realpath(r"C:\Projects\project-brr\src\python\brr\fbo_sim.py")
'C:\\Projects\\project-brr\\src\\python\\brr\\fbo_sim.py'

linked path:

>>> os.path.realpath(r"C:\Projects\project-brr\build\__editable__.project_brr-2022.12-py3-none-any\brr\fbo_sim.py")
'C:\\Projects\\project-brr\\build\\__editable__.project_brr-2022.12-py3-none-any\\brr\\fbo_sim.py'

@fabioz
Copy link
Collaborator

fabioz commented Dec 13, 2022

Are you sure that's a link at all? If realpath cannot resolve it, it's possible that it's just a copy and not a link (in which case the debugger can't do much about it).

If this is the case you need to use the approach using pathMappings commented at: #1152 (comment)

@mcrumiller
Copy link
Author

I tested by altering one file and saving that file: the changes were immediately reflected in the other file.

@fabioz
Copy link
Collaborator

fabioz commented Dec 13, 2022

It's probably a hard link then, but I don't think hard links are resolvable (you have 2 different entries pointing to the same data, but I don't think one can be considered the canonical representation -- you need to delete both to erase the data).

@mcrumiller
Copy link
Author

Ok; I'll use the pathMappings technique. Thanks for your help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants