From 6b10225c94087d47782049aafc8e12efa512337b Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 1 Jul 2023 01:29:58 +0900 Subject: [PATCH 01/27] Disable renovate dashboard --- renovate.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 39a2b6e9..09e16da6 100644 --- a/renovate.json +++ b/renovate.json @@ -2,5 +2,6 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:base" - ] + ], + "dependencyDashboard": false } From 8157da51e844f619eb693c5f5dd2758dca1d1c98 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 4 Sep 2023 02:04:26 -0600 Subject: [PATCH 02/27] Add support for Python 3.12 (#1134) --- .github/workflows/test.yaml | 7 +++++++ pyproject.toml | 1 + 2 files changed, 8 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6b1e0f32..1153b9e4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -8,6 +8,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true +env: + FORCE_COLOR: 1 + jobs: test: runs-on: ubuntu-latest @@ -24,6 +27,9 @@ jobs: - db: "mariadb:10.6" py: "3.11" + - db: "mariadb:10.6" + py: "3.12" + - db: "mariadb:lts" py: "3.9" @@ -62,6 +68,7 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.py }} + allow-prereleases: true cache: 'pip' cache-dependency-path: 'requirements-dev.txt' diff --git a/pyproject.toml b/pyproject.toml index 15df9f3c..8e75058c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Intended Audience :: Developers", From 9e956ad5212f533a0541ee4f5e9e676d8a11b6d6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 11:59:37 +0900 Subject: [PATCH 03/27] update actions/checkout action to v4 (#1136) --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/django.yaml | 2 +- .github/workflows/lint.yaml | 2 +- .github/workflows/test.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a4c434c5..13519f18 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/django.yaml b/.github/workflows/django.yaml index da664f85..395c64fd 100644 --- a/.github/workflows/django.yaml +++ b/.github/workflows/django.yaml @@ -36,7 +36,7 @@ jobs: mysql -uroot -proot -e "CREATE USER 'scott'@'%' IDENTIFIED BY 'tiger'; GRANT ALL ON *.* TO scott;" mysql -uroot -proot -e "CREATE DATABASE django_default; CREATE DATABASE django_other;" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 77edb0c3..c0c013b0 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -13,7 +13,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: psf/black@stable with: diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1153b9e4..dcd1abea 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -56,7 +56,7 @@ jobs: - /run/mysqld:/run/mysqld steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Workaround MySQL container permissions if: startsWith(matrix.db, 'mysql') From c1d8063759a4a3968b0f7907e098554d9a8ad552 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 06:55:02 +0900 Subject: [PATCH 04/27] Update codecov/codecov-action action to v4 (#1137) --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index dcd1abea..b28b63bd 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -106,4 +106,4 @@ jobs: - name: Upload coverage reports to Codecov if: github.repository == 'PyMySQL/PyMySQL' - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 From 39bf50e057332d27b8ccf27f11d04467fa1e3904 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 14 Nov 2023 18:34:43 +0900 Subject: [PATCH 05/27] ci: use codecov@v3 (#1142) v4 is still beta. --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b28b63bd..dcd1abea 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -106,4 +106,4 @@ jobs: - name: Upload coverage reports to Codecov if: github.repository == 'PyMySQL/PyMySQL' - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v3 From 5820fa09844276477b3f6299341f9dc05d415526 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 14 Nov 2023 18:35:17 +0900 Subject: [PATCH 06/27] update CHANGELOG Add future changes. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6283670..f371ef32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * Error classes in Cursor class will be removed after 2024-06 * `Connection.set_charset(charset)` will be removed after 2024-06 * `db` and `passwd` will emit DeprecationWarning in v1.2. See #933. - +* `Connection.ping(reconnect)` change the default to not reconnect. ## v1.1.0 From 8b514a4bc103852c8031fd4e0e634ae3d2c10c22 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 02:44:13 +0900 Subject: [PATCH 07/27] ci: update dessant/lock-threads action to v5 (#1141) --- .github/workflows/lock.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 780dd92d..21449e3b 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -13,5 +13,5 @@ jobs: if: github.repository == 'PyMySQL/PyMySQL' runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v4 + - uses: dessant/lock-threads@v5 From 523f0949f33f481e4d41c920c2e1314faeae28ab Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 13:51:06 +0900 Subject: [PATCH 08/27] update document settings --- .readthedocs.yaml | 22 ++++ docs/Makefile | 24 ----- docs/make.bat | 242 ------------------------------------------ docs/source/conf.py | 3 +- docs/source/index.rst | 4 +- 5 files changed, 26 insertions(+), 269 deletions(-) create mode 100644 .readthedocs.yaml delete mode 100644 docs/make.bat diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..0ff55962 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,22 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/source/conf.py + +# We recommend specifying your dependencies to enable reproducible builds: +# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +# python: +# install: +# - requirements: docs/requirements.txt diff --git a/docs/Makefile b/docs/Makefile index d3725552..c1240d2b 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -74,30 +74,6 @@ json: @echo @echo "Build finished; now you can process the JSON files." -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyMySQL.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyMySQL.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/PyMySQL" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PyMySQL" - @echo "# devhelp" - epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index dcd4287c..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,242 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -set I18NSPHINXOPTS=%SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PyMySQL.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PyMySQL.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %BUILDDIR%/.. - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/docs/source/conf.py b/docs/source/conf.py index a57a03c4..d346fbda 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -101,7 +101,8 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "default" +# html_theme = "default" +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/source/index.rst b/docs/source/index.rst index 97633f1a..e64b6423 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,5 +1,5 @@ -Welcome to PyMySQL's documentation! -=================================== +PyMySQL documentation +===================== .. toctree:: :maxdepth: 2 From f62893a2c284468091efc95e5b744abcf274dc34 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 13:57:25 +0900 Subject: [PATCH 09/27] update document settings --- docs/source/conf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index d346fbda..410e9c74 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -30,7 +30,7 @@ # ones. extensions = [ "sphinx.ext.autodoc", - "sphinx.ext.intersphinx", + "sphinx_rtd_theme", ] # Add any paths that contain templates here, relative to this directory. @@ -47,7 +47,7 @@ # General information about the project. project = "PyMySQL" -copyright = "2016, Yutaka Matsubara and GitHub contributors" +copyright = "2023, Inada Naoki and GitHub contributors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -104,6 +104,7 @@ # html_theme = "default" html_theme = "sphinx_rtd_theme" + # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. From eb0b6e3429fcd1971be56cae32ffe5780c1c9cb6 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 13:57:25 +0900 Subject: [PATCH 10/27] update document settings --- docs/source/conf.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 410e9c74..1eafbda8 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -30,7 +30,6 @@ # ones. extensions = [ "sphinx.ext.autodoc", - "sphinx_rtd_theme", ] # Add any paths that contain templates here, relative to this directory. @@ -101,9 +100,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -# html_theme = "default" -html_theme = "sphinx_rtd_theme" - + html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From 7f96f9335181c5ae4992a097540348a2ae174cc6 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 14:12:24 +0900 Subject: [PATCH 11/27] fix conf.py --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1eafbda8..a8bee6c6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -100,7 +100,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. - html_theme = "default" +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From 910e5fc1e2bec0e80f75ac5c2d955686e3a5242c Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 14:28:25 +0900 Subject: [PATCH 12/27] update document settings --- .readthedocs.yaml | 15 +++++---------- docs/requirements.txt | 2 ++ 2 files changed, 7 insertions(+), 10 deletions(-) create mode 100644 docs/requirements.txt diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 0ff55962..59fdb65d 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,22 +1,17 @@ # .readthedocs.yaml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required version: 2 -# Set the version of Python and other tools you might need build: os: ubuntu-22.04 tools: - python: "3.11" + python: "3.12" + +python: + install: + - requirements: docs/requirements.txt # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/source/conf.py - -# We recommend specifying your dependencies to enable reproducible builds: -# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -# python: -# install: -# - requirements: docs/requirements.txt diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..8d45d0b6 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +sphinx~=7.2 +sphinx-rtd-theme~=1.3.0 From 0001c409524e4738a3e686c7faf65421281fbf4f Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 14:34:27 +0900 Subject: [PATCH 13/27] doc: use rtd theme (#1143) --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index a8bee6c6..78dc55ca 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -100,7 +100,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "default" +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From 1ed7cffc0335442235ac103ed458ae38f95b33b1 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 14:39:24 +0900 Subject: [PATCH 14/27] fix ruff error --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 8e75058c..b9a3ef54 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ line-length = 99 exclude = [ "pymysql/tests/thirdparty", ] +ignore = ["E721"] [tool.pdm.dev-dependencies] dev = [ From 84d3f93701341ba34c352663d3a5fc22af2f3d32 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 15 Nov 2023 17:24:51 +0900 Subject: [PATCH 15/27] use Ruff as formatter (#1144) --- .github/workflows/lint.yaml | 14 ++++++++------ pymysql/protocol.py | 4 ++-- pymysql/tests/test_SSCursor.py | 5 +---- pymysql/tests/test_basic.py | 6 +++--- pymysql/tests/test_cursor.py | 3 +-- pymysql/tests/test_issues.py | 5 ++--- pymysql/tests/test_nextset.py | 2 +- pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py | 8 ++++---- .../test_MySQLdb/test_MySQLdb_dbapi20.py | 2 +- pyproject.toml | 1 - 10 files changed, 23 insertions(+), 27 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index c0c013b0..269211c2 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -13,11 +13,13 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: checkout + uses: actions/checkout@v4 - - uses: psf/black@stable - with: - options: "--check --verbose" - src: "." + - name: lint + uses: chartboost/ruff-action@v1 - - uses: chartboost/ruff-action@v1 + - name: check format + uses: chartboost/ruff-action@v1 + with: + args: "format --diff" diff --git a/pymysql/protocol.py b/pymysql/protocol.py index 2db92d39..340d9cf2 100644 --- a/pymysql/protocol.py +++ b/pymysql/protocol.py @@ -89,8 +89,8 @@ def advance(self, length): new_position = self._position + length if new_position < 0 or new_position > len(self._data): raise Exception( - "Invalid advance amount (%s) for cursor. " - "Position=%s" % (length, new_position) + "Invalid advance amount (%s) for cursor. Position=%s" + % (length, new_position) ) self._position = new_position diff --git a/pymysql/tests/test_SSCursor.py b/pymysql/tests/test_SSCursor.py index 9cb5bafe..d5e6e2bc 100644 --- a/pymysql/tests/test_SSCursor.py +++ b/pymysql/tests/test_SSCursor.py @@ -27,10 +27,7 @@ def test_SSCursor(self): # Create table cursor.execute( - "CREATE TABLE tz_data (" - "region VARCHAR(64)," - "zone VARCHAR(64)," - "name VARCHAR(64))" + "CREATE TABLE tz_data (region VARCHAR(64), zone VARCHAR(64), name VARCHAR(64))" ) conn.begin() diff --git a/pymysql/tests/test_basic.py b/pymysql/tests/test_basic.py index e77605fd..c60b0cca 100644 --- a/pymysql/tests/test_basic.py +++ b/pymysql/tests/test_basic.py @@ -364,7 +364,7 @@ def test_bulk_insert(self): data = [(0, "bob", 21, 123), (1, "jim", 56, 45), (2, "fred", 100, 180)] cursor.executemany( - "insert into bulkinsert (id, name, age, height) " "values (%s,%s,%s,%s)", + "insert into bulkinsert (id, name, age, height) values (%s,%s,%s,%s)", data, ) self.assertEqual( @@ -414,14 +414,14 @@ def test_bulk_insert_single_record(self): cursor = conn.cursor() data = [(0, "bob", 21, 123)] cursor.executemany( - "insert into bulkinsert (id, name, age, height) " "values (%s,%s,%s,%s)", + "insert into bulkinsert (id, name, age, height) values (%s,%s,%s,%s)", data, ) cursor.execute("commit") self._verify_records(data) def test_issue_288(self): - """executemany should work with "insert ... on update" """ + """executemany should work with "insert ... on update""" conn = self.connect() cursor = conn.cursor() data = [(0, "bob", 21, 123), (1, "jim", 56, 45), (2, "fred", 100, 180)] diff --git a/pymysql/tests/test_cursor.py b/pymysql/tests/test_cursor.py index b292c206..2e267fb6 100644 --- a/pymysql/tests/test_cursor.py +++ b/pymysql/tests/test_cursor.py @@ -17,8 +17,7 @@ def setUp(self): ) cursor = conn.cursor() cursor.execute( - "insert into test (data) values " - "('row1'), ('row2'), ('row3'), ('row4'), ('row5')" + "insert into test (data) values ('row1'), ('row2'), ('row3'), ('row4'), ('row5')" ) conn.commit() cursor.close() diff --git a/pymysql/tests/test_issues.py b/pymysql/tests/test_issues.py index 3564d3a6..f1fe8dd4 100644 --- a/pymysql/tests/test_issues.py +++ b/pymysql/tests/test_issues.py @@ -401,10 +401,9 @@ def test_issue_321(self): sql_insert = "insert into issue321 (value_1, value_2) values (%s, %s)" sql_dict_insert = ( - "insert into issue321 (value_1, value_2) " - "values (%(value_1)s, %(value_2)s)" + "insert into issue321 (value_1, value_2) values (%(value_1)s, %(value_2)s)" ) - sql_select = "select * from issue321 where " "value_1 in %s and value_2=%s" + sql_select = "select * from issue321 where value_1 in %s and value_2=%s" data = [ [("a",), "\u0430"], [["b"], "\u0430"], diff --git a/pymysql/tests/test_nextset.py b/pymysql/tests/test_nextset.py index 4b6b2a77..a10f8d5b 100644 --- a/pymysql/tests/test_nextset.py +++ b/pymysql/tests/test_nextset.py @@ -75,7 +75,7 @@ def test_multi_statement_warnings(self): cursor = con.cursor() try: - cursor.execute("DROP TABLE IF EXISTS a; " "DROP TABLE IF EXISTS b;") + cursor.execute("DROP TABLE IF EXISTS a; DROP TABLE IF EXISTS b;") except TypeError: self.fail() diff --git a/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py b/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py index 83851295..fff14b86 100644 --- a/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py +++ b/pymysql/tests/thirdparty/test_MySQLdb/dbapi20.py @@ -299,7 +299,7 @@ def test_rowcount(self): self.assertEqual( cur.rowcount, -1, - "cursor.rowcount should be -1 after executing no-result " "statements", + "cursor.rowcount should be -1 after executing no-result statements", ) cur.execute( "insert into %sbooze values ('Victoria Bitter')" % (self.table_prefix) @@ -409,12 +409,12 @@ def _paraminsert(self, cur): self.assertEqual( beers[0], "Cooper's", - "cursor.fetchall retrieved incorrect data, or data inserted " "incorrectly", + "cursor.fetchall retrieved incorrect data, or data inserted incorrectly", ) self.assertEqual( beers[1], "Victoria Bitter", - "cursor.fetchall retrieved incorrect data, or data inserted " "incorrectly", + "cursor.fetchall retrieved incorrect data, or data inserted incorrectly", ) def test_executemany(self): @@ -482,7 +482,7 @@ def test_fetchone(self): self.assertEqual( cur.fetchone(), None, - "cursor.fetchone should return None if a query retrieves " "no rows", + "cursor.fetchone should return None if a query retrieves no rows", ) self.assertTrue(cur.rowcount in (-1, 0)) diff --git a/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py b/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py index c68289fe..5c34d40d 100644 --- a/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py +++ b/pymysql/tests/thirdparty/test_MySQLdb/test_MySQLdb_dbapi20.py @@ -98,7 +98,7 @@ def test_fetchone(self): self.assertEqual( cur.fetchone(), None, - "cursor.fetchone should return None if a query retrieves " "no rows", + "cursor.fetchone should return None if a query retrieves no rows", ) self.assertTrue(cur.rowcount in (-1, 0)) diff --git a/pyproject.toml b/pyproject.toml index b9a3ef54..1c10b4b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,7 +53,6 @@ exclude = ["tests*", "pymysql.tests*"] version = {attr = "pymysql.VERSION_STRING"} [tool.ruff] -line-length = 99 exclude = [ "pymysql/tests/thirdparty", ] From d206182822d61650eed8ccd167171ea6131113d1 Mon Sep 17 00:00:00 2001 From: Sergei Vaskov Date: Thu, 16 Nov 2023 12:39:02 +0200 Subject: [PATCH 16/27] Add ssl_key_password param (#1145) Add support for SSL private key password in Connection class to handle encrypted keys. Co-authored-by: Sergei Vaskov --- pymysql/connections.py | 10 +++- pymysql/tests/test_connection.py | 81 +++++++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/pymysql/connections.py b/pymysql/connections.py index 843bea5e..7e12e169 100644 --- a/pymysql/connections.py +++ b/pymysql/connections.py @@ -135,6 +135,7 @@ class Connection: :param ssl_disabled: A boolean value that disables usage of TLS. :param ssl_key: Path to the file that contains a PEM-formatted private key for the client certificate. + :param ssl_key_password: The password for the client certificate private key. :param ssl_verify_cert: Set to true to check the server certificate's validity. :param ssl_verify_identity: Set to true to check the server's identity. :param read_default_group: Group to read from in the configuration file. @@ -201,6 +202,7 @@ def __init__( ssl_cert=None, ssl_disabled=None, ssl_key=None, + ssl_key_password=None, ssl_verify_cert=None, ssl_verify_identity=None, compress=None, # not supported @@ -262,7 +264,7 @@ def _config(key, arg): if not ssl: ssl = {} if isinstance(ssl, dict): - for key in ["ca", "capath", "cert", "key", "cipher"]: + for key in ["ca", "capath", "cert", "key", "password", "cipher"]: value = _config("ssl-" + key, ssl.get(key)) if value: ssl[key] = value @@ -281,6 +283,8 @@ def _config(key, arg): ssl["cert"] = ssl_cert if ssl_key is not None: ssl["key"] = ssl_key + if ssl_key_password is not None: + ssl["password"] = ssl_key_password if ssl: if not SSL_ENABLED: raise NotImplementedError("ssl module not found") @@ -389,7 +393,9 @@ def _create_ssl_ctx(self, sslp): else: ctx.verify_mode = ssl.CERT_NONE if hasnoca else ssl.CERT_REQUIRED if "cert" in sslp: - ctx.load_cert_chain(sslp["cert"], keyfile=sslp.get("key")) + ctx.load_cert_chain( + sslp["cert"], keyfile=sslp.get("key"), password=sslp.get("password") + ) if "cipher" in sslp: ctx.set_ciphers(sslp["cipher"]) ctx.options |= ssl.OP_NO_SSLv2 diff --git a/pymysql/tests/test_connection.py b/pymysql/tests/test_connection.py index 0803efc9..ccfc4a32 100644 --- a/pymysql/tests/test_connection.py +++ b/pymysql/tests/test_connection.py @@ -574,7 +574,11 @@ def test_ssl_connect(self): assert create_default_context.called assert dummy_ssl_context.check_hostname assert dummy_ssl_context.verify_mode == ssl.CERT_REQUIRED - dummy_ssl_context.load_cert_chain.assert_called_with("cert", keyfile="key") + dummy_ssl_context.load_cert_chain.assert_called_with( + "cert", + keyfile="key", + password=None, + ) dummy_ssl_context.set_ciphers.assert_called_with("cipher") dummy_ssl_context = mock.Mock(options=0) @@ -592,7 +596,34 @@ def test_ssl_connect(self): assert create_default_context.called assert dummy_ssl_context.check_hostname assert dummy_ssl_context.verify_mode == ssl.CERT_REQUIRED - dummy_ssl_context.load_cert_chain.assert_called_with("cert", keyfile="key") + dummy_ssl_context.load_cert_chain.assert_called_with( + "cert", + keyfile="key", + password=None, + ) + dummy_ssl_context.set_ciphers.assert_not_called + + dummy_ssl_context = mock.Mock(options=0) + with mock.patch("pymysql.connections.Connection.connect"), mock.patch( + "pymysql.connections.ssl.create_default_context", + new=mock.Mock(return_value=dummy_ssl_context), + ) as create_default_context: + pymysql.connect( + ssl={ + "ca": "ca", + "cert": "cert", + "key": "key", + "password": "password", + }, + ) + assert create_default_context.called + assert dummy_ssl_context.check_hostname + assert dummy_ssl_context.verify_mode == ssl.CERT_REQUIRED + dummy_ssl_context.load_cert_chain.assert_called_with( + "cert", + keyfile="key", + password="password", + ) dummy_ssl_context.set_ciphers.assert_not_called dummy_ssl_context = mock.Mock(options=0) @@ -622,7 +653,11 @@ def test_ssl_connect(self): assert create_default_context.called assert not dummy_ssl_context.check_hostname assert dummy_ssl_context.verify_mode == ssl.CERT_NONE - dummy_ssl_context.load_cert_chain.assert_called_with("cert", keyfile="key") + dummy_ssl_context.load_cert_chain.assert_called_with( + "cert", + keyfile="key", + password=None, + ) dummy_ssl_context.set_ciphers.assert_not_called for ssl_verify_cert in (True, "1", "yes", "true"): @@ -640,7 +675,9 @@ def test_ssl_connect(self): assert not dummy_ssl_context.check_hostname assert dummy_ssl_context.verify_mode == ssl.CERT_REQUIRED dummy_ssl_context.load_cert_chain.assert_called_with( - "cert", keyfile="key" + "cert", + keyfile="key", + password=None, ) dummy_ssl_context.set_ciphers.assert_not_called @@ -659,7 +696,9 @@ def test_ssl_connect(self): assert not dummy_ssl_context.check_hostname assert dummy_ssl_context.verify_mode == ssl.CERT_NONE dummy_ssl_context.load_cert_chain.assert_called_with( - "cert", keyfile="key" + "cert", + keyfile="key", + password=None, ) dummy_ssl_context.set_ciphers.assert_not_called @@ -682,7 +721,9 @@ def test_ssl_connect(self): ssl.CERT_REQUIRED if ssl_ca is not None else ssl.CERT_NONE ), (ssl_ca, ssl_verify_cert) dummy_ssl_context.load_cert_chain.assert_called_with( - "cert", keyfile="key" + "cert", + keyfile="key", + password=None, ) dummy_ssl_context.set_ciphers.assert_not_called @@ -700,7 +741,33 @@ def test_ssl_connect(self): assert create_default_context.called assert dummy_ssl_context.check_hostname assert dummy_ssl_context.verify_mode == ssl.CERT_NONE - dummy_ssl_context.load_cert_chain.assert_called_with("cert", keyfile="key") + dummy_ssl_context.load_cert_chain.assert_called_with( + "cert", + keyfile="key", + password=None, + ) + dummy_ssl_context.set_ciphers.assert_not_called + + dummy_ssl_context = mock.Mock(options=0) + with mock.patch("pymysql.connections.Connection.connect"), mock.patch( + "pymysql.connections.ssl.create_default_context", + new=mock.Mock(return_value=dummy_ssl_context), + ) as create_default_context: + pymysql.connect( + ssl_ca="ca", + ssl_cert="cert", + ssl_key="key", + ssl_key_password="password", + ssl_verify_identity=True, + ) + assert create_default_context.called + assert dummy_ssl_context.check_hostname + assert dummy_ssl_context.verify_mode == ssl.CERT_NONE + dummy_ssl_context.load_cert_chain.assert_called_with( + "cert", + keyfile="key", + password="password", + ) dummy_ssl_context.set_ciphers.assert_not_called dummy_ssl_context = mock.Mock(options=0) From f476773eca5480c75e6d418abd7e73ae6c51ac22 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:31:03 +0900 Subject: [PATCH 17/27] chore(deps): update dependency sphinx-rtd-theme to v2 (#1147) --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 8d45d0b6..01406623 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,2 @@ sphinx~=7.2 -sphinx-rtd-theme~=1.3.0 +sphinx-rtd-theme~=2.0.0 From f13f054abcc18b39855a760a84be0a517f0da658 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:34:08 +0900 Subject: [PATCH 18/27] chore(deps): update actions/setup-python action to v5 (#1152) --- .github/workflows/django.yaml | 2 +- .github/workflows/test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/django.yaml b/.github/workflows/django.yaml index 395c64fd..5c460954 100644 --- a/.github/workflows/django.yaml +++ b/.github/workflows/django.yaml @@ -39,7 +39,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index dcd1abea..bfe8fff1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -65,7 +65,7 @@ jobs: /usr/bin/docker ps --all --filter status=exited --no-trunc --format "{{.ID}}" | xargs -r /usr/bin/docker start - name: Set up Python ${{ matrix.py }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.py }} allow-prereleases: true From 1e28be81c24dde66f8acbf4c5e24f60d6b5e72e7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:04:49 +0900 Subject: [PATCH 19/27] chore(deps): update github/codeql-action action to v3 (#1154) --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 13519f18..df49979e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -34,7 +34,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: "python" # If you wish to specify custom queries, you can do so here or in a config file. @@ -45,7 +45,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -59,4 +59,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 1f0b7856de4008e7e4c1e8c1b215d5d4dfaecd1a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Feb 2024 12:55:12 +0900 Subject: [PATCH 20/27] chore(deps): update codecov/codecov-action action to v4 (#1158) --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index bfe8fff1..6d59d8c4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -106,4 +106,4 @@ jobs: - name: Upload coverage reports to Codecov if: github.repository == 'PyMySQL/PyMySQL' - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 From 9694747ae619e88b792a8e0b4c08036572452584 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 2 Feb 2024 15:42:24 +0900 Subject: [PATCH 21/27] pyupgrade --- docs/source/conf.py | 2 -- pymysql/connections.py | 23 +++++++++-------------- pymysql/protocol.py | 6 ++---- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 78dc55ca..158d0d12 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # PyMySQL documentation build configuration file, created by # sphinx-quickstart on Tue May 17 12:01:11 2016. # diff --git a/pymysql/connections.py b/pymysql/connections.py index 7e12e169..dc121e1b 100644 --- a/pymysql/connections.py +++ b/pymysql/connections.py @@ -84,8 +84,7 @@ def _lenenc_int(i): return b"\xfe" + struct.pack(" len(self._data): raise Exception( - "Invalid advance amount (%s) for cursor. Position=%s" - % (length, new_position) + f"Invalid advance amount ({length}) for cursor. Position={new_position}" ) self._position = new_position From bbd049f40db9c696574ce6f31669880042c56d79 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 2 Feb 2024 17:16:41 +0900 Subject: [PATCH 22/27] Support error packet without sqlstate (#1160) Fix #1156 --- pymysql/connections.py | 2 -- pymysql/err.py | 9 ++++++++- pymysql/tests/test_err.py | 22 ++++++++++++---------- pyproject.toml | 2 ++ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/pymysql/connections.py b/pymysql/connections.py index dc121e1b..3a04ddd6 100644 --- a/pymysql/connections.py +++ b/pymysql/connections.py @@ -765,8 +765,6 @@ def _read_packet(self, packet_type=MysqlPacket): dump_packet(recv_data) buff += recv_data # https://dev.mysql.com/doc/internals/en/sending-more-than-16mbyte.html - if bytes_to_read == 0xFFFFFF: - continue if bytes_to_read < MAX_PACKET_LEN: break diff --git a/pymysql/err.py b/pymysql/err.py index 3da5b166..dac65d3b 100644 --- a/pymysql/err.py +++ b/pymysql/err.py @@ -136,7 +136,14 @@ def _map_error(exc, *errors): def raise_mysql_exception(data): errno = struct.unpack(" Date: Tue, 26 Mar 2024 18:02:41 +1100 Subject: [PATCH 23/27] test json - mariadb without JSON type (#1165) MariaDB-11.0.1 removed the 5.5.5 version hack (MDEV-28910). MariaDB still doesn't support JSON as a type. Use get_mysql_vendor() == mysql for the final part of test_json. --- pymysql/tests/test_basic.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pymysql/tests/test_basic.py b/pymysql/tests/test_basic.py index c60b0cca..0fe13b59 100644 --- a/pymysql/tests/test_basic.py +++ b/pymysql/tests/test_basic.py @@ -323,9 +323,10 @@ def test_json(self): res = cur.fetchone()[0] self.assertEqual(json.loads(res), json.loads(json_str)) - cur.execute("SELECT CAST(%s AS JSON) AS x", (json_str,)) - res = cur.fetchone()[0] - self.assertEqual(json.loads(res), json.loads(json_str)) + if self.get_mysql_vendor(conn) == "mysql": + cur.execute("SELECT CAST(%s AS JSON) AS x", (json_str,)) + res = cur.fetchone()[0] + self.assertEqual(json.loads(res), json.loads(json_str)) class TestBulkInserts(base.PyMySQLTestCase): From 69f6c7439bee14784e0ea70ae107af6446cc0c67 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 4 May 2024 15:55:22 +0900 Subject: [PATCH 24/27] ruff format --- pymysql/__init__.py | 1 + pymysql/_auth.py | 1 + 2 files changed, 2 insertions(+) diff --git a/pymysql/__init__.py b/pymysql/__init__.py index 53625d37..37395551 100644 --- a/pymysql/__init__.py +++ b/pymysql/__init__.py @@ -21,6 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ + import sys from .constants import FIELD_TYPE diff --git a/pymysql/_auth.py b/pymysql/_auth.py index 99987b77..8ce744fb 100644 --- a/pymysql/_auth.py +++ b/pymysql/_auth.py @@ -1,6 +1,7 @@ """ Implements auth methods """ + from .err import OperationalError From 7f032a699d55340f05101deb4d7d4f63db4adc11 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Mon, 20 May 2024 13:25:18 +0900 Subject: [PATCH 25/27] remove coveralls from requirements --- requirements-dev.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 13d7f7fb..140d3706 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,4 +2,3 @@ cryptography PyNaCl>=1.4.0 pytest pytest-cov -coveralls From 521e40050cb386a499f68f483fefd144c493053c Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 18 May 2024 11:33:30 +0900 Subject: [PATCH 26/27] forbid dict parameter --- pymysql/converters.py | 6 +----- pymysql/tests/test_connection.py | 7 +++++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pymysql/converters.py b/pymysql/converters.py index 1adac752..dbf97ca7 100644 --- a/pymysql/converters.py +++ b/pymysql/converters.py @@ -27,11 +27,7 @@ def escape_item(val, charset, mapping=None): def escape_dict(val, charset, mapping=None): - n = {} - for k, v in val.items(): - quoted = escape_item(v, charset, mapping) - n[k] = quoted - return n + raise TypeError("dict can not be used as parameter") def escape_sequence(val, charset, mapping=None): diff --git a/pymysql/tests/test_connection.py b/pymysql/tests/test_connection.py index ccfc4a32..dcf3394c 100644 --- a/pymysql/tests/test_connection.py +++ b/pymysql/tests/test_connection.py @@ -848,12 +848,15 @@ def test_escape_no_default(self): self.assertRaises(TypeError, con.escape, 42, {}) - def test_escape_dict_value(self): + def test_escape_dict_raise_typeerror(self): + """con.escape(dict) should raise TypeError""" con = self.connect() mapping = con.encoders.copy() mapping[Foo] = escape_foo - self.assertEqual(con.escape({"foo": Foo()}, mapping), {"foo": "bar"}) + #self.assertEqual(con.escape({"foo": Foo()}, mapping), {"foo": "bar"}) + with self.assertRaises(TypeError): + con.escape({"foo": Foo()}) def test_escape_list_item(self): con = self.connect() From 2cab9ecc641e962565c6254a5091f90c47f59b35 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 21 May 2024 20:01:22 +0900 Subject: [PATCH 27/27] v1.1.1 --- CHANGELOG.md | 15 +++++++++++++++ pymysql/__init__.py | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f371ef32..825dc47c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ * `db` and `passwd` will emit DeprecationWarning in v1.2. See #933. * `Connection.ping(reconnect)` change the default to not reconnect. +## v1.1.1 + +Release date: 2024-05-21 + +> [!WARNING] +> This release fixes a vulnerability (CVE-2024-36039). +> All users are recommended to update to this version. +> +> If you can not update soon, check the input value from +> untrusted source has an expected type. Only dict input +> from untrusted source can be an attack vector. + +* Prohibit dict parameter for `Cursor.execute()`. It didn't produce valid SQL + and might cause SQL injection. (CVE-2024-36039) + ## v1.1.0 Release date: 2023-06-26 diff --git a/pymysql/__init__.py b/pymysql/__init__.py index 37395551..bbf9023e 100644 --- a/pymysql/__init__.py +++ b/pymysql/__init__.py @@ -49,8 +49,8 @@ # PyMySQL version. # Used by setuptools and connection_attrs -VERSION = (1, 1, 0, "final", 1) -VERSION_STRING = "1.1.0" +VERSION = (1, 1, 1, "final", 1) +VERSION_STRING = "1.1.1" ### for mysqlclient compatibility ### Django checks mysqlclient version.