diff --git a/.github/spellcheck-settings.yml b/.github/spellcheck-settings.yml new file mode 100644 index 00000000..b8ca6cca --- /dev/null +++ b/.github/spellcheck-settings.yml @@ -0,0 +1,29 @@ +matrix: +- name: Markdown + expect_match: false + apsell: + lang: en + d: en_US + ignore-case: true + dictionary: + wordlists: + - .github/wordlist.txt + output: wordlist.dic + pipeline: + - pyspelling.filters.markdown: + markdown_extensions: + - markdown.extensions.extra: + - pyspelling.filters.html: + comments: false + attributes: + - alt + ignores: + - ':matches(code, pre)' + - code + - pre + - blockquote + - img + sources: + - 'README.md' + - 'FAQ.md' + - 'docs/**' diff --git a/.github/wordlist.txt b/.github/wordlist.txt new file mode 100644 index 00000000..862c517e --- /dev/null +++ b/.github/wordlist.txt @@ -0,0 +1,54 @@ +ACLs +Autoloading +CAS +Customizable +ElastiCache +FPM +IANA +Kops +LRANGE +Lua +Misspelled words: +PSR +Packagist +PhpRedis +Predis +PyPI +README +Redis +SHA +SSL +TCP +TLS +URI +autoload +autoloader +autoloading +backend +backends +behaviour +benchmarking +boolean +customizable +dataset +de +dedcoded +extensibility +gcc +gevent +hiredis +keyspace +keyspaces +localhost +namespace +pipelining +pluggable +py +rebalanced +rebalancing +redis +runtime +sharding +stunnel +submodules +variadic diff --git a/.github/workflows/freebsd.yaml b/.github/workflows/freebsd.yaml index 08199a41..6872c9a3 100644 --- a/.github/workflows/freebsd.yaml +++ b/.github/workflows/freebsd.yaml @@ -43,5 +43,5 @@ jobs: /usr/local/bin/pip install -U pip setuptools wheel /usr/local/bin/pip install -r dev_requirements.txt /usr/local/bin/python3.9 setup.py build_ext --inplace - pytest + python -m pytest python3.9 setup.py bdist_wheel diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index eaf9bff8..a433dcf5 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -45,7 +45,7 @@ jobs: pip install -U pip setuptools wheel pip install -r dev_requirements.txt python setup.py build_ext --inplace - pytest + python -m pytest - name: build and install the wheel run: | - python setup.py bdist_wheel \ No newline at end of file + python setup.py bdist_wheel diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml new file mode 100644 index 00000000..e1528415 --- /dev/null +++ b/.github/workflows/spellcheck.yml @@ -0,0 +1,14 @@ +name: spellcheck +on: + pull_request: +jobs: + check-spelling: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Check Spelling + uses: rojopolis/spellcheck-github-actions@0.33.1 + with: + config_path: .github/spellcheck-settings.yml + task_name: Markdown diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e577c00..7983e0bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ * Implement pack_command that serializes redis-py command to the RESP bytes object. +* Implement garbage collection support in Reader (#162) ### 2.1.1 (2023-10-01) diff --git a/LICENSE b/LICENSE index 8afe290b..0cd4acde 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,21 @@ -Note: This license has also been called the "New BSD License" or "Modified BSD License". See also the 2-clause BSD License. +MIT License -Copyright 2011 Pieter Noordhuis +Copyright (c) 2022-2023, the maintainers of this library. -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +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: -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +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. diff --git a/MANIFEST.in b/MANIFEST.in index a1865207..fb645d00 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,7 +4,6 @@ include README.md include src/*.[ch] include vendor/hiredis/COPYING include vendor/hiredis/*.[ch] -include test.py -graft test +graft tests global-exclude __pycache__ global-exclude *.py[co] diff --git a/README.md b/README.md index 0d6cbf42..d1c0d9b9 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,20 @@ It primarily speeds up parsing of multi bulk replies. [hiredis]: http://github.com/redis/hiredis +## How do I Redis? + +[Learn for free at Redis University](https://university.redis.com/) + +[Build faster with the Redis Launchpad](https://launchpad.redis.com/) + +[Try the Redis Cloud](https://redis.com/try-free/) + +[Dive in developer tutorials](https://developer.redis.com/) + +[Join the Redis community](https://redis.com/community/) + +[Work at Redis](https://redis.com/company/careers/jobs/) + ## Install hiredis-py is available on [PyPI](https://pypi.org/project/hiredis/), and can be installed via: @@ -22,7 +36,7 @@ Building this repository requires a recursive checkout of submodules, and buildi ```bash git clone --recursse-submodules https://github.com/redis/hiredis-py python setup.py build_ext --inplace -pytest +python -m pytest ``` ### Requirements diff --git a/hiredis/__init__.py b/hiredis/__init__.py index 10afc025..623ee6bc 100644 --- a/hiredis/__init__.py +++ b/hiredis/__init__.py @@ -1,5 +1,5 @@ -from .hiredis import Reader, HiredisError, pack_command, ProtocolError, ReplyError -from .version import __version__ +from hiredis.hiredis import Reader, HiredisError, pack_command, ProtocolError, ReplyError +from hiredis.version import __version__ __all__ = [ "Reader", diff --git a/hiredis/version.py b/hiredis/version.py index ba51cedf..55e47090 100644 --- a/hiredis/version.py +++ b/hiredis/version.py @@ -1 +1 @@ -__version__ = "2.2.2" +__version__ = "2.3.0" diff --git a/src/reader.c b/src/reader.c index e1942024..77a7efe5 100644 --- a/src/reader.c +++ b/src/reader.c @@ -3,6 +3,7 @@ #include static void Reader_dealloc(hiredis_ReaderObject *self); +static int Reader_traverse(hiredis_ReaderObject *self, visitproc visit, void *arg); static int Reader_init(hiredis_ReaderObject *self, PyObject *args, PyObject *kwds); static PyObject *Reader_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static PyObject *Reader_feed(hiredis_ReaderObject *self, PyObject *args); @@ -44,9 +45,9 @@ PyTypeObject hiredis_ReaderType = { 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ "Hiredis protocol reader", /*tp_doc */ - 0, /*tp_traverse */ + (traverseproc)Reader_traverse,/*tp_traverse */ 0, /*tp_clear */ 0, /*tp_richcompare */ 0, /*tp_weaklistoffset */ @@ -209,16 +210,24 @@ redisReplyObjectFunctions hiredis_ObjectFunctions = { }; static void Reader_dealloc(hiredis_ReaderObject *self) { + PyObject_GC_UnTrack(self); // we don't need to free self->encoding as the buffer is managed by Python // https://docs.python.org/3/c-api/arg.html#strings-and-buffers redisReaderFree(self->reader); - Py_XDECREF(self->protocolErrorClass); - Py_XDECREF(self->replyErrorClass); - Py_XDECREF(self->notEnoughDataObject); + Py_CLEAR(self->protocolErrorClass); + Py_CLEAR(self->replyErrorClass); + Py_CLEAR(self->notEnoughDataObject); ((PyObject *)self)->ob_type->tp_free((PyObject*)self); } +static int Reader_traverse(hiredis_ReaderObject *self, visitproc visit, void *arg) { + Py_VISIT(self->protocolErrorClass); + Py_VISIT(self->replyErrorClass); + Py_VISIT(self->notEnoughDataObject); + return 0; +} + static int _Reader_set_exception(PyObject **target, PyObject *value) { int callable; callable = PyCallable_Check(value); diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/test_gc.py b/tests/test_gc.py new file mode 100644 index 00000000..71f4188f --- /dev/null +++ b/tests/test_gc.py @@ -0,0 +1,17 @@ +import gc + +import hiredis + + +def test_reader_gc(): + class A: + def __init__(self): + self.reader = hiredis.Reader(replyError=self.reply_error) + + def reply_error(self, error): + return Exception() + + A() + gc.collect() + + assert not any(isinstance(o, A) for o in gc.get_objects()), "Referent was not collected" diff --git a/vendor/hiredis b/vendor/hiredis index c14775b4..60e5075d 160000 --- a/vendor/hiredis +++ b/vendor/hiredis @@ -1 +1 @@ -Subproject commit c14775b4e48334e0262c9f168887578f4a368b5d +Subproject commit 60e5075d4ac77424809f855ba3e398df7aacefe8