diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 73b4a96bb6..0000000000 --- a/.flake8 +++ /dev/null @@ -1,25 +0,0 @@ -[flake8] -max-line-length = 88 -exclude = - *.egg-info, - *.pyc, - .git, - .venv*, - build, - docs/*, - dist, - docker, - venv*, - .venv*, - whitelist.py, - tasks.py -ignore = - E126 - E203 - F405 - N801 - N802 - N803 - N806 - N815 - W503 diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml new file mode 100644 index 0000000000..aa958a9236 --- /dev/null +++ b/.github/actions/run-tests/action.yml @@ -0,0 +1,146 @@ +name: 'Run redis-py tests' +description: 'Runs redis-py tests against different Redis versions and configurations' +inputs: + python-version: + description: 'Python version to use for running tests' + default: '3.12' + parser-backend: + description: 'Parser backend to use: plain or hiredis' + required: true + redis-version: + description: 'Redis version to test against' + required: true + hiredis-version: + description: 'hiredis version to test against' + required: false + default: '>3.0.0' + event-loop: + description: 'Event loop to use' + required: false + default: 'asyncio' +runs: + using: "composite" + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python-version }} + cache: 'pip' + + - name: Setup Test environment + env: + REDIS_VERSION: ${{ inputs.redis-version }} + CLIENT_LIBS_TEST_IMAGE_TAG: ${{ inputs.redis-version }} + run: | + set -e + + echo "::group::Installing dependencies" + pip install -r dev_requirements.txt + pip uninstall -y redis # uninstall Redis package installed via redis-entraid + pip install -e .[jwt] # install the working copy + if [ "${{inputs.parser-backend}}" == "hiredis" ]; then + pip install "hiredis${{inputs.hiredis-version}}" + echo "PARSER_BACKEND=$(echo "${{inputs.parser-backend}}_${{inputs.hiredis-version}}" | sed 's/[^a-zA-Z0-9]/_/g')" >> $GITHUB_ENV + else + echo "PARSER_BACKEND=${{inputs.parser-backend}}" >> $GITHUB_ENV + fi + echo "::endgroup::" + + echo "::group::Starting Redis servers" + redis_major_version=$(echo "$REDIS_VERSION" | grep -oP '^\d+') + + if (( redis_major_version < 8 )); then + echo "Using redis-stack for module tests" + + # Mapping of redis version to stack version + declare -A redis_stack_version_mapping=( + ["7.4.2"]="rs-7.4.0-v2" + ["7.2.7"]="rs-7.2.0-v14" + ["6.2.17"]="rs-6.2.6-v18" + ) + + if [[ -v redis_stack_version_mapping[$REDIS_VERSION] ]]; then + export CLIENT_LIBS_TEST_STACK_IMAGE_TAG=${redis_stack_version_mapping[$REDIS_VERSION]} + echo "REDIS_MOD_URL=redis://127.0.0.1:6479/0" >> $GITHUB_ENV + else + echo "Version not found in the mapping." + exit 1 + fi + + if (( redis_major_version < 7 )); then + export REDIS_STACK_EXTRA_ARGS="--tls-auth-clients optional --save ''" + export REDIS_EXTRA_ARGS="--tls-auth-clients optional --save ''" + echo "REDIS_MAJOR_VERSION=${redis_major_version}" >> $GITHUB_ENV + fi + + invoke devenv --endpoints=all-stack + else + echo "Using redis CE for module tests" + echo "REDIS_MOD_URL=redis://127.0.0.1:6379" >> $GITHUB_ENV + invoke devenv --endpoints all + fi + + sleep 10 # time to settle + echo "::endgroup::" + shell: bash + + - name: Run tests + run: | + set -e + + run_tests() { + local protocol=$1 + local eventloop="" + + if [ "${{inputs.event-loop}}" == "uvloop" ]; then + eventloop="--uvloop" + fi + + echo "::group::RESP${protocol} standalone tests" + echo "REDIS_MOD_URL=${REDIS_MOD_URL}" + + if (( $REDIS_MAJOR_VERSION < 7 )) && [ "$protocol" == "3" ]; then + echo "Skipping module tests: Modules doesn't support RESP3 for Redis versions < 7" + invoke standalone-tests --redis-mod-url=${REDIS_MOD_URL} $eventloop --protocol="${protocol}" --extra-markers="not redismod and not cp_integration" + else + invoke standalone-tests --redis-mod-url=${REDIS_MOD_URL} $eventloop --protocol="${protocol}" + fi + + echo "::endgroup::" + + if [ "$protocol" == "2" ] || [ "${{inputs.parser-backend}}" != 'hiredis' ]; then + echo "::group::RESP${protocol} cluster tests" + invoke cluster-tests $eventloop --protocol=${protocol} + echo "::endgroup::" + fi + } + + run_tests 2 "${{inputs.event-loop}}" + run_tests 3 "${{inputs.event-loop}}" + shell: bash + + - name: Debug + if: failure() + run: | + sudo apt-get install -y redis-tools + echo "Docker Containers:" + docker ps + redis-cli -p 16379 CLUSTER NODES + shell: bash + + - name: Upload test results and profiling data + uses: actions/upload-artifact@v4 + with: + name: pytest-results-redis_${{inputs.redis-version}}-python_${{inputs.python-version}}-parser_${{env.PARSER_BACKEND}}-el_${{inputs.event-loop}} + path: | + *-results.xml + prof/** + profile_output* + if-no-files-found: error + retention-days: 10 + + - name: Upload codecov coverage + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: false diff --git a/.github/release-drafter-config.yml b/.github/release-drafter-config.yml index 9ccb28aca4..4607da071c 100644 --- a/.github/release-drafter-config.yml +++ b/.github/release-drafter-config.yml @@ -1,5 +1,7 @@ name-template: '$NEXT_MINOR_VERSION' tag-template: 'v$NEXT_MINOR_VERSION' +filter-by-commitish: true +commitish: master autolabeler: - label: 'maintenance' files: @@ -15,7 +17,7 @@ autolabeler: branch: - '/feature-.+' categories: - - title: 'Breaking Changes' + - title: '🔥 Breaking Changes' labels: - 'breakingchange' - title: '🧪 Experimental Features' @@ -32,7 +34,12 @@ categories: - 'bug' - 'BUG' - title: '🧰 Maintenance' - label: 'maintenance' + labels: + - 'maintenance' + - 'dependencies' + - 'documentation' + - 'docs' + - 'testing' change-template: '- $TITLE (#$NUMBER)' exclude-labels: - 'skip-changelog' diff --git a/.github/wordlist.txt b/.github/wordlist.txt index 22ae767e46..29bcaa9d77 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -1,6 +1,7 @@ APM ARGV BFCommands +CacheImpl CFCommands CMSCommands ClusterNode @@ -11,7 +12,6 @@ ConnectionPool CoreCommands EVAL EVALSHA -GraphCommands Grokzen's INCR IOError @@ -38,7 +38,6 @@ RedisCluster RedisClusterCommands RedisClusterException RedisClusters -RedisGraph RedisInstrumentor RedisJSON RedisTimeSeries @@ -74,6 +73,8 @@ bysource charset del dev +docstring +docstrings eg exc firsttimersonly @@ -139,3 +140,4 @@ unicode url virtualenv www +yaml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 61da2fce55..4670c55b0f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -40,7 +40,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: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -51,7 +51,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 @@ -65,4 +65,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 56f16fa2b0..747b3b6d76 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -13,7 +13,7 @@ on: - cron: '0 1 * * *' # nightly build concurrency: - group: ${{ github.event.pull_request.number || github.ref }} + group: ${{ github.event.pull_request.number || github.ref }}-docs cancel-in-progress: true permissions: @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: 3.9 cache: 'pip' @@ -36,11 +36,11 @@ jobs: sudo apt-get install -yqq pandoc make - name: run code linters run: | - pip install -r requirements.txt -r dev_requirements.txt -r docs/requirements.txt + pip install -r dev_requirements.txt -r docs/requirements.txt invoke build-docs - name: upload docs - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: redis-py-docs path: | diff --git a/.github/workflows/install_and_test.sh b/.github/workflows/install_and_test.sh index 33a1edb1e7..e647126539 100755 --- a/.github/workflows/install_and_test.sh +++ b/.github/workflows/install_and_test.sh @@ -21,7 +21,8 @@ python -m venv ${DESTENV} source ${DESTENV}/bin/activate pip install --upgrade --quiet pip pip install --quiet -r dev_requirements.txt -invoke devenv +pip uninstall -y redis # uninstall Redis package installed via redis-entraid +invoke devenv --endpoints=all-stack invoke package # find packages @@ -42,4 +43,6 @@ pip install ${PKG} pytest -m 'not onlycluster' # RedisCluster tests CLUSTER_URL="redis://localhost:16379/0" -pytest -m 'not onlynoncluster and not redismod and not ssl' --redis-url=${CLUSTER_URL} +CLUSTER_SSL_URL="rediss://localhost:27379/0" +pytest -m 'not onlynoncluster and not redismod and not ssl' \ + --redis-url="${CLUSTER_URL}" --redis-ssl-url="${CLUSTER_SSL_URL}" diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 96b51fbafb..bb56e8a024 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -17,153 +17,184 @@ on: - cron: '0 1 * * *' # nightly build concurrency: - group: ${{ github.event.pull_request.number || github.ref }} + group: ${{ github.event.pull_request.number || github.ref }}-integration cancel-in-progress: true permissions: contents: read # to fetch code (actions/checkout) -jobs: +env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + # this speeds up coverage with Python 3.12: https://github.com/nedbat/coveragepy/issues/1665 + COVERAGE_CORE: sysmon + CURRENT_CLIENT_LIBS_TEST_STACK_IMAGE_TAG: 'rs-7.4.0-v2' + CURRENT_REDIS_VERSION: '7.4.2' - dependency-audit: - name: Dependency audit - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: pypa/gh-action-pip-audit@v1.0.8 - with: - inputs: requirements.txt dev_requirements.txt - ignore-vulns: | - GHSA-w596-4wvx-j9j6 # subversion related git pull, dependency for pytest. There is no impact here. +jobs: + dependency-audit: + name: Dependency audit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pypa/gh-action-pip-audit@v1.0.8 + with: + inputs: dev_requirements.txt + ignore-vulns: | + GHSA-w596-4wvx-j9j6 # subversion related git pull, dependency for pytest. There is no impact here. - lint: - name: Code linters - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 - with: - python-version: 3.9 - cache: 'pip' - - name: run code linters - run: | - pip install -r dev_requirements.txt - invoke linters + lint: + name: Code linters + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.9 + cache: 'pip' + - name: run code linters + run: | + pip install -r dev_requirements.txt + pip uninstall -y redis # uninstall Redis package installed via redis-entraid + invoke linters - run-tests: - runs-on: ubuntu-latest - timeout-minutes: 60 - strategy: - max-parallel: 15 - fail-fast: false - matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9'] - test-type: ['standalone', 'cluster'] - connection-type: ['hiredis', 'plain'] - env: - ACTIONS_ALLOW_UNSECURE_COMMANDS: true - name: Python ${{ matrix.python-version }} ${{matrix.test-type}}-${{matrix.connection-type}} tests - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: 'pip' - - name: run tests - run: | - pip install -U setuptools wheel - pip install -r requirements.txt - pip install -r dev_requirements.txt - if [ "${{matrix.connection-type}}" == "hiredis" ]; then - pip install hiredis - fi - invoke devenv - sleep 10 # time to settle - invoke ${{matrix.test-type}}-tests + redis_version: + runs-on: ubuntu-latest + outputs: + CURRENT: ${{ env.CURRENT_REDIS_VERSION }} + steps: + - name: Compute outputs + run: | + echo "CURRENT=${{ env.CURRENT_REDIS_VERSION }}" >> $GITHUB_OUTPUT - - uses: actions/upload-artifact@v3 - if: success() || failure() - with: - name: pytest-results-${{matrix.test-type}}-${{matrix.connection-type}}-${{matrix.python-version}} - path: '${{matrix.test-type}}*results.xml' + tests: + runs-on: ubuntu-latest + timeout-minutes: 60 + needs: redis_version + strategy: + max-parallel: 15 + fail-fast: false + matrix: + redis-version: ['8.0-M04-pre', '${{ needs.redis_version.outputs.CURRENT }}', '7.2.7', '6.2.17'] + python-version: ['3.8', '3.13'] + parser-backend: ['plain'] + event-loop: ['asyncio'] + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + name: Redis ${{ matrix.redis-version }}; Python ${{ matrix.python-version }}; RESP Parser:${{matrix.parser-backend}}; EL:${{matrix.event-loop}} + steps: + - uses: actions/checkout@v4 + - name: Run tests + uses: ./.github/actions/run-tests + with: + python-version: ${{ matrix.python-version }} + parser-backend: ${{ matrix.parser-backend }} + redis-version: ${{ matrix.redis-version }} - - name: Upload codecov coverage - uses: codecov/codecov-action@v3 - if: ${{matrix.python-version == '3.11'}} - with: - fail_ci_if_error: false + python-compatibility-tests: + runs-on: ubuntu-latest + needs: [ redis_version, tests ] + timeout-minutes: 60 + strategy: + max-parallel: 15 + fail-fast: false + matrix: + redis-version: [ '${{ needs.redis_version.outputs.CURRENT }}' ] + python-version: ['3.9', '3.10', '3.11', '3.12', 'pypy-3.9', 'pypy-3.10'] + parser-backend: [ 'plain' ] + event-loop: [ 'asyncio' ] + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + name: Redis ${{ matrix.redis-version }}; Python ${{ matrix.python-version }}; RESP Parser:${{matrix.parser-backend}}; EL:${{matrix.event-loop}} + steps: + - uses: actions/checkout@v4 + - name: Run tests + uses: ./.github/actions/run-tests + with: + python-version: ${{ matrix.python-version }} + parser-backend: ${{ matrix.parser-backend }} + redis-version: ${{ matrix.redis-version }} - - name: View Test Results - uses: dorny/test-reporter@v1 - if: success() || failure() - continue-on-error: true - with: - name: Test Results ${{matrix.python-version}} ${{matrix.test-type}}-${{matrix.connection-type}} - path: '*.xml' - reporter: java-junit - list-suites: all - list-tests: all - max-annotations: 10 - fail-on-error: 'false' + hiredis-tests: + runs-on: ubuntu-latest + needs: [redis_version, tests] + timeout-minutes: 60 + strategy: + max-parallel: 15 + fail-fast: false + matrix: + redis-version: [ '${{ needs.redis_version.outputs.CURRENT }}' ] + python-version: [ '3.8', '3.13'] + parser-backend: [ 'hiredis' ] + hiredis-version: [ '>=3.0.0', '<3.0.0' ] + event-loop: [ 'asyncio' ] + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + name: Redis ${{ matrix.redis-version }}; Python ${{ matrix.python-version }}; RESP Parser:${{matrix.parser-backend}} (${{ matrix.hiredis-version }}); EL:${{matrix.event-loop}} + steps: + - uses: actions/checkout@v4 + - name: Run tests + uses: ./.github/actions/run-tests + with: + python-version: ${{ matrix.python-version }} + parser-backend: ${{ matrix.parser-backend }} + redis-version: ${{ matrix.redis-version }} + hiredis-version: ${{ matrix.hiredis-version }} - resp3_tests: + uvloop-tests: runs-on: ubuntu-latest + needs: [redis_version, tests] + timeout-minutes: 60 strategy: + max-parallel: 15 fail-fast: false matrix: - python-version: ['3.7', '3.11'] - test-type: ['standalone', 'cluster'] - connection-type: ['hiredis', 'plain'] - protocol: ['3'] + redis-version: [ '${{ needs.redis_version.outputs.CURRENT }}' ] + python-version: [ '3.8', '3.13' ] + parser-backend: [ 'plain' ] + event-loop: [ 'uvloop' ] env: - ACTIONS_ALLOW_UNSECURE_COMMANDS: true - name: RESP3 [${{ matrix.python-version }} ${{matrix.test-type}}-${{matrix.connection-type}}] + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + name: Redis ${{ matrix.redis-version }}; Python ${{ matrix.python-version }}; RESP Parser:${{matrix.parser-backend}}; EL:${{matrix.event-loop}} steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - name: Run tests + uses: ./.github/actions/run-tests with: python-version: ${{ matrix.python-version }} - cache: 'pip' - - name: run tests - run: | - pip install -U setuptools wheel - pip install -r requirements.txt - pip install -r dev_requirements.txt - if [ "${{matrix.connection-type}}" == "hiredis" ]; then - pip install hiredis - fi - invoke devenv - sleep 5 # time to settle - invoke ${{matrix.test-type}}-tests - invoke ${{matrix.test-type}}-tests --uvloop + parser-backend: ${{ matrix.parser-backend }} + redis-version: ${{ matrix.redis-version }} + event-loop: ${{ matrix.event-loop }} - build_and_test_package: + build-and-test-package: name: Validate building and installing the package runs-on: ubuntu-latest - needs: [run-tests] + needs: [tests] strategy: fail-fast: false matrix: extension: ['tar.gz', 'whl'] steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: 3.9 - name: Run installed unit tests + env: + CLIENT_LIBS_TEST_IMAGE_TAG: ${{ env.CURRENT_REDIS_VERSION }} + CLIENT_LIBS_TEST_STACK_IMAGE_TAG: ${{ env.CURRENT_CLIENT_LIBS_TEST_STACK_IMAGE_TAG }} run: | bash .github/workflows/install_and_test.sh ${{ matrix.extension }} - install_package_from_commit: + install-package-from-commit: name: Install package from commit hash runs-on: ubuntu-latest strategy: fail-fast: false matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', 'pypy-3.9', 'pypy-3.10'] steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' diff --git a/.github/workflows/pypi-publish.yaml b/.github/workflows/pypi-publish.yaml index 4f8833372f..048d06c53c 100644 --- a/.github/workflows/pypi-publish.yaml +++ b/.github/workflows/pypi-publish.yaml @@ -3,6 +3,7 @@ name: Publish tag to Pypi on: release: types: [published] + workflow_dispatch: permissions: contents: read # to fetch code (actions/checkout) @@ -14,18 +15,17 @@ jobs: steps: - uses: actions/checkout@v4 - name: install python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 - - name: Install dev tools - run: | - pip install -r dev_requirements.txt - pip install twine wheel + - run: pip install build twine - name: Build package + run: python -m build . + + - name: Basic package test prior to upload run: | - python setup.py build - python setup.py sdist bdist_wheel + twine check dist/* - name: Publish to Pypi uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index eebb3e678b..6695abfe4b 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: # Drafts your next Release notes as Pull Requests are merged into "master" - - uses: release-drafter/release-drafter@v5 + - uses: release-drafter/release-drafter@v6 with: # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml config-name: release-drafter-config.yml diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index a48781aa84..beefa6164f 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -8,7 +8,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Check Spelling - uses: rojopolis/spellcheck-github-actions@0.35.0 + uses: rojopolis/spellcheck-github-actions@0.47.0 with: config_path: .github/spellcheck-settings.yml task_name: Markdown diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml index 32fd9e8179..f3bc21bbf3 100644 --- a/.github/workflows/stale-issues.yml +++ b/.github/workflows/stale-issues.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is marked stale. It will be closed in 30 days if it is not updated.' @@ -21,5 +21,5 @@ jobs: days-before-close: 30 stale-issue-label: "Stale" stale-pr-label: "Stale" - operations-per-run: 10 + operations-per-run: 20 remove-stale-when-updated: true diff --git a/.gitignore b/.gitignore index 3baa34034f..5f77dcfde4 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,13 @@ coverage.xml .venv* *.xml .coverage* +prof +profile_output* docker/stunnel/keys +/dockers/*/node-*/* +/dockers/*/tls/* +/dockers/standalone/ +/dockers/cluster/ +/dockers/replica/ +/dockers/sentinel/ +/dockers/redis-stack/ diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index 039f0337a2..0000000000 --- a/.isort.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[settings] -profile=black -multi_line_output=3 -src_paths = ["redis", "tests"] -skip_glob=benchmarks/* \ No newline at end of file diff --git a/.readthedocs.yml b/.readthedocs.yml index 800cb14816..17bfa9d47c 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,8 +2,9 @@ version: 2 python: install: - - requirements: ./docs/requirements.txt - - requirements: requirements.txt + - requirements: docs/requirements.txt + - method: pip + path: . build: os: ubuntu-20.04 diff --git a/CHANGES b/CHANGES index 9e0db230c6..24b52c54db 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ + * Removing support for RedisGraph module. RedisGraph support is deprecated since Redis Stack 7.2 (https://redis.com/blog/redisgraph-eol/) + * Fix lock.extend() typedef to accept float TTL extension + * Update URL in the readme linking to Redis University + * Move doctests (doc code examples) to main branch + * Update `ResponseT` type hint + * Allow to control the minimum SSL version + * Add an optional lock_name attribute to LockError. * Fix return types for `get`, `set_path` and `strappend` in JSONCommands * Connection.register_connect_callback() is made public. * Fix async `read_response` to use `disable_decoding`. @@ -60,6 +67,9 @@ * Make `ClusterCommandsProtocol` an actual Protocol * Add `sum` to DUPLICATE_POLICY documentation of `TS.CREATE`, `TS.ADD` and `TS.ALTER` * Prevent async ClusterPipeline instances from becoming "false-y" in case of empty command stack (#3061) + * Close Unix sockets if the connection attempt fails. This prevents `ResourceWarning`s. (#3314) + * Close SSL sockets if the connection attempt fails, or if validations fail. (#3317) + * Eliminate mutable default arguments in the `redis.commands.core.Script` class. (#3332) * 4.1.3 (Feb 8, 2022) * Fix flushdb and flushall (#1926) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4da55c737c..eb333f644f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,13 +32,13 @@ Here's how to get started with your code contribution: 1. Create your own fork of redis-py 2. Do the changes in your fork -3. - *Create a virtualenv and install the development dependencies from the dev_requirements.txt file:* - - a. python -m venv .venv - b. source .venv/bin/activate - c. pip install -r dev_requirements.txt - c. pip install -r requirements.txt +3. Create a virtualenv and install the development dependencies from the dev_requirements.txt file: + ``` + python -m venv .venv + source .venv/bin/activate + pip install -r dev_requirements.txt + pip install -e .[jwt] + ``` 4. If you need a development environment, run `invoke devenv`. Note: this relies on docker-compose to build environments, and assumes that you have a version supporting [docker profiles](https://docs.docker.com/compose/profiles/). 5. While developing, make sure the tests pass by running `invoke tests` @@ -81,6 +81,19 @@ using `invoke standalone-tests`; similarly, RedisCluster tests can be run by usi Each run of tests starts and stops the various dockers required. Sometimes things get stuck, an `invoke clean` can help. +## Documentation + +If relevant, update the code documentation, via docstrings, or in `/docs`. + +You can check how the documentation looks locally by running `invoke build-docs` +and loading the generated HTML files in a browser. + +Historically there is a mix of styles in the docstrings, but the preferred way +of documenting code is by applying the +[Google style](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html). +Type hints should be added according to PEP484, and should not be repeated in +the docstrings. + ### Docker Tips Following are a few tips that can help you work with the Docker-based diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 951f7dea8a..0000000000 --- a/INSTALL +++ /dev/null @@ -1,6 +0,0 @@ - -Please use - python setup.py install - -and report errors to Andy McCurdy (sedrik@gmail.com) - diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 97fa305889..0000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include INSTALL -include LICENSE -include README.md -exclude __pycache__ -recursive-include tests * -recursive-exclude tests *.pyc diff --git a/README.md b/README.md index 2097e87bba..8b4d4b6875 100644 --- a/README.md +++ b/README.md @@ -13,23 +13,21 @@ The Python interface to the Redis key-value store. --------------------------------------------- -**Note: ** redis-py 5.0 will be the last version of redis-py to support Python 3.7, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 5.1 will support Python 3.8+. +**Note:** redis-py 5.0 will be the last version of redis-py to support Python 3.7, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 5.1 will support Python 3.8+. --------------------------------------------- ## How do I Redis? -[Learn for free at Redis University](https://university.redis.com/) +[Learn for free at Redis University](https://redis.io/learn/university) -[Build faster with the Redis Launchpad](https://launchpad.redis.com/) +[Try the Redis Cloud](https://redis.io/try-free/) -[Try the Redis Cloud](https://redis.com/try-free/) +[Dive in developer tutorials](https://redis.io/learn) -[Dive in developer tutorials](https://developer.redis.com/) +[Join the Redis community](https://redis.io/community/) -[Join the Redis community](https://redis.com/community/) - -[Work at Redis](https://redis.com/company/careers/jobs/) +[Work at Redis](https://redis.io/careers/) ## Installation @@ -56,7 +54,7 @@ Looking for a high-level library to handle object mapping? See [redis-om-python] ## Supported Redis Versions -The most recent version of this library supports redis version [5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES), [6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES), [6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES), [7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES) and [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES). +The most recent version of this library supports redis version [5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES), [6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES), [6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES), [7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES), [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES) and [7.4](https://github.com/redis/redis/blob/7.4/00-RELEASENOTES). The table below highlights version compatibility of the most-recent library versions and redis versions. @@ -159,7 +157,7 @@ The following example shows how to utilize [Redis Pub/Sub](https://redis.io/docs ### Author -redis-py is developed and maintained by [Redis Inc](https://redis.com). It can be found [here]( +redis-py is developed and maintained by [Redis Inc](https://redis.io). It can be found [here]( https://github.com/redis/redis-py), or downloaded from [pypi](https://pypi.org/project/redis/). Special thanks to: @@ -171,4 +169,4 @@ Special thanks to: system. - Paul Hubbard for initial packaging support. -[![Redis](./docs/logo-redis.png)](https://www.redis.com) +[![Redis](./docs/_static/logo-redis.svg)](https://redis.io) diff --git a/benchmarks/basic_operations.py b/benchmarks/basic_operations.py index c9f5853652..66cd6b320d 100644 --- a/benchmarks/basic_operations.py +++ b/benchmarks/basic_operations.py @@ -54,7 +54,7 @@ def wrapper(*args, **kwargs): count = args[1] print(f"{func.__name__} - {count} Requests") print(f"Duration = {duration}") - print(f"Rate = {count/duration}") + print(f"Rate = {count / duration}") print() return ret diff --git a/benchmarks/command_packer_benchmark.py b/benchmarks/command_packer_benchmark.py index e66dbbcbf9..4fb7196422 100644 --- a/benchmarks/command_packer_benchmark.py +++ b/benchmarks/command_packer_benchmark.py @@ -78,7 +78,6 @@ def pack_command(self, *args): class CommandPackerBenchmark(Benchmark): - ARGUMENTS = ( { "name": "connection_class", diff --git a/benchmarks/socket_read_size.py b/benchmarks/socket_read_size.py index 544c733178..37ffa97812 100644 --- a/benchmarks/socket_read_size.py +++ b/benchmarks/socket_read_size.py @@ -4,7 +4,6 @@ class SocketReadBenchmark(Benchmark): - ARGUMENTS = ( {"name": "parser", "values": [PythonParser, _HiredisParser]}, { diff --git a/dev_requirements.txt b/dev_requirements.txt index 3715599af0..ad7330598d 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,17 +1,16 @@ +build click==8.0.4 -black==22.3.0 -flake8==5.0.4 -flake8-isort==6.0.0 -flynt~=0.69.0 -mock==4.0.3 +invoke==2.2.0 +mock packaging>=20.4 -pytest==7.2.0 -pytest-timeout==2.1.0 -pytest-asyncio>=0.20.2 -invoke==1.7.3 -pytest-cov>=4.0.0 -vulture>=2.3.0 +pytest +pytest-asyncio>=0.23.0 +pytest-cov +pytest-profiling==1.8.1 +pytest-timeout +ruff==0.9.6 ujson>=4.2.0 -wheel>=0.30.0 -urllib3<2 uvloop +vulture>=2.3.0 +numpy>=1.24.0 +redis-entraid==0.4.0b2 diff --git a/docker-compose.yml b/docker-compose.yml index 17d4b23977..76a60398f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,109 +1,107 @@ --- +x-client-libs-stack-image: &client-libs-stack-image + image: "redislabs/client-libs-test:${CLIENT_LIBS_TEST_STACK_IMAGE_TAG:-rs-7.4.0-v2}" -version: "3.8" +x-client-libs-image: &client-libs-image + image: "redislabs/client-libs-test:${CLIENT_LIBS_TEST_IMAGE_TAG:-7.4.2}" services: redis: - image: redis/redis-stack-server:edge + <<: *client-libs-image container_name: redis-standalone + environment: + - TLS_ENABLED=yes + - REDIS_CLUSTER=no + - PORT=6379 + - TLS_PORT=6666 + command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save ""} ports: - 6379:6379 - environment: - - "REDIS_ARGS=--enable-debug-command yes --enable-module-command yes" + - 6666:6666 # TLS port + volumes: + - "./dockers/standalone:/redis/work" profiles: - standalone - sentinel - replica + - all-stack - all replica: - image: redis/redis-stack-server:edge + <<: *client-libs-image container_name: redis-replica depends_on: - redis environment: - - "REDIS_ARGS=--replicaof redis 6379" + - TLS_ENABLED=no + - REDIS_CLUSTER=no + - PORT=6380 + command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --replicaof redis 6379 --protected-mode no --save ""} ports: - - 6380:6379 + - 6380:6380 + volumes: + - "./dockers/replica:/redis/work" profiles: - replica + - all-stack - all cluster: + <<: *client-libs-image container_name: redis-cluster - build: - context: . - dockerfile: dockers/Dockerfile.cluster + environment: + - REDIS_CLUSTER=yes + - NODES=6 + - REPLICAS=1 + - TLS_ENABLED=yes + - PORT=16379 + - TLS_PORT=27379 + command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --tls-auth-clients optional --save ""} ports: - - 16379:16379 - - 16380:16380 - - 16381:16381 - - 16382:16382 - - 16383:16383 - - 16384:16384 + - "16379-16384:16379-16384" + - "27379-27384:27379-27384" volumes: - - "./dockers/cluster.redis.conf:/redis.conf:ro" + - "./dockers/cluster:/redis/work" profiles: - cluster + - all-stack - all - stunnel: - image: redisfab/stunnel:latest - depends_on: - - redis - ports: - - 6666:6666 - profiles: - - all - - standalone - - ssl - volumes: - - "./dockers/stunnel/conf:/etc/stunnel/conf.d:ro" - - "./dockers/stunnel/keys:/etc/stunnel/keys:ro" - sentinel: - image: redis/redis-stack-server:edge + <<: *client-libs-image container_name: redis-sentinel depends_on: - redis environment: - - "REDIS_ARGS=--port 26379" - entrypoint: "/opt/redis-stack/bin/redis-sentinel /redis.conf --port 26379" + - REDIS_CLUSTER=no + - NODES=3 + - PORT=26379 + command: ${REDIS_EXTRA_ARGS:---sentinel} ports: - 26379:26379 - volumes: - - "./dockers/sentinel.conf:/redis.conf" - profiles: - - sentinel - - all - - sentinel2: - image: redis/redis-stack-server:edge - container_name: redis-sentinel2 - depends_on: - - redis - environment: - - "REDIS_ARGS=--port 26380" - entrypoint: "/opt/redis-stack/bin/redis-sentinel /redis.conf --port 26380" - ports: - 26380:26380 + - 26381:26381 volumes: - - "./dockers/sentinel.conf:/redis.conf" + - "./dockers/sentinel.conf:/redis/config-default/redis.conf" + - "./dockers/sentinel:/redis/work" profiles: - sentinel + - all-stack - all - sentinel3: - image: redis/redis-stack-server:edge - container_name: redis-sentinel3 - depends_on: - - redis - entrypoint: "/opt/redis-stack/bin/redis-sentinel /redis.conf --port 26381" + redis-stack: + <<: *client-libs-stack-image + container_name: redis-stack + environment: + - REDIS_CLUSTER=no + - PORT=6379 + command: ${REDIS_EXTRA_ARGS:---enable-debug-command yes --enable-module-command yes --save ""} ports: - - 26381:26381 + - 6479:6379 volumes: - - "./dockers/sentinel.conf:/redis.conf" + - "./dockers/redis-stack:/redis/work" profiles: - - sentinel + - standalone + - all-stack - all diff --git a/dockers/Dockerfile.cluster b/dockers/Dockerfile.cluster deleted file mode 100644 index 3a0d73415e..0000000000 --- a/dockers/Dockerfile.cluster +++ /dev/null @@ -1,7 +0,0 @@ -FROM redis/redis-stack-server:edge as rss - -COPY dockers/create_cluster.sh /create_cluster.sh -RUN ls -R /opt/redis-stack -RUN chmod a+x /create_cluster.sh - -ENTRYPOINT [ "/create_cluster.sh"] diff --git a/dockers/cluster.redis.conf b/dockers/cluster.redis.conf deleted file mode 100644 index d4de46fbed..0000000000 --- a/dockers/cluster.redis.conf +++ /dev/null @@ -1,8 +0,0 @@ -protected-mode no -enable-debug-command yes -loadmodule /opt/redis-stack/lib/redisearch.so -loadmodule /opt/redis-stack/lib/redisgraph.so -loadmodule /opt/redis-stack/lib/redistimeseries.so -loadmodule /opt/redis-stack/lib/rejson.so -loadmodule /opt/redis-stack/lib/redisbloom.so -loadmodule /opt/redis-stack/lib/redisgears.so v8-plugin-path /opt/redis-stack/lib/libredisgears_v8_plugin.so diff --git a/dockers/create_cluster.sh b/dockers/create_cluster.sh deleted file mode 100644 index da9a0cb606..0000000000 --- a/dockers/create_cluster.sh +++ /dev/null @@ -1,47 +0,0 @@ -#! /bin/bash - -mkdir -p /nodes -touch /nodes/nodemap -if [ -z ${START_PORT} ]; then - START_PORT=16379 -fi -if [ -z ${END_PORT} ]; then - END_PORT=16384 -fi -if [ ! -z "$3" ]; then - START_PORT=$2 - START_PORT=$3 -fi -echo "STARTING: ${START_PORT}" -echo "ENDING: ${END_PORT}" - -for PORT in `seq ${START_PORT} ${END_PORT}`; do - mkdir -p /nodes/$PORT - if [[ -e /redis.conf ]]; then - cp /redis.conf /nodes/$PORT/redis.conf - else - touch /nodes/$PORT/redis.conf - fi - cat << EOF >> /nodes/$PORT/redis.conf -port ${PORT} -cluster-enabled yes -daemonize yes -logfile /redis.log -dir /nodes/$PORT -EOF - - set -x - /opt/redis-stack/bin/redis-server /nodes/$PORT/redis.conf - sleep 1 - if [ $? -ne 0 ]; then - echo "Redis failed to start, exiting." - continue - fi - echo 127.0.0.1:$PORT >> /nodes/nodemap -done -if [ -z "${REDIS_PASSWORD}" ]; then - echo yes | /opt/redis-stack/bin/redis-cli --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1 -else - echo yes | opt/redis-stack/bin/redis-cli -a ${REDIS_PASSWORD} --cluster create `seq -f 127.0.0.1:%g ${START_PORT} ${END_PORT}` --cluster-replicas 1 -fi -tail -f /redis.log diff --git a/dockers/sentinel.conf b/dockers/sentinel.conf index 1a33f53344..75f711e5d4 100644 --- a/dockers/sentinel.conf +++ b/dockers/sentinel.conf @@ -1,4 +1,5 @@ -sentinel monitor redis-py-test 127.0.0.1 6379 2 +sentinel resolve-hostnames yes +sentinel monitor redis-py-test redis 6379 2 sentinel down-after-milliseconds redis-py-test 5000 sentinel failover-timeout redis-py-test 60000 sentinel parallel-syncs redis-py-test 1 \ No newline at end of file diff --git a/dockers/stunnel/README b/dockers/stunnel/README deleted file mode 100644 index e92ae78981..0000000000 --- a/dockers/stunnel/README +++ /dev/null @@ -1 +0,0 @@ - This directory contains a helper script to create ssl certificates for ssl tests. If the certificates are out of date, re-run create_certs and check them in. These are snake oil certificates. diff --git a/dockers/stunnel/conf/redis.conf b/dockers/stunnel/conf/redis.conf deleted file mode 100644 index a150d8b011..0000000000 --- a/dockers/stunnel/conf/redis.conf +++ /dev/null @@ -1,6 +0,0 @@ -[redis] -accept = 6666 -connect = redis:6379 -cert = /etc/stunnel/keys/server-cert.pem -key = /etc/stunnel/keys/server-key.pem -verify = 0 diff --git a/dockers/stunnel/create_certs.sh b/dockers/stunnel/create_certs.sh deleted file mode 100755 index f3bcea6f5d..0000000000 --- a/dockers/stunnel/create_certs.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -set -e - -DESTDIR=`dirname "$0"`/keys -test -d ${DESTDIR} || mkdir ${DESTDIR} -cd ${DESTDIR} - -SSL_SUBJECT="/C=CA/ST=Winnipeg/L=Manitoba/O=Some Corp/OU=IT Department/CN=example.com" -which openssl &>/dev/null -if [ $? -ne 0 ]; then - echo "No openssl binary present, exiting." - exit 1 -fi - -openssl genrsa -out ca-key.pem 2048 &>/dev/null - -openssl req -new -x509 -nodes -days 365000 \ - -key ca-key.pem \ - -out ca-cert.pem \ - -subj "${SSL_SUBJECT}" &>/dev/null - -openssl req -newkey rsa:2048 -nodes -days 365000 \ - -keyout server-key.pem \ - -out server-req.pem \ - -subj "${SSL_SUBJECT}" &>/dev/null - -openssl x509 -req -days 365000 -set_serial 01 \ - -in server-req.pem \ - -out server-cert.pem \ - -CA ca-cert.pem \ - -CAkey ca-key.pem &>/dev/null - -openssl req -newkey rsa:2048 -nodes -days 365000 \ - -keyout client-key.pem \ - -out client-req.pem \ - -subj "${SSL_SUBJECT}" &>/dev/null - -openssl x509 -req -days 365000 -set_serial 01 \ - -in client-req.pem \ - -out client-cert.pem \ - -CA ca-cert.pem \ - -CAkey ca-key.pem &>/dev/null - -echo "Keys generated in ${DESTDIR}:" -ls diff --git a/dockers/stunnel/keys/ca-cert.pem b/dockers/stunnel/keys/ca-cert.pem deleted file mode 100644 index 460354d9ad..0000000000 --- a/dockers/stunnel/keys/ca-cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDaDCCAlACCQCui7X/vxmwGjANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJD -QTERMA8GA1UECAwIV2lubmlwZWcxETAPBgNVBAcMCE1hbml0b2JhMRIwEAYDVQQK -DAlTb21lIENvcnAxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDASBgNVBAMMC2V4 -YW1wbGUuY29tMCAXDTIyMDExMjE0NTQyMVoYDzMwMjEwNTE1MTQ1NDIxWjB1MQsw -CQYDVQQGEwJDQTERMA8GA1UECAwIV2lubmlwZWcxETAPBgNVBAcMCE1hbml0b2Jh -MRIwEAYDVQQKDAlTb21lIENvcnAxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxFDAS -BgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAtSqof5fXyN/Y6GSLBBNA/zhrqw2qcBW4va6+Wc24WTaBXcP0w13njz+j1b5V -9rbpz0i7WUkg3bBPecFFuCFyQnvn2JaE9b7kX1lLmszanrYfWQ9bYQyecox3HuYq -eu330S+bD0liYh5rV7oEanuSCJW+a/dgEl3l/+Qb0zo2ZNEAXRuBv6lNmvBSsdIt -lc5n/P06ntJ6Ia/7rO0ZEiBb6hLFKfiIo/XvDrGNlYulJEcDmC3PkzzJRGnA7R2F -7Vggj4l4pGE/3EtnA4C/rd0Shf9TIPQFA2HOx3oYsrOonuBYM2urciNeojP5XGY/ -Zdau7hzgFBgF8tWsLU6bKyZ3NwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBJwnf3 -FARRxQF1Q2jIXQdyUS/lqq74C+PZF5IKOKb2K3dT1BFJlBgduvj4Ih5KUakImhMB -SdaiwKzgB9APXNVAgrzSCb49PzXzvmaIFhPmBXSITFFfGupxpo0ZStwI03B0KZBs -l3Zd0SzjKqZNVtTnxyDyWnYNFJtuCGanTjyPcCAFvVwzDQyzZ14liyM389WM950a -ANM7H0iv6U/h7lWhnvBOlRfj89JChBvEROlWuYfyyELZpAXsmuwWdh0pwgGpqMI/ -EtLas2sbX5apE8P1S2Uxc+dS4IjoA/TrnP21rXwJ8AWzrntsZalSx9uueb1qhPp8 -EL7asG4+G3BpQrL1 ------END CERTIFICATE----- diff --git a/dockers/stunnel/keys/ca-key.pem b/dockers/stunnel/keys/ca-key.pem deleted file mode 100644 index 64db528c48..0000000000 --- a/dockers/stunnel/keys/ca-key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAtSqof5fXyN/Y6GSLBBNA/zhrqw2qcBW4va6+Wc24WTaBXcP0 -w13njz+j1b5V9rbpz0i7WUkg3bBPecFFuCFyQnvn2JaE9b7kX1lLmszanrYfWQ9b -YQyecox3HuYqeu330S+bD0liYh5rV7oEanuSCJW+a/dgEl3l/+Qb0zo2ZNEAXRuB -v6lNmvBSsdItlc5n/P06ntJ6Ia/7rO0ZEiBb6hLFKfiIo/XvDrGNlYulJEcDmC3P -kzzJRGnA7R2F7Vggj4l4pGE/3EtnA4C/rd0Shf9TIPQFA2HOx3oYsrOonuBYM2ur -ciNeojP5XGY/Zdau7hzgFBgF8tWsLU6bKyZ3NwIDAQABAoIBACq8mWsgAsNcKusH -bNPVRuvt/1gmrSIrvZzhb/33TZmeBf58j2zW5h0gwiFV+SluFNHVMnzph1tEkDsE -oNHC8hVE7XhmaY8fLPhhNDicQqZWCCcWPFQ0idwzzpX3beX55Q/vzwBYK2FCE8hq -FUiZReXIjVci0AMFK5Cl2vqFLPezAGvaZ4/M1reOF3vCgWl8IXTwYOs4EYd1CJt7 -bMwO9Q6P8V0BVhJO2tdwIe5XL5X086sMMPYXqMuwX9m3vZFQFpsZobmoAyYLVY+h -IMoQZdh4O4sFYPQBPzhZXluFDl8rX6G5A9jUPxDfeVz+799RXi31jTYeH01OwM89 -/0BNryECgYEA15hU0qDAnM7fBiTTGbRUT/QPOmEUOPcnWfLWOyJsovAVLL1X0jmt -GFm+FkTtOlcTVgDHXeHNw81zrgDDuW7fwaKloPeyWhyO6rp2jntAz/OayfA5UYOf -REhXdQH7rMAkGgy1t7zKGHTYAslHjD2dOikCuHH/13otSJS4wNvTaZUCgYEA1x6L -abxYDpR7jn2Yym0CbIiZ6tqShtqLi4eNF7PDVe3rUM7gYU767UFSKPvRpsq+BFwf -LLRFgpggNRDrZWoK0ZekHD1x8pCJF+O4pj/Fhra4uI+hInycRQ4xsj9VU/WftxQ4 -aOojB28F0fBO56T90caQVSR09DGNmElSQFcw4psCgYApf8n8DTNmO6/UV+xGi16b -UUhJHXyuBm0NtF+mXFb6+impRf0Mm0uFX2jmknfzfeVb7aRyns9jvD1jJgSGwh/R -/wPQuz0aeVrNNf0yKels3eBStKnj1eknVKF5BVuzgfyxAvdLmcxw7rTRvHrINOf5 -1QEQDemISZ1D1lTF0sqcDQKBgCmE6rGAuZouzF4nHZtMSOB7yQFMKGXAvpgylGfT -uUrXfch99U6yuLmcFuh0GfXQQbaDtTyimpvnEqhLWLOdMPNdCj6tGVYQ0XT77cKg -olYq5CIzDo2icWLep3bYxHZM/QOP8odFUXd41S287O3GqXqYkXjtbWlIOyT+WdKz -QWsrAoGALnac4Vh2s12Cv3YiQbkPtBRe8oxI0h6DEIdBciPDGq6WXq6O2PXXuBhM -X47mObUsSuzI6hI4/vd4/tXD7TM3fS1YDdZXj7d51ZjT/jmlTVxAHa3DJ8i7o+rH -Fqv/lh6MB6FGkXZ9vAGQe5RwUbDD16QO/1mz7fg0YBA9A8plM8s= ------END RSA PRIVATE KEY----- diff --git a/dockers/stunnel/keys/client-cert.pem b/dockers/stunnel/keys/client-cert.pem deleted file mode 100644 index 5c48eb8b3d..0000000000 --- a/dockers/stunnel/keys/client-cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYDCCAkgCAQEwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCQ0ExETAPBgNV -BAgMCFdpbm5pcGVnMREwDwYDVQQHDAhNYW5pdG9iYTESMBAGA1UECgwJU29tZSBD -b3JwMRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNv -bTAgFw0yMjAxMTIxNDU0MjFaGA8zMDIxMDUxNTE0NTQyMVowdTELMAkGA1UEBhMC -Q0ExETAPBgNVBAgMCFdpbm5pcGVnMREwDwYDVQQHDAhNYW5pdG9iYTESMBAGA1UE -CgwJU29tZSBDb3JwMRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRQwEgYDVQQDDAtl -eGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALwWezv2 -WHf6fCyiLYHmi3+Qf/33VmdNAapWzpOZ0Xmuzf8SSoEep/YotvnmIBe8DqspjzBW -eeg+n7qre+qawGv1AOANlStLKeNvnXhWS0bdoAKMP68Q8jvU+YSmJNZTRkg/39MA -YNqxYABYamoIQ7qX+g91HsCxPSzqIyjLwY4hPHGYfxGhRH5ne2RtsYEcMjOJWs8s -U4x6wpwn9Y4vnG1AqpcwY4xm65g/52BWWM9WfZ++y17MynSdoE29EqXCAGqhh1i1 -IRlKN1vr/792VYzOm2fHScaaCaCmhDIlTw0TlOgnfi7CFtY0z6uizSwG4RWCW+3/ -g47T3q8aCnvlkCkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAGuNzbKtvKsdfQaAV -SmeNAZqyoG2Fbmh/txj6j+UThu3tadk07/SukgsM6yepeq05+wguW43eBtig/LzH -pSHCn4s/w0fvu1GqePWsTdGI3xnJakZIlkOXPStIgZJNewT9rD6WoRfthvTOda8v -NBjW0InACnVvzAivX9xhbUB4K/I8aEGaAZwzIGnQbsxygPVZKe/Y8oWhiks0qYo2 -Wev1Swli4EeqbYvg+3TMy7T1pDkjAmAdsv7yJAYKsM3xCu7K8vA/e+2J2hjUQIfI -Thdjb6FNywihVaAK2BUqL6cMgF8I+nX7ywVOBAz+a3F00sSogapztinzqsjFDeT9 -5V/MSg== ------END CERTIFICATE----- diff --git a/dockers/stunnel/keys/client-key.pem b/dockers/stunnel/keys/client-key.pem deleted file mode 100644 index 4117706d0e..0000000000 --- a/dockers/stunnel/keys/client-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Fns79lh3+nws -oi2B5ot/kH/991ZnTQGqVs6TmdF5rs3/EkqBHqf2KLb55iAXvA6rKY8wVnnoPp+6 -q3vqmsBr9QDgDZUrSynjb514VktG3aACjD+vEPI71PmEpiTWU0ZIP9/TAGDasWAA -WGpqCEO6l/oPdR7AsT0s6iMoy8GOITxxmH8RoUR+Z3tkbbGBHDIziVrPLFOMesKc -J/WOL5xtQKqXMGOMZuuYP+dgVljPVn2fvstezMp0naBNvRKlwgBqoYdYtSEZSjdb -6/+/dlWMzptnx0nGmgmgpoQyJU8NE5ToJ34uwhbWNM+ros0sBuEVglvt/4OO096v -Ggp75ZApAgMBAAECggEBAJDXLydJ2W7rMdydNzYld59Qg3/rjFoYbwPhvUrk1O9D -sdaPG1i7ZtSlHeLrWCNu6kzcwCuVLGOwdgimLdLIQQ3hqj7fttOUGjnOphEZQvbb -jHDp19DU1/VDWLLRzuRNVH4m0hIG5I8EsM0TST9GBgIXLrXgl0IEOvvvggvUfMUZ -eGrrVsW56XIc25LZCalf20lcoyKa2hVjtlF2ds41PY6WqytkRJ7zpnBzO4g+Kz3D -iA2rzNn/Ds2CCvuNDA8UF6qG/INbcySaq+qbSYLohWSsz9smIhkWUyF4YfbtziZr -8AbxZKbS8VopSFxF+o35CbEZeTPkFkrBfbD0xUlCeEECgYEA6h1hLodTeQUpQoc3 -6brWvw1gM/tM0RyKbpOEwJGK1MnX99IM5z6qGY+d1htl7cB3RARpaY1HAvRXHhXt -9qaSdhqR1hagZLn2vbelFkbJ0N1agdR6XYgGoxfH2RCluNfZZPOB6urfCLNbMjgb -B1rkvIWiELCzujwsZ6m5sOomP70CgYEAzauggpcqEXQ4P4+y6B/8gOt7chuRczft -1YTj2Y5tfZSTZmh01BUgenDgA1+NFJ9ni33P6+Ij/1D0ZGdea5Lqw2VP1ZDEIYSm -j3ekkge/0AljZgIil2UviBhx5W2BlwnlukIwMvzVRwDulQsV3sDxprZKHYTaRcnC -EB4Y9T6uUt0CgYBjeCojP8IaiDPYnWUHPKgjMoaub1Za/ppekvTzcKMg98V3+Noc -okZZZ+iy4J81HfJOhuVWwHzsZ25gTQb3JhzSa0WNRb3OLikEwHM2/MqgoHvk76cx -+CqBvwfdVTJkT+mA9+k6K6KpqrLTqnzpahgHdWu/VaR3OzvOq5FG9qVbrQKBgF5F -xRUW5RmLBB1eaMstnjgZuEPdjxYZFNNCTo5yUo21hLr0NljgNjrpckUZjzlct8Gg -saWVyppFKUC8gPMeLK3TynxCFySmARLR7IVjN/DL3NvtLp3mq5reWZaoUzZAOyTd -Ieq9KaWaL8HxitzH4/xeoipVsxc6G9H3eckwKgehAoGBAM/E0qLpEXOaLxODY8tt -+qpoNWHZn1M6cVX+tA/6igKfqUY96lefLmEiV1N01qW7+keFMXT12X/edsykG8jd -gcNkNjSNwDSi8ixl0YlQwRJjX93TEip78sisQ3mCUqZUCNbm0Dm66Bqe8rAD5AdF -G4oVbUu1gN0StX85Uw8J0AYS ------END PRIVATE KEY----- diff --git a/dockers/stunnel/keys/client-req.pem b/dockers/stunnel/keys/client-req.pem deleted file mode 100644 index ecf83f4daa..0000000000 --- a/dockers/stunnel/keys/client-req.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICujCCAaICAQAwdTELMAkGA1UEBhMCQ0ExETAPBgNVBAgMCFdpbm5pcGVnMREw -DwYDVQQHDAhNYW5pdG9iYTESMBAGA1UECgwJU29tZSBDb3JwMRYwFAYDVQQLDA1J -VCBEZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBALwWezv2WHf6fCyiLYHmi3+Qf/33VmdNAapWzpOZ -0Xmuzf8SSoEep/YotvnmIBe8DqspjzBWeeg+n7qre+qawGv1AOANlStLKeNvnXhW -S0bdoAKMP68Q8jvU+YSmJNZTRkg/39MAYNqxYABYamoIQ7qX+g91HsCxPSzqIyjL -wY4hPHGYfxGhRH5ne2RtsYEcMjOJWs8sU4x6wpwn9Y4vnG1AqpcwY4xm65g/52BW -WM9WfZ++y17MynSdoE29EqXCAGqhh1i1IRlKN1vr/792VYzOm2fHScaaCaCmhDIl -Tw0TlOgnfi7CFtY0z6uizSwG4RWCW+3/g47T3q8aCnvlkCkCAwEAAaAAMA0GCSqG -SIb3DQEBCwUAA4IBAQAqLgfkWWIE1RV1TENnr9jT+SK8u3F2nX4mUzNmy8azq52I -fO8qPKmvV2amt5y961jNpR+rRpARncONuf6NQR5qCMu/EKjVi9BhOkoIOK0RjgtK -AkCTON1J8022JDQpN5/H5ZpLDkIlBtpwDvEaR/PnTaJxtGwLY8HxY6h20PDjP3J9 -Xu3w3m/s3uVjFG07RDvbwK02vYskePnlsKVw+uu5C2blOQRlRVvdCCkwN0y6IiWW -uRGRSzwufgejrfDUJG4VZuNpvWjFfzjHW105g1AxaTW3anRqBSNxYF+iawfbGdf4 -bGT4Wazbwq5uU3uixxOzxPMI5ZP/gn0ywz9S1RRK ------END CERTIFICATE REQUEST----- diff --git a/dockers/stunnel/keys/server-cert.pem b/dockers/stunnel/keys/server-cert.pem deleted file mode 100644 index 3a1bf72011..0000000000 --- a/dockers/stunnel/keys/server-cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYDCCAkgCAQEwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCQ0ExETAPBgNV -BAgMCFdpbm5pcGVnMREwDwYDVQQHDAhNYW5pdG9iYTESMBAGA1UECgwJU29tZSBD -b3JwMRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNv -bTAgFw0yMjAxMTIxNDU0MjFaGA8zMDIxMDUxNTE0NTQyMVowdTELMAkGA1UEBhMC -Q0ExETAPBgNVBAgMCFdpbm5pcGVnMREwDwYDVQQHDAhNYW5pdG9iYTESMBAGA1UE -CgwJU29tZSBDb3JwMRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRQwEgYDVQQDDAtl -eGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMxZETTb -dxqFsNjUIJbpS6ZT9RkH/dWYTVk1uRUMh6Cr6920g/7pSaRLIx8guTDHa1jhPIlX -lax7oZyX9coLjhSc6cy0ZmoH0zrp8ZbRc/qOawuO62arKP89pO/18MB3r9zPb1PJ -evTP203+2a8ly25cscMTUge+rHMFAUW+/01hc90CY9ial9oCl9wtoPdPGA8XlX3u -RswOAM79fM+Szvv+bX0VvFakkfHIE8oIK5/rJYDswBKAshw5CjW/OEjD6FbCb84c -1E7jJhwwd6X70yDMOrJ8iVkA/lpzfoosiuYm/okgbPPXWEo8aa//MrSH90l2+M9q -Vvn8hbmwlJl+2IMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAEcTps0CUnBZJBH/w -8oJo8kAvsHhFTLJpTtiztut5qI+FMgC6sPcVUKi95gie2pdJ91y6sFzqLpghAciR -ocYBy/jxK0M7OGJHLpUPeCS1yxeEyeZXpMPS90bUo1tPh7QDAojoRrFYo6M6DbL3 -dcErTJlvKnBBT9/DmENx75R+1nSB86vq0je+X0IqbZXeJyWju6ybjbwo1NPpnu+f -jnXTG0+ZIsepms0VTXwcTy3dthIE+uw4XqTQ1qYg2stQAOUJ0nmb68NExi5zom5G -0nh7tZnL0N+Z+XeNo7gaVatxfmgyk/HO2Vl4Wk4NA0PkR0yk2vNUwS0rKAb2mYc6 -T2gHdQ== ------END CERTIFICATE----- diff --git a/dockers/stunnel/keys/server-key.pem b/dockers/stunnel/keys/server-key.pem deleted file mode 100644 index 62595e017c..0000000000 --- a/dockers/stunnel/keys/server-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDMWRE023cahbDY -1CCW6UumU/UZB/3VmE1ZNbkVDIegq+vdtIP+6UmkSyMfILkwx2tY4TyJV5Wse6Gc -l/XKC44UnOnMtGZqB9M66fGW0XP6jmsLjutmqyj/PaTv9fDAd6/cz29TyXr0z9tN -/tmvJctuXLHDE1IHvqxzBQFFvv9NYXPdAmPYmpfaApfcLaD3TxgPF5V97kbMDgDO -/XzPks77/m19FbxWpJHxyBPKCCuf6yWA7MASgLIcOQo1vzhIw+hWwm/OHNRO4yYc -MHel+9MgzDqyfIlZAP5ac36KLIrmJv6JIGzz11hKPGmv/zK0h/dJdvjPalb5/IW5 -sJSZftiDAgMBAAECggEAct5+daAIy7frOXfE+hAanl0DohaD8dWzZTp12Ac7Fm6O -IAqhSGILK3exPoY+k9UF2uiCBxJc6KB2sHgbioAEVkH+izu9dkz/yFZJn+YNtALq -2Yx1dzkvyor0dI9jzk15Zj6U7hyMKaHOPYHNDE/Kkzc4Fdh+fCwK9H0TwgkjqnLj -hfRK32+SqaftkhZnCxaFfdVVzhonWsaB7VcyUPdIHAMG0xUQ9oNTM0WLPotU/uh0 -XDCemwXhkqfKaAlnj0YBsu65WOTTiPixOPigDe745CHFBXwvCF28kxjSbCAVlHIv -JcTtq1EA+fNHRTeHgNGSpqOdfuVrBMyp3KiztLBfQQKBgQD47MFmQphXVQWRmKoU -gCFf28notV8J0VGyG7E0tFMS3GgyAAl8H8I6fB9UYOmD95PrHTROxKpc7jYtZRW3 -KcYJP5zKa+DqSSks8I5dLwFkKYVC0GiEJWuRwS9aHaD7ja65NtXJO+2iZ598s39w -iSx0OAvaf9cFUrsAmHAE84c+/QKBgQDSJ/VE1CS0Tv2kL5Wbr/RmgYBZbXHnRz6j -LFA7JwX3seHtuo+WBe8BMOMS4YqW6K2YTqwU8NtN1oATWg72TcLhwJZ3sKGPiMhM -/cHW0dJqYsXujIOd/dlSr+j9Mouoxm6Spl+hGpj2IPUV9Dlm8N4SqPk83m0O+8Hy -P088HK7NfwKBgQC3D0XbMjZeY0RJIoBRuzjQCg6eeGOAENOHrB3RqJs/T5/AxY40 -Hhb0c7uGjg6s4jGBwmRpWPAAj56AG8qwfKQKwSFJK7SoF02UowPPO3ZGdtJtpF54 -cBx/gBaWqxtsY3GO++iUqOHFgXckeczKsdZjUaRF96XlYEXt1izrNzzK8QKBgQCP -OsCE6nkhknx3/B5g/2j4u+Y4DMmGsR3VpAwCZLRCfq/WkEHwI5cjHqiEY8dK1sYJ -egT6OLWetUSQ694qrBDYP6PNa0qRQs4Q+xmzSUm5TBxOWuIROcN2AYIvntVkb+lI -da/TYwdBKHEhR1Qf/qW73gIQJB/8CEXEzrU36OySDQKBgQD35khRdiU+1bPt/DpW -+8A+88BuxXMFxKYtEoMuTJnb7enarwp7+FtY6WhNgOgxELTpRbYw9496mOmNbJKL -PmTXzs3aS5bv/2JTtc5+CHzf9PJ+jAYWnh9hCq9x/mA0QRMQAZEi8vhhYFaWiiV3 -wUYnDFnnAKia1VILt9jZ7I4T7Q== ------END PRIVATE KEY----- diff --git a/dockers/stunnel/keys/server-req.pem b/dockers/stunnel/keys/server-req.pem deleted file mode 100644 index 361891d1c8..0000000000 --- a/dockers/stunnel/keys/server-req.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICujCCAaICAQAwdTELMAkGA1UEBhMCQ0ExETAPBgNVBAgMCFdpbm5pcGVnMREw -DwYDVQQHDAhNYW5pdG9iYTESMBAGA1UECgwJU29tZSBDb3JwMRYwFAYDVQQLDA1J -VCBEZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAMxZETTbdxqFsNjUIJbpS6ZT9RkH/dWYTVk1uRUM -h6Cr6920g/7pSaRLIx8guTDHa1jhPIlXlax7oZyX9coLjhSc6cy0ZmoH0zrp8ZbR -c/qOawuO62arKP89pO/18MB3r9zPb1PJevTP203+2a8ly25cscMTUge+rHMFAUW+ -/01hc90CY9ial9oCl9wtoPdPGA8XlX3uRswOAM79fM+Szvv+bX0VvFakkfHIE8oI -K5/rJYDswBKAshw5CjW/OEjD6FbCb84c1E7jJhwwd6X70yDMOrJ8iVkA/lpzfoos -iuYm/okgbPPXWEo8aa//MrSH90l2+M9qVvn8hbmwlJl+2IMCAwEAAaAAMA0GCSqG -SIb3DQEBCwUAA4IBAQCljqLOTU3tFEqxJ2AbZ5HVg9AN/SEUX8c/SyzCBii3r9Dj -ubp0YWvYvgm7lnXsFAVDznf89RAzwdFur5iAQ95VfWBW6NEjdFQIh51KF6P/Qzjg -TbctVeX/MTPuKewVhkQg9/sRmegbb+RBKEeCZccLUVuk5DAgFmi0cFP4e50uuNRG -gwskG9nJp/X5aBd4Y1YKg8XS+WLPwwrYvffoHN8mWHh+YqF16MbxMHM5xRMWu6E7 -801EzEWAW5Y8J2ssp/9FSI+aXOhk68aNlIVNc2R6Rg1IA8zKV4WSWTMUWAud832h -z9UZH/YkPgipuiflpKBGs5lbElRx3o6lYblhRL8J ------END CERTIFICATE REQUEST----- diff --git a/docs/_static/logo-redis.svg b/docs/_static/logo-redis.svg new file mode 100644 index 0000000000..a8de68d23c --- /dev/null +++ b/docs/_static/logo-redis.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/_static/redis-cube-red-white-rgb.svg b/docs/_static/redis-cube-red-white-rgb.svg deleted file mode 100644 index 936eb231b9..0000000000 --- a/docs/_static/redis-cube-red-white-rgb.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/advanced_features.rst b/docs/advanced_features.rst index de645bd764..0ed3e1ff34 100644 --- a/docs/advanced_features.rst +++ b/docs/advanced_features.rst @@ -380,8 +380,6 @@ run_in_thread. >>> def exception_handler(ex, pubsub, thread): >>> print(ex) >>> thread.stop() - >>> thread.join(timeout=1.0) - >>> pubsub.close() >>> thread = p.run_in_thread(exception_handler=exception_handler) A PubSub object adheres to the same encoding semantics as the client diff --git a/docs/clustering.rst b/docs/clustering.rst index f8320e4e59..cf257d8ad5 100644 --- a/docs/clustering.rst +++ b/docs/clustering.rst @@ -17,8 +17,8 @@ Nodes <#specifying-target-nodes>`__ \| `Multi-key Commands <#multi-key-commands>`__ \| `Known PubSub Limitations <#known-pubsub-limitations>`__ -Creating clusters ------------------ +Connecting to cluster +--------------------- Connecting redis-py to a Redis Cluster instance(s) requires at a minimum a single node for cluster discovery. There are multiple ways in which a diff --git a/docs/conf.py b/docs/conf.py index a201da2fc0..865bd522a2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -10,6 +10,7 @@ # All configuration values have a default; values that are commented out # serve to show the default. +import datetime import os import sys @@ -30,12 +31,15 @@ "nbsphinx", "sphinx_gallery.load_style", "sphinx.ext.autodoc", - "sphinx_autodoc_typehints", - "sphinx.ext.doctest", "sphinx.ext.viewcode", "sphinx.ext.autosectionlabel", + "sphinx.ext.napoleon", ] +# Napoleon settings. We only accept Google-style docstrings. +napoleon_google_docstring = True +napoleon_numpy_docstring = False + # AutosectionLabel settings. # Uses a :