From 19d78f0130c6bdb10fd5aae3d7952d9570f8579c Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Wed, 13 Oct 2021 22:59:12 +1100 Subject: [PATCH 01/11] docs: Fix a few typos There are small typos in: - docs/_static/searchtools.js - docs/_static/websupport.js Fixes: - Should read `utilities` rather than `utilties`. - Should read `occurrence` rather than `occurance`. --- docs/_static/searchtools.js | 4 ++-- docs/_static/websupport.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/_static/searchtools.js b/docs/_static/searchtools.js index 56676b2..64d124a 100644 --- a/docs/_static/searchtools.js +++ b/docs/_static/searchtools.js @@ -2,7 +2,7 @@ * searchtools.js_t * ~~~~~~~~~~~~~~~~ * - * Sphinx JavaScript utilties for the full-text search. + * Sphinx JavaScript utilities for the full-text search. * * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. @@ -594,7 +594,7 @@ var Search = { * helper function to return a node containing the * search summary for a given text. keywords is a list * of stemmed words, hlwords is the list of normal, unstemmed - * words. the first one is used to find the occurance, the + * words. the first one is used to find the occurrence, the * latter for highlighting it. */ makeSearchSummary : function(text, keywords, hlwords) { diff --git a/docs/_static/websupport.js b/docs/_static/websupport.js index 19fcda5..8e8f0aa 100644 --- a/docs/_static/websupport.js +++ b/docs/_static/websupport.js @@ -2,7 +2,7 @@ * websupport.js * ~~~~~~~~~~~~~ * - * sphinx.websupport utilties for all documentation. + * sphinx.websupport utilities for all documentation. * * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. From ec52fe0a0f7c4becbe181bd0e9bab05e3277c4fa Mon Sep 17 00:00:00 2001 From: Jayson Reis Date: Wed, 14 Dec 2022 16:32:35 +0100 Subject: [PATCH 02/11] chore: Add publish step --- .github/workflows/publish.yml | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..c7d6bfc --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,39 @@ +name: Publish Python 🐍 distributions 📦 to PyPI +on: push +jobs: + build-n-publish: + name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.10" + - name: Setup pandoc for changelog conversion + run: sudo apt update && sudo apt install -y pandoc + - name: Write pypi's readme + run: | + cat README.rst > to-pypi.rst + echo "" >> to-pypi.rst + pandoc -s --to rst -o /dev/stdout CHANGELOG.md | tee -a to-pypi.rst + mv to-pypi.rst README.rst + - name: Install pypa/build + run: >- + python -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: >- + python -m + build + --sdist + --wheel + --outdir dist/ + . + - name: Publish distribution 📦 to PyPI + if: startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} From f650430266419cdd2ffa5782e02c9ec1a7eec277 Mon Sep 17 00:00:00 2001 From: Jayson Reis Date: Wed, 14 Dec 2022 16:38:50 +0100 Subject: [PATCH 03/11] chore: Remove python 3.6 and add 3.11 to the pipeline --- .github/workflows/tests-and-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests-and-lint.yml b/.github/workflows/tests-and-lint.yml index 44d9527..3095c95 100644 --- a/.github/workflows/tests-and-lint.yml +++ b/.github/workflows/tests-and-lint.yml @@ -12,7 +12,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [2.7, 3.6, 3.7, 3.8, 3.9, "3.10"] + python-version: [2.7, 3.7, 3.8, 3.9, "3.10", 3.11] steps: - uses: actions/checkout@v2 From cd2f372aa9367858cd02277a2a7429f481181741 Mon Sep 17 00:00:00 2001 From: Alexandre Detiste Date: Mon, 13 May 2024 21:24:08 +0200 Subject: [PATCH 04/11] remove obsolete requirement --- requirements_test.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/requirements_test.txt b/requirements_test.txt index fb5565e..4cf6022 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,7 +1,5 @@ flake8~=4.0; python_version > '2.7' flake8~=3.9; python_version < '3.0' -m2r~=0.2.1 -mistune<2 # m2r breaks with newer versions mock~=4.0; python_version > '2.7' mock~=3.0; python_version < '3.0' pytest-cov~=3.0; python_version > '2.7' From 801f344c506ccce20fb0e8d84fac164d7379b79b Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Tue, 22 Oct 2024 18:06:43 -0700 Subject: [PATCH 05/11] Use an unofficial setup-python action that still works with 2.7 Signed-off-by: Anders Kaseorg --- .github/workflows/tests-and-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests-and-lint.yml b/.github/workflows/tests-and-lint.yml index 3095c95..b513035 100644 --- a/.github/workflows/tests-and-lint.yml +++ b/.github/workflows/tests-and-lint.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: LizardByte/setup-python-action@v2024.919.163656 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies From 3d44035396e514b70d478bb85d522e478ce5a2a7 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Tue, 22 Oct 2024 16:33:44 -0700 Subject: [PATCH 06/11] Avoid urllib.parse.splitport DeprecationWarning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “DeprecationWarning: urllib.parse.splitport() is deprecated as of 3.8, use urllib.parse.urlparse() instead” Signed-off-by: Anders Kaseorg --- bmemcached/protocol.py | 14 ++++---------- test/test_server_parsing.py | 5 ++--- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/bmemcached/protocol.py b/bmemcached/protocol.py index e45e010..1037888 100644 --- a/bmemcached/protocol.py +++ b/bmemcached/protocol.py @@ -1,13 +1,12 @@ from datetime import datetime, timedelta import logging -import re import socket import struct import threading try: - from urllib import splitport # type: ignore + from urlparse import SplitResult # type: ignore[import-not-found] except ImportError: - from urllib.parse import splitport # type: ignore + from urllib.parse import SplitResult # type: ignore[import-not-found] import zlib from io import BytesIO @@ -180,13 +179,8 @@ def split_host_port(cls, server): >>> split_host_port('127.0.0.1') ('127.0.0.1', 11211) """ - host, port = splitport(server) - if port is None: - port = 11211 - port = int(port) - if re.search(':.*$', host): - host = re.sub(':.*$', '', host) - return host, port + u = SplitResult("", server, "", "", "") + return u.hostname, 11211 if u.port is None else u.port def _read_socket(self, size): """ diff --git a/test/test_server_parsing.py b/test/test_server_parsing.py index a384395..a750562 100644 --- a/test/test_server_parsing.py +++ b/test/test_server_parsing.py @@ -27,9 +27,8 @@ def testNoPortGiven(self): self.assertEqual(server.port, 11211) def testInvalidPort(self): - server = bmemcached.protocol.Protocol('{}:blah'.format(os.environ['MEMCACHED_HOST'])) - self.assertEqual(server.host, os.environ['MEMCACHED_HOST']) - self.assertEqual(server.port, 11211) + with self.assertRaises(ValueError): + bmemcached.protocol.Protocol('{}:blah'.format(os.environ['MEMCACHED_HOST'])) def testNonStandardPort(self): server = bmemcached.protocol.Protocol('{}:5000'.format(os.environ['MEMCACHED_HOST'])) From bca44248cf5fbdcd8cd711db6fa9ec2f2dd18b36 Mon Sep 17 00:00:00 2001 From: Jayson Reis Date: Wed, 23 Oct 2024 14:39:27 +0200 Subject: [PATCH 07/11] fix: Avoid urllib.parse.splitport DeprecationWarning From 600ec1bceff5341d9bb2b7748c4f2b80cbc9f56f Mon Sep 17 00:00:00 2001 From: Jayson Reis Date: Wed, 23 Oct 2024 14:39:50 +0200 Subject: [PATCH 08/11] =?UTF-8?q?bump:=20version=200.31.2=20=E2=86=92=200.?= =?UTF-8?q?31.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cz.yaml | 3 ++- docs/conf.py | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.cz.yaml b/.cz.yaml index b906a20..261096e 100644 --- a/.cz.yaml +++ b/.cz.yaml @@ -1,7 +1,8 @@ +--- commitizen: name: cz_conventional_commits tag_format: v$version - version: 0.31.2 + version: 0.31.3 version_files: - setup.py - docs/conf.py diff --git a/docs/conf.py b/docs/conf.py index 81a001d..9b60470 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -52,7 +52,7 @@ # The short X.Y version. version = '0.31' # The full version, including alpha/beta/rc tags. -release = '0.31.2' +release = '0.31.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index c6a7080..e6c8714 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ def read(filename): setup( name="python-binary-memcached", - version="0.31.2", + version="0.31.3", author="Jayson Reis", author_email="santosdosreis@gmail.com", description="A pure python module to access memcached via its binary protocol with SASL auth support", From efeb037adcd07eef8d7a0fee633b7efb6935ec63 Mon Sep 17 00:00:00 2001 From: Keisuke Umegaki <41987730+keisku@users.noreply.github.com> Date: Thu, 9 Jan 2025 05:32:14 +0900 Subject: [PATCH 09/11] Merge pull request #258 from keisku/support-ipv6 fix: Support IPv6 --- bmemcached/protocol.py | 32 +++++++++++++++++++++++++++++--- test/conftest.py | 13 +++++++++++++ test/test_server_parsing.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/bmemcached/protocol.py b/bmemcached/protocol.py index 1037888..1f27b21 100644 --- a/bmemcached/protocol.py +++ b/bmemcached/protocol.py @@ -9,6 +9,7 @@ from urllib.parse import SplitResult # type: ignore[import-not-found] import zlib +from ipaddress import ip_address from io import BytesIO import six from six import binary_type, text_type @@ -144,9 +145,7 @@ def _open_connection(self): try: if self.host: - self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.connection.settimeout(self.socket_timeout) - self.connection.connect((self.host, self.port)) + self.connection = socket.create_connection((self.host, self.port), self.socket_timeout) if self.tls_context: self.connection = self.tls_context.wrap_socket( @@ -174,11 +173,38 @@ def split_host_port(cls, server): Port defaults to 11211. + When using IPv6 with a specified port, the address must be enclosed in brackets. + If the port is not specified, brackets are optional. + >>> split_host_port('127.0.0.1:11211') ('127.0.0.1', 11211) >>> split_host_port('127.0.0.1') ('127.0.0.1', 11211) + >>> split_host_port('::1') + ('::1', 11211) + >>> split_host_port('[::1]') + ('::1', 11211) + >>> split_host_port('[::1]:11211') + ('::1', 11211) """ + default_port = 11211 + + def is_ip_address(address): + try: + ip_address(address) + return True + except ValueError: + return False + + if is_ip_address(server): + return server, default_port + + if server.startswith('['): + host, _, port = server[1:].partition(']') + if not is_ip_address(host): + raise ValueError('{} is not a valid IPv6 address'.format(server)) + return host, default_port if not port else int(port.lstrip(':')) + u = SplitResult("", server, "", "", "") return u.hostname, 11211 if u.port is None else u.port diff --git a/test/conftest.py b/test/conftest.py index b4cb3b8..95abf0d 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -41,3 +41,16 @@ def memcached_socket(): yield p p.kill() p.wait() + + +@pytest.yield_fixture(scope="session", autouse=True) +def memcached_ipv6(): + p = subprocess.Popen( + ["memcached", "-l::1"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + time.sleep(0.1) + yield p + p.kill() + p.wait() diff --git a/test/test_server_parsing.py b/test/test_server_parsing.py index a750562..bd3b368 100644 --- a/test/test_server_parsing.py +++ b/test/test_server_parsing.py @@ -26,9 +26,38 @@ def testNoPortGiven(self): self.assertEqual(server.host, os.environ['MEMCACHED_HOST']) self.assertEqual(server.port, 11211) + def testIPv6(self): + server = bmemcached.protocol.Protocol('[::1]') + self.assertEqual(server.host, '::1') + self.assertEqual(server.port, 11211) + server = bmemcached.protocol.Protocol('::1') + self.assertEqual(server.host, '::1') + self.assertEqual(server.port, 11211) + server = bmemcached.protocol.Protocol('[2001:db8::2]') + self.assertEqual(server.host, '2001:db8::2') + self.assertEqual(server.port, 11211) + server = bmemcached.protocol.Protocol('2001:db8::2') + self.assertEqual(server.host, '2001:db8::2') + self.assertEqual(server.port, 11211) + # Since `2001:db8::2:8080` is a valid IPv6 address, + # it is ambiguous whether to split it into `2001:db8::2` and `8080` + # or treat it as `2001:db8::2:8080`. + # Therefore, it will be treated as `2001:db8::2:8080`. + server = bmemcached.protocol.Protocol('2001:db8::2:8080') + self.assertEqual(server.host, '2001:db8::2:8080') + self.assertEqual(server.port, 11211) + server = bmemcached.protocol.Protocol('[::1]:5000') + self.assertEqual(server.host, '::1') + self.assertEqual(server.port, 5000) + server = bmemcached.protocol.Protocol('[2001:db8::2]:5000') + self.assertEqual(server.host, '2001:db8::2') + self.assertEqual(server.port, 5000) + def testInvalidPort(self): with self.assertRaises(ValueError): bmemcached.protocol.Protocol('{}:blah'.format(os.environ['MEMCACHED_HOST'])) + with self.assertRaises(ValueError): + bmemcached.protocol.Protocol('[::1]:blah') def testNonStandardPort(self): server = bmemcached.protocol.Protocol('{}:5000'.format(os.environ['MEMCACHED_HOST'])) From 538a75a030eb7c895aa0d2aaada7bbbac3cb422b Mon Sep 17 00:00:00 2001 From: Jayson Reis Date: Wed, 8 Jan 2025 22:17:00 +0100 Subject: [PATCH 10/11] Remove python2 runner (#259) * Remove python2 runner * Lint fixes --- .github/workflows/tests-and-lint.yml | 4 ++-- bmemcached/protocol.py | 2 +- test/test_server_parsing.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests-and-lint.yml b/.github/workflows/tests-and-lint.yml index b513035..39bd99c 100644 --- a/.github/workflows/tests-and-lint.yml +++ b/.github/workflows/tests-and-lint.yml @@ -12,12 +12,12 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [2.7, 3.7, 3.8, 3.9, "3.10", 3.11] + python-version: [3.7, 3.8, 3.9, "3.10", 3.11] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} - uses: LizardByte/setup-python-action@v2024.919.163656 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies diff --git a/bmemcached/protocol.py b/bmemcached/protocol.py index 1f27b21..06d7cb3 100644 --- a/bmemcached/protocol.py +++ b/bmemcached/protocol.py @@ -195,7 +195,7 @@ def is_ip_address(address): return True except ValueError: return False - + if is_ip_address(server): return server, default_port diff --git a/test/test_server_parsing.py b/test/test_server_parsing.py index bd3b368..50e18bd 100644 --- a/test/test_server_parsing.py +++ b/test/test_server_parsing.py @@ -39,9 +39,9 @@ def testIPv6(self): server = bmemcached.protocol.Protocol('2001:db8::2') self.assertEqual(server.host, '2001:db8::2') self.assertEqual(server.port, 11211) - # Since `2001:db8::2:8080` is a valid IPv6 address, + # Since `2001:db8::2:8080` is a valid IPv6 address, # it is ambiguous whether to split it into `2001:db8::2` and `8080` - # or treat it as `2001:db8::2:8080`. + # or treat it as `2001:db8::2:8080`. # Therefore, it will be treated as `2001:db8::2:8080`. server = bmemcached.protocol.Protocol('2001:db8::2:8080') self.assertEqual(server.host, '2001:db8::2:8080') From 6cdc6784e1479a5000e53f1913a9acc342ebcedb Mon Sep 17 00:00:00 2001 From: Jayson Reis Date: Wed, 8 Jan 2025 22:17:37 +0100 Subject: [PATCH 11/11] =?UTF-8?q?bump:=20version=200.31.3=20=E2=86=92=200.?= =?UTF-8?q?31.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cz.yaml | 2 +- docs/conf.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.cz.yaml b/.cz.yaml index 261096e..d33569b 100644 --- a/.cz.yaml +++ b/.cz.yaml @@ -2,7 +2,7 @@ commitizen: name: cz_conventional_commits tag_format: v$version - version: 0.31.3 + version: 0.31.4 version_files: - setup.py - docs/conf.py diff --git a/docs/conf.py b/docs/conf.py index 9b60470..64f07fd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -52,7 +52,7 @@ # The short X.Y version. version = '0.31' # The full version, including alpha/beta/rc tags. -release = '0.31.3' +release = '0.31.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index e6c8714..ce0b628 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ def read(filename): setup( name="python-binary-memcached", - version="0.31.3", + version="0.31.4", author="Jayson Reis", author_email="santosdosreis@gmail.com", description="A pure python module to access memcached via its binary protocol with SASL auth support",