зеркало из https://github.com/microsoft/debugpy.git
Use `subrepo` to link to PyDev.Debugger instead of copying it (#1714)
* Remove copy of pydevd and add subrepo script * git subrepo clone https://github.com/fabioz/PyDev.Debugger.git src/debugpy/_vendored/pydevd subrepo: subdir: "src/debugpy/_vendored/pydevd" merged: "7d6e6e68" upstream: origin: "https://github.com/fabioz/PyDev.Debugger.git" branch: "main" commit: "7d6e6e68" git-subrepo: version: "0.4.9" origin: "???" commit: "???" * Add binskim settings to match debugpy * git subrepo clone --force https://github.com/fabioz/PyDev.Debugger.git src/debugpy/_vendored/pydevd subrepo: subdir: "src/debugpy/_vendored/pydevd" merged: "cf2e47cb" upstream: origin: "https://github.com/fabioz/PyDev.Debugger.git" branch: "main" commit: "cf2e47cb" git-subrepo: version: "0.4.9" origin: "???" commit: "???" * Remove unnecessary string test by removing the lambda in pydevd_sys_monitoring * Fix linter * Put back the fix in qt_loaders * Put back binskim flag
This commit is contained in:
Родитель
8ab4ee89e9
Коммит
a7d5a7ec12
|
@ -103,13 +103,14 @@ Using `pydevd_log.debug` you can add logging just about anywhere in the pydevd c
|
|||
|
||||
## Updating pydevd
|
||||
|
||||
Pydevd (at src/debugpy/_vendored/pydevd) is a copy of https://github.com/fabioz/PyDev.Debugger. We do not use a git submodule but instead just copy the source.
|
||||
Pydevd (at src/debugpy/_vendored/pydevd) is a subrepo of https://github.com/fabioz/PyDev.Debugger. We use the [subrepo](https://github.com/ingydotnet/git-subrepo) to have a copy of pydevd inside of debugpy
|
||||
|
||||
In order to update the source, you would:
|
||||
- Sync to the appropriate commit in a pydevd repo
|
||||
- Diff this against the src/debugpy/_vendored/pydevd folder, being careful to not remove the edits made in the debugpy version
|
||||
- Run our tests
|
||||
- Make any fixes to get the tests to pass (see logging on how to debug)
|
||||
- git checkout -b "branch name"
|
||||
- python subrepo.py pull
|
||||
- git push
|
||||
- Fix any debugpy tests that are failing as a result of the pull
|
||||
- Create a PR from your branch
|
||||
|
||||
You might need to regenerate the Cython modules after any changes. This can be done by:
|
||||
|
||||
|
@ -123,13 +124,17 @@ You might need to regenerate the Cython modules after any changes. This can be d
|
|||
|
||||
If you've made changes to pydevd (at src/debugpy/_vendored/pydevd), you'll want to push back changes to pydevd so as Fabio makes changes to pydevd we can continue to share updates.
|
||||
|
||||
To do this, you would:
|
||||
|
||||
- python subrepo.py branch -m "pydevd branch you want to create"
|
||||
- git push -f https://github.com/fabioz/PyDev.Debugger subrepo/src/debugpy/_vendored/pydevd:$(pydevd branch you want to create)
|
||||
- Create a PR from that branch
|
||||
- Get Fabio's buyoff on the changes
|
||||
|
||||
### Setting up pydevd to be testable
|
||||
|
||||
Follow these steps to get pydevd testable:
|
||||
|
||||
- git clone https://github.com/fabioz/PyDev.Debugger (or using your own fork)
|
||||
- copy all of your changes from src/debugpy/_vendored/pydevd to the root of your PyDev.Debugger clone
|
||||
- remove the pdb files (pydevd doesn't ship those) if you rebuilt the attach dlls
|
||||
- create an environment to test. The list of stuff in your environment is outlined [here](https://github.com/fabioz/PyDev.Debugger/blob/6cd4d431e6a794448f33a73857d479149041500a/.github/workflows/pydevd-tests-python.yml#L83).
|
||||
- set PYTHONPATH=. (make sure you don't forget this part, otherwise a lot of tests will fail)
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: [fabioz]
|
||||
patreon: fabioz
|
||||
#open_collective: # Replace with a single Open Collective username
|
||||
#ko_fi: # Replace with a single Ko-fi username
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
#issuehunt: # Replace with a single IssueHunt username
|
||||
#otechie: # Replace with a single Otechie username
|
||||
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: [https://www.pydev.org/about.html] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
|
@ -0,0 +1,35 @@
|
|||
# Build the cython extensions (to check that we don't crash when they're there in debug mode).
|
||||
python setup_pydevd_cython.py build_ext --inplace
|
||||
|
||||
curl -L https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz -o Python-3.8.3.tgz
|
||||
tar -xzf Python-3.8.3.tgz
|
||||
cd Python-3.8.3
|
||||
mkdir debug
|
||||
cd debug
|
||||
../configure --with-pydebug
|
||||
make
|
||||
|
||||
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
|
||||
./python get-pip.py
|
||||
|
||||
./python -m pip install "pytest"
|
||||
./python -m pip install "psutil"
|
||||
./python -m pip install "untangle"
|
||||
|
||||
# Check that it worked.
|
||||
./python -c "import pytest"
|
||||
./python -c "import psutil"
|
||||
./python -c "import untangle"
|
||||
|
||||
cd ..
|
||||
cd ..
|
||||
ls -la
|
||||
|
||||
./Python-3.8.3/debug/python -c "import sys;assert hasattr(sys,'gettotalrefcount')"
|
||||
|
||||
cd tests_python
|
||||
|
||||
# Although we compiled cython, all we're checking is that we don't crash (since it was built for the release env).
|
||||
../Python-3.8.3/debug/python -m pytest test_debugger_json.py -k "test_case_json_change_breaks or test_remote_debugger_basic"
|
||||
export PYTHONPATH=..
|
||||
../Python-3.8.3/debug/python -c "import check_debug_python;check_debug_python.check() "
|
48
src/debugpy/_vendored/pydevd/.github/workflows/pydevd-release-manylinux.yml
поставляемый
Normal file
48
src/debugpy/_vendored/pydevd/.github/workflows/pydevd-release-manylinux.yml
поставляемый
Normal file
|
@ -0,0 +1,48 @@
|
|||
# Nice reference: https://github.com/tornadoweb/tornado/blob/master/.github/workflows/build.yml
|
||||
# Docs: https://cibuildwheel.readthedocs.io/en/stable/options/
|
||||
# Configurations are here and in pyproject.toml.
|
||||
name: PyDev.Debugger [MANYLINUX] Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "release-pydev-debugger-test"
|
||||
tags:
|
||||
- "pydev_debugger_*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-20.04]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Used to host cibuildwheel
|
||||
- uses: actions/setup-python@v3
|
||||
|
||||
- name: Install cibuildwheel
|
||||
run: python -m pip install cibuildwheel==2.21.2
|
||||
|
||||
- name: Remove .so files (will be rebuilt)
|
||||
run: rm pydevd_attach_to_process/*.so
|
||||
|
||||
- name: Build wheels
|
||||
run: python -m cibuildwheel --output-dir wheelhouse
|
||||
env:
|
||||
CIBW_SKIP: pp* cp36-* cp37-*
|
||||
CIBW_BUILD_VERBOSITY: 1
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
- name: Upload to PyPI .whl
|
||||
run: |
|
||||
pip install twine
|
||||
twine upload wheelhouse/*.whl
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.TWINE_KEY }}
|
|
@ -0,0 +1,67 @@
|
|||
name: PyDev.Debugger [Windows, MacOS] Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "release-pydev-debugger-test"
|
||||
tags:
|
||||
- "pydev_debugger_*"
|
||||
env:
|
||||
DISPLAY: ":99"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest]
|
||||
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Display Python version
|
||||
run: python --version
|
||||
|
||||
- name: Install common Python deps
|
||||
run: |
|
||||
pip install --upgrade pip
|
||||
pip install wheel "cython>3" setuptools psutil twine --no-warn-script-location
|
||||
|
||||
- name: Build cython
|
||||
env:
|
||||
PYTHONPATH: .
|
||||
PYDEVD_USE_CYTHON: yes
|
||||
run: python build_tools/build.py
|
||||
|
||||
- name: Check cython unchanged
|
||||
env:
|
||||
PYTHONPATH: .
|
||||
PYDEVD_USE_CYTHON: yes
|
||||
run: python build_tools/check_no_git_modifications.py
|
||||
|
||||
- name: Create sdist
|
||||
run: python setup.py sdist bdist_wheel
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dist-${{ matrix.os }}-${{ matrix.python-version }}
|
||||
path: dist/*
|
||||
|
||||
- name: Upload to PyPI .whl
|
||||
run: twine upload dist/*.whl
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.TWINE_KEY }}
|
||||
|
||||
- name: Upload to PyPI .tar.gz
|
||||
if: ${{ (matrix.os == 'windows-latest') && (matrix.python-version == '3.9') }}
|
||||
run: twine upload dist/*.tar.gz
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.TWINE_KEY }}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
name: PyDev.Debugger TESTS
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
DISPLAY: ":99"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
name: [
|
||||
"ubuntu-pypy3",
|
||||
# "macos-py37-cython", -- misbehaving on github actions
|
||||
"ubuntu-py38-cython-checkbin",
|
||||
"windows-py39-cython",
|
||||
"windows-py310-cython-checkbin",
|
||||
"windows-py311-cython",
|
||||
"ubuntu-py311-cython",
|
||||
"ubuntu-py312-cython-checkbin",
|
||||
"windows-py312-cython-checkbin",
|
||||
"ubuntu-py313-cython",
|
||||
"windows-py313-cython",
|
||||
]
|
||||
|
||||
include:
|
||||
- name: "ubuntu-pypy3"
|
||||
python: "pypy3.10"
|
||||
os: ubuntu-20.04
|
||||
PYDEVD_USE_CYTHON: NO
|
||||
# - name: "macos-py37-cython"
|
||||
# python: "3.7"
|
||||
# os: macos-latest
|
||||
# PYDEVD_USE_CYTHON: YES
|
||||
- name: "ubuntu-py38-cython-checkbin"
|
||||
python: "3.8"
|
||||
os: ubuntu-20.04
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
- name: "windows-py39-cython"
|
||||
python: "3.9"
|
||||
os: windows-latest
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
- name: "windows-py310-cython-checkbin"
|
||||
python: "3.10"
|
||||
os: windows-latest
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
# See: https://github.com/actions/python-versions/releases
|
||||
- name: "windows-py311-cython"
|
||||
python: "3.11.0"
|
||||
os: windows-latest
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
- name: "ubuntu-py311-cython"
|
||||
python: "3.11.0"
|
||||
os: ubuntu-20.04
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
- name: "ubuntu-py312-cython-checkbin"
|
||||
python: "3.12.0"
|
||||
os: ubuntu-20.04
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
- name: "windows-py312-cython-checkbin"
|
||||
python: "3.12"
|
||||
os: windows-latest
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
- name: "ubuntu-py313-cython"
|
||||
python: "3.13"
|
||||
os: ubuntu-20.04
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
- name: "windows-py313-cython"
|
||||
python: "3.13"
|
||||
os: windows-latest
|
||||
PYDEVD_USE_CYTHON: YES
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
- name: Install gdb/xvfb/ptrace_scope
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install gdb
|
||||
sudo sysctl kernel.yama.ptrace_scope=0
|
||||
sudo apt-get install xvfb
|
||||
sudo apt-get install libqt5x11extras5
|
||||
Xvfb -ac :99 -screen 0 1280x1024x16 > /dev/null 2>&1 &
|
||||
if: contains(matrix.name, 'ubuntu')
|
||||
- name: Install common Python deps
|
||||
run: |
|
||||
pip install --upgrade pip
|
||||
pip install setuptools --no-warn-script-location
|
||||
pip install wheel --no-warn-script-location
|
||||
pip install "cython>3" --no-warn-script-location
|
||||
pip install psutil --no-warn-script-location
|
||||
pip install numpy --no-warn-script-location
|
||||
pip install pytest --no-warn-script-location
|
||||
pip install pytest-xdist --no-warn-script-location
|
||||
pip install psutil --no-warn-script-location
|
||||
pip install ipython --no-warn-script-location
|
||||
pip install untangle --no-warn-script-location
|
||||
pip install importlib-metadata --no-warn-script-location
|
||||
- name: Install Python 3.x deps
|
||||
if: contains(matrix.name, 'py3') && !contains(matrix.name, 'pypy') && !contains(matrix.name, 'py312') && !contains(matrix.name, 'py311') && !contains(matrix.name, 'py313')
|
||||
run: |
|
||||
pip install PySide2 --no-warn-script-location
|
||||
pip install "numpy<2" --force --no-warn-script-location
|
||||
pip install cherrypy --no-warn-script-location
|
||||
pip install gevent==23.9.1 greenlet
|
||||
|
||||
- name: Install django
|
||||
if: "!contains(matrix.name, 'py38')"
|
||||
run: pip install "django<=4.2" --no-warn-script-location
|
||||
|
||||
- name: Install Pandas
|
||||
if: contains(matrix.name, 'py310') && !contains(matrix.name, 'pypy')
|
||||
# The pandas Styler also requires jinja2.
|
||||
run: pip install pandas pyarrow jinja2 --no-warn-script-location
|
||||
- name: Install Pypy 3 deps
|
||||
if: contains(matrix.name, 'py3')
|
||||
run: |
|
||||
pip install trio
|
||||
|
||||
- name: Check that wheels can be built
|
||||
if: contains(matrix.name, 'checkbin') && contains(matrix.name, 'ubuntu')
|
||||
run: |
|
||||
python -m pip install setuptools --no-warn-script-location
|
||||
python -m pip install cibuildwheel==2.21.3
|
||||
# Remove these .so files (will be rebuilt)
|
||||
rm pydevd_attach_to_process/*.so
|
||||
python -m cibuildwheel --output-dir wheelhouse
|
||||
env:
|
||||
CIBW_BUILD: cp310-*manylinux*x86_64 cp311-*manylinux*x86_64 cp312-*manylinux*x86_64 cp313-*manylinux*x86_64
|
||||
CIBW_BUILD_VERBOSITY: 3
|
||||
|
||||
- name: Rebuild .so
|
||||
if: contains(matrix.name, 'checkbin') && contains(matrix.name, 'ubuntu')
|
||||
run: |
|
||||
pydevd_attach_to_process/linux_and_mac/compile_linux.sh
|
||||
|
||||
- name: Check cython unchanged
|
||||
if: contains(matrix.name, 'checkbin')
|
||||
env:
|
||||
PYTHONPATH: .
|
||||
run: |
|
||||
python build_tools/build.py
|
||||
python build_tools/check_no_git_modifications.py
|
||||
|
||||
- name: Create cython binaries
|
||||
if: contains(matrix.name, 'cython')
|
||||
run: |
|
||||
python setup_pydevd_cython.py build_ext --inplace
|
||||
- name: Check debug
|
||||
if: contains(matrix.name, 'checkdebug')
|
||||
run: |
|
||||
./.github/install_and_run_debug_py.sh
|
||||
- name: Run Python 3.x tests
|
||||
env:
|
||||
# QT_DEBUG_PLUGINS: 1
|
||||
PYTHONPATH: .
|
||||
PYDEVD_USE_CYTHON: ${{matrix.PYDEVD_USE_CYTHON }}
|
||||
run: |
|
||||
python -m pytest -n auto -rfE
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = https://github.com/fabioz/PyDev.Debugger.git
|
||||
branch = main
|
||||
commit = cf2e47cbb81a7b4e159f10d56208f4d22ff5423d
|
||||
parent = 942a2276127598ef84d06b7f7b889281c1047712
|
||||
method = merge
|
||||
cmdver = 0.4.9
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>PyDev.Debugger</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.python.pydev.PyDevBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.python.pydev.pythonNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||
|
||||
|
||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||
|
||||
|
||||
<path>/${PROJECT_DIR_NAME}</path>
|
||||
|
||||
|
||||
<path>/${PROJECT_DIR_NAME}/build_tools</path>
|
||||
|
||||
|
||||
<path>/${PROJECT_DIR_NAME}/jython_test_deps/ant.jar</path>
|
||||
|
||||
|
||||
<path>/${PROJECT_DIR_NAME}/jython_test_deps/junit.jar</path>
|
||||
|
||||
|
||||
<path>/${PROJECT_DIR_NAME}/pydevd_attach_to_process</path>
|
||||
|
||||
|
||||
</pydev_pathproperty>
|
||||
|
||||
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
|
||||
|
||||
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
|
||||
|
||||
<pydev_property name="org.python.pydev.PYTHON_ADDITIONAL_GRAMMAR_VALIDATION">3.6</pydev_property>
|
||||
|
||||
</pydev_project>
|
|
@ -0,0 +1,46 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding//.settings/org.python.pydev.yaml=UTF-8
|
||||
encoding//_pydevd_bundle/_debug_adapter/pydevd_schema.py=utf-8
|
||||
encoding//pydev_ipython/inputhook.py=utf-8
|
||||
encoding//pydev_ipython/inputhookglut.py=utf-8
|
||||
encoding//pydev_ipython/inputhookgtk.py=utf-8
|
||||
encoding//pydev_ipython/inputhookgtk3.py=utf-8
|
||||
encoding//pydev_ipython/inputhookpyglet.py=utf-8
|
||||
encoding//pydev_ipython/inputhookqt4.py=utf-8
|
||||
encoding//pydev_ipython/inputhookqt5.py=utf-8
|
||||
encoding//pydev_ipython/inputhooktk.py=utf-8
|
||||
encoding//pydev_ipython/inputhookwx.py=utf-8
|
||||
encoding//pydev_ipython/version.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/breakpoint.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/crash.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/interactive.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/process.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/thread.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/util.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/__init__.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/advapi32.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/context_amd64.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/context_i386.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/dbghelp.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/defines.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/gdi32.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/kernel32.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/ntdll.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/peb_teb.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/psapi.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/shell32.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/shlwapi.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/user32.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/version.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/wtsapi32.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/window.py=utf-8
|
||||
encoding//tests_python/debugger_fixtures.py=utf-8
|
||||
encoding//tests_python/resources/_debugger_case_redirect.py=utf-8
|
||||
encoding//tests_python/test_collect_bytecode_info.py=utf-8
|
||||
encoding//tests_python/test_convert_utilities.py=utf-8
|
||||
encoding//tests_python/test_debugger.py=utf-8
|
||||
encoding//tests_python/test_debugger_json.py=utf-8
|
||||
encoding//tests_python/test_extract_token.py=utf-8
|
||||
encoding//tests_python/test_frame_utils.py=utf-8
|
||||
encoding//tests_python/test_pydev_monkey.py=utf-8
|
||||
encoding//tests_python/test_safe_repr.py=utf-8
|
|
@ -0,0 +1,52 @@
|
|||
ADD_NEW_LINE_AT_END_OF_FILE: true
|
||||
AUTOPEP8_PARAMETERS: ''
|
||||
AUTO_ADD_SELF: true
|
||||
AUTO_BRACES: true
|
||||
AUTO_COLON: true
|
||||
AUTO_DEDENT_ELSE: true
|
||||
AUTO_INDENT_AFTER_PAR_WIDTH: 1
|
||||
AUTO_INDENT_TO_PAR_LEVEL: false
|
||||
AUTO_LINK: false
|
||||
AUTO_LITERALS: true
|
||||
AUTO_PAR: true
|
||||
AUTO_WRITE_IMPORT_STR: true
|
||||
BLACK_FORMATTER_FILE_LOCATION: ''
|
||||
BLACK_FORMATTER_LOCATION_OPTION: LOCATION_SEARCH
|
||||
BLACK_PARAMETERS: ''
|
||||
BLANK_LINES_INNER: 1
|
||||
BLANK_LINES_TOP_LEVEL: 2
|
||||
BREAK_IMPORTS_MODE: PARENTHESIS
|
||||
DATE_FIELD_FORMAT: yyyy-MM-dd
|
||||
DATE_FIELD_NAME: __updated__
|
||||
DELETE_UNUSED_IMPORTS: false
|
||||
ENABLE_DATE_FIELD_ACTION: false
|
||||
FORMATTER_STYLE: RUFF
|
||||
FORMAT_BEFORE_SAVING: true
|
||||
FORMAT_ONLY_CHANGED_LINES: false
|
||||
FORMAT_WITH_AUTOPEP8: false
|
||||
FROM_IMPORTS_FIRST: false
|
||||
GROUP_IMPORTS: true
|
||||
IMPORT_ENGINE: IMPORT_ENGINE_PEP_8
|
||||
INDENT_AFTER_PAR_AS_PEP8: false
|
||||
MANAGE_BLANK_LINES: true
|
||||
MULTILINE_IMPORTS: true
|
||||
PEP8_IMPORTS: true
|
||||
PYDEV_TEST_RUNNER: '2'
|
||||
PYDEV_TEST_RUNNER_DEFAULT_PARAMETERS: --capture=no -vv --tb=native -n 0
|
||||
PYDEV_USE_PYUNIT_VIEW: true
|
||||
RUFF_FORMATTER_FILE_LOCATION: ''
|
||||
RUFF_FORMATTER_LOCATION_OPTION: LOCATION_SEARCH
|
||||
RUFF_PARAMETERS: ''
|
||||
SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES: true
|
||||
SMART_INDENT_PAR: true
|
||||
SMART_LINE_MOVE: false
|
||||
SORT_IMPORTS_ON_SAVE: false
|
||||
SORT_NAMES_GROUPED: false
|
||||
SPACES_BEFORE_COMMENT: '2'
|
||||
SPACES_IN_START_COMMENT: '1'
|
||||
TRIM_EMPTY_LINES: true
|
||||
TRIM_MULTILINE_LITERALS: true
|
||||
USE_ASSIGN_WITH_PACES_INSIDER_PARENTESIS: false
|
||||
USE_OPERATORS_WITH_SPACE: true
|
||||
USE_SPACE_AFTER_COMMA: true
|
||||
USE_SPACE_FOR_PARENTESIS: false
|
|
@ -1,8 +1,8 @@
|
|||
include *.rst *.txt *.md LICENSE-EPL LICENSE-APACHE *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process/common *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process/linux_and_mac *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process/winappdbg *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process/windows *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include _pydevd_bundle *.pyx *.cpp *.hpp
|
||||
include *.rst *.txt *.md LICENSE-EPL LICENSE-APACHE *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process/common *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process/linux_and_mac *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process/winappdbg *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include pydevd_attach_to_process/windows *.py *.dll *.so *.dylib *.txt *.c *.h *.bat Makefile *.sh *.pyx *.cpp *.hpp
|
||||
recursive-include _pydevd_bundle *.pyx *.cpp *.hpp
|
||||
recursive-include build_tools *.py
|
|
@ -4,7 +4,14 @@ from _pydev_bundle._pydev_saved_modules import threading
|
|||
# circumstances).
|
||||
# It is required to debug threads started by start_new_thread in Python 3.4
|
||||
_temp = threading.Thread()
|
||||
if hasattr(_temp, "_is_stopped"): # Python 3.12 and earlier has this
|
||||
|
||||
if hasattr(_temp, "_handle") and hasattr(_temp, "_started"): # Python 3.13 and later has this
|
||||
|
||||
def is_thread_alive(t):
|
||||
return not t._handle.is_done()
|
||||
|
||||
|
||||
elif hasattr(_temp, "_is_stopped"): # Python 3.12 and earlier has this
|
||||
|
||||
def is_thread_alive(t):
|
||||
return not t._is_stopped
|
||||
|
|
|
@ -12,17 +12,14 @@ from _pydevd_bundle.pydevd_constants import (
|
|||
set_global_debugger,
|
||||
DebugInfoHolder,
|
||||
PYDEVD_USE_SYS_MONITORING,
|
||||
IS_PY313_OR_GREATER,
|
||||
)
|
||||
from _pydev_bundle import pydev_log
|
||||
from contextlib import contextmanager
|
||||
from _pydevd_bundle import pydevd_constants, pydevd_defaults
|
||||
from _pydevd_bundle.pydevd_defaults import PydevdCustomization
|
||||
import ast
|
||||
|
||||
try:
|
||||
from pathlib import Path
|
||||
except ImportError:
|
||||
Path = None
|
||||
from pathlib import Path
|
||||
|
||||
# ===============================================================================
|
||||
# Things that are dependent on having the pydevd debugger
|
||||
|
@ -299,7 +296,7 @@ def remove_quotes_from_args(args):
|
|||
new_args = []
|
||||
|
||||
for x in args:
|
||||
if Path is not None and isinstance(x, Path):
|
||||
if isinstance(x, Path):
|
||||
x = str(x)
|
||||
else:
|
||||
if not isinstance(x, (bytes, str)):
|
||||
|
@ -316,7 +313,7 @@ def remove_quotes_from_args(args):
|
|||
else:
|
||||
new_args = []
|
||||
for x in args:
|
||||
if Path is not None and isinstance(x, Path):
|
||||
if isinstance(x, Path):
|
||||
x = x.as_posix()
|
||||
else:
|
||||
if not isinstance(x, (bytes, str)):
|
||||
|
@ -1173,15 +1170,31 @@ threading_modules_to_patch = _get_threading_modules_to_patch()
|
|||
|
||||
|
||||
def patch_thread_module(thread_module):
|
||||
if getattr(thread_module, "_original_start_new_thread", None) is None:
|
||||
if thread_module is threading:
|
||||
if not hasattr(thread_module, "_start_new_thread"):
|
||||
return # Jython doesn't have it.
|
||||
_original_start_new_thread = thread_module._original_start_new_thread = thread_module._start_new_thread
|
||||
# Note: this is needed not just for the tracing, but to have an early way to
|
||||
# notify that a thread was created (i.e.: tests_python.test_debugger_json.test_case_started_exited_threads_protocol)
|
||||
start_thread_attrs = ["_start_new_thread", "start_new_thread", "start_new"]
|
||||
start_joinable_attrs = ["start_joinable_thread", "_start_joinable_thread"]
|
||||
check = start_thread_attrs + start_joinable_attrs
|
||||
|
||||
replace_attrs = []
|
||||
for attr in check:
|
||||
if hasattr(thread_module, attr):
|
||||
replace_attrs.append(attr)
|
||||
|
||||
if not replace_attrs:
|
||||
return
|
||||
|
||||
for attr in replace_attrs:
|
||||
if attr in start_joinable_attrs:
|
||||
if getattr(thread_module, "_original_start_joinable_thread", None) is None:
|
||||
_original_start_joinable_thread = thread_module._original_start_joinable_thread = getattr(thread_module, attr)
|
||||
else:
|
||||
_original_start_joinable_thread = thread_module._original_start_joinable_thread
|
||||
else:
|
||||
_original_start_new_thread = thread_module._original_start_new_thread = thread_module.start_new_thread
|
||||
else:
|
||||
_original_start_new_thread = thread_module._original_start_new_thread
|
||||
if getattr(thread_module, "_original_start_new_thread", None) is None:
|
||||
_original_start_new_thread = thread_module._original_start_new_thread = getattr(thread_module, attr)
|
||||
else:
|
||||
_original_start_new_thread = thread_module._original_start_new_thread
|
||||
|
||||
class ClassWithPydevStartNewThread:
|
||||
def pydev_start_new_thread(self, function, args=(), kwargs={}):
|
||||
|
@ -1191,6 +1204,19 @@ def patch_thread_module(thread_module):
|
|||
"""
|
||||
return _original_start_new_thread(_UseNewThreadStartup(function, args, kwargs), ())
|
||||
|
||||
class ClassWithPydevStartJoinableThread:
|
||||
def pydev_start_joinable_thread(self, function, *args, **kwargs):
|
||||
"""
|
||||
We need to replace the original thread_module._start_joinable_thread with this function so that threads started
|
||||
through it and not through the threading module are properly traced.
|
||||
"""
|
||||
# Note: only handling the case from threading.py where the handle
|
||||
# and daemon flags are passed explicitly. This will fail if some user library
|
||||
# actually passes those without being a keyword argument!
|
||||
handle = kwargs.pop("handle", None)
|
||||
daemon = kwargs.pop("daemon", True)
|
||||
return _original_start_joinable_thread(_UseNewThreadStartup(function, args, kwargs), handle=handle, daemon=daemon)
|
||||
|
||||
# This is a hack for the situation where the thread_module.start_new_thread is declared inside a class, such as the one below
|
||||
# class F(object):
|
||||
# start_new_thread = thread_module.start_new_thread
|
||||
|
@ -1200,17 +1226,15 @@ def patch_thread_module(thread_module):
|
|||
# So, if it's an already bound method, calling self.start_new_thread won't really receive a different 'self' -- it
|
||||
# does work in the default case because in builtins self isn't passed either.
|
||||
pydev_start_new_thread = ClassWithPydevStartNewThread().pydev_start_new_thread
|
||||
pydev_start_joinable_thread = ClassWithPydevStartJoinableThread().pydev_start_joinable_thread
|
||||
|
||||
try:
|
||||
# We need to replace the original thread_module.start_new_thread with this function so that threads started through
|
||||
# it and not through the threading module are properly traced.
|
||||
if thread_module is threading:
|
||||
thread_module._start_new_thread = pydev_start_new_thread
|
||||
# We need to replace the original thread_module.start_new_thread with this function so that threads started through
|
||||
# it and not through the threading module are properly traced.
|
||||
for attr in replace_attrs:
|
||||
if attr in start_joinable_attrs:
|
||||
setattr(thread_module, attr, pydev_start_joinable_thread)
|
||||
else:
|
||||
thread_module.start_new_thread = pydev_start_new_thread
|
||||
thread_module.start_new = pydev_start_new_thread
|
||||
except:
|
||||
pass
|
||||
setattr(thread_module, attr, pydev_start_new_thread)
|
||||
|
||||
|
||||
def patch_thread_modules():
|
||||
|
@ -1235,6 +1259,16 @@ def undo_patch_thread_modules():
|
|||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
t._start_joinable_thread = t._original_start_joinable_thread
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
t.start_joinable_thread = t._original_start_joinable_thread
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def disable_trace_thread_modules():
|
||||
"""
|
||||
|
|
|
@ -846,6 +846,8 @@ class _Disassembler(object):
|
|||
argrepr = instruction.argrepr
|
||||
if isinstance(argrepr, str) and argrepr.startswith("NULL + "):
|
||||
argrepr = argrepr[7:]
|
||||
if isinstance(argrepr, str) and argrepr.endswith("+ NULL"):
|
||||
argrepr = argrepr[:-7]
|
||||
return _MsgPart(line, tok if tok is not None else dec(instruction, argrepr))
|
||||
|
||||
def _next_instruction_to_str(self, line_to_contents):
|
||||
|
|
|
@ -1140,7 +1140,8 @@ def internal_get_next_statement_targets(dbg, seq, thread_id, frame_id):
|
|||
xml += "<line>%d</line>" % (frame.f_lineno,)
|
||||
else:
|
||||
for _, line in linestarts:
|
||||
xml += "<line>%d</line>" % (line,)
|
||||
if line is not None:
|
||||
xml += "<line>%d</line>" % (line,)
|
||||
del frame
|
||||
xml += "</xml>"
|
||||
cmd = dbg.cmd_factory.make_get_next_statement_targets_message(seq, xml)
|
||||
|
@ -1342,9 +1343,10 @@ def internal_evaluate_expression(dbg, seq, thread_id, frame_id, expression, is_e
|
|||
dbg.writer.add_command(cmd)
|
||||
|
||||
|
||||
def _set_expression_response(py_db, request, result, error_message):
|
||||
body = pydevd_schema.SetExpressionResponseBody(result="", variablesReference=0)
|
||||
variables_response = pydevd_base_schema.build_response(request, kwargs={"body": body, "success": False, "message": error_message})
|
||||
def _set_expression_response(py_db, request, error_message):
|
||||
body = pydevd_schema.SetExpressionResponseBody(value='')
|
||||
variables_response = pydevd_base_schema.build_response(request, kwargs={
|
||||
'body':body, 'success':False, 'message': error_message})
|
||||
py_db.writer.add_command(NetCommand(CMD_RETURN, 0, variables_response, is_json=True))
|
||||
|
||||
|
||||
|
@ -1360,19 +1362,18 @@ def internal_set_expression_json(py_db, request, thread_id):
|
|||
fmt = fmt.to_dict()
|
||||
|
||||
frame = py_db.find_frame(thread_id, frame_id)
|
||||
exec_code = "%s = (%s)" % (expression, value)
|
||||
result = pydevd_vars.evaluate_expression(py_db, frame, exec_code, is_exec=True)
|
||||
is_error = isinstance(result, ExceptionOnEvaluate)
|
||||
|
||||
if is_error:
|
||||
_set_expression_response(py_db, request, result, error_message="Error executing: %s" % (exec_code,))
|
||||
exec_code = '%s = (%s)' % (expression, value)
|
||||
try:
|
||||
pydevd_vars.evaluate_expression(py_db, frame, exec_code, is_exec=True)
|
||||
except (Exception, KeyboardInterrupt):
|
||||
_set_expression_response(py_db, request, error_message='Error executing: %s' % (exec_code,))
|
||||
return
|
||||
|
||||
# Ok, we have the result (could be an error), let's put it into the saved variables.
|
||||
frame_tracker = py_db.suspended_frames_manager.get_frame_tracker(thread_id)
|
||||
if frame_tracker is None:
|
||||
# This is not really expected.
|
||||
_set_expression_response(py_db, request, result, error_message="Thread id: %s is not current thread id." % (thread_id,))
|
||||
_set_expression_response(py_db, request, error_message='Thread id: %s is not current thread id.' % (thread_id,))
|
||||
return
|
||||
|
||||
# Now that the exec is done, get the actual value changed to return.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""
|
||||
This module holds the constants used for specifying the states of the debugger.
|
||||
"""
|
||||
|
||||
from __future__ import nested_scopes
|
||||
import platform
|
||||
import weakref
|
||||
|
@ -176,6 +177,13 @@ IS_PY312_OR_GREATER = sys.version_info >= (3, 12)
|
|||
IS_PY313_OR_GREATER = sys.version_info >= (3, 13)
|
||||
IS_PY314_OR_GREATER = sys.version_info >= (3, 14)
|
||||
|
||||
# Bug affecting Python 3.13.0 specifically makes some tests crash the interpreter!
|
||||
# Hopefully it'll be fixed in 3.13.1.
|
||||
IS_PY313_0 = sys.version_info[:3] == (3, 13, 0)
|
||||
|
||||
# Mark tests that need to be fixed with this.
|
||||
TODO_PY313_OR_GREATER = IS_PY313_OR_GREATER
|
||||
|
||||
# Not currently supported in Python 3.14.
|
||||
SUPPORT_ATTACH_TO_PID = not IS_PY314_OR_GREATER
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ def _patch_threading_to_hide_pydevd_threads():
|
|||
{"_active_limbo_lock", "_limbo", "_active", "values", "list"},
|
||||
{"_active_limbo_lock", "_limbo", "_active", "values", "NULL + list"},
|
||||
{"NULL + list", "_active", "_active_limbo_lock", "NULL|self + values", "_limbo"},
|
||||
{'_active_limbo_lock', 'values + NULL|self', '_limbo', '_active', 'list + NULL'},
|
||||
):
|
||||
pydev_log.debug("Applying patching to hide pydevd threads (Py3 version).")
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from _pydevd_bundle.pydevd_constants import EXCEPTION_TYPE_USER_UNHANDLED, EXCEPTION_TYPE_UNHANDLED, IS_PY311_OR_GREATER
|
||||
from _pydevd_bundle.pydevd_constants import EXCEPTION_TYPE_USER_UNHANDLED, EXCEPTION_TYPE_UNHANDLED, IS_PY311_OR_GREATER, IS_PY313_0
|
||||
from _pydev_bundle import pydev_log
|
||||
import itertools
|
||||
from typing import Any, Dict
|
||||
|
@ -34,47 +34,50 @@ def add_exception_to_frame(frame, exception_info):
|
|||
|
||||
|
||||
def remove_exception_from_frame(frame):
|
||||
# In 3.13 frame.f_locals became a proxy for a dict, so we need to copy it to a real dict
|
||||
# so we can call the defined update method. Just deleting the entry throws in 3.13.
|
||||
items = {key: value for key, value in frame.f_locals.items()}
|
||||
if "__exception__" in items:
|
||||
del items["__exception__"]
|
||||
frame.f_locals.update(items)
|
||||
if IS_PY313_0:
|
||||
# In 3.13.0 frame.f_locals became a proxy for a dict, It does not
|
||||
# have methods to allow items to be removed, only added. So just set the item to None.
|
||||
# Should be fixed in 3.13.1 in PR: https://github.com/python/cpython/pull/125616
|
||||
frame.f_locals["__exception__"] = None
|
||||
else:
|
||||
frame.f_locals.pop("__exception__", None)
|
||||
|
||||
|
||||
FILES_WITH_IMPORT_HOOKS = ["pydev_monkey_qt.py", "pydev_import_hook.py"]
|
||||
|
||||
|
||||
|
||||
def just_raised(trace):
|
||||
if trace is None:
|
||||
return False
|
||||
|
||||
|
||||
return trace.tb_next is None
|
||||
|
||||
|
||||
def short_tb(exc_tb):
|
||||
traceback = []
|
||||
while exc_tb:
|
||||
traceback.append('{%r, %r, %r}' % (exc_tb.tb_frame.f_code.co_filename,
|
||||
exc_tb.tb_frame.f_code.co_name,
|
||||
exc_tb.tb_lineno))
|
||||
traceback.append("{%r, %r, %r}" % (exc_tb.tb_frame.f_code.co_filename, exc_tb.tb_frame.f_code.co_name, exc_tb.tb_lineno))
|
||||
exc_tb = exc_tb.tb_next
|
||||
return 'Traceback: %s\n' % (' -> '.join(traceback))
|
||||
return "Traceback: %s\n" % (" -> ".join(traceback))
|
||||
|
||||
|
||||
def short_frame(frame):
|
||||
if frame is None:
|
||||
return 'None'
|
||||
|
||||
return "None"
|
||||
|
||||
filename = frame.f_code.co_filename
|
||||
name = splitext(basename(filename))[0]
|
||||
return '%s::%s %s' % (name, frame.f_code.co_name, frame.f_lineno)
|
||||
line = hasattr(frame, "f_lineno") and frame.f_lineno or 1
|
||||
return "%s::%s %s" % (name, frame.f_code.co_name, line)
|
||||
|
||||
|
||||
def short_stack(frame):
|
||||
stack = []
|
||||
while frame:
|
||||
stack.append(short_frame(frame))
|
||||
frame = frame.f_back
|
||||
return 'Stack: %s\n' % (' -> '.join(stack))
|
||||
frame = frame.f_back if hasattr(frame, "f_back") else None
|
||||
return "Stack: %s\n" % (" -> ".join(stack))
|
||||
|
||||
|
||||
def ignore_exception_trace(trace):
|
||||
while trace is not None:
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
Utility for saving locals.
|
||||
"""
|
||||
import sys
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY313_OR_GREATER
|
||||
from _pydev_bundle import pydev_log
|
||||
|
||||
try:
|
||||
import types
|
||||
|
@ -54,6 +56,11 @@ def make_save_locals_impl():
|
|||
|
||||
return save_locals_pypy_impl
|
||||
|
||||
if IS_PY313_OR_GREATER:
|
||||
# No longer needed in Python 3.13 (deprecated)
|
||||
# See PEP 667
|
||||
return None
|
||||
|
||||
try:
|
||||
import ctypes
|
||||
|
||||
|
@ -108,8 +115,16 @@ def update_globals_and_locals(updated_globals, initial_globals, frame):
|
|||
for key in removed:
|
||||
try:
|
||||
del f_locals[key]
|
||||
except KeyError:
|
||||
pass
|
||||
except Exception:
|
||||
# Python 3.13.0 has issues here:
|
||||
# https://github.com/python/cpython/pull/125616
|
||||
# This should be backported from the pull request
|
||||
# but we still need to handle it in this version
|
||||
try:
|
||||
if key in f_locals:
|
||||
f_locals[key] = None
|
||||
except Exception as e:
|
||||
pydev_log.info('Unable to remove key: %s from locals. Exception: %s', key, e)
|
||||
|
||||
if f_locals is not None:
|
||||
save_locals(frame)
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
Copyright (c) 2016 Red Hat.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1 @@
|
|||
pip
|
|
@ -0,0 +1,77 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: bytecode
|
||||
Version: 0.13.0.dev0
|
||||
Summary: Python module to generate and modify bytecode
|
||||
Home-page: https://github.com/MatthieuDartiailh/bytecode
|
||||
Author: Victor Stinner
|
||||
Author-email: victor.stinner@gmail.com
|
||||
Maintainer: Matthieu C. Dartiailh
|
||||
Maintainer-email: m.dartiailh@gmail.com
|
||||
License: MIT license
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Requires-Python: >=3.6
|
||||
|
||||
********
|
||||
bytecode
|
||||
********
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/bytecode.svg
|
||||
:alt: Latest release on the Python Cheeseshop (PyPI)
|
||||
:target: https://pypi.python.org/pypi/bytecode
|
||||
|
||||
.. image:: https://github.com/MatthieuDartiailh/bytecode/workflows/Continuous%20Integration/badge.svg
|
||||
:target: https://github.com/MatthieuDartiailh/bytecode/actions
|
||||
:alt: Continuous integration
|
||||
|
||||
.. image:: https://github.com/MatthieuDartiailh/bytecode/workflows/Documentation%20building/badge.svg
|
||||
:target: https://github.com/MatthieuDartiailh/bytecode/actions
|
||||
:alt: Documentation building
|
||||
|
||||
.. image:: https://img.shields.io/codecov/c/github/MatthieuDartiailh/bytecode/master.svg
|
||||
:alt: Code coverage of bytecode on codecov.io
|
||||
:target: https://codecov.io/github/MatthieuDartiailh/bytecode
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:alt: Code formatted using Black
|
||||
:target: https://github.com/psf/black
|
||||
|
||||
``bytecode`` is a Python module to generate and modify bytecode.
|
||||
|
||||
* `bytecode project homepage at GitHub
|
||||
<https://github.com/MatthieuDartiailh/bytecode>`_ (code, bugs)
|
||||
* `bytecode documentation
|
||||
<https://bytecode.readthedocs.io/>`_
|
||||
* `Download latest bytecode release at the Python Cheeseshop (PyPI)
|
||||
<https://pypi.python.org/pypi/bytecode>`_
|
||||
|
||||
Install bytecode: ``python3 -m pip install bytecode``. It requires Python 3.6
|
||||
or newer. The latest release that supports Python 3.5 is 0.12.0. For Python 2.7
|
||||
support, have a look at `dead-bytecode
|
||||
<https://github.com/p403n1x87/dead-bytecode>`_ instead.
|
||||
|
||||
Example executing ``print('Hello World!')``:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from bytecode import Instr, Bytecode
|
||||
|
||||
bytecode = Bytecode([Instr("LOAD_NAME", 'print'),
|
||||
Instr("LOAD_CONST", 'Hello World!'),
|
||||
Instr("CALL_FUNCTION", 1),
|
||||
Instr("POP_TOP"),
|
||||
Instr("LOAD_CONST", None),
|
||||
Instr("RETURN_VALUE")])
|
||||
code = bytecode.to_code()
|
||||
exec(code)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
bytecode-0.13.0.dev0.dist-info/COPYING,sha256=baWkm-Te2LLURwK7TL0zOkMSVjVCU_ezvObHBo298Tk,1074
|
||||
bytecode-0.13.0.dev0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
bytecode-0.13.0.dev0.dist-info/METADATA,sha256=9XadDK6YTQ-FPowYI5DS4ieA7hRGnRP_fM5Z9ioPkEQ,2929
|
||||
bytecode-0.13.0.dev0.dist-info/RECORD,,
|
||||
bytecode-0.13.0.dev0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
bytecode-0.13.0.dev0.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
|
||||
bytecode-0.13.0.dev0.dist-info/direct_url.json,sha256=s58Rb4KXRlMKxk-mzpvr_tJRQ-Hx8-DHsU6NdohCnAg,93
|
||||
bytecode-0.13.0.dev0.dist-info/top_level.txt,sha256=9BhdB7HqYZ-PvHNoWX6ilwLYWQqcgEOLwdb3aXm5Gys,9
|
||||
bytecode/__init__.py,sha256=d-yk4Xh4SwOWq9NgoD2rmBLG6RhUFNljeqs-NjMNSYM,3885
|
||||
bytecode/__pycache__/__init__.cpython-38.pyc,,
|
||||
bytecode/__pycache__/bytecode.cpython-38.pyc,,
|
||||
bytecode/__pycache__/cfg.cpython-38.pyc,,
|
||||
bytecode/__pycache__/concrete.cpython-38.pyc,,
|
||||
bytecode/__pycache__/flags.cpython-38.pyc,,
|
||||
bytecode/__pycache__/instr.cpython-38.pyc,,
|
||||
bytecode/__pycache__/peephole_opt.cpython-38.pyc,,
|
||||
bytecode/bytecode.py,sha256=IMCcatHMtQ7M31nwj4r3drcvQuGVJAOP0d7C0O8P_SE,6894
|
||||
bytecode/cfg.py,sha256=RmJGJqwCxR-XYaPH9YGY4wNDycdtLvIBJb1OGSmxcN0,15274
|
||||
bytecode/concrete.py,sha256=0eb6Yh_NDLmzJNcMs2TFom0EqFVSM1cO3inMH90YE-s,21683
|
||||
bytecode/flags.py,sha256=hAvM_B2yQKRw44leHP0oCae0aaJraAbDDTpqIf4I1CM,5987
|
||||
bytecode/instr.py,sha256=HYc65LjNSOB3GCWkNkCSkee1rRzUyr89rgdjbKBaTpE,11616
|
||||
bytecode/peephole_opt.py,sha256=W-cFVPOZN-JKfDV3aImsYenDSZkSNBDTVQqeMrGPU18,15712
|
||||
bytecode/tests/__init__.py,sha256=BAdOXXNRdMVX4D8TuRYPlG9PHU7Cb0bzvyfA9s435kM,4968
|
||||
bytecode/tests/__pycache__/__init__.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/test_bytecode.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/test_cfg.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/test_code.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/test_concrete.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/test_flags.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/test_instr.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/test_misc.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/test_peephole_opt.cpython-38.pyc,,
|
||||
bytecode/tests/__pycache__/util_annotation.cpython-38.pyc,,
|
||||
bytecode/tests/test_bytecode.py,sha256=buvtlDC0NwoQ3zuZ7OENIIDngSqtiO9WkAa2-UvxGkI,15584
|
||||
bytecode/tests/test_cfg.py,sha256=c0xT8OfV-mDHu-DIDWr6LVlZQyK4GfgLSmT5AsodbMk,28194
|
||||
bytecode/tests/test_code.py,sha256=XCOH29rOXSoQz130s-AIC62r23e9qNjk8Y2xDB2LmSc,2100
|
||||
bytecode/tests/test_concrete.py,sha256=qT2qvabkF0yC7inniNx53cMSDN-2Qi0IE3pwBZSzF8g,49253
|
||||
bytecode/tests/test_flags.py,sha256=DY9U3c6tJdxJFm0jEm_To1Cc0I99EidQv_0guud-4oE,5684
|
||||
bytecode/tests/test_instr.py,sha256=rYeF8u-L0aW8bLPBxTUSy_T7KP6SaXyJKv9OhC8k6aA,11295
|
||||
bytecode/tests/test_misc.py,sha256=wyK1wpVPHRfaXgo-EqUI-F1nyB9-UACerHsHbExAo1U,6758
|
||||
bytecode/tests/test_peephole_opt.py,sha256=niUfhgEbiFR7IAmdQ_N9Qgh7D3wdRQ_zS0V8mKC4EzI,32640
|
||||
bytecode/tests/util_annotation.py,sha256=wKq6yPWrzkNlholl5Y10b3VjuCkoiYVgvcIjk_8jzf8,485
|
|
@ -0,0 +1,5 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.36.2)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"archive_info": {}, "url": "https://github.com/MatthieuDartiailh/bytecode/archive/main.zip"}
|
|
@ -0,0 +1 @@
|
|||
bytecode
|
|
@ -13,9 +13,9 @@ from typing import Dict, Optional, Tuple, Any
|
|||
from os.path import basename, splitext
|
||||
|
||||
from _pydev_bundle import pydev_log
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
from _pydevd_bundle import pydevd_dont_trace
|
||||
from _pydevd_bundle.pydevd_constants import (
|
||||
IS_PY313_OR_GREATER,
|
||||
GlobalDebuggerHolder,
|
||||
ForkSafeLock,
|
||||
PYDEVD_IPYTHON_CONTEXT,
|
||||
|
@ -33,7 +33,7 @@ from _pydevd_bundle.pydevd_constants import EXCEPTION_TYPE_HANDLED
|
|||
from _pydevd_bundle.pydevd_trace_dispatch import is_unhandled_exception
|
||||
from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception
|
||||
from _pydevd_bundle.pydevd_utils import get_clsname_for_code
|
||||
from _pydevd_bundle.pydevd_dont_trace_files import PYDEV_FILE
|
||||
|
||||
|
||||
# fmt: off
|
||||
# IFDEF CYTHON
|
||||
|
@ -60,10 +60,8 @@ _thread_local_info = threading.local()
|
|||
_get_ident = threading.get_ident
|
||||
_thread_active = threading._active # noqa
|
||||
|
||||
STATE_SUSPEND: int = 2
|
||||
CMD_STEP_INTO: int = 107
|
||||
CMD_STEP_OVER: int = 108
|
||||
CMD_STEP_OVER_MY_CODE: int = 159
|
||||
CMD_STEP_INTO_MY_CODE: int = 144
|
||||
CMD_STEP_INTO_COROUTINE: int = 206
|
||||
CMD_SMART_STEP_INTO: int = 128
|
||||
|
@ -236,6 +234,7 @@ def _get_unhandled_exception_frame(exc, depth: int) -> Optional[FrameType]:
|
|||
# cdef PyDBAdditionalThreadInfo additional_info
|
||||
# thread: threading.Thread
|
||||
# trace: bool
|
||||
# _use_is_stopped: bool
|
||||
# ELSE
|
||||
class ThreadInfo:
|
||||
additional_info: PyDBAdditionalThreadInfo
|
||||
|
@ -256,6 +255,19 @@ class ThreadInfo:
|
|||
self.thread_ident = thread_ident
|
||||
self.additional_info = additional_info
|
||||
self.trace = trace
|
||||
self._use_is_stopped = hasattr(thread, '_is_stopped')
|
||||
|
||||
# fmt: off
|
||||
# IFDEF CYTHON
|
||||
# cdef bint is_thread_alive(self):
|
||||
# ELSE
|
||||
def is_thread_alive(self):
|
||||
# ENDIF
|
||||
# fmt: on
|
||||
if self._use_is_stopped:
|
||||
return not self.thread._is_stopped
|
||||
else:
|
||||
return not self.thread._handle.is_done()
|
||||
|
||||
|
||||
class _DeleteDummyThreadOnDel:
|
||||
|
@ -319,7 +331,7 @@ def _create_thread_info(depth):
|
|||
if t is None:
|
||||
t = _thread_active.get(thread_ident)
|
||||
|
||||
if isinstance(t, threading._DummyThread):
|
||||
if isinstance(t, threading._DummyThread) and not IS_PY313_OR_GREATER:
|
||||
_thread_local_info._ref = _DeleteDummyThreadOnDel(t)
|
||||
|
||||
if t is None:
|
||||
|
@ -406,8 +418,9 @@ class FuncCodeInfo:
|
|||
|
||||
def get_line_of_offset(self, offset):
|
||||
for start, end, line in self.code_obj.co_lines():
|
||||
if offset >= start and offset <= end:
|
||||
return line
|
||||
if start is not None and end is not None and line is not None:
|
||||
if offset >= start and offset <= end:
|
||||
return line
|
||||
return -1
|
||||
|
||||
|
||||
|
@ -438,15 +451,41 @@ def _get_thread_info(create: bool, depth: int) -> Optional[ThreadInfo]:
|
|||
return _thread_local_info.thread_info
|
||||
|
||||
|
||||
_CodeLineInfo = namedtuple("_CodeLineInfo", "line_to_offset, first_line, last_line")
|
||||
# fmt: off
|
||||
# IFDEF CYTHON
|
||||
# cdef class _CodeLineInfo:
|
||||
# cdef dict line_to_offset
|
||||
# cdef int first_line
|
||||
# cdef int last_line
|
||||
# ELSE
|
||||
class _CodeLineInfo:
|
||||
line_to_offset: Dict[int, Any]
|
||||
first_line: int
|
||||
last_line: int
|
||||
# ENDIF
|
||||
# fmt: on
|
||||
|
||||
# fmt: off
|
||||
# IFDEF CYTHON
|
||||
# def __init__(self, dict line_to_offset, int first_line, int last_line):
|
||||
# self.line_to_offset = line_to_offset
|
||||
# self.first_line = first_line
|
||||
# self.last_line = last_line
|
||||
# ELSE
|
||||
def __init__(self, line_to_offset, first_line, last_line):
|
||||
self.line_to_offset = line_to_offset
|
||||
self.first_line = first_line
|
||||
self.last_line = last_line
|
||||
|
||||
# ENDIF
|
||||
# fmt: on
|
||||
|
||||
# Note: this method has a version in cython too
|
||||
# fmt: off
|
||||
# IFDEF CYTHON
|
||||
# cdef _get_code_line_info(code_obj, _cache={}):
|
||||
# cdef _CodeLineInfo _get_code_line_info(code_obj, _cache={}):
|
||||
# ELSE
|
||||
def _get_code_line_info(code_obj, _cache={}):
|
||||
def _get_code_line_info(code_obj, _cache={}) -> _CodeLineInfo:
|
||||
# ENDIF
|
||||
# fmt: on
|
||||
try:
|
||||
|
@ -834,16 +873,16 @@ def _unwind_event(code, instruction, exc):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
||||
|
||||
func_code_info: FuncCodeInfo = _get_func_code_info(code, 1)
|
||||
if func_code_info.always_skip_code:
|
||||
return
|
||||
|
||||
# pydev_log.debug('_unwind_event', code, exc)
|
||||
|
||||
# print('_unwind_event', code, exc)
|
||||
frame = _getframe(1)
|
||||
arg = (type(exc), exc, exc.__traceback__)
|
||||
|
||||
|
@ -868,7 +907,6 @@ def _unwind_event(code, instruction, exc):
|
|||
)
|
||||
|
||||
if is_unhandled:
|
||||
# print('stop in user uncaught')
|
||||
handle_exception(py_db, thread_info.thread, frame, user_uncaught_exc_info[0], EXCEPTION_TYPE_USER_UNHANDLED)
|
||||
return
|
||||
|
||||
|
@ -904,12 +942,12 @@ def _raise_event(code, instruction, exc):
|
|||
thread_info = _get_thread_info(True, 1)
|
||||
if thread_info is None:
|
||||
return
|
||||
|
||||
|
||||
py_db: object = GlobalDebuggerHolder.global_dbg
|
||||
if py_db is None or py_db.pydb_disposed:
|
||||
return
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
@ -920,7 +958,6 @@ def _raise_event(code, instruction, exc):
|
|||
|
||||
frame = _getframe(1)
|
||||
arg = (type(exc), exc, exc.__traceback__)
|
||||
# pydev_log.debug('_raise_event', code, exc)
|
||||
|
||||
# Compute the previous exception info (if any). We use it to check if the exception
|
||||
# should be stopped
|
||||
|
@ -1025,7 +1062,7 @@ def _return_event(code, instruction, retval):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
@ -1340,7 +1377,7 @@ def _jump_event(code, from_offset, to_offset):
|
|||
if hasattr(_thread_local_info, "f_disable_next_line_if_match"):
|
||||
del _thread_local_info.f_disable_next_line_if_match
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
@ -1358,7 +1395,6 @@ def _jump_event(code, from_offset, to_offset):
|
|||
|
||||
from_line = func_code_info.get_line_of_offset(from_offset or 0)
|
||||
to_line = func_code_info.get_line_of_offset(to_offset or 0)
|
||||
# print('jump event', code.co_name, 'from line', from_line, 'to line', to_line)
|
||||
|
||||
if from_line != to_line:
|
||||
# I.e.: use case: "yield from [j for j in a if j % 2 == 0]"
|
||||
|
@ -1369,6 +1405,7 @@ def _jump_event(code, from_offset, to_offset):
|
|||
|
||||
# Disable the next line event as we're jumping to a line. The line event will be redundant.
|
||||
_thread_local_info.f_disable_next_line_if_match = (func_code_info.co_filename, frame.f_lineno)
|
||||
# pydev_log.debug('_jump_event', code.co_name, 'from line', from_line, 'to line', frame.f_lineno)
|
||||
|
||||
return _internal_line_event(func_code_info, frame, frame.f_lineno)
|
||||
|
||||
|
@ -1397,24 +1434,26 @@ def _line_event(code, line):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
||||
# If we get another line event, remove the extra check for the line event
|
||||
if hasattr(_thread_local_info, "f_disable_next_line_if_match"):
|
||||
(co_filename, line_to_skip) = _thread_local_info.f_disable_next_line_if_match
|
||||
del _thread_local_info.f_disable_next_line_if_match
|
||||
if line_to_skip is line and co_filename == code.co_filename:
|
||||
# If we're in a jump, we should skip this line event. The jump would have
|
||||
# been considered a line event for this same line and we don't want to
|
||||
# The last jump already jumped to this line and we haven't had any
|
||||
# line events or jumps since then. We don't want to consider this line twice
|
||||
# pydev_log.debug('_line_event skipped', line)
|
||||
return
|
||||
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
||||
func_code_info: FuncCodeInfo = _get_func_code_info(code, 1)
|
||||
if func_code_info.always_skip_code or func_code_info.always_filtered_out:
|
||||
return monitor.DISABLE
|
||||
|
||||
# print('line event', code.co_name, line)
|
||||
# pydev_log.debug('_line_event', code.co_name, line)
|
||||
|
||||
# We know the frame depth.
|
||||
frame = _getframe(1)
|
||||
|
@ -1644,7 +1683,7 @@ def _start_method_event(code, instruction_offset):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
@ -1841,7 +1880,10 @@ def update_monitor_events(suspend_requested: Optional[bool] = None) -> None:
|
|||
monitor.register_callback(DEBUGGER_ID, monitor.events.PY_START, _start_method_event)
|
||||
# monitor.register_callback(DEBUGGER_ID, monitor.events.PY_RESUME, _resume_method_event)
|
||||
monitor.register_callback(DEBUGGER_ID, monitor.events.LINE, _line_event)
|
||||
monitor.register_callback(DEBUGGER_ID, monitor.events.JUMP, _jump_event)
|
||||
if not IS_PY313_OR_GREATER:
|
||||
# In Python 3.13+ jump_events aren't necessary as we have a line_event for every
|
||||
# jump location.
|
||||
monitor.register_callback(DEBUGGER_ID, monitor.events.JUMP, _jump_event)
|
||||
monitor.register_callback(DEBUGGER_ID, monitor.events.PY_RETURN, _return_event)
|
||||
|
||||
else:
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -19,9 +19,9 @@ from typing import Dict, Optional, Tuple, Any
|
|||
from os.path import basename, splitext
|
||||
|
||||
from _pydev_bundle import pydev_log
|
||||
from _pydev_bundle.pydev_is_thread_alive import is_thread_alive
|
||||
from _pydevd_bundle import pydevd_dont_trace
|
||||
from _pydevd_bundle.pydevd_constants import (
|
||||
IS_PY313_OR_GREATER,
|
||||
GlobalDebuggerHolder,
|
||||
ForkSafeLock,
|
||||
PYDEVD_IPYTHON_CONTEXT,
|
||||
|
@ -39,7 +39,7 @@ from _pydevd_bundle.pydevd_constants import EXCEPTION_TYPE_HANDLED
|
|||
from _pydevd_bundle.pydevd_trace_dispatch import is_unhandled_exception
|
||||
from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception
|
||||
from _pydevd_bundle.pydevd_utils import get_clsname_for_code
|
||||
from _pydevd_bundle.pydevd_dont_trace_files import PYDEV_FILE
|
||||
|
||||
|
||||
# fmt: off
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
|
@ -66,10 +66,8 @@ _thread_local_info = threading.local()
|
|||
_get_ident = threading.get_ident
|
||||
_thread_active = threading._active # noqa
|
||||
|
||||
STATE_SUSPEND: int = 2
|
||||
CMD_STEP_INTO: int = 107
|
||||
CMD_STEP_OVER: int = 108
|
||||
CMD_STEP_OVER_MY_CODE: int = 159
|
||||
CMD_STEP_INTO_MY_CODE: int = 144
|
||||
CMD_STEP_INTO_COROUTINE: int = 206
|
||||
CMD_SMART_STEP_INTO: int = 128
|
||||
|
@ -242,6 +240,7 @@ cdef class ThreadInfo:
|
|||
cdef PyDBAdditionalThreadInfo additional_info
|
||||
thread: threading.Thread
|
||||
trace: bool
|
||||
_use_is_stopped: bool
|
||||
# ELSE
|
||||
# class ThreadInfo:
|
||||
# additional_info: PyDBAdditionalThreadInfo
|
||||
|
@ -262,6 +261,19 @@ cdef class ThreadInfo:
|
|||
self.thread_ident = thread_ident
|
||||
self.additional_info = additional_info
|
||||
self.trace = trace
|
||||
self._use_is_stopped = hasattr(thread, '_is_stopped')
|
||||
|
||||
# fmt: off
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
cdef bint is_thread_alive(self):
|
||||
# ELSE
|
||||
# def is_thread_alive(self):
|
||||
# ENDIF
|
||||
# fmt: on
|
||||
if self._use_is_stopped:
|
||||
return not self.thread._is_stopped
|
||||
else:
|
||||
return not self.thread._handle.is_done()
|
||||
|
||||
|
||||
class _DeleteDummyThreadOnDel:
|
||||
|
@ -325,7 +337,7 @@ cdef _create_thread_info(depth):
|
|||
if t is None:
|
||||
t = _thread_active.get(thread_ident)
|
||||
|
||||
if isinstance(t, threading._DummyThread):
|
||||
if isinstance(t, threading._DummyThread) and not IS_PY313_OR_GREATER:
|
||||
_thread_local_info._ref = _DeleteDummyThreadOnDel(t)
|
||||
|
||||
if t is None:
|
||||
|
@ -412,8 +424,9 @@ cdef class FuncCodeInfo:
|
|||
|
||||
def get_line_of_offset(self, offset):
|
||||
for start, end, line in self.code_obj.co_lines():
|
||||
if offset >= start and offset <= end:
|
||||
return line
|
||||
if start is not None and end is not None and line is not None:
|
||||
if offset >= start and offset <= end:
|
||||
return line
|
||||
return -1
|
||||
|
||||
|
||||
|
@ -444,15 +457,41 @@ cdef _get_thread_info(bint create, int depth):
|
|||
return _thread_local_info.thread_info
|
||||
|
||||
|
||||
_CodeLineInfo = namedtuple("_CodeLineInfo", "line_to_offset, first_line, last_line")
|
||||
# fmt: off
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
cdef class _CodeLineInfo:
|
||||
cdef dict line_to_offset
|
||||
cdef int first_line
|
||||
cdef int last_line
|
||||
# ELSE
|
||||
# class _CodeLineInfo:
|
||||
# line_to_offset: Dict[int, Any]
|
||||
# first_line: int
|
||||
# last_line: int
|
||||
# ENDIF
|
||||
# fmt: on
|
||||
|
||||
# fmt: off
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
def __init__(self, dict line_to_offset, int first_line, int last_line):
|
||||
self.line_to_offset = line_to_offset
|
||||
self.first_line = first_line
|
||||
self.last_line = last_line
|
||||
# ELSE
|
||||
# def __init__(self, line_to_offset, first_line, last_line):
|
||||
# self.line_to_offset = line_to_offset
|
||||
# self.first_line = first_line
|
||||
# self.last_line = last_line
|
||||
#
|
||||
# ENDIF
|
||||
# fmt: on
|
||||
|
||||
# Note: this method has a version in cython too
|
||||
# fmt: off
|
||||
# IFDEF CYTHON -- DONT EDIT THIS FILE (it is automatically generated)
|
||||
cdef _get_code_line_info(code_obj, _cache={}):
|
||||
cdef _CodeLineInfo _get_code_line_info(code_obj, _cache={}):
|
||||
# ELSE
|
||||
# def _get_code_line_info(code_obj, _cache={}):
|
||||
# def _get_code_line_info(code_obj, _cache={}) -> _CodeLineInfo:
|
||||
# ENDIF
|
||||
# fmt: on
|
||||
try:
|
||||
|
@ -840,16 +879,16 @@ cdef _unwind_event(code, instruction, exc):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
||||
|
||||
func_code_info: FuncCodeInfo = _get_func_code_info(code, 1)
|
||||
if func_code_info.always_skip_code:
|
||||
return
|
||||
|
||||
# pydev_log.debug('_unwind_event', code, exc)
|
||||
|
||||
# print('_unwind_event', code, exc)
|
||||
frame = _getframe(1)
|
||||
arg = (type(exc), exc, exc.__traceback__)
|
||||
|
||||
|
@ -874,7 +913,6 @@ cdef _unwind_event(code, instruction, exc):
|
|||
)
|
||||
|
||||
if is_unhandled:
|
||||
# print('stop in user uncaught')
|
||||
handle_exception(py_db, thread_info.thread, frame, user_uncaught_exc_info[0], EXCEPTION_TYPE_USER_UNHANDLED)
|
||||
return
|
||||
|
||||
|
@ -910,12 +948,12 @@ cdef _raise_event(code, instruction, exc):
|
|||
thread_info = _get_thread_info(True, 1)
|
||||
if thread_info is None:
|
||||
return
|
||||
|
||||
|
||||
py_db: object = GlobalDebuggerHolder.global_dbg
|
||||
if py_db is None or py_db.pydb_disposed:
|
||||
return
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
@ -926,7 +964,6 @@ cdef _raise_event(code, instruction, exc):
|
|||
|
||||
frame = _getframe(1)
|
||||
arg = (type(exc), exc, exc.__traceback__)
|
||||
# pydev_log.debug('_raise_event', code, exc)
|
||||
|
||||
# Compute the previous exception info (if any). We use it to check if the exception
|
||||
# should be stopped
|
||||
|
@ -1031,7 +1068,7 @@ cdef _return_event(code, instruction, retval):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
@ -1346,7 +1383,7 @@ cdef _jump_event(code, int from_offset, int to_offset):
|
|||
if hasattr(_thread_local_info, "f_disable_next_line_if_match"):
|
||||
del _thread_local_info.f_disable_next_line_if_match
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
@ -1364,7 +1401,6 @@ cdef _jump_event(code, int from_offset, int to_offset):
|
|||
|
||||
from_line = func_code_info.get_line_of_offset(from_offset or 0)
|
||||
to_line = func_code_info.get_line_of_offset(to_offset or 0)
|
||||
# print('jump event', code.co_name, 'from line', from_line, 'to line', to_line)
|
||||
|
||||
if from_line != to_line:
|
||||
# I.e.: use case: "yield from [j for j in a if j % 2 == 0]"
|
||||
|
@ -1375,6 +1411,7 @@ cdef _jump_event(code, int from_offset, int to_offset):
|
|||
|
||||
# Disable the next line event as we're jumping to a line. The line event will be redundant.
|
||||
_thread_local_info.f_disable_next_line_if_match = (func_code_info.co_filename, frame.f_lineno)
|
||||
# pydev_log.debug('_jump_event', code.co_name, 'from line', from_line, 'to line', frame.f_lineno)
|
||||
|
||||
return _internal_line_event(func_code_info, frame, frame.f_lineno)
|
||||
|
||||
|
@ -1403,24 +1440,26 @@ cdef _line_event(code, int line):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
||||
# If we get another line event, remove the extra check for the line event
|
||||
if hasattr(_thread_local_info, "f_disable_next_line_if_match"):
|
||||
(co_filename, line_to_skip) = _thread_local_info.f_disable_next_line_if_match
|
||||
del _thread_local_info.f_disable_next_line_if_match
|
||||
if line_to_skip is line and co_filename == code.co_filename:
|
||||
# If we're in a jump, we should skip this line event. The jump would have
|
||||
# been considered a line event for this same line and we don't want to
|
||||
# The last jump already jumped to this line and we haven't had any
|
||||
# line events or jumps since then. We don't want to consider this line twice
|
||||
# pydev_log.debug('_line_event skipped', line)
|
||||
return
|
||||
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
||||
func_code_info: FuncCodeInfo = _get_func_code_info(code, 1)
|
||||
if func_code_info.always_skip_code or func_code_info.always_filtered_out:
|
||||
return monitor.DISABLE
|
||||
|
||||
# print('line event', code.co_name, line)
|
||||
# pydev_log.debug('_line_event', code.co_name, line)
|
||||
|
||||
# We know the frame depth.
|
||||
frame = _getframe(1)
|
||||
|
@ -1650,7 +1689,7 @@ cdef _start_method_event(code, instruction_offset):
|
|||
if py_db is None or py_db.pydb_disposed:
|
||||
return monitor.DISABLE
|
||||
|
||||
if not thread_info.trace or not is_thread_alive(thread_info.thread):
|
||||
if not thread_info.trace or not thread_info.is_thread_alive():
|
||||
# For thread-related stuff we can't disable the code tracing because other
|
||||
# threads may still want it...
|
||||
return
|
||||
|
@ -1847,7 +1886,10 @@ def update_monitor_events(suspend_requested: Optional[bool] = None) -> None:
|
|||
monitor.register_callback(DEBUGGER_ID, monitor.events.PY_START, _start_method_event)
|
||||
# monitor.register_callback(DEBUGGER_ID, monitor.events.PY_RESUME, _resume_method_event)
|
||||
monitor.register_callback(DEBUGGER_ID, monitor.events.LINE, _line_event)
|
||||
monitor.register_callback(DEBUGGER_ID, monitor.events.JUMP, _jump_event)
|
||||
if not IS_PY313_OR_GREATER:
|
||||
# In Python 3.13+ jump_events aren't necessary as we have a line_event for every
|
||||
# jump location.
|
||||
monitor.register_callback(DEBUGGER_ID, monitor.events.JUMP, _jump_event)
|
||||
monitor.register_callback(DEBUGGER_ID, monitor.events.PY_RETURN, _return_event)
|
||||
|
||||
else:
|
||||
|
|
|
@ -7,6 +7,7 @@ It should:
|
|||
|
||||
Note that it's used in the CI to build the cython deps based on the PYDEVD_USE_CYTHON environment variable.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
|
@ -109,19 +110,24 @@ def build():
|
|||
# set VS100COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools
|
||||
|
||||
if "GITHUB_ACTION" not in os.environ:
|
||||
if sys.version_info[:2] in ((3, 6), (3, 7), (3, 8), (3, 9), (3, 10), (3, 11), (3, 12)):
|
||||
if sys.version_info[:2] in ((3, 6), (3, 7), (3, 8), (3, 9), (3, 10), (3, 11), (3, 12), (3, 13)):
|
||||
FORCE_PYDEVD_VC_VARS = os.environ.get("FORCE_PYDEVD_VC_VARS")
|
||||
if FORCE_PYDEVD_VC_VARS:
|
||||
env.update(get_environment_from_batch_command([FORCE_PYDEVD_VC_VARS], initial=os.environ.copy()))
|
||||
else:
|
||||
import setuptools # We have to import it first for the compiler to be found
|
||||
from distutils import msvc9compiler
|
||||
try:
|
||||
from setuptools._distutils._msvccompiler import _find_vcvarsall as find_vcvarsall
|
||||
except Exception:
|
||||
import setuptools # We have to import it first for the compiler to be found
|
||||
from distutils.msvc9compiler import find_vcvarsall
|
||||
|
||||
vcvarsall = msvc9compiler.find_vcvarsall(14.0)
|
||||
vcvarsall = find_vcvarsall(14.0)
|
||||
if isinstance(vcvarsall, tuple):
|
||||
vcvarsall = vcvarsall[0]
|
||||
if vcvarsall is None or not os.path.exists(vcvarsall):
|
||||
msvc_version = msvc9compiler.get_build_version()
|
||||
print("msvc_version", msvc_version)
|
||||
vcvarsall = msvc9compiler.find_vcvarsall(msvc_version)
|
||||
vcvarsall = find_vcvarsall(msvc_version)
|
||||
|
||||
if vcvarsall is None or not os.path.exists(vcvarsall):
|
||||
raise RuntimeError("Error finding vcvarsall.")
|
||||
|
|
|
@ -42,6 +42,17 @@ expected_differences = set(
|
|||
-static const char __pyx_k_pydevd_sys_monitoring__pydevd_s[] = "_pydevd_sys_monitoring\\_pydevd_sys_monitoring_cython.pyx";
|
||||
- ".\\\\\\\\_pydevd_bundle\\\\\\\\pydevd_cython.pxd",
|
||||
- ".\\\\_pydevd_bundle\\\\pydevd_cython.pxd",
|
||||
|
||||
- "_pydevd_sys_monitoring/_pydevd_sys_monitoring_cython.pyx",
|
||||
+ "_pydevd_sys_monitoring\\\\\\\\_pydevd_sys_monitoring_cython.pyx",
|
||||
- "./_pydevd_bundle/pydevd_cython.pxd",
|
||||
+ ".\\\\\\\\_pydevd_bundle\\\\\\\\pydevd_cython.pxd",
|
||||
-static const char __pyx_k_pydevd_sys_monitoring__pydevd_s[] = "_pydevd_sys_monitoring/_pydevd_sys_monitoring_cython.pyx";
|
||||
+static const char __pyx_k_pydevd_sys_monitoring__pydevd_s[] = "_pydevd_sys_monitoring\\\\_pydevd_sys_monitoring_cython.pyx";
|
||||
|
||||
+ "_pydevd_sys_monitoring\\\\_pydevd_sys_monitoring_cython.pyx",
|
||||
+ ".\\\\_pydevd_bundle\\\\pydevd_cython.pxd",
|
||||
+static const char __pyx_k_pydevd_sys_monitoring__pydevd_s[] = "_pydevd_sys_monitoring\\_pydevd_sys_monitoring_cython.pyx";
|
||||
""".splitlines()
|
||||
if line.strip()
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ Update cython-generated files (must update cython and then run build_tools/build
|
|||
|
||||
Create tag:
|
||||
-----------
|
||||
git tag pydev_debugger_3_1_0 -a -m "PyDev.Debugger 3.1.0"
|
||||
git tag pydev_debugger_3_2_1 -a -m "PyDev.Debugger 3.2.1"
|
||||
git push --tags
|
||||
|
||||
|
||||
|
|
|
@ -130,7 +130,6 @@ def has_binding(api):
|
|||
import importlib
|
||||
|
||||
try:
|
||||
import imp
|
||||
# importing top level PyQt4/PySide module is ok...
|
||||
mod = __import__(module_name)
|
||||
# ...importing submodules is not
|
||||
|
@ -144,13 +143,13 @@ def has_binding(api):
|
|||
return check_version(mod.__version__, "1.0.3")
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
except ModuleNotFoundError:
|
||||
from importlib import machinery
|
||||
|
||||
|
||||
# importing top level PyQt4/PySide module is ok...
|
||||
mod = __import__(module_name)
|
||||
|
||||
|
||||
# ...importing submodules is not
|
||||
loader_details = (machinery.ExtensionFileLoader, machinery.EXTENSION_SUFFIXES)
|
||||
submod_finder = machinery.FileFinder(mod.__path__[0], loader_details)
|
||||
|
@ -159,7 +158,7 @@ def has_binding(api):
|
|||
and submod_finder.find_spec("QtGui") is not None
|
||||
and submod_finder.find_spec("QtSvg") is not None
|
||||
)
|
||||
|
||||
|
||||
# we can also safely check PySide version
|
||||
if api == QT_API_PYSIDE:
|
||||
return check_version(mod.__version__, '1.0.3') and submod_check
|
||||
|
|
|
@ -3,6 +3,7 @@ Entry point module (keep at root):
|
|||
|
||||
This module starts the debugger.
|
||||
"""
|
||||
|
||||
import sys # @NoMove
|
||||
|
||||
if sys.version_info[:2] < (3, 6):
|
||||
|
@ -11,14 +12,11 @@ if sys.version_info[:2] < (3, 6):
|
|||
)
|
||||
import os
|
||||
|
||||
try:
|
||||
# Just empty packages to check if they're in the PYTHONPATH.
|
||||
import _pydev_bundle
|
||||
except ImportError:
|
||||
# On the first import of a pydevd module, add pydevd itself to the PYTHONPATH
|
||||
# if its dependencies cannot be imported.
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import _pydev_bundle
|
||||
# On the first import of a pydevd module, add pydevd itself to the PYTHONPATH
|
||||
this_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, this_dir)
|
||||
|
||||
import _pydev_bundle
|
||||
|
||||
# Import this first as it'll check for shadowed modules and will make sure that we import
|
||||
# things as needed for gevent.
|
||||
|
@ -125,7 +123,7 @@ from pydevd_file_utils import (
|
|||
get_abs_path_real_path_and_base_from_file,
|
||||
NORM_PATHS_AND_BASE_CONTAINER,
|
||||
)
|
||||
from pydevd_file_utils import get_fullname, get_package_dir, is_pydevd_path
|
||||
from pydevd_file_utils import get_fullname, get_package_dir
|
||||
from os.path import abspath as os_path_abspath
|
||||
import pydevd_tracing
|
||||
from _pydevd_bundle.pydevd_comm import InternalThreadCommand, InternalThreadCommandForAnyThread, create_server_socket, FSNotifyThread
|
||||
|
@ -175,7 +173,7 @@ if SUPPORT_GEVENT:
|
|||
if USE_CUSTOM_SYS_CURRENT_FRAMES_MAP:
|
||||
from _pydevd_bundle.pydevd_constants import constructed_tid_to_last_frame
|
||||
|
||||
__version_info__ = (3, 1, 0)
|
||||
__version_info__ = (3, 2, 2)
|
||||
__version_info_str__ = []
|
||||
for v in __version_info__:
|
||||
__version_info_str__.append(str(v))
|
||||
|
@ -1075,13 +1073,6 @@ class PyDB(object):
|
|||
return _cache_file_type[cache_key]
|
||||
except:
|
||||
if abs_real_path_and_basename[0] == "<string>":
|
||||
# Consider it an untraceable file unless there's no back frame (ignoring
|
||||
# internal files and runpy.py).
|
||||
if frame.f_back is not None and self.get_file_type(frame.f_back) == self.PYDEV_FILE and is_pydevd_path(frame.f_back.f_code.co_filename):
|
||||
# Special case, this is a string coming from pydevd itself. However we have to skip this logic for other
|
||||
# files that are also marked as PYDEV_FILE (like external files marked this way)
|
||||
return self.PYDEV_FILE
|
||||
|
||||
f = frame.f_back
|
||||
while f is not None:
|
||||
if self.get_file_type(f) != self.PYDEV_FILE and pydevd_file_utils.basename(f.f_code.co_filename) not in (
|
||||
|
@ -1099,7 +1090,7 @@ class PyDB(object):
|
|||
# to show it in the stack.
|
||||
_cache_file_type[cache_key] = LIB_FILE
|
||||
return LIB_FILE
|
||||
|
||||
|
||||
f = f.f_back
|
||||
else:
|
||||
# This is a top-level file (used in python -c), so, trace it as usual... we
|
||||
|
@ -3701,5 +3692,13 @@ def main():
|
|||
debugger.wait_for_commands(globals)
|
||||
|
||||
|
||||
try:
|
||||
# Remove the entry we added: it should no longer be needed as
|
||||
# what we need should've been imported already
|
||||
if sys.path[:1] == [this_dir]:
|
||||
sys.path.remove(this_dir)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -308,7 +308,7 @@ def run_python_code_windows(pid, python_code, connect_debugger_tracing=False, sh
|
|||
args = [target_executable, str(pid), target_dll_run_on_dllmain]
|
||||
subprocess.check_call(args)
|
||||
|
||||
if not event.wait_for_event_set(30):
|
||||
if not event.wait_for_event_set(15):
|
||||
print("Timeout error: the attach may not have completed.")
|
||||
sys.stdout.flush()
|
||||
print("--- Finished dll injection ---\n")
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -81,6 +81,10 @@ def fix_main_thread_id(on_warn=lambda msg: None, on_exception=lambda msg: None,
|
|||
import sys
|
||||
import threading
|
||||
|
||||
# This is no longer needed in Py 3.13 (as the related issue is already fixed).
|
||||
if sys.version_info[:2] >= (3, 13):
|
||||
return
|
||||
|
||||
try:
|
||||
with threading._active_limbo_lock:
|
||||
main_thread_instance = get_main_thread_instance(threading)
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
src/debugpy/_vendored/pydevd/pydevd_attach_to_process/attach_x86_64.dylib
Normal file → Executable file
Двоичные данные
src/debugpy/_vendored/pydevd/pydevd_attach_to_process/attach_x86_64.dylib
Normal file → Executable file
Двоичный файл не отображается.
|
@ -127,20 +127,20 @@ int InternalSetSysTraceFunc(
|
|||
pyUnicode_InternFromString = stringFromString;
|
||||
}
|
||||
|
||||
DEFINE_PROC_NO_CHECK(pyObject_FastCallDict, _PyObject_FastCallDict*, "_PyObject_FastCallDict", 530);
|
||||
_PyObject_FastCallDict* pyObject_FastCallDict;
|
||||
if (version < PythonVersion_37) {
|
||||
pyObject_FastCallDict = reinterpret_cast<_PyObject_FastCallDict*>(&PyObject_FastCallDictCustom);
|
||||
} else if (version < PythonVersion_39) {
|
||||
DEFINE_PROC(fastCallDict, _PyObject_FastCallDict*, "_PyObject_FastCallDict", 530);
|
||||
pyObject_FastCallDict = fastCallDict;
|
||||
} else {
|
||||
DEFINE_PROC(vectorcallDict, _PyObject_FastCallDict*, "PyObject_VectorcallDict", 530);
|
||||
pyObject_FastCallDict = vectorcallDict;
|
||||
}
|
||||
|
||||
DEFINE_PROC(pyTuple_New, PyTuple_New*, "PyTuple_New", 531);
|
||||
DEFINE_PROC(pyEval_CallObjectWithKeywords, PyEval_CallObjectWithKeywords*, "PyEval_CallObjectWithKeywords", 532);
|
||||
|
||||
if(pyObject_FastCallDict == nullptr) {
|
||||
DEFINE_PROC_NO_CHECK(pyObject_VectorcallDict, _PyObject_FastCallDict*, "PyObject_VectorcallDict", 533);
|
||||
pyObject_FastCallDict = pyObject_VectorcallDict;
|
||||
}
|
||||
|
||||
if(pyObject_FastCallDict == nullptr) {
|
||||
// we have to use PyObject_FastCallDictCustom for older versions of CPython (pre 3.7).
|
||||
pyObject_FastCallDict = reinterpret_cast<_PyObject_FastCallDict*>(&PyObject_FastCallDictCustom);
|
||||
}
|
||||
|
||||
|
||||
DEFINE_PROC(pyTraceBack_Here, PyTraceBack_Here*, "PyTraceBack_Here", 540);
|
||||
DEFINE_PROC(pyEval_SetTrace, PyEval_SetTrace*, "PyEval_SetTrace", 550);
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
0
src/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/compile_linux.sh
Normal file → Executable file
0
src/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/compile_linux.sh
Normal file → Executable file
0
src/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/compile_mac.sh
Normal file → Executable file
0
src/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/compile_mac.sh
Normal file → Executable file
0
src/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/compile_manylinux.cmd
Normal file → Executable file
0
src/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/compile_manylinux.cmd
Normal file → Executable file
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -108,8 +108,8 @@ struct InitializeThreadingInfo {
|
|||
PyEval_Lock* initThreads;
|
||||
|
||||
CRITICAL_SECTION cs;
|
||||
HANDLE initedEvent; // Note: only access with cs locked (and check if not already nullptr).
|
||||
bool completed; // Note: only access with cs locked
|
||||
HANDLE initedEvent; // Note: only access with mutex locked (and check if not already nullptr).
|
||||
bool completed; // Note: only access with mutex locked
|
||||
};
|
||||
|
||||
|
||||
|
@ -322,7 +322,6 @@ extern "C"
|
|||
return -240;
|
||||
}
|
||||
|
||||
|
||||
// Either _Py_CheckInterval or _PyEval_[GS]etSwitchInterval are useful, but not required
|
||||
DEFINE_PROC_NO_CHECK(intervalCheck, int*, "_Py_CheckInterval", -250); // optional
|
||||
DEFINE_PROC_NO_CHECK(getSwitchInterval, _PyEval_GetSwitchInterval*, "_PyEval_GetSwitchInterval", -260); // optional
|
||||
|
@ -375,7 +374,6 @@ extern "C"
|
|||
initializeThreadingInfo->initedEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
InitializeCriticalSection(&initializeThreadingInfo->cs);
|
||||
|
||||
|
||||
// Add the call to initialize threading.
|
||||
addPendingCall(&AttachCallback, initializeThreadingInfo);
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
:: This script compiles the attach and inject DLLs for x86 and x64 architectures.
|
||||
:: It runs as part of the PR checks in the debugpy repo, AND the artifacts are uploaded to github,
|
||||
:: so you don't have to run it locally.
|
||||
|
||||
setlocal
|
||||
@cd /d %~dp0
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
r"""
|
||||
This module provides utilities to get the absolute filenames so that we can be sure that:
|
||||
- The case of a file will match the actual file in the filesystem (otherwise breakpoints won't be hit).
|
||||
- Providing means for the user to make path conversions when doing a remote debugging session in
|
||||
one machine and debugging in another.
|
||||
This module provides utilities to get the absolute filenames so that we can be sure that:
|
||||
- The case of a file will match the actual file in the filesystem (otherwise breakpoints won't be hit).
|
||||
- Providing means for the user to make path conversions when doing a remote debugging session in
|
||||
one machine and debugging in another.
|
||||
|
||||
To do that, the PATHS_FROM_ECLIPSE_TO_PYTHON constant must be filled with the appropriate paths.
|
||||
To do that, the PATHS_FROM_ECLIPSE_TO_PYTHON constant must be filled with the appropriate paths.
|
||||
|
||||
@note:
|
||||
in this context, the server is where your python process is running
|
||||
and the client is where eclipse is running.
|
||||
@note:
|
||||
in this context, the server is where your python process is running
|
||||
and the client is where eclipse is running.
|
||||
|
||||
E.g.:
|
||||
If the server (your python process) has the structure
|
||||
/user/projects/my_project/src/package/module1.py
|
||||
E.g.:
|
||||
If the server (your python process) has the structure
|
||||
/user/projects/my_project/src/package/module1.py
|
||||
|
||||
and the client has:
|
||||
c:\my_project\src\package\module1.py
|
||||
and the client has:
|
||||
c:\my_project\src\package\module1.py
|
||||
|
||||
the PATHS_FROM_ECLIPSE_TO_PYTHON would have to be:
|
||||
PATHS_FROM_ECLIPSE_TO_PYTHON = [(r'c:\my_project\src', r'/user/projects/my_project/src')]
|
||||
the PATHS_FROM_ECLIPSE_TO_PYTHON would have to be:
|
||||
PATHS_FROM_ECLIPSE_TO_PYTHON = [(r'c:\my_project\src', r'/user/projects/my_project/src')]
|
||||
|
||||
alternatively, this can be set with an environment variable from the command line:
|
||||
set PATHS_FROM_ECLIPSE_TO_PYTHON=[['c:\my_project\src','/user/projects/my_project/src']]
|
||||
alternatively, this can be set with an environment variable from the command line:
|
||||
set PATHS_FROM_ECLIPSE_TO_PYTHON=[['c:\my_project\src','/user/projects/my_project/src']]
|
||||
|
||||
@note: DEBUG_CLIENT_SERVER_TRANSLATION can be set to True to debug the result of those translations
|
||||
@note: DEBUG_CLIENT_SERVER_TRANSLATION can be set to True to debug the result of those translations
|
||||
|
||||
@note: the case of the paths is important! Note that this can be tricky to get right when one machine
|
||||
uses a case-independent filesystem and the other uses a case-dependent filesystem (if the system being
|
||||
debugged is case-independent, 'normcase()' should be used on the paths defined in PATHS_FROM_ECLIPSE_TO_PYTHON).
|
||||
@note: the case of the paths is important! Note that this can be tricky to get right when one machine
|
||||
uses a case-independent filesystem and the other uses a case-dependent filesystem (if the system being
|
||||
debugged is case-independent, 'normcase()' should be used on the paths defined in PATHS_FROM_ECLIPSE_TO_PYTHON).
|
||||
|
||||
@note: all the paths with breakpoints must be translated (otherwise they won't be found in the server)
|
||||
@note: all the paths with breakpoints must be translated (otherwise they won't be found in the server)
|
||||
|
||||
@note: to enable remote debugging in the target machine (pydev extensions in the eclipse installation)
|
||||
import pydevd;pydevd.settrace(host, stdoutToServer, stderrToServer, port, suspend)
|
||||
@note: to enable remote debugging in the target machine (pydev extensions in the eclipse installation)
|
||||
import pydevd;pydevd.settrace(host, stdoutToServer, stderrToServer, port, suspend)
|
||||
|
||||
see parameter docs on pydevd.py
|
||||
see parameter docs on pydevd.py
|
||||
|
||||
@note: for doing a remote debugging session, all the pydevd_ files must be on the server accessible
|
||||
through the PYTHONPATH (and the PATHS_FROM_ECLIPSE_TO_PYTHON only needs to be set on the target
|
||||
machine for the paths that'll actually have breakpoints).
|
||||
@note: for doing a remote debugging session, all the pydevd_ files must be on the server accessible
|
||||
through the PYTHONPATH (and the PATHS_FROM_ECLIPSE_TO_PYTHON only needs to be set on the target
|
||||
machine for the paths that'll actually have breakpoints).
|
||||
"""
|
||||
|
||||
from _pydev_bundle import pydev_log
|
||||
|
@ -71,7 +71,6 @@ except:
|
|||
# realpath is a no-op on systems without islink support
|
||||
os_path_real_path = os.path.abspath
|
||||
|
||||
PYDEVD_ROOT_PATH = os_path_real_path(os.path.dirname(__file__))
|
||||
|
||||
def _get_library_dir():
|
||||
library_dir = None
|
||||
|
@ -964,9 +963,3 @@ def get_package_dir(mod_name):
|
|||
if os.path.isdir(mod_path):
|
||||
return mod_path
|
||||
return None
|
||||
|
||||
def is_pydevd_path(path):
|
||||
# Return true if this file is rooted in the pydevd directory.
|
||||
dir: str = os_path_real_path(os.path.dirname(path))
|
||||
return dir.startswith(PYDEVD_ROOT_PATH)
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
before-build = """
|
||||
pydevd_attach_to_process/linux_and_mac/compile_linux.sh
|
||||
pip install cython
|
||||
pip install setuptools
|
||||
python build_tools/build.py
|
||||
"""
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import unittest
|
||||
import pydevd_file_utils
|
||||
|
||||
class TestFileUtils(unittest.TestCase):
|
||||
def test_path_search(self):
|
||||
self.assertTrue(pydevd_file_utils.contains_dir("foo/bar/inspect.py", "inspect.py"))
|
||||
self.assertTrue(pydevd_file_utils.contains_dir("foo/bar/inspect.py", "foo"))
|
||||
self.assertTrue(pydevd_file_utils.contains_dir("foo/bar/inspect.py", "bar"))
|
||||
self.assertFalse(pydevd_file_utils.contains_dir("foo/bar/inspect.py", "boo"))
|
||||
self.assertFalse(pydevd_file_utils.contains_dir("foo/bar/inspect.py", "foo/bar"))
|
||||
self.assertFalse(pydevd_file_utils.contains_dir("<not a path>", "path"))
|
|
@ -1,5 +1,6 @@
|
|||
import sys
|
||||
from _pydev_bundle._pydev_saved_modules import thread
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY313_OR_GREATER
|
||||
import pycompletionserver
|
||||
import socket
|
||||
from urllib.parse import quote_plus
|
||||
|
@ -71,6 +72,8 @@ class TestCPython(unittest.TestCase):
|
|||
|
||||
return msg
|
||||
|
||||
@unittest.skipIf(IS_PY313_OR_GREATER and sys.platform == "linux",
|
||||
"Flakey on Linux")
|
||||
def test_completion_sockets_and_messages(self):
|
||||
t, socket = self.create_connections()
|
||||
self.socket = socket
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""
|
||||
@author Fabio Zadrozny
|
||||
"""
|
||||
|
||||
from _pydev_bundle import _pydev_imports_tipper
|
||||
import inspect
|
||||
import pytest
|
||||
|
@ -176,7 +177,13 @@ class TestCPython(unittest.TestCase):
|
|||
self.assert_in("parseFile", tip)
|
||||
else:
|
||||
self.assert_args(
|
||||
"parse", ["(source, filename, mode)", "(source, filename, mode, type_comments=False, feature_version=None)"], tip
|
||||
"parse",
|
||||
[
|
||||
"(source, filename, mode)",
|
||||
"(source, filename, mode, type_comments=False, feature_version=None)",
|
||||
"(source, filename, mode, type_comments=False, feature_version=None, optimize=-1)",
|
||||
],
|
||||
tip,
|
||||
)
|
||||
self.assert_args("walk", "(node)", tip)
|
||||
self.assert_in("parse", tip)
|
||||
|
|
|
@ -146,7 +146,7 @@ def overrides(method):
|
|||
return wrapper
|
||||
|
||||
|
||||
TIMEOUT = 60
|
||||
TIMEOUT = 20
|
||||
|
||||
try:
|
||||
TimeoutError = TimeoutError # @ReservedAssignment
|
||||
|
@ -647,7 +647,7 @@ class DebuggerRunner(object):
|
|||
except:
|
||||
traceback.print_exc()
|
||||
finish[0] = True
|
||||
# print("Log on success: " + self.get_log_contents())
|
||||
print("Log on success: " + self.get_log_contents())
|
||||
|
||||
def get_log_contents(self):
|
||||
log_contents = ""
|
||||
|
@ -1656,7 +1656,9 @@ class AbstractWriterThread(threading.Thread):
|
|||
|
||||
def wait_for_thread_join(self, main_thread_id):
|
||||
def condition():
|
||||
return self.get_frame_names(main_thread_id) in (
|
||||
names = self.get_frame_names(main_thread_id)
|
||||
return names in (
|
||||
["join", "<module>"],
|
||||
["wait", "join", "<module>"],
|
||||
["_wait_for_tstate_lock", "join", "<module>"],
|
||||
["_wait_for_tstate_lock", "join", "<module>", "_run_code", "_run_module_code", "run_path"],
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>flask1</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.python.pydev.PyDevBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.python.pydev.pythonNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||
<path>/${PROJECT_DIR_NAME}</path>
|
||||
</pydev_pathproperty>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
</pydev_project>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>my_django_proj_17</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.python.pydev.PyDevBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.python.pydev.pythonNature</nature>
|
||||
<nature>org.python.pydev.django.djangoNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||
<pydev_variables_property name="org.python.pydev.PROJECT_VARIABLE_SUBSTITUTION">
|
||||
<key>DJANGO_MANAGE_LOCATION</key>
|
||||
<value>manage.py</value>
|
||||
</pydev_variables_property>
|
||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||
<path>/${PROJECT_DIR_NAME}</path>
|
||||
</pydev_pathproperty>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
</pydev_project>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>my_django_proj_21</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.python.pydev.PyDevBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.python.pydev.pythonNature</nature>
|
||||
<nature>org.python.pydev.django.djangoNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||
<pydev_variables_property name="org.python.pydev.PROJECT_VARIABLE_SUBSTITUTION">
|
||||
<key>DJANGO_MANAGE_LOCATION</key>
|
||||
<value>manage.py</value>
|
||||
<key>DJANGO_SETTINGS_MODULE</key>
|
||||
<value>my_django_proj_21.settings</value>
|
||||
</pydev_variables_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||
<path>/${PROJECT_DIR_NAME}</path>
|
||||
</pydev_pathproperty>
|
||||
</pydev_project>
|
|
@ -0,0 +1,27 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding//.settings/org.python.pydev.yaml=UTF-8
|
||||
encoding//_pydevd_bundle/_debug_adapter/pydevd_schema.py=utf-8
|
||||
encoding//pydev_ipython/inputhook.py=utf-8
|
||||
encoding//pydev_ipython/inputhookglut.py=utf-8
|
||||
encoding//pydev_ipython/inputhookpyglet.py=utf-8
|
||||
encoding//pydev_ipython/inputhookqt4.py=utf-8
|
||||
encoding//pydev_ipython/inputhookqt5.py=utf-8
|
||||
encoding//pydev_ipython/inputhookwx.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/breakpoint.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/crash.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/interactive.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/plugins/do_exploitable.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/process.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/__init__.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/defines.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/kernel32.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/user32.py=utf-8
|
||||
encoding//pydevd_attach_to_process/winappdbg/win32/version.py=utf-8
|
||||
encoding//tests_python/debugger_fixtures.py=utf-8
|
||||
encoding//tests_python/test_collect_bytecode_info.py=utf-8
|
||||
encoding//tests_python/test_convert_utilities.py=utf-8
|
||||
encoding//tests_python/test_debugger.py=utf-8
|
||||
encoding//tests_python/test_debugger_json.py=utf-8
|
||||
encoding//tests_python/test_extract_token.py=utf-8
|
||||
encoding//tests_python/test_pydev_monkey.py=utf-8
|
||||
encoding//tests_python/test_safe_repr.py=utf-8
|
|
@ -0,0 +1,47 @@
|
|||
ADD_NEW_LINE_AT_END_OF_FILE: true
|
||||
AUTOPEP8_PARAMETERS: ''
|
||||
AUTO_ADD_SELF: true
|
||||
AUTO_BRACES: true
|
||||
AUTO_COLON: true
|
||||
AUTO_DEDENT_ELSE: true
|
||||
AUTO_INDENT_AFTER_PAR_WIDTH: 1
|
||||
AUTO_INDENT_TO_PAR_LEVEL: false
|
||||
AUTO_LINK: false
|
||||
AUTO_LITERALS: true
|
||||
AUTO_PAR: true
|
||||
AUTO_WRITE_IMPORT_STR: true
|
||||
BLACK_PARAMETERS: ''
|
||||
BLANK_LINES_INNER: 1
|
||||
BLANK_LINES_TOP_LEVEL: 2
|
||||
BREAK_IMPORTS_MODE: PARENTHESIS
|
||||
DATE_FIELD_FORMAT: yyyy-MM-dd
|
||||
DATE_FIELD_NAME: __updated__
|
||||
DELETE_UNUSED_IMPORTS: false
|
||||
ENABLE_DATE_FIELD_ACTION: false
|
||||
FORMATTER_STYLE: PYDEVF
|
||||
FORMAT_BEFORE_SAVING: true
|
||||
FORMAT_ONLY_CHANGED_LINES: false
|
||||
FORMAT_WITH_AUTOPEP8: false
|
||||
FROM_IMPORTS_FIRST: false
|
||||
GROUP_IMPORTS: true
|
||||
IMPORT_ENGINE: IMPORT_ENGINE_PEP_8
|
||||
INDENT_AFTER_PAR_AS_PEP8: false
|
||||
MANAGE_BLANK_LINES: true
|
||||
MULTILINE_IMPORTS: true
|
||||
PEP8_IMPORTS: true
|
||||
PYDEV_TEST_RUNNER: '2'
|
||||
PYDEV_TEST_RUNNER_DEFAULT_PARAMETERS: --capture=no -vv --tb=native -n 0
|
||||
PYDEV_USE_PYUNIT_VIEW: true
|
||||
SAVE_ACTIONS_ONLY_ON_WORKSPACE_FILES: true
|
||||
SMART_INDENT_PAR: true
|
||||
SMART_LINE_MOVE: false
|
||||
SORT_IMPORTS_ON_SAVE: false
|
||||
SORT_NAMES_GROUPED: false
|
||||
SPACES_BEFORE_COMMENT: '2'
|
||||
SPACES_IN_START_COMMENT: '1'
|
||||
TRIM_EMPTY_LINES: true
|
||||
TRIM_MULTILINE_LITERALS: true
|
||||
USE_ASSIGN_WITH_PACES_INSIDER_PARENTESIS: false
|
||||
USE_OPERATORS_WITH_SPACE: true
|
||||
USE_SPACE_AFTER_COMMA: true
|
||||
USE_SPACE_FOR_PARENTESIS: false
|
|
@ -1,38 +1,99 @@
|
|||
import pydevd
|
||||
import threading
|
||||
import sys
|
||||
|
||||
original = pydevd.PyDB.notify_thread_created
|
||||
|
||||
found = set()
|
||||
|
||||
|
||||
def new_notify_thread_created(self, thread_id, thread, *args, **kwargs):
|
||||
found.add(thread)
|
||||
return original(self, thread_id, thread, *args, **kwargs)
|
||||
|
||||
pydevd.PyDB.notify_thread_created = new_notify_thread_created
|
||||
|
||||
pydevd.PyDB.notify_thread_created = new_notify_thread_created
|
||||
|
||||
ok = []
|
||||
|
||||
|
||||
class MyThread(threading.Thread):
|
||||
|
||||
def run(self):
|
||||
if self not in found:
|
||||
ok.append(False)
|
||||
else:
|
||||
ok.append(True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
threads = []
|
||||
|
||||
|
||||
class ManualCreatedThreadPy313:
|
||||
def __init__(self):
|
||||
self.ev = threading.Event()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
if threading.current_thread() not in found:
|
||||
ok.append(False)
|
||||
else:
|
||||
ok.append(True)
|
||||
finally:
|
||||
self.ev.set()
|
||||
|
||||
def start(self):
|
||||
import _thread
|
||||
|
||||
_thread.start_joinable_thread(self.run)
|
||||
|
||||
def join(self):
|
||||
self.ev.wait()
|
||||
|
||||
|
||||
class ManualCreatedThreadFromThreadModule:
|
||||
def __init__(self):
|
||||
self.ev = threading.Event()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
if threading.current_thread() not in found:
|
||||
ok.append(False)
|
||||
else:
|
||||
ok.append(True)
|
||||
finally:
|
||||
self.ev.set()
|
||||
|
||||
def start(self):
|
||||
try:
|
||||
import thread
|
||||
except Exception:
|
||||
import _thread as thread
|
||||
|
||||
thread.start_new_thread(self.run)
|
||||
|
||||
def join(self):
|
||||
self.ev.wait()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
threads: list = []
|
||||
|
||||
if sys.version_info[:2] >= (3, 13):
|
||||
t1 = ManualCreatedThreadPy313()
|
||||
t1.start()
|
||||
threads.append(t1)
|
||||
|
||||
t2 = ManualCreatedThreadFromThreadModule()
|
||||
t2.start()
|
||||
threads.append(t2)
|
||||
|
||||
for i in range(15):
|
||||
t = MyThread()
|
||||
t.start()
|
||||
threads.append(t)
|
||||
|
||||
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
|
||||
assert len(ok) == len(threads)
|
||||
assert all(ok), 'Expected all threads to be notified of their creation before starting to run. Found: %s' % (ok,)
|
||||
|
||||
assert all(ok), "Expected all threads to be notified of their creation before starting to run. Found: %s" % (ok,)
|
||||
|
||||
found.clear()
|
||||
print('TEST SUCEEDED')
|
||||
|
||||
print("TEST SUCEEDED")
|
||||
|
|
|
@ -14,7 +14,8 @@ def method1():
|
|||
method2() # handle on method1
|
||||
except:
|
||||
pass # Ok, handled
|
||||
assert '__exception__' not in sys._getframe().f_locals
|
||||
exc = sys._getframe().f_locals.get('__exception__', None)
|
||||
assert exc is None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -4,7 +4,7 @@ def Call():
|
|||
variable_for_test_1 = 10 # Break here
|
||||
variable_for_test_2 = 20
|
||||
variable_for_test_3 = {'a':30, 'b':20}
|
||||
locals()[u'\u16A0'] = u'\u16A1' # unicode variable (would be syntax error on py2).
|
||||
ᚠ = u'\u16A1'
|
||||
|
||||
all_vars_set = True # Break 2 here
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import time
|
||||
|
||||
wait = True
|
||||
while wait:
|
||||
time.sleep(1) # break here
|
||||
|
||||
print('attached')
|
|
@ -1,11 +1,6 @@
|
|||
import time
|
||||
import os
|
||||
|
||||
wait = True
|
||||
while wait:
|
||||
time.sleep(1) # break here
|
||||
|
||||
print('attached')
|
||||
import _debugger_case_sysexit_unhandled_break
|
||||
|
||||
# Raise an exception in a system module.
|
||||
def raise_exception():
|
||||
|
|
|
@ -2,38 +2,40 @@
|
|||
# imported and having no other threads running).
|
||||
|
||||
|
||||
def wait_for_condition(condition, msg=None, timeout=5, sleep=.05):
|
||||
def wait_for_condition(condition, msg=None, timeout=5, sleep=0.05):
|
||||
import time
|
||||
|
||||
curtime = time.time()
|
||||
while True:
|
||||
if condition():
|
||||
break
|
||||
if time.time() - curtime > timeout:
|
||||
error_msg = 'Condition not reached in %s seconds' % (timeout,)
|
||||
error_msg = "Condition not reached in %s seconds" % (timeout,)
|
||||
if msg is not None:
|
||||
error_msg += '\n'
|
||||
error_msg += "\n"
|
||||
if callable(msg):
|
||||
error_msg += msg()
|
||||
else:
|
||||
error_msg += str(msg)
|
||||
|
||||
raise AssertionError('Timeout: %s' % (error_msg,))
|
||||
raise AssertionError("Timeout: %s" % (error_msg,))
|
||||
time.sleep(sleep)
|
||||
|
||||
|
||||
def check_main_thread_id_simple():
|
||||
import attach_script
|
||||
import sys
|
||||
assert 'threading' not in sys.modules
|
||||
|
||||
assert "threading" not in sys.modules
|
||||
try:
|
||||
import thread
|
||||
except ImportError:
|
||||
import _thread as thread
|
||||
|
||||
main_thread_id, log_msg = attach_script.get_main_thread_id(None)
|
||||
assert main_thread_id == thread.get_ident(), 'Found: %s, Expected: %s' % (main_thread_id, thread.get_ident())
|
||||
assert main_thread_id == thread.get_ident(), "Found: %s, Expected: %s" % (main_thread_id, thread.get_ident())
|
||||
assert not log_msg
|
||||
assert 'threading' not in sys.modules
|
||||
assert "threading" not in sys.modules
|
||||
wait_for_condition(lambda: len(sys._current_frames()) == 1)
|
||||
|
||||
|
||||
|
@ -41,7 +43,8 @@ def check_main_thread_id_multiple_threads():
|
|||
import attach_script
|
||||
import sys
|
||||
import time
|
||||
assert 'threading' not in sys.modules
|
||||
|
||||
assert "threading" not in sys.modules
|
||||
try:
|
||||
import thread
|
||||
except ImportError:
|
||||
|
@ -58,14 +61,14 @@ def check_main_thread_id_multiple_threads():
|
|||
with lock:
|
||||
thread.start_new_thread(method, ())
|
||||
while not lock2.locked():
|
||||
time.sleep(.1)
|
||||
time.sleep(0.1)
|
||||
|
||||
wait_for_condition(lambda: len(sys._current_frames()) == 2)
|
||||
|
||||
main_thread_id, log_msg = attach_script.get_main_thread_id(None)
|
||||
assert main_thread_id == thread.get_ident(), 'Found: %s, Expected: %s' % (main_thread_id, thread.get_ident())
|
||||
assert main_thread_id == thread.get_ident(), "Found: %s, Expected: %s" % (main_thread_id, thread.get_ident())
|
||||
assert not log_msg
|
||||
assert 'threading' not in sys.modules
|
||||
# assert 'threading' not in sys.modules
|
||||
wait_for_condition(lambda: len(sys._current_frames()) == 1)
|
||||
|
||||
|
||||
|
@ -73,7 +76,8 @@ def check_fix_main_thread_id_multiple_threads():
|
|||
import attach_script
|
||||
import sys
|
||||
import time
|
||||
assert 'threading' not in sys.modules
|
||||
|
||||
assert "threading" not in sys.modules
|
||||
try:
|
||||
import thread
|
||||
except ImportError:
|
||||
|
@ -85,13 +89,25 @@ def check_fix_main_thread_id_multiple_threads():
|
|||
def method():
|
||||
lock2.acquire()
|
||||
import threading # Note: imported on wrong thread
|
||||
assert threading.current_thread().ident == thread.get_ident()
|
||||
assert threading.current_thread() is attach_script.get_main_thread_instance(threading)
|
||||
|
||||
attach_script.fix_main_thread_id()
|
||||
if sys.version_info[:2] >= (3, 13):
|
||||
assert threading.current_thread().ident == thread.get_ident()
|
||||
|
||||
assert threading.current_thread().ident == thread.get_ident()
|
||||
assert threading.current_thread() is not attach_script.get_main_thread_instance(threading)
|
||||
# yay, Python 3.13 fixed this (so, no patchis is actually needed)
|
||||
assert threading.current_thread() is not attach_script.get_main_thread_instance(threading)
|
||||
|
||||
# Call it just to make sure it doesn't raise any error.
|
||||
attach_script.fix_main_thread_id()
|
||||
assert threading.current_thread() is not attach_script.get_main_thread_instance(threading)
|
||||
|
||||
else:
|
||||
assert threading.current_thread().ident == thread.get_ident()
|
||||
assert threading.current_thread() is attach_script.get_main_thread_instance(threading)
|
||||
|
||||
attach_script.fix_main_thread_id()
|
||||
|
||||
assert threading.current_thread().ident == thread.get_ident()
|
||||
assert threading.current_thread() is not attach_script.get_main_thread_instance(threading)
|
||||
|
||||
with lock:
|
||||
pass # Will only finish when lock is released.
|
||||
|
@ -99,27 +115,30 @@ def check_fix_main_thread_id_multiple_threads():
|
|||
with lock:
|
||||
thread.start_new_thread(method, ())
|
||||
while not lock2.locked():
|
||||
time.sleep(.1)
|
||||
time.sleep(0.1)
|
||||
|
||||
wait_for_condition(lambda: len(sys._current_frames()) == 2)
|
||||
wait_for_condition(lambda: len(sys._current_frames()) == 2, msg=(lambda: "Current frames: %s" % sys._current_frames()))
|
||||
|
||||
main_thread_id, log_msg = attach_script.get_main_thread_id(None)
|
||||
assert main_thread_id == thread.get_ident(), 'Found: %s, Expected: %s' % (main_thread_id, thread.get_ident())
|
||||
assert main_thread_id == thread.get_ident(), "Found: %s, Expected: %s" % (main_thread_id, thread.get_ident())
|
||||
assert not log_msg
|
||||
assert 'threading' in sys.modules
|
||||
assert "threading" in sys.modules
|
||||
import threading
|
||||
|
||||
assert threading.current_thread().ident == main_thread_id
|
||||
wait_for_condition(lambda: len(sys._current_frames()) == 1)
|
||||
|
||||
|
||||
def check_win_threads():
|
||||
import sys
|
||||
if sys.platform != 'win32':
|
||||
|
||||
if sys.platform != "win32":
|
||||
return
|
||||
|
||||
import attach_script
|
||||
import time
|
||||
assert 'threading' not in sys.modules
|
||||
|
||||
assert "threading" not in sys.modules
|
||||
try:
|
||||
import thread
|
||||
except ImportError:
|
||||
|
@ -141,18 +160,18 @@ def check_win_threads():
|
|||
with lock:
|
||||
windll.kernel32.CreateThread(None, c_size_t(0), method, None, c_uint32(0), None)
|
||||
while not lock2.locked():
|
||||
time.sleep(.1)
|
||||
time.sleep(0.1)
|
||||
|
||||
wait_for_condition(lambda: len(sys._current_frames()) == 2)
|
||||
|
||||
main_thread_id, log_msg = attach_script.get_main_thread_id(None)
|
||||
assert main_thread_id == thread.get_ident(), 'Found: %s, Expected: %s' % (main_thread_id, thread.get_ident())
|
||||
assert main_thread_id == thread.get_ident(), "Found: %s, Expected: %s" % (main_thread_id, thread.get_ident())
|
||||
assert not log_msg
|
||||
assert 'threading' not in sys.modules
|
||||
assert "threading" not in sys.modules
|
||||
wait_for_condition(lambda: len(sys._current_frames()) == 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
check_main_thread_id_simple()
|
||||
check_main_thread_id_multiple_threads()
|
||||
check_win_threads()
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
def exec_breakpoint():
|
||||
# This exists so we can test that string frames from pydevd
|
||||
# don't get handled
|
||||
exec("breakpoint()")
|
|
@ -1,12 +0,0 @@
|
|||
if __name__ == '__main__':
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
# Create a breakpoint in a <string> frame
|
||||
import _pydevd_string_breakpoint
|
||||
_pydevd_string_breakpoint.exec_breakpoint()
|
||||
|
||||
# Now run the actual entry point
|
||||
import empty_file
|
||||
print('TEST SUCEEDED')
|
|
@ -10,7 +10,6 @@ from tests_python.debugger_unittest import IS_CPYTHON, IS_PYPY
|
|||
from _pydevd_bundle.pydevd_constants import IS_PY38_OR_GREATER, IS_JYTHON
|
||||
from tests_python.debug_constants import IS_PY311_OR_GREATER, TODO_PYPY
|
||||
|
||||
|
||||
def _method_call_with_error():
|
||||
try:
|
||||
_method_reraise()
|
||||
|
@ -161,7 +160,7 @@ class _ExcVerifier(object):
|
|||
if update_try_except_infos is not None:
|
||||
update_try_except_infos(try_except_infos)
|
||||
|
||||
if sys.version_info[:2] not in ((3, 10), (3, 11), (3, 12)):
|
||||
if sys.version_info[:2] not in ((3, 10), (3, 11), (3, 12), (3, 13)):
|
||||
assert str(try_except_infos) == expected_as_str
|
||||
from _pydevd_bundle.pydevd_collect_bytecode_info import collect_try_except_info_from_source
|
||||
|
||||
|
@ -193,7 +192,7 @@ def test_collect_try_except_info(data_regression, pyfile):
|
|||
info = collect_try_except_info(method.__code__, use_func_first_line=True)
|
||||
method_to_info[key] = sorted(str(x) for x in info)
|
||||
|
||||
if sys.version_info[:2] not in ((3, 10), (3, 11), (3, 12)):
|
||||
if sys.version_info[:2] not in ((3, 10), (3, 11), (3, 12), (3, 13)):
|
||||
data_regression.check(method_to_info)
|
||||
|
||||
data_regression.check(method_to_info_from_source)
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# coding: utf-8
|
||||
"""
|
||||
The idea is that we record the commands sent to the debugger and reproduce them from this script
|
||||
(so, this works as the client, which spawns the debugger as a separate process and communicates
|
||||
to it as if it was run from the outside)
|
||||
The idea is that we record the commands sent to the debugger and reproduce them from this script
|
||||
(so, this works as the client, which spawns the debugger as a separate process and communicates
|
||||
to it as if it was run from the outside)
|
||||
|
||||
Note that it's a python script but it'll spawn a process to run as jython, ironpython and as python.
|
||||
Note that it's a python script but it'll spawn a process to run as jython, ironpython and as python.
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
@ -1523,7 +1524,7 @@ def test_case_handled_and_unhandled_exception_generator(case_setup, target_file,
|
|||
if unhandled:
|
||||
writer.write_add_exception_breakpoint_with_policy("Exception", "0", "1", "0")
|
||||
else:
|
||||
writer.write_add_exception_breakpoint_with_policy("Exception", "1", "0", "0")
|
||||
writer.write_add_exception_breakpoint_with_policy("Exception", "1", "0", "1")
|
||||
|
||||
writer.write_make_initial_run()
|
||||
|
||||
|
@ -1726,7 +1727,7 @@ def test_unhandled_exceptions_in_top_level4(case_setup_unhandled_exceptions):
|
|||
EXPECTED_RETURNCODE=1,
|
||||
) as writer:
|
||||
# Handled and unhandled
|
||||
writer.write_add_exception_breakpoint_with_policy("Exception", "1", "1", "0")
|
||||
writer.write_add_exception_breakpoint_with_policy("Exception", "1", "1", "1")
|
||||
writer.write_make_initial_run()
|
||||
|
||||
# We have an exception thrown and handled and another which is thrown and is then unhandled.
|
||||
|
@ -2258,7 +2259,7 @@ def test_redirect_output(case_setup):
|
|||
if original_ignore_stderr_line(line):
|
||||
return True
|
||||
|
||||
binary_junk = b"\xe8\xF0\x80\x80\x80"
|
||||
binary_junk = b"\xe8\xf0\x80\x80\x80"
|
||||
if sys.version_info[0] >= 3:
|
||||
binary_junk = binary_junk.decode("utf-8", "replace")
|
||||
|
||||
|
@ -3044,7 +3045,9 @@ def test_attach_to_pid_no_threads(case_setup_remote, reattach):
|
|||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(not IS_CPYTHON or IS_MAC or not SUPPORT_ATTACH_TO_PID or IS_PY312_OR_GREATER, reason="CPython only test (brittle on Mac).")
|
||||
@pytest.mark.skipif(
|
||||
not IS_CPYTHON or IS_MAC or not SUPPORT_ATTACH_TO_PID or IS_PY312_OR_GREATER, reason="CPython only test (brittle on Mac)."
|
||||
)
|
||||
def test_attach_to_pid_halted(case_setup_remote):
|
||||
with case_setup_remote.test_file("_debugger_case_attach_to_pid_multiple_threads.py", wait_for_port=False) as writer:
|
||||
time.sleep(1) # Give it some time to initialize and get to the proper halting condition
|
||||
|
|
|
@ -50,6 +50,7 @@ from _pydevd_bundle.pydevd_constants import (
|
|||
PYDEVD_USE_SYS_MONITORING,
|
||||
IS_PY312_OR_GREATER,
|
||||
SUPPORT_ATTACH_TO_PID,
|
||||
IS_PY313_OR_GREATER,
|
||||
)
|
||||
from tests_python import debugger_unittest
|
||||
from tests_python.debug_constants import TEST_CHERRYPY, TEST_DJANGO, TEST_FLASK, IS_CPYTHON, TEST_GEVENT, TEST_CYTHON, IS_PY311
|
||||
|
@ -1402,11 +1403,12 @@ def test_case_sys_exit_multiple_exception_attach(case_setup_remote, raised, unca
|
|||
wait_for_condition(lambda: hasattr(writer, "reader_thread"))
|
||||
|
||||
json_facade = JsonFacade(writer)
|
||||
json_facade.write_set_debugger_property([], ["_debugger_case_sysexit_unhandled_launcher.py"])
|
||||
|
||||
break_file = debugger_unittest._get_debugger_test_file("_debugger_case_sysexit_unhandled_break.py")
|
||||
target_file = debugger_unittest._get_debugger_test_file("_debugger_case_sysexit_unhandled_attach.py")
|
||||
|
||||
bp_line = writer.get_line_index_with_content("break here")
|
||||
final_line = writer.get_line_index_with_content("final break")
|
||||
bp_line = writer.get_line_index_with_content("break here", filename=break_file)
|
||||
handled_line = writer.get_line_index_with_content("@handled", filename=target_file)
|
||||
unhandled_line = writer.get_line_index_with_content("@unhandled", filename=target_file)
|
||||
original_ignore_stderr_line = writer._ignore_stderr_line
|
||||
|
@ -1421,21 +1423,21 @@ def test_case_sys_exit_multiple_exception_attach(case_setup_remote, raised, unca
|
|||
|
||||
# Not really a launch, but we want to send these before the make_initial_run.
|
||||
json_facade.write_launch(
|
||||
breakpointOnSystemExit=True if zero else False,
|
||||
debugOptions=["BreakOnSystemExitZero", "ShowReturnValue"] if zero else ["ShowReturnValue"],
|
||||
breakpointOnSystemExit=True if zero else False,
|
||||
debugOptions=["BreakOnSystemExitZero", "ShowReturnValue"] if zero else ["ShowReturnValue"],
|
||||
)
|
||||
|
||||
json_facade.write_set_exception_breakpoints(filters)
|
||||
json_facade.write_set_breakpoints([bp_line])
|
||||
json_facade.write_set_breakpoints([bp_line], filename=break_file)
|
||||
json_facade.write_make_initial_run()
|
||||
hit = json_facade.wait_for_thread_stopped(line=bp_line)
|
||||
hit = json_facade.wait_for_thread_stopped(line=bp_line, file=break_file)
|
||||
|
||||
# Stop looping
|
||||
json_facade.get_global_var(hit.frame_id, "wait")
|
||||
json_facade.write_set_variable(hit.frame_id, "wait", "False")
|
||||
json_facade.write_set_breakpoints([])
|
||||
json_facade.write_continue()
|
||||
|
||||
|
||||
# When breaking on raised exceptions, we'll stop on both lines,
|
||||
# unless it's SystemExit(0) and we asked to ignore that.
|
||||
if raised and (zero or exit_code != 0):
|
||||
|
@ -1451,12 +1453,6 @@ def test_case_sys_exit_multiple_exception_attach(case_setup_remote, raised, unca
|
|||
)
|
||||
json_facade.write_continue()
|
||||
|
||||
json_facade.wait_for_thread_stopped(
|
||||
"exception",
|
||||
line=final_line,
|
||||
)
|
||||
json_facade.write_continue()
|
||||
|
||||
# When breaking on uncaught exceptions, we'll stop on the second line,
|
||||
# unless it's SystemExit(0) and we asked to ignore that.
|
||||
# Note that if both raised and uncaught filters are set, there will be
|
||||
|
@ -4227,7 +4223,7 @@ def test_wait_for_attach(case_setup_remote_attach_to_dap):
|
|||
json_facade.write_list_threads()
|
||||
# Check that we have the started thread event (whenever we reconnect).
|
||||
started_events = json_facade.mark_messages(ThreadEvent, lambda x: x.body.reason == "started")
|
||||
assert len(started_events) == 1
|
||||
assert len(started_events) >= 1
|
||||
|
||||
def check_process_event(json_facade, start_method):
|
||||
if start_method == "attach":
|
||||
|
@ -5742,24 +5738,6 @@ def test_stop_on_entry2(case_setup_dap):
|
|||
json_facade.write_continue()
|
||||
writer.finished_ok = True
|
||||
|
||||
def test_stop_on_entry_verify_strings(case_setup_dap):
|
||||
with case_setup_dap.test_file("not_my_code/main_on_entry3.py") as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
json_facade.write_set_debugger_property([], ["main_on_entry3.py", "_pydevd_string_breakpoint.py"])
|
||||
json_facade.write_launch(
|
||||
justMyCode=True,
|
||||
stopOnEntry=True,
|
||||
showReturnValue=True,
|
||||
rules=[
|
||||
{"path": "**/main_on_entry3.py", "include": False},
|
||||
{"path": "**/_pydevd_string_breakpoint.py", "include": False},
|
||||
],
|
||||
)
|
||||
|
||||
json_facade.write_make_initial_run()
|
||||
json_facade.wait_for_thread_stopped("breakpoint", file="empty_file.py")
|
||||
json_facade.write_continue()
|
||||
writer.finished_ok = True
|
||||
|
||||
@pytest.mark.parametrize("val", [True, False])
|
||||
def test_debug_options(case_setup_dap, val):
|
||||
|
@ -6257,11 +6235,14 @@ print('TEST SUCEEDED')
|
|||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not IS_WINDOWS
|
||||
or not IS_PY36_OR_GREATER
|
||||
or not IS_CPYTHON
|
||||
or not TEST_CYTHON
|
||||
or IS_PY311, # Requires frame-eval mode (not available for Python 3.11).
|
||||
not (IS_PY312_OR_GREATER and IS_WINDOWS) # Always works with sys.monitoring (even without TEST_CYTHON)
|
||||
and (
|
||||
not IS_WINDOWS
|
||||
or not IS_PY36_OR_GREATER
|
||||
or not IS_CPYTHON
|
||||
or not TEST_CYTHON
|
||||
or IS_PY311 # Requires frame-eval mode (not available for Python 3.11).
|
||||
),
|
||||
# Note that this works in Python 3.12 as it uses sys.monitoring.
|
||||
reason="Windows only test and only Python 3.6 onwards.",
|
||||
)
|
||||
|
@ -6300,6 +6281,41 @@ def test_native_threads(case_setup_dap, pyfile):
|
|||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(not IS_PY313_OR_GREATER, reason="3.13 onwards only test.")
|
||||
def test_internal_thread(case_setup_dap, pyfile):
|
||||
@pyfile
|
||||
def case_native_thread():
|
||||
import _thread
|
||||
import time
|
||||
|
||||
entered_thread = [False]
|
||||
|
||||
def method(*args, **kwargs):
|
||||
entered_thread[0] = True # Break here
|
||||
return 0
|
||||
|
||||
# Using it directly must still work!
|
||||
_thread.start_joinable_thread(method)
|
||||
|
||||
while not entered_thread[0]:
|
||||
time.sleep(0.1)
|
||||
|
||||
print("TEST SUCEEDED")
|
||||
|
||||
with case_setup_dap.test_file(case_native_thread) as writer:
|
||||
json_facade = JsonFacade(writer)
|
||||
|
||||
line = writer.get_line_index_with_content("Break here")
|
||||
json_facade.write_launch(justMyCode=False)
|
||||
json_facade.write_set_breakpoints(line)
|
||||
json_facade.write_make_initial_run()
|
||||
|
||||
json_facade.wait_for_thread_stopped(line=line)
|
||||
|
||||
json_facade.write_continue()
|
||||
writer.finished_ok = True
|
||||
|
||||
|
||||
def test_code_reload(case_setup_dap, pyfile):
|
||||
@pyfile
|
||||
def mod1():
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from _pydevd_bundle.pydevd_constants import IS_PY38_OR_GREATER, NULL
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY313_OR_GREATER, IS_PY38_OR_GREATER, NULL, IS_PY313_0
|
||||
from _pydevd_bundle.pydevd_xml import ExceptionOnEvaluate
|
||||
|
||||
import sys
|
||||
|
@ -27,6 +27,7 @@ def disable_critical_log():
|
|||
yield
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_basic(disable_critical_log):
|
||||
from _pydevd_bundle.pydevd_vars import evaluate_expression
|
||||
|
||||
|
@ -45,6 +46,7 @@ def test_evaluate_expression_basic(disable_critical_log):
|
|||
assert "some_var" not in sys._getframe().f_globals
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_1(disable_critical_log):
|
||||
from _pydevd_bundle.pydevd_vars import evaluate_expression
|
||||
|
||||
|
@ -73,6 +75,7 @@ for s in container:
|
|||
del sys._getframe().f_globals[varname]
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_2(disable_critical_log):
|
||||
from _pydevd_bundle.pydevd_vars import evaluate_expression
|
||||
|
||||
|
@ -84,6 +87,7 @@ def test_evaluate_expression_2(disable_critical_log):
|
|||
check(global_frame)
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_3(disable_critical_log):
|
||||
if not IS_PY38_OR_GREATER:
|
||||
return
|
||||
|
@ -104,6 +108,7 @@ def test_evaluate_expression_3(disable_critical_log):
|
|||
assert "some_var" not in sys._getframe().f_globals
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_4(disable_critical_log):
|
||||
from _pydevd_bundle.pydevd_vars import evaluate_expression
|
||||
|
||||
|
@ -123,6 +128,7 @@ def test_evaluate_expression_4(disable_critical_log):
|
|||
assert "email" not in sys._getframe().f_globals
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_access_globals(disable_critical_log):
|
||||
from _pydevd_bundle.pydevd_vars import evaluate_expression
|
||||
|
||||
|
@ -137,6 +143,7 @@ def test_evaluate_expression_access_globals(disable_critical_log):
|
|||
assert "global_variable" not in sys._getframe().f_locals
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_create_none(disable_critical_log):
|
||||
from _pydevd_bundle.pydevd_vars import evaluate_expression
|
||||
|
||||
|
@ -149,6 +156,7 @@ def test_evaluate_expression_create_none(disable_critical_log):
|
|||
check(next(iter(obtain_frame())))
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_delete_var(disable_critical_log):
|
||||
from _pydevd_bundle.pydevd_vars import evaluate_expression
|
||||
|
||||
|
@ -159,11 +167,15 @@ def test_evaluate_expression_delete_var(disable_critical_log):
|
|||
|
||||
eval_txt = "del x"
|
||||
evaluate_expression(None, frame, eval_txt, is_exec=True)
|
||||
assert "x" not in frame.f_locals
|
||||
if IS_PY313_0:
|
||||
assert frame.f_locals["x"] == None
|
||||
else:
|
||||
assert "x" not in frame.f_locals
|
||||
|
||||
check(next(iter(obtain_frame())))
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_PY313_0, reason="Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_5(disable_critical_log):
|
||||
from _pydevd_bundle.pydevd_vars import evaluate_expression
|
||||
|
||||
|
@ -243,7 +255,7 @@ def test_evaluate_expression_async_exec_as_eval(disable_critical_log):
|
|||
asyncio.run(main())
|
||||
|
||||
|
||||
@pytest.mark.skipif(not CAN_EVALUATE_TOP_LEVEL_ASYNC, reason="Requires top-level async evaluation.")
|
||||
@pytest.mark.skipif(not CAN_EVALUATE_TOP_LEVEL_ASYNC or IS_PY313_0, reason="Requires top-level async evaluation. Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_async_exec_error(disable_critical_log):
|
||||
py_db = _DummyPyDB()
|
||||
|
||||
|
@ -266,7 +278,7 @@ def test_evaluate_expression_async_exec_error(disable_critical_log):
|
|||
asyncio.run(main())
|
||||
|
||||
|
||||
@pytest.mark.skipif(not CAN_EVALUATE_TOP_LEVEL_ASYNC, reason="Requires top-level async evaluation.")
|
||||
@pytest.mark.skipif(not CAN_EVALUATE_TOP_LEVEL_ASYNC or IS_PY313_0, reason="Requires top-level async evaluation. Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_async_eval(disable_critical_log):
|
||||
py_db = _DummyPyDB()
|
||||
|
||||
|
@ -290,7 +302,7 @@ def test_evaluate_expression_async_eval(disable_critical_log):
|
|||
asyncio.run(main())
|
||||
|
||||
|
||||
@pytest.mark.skipif(not CAN_EVALUATE_TOP_LEVEL_ASYNC, reason="Requires top-level async evaluation.")
|
||||
@pytest.mark.skipif(not CAN_EVALUATE_TOP_LEVEL_ASYNC or IS_PY313_0, reason="Requires top-level async evaluation. Crashes on Python 3.13.0")
|
||||
def test_evaluate_expression_async_eval_error(disable_critical_log):
|
||||
py_db = _DummyPyDB()
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import time
|
|||
from contextlib import contextmanager
|
||||
from tests_python.debugger_unittest import IS_CPYTHON
|
||||
from tests_python.debug_constants import TEST_CYTHON
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY312_OR_GREATER, IS_PY311_OR_GREATER
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY312_OR_GREATER, IS_PY311_OR_GREATER, IS_PY313_OR_GREATER, TODO_PY313_OR_GREATER
|
||||
|
||||
pytest_plugins = [
|
||||
str("tests_python.debugger_fixtures"),
|
||||
|
@ -296,6 +296,7 @@ def test_frame_eval_change_breakpoints(case_setup_force_frame_eval):
|
|||
writer.finished_ok = True
|
||||
|
||||
|
||||
@pytest.mark.skipif(TODO_PY313_OR_GREATER, reason="Flakey on python 3.13 or newer")
|
||||
def test_generator_code_cache(case_setup_force_frame_eval):
|
||||
with case_setup_force_frame_eval.test_file("_debugger_case_yield_from.py") as writer:
|
||||
break1_line = writer.get_line_index_with_content("break1")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import sys
|
||||
from _pydevd_bundle.pydevd_constants import IS_PY312_OR_GREATER, \
|
||||
IS_PY311_OR_GREATER
|
||||
IS_PY311_OR_GREATER, IS_PY313_OR_GREATER
|
||||
try:
|
||||
from _pydevd_bundle import pydevd_bytecode_utils
|
||||
except ImportError:
|
||||
|
@ -173,7 +173,9 @@ def test_smart_step_into_bytecode_info_002():
|
|||
found = collect_smart_step_into_variants(
|
||||
frame, 0, 99999, base=function.__code__.co_firstlineno)
|
||||
|
||||
if IS_PY311_OR_GREATER:
|
||||
if IS_PY313_OR_GREATER:
|
||||
check_name_and_line(found, [('sys._getframe()', 1), ('foo.bar(\n Something(param1, param2=xxx.yyy),\n )', 2), ('call()', 5)])
|
||||
elif IS_PY311_OR_GREATER:
|
||||
check_name_and_line(found, [('sys._getframe()', 1), ('foo.bar(\n Something(param1, param2=xxx.yyy),\n )', 2), ('Something(param1, param2=xxx.yyy)', 3), ('call()', 5)])
|
||||
else:
|
||||
check_name_and_line(found, [('_getframe', 1), ('bar', 2), ('Something', 3), ('call', 5)])
|
||||
|
@ -194,7 +196,9 @@ def test_smart_step_into_bytecode_info_003():
|
|||
found = collect_smart_step_into_variants(
|
||||
frame, 0, 99999, base=function.__code__.co_firstlineno)
|
||||
|
||||
if IS_PY311_OR_GREATER:
|
||||
if IS_PY313_OR_GREATER:
|
||||
check_name_and_line(found, [('sys._getframe()', 1), ('foo.bar(\n Something(param1, param2=xxx.yyy), {}\n )', 2), ('call()', 5)])
|
||||
elif IS_PY311_OR_GREATER:
|
||||
check_name_and_line(found, [('sys._getframe()', 1), ('foo.bar(\n Something(param1, param2=xxx.yyy), {}\n )', 2), ('Something(param1, param2=xxx.yyy)', 3), ('call()', 5)])
|
||||
else:
|
||||
check_name_and_line(found, [('_getframe', 1), ('bar', 2), ('Something', 3), ('call', 5)])
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# pyright: strict
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from typing import Iterator
|
||||
|
||||
_SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
os.chdir(_SCRIPT_DIR)
|
||||
|
||||
_GIT_SUBREPO_ROOT = os.path.join(_SCRIPT_DIR, "build", "git-subrepo")
|
||||
os.environ["GIT_SUBREPO_ROOT"] = _GIT_SUBREPO_ROOT
|
||||
os.environ["PATH"] = (
|
||||
os.path.join(_GIT_SUBREPO_ROOT, "lib") + os.pathsep + os.environ["PATH"]
|
||||
)
|
||||
os.environ["FILTER_BRANCH_SQUELCH_WARNING"] = "1"
|
||||
|
||||
_GIT_URL = "https://github.com/fabioz/PyDev.Debugger.git"
|
||||
_SUBREPO_NAME = "src/debugpy/_vendored/pydevd"
|
||||
_SUBREPO_TMP = ".git/tmp/subrepo/" + _SUBREPO_NAME
|
||||
|
||||
|
||||
@contextmanager
|
||||
def cwd(p: str) -> Iterator[None]:
|
||||
old = os.getcwd()
|
||||
os.chdir(p)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
os.chdir(old)
|
||||
|
||||
|
||||
def invoke_call(*args: str) -> None:
|
||||
print(f"== {shlex.join(args)} ==")
|
||||
subprocess.check_call(args)
|
||||
|
||||
|
||||
def invoke_call_ok(*args: str) -> bool:
|
||||
try:
|
||||
subprocess.check_call(args)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def invoke_output(*args: str, no_log: bool = False) -> str:
|
||||
if not no_log:
|
||||
print(f"== {shlex.join(args)} ==")
|
||||
|
||||
return subprocess.check_output(args, text=True)
|
||||
|
||||
|
||||
def get_current_commit() -> str:
|
||||
return invoke_output(
|
||||
"git",
|
||||
"config",
|
||||
"--file",
|
||||
f"{_SUBREPO_NAME}/.gitrepo",
|
||||
"subrepo.commit",
|
||||
no_log=True,
|
||||
).strip()
|
||||
|
||||
|
||||
def err_exit(message: str):
|
||||
print(message, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def clone() -> None:
|
||||
# Clone the repo.
|
||||
invoke_call("git", "subrepo", "clone", _GIT_URL, _SUBREPO_NAME)
|
||||
|
||||
|
||||
def reclone() -> None:
|
||||
# Remove the temporary branch and worktree.
|
||||
invoke_call("git", "subrepo", "clean", _SUBREPO_NAME)
|
||||
# Force clone the repo.
|
||||
invoke_call("git", "subrepo", "clone", "--force", _GIT_URL, _SUBREPO_NAME)
|
||||
|
||||
|
||||
def pull() -> None:
|
||||
# Remove the temporary branch and worktree.
|
||||
invoke_call("git", "subrepo", "clean", "--force", _SUBREPO_NAME)
|
||||
|
||||
invoke_call("git", "subrepo", "fetch", _SUBREPO_NAME)
|
||||
with cwd(_SUBREPO_NAME):
|
||||
new_commit = invoke_output("git", "rev-parse","--verify", "FETCH_HEAD").strip()
|
||||
|
||||
print(f"Updating to pydevd commit {new_commit}.")
|
||||
|
||||
# Pull changes and squash commit them.
|
||||
invoke_call("git", "subrepo", "pull", _SUBREPO_NAME)
|
||||
|
||||
# Now, branch to see if there are any diffs. If not, then we can just reclone.
|
||||
print("Branching to check if the pydevd tree is clean.")
|
||||
invoke_call("git", "subrepo", "clean", _SUBREPO_NAME)
|
||||
invoke_call("git", "subrepo", "branch", _SUBREPO_NAME)
|
||||
|
||||
with cwd(_SUBREPO_TMP):
|
||||
no_diff = invoke_call_ok("git", "diff", "--quiet", new_commit)
|
||||
|
||||
if no_diff:
|
||||
# No diff, so it's safe to manually move the subrepo parent to HEAD.
|
||||
print("pydevd tree is clean, moving subrepo parent.")
|
||||
new_parent = invoke_output("git", "rev-parse", "HEAD", no_log=True).strip()
|
||||
invoke_call(
|
||||
"git",
|
||||
"config",
|
||||
"--file",
|
||||
"src/debugpy/_vendored/pydevd/.gitrepo",
|
||||
"subrepo.parent",
|
||||
new_parent,
|
||||
)
|
||||
invoke_call("git", "commit", "-am", "Update git-subrepo parent")
|
||||
else:
|
||||
print("pydevd tree has changes not pushed upstream.")
|
||||
|
||||
|
||||
def branch(message: str) -> None:
|
||||
current_commit = get_current_commit()
|
||||
|
||||
# Remove the temporary branch and worktree.
|
||||
invoke_call("git", "subrepo", "clean", _SUBREPO_NAME)
|
||||
# Ensure we have all of the subrepo refs.
|
||||
invoke_call("git", "subrepo", "fetch", _SUBREPO_NAME)
|
||||
# Populate the subrepo/src/debugpy/_vendored/pydevd branch with new changes.
|
||||
invoke_call("git", "subrepo", "branch", _SUBREPO_NAME)
|
||||
|
||||
# Enter worktree; changes here are applied to the subrepo/src/debugpy/_vendored/pydevd branch.
|
||||
with cwd(_SUBREPO_TMP):
|
||||
# Remove all commits after the last pull and restage the difference.
|
||||
invoke_call("git", "reset", "--soft", current_commit)
|
||||
|
||||
hasModifiedFile = invoke_output("git", "status","-s").strip()
|
||||
|
||||
if hasModifiedFile:
|
||||
# Commit changes with a new message.
|
||||
invoke_call("git", "commit", "-m", message)
|
||||
|
||||
|
||||
def push_to_fork(fork_remote: str, fork_branch: str) -> None:
|
||||
invoke_call("git", "push", fork_remote, f"subrepo/src/debugpy/_vendored/pydevd:{fork_branch}")
|
||||
|
||||
|
||||
def commit() -> None:
|
||||
invoke_call("git", "subrepo", "commit", _SUBREPO_NAME)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
||||
)
|
||||
subparsers = parser.add_subparsers(dest="subcommand", required=True)
|
||||
|
||||
subparsers.add_parser(
|
||||
"clone",
|
||||
help="clones pydevd for the first time",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
subparsers.add_parser(
|
||||
"reclone",
|
||||
help="force reclones pydevd",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
subparsers.add_parser(
|
||||
"pull",
|
||||
help="pulls pydevd",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
|
||||
branch_parser = subparsers.add_parser(
|
||||
"branch",
|
||||
help="squashes changes to pydevd",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
branch_parser.add_argument(
|
||||
"-m",
|
||||
"--message",
|
||||
dest="message",
|
||||
required=True,
|
||||
help="message for the squashed commit",
|
||||
)
|
||||
|
||||
ptf_parser = subparsers.add_parser(
|
||||
"push-to-fork",
|
||||
help="pushes the squashed changes to pydevd",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
ptf_parser.add_argument(
|
||||
"--fork-remote",
|
||||
dest="fork_remote",
|
||||
default="pydevd-fork",
|
||||
help="pydevd remote",
|
||||
)
|
||||
ptf_parser.add_argument(
|
||||
"--fork-branch",
|
||||
dest="fork_branch",
|
||||
required=True,
|
||||
help="branch to push to on the remote",
|
||||
)
|
||||
|
||||
subparsers.add_parser(
|
||||
"commit",
|
||||
help=f"runs 'git subrepo commit {_SUBREPO_NAME}'",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.subcommand == "clone":
|
||||
clone()
|
||||
elif args.subcommand == "reclone":
|
||||
reclone()
|
||||
elif args.subcommand == "pull":
|
||||
pull()
|
||||
elif args.subcommand == "branch":
|
||||
branch(args.message)
|
||||
elif args.subcommand == "push-to-fork":
|
||||
push_to_fork(args.fork_remote, args.fork_branch)
|
||||
elif args.subcommand == "commit":
|
||||
commit()
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Загрузка…
Ссылка в новой задаче