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

pdm run does not catch ctrl-c on 2nd run (Win11) #2292

Closed
srfoster65 opened this issue Oct 2, 2023 · 5 comments · Fixed by #2351
Closed

pdm run does not catch ctrl-c on 2nd run (Win11) #2292

srfoster65 opened this issue Oct 2, 2023 · 5 comments · Fixed by #2351
Labels
🐛 bug Something isn't working 💝 good first issue Good for newcomers

Comments

@srfoster65
Copy link
Contributor

  • [ x] I have searched the issue tracker and believe that this is not a duplicate.

Steps to reproduce

Given a project that is setup to support mkdocs for generating documentation.
From a windows command shell (cmd), cd to the project root and enter the following commands

pdm run mkdocs serve

[ctrl-c] - To terminate serve process - this works correctly.

pdm run mkdocs serve

[ctrl-c] - Does not interrupt/terminate process

Note:
I have tested the same project with poetry, and this can repeatedly start and stop mkdocs serve with the command "poetry run mkdocs serve".

Actual behaviour

mkdocs serve process continues to run.

Expected behaviour

mkdocs serve process should be interrupted

Environment Information

pdm info
PDM version:
2.9.3
Python Interpreter:
C:\Users\Steve\Development\python\arg_init.venv\Scripts\python.exe (3.11)
Project Root:
C:/Users/Steve/Development/python/arg_init
Local Packages:

{
"implementation_name": "cpython",
"implementation_version": "3.11.3",
"os_name": "nt",
"platform_machine": "AMD64",
"platform_release": "10",
"platform_system": "Windows",
"platform_version": "10.0.22621",
"python_full_version": "3.11.3",
"platform_python_implementation": "CPython",
"python_version": "3.11",
"sys_platform": "win32"
}

@srfoster65 srfoster65 added the 🐛 bug Something isn't working label Oct 2, 2023
@srfoster65
Copy link
Contributor Author

srfoster65 commented Oct 3, 2023

Something very odd is happening here. Almost certainly windows specific.

The issue is in the file pdm\cli\commands\run.py and function _run_process().

If I simplify the code in _run_process() (This is not a solution, but an attempt to understand program flow) and remove the signal handler function and replace with a try/except block.

   try:
        process = subprocess.Popen(expanded_args, cwd=cwd, env=process_env, shell=shell, bufsize=0)
        process.wait()
    except KeyboardInterrupt:
        process.send_signal(signal.SIGINT) 

This works everytime. Note: this is sending signal.SIGINT to the subporocess.

If I modify the existing forward_signal() function

    def forward_signal(signum: int, frame: FrameType | None) -> None:
        process.send_signal(signum)

This will raise
[ValueError]: Unsupported signal: 2

everytime, but will abort the script.

But why should this raise a ValueError when calling send_signal() in the exception handler with the same value (signal.SIGINT = 2) does not?

@srfoster65
Copy link
Contributor Author

https://docs.python.org/3/library/signal.html#signal.CTRL_C_EVENT

signal.CTRL_C_EVENT
The signal corresponding to the Ctrl+C keystroke event. This signal can only be used with os.kill().

So the code in forward signal should not work as intended, and may partially explain the observed behaviour.

@srfoster65
Copy link
Contributor Author

A solution I found on stackoverflow that was used for a similar issue on postgress was to use signum=signal.SIGTERM for windows.

    def forward_signal(signum: int, frame: FrameType | None) -> None:
        if sys.platform == "win32" and signum == signal.SIGINT:
            signum = signal.SIGTERM
        process.send_signal(signum)

I have tested this and this seems to reliably terminate the subprocess.

@frostming
Copy link
Collaborator

frostming commented Oct 30, 2023

A solution I found on stackoverflow that was used for a similar issue on postgress was to use signum=signal.SIGTERM for windows.

    def forward_signal(signum: int, frame: FrameType | None) -> None:
        if sys.platform == "win32" and signum == signal.SIGINT:
            signum = signal.SIGTERM
        process.send_signal(signum)

I have tested this and this seems to reliably terminate the subprocess.

This seems to fix the issue without causing any other problems though TBH, I was unable to reproduce it. Would you or @xzmeng like to send a PR?

@frostming frostming added the 💝 good first issue Good for newcomers label Oct 30, 2023
@srfoster65
Copy link
Contributor Author

Sure, I will create a PR.
This will be my first PR, so I hope I get things right.

@frostming frostming linked a pull request Oct 31, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working 💝 good first issue Good for newcomers
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants