Showing preview only (1,165K chars total). Download the full file or copy to clipboard to get everything.
Repository: MagicStack/asyncpg
Branch: master
Commit: db8ecc2a38e1
Files: 121
Total size: 1.1 MB
Directory structure:
gitextract_qed7mic1/
├── .clang-format
├── .clangd
├── .flake8
├── .github/
│ ├── ISSUE_TEMPLATE.md
│ ├── RELEASING.rst
│ ├── release_log.py
│ └── workflows/
│ ├── install-krb5.sh
│ ├── install-postgres.sh
│ ├── release.yml
│ └── tests.yml
├── .gitignore
├── .gitmodules
├── AUTHORS
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── asyncpg/
│ ├── .gitignore
│ ├── __init__.py
│ ├── _asyncio_compat.py
│ ├── _testbase/
│ │ ├── __init__.py
│ │ └── fuzzer.py
│ ├── _version.py
│ ├── cluster.py
│ ├── compat.py
│ ├── connect_utils.py
│ ├── connection.py
│ ├── connresource.py
│ ├── cursor.py
│ ├── exceptions/
│ │ ├── __init__.py
│ │ └── _base.py
│ ├── introspection.py
│ ├── pool.py
│ ├── prepared_stmt.py
│ ├── protocol/
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── codecs/
│ │ │ ├── __init__.py
│ │ │ ├── array.pyx
│ │ │ ├── base.pxd
│ │ │ ├── base.pyx
│ │ │ ├── pgproto.pyx
│ │ │ ├── range.pyx
│ │ │ ├── record.pyx
│ │ │ └── textutils.pyx
│ │ ├── consts.pxi
│ │ ├── coreproto.pxd
│ │ ├── coreproto.pyx
│ │ ├── cpythonx.pxd
│ │ ├── encodings.pyx
│ │ ├── pgtypes.pxi
│ │ ├── prepared_stmt.pxd
│ │ ├── prepared_stmt.pyx
│ │ ├── protocol.pxd
│ │ ├── protocol.pyi
│ │ ├── protocol.pyx
│ │ ├── record/
│ │ │ ├── pythoncapi_compat.h
│ │ │ ├── pythoncapi_compat_extras.h
│ │ │ ├── recordobj.c
│ │ │ └── recordobj.h
│ │ ├── record.pyi
│ │ ├── recordcapi.pxd
│ │ ├── scram.pxd
│ │ ├── scram.pyx
│ │ ├── settings.pxd
│ │ └── settings.pyx
│ ├── serverversion.py
│ ├── transaction.py
│ ├── types.py
│ └── utils.py
├── docs/
│ ├── .gitignore
│ ├── Makefile
│ ├── _static/
│ │ └── theme_overrides.css
│ ├── api/
│ │ └── index.rst
│ ├── conf.py
│ ├── faq.rst
│ ├── index.rst
│ ├── installation.rst
│ ├── requirements.txt
│ └── usage.rst
├── pyproject.toml
├── setup.py
├── tests/
│ ├── __init__.py
│ ├── certs/
│ │ ├── ca.cert.pem
│ │ ├── ca.crl.pem
│ │ ├── ca.key.pem
│ │ ├── client.cert.pem
│ │ ├── client.csr.pem
│ │ ├── client.key.pem
│ │ ├── client.key.protected.pem
│ │ ├── client_ca.cert.pem
│ │ ├── client_ca.cert.srl
│ │ ├── client_ca.key.pem
│ │ ├── gen.py
│ │ ├── server.cert.pem
│ │ ├── server.crl.pem
│ │ └── server.key.pem
│ ├── test__environment.py
│ ├── test__sourcecode.py
│ ├── test_adversity.py
│ ├── test_cache_invalidation.py
│ ├── test_cancellation.py
│ ├── test_codecs.py
│ ├── test_connect.py
│ ├── test_copy.py
│ ├── test_cursor.py
│ ├── test_exceptions.py
│ ├── test_execute.py
│ ├── test_introspection.py
│ ├── test_listeners.py
│ ├── test_logging.py
│ ├── test_pool.py
│ ├── test_prepare.py
│ ├── test_record.py
│ ├── test_subinterpreters.py
│ ├── test_test.py
│ ├── test_timeout.py
│ ├── test_transaction.py
│ ├── test_types.py
│ └── test_utils.py
└── tools/
├── generate_exceptions.py
└── generate_type_map.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .clang-format
================================================
# A clang-format style that approximates Python's PEP 7
BasedOnStyle: Google
AlwaysBreakAfterReturnType: All
AllowShortIfStatementsOnASingleLine: false
AlignAfterOpenBracket: Align
BreakBeforeBraces: Stroustrup
ColumnLimit: 95
DerivePointerAlignment: false
IndentWidth: 4
Language: Cpp
PointerAlignment: Right
ReflowComments: true
SpaceBeforeParens: ControlStatements
SpacesInParentheses: false
TabWidth: 4
UseTab: Never
SortIncludes: false
================================================
FILE: .clangd
================================================
Diagnostics:
Includes:
IgnoreHeader:
- "pythoncapi_compat.*\\.h"
================================================
FILE: .flake8
================================================
[flake8]
select = C90,E,F,W,Y0
ignore = E402,E731,W503,W504,E252
exclude = .git,__pycache__,build,dist,.eggs,.github,.local,.venv*,.tox
per-file-ignores = *.pyi: F401,F403,F405,F811,E127,E128,E203,E266,E301,E302,E305,E501,E701,E704,E741,B303,W503,W504
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!--
Thank you for reporting an issue/feature request.
If this is a feature request, please disregard this template. If this is
a bug report, please answer to the questions below.
It will be much easier for us to fix the issue if a test case that reproduces
the problem is provided, with clear instructions on how to run it.
Thank you!
-->
* **asyncpg version**:
* **PostgreSQL version**:
* **Do you use a PostgreSQL SaaS? If so, which? Can you reproduce
the issue with a local PostgreSQL install?**:
* **Python version**:
* **Platform**:
* **Do you use pgbouncer?**:
* **Did you install asyncpg with pip?**:
* **If you built asyncpg locally, which version of Cython did you use?**:
* **Can the issue be reproduced under both asyncio and
[uvloop](https://github.com/magicstack/uvloop)?**:
<!-- Enter your issue details below this comment. -->
================================================
FILE: .github/RELEASING.rst
================================================
Releasing asyncpg
=================
When making an asyncpg release follow the below checklist.
1. Remove the ``.dev0`` suffix from ``__version__`` in ``asyncpg/__init__.py``.
2. Make a release commit:
.. code-block:: shell
$ git commit -a -m "asyncpg vX.Y.0"
Here, X.Y.0 is the ``__version__`` in ``asyncpg/__init__.py``.
3. Force push into the "releases" branch on Github:
.. code-block:: shell
$ git push --force origin master:releases
4. Wait for CI to make the release build. If there are errors,
investigate, fix and repeat steps 2 through 4.
5. Prepare the release changelog by cleaning and categorizing the output of
``.github/release_log.py``. Look at previous releases for examples
of changelog formatting:
.. code-block:: shell
$ .github/release_log.py <previously-released-version-tag>
6. Make an annotated, signed git tag and use the changelog as the tag
annotation:
.. code-block:: shell
$ git tag -s vX.Y.0
<paste changelog>
7. Push the release commit and the new tag to master on Github:
.. code-block:: shell
$ git push --follow-tags
8. Wait for CI to publish the build to PyPI.
9. Edit the release on Github and paste the same content you used for
the tag annotation (Github treats tag annotations as plain text,
rather than Markdown.)
10. Open master for development by bumping the minor component of
``__version__`` in ``asyncpg/__init__.py`` and appending the ``.dev0``
suffix.
================================================
FILE: .github/release_log.py
================================================
#!/usr/bin/env python3
#
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
import json
import requests
import re
import sys
BASE_URL = 'https://api.github.com/repos/magicstack/asyncpg/compare'
def main():
if len(sys.argv) < 2:
print('pass a sha1 hash as a first argument')
sys.exit(1)
from_hash = sys.argv[1]
if len(sys.argv) > 2:
to_hash = sys.argv[2]
r = requests.get(f'{BASE_URL}/{from_hash}...{to_hash}')
data = json.loads(r.text)
for commit in data['commits']:
message = commit['commit']['message']
first_line = message.partition('\n\n')[0]
if commit.get('author'):
username = '@{}'.format(commit['author']['login'])
else:
username = commit['commit']['author']['name']
sha = commit["sha"][:8]
m = re.search(r'\#(?P<num>\d+)\b', message)
if m:
issue_num = m.group('num')
else:
issue_num = None
print(f'* {first_line}')
print(f' (by {username} in {sha}', end='')
print(')')
print()
if __name__ == '__main__':
main()
================================================
FILE: .github/workflows/install-krb5.sh
================================================
#!/bin/bash
set -Eexuo pipefail
shopt -s nullglob
if [[ $OSTYPE == linux* ]]; then
if [ "$(id -u)" = "0" ]; then
SUDO=
else
SUDO=sudo
fi
if [ -e /etc/os-release ]; then
source /etc/os-release
elif [ -e /etc/centos-release ]; then
ID="centos"
VERSION_ID=$(cat /etc/centos-release | cut -f3 -d' ' | cut -f1 -d.)
else
echo "install-krb5.sh: cannot determine which Linux distro this is" >&2
exit 1
fi
if [ "${ID}" = "debian" -o "${ID}" = "ubuntu" ]; then
export DEBIAN_FRONTEND=noninteractive
$SUDO apt-get update
$SUDO apt-get install -y --no-install-recommends \
libkrb5-dev krb5-user krb5-kdc krb5-admin-server
elif [ "${ID}" = "almalinux" ]; then
$SUDO dnf install -y krb5-server krb5-workstation krb5-libs krb5-devel
elif [ "${ID}" = "centos" ]; then
$SUDO yum install -y krb5-server krb5-workstation krb5-libs krb5-devel
elif [ "${ID}" = "alpine" ]; then
$SUDO apk add krb5 krb5-server krb5-dev
else
echo "install-krb5.sh: Unsupported linux distro: ${distro}" >&2
exit 1
fi
else
echo "install-krb5.sh: unsupported OS: ${OSTYPE}" >&2
exit 1
fi
================================================
FILE: .github/workflows/install-postgres.sh
================================================
#!/bin/bash
set -Eexuo pipefail
shopt -s nullglob
if [[ $OSTYPE == linux* ]]; then
PGVERSION=${PGVERSION:-12}
if [ -e /etc/os-release ]; then
source /etc/os-release
elif [ -e /etc/centos-release ]; then
ID="centos"
VERSION_ID=$(cat /etc/centos-release | cut -f3 -d' ' | cut -f1 -d.)
else
echo "install-postgres.sh: cannot determine which Linux distro this is" >&2
exit 1
fi
if [ "${ID}" = "debian" -o "${ID}" = "ubuntu" ]; then
export DEBIAN_FRONTEND=noninteractive
apt-get install -y --no-install-recommends curl gnupg ca-certificates
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
mkdir -p /etc/apt/sources.list.d/
echo "deb https://apt.postgresql.org/pub/repos/apt/ ${VERSION_CODENAME}-pgdg main" \
>> /etc/apt/sources.list.d/pgdg.list
apt-get update
apt-get install -y --no-install-recommends \
"postgresql-${PGVERSION}" \
"postgresql-contrib-${PGVERSION}"
elif [ "${ID}" = "almalinux" ]; then
yum install -y \
"postgresql-server" \
"postgresql-devel" \
"postgresql-contrib"
elif [ "${ID}" = "centos" ]; then
el="EL-${VERSION_ID%.*}-$(arch)"
baseurl="https://download.postgresql.org/pub/repos/yum/reporpms"
yum install -y "${baseurl}/${el}/pgdg-redhat-repo-latest.noarch.rpm"
if [ ${VERSION_ID%.*} -ge 8 ]; then
dnf -qy module disable postgresql
fi
yum install -y \
"postgresql${PGVERSION}-server" \
"postgresql${PGVERSION}-contrib"
ln -s "/usr/pgsql-${PGVERSION}/bin/pg_config" "/usr/local/bin/pg_config"
elif [ "${ID}" = "alpine" ]; then
apk add shadow postgresql postgresql-dev postgresql-contrib
else
echo "install-postgres.sh: unsupported Linux distro: ${distro}" >&2
exit 1
fi
useradd -m -s /bin/bash apgtest
elif [[ $OSTYPE == darwin* ]]; then
brew install postgresql
else
echo "install-postgres.sh: unsupported OS: ${OSTYPE}" >&2
exit 1
fi
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
pull_request:
branches:
- "master"
- "ci"
- "[0-9]+.[0-9x]+*"
paths:
- "asyncpg/_version.py"
jobs:
validate-release-request:
runs-on: ubuntu-latest
steps:
- name: Validate release PR
uses: edgedb/action-release/validate-pr@master
id: checkver
with:
require_team: Release Managers
require_approval: no
github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}
version_file: asyncpg/_version.py
version_line_pattern: |
__version__(?:\s*:\s*typing\.Final)?\s*=\s*(?:['"])([[:PEP440:]])(?:['"])
- name: Stop if not approved
if: steps.checkver.outputs.approved != 'true'
run: |
echo ::error::PR is not approved yet.
exit 1
- name: Store release version for later use
env:
VERSION: ${{ steps.checkver.outputs.version }}
run: |
mkdir -p dist/
echo "${VERSION}" > dist/VERSION
- uses: actions/upload-artifact@v4
with:
name: dist-version
path: dist/VERSION
build-sdist:
needs: validate-release-request
runs-on: ubuntu-latest
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 50
submodules: true
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.x"
- name: Build source distribution
run: |
pip install -U setuptools wheel pip
python setup.py sdist
- uses: actions/upload-artifact@v4
with:
name: dist-sdist
path: dist/*.tar.*
build-wheels-matrix:
needs: validate-release-request
runs-on: ubuntu-latest
outputs:
include: ${{ steps.set-matrix.outputs.include }}
steps:
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: actions/setup-python@v6
with:
python-version: "3.x"
- run: pip install cibuildwheel==3.3.0
- id: set-matrix
run: |
MATRIX_INCLUDE=$(
{
cibuildwheel --print-build-identifiers --platform linux --archs x86_64,aarch64 | grep cp | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \
&& cibuildwheel --print-build-identifiers --platform macos --archs x86_64,arm64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-latest"}' \
&& cibuildwheel --print-build-identifiers --platform windows --archs x86,AMD64 | grep cp | jq -nRc '{"only": inputs, "os": "windows-latest"}'
} | jq -sc
)
echo "include=$MATRIX_INCLUDE" >> $GITHUB_OUTPUT
build-wheels:
needs: build-wheels-matrix
runs-on: ${{ matrix.os }}
name: Build ${{ matrix.only }}
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.build-wheels-matrix.outputs.include) }}
defaults:
run:
shell: bash
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 50
submodules: true
persist-credentials: false
- name: Set up QEMU
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- uses: pypa/cibuildwheel@63fd63b352a9a8bdcc24791c9dbee952ee9a8abc # v3.3.0
with:
only: ${{ matrix.only }}
env:
CIBW_BUILD_VERBOSITY: 1
- uses: actions/upload-artifact@v4
with:
name: dist-wheels-${{ matrix.only }}
path: wheelhouse/*.whl
merge-artifacts:
runs-on: ubuntu-latest
needs: [build-sdist, build-wheels]
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@v4
with:
name: dist
delete-merged: true
publish-docs:
needs: [build-sdist, build-wheels]
runs-on: ubuntu-latest
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
steps:
- name: Checkout source
uses: actions/checkout@v5
with:
fetch-depth: 5
submodules: true
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.x"
- name: Build docs
run: |
pip install --group docs
pip install -e .
make htmldocs
- name: Checkout gh-pages
uses: actions/checkout@v5
with:
fetch-depth: 5
ref: gh-pages
path: docs/gh-pages
persist-credentials: false
- name: Sync docs
run: |
rsync -a docs/_build/html/ docs/gh-pages/current/
- name: Commit and push docs
uses: magicstack/gha-commit-and-push@master
with:
target_branch: gh-pages
workdir: docs/gh-pages
commit_message: Automatic documentation update
github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}
ssh_key: ${{ secrets.RELEASE_BOT_SSH_KEY }}
gpg_key: ${{ secrets.RELEASE_BOT_GPG_KEY }}
gpg_key_id: "5C468778062D87BF!"
publish:
needs: [build-sdist, build-wheels, publish-docs]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/asyncpg
permissions:
id-token: write
attestations: write
contents: write
deployments: write
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 5
submodules: false
persist-credentials: false
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Extract Release Version
id: relver
run: |
set -e
echo "version=$(cat dist/VERSION)" >> $GITHUB_OUTPUT
rm dist/VERSION
- name: Merge and tag the PR
uses: edgedb/action-release/merge@master
with:
github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}
ssh_key: ${{ secrets.RELEASE_BOT_SSH_KEY }}
gpg_key: ${{ secrets.RELEASE_BOT_GPG_KEY }}
gpg_key_id: "5C468778062D87BF!"
tag_name: v${{ steps.relver.outputs.version }}
- name: Publish Github Release
uses: elprans/gh-action-create-release@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ steps.relver.outputs.version }}
release_name: v${{ steps.relver.outputs.version }}
target: ${{ github.event.pull_request.base.ref }}
body: ${{ github.event.pull_request.body }}
- run: |
ls -al dist/
- name: Upload to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
attestations: true
================================================
FILE: .github/workflows/tests.yml
================================================
name: Tests
on:
push:
branches:
- master
- ci
pull_request:
branches:
- master
jobs:
test-platforms:
# NOTE: this matrix is for testing various combinations of Python and OS
# versions on the system-installed PostgreSQL version (which is usually
# fairly recent). For a PostgreSQL version matrix see the test-postgres
# job.
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"]
os: [ubuntu-latest, macos-latest, windows-latest]
loop: [asyncio, uvloop]
exclude:
# uvloop does not support windows
- loop: uvloop
os: windows-latest
runs-on: ${{ matrix.os }}
permissions: {}
defaults:
run:
shell: bash
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 50
submodules: true
persist-credentials: false
- name: Check if release PR.
uses: edgedb/action-release/validate-pr@master
id: release
with:
github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}
missing_version_ok: yes
version_file: asyncpg/_version.py
version_line_pattern: |
__version__(?:\s*:\s*typing\.Final)?\s*=\s*(?:['"])([[:PEP440:]])(?:['"])
- name: Setup PostgreSQL
if: "!steps.release.outputs.is_release && matrix.os == 'macos-latest'"
run: |
POSTGRES_FORMULA="postgresql@18"
brew install "$POSTGRES_FORMULA"
echo "$(brew --prefix "$POSTGRES_FORMULA")/bin" >> $GITHUB_PATH
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
if: "!steps.release.outputs.is_release"
with:
python-version: ${{ matrix.python-version }}
- name: Install Python Deps
if: "!steps.release.outputs.is_release"
run: |
[ "$RUNNER_OS" = "Linux" ] && .github/workflows/install-krb5.sh
python -m pip install -U pip setuptools wheel
python -m pip install --group test
python -m pip install -e .
- name: Test
if: "!steps.release.outputs.is_release"
env:
LOOP_IMPL: ${{ matrix.loop }}
run: |
if [ "${LOOP_IMPL}" = "uvloop" ]; then
env USE_UVLOOP=1 python -m unittest -v tests.suite
else
python -m unittest -v tests.suite
fi
test-postgres:
strategy:
matrix:
postgres-version: ["9.5", "9.6", "10", "11", "12", "13", "14", "15", "16", "17", "18"]
runs-on: ubuntu-latest
permissions: {}
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 50
submodules: true
persist-credentials: false
- name: Check if release PR.
uses: edgedb/action-release/validate-pr@master
id: release
with:
github_token: ${{ secrets.RELEASE_BOT_GITHUB_TOKEN }}
missing_version_ok: yes
version_file: asyncpg/_version.py
version_line_pattern: |
__version__(?:\s*:\s*typing\.Final)?\s*=\s*(?:['"])([[:PEP440:]])(?:['"])
- name: Set up PostgreSQL
if: "!steps.release.outputs.is_release"
env:
PGVERSION: ${{ matrix.postgres-version }}
DISTRO_NAME: focal
run: |
sudo env DISTRO_NAME="${DISTRO_NAME}" PGVERSION="${PGVERSION}" \
.github/workflows/install-postgres.sh
echo PGINSTALLATION="/usr/lib/postgresql/${PGVERSION}/bin" \
>> "${GITHUB_ENV}"
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
if: "!steps.release.outputs.is_release"
with:
python-version: "3.x"
- name: Install Python Deps
if: "!steps.release.outputs.is_release"
run: |
[ "$RUNNER_OS" = "Linux" ] && .github/workflows/install-krb5.sh
python -m pip install -U pip setuptools wheel
python -m pip install --group test
python -m pip install -e .
- name: Test
if: "!steps.release.outputs.is_release"
env:
PGVERSION: ${{ matrix.postgres-version }}
run: |
python -m unittest -v tests.suite
# This job exists solely to act as the test job aggregate to be
# targeted by branch policies.
regression-tests:
name: "Regression Tests"
needs: [test-platforms, test-postgres]
runs-on: ubuntu-latest
permissions: {}
steps:
- run: echo OK
================================================
FILE: .gitignore
================================================
*._*
*.pyc
*.pyo
*.ymlc
*.ymlc~
*.scssc
*.so
*.pyd
*~
.#*
.DS_Store
.project
.pydevproject
.settings
.idea
/.ropeproject
\#*#
/pub
/test*.py
/.local
/perf.data*
/config_local.yml
/build
__pycache__/
.d8_history
/*.egg
/*.egg-info
/dist
/.cache
docs/_build
*,cover
.coverage
/.pytest_cache/
/.eggs
/.vscode
/.zed
/.mypy_cache
/.venv*
/.tox
/compile_commands.json
================================================
FILE: .gitmodules
================================================
[submodule "asyncpg/pgproto"]
path = asyncpg/pgproto
url = https://github.com/MagicStack/py-pgproto.git
================================================
FILE: AUTHORS
================================================
Main contributors
=================
MagicStack Inc.:
Elvis Pranskevichus <elvis@magic.io>
Yury Selivanov <yury@magic.io>
================================================
FILE: LICENSE
================================================
Copyright (C) 2016-present the asyncpg authors and contributors.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (C) 2016-present the asyncpg authors and contributors
<see AUTHORS file>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: MANIFEST.in
================================================
recursive-include docs *.py *.rst Makefile *.css
recursive-include examples *.py
recursive-include tests *.py *.pem
recursive-include asyncpg *.pyx *.pxd *.pxi *.py *.pyi *.c *.h
include LICENSE README.rst Makefile performance.png .flake8
================================================
FILE: Makefile
================================================
.PHONY: compile debug test quicktest clean all
PYTHON ?= python
ROOT = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
all: compile
clean:
rm -fr dist/ doc/_build/
rm -fr asyncpg/pgproto/*.c asyncpg/pgproto/*.html
rm -fr asyncpg/pgproto/codecs/*.html
rm -fr asyncpg/pgproto/*.so
rm -fr asyncpg/protocol/*.c asyncpg/protocol/*.html
rm -fr asyncpg/protocol/*.so build *.egg-info
rm -fr asyncpg/protocol/codecs/*.html
find . -name '__pycache__' | xargs rm -rf
compile:
env ASYNCPG_BUILD_CYTHON_ALWAYS=1 $(PYTHON) -m pip install -e .
debug:
env ASYNCPG_DEBUG=1 $(PYTHON) -m pip install -e .
test:
PYTHONASYNCIODEBUG=1 $(PYTHON) -m unittest -v tests.suite
$(PYTHON) -m unittest -v tests.suite
USE_UVLOOP=1 $(PYTHON) -m unittest -v tests.suite
testinstalled:
cd "$${HOME}" && $(PYTHON) $(ROOT)/tests/__init__.py
quicktest:
$(PYTHON) -m unittest -v tests.suite
htmldocs:
$(PYTHON) -m pip install -e .[docs]
$(MAKE) -C docs html
================================================
FILE: README.rst
================================================
asyncpg -- A fast PostgreSQL Database Client Library for Python/asyncio
=======================================================================
.. image:: https://github.com/MagicStack/asyncpg/workflows/Tests/badge.svg
:target: https://github.com/MagicStack/asyncpg/actions?query=workflow%3ATests+branch%3Amaster
:alt: GitHub Actions status
.. image:: https://img.shields.io/pypi/v/asyncpg.svg
:target: https://pypi.python.org/pypi/asyncpg
**asyncpg** is a database interface library designed specifically for
PostgreSQL and Python/asyncio. asyncpg is an efficient, clean implementation
of PostgreSQL server binary protocol for use with Python's ``asyncio``
framework. You can read more about asyncpg in an introductory
`blog post <http://magic.io/blog/asyncpg-1m-rows-from-postgres-to-python/>`_.
asyncpg requires Python 3.9 or later and is supported for PostgreSQL
versions 9.5 to 18. Other PostgreSQL versions or other databases
implementing the PostgreSQL protocol *may* work, but are not being
actively tested.
Documentation
-------------
The project documentation can be found
`here <https://magicstack.github.io/asyncpg/current/>`_.
Performance
-----------
In our testing asyncpg is, on average, **5x** faster than psycopg3.
.. image:: https://raw.githubusercontent.com/MagicStack/asyncpg/master/performance.png?fddca40ab0
:target: https://gistpreview.github.io/?0ed296e93523831ea0918d42dd1258c2
The above results are a geometric mean of benchmarks obtained with PostgreSQL
`client driver benchmarking toolbench <https://github.com/MagicStack/pgbench>`_
in June 2023 (click on the chart to see full details).
Features
--------
asyncpg implements PostgreSQL server protocol natively and exposes its
features directly, as opposed to hiding them behind a generic facade
like DB-API.
This enables asyncpg to have easy-to-use support for:
* **prepared statements**
* **scrollable cursors**
* **partial iteration** on query results
* automatic encoding and decoding of composite types, arrays,
and any combination of those
* straightforward support for custom data types
Installation
------------
asyncpg is available on PyPI. When not using GSSAPI/SSPI authentication it
has no dependencies. Use pip to install::
$ pip install asyncpg
If you need GSSAPI/SSPI authentication, use::
$ pip install 'asyncpg[gssauth]'
For more details, please `see the documentation
<https://magicstack.github.io/asyncpg/current/installation.html>`_.
Basic Usage
-----------
.. code-block:: python
import asyncio
import asyncpg
async def run():
conn = await asyncpg.connect(user='user', password='password',
database='database', host='127.0.0.1')
values = await conn.fetch(
'SELECT * FROM mytable WHERE id = $1',
10,
)
await conn.close()
asyncio.run(run())
License
-------
asyncpg is developed and distributed under the Apache 2.0 license.
================================================
FILE: asyncpg/.gitignore
================================================
*.html
================================================
FILE: asyncpg/__init__.py
================================================
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
from __future__ import annotations
from .connection import connect, Connection # NOQA
from .exceptions import * # NOQA
from .pool import create_pool, Pool # NOQA
from .protocol import Record # NOQA
from .types import * # NOQA
from ._version import __version__ # NOQA
from . import exceptions
__all__: tuple[str, ...] = (
'connect', 'create_pool', 'Pool', 'Record', 'Connection'
)
__all__ += exceptions.__all__ # NOQA
================================================
FILE: asyncpg/_asyncio_compat.py
================================================
# Backports from Python/Lib/asyncio for older Pythons
#
# Copyright (c) 2001-2023 Python Software Foundation; All Rights Reserved
#
# SPDX-License-Identifier: PSF-2.0
from __future__ import annotations
import asyncio
import functools
import sys
import typing
if typing.TYPE_CHECKING:
from . import compat
if sys.version_info < (3, 11):
from async_timeout import timeout as timeout_ctx
else:
from asyncio import timeout as timeout_ctx
_T = typing.TypeVar('_T')
async def wait_for(fut: compat.Awaitable[_T], timeout: float | None) -> _T:
"""Wait for the single Future or coroutine to complete, with timeout.
Coroutine will be wrapped in Task.
Returns result of the Future or coroutine. When a timeout occurs,
it cancels the task and raises TimeoutError. To avoid the task
cancellation, wrap it in shield().
If the wait is cancelled, the task is also cancelled.
If the task supresses the cancellation and returns a value instead,
that value is returned.
This function is a coroutine.
"""
# The special case for timeout <= 0 is for the following case:
#
# async def test_waitfor():
# func_started = False
#
# async def func():
# nonlocal func_started
# func_started = True
#
# try:
# await asyncio.wait_for(func(), 0)
# except asyncio.TimeoutError:
# assert not func_started
# else:
# assert False
#
# asyncio.run(test_waitfor())
if timeout is not None and timeout <= 0:
fut = asyncio.ensure_future(fut)
if fut.done():
return fut.result()
await _cancel_and_wait(fut)
try:
return fut.result()
except asyncio.CancelledError as exc:
raise TimeoutError from exc
async with timeout_ctx(timeout):
return await fut
async def _cancel_and_wait(fut: asyncio.Future[_T]) -> None:
"""Cancel the *fut* future or task and wait until it completes."""
loop = asyncio.get_running_loop()
waiter = loop.create_future()
cb = functools.partial(_release_waiter, waiter)
fut.add_done_callback(cb)
try:
fut.cancel()
# We cannot wait on *fut* directly to make
# sure _cancel_and_wait itself is reliably cancellable.
await waiter
finally:
fut.remove_done_callback(cb)
def _release_waiter(waiter: asyncio.Future[typing.Any], *args: object) -> None:
if not waiter.done():
waiter.set_result(None)
================================================
FILE: asyncpg/_testbase/__init__.py
================================================
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
import asyncio
import atexit
import contextlib
import functools
import inspect
import logging
import os
import re
import textwrap
import time
import traceback
import unittest
import asyncpg
from asyncpg import cluster as pg_cluster
from asyncpg import connection as pg_connection
from asyncpg import pool as pg_pool
from . import fuzzer
@contextlib.contextmanager
def silence_asyncio_long_exec_warning():
def flt(log_record):
msg = log_record.getMessage()
return not msg.startswith('Executing ')
logger = logging.getLogger('asyncio')
logger.addFilter(flt)
try:
yield
finally:
logger.removeFilter(flt)
def with_timeout(timeout):
def wrap(func):
func.__timeout__ = timeout
return func
return wrap
class TestCaseMeta(type(unittest.TestCase)):
TEST_TIMEOUT = None
@staticmethod
def _iter_methods(bases, ns):
for base in bases:
for methname in dir(base):
if not methname.startswith('test_'):
continue
meth = getattr(base, methname)
if not inspect.iscoroutinefunction(meth):
continue
yield methname, meth
for methname, meth in ns.items():
if not methname.startswith('test_'):
continue
if not inspect.iscoroutinefunction(meth):
continue
yield methname, meth
def __new__(mcls, name, bases, ns):
for methname, meth in mcls._iter_methods(bases, ns):
@functools.wraps(meth)
def wrapper(self, *args, __meth__=meth, **kwargs):
coro = __meth__(self, *args, **kwargs)
timeout = getattr(__meth__, '__timeout__', mcls.TEST_TIMEOUT)
if timeout:
coro = asyncio.wait_for(coro, timeout)
try:
self.loop.run_until_complete(coro)
except asyncio.TimeoutError:
raise self.failureException(
'test timed out after {} seconds'.format(
timeout)) from None
else:
self.loop.run_until_complete(coro)
ns[methname] = wrapper
return super().__new__(mcls, name, bases, ns)
class TestCase(unittest.TestCase, metaclass=TestCaseMeta):
@classmethod
def setUpClass(cls):
if os.environ.get('USE_UVLOOP'):
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
loop = asyncio.new_event_loop()
asyncio.set_event_loop(None)
cls.loop = loop
@classmethod
def tearDownClass(cls):
cls.loop.close()
asyncio.set_event_loop(None)
def setUp(self):
self.loop.set_exception_handler(self.loop_exception_handler)
self.__unhandled_exceptions = []
def tearDown(self):
excs = []
for exc in self.__unhandled_exceptions:
if isinstance(exc, ConnectionResetError):
texc = traceback.TracebackException.from_exception(
exc, lookup_lines=False)
if texc.stack[-1].name == "_call_connection_lost":
# On Windows calling socket.shutdown may raise
# ConnectionResetError, which happens in the
# finally block of _call_connection_lost.
continue
excs.append(exc)
if excs:
formatted = []
for i, context in enumerate(excs):
formatted.append(self._format_loop_exception(context, i + 1))
self.fail(
'unexpected exceptions in asynchronous code:\n' +
'\n'.join(formatted))
@contextlib.contextmanager
def assertRunUnder(self, delta):
st = time.monotonic()
try:
yield
finally:
elapsed = time.monotonic() - st
if elapsed > delta:
raise AssertionError(
'running block took {:0.3f}s which is longer '
'than the expected maximum of {:0.3f}s'.format(
elapsed, delta))
@contextlib.contextmanager
def assertLoopErrorHandlerCalled(self, msg_re: str):
contexts = []
def handler(loop, ctx):
contexts.append(ctx)
old_handler = self.loop.get_exception_handler()
self.loop.set_exception_handler(handler)
try:
yield
for ctx in contexts:
msg = ctx.get('message')
if msg and re.search(msg_re, msg):
return
raise AssertionError(
'no message matching {!r} was logged with '
'loop.call_exception_handler()'.format(msg_re))
finally:
self.loop.set_exception_handler(old_handler)
def loop_exception_handler(self, loop, context):
self.__unhandled_exceptions.append(context)
loop.default_exception_handler(context)
def _format_loop_exception(self, context, n):
message = context.get('message', 'Unhandled exception in event loop')
exception = context.get('exception')
if exception is not None:
exc_info = (type(exception), exception, exception.__traceback__)
else:
exc_info = None
lines = []
for key in sorted(context):
if key in {'message', 'exception'}:
continue
value = context[key]
if key == 'source_traceback':
tb = ''.join(traceback.format_list(value))
value = 'Object created at (most recent call last):\n'
value += tb.rstrip()
else:
try:
value = repr(value)
except Exception as ex:
value = ('Exception in __repr__ {!r}; '
'value type: {!r}'.format(ex, type(value)))
lines.append('[{}]: {}\n\n'.format(key, value))
if exc_info is not None:
lines.append('[exception]:\n')
formatted_exc = textwrap.indent(
''.join(traceback.format_exception(*exc_info)), ' ')
lines.append(formatted_exc)
details = textwrap.indent(''.join(lines), ' ')
return '{:02d}. {}:\n{}\n'.format(n, message, details)
_default_cluster = None
def _init_cluster(ClusterCls, cluster_kwargs, initdb_options=None):
cluster = ClusterCls(**cluster_kwargs)
cluster.init(**(initdb_options or {}))
cluster.trust_local_connections()
atexit.register(_shutdown_cluster, cluster)
return cluster
def _get_initdb_options(initdb_options=None):
if not initdb_options:
initdb_options = {}
else:
initdb_options = dict(initdb_options)
# Make the default superuser name stable.
if 'username' not in initdb_options:
initdb_options['username'] = 'postgres'
return initdb_options
def _init_default_cluster(initdb_options=None):
global _default_cluster
if _default_cluster is None:
pg_host = os.environ.get('PGHOST')
if pg_host:
# Using existing cluster, assuming it is initialized and running
_default_cluster = pg_cluster.RunningCluster()
else:
_default_cluster = _init_cluster(
pg_cluster.TempCluster,
cluster_kwargs={
"data_dir_suffix": ".apgtest",
},
initdb_options=_get_initdb_options(initdb_options),
)
return _default_cluster
def _shutdown_cluster(cluster):
if cluster.get_status() == 'running':
cluster.stop()
if cluster.get_status() != 'not-initialized':
cluster.destroy()
def create_pool(dsn=None, *,
min_size=10,
max_size=10,
max_queries=50000,
max_inactive_connection_lifetime=60.0,
connect=None,
setup=None,
init=None,
loop=None,
pool_class=pg_pool.Pool,
connection_class=pg_connection.Connection,
record_class=asyncpg.Record,
**connect_kwargs):
return pool_class(
dsn,
min_size=min_size,
max_size=max_size,
max_queries=max_queries,
loop=loop,
connect=connect,
setup=setup,
init=init,
max_inactive_connection_lifetime=max_inactive_connection_lifetime,
connection_class=connection_class,
record_class=record_class,
**connect_kwargs,
)
class ClusterTestCase(TestCase):
@classmethod
def get_server_settings(cls):
settings = {
'log_connections': 'on'
}
if cls.cluster.get_pg_version() >= (11, 0):
# JITting messes up timing tests, and
# is not essential for testing.
settings['jit'] = 'off'
return settings
@classmethod
def new_cluster(cls, ClusterCls, *, cluster_kwargs={}, initdb_options={}):
cluster = _init_cluster(ClusterCls, cluster_kwargs,
_get_initdb_options(initdb_options))
cls._clusters.append(cluster)
return cluster
@classmethod
def start_cluster(cls, cluster, *, server_settings={}):
cluster.start(port='dynamic', server_settings=server_settings)
@classmethod
def setup_cluster(cls):
cls.cluster = _init_default_cluster()
if cls.cluster.get_status() != 'running':
cls.cluster.start(
port='dynamic', server_settings=cls.get_server_settings())
@classmethod
def setUpClass(cls):
super().setUpClass()
cls._clusters = []
cls.setup_cluster()
@classmethod
def tearDownClass(cls):
super().tearDownClass()
for cluster in cls._clusters:
if cluster is not _default_cluster:
cluster.stop()
cluster.destroy()
cls._clusters = []
@classmethod
def get_connection_spec(cls, kwargs={}):
conn_spec = cls.cluster.get_connection_spec()
if kwargs.get('dsn'):
conn_spec.pop('host')
conn_spec.update(kwargs)
if not os.environ.get('PGHOST') and not kwargs.get('dsn'):
if 'database' not in conn_spec:
conn_spec['database'] = 'postgres'
if 'user' not in conn_spec:
conn_spec['user'] = 'postgres'
return conn_spec
@classmethod
def connect(cls, **kwargs):
conn_spec = cls.get_connection_spec(kwargs)
return pg_connection.connect(**conn_spec, loop=cls.loop)
def setUp(self):
super().setUp()
self._pools = []
def tearDown(self):
super().tearDown()
for pool in self._pools:
pool.terminate()
self._pools = []
def create_pool(self, pool_class=pg_pool.Pool,
connection_class=pg_connection.Connection, **kwargs):
conn_spec = self.get_connection_spec(kwargs)
pool = create_pool(loop=self.loop, pool_class=pool_class,
connection_class=connection_class, **conn_spec)
self._pools.append(pool)
return pool
class ProxiedClusterTestCase(ClusterTestCase):
@classmethod
def get_server_settings(cls):
settings = dict(super().get_server_settings())
settings['listen_addresses'] = '127.0.0.1'
return settings
@classmethod
def get_proxy_settings(cls):
return {'fuzzing-mode': None}
@classmethod
def setUpClass(cls):
super().setUpClass()
conn_spec = cls.cluster.get_connection_spec()
host = conn_spec.get('host')
if not host:
host = '127.0.0.1'
elif host.startswith('/'):
host = '127.0.0.1'
cls.proxy = fuzzer.TCPFuzzingProxy(
backend_host=host,
backend_port=conn_spec['port'],
)
cls.proxy.start()
@classmethod
def tearDownClass(cls):
cls.proxy.stop()
super().tearDownClass()
@classmethod
def get_connection_spec(cls, kwargs):
conn_spec = super().get_connection_spec(kwargs)
conn_spec['host'] = cls.proxy.listening_addr
conn_spec['port'] = cls.proxy.listening_port
return conn_spec
def tearDown(self):
self.proxy.reset()
super().tearDown()
def with_connection_options(**options):
if not options:
raise ValueError('no connection options were specified')
def wrap(func):
func.__connect_options__ = options
return func
return wrap
class ConnectedTestCase(ClusterTestCase):
def setUp(self):
super().setUp()
# Extract options set up with `with_connection_options`.
test_func = getattr(self, self._testMethodName).__func__
opts = getattr(test_func, '__connect_options__', {})
self.con = self.loop.run_until_complete(self.connect(**opts))
self.server_version = self.con.get_server_version()
def tearDown(self):
try:
self.loop.run_until_complete(self.con.close())
self.con = None
finally:
super().tearDown()
class HotStandbyTestCase(ClusterTestCase):
@classmethod
def setup_cluster(cls):
cls.master_cluster = cls.new_cluster(pg_cluster.TempCluster)
cls.start_cluster(
cls.master_cluster,
server_settings={
'max_wal_senders': 10,
'wal_level': 'hot_standby'
}
)
con = None
try:
con = cls.loop.run_until_complete(
cls.master_cluster.connect(
database='postgres', user='postgres', loop=cls.loop))
cls.loop.run_until_complete(
con.execute('''
CREATE ROLE replication WITH LOGIN REPLICATION
'''))
cls.master_cluster.trust_local_replication_by('replication')
conn_spec = cls.master_cluster.get_connection_spec()
cls.standby_cluster = cls.new_cluster(
pg_cluster.HotStandbyCluster,
cluster_kwargs={
'master': conn_spec,
'replication_user': 'replication'
}
)
cls.start_cluster(
cls.standby_cluster,
server_settings={
'hot_standby': True
}
)
finally:
if con is not None:
cls.loop.run_until_complete(con.close())
@classmethod
def get_cluster_connection_spec(cls, cluster, kwargs={}):
conn_spec = cluster.get_connection_spec()
if kwargs.get('dsn'):
conn_spec.pop('host')
conn_spec.update(kwargs)
if not os.environ.get('PGHOST') and not kwargs.get('dsn'):
if 'database' not in conn_spec:
conn_spec['database'] = 'postgres'
if 'user' not in conn_spec:
conn_spec['user'] = 'postgres'
return conn_spec
@classmethod
def get_connection_spec(cls, kwargs={}):
primary_spec = cls.get_cluster_connection_spec(
cls.master_cluster, kwargs
)
standby_spec = cls.get_cluster_connection_spec(
cls.standby_cluster, kwargs
)
return {
'host': [primary_spec['host'], standby_spec['host']],
'port': [primary_spec['port'], standby_spec['port']],
'database': primary_spec['database'],
'user': primary_spec['user'],
**kwargs
}
@classmethod
def connect_primary(cls, **kwargs):
conn_spec = cls.get_cluster_connection_spec(cls.master_cluster, kwargs)
return pg_connection.connect(**conn_spec, loop=cls.loop)
@classmethod
def connect_standby(cls, **kwargs):
conn_spec = cls.get_cluster_connection_spec(
cls.standby_cluster,
kwargs
)
return pg_connection.connect(**conn_spec, loop=cls.loop)
================================================
FILE: asyncpg/_testbase/fuzzer.py
================================================
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
import asyncio
import socket
import threading
import typing
from asyncpg import cluster
class StopServer(Exception):
pass
class TCPFuzzingProxy:
def __init__(self, *, listening_addr: str='127.0.0.1',
listening_port: typing.Optional[int]=None,
backend_host: str, backend_port: int,
settings: typing.Optional[dict]=None) -> None:
self.listening_addr = listening_addr
self.listening_port = listening_port
self.backend_host = backend_host
self.backend_port = backend_port
self.settings = settings or {}
self.loop = None
self.connectivity = None
self.connectivity_loss = None
self.stop_event = None
self.connections = {}
self.sock = None
self.listen_task = None
async def _wait(self, work):
work_task = asyncio.ensure_future(work)
stop_event_task = asyncio.ensure_future(self.stop_event.wait())
try:
await asyncio.wait(
[work_task, stop_event_task],
return_when=asyncio.FIRST_COMPLETED)
if self.stop_event.is_set():
raise StopServer()
else:
return work_task.result()
finally:
if not work_task.done():
work_task.cancel()
if not stop_event_task.done():
stop_event_task.cancel()
def start(self):
started = threading.Event()
self.thread = threading.Thread(
target=self._start_thread, args=(started,))
self.thread.start()
if not started.wait(timeout=2):
raise RuntimeError('fuzzer proxy failed to start')
def stop(self):
self.loop.call_soon_threadsafe(self._stop)
self.thread.join()
def _stop(self):
self.stop_event.set()
def _start_thread(self, started_event):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
self.connectivity = asyncio.Event()
self.connectivity.set()
self.connectivity_loss = asyncio.Event()
self.stop_event = asyncio.Event()
if self.listening_port is None:
self.listening_port = cluster.find_available_port()
self.sock = socket.socket()
self.sock.bind((self.listening_addr, self.listening_port))
self.sock.listen(50)
self.sock.setblocking(False)
try:
self.loop.run_until_complete(self._main(started_event))
finally:
self.loop.close()
async def _main(self, started_event):
self.listen_task = asyncio.ensure_future(self.listen())
# Notify the main thread that we are ready to go.
started_event.set()
try:
await self.listen_task
finally:
for c in list(self.connections):
c.close()
await asyncio.sleep(0.01)
if hasattr(self.loop, 'remove_reader'):
self.loop.remove_reader(self.sock.fileno())
self.sock.close()
async def listen(self):
while True:
try:
client_sock, _ = await self._wait(
self.loop.sock_accept(self.sock))
backend_sock = socket.socket()
backend_sock.setblocking(False)
await self._wait(self.loop.sock_connect(
backend_sock, (self.backend_host, self.backend_port)))
except StopServer:
break
conn = Connection(client_sock, backend_sock, self)
conn_task = self.loop.create_task(conn.handle())
self.connections[conn] = conn_task
def trigger_connectivity_loss(self):
self.loop.call_soon_threadsafe(self._trigger_connectivity_loss)
def _trigger_connectivity_loss(self):
self.connectivity.clear()
self.connectivity_loss.set()
def restore_connectivity(self):
self.loop.call_soon_threadsafe(self._restore_connectivity)
def _restore_connectivity(self):
self.connectivity.set()
self.connectivity_loss.clear()
def reset(self):
self.restore_connectivity()
def _close_connection(self, connection):
conn_task = self.connections.pop(connection, None)
if conn_task is not None:
conn_task.cancel()
def close_all_connections(self):
for conn in list(self.connections):
self.loop.call_soon_threadsafe(self._close_connection, conn)
class Connection:
def __init__(self, client_sock, backend_sock, proxy):
self.client_sock = client_sock
self.backend_sock = backend_sock
self.proxy = proxy
self.loop = proxy.loop
self.connectivity = proxy.connectivity
self.connectivity_loss = proxy.connectivity_loss
self.proxy_to_backend_task = None
self.proxy_from_backend_task = None
self.is_closed = False
def close(self):
if self.is_closed:
return
self.is_closed = True
if self.proxy_to_backend_task is not None:
self.proxy_to_backend_task.cancel()
self.proxy_to_backend_task = None
if self.proxy_from_backend_task is not None:
self.proxy_from_backend_task.cancel()
self.proxy_from_backend_task = None
self.proxy._close_connection(self)
async def handle(self):
self.proxy_to_backend_task = asyncio.ensure_future(
self.proxy_to_backend())
self.proxy_from_backend_task = asyncio.ensure_future(
self.proxy_from_backend())
try:
await asyncio.wait(
[self.proxy_to_backend_task, self.proxy_from_backend_task],
return_when=asyncio.FIRST_COMPLETED)
finally:
if self.proxy_to_backend_task is not None:
self.proxy_to_backend_task.cancel()
if self.proxy_from_backend_task is not None:
self.proxy_from_backend_task.cancel()
# Asyncio fails to properly remove the readers and writers
# when the task doing recv() or send() is cancelled, so
# we must remove the readers and writers manually before
# closing the sockets.
self.loop.remove_reader(self.client_sock.fileno())
self.loop.remove_writer(self.client_sock.fileno())
self.loop.remove_reader(self.backend_sock.fileno())
self.loop.remove_writer(self.backend_sock.fileno())
self.client_sock.close()
self.backend_sock.close()
async def _read(self, sock, n):
read_task = asyncio.ensure_future(
self.loop.sock_recv(sock, n))
conn_event_task = asyncio.ensure_future(
self.connectivity_loss.wait())
try:
await asyncio.wait(
[read_task, conn_event_task],
return_when=asyncio.FIRST_COMPLETED)
if self.connectivity_loss.is_set():
return None
else:
return read_task.result()
finally:
if not self.loop.is_closed():
if not read_task.done():
read_task.cancel()
if not conn_event_task.done():
conn_event_task.cancel()
async def _write(self, sock, data):
write_task = asyncio.ensure_future(
self.loop.sock_sendall(sock, data))
conn_event_task = asyncio.ensure_future(
self.connectivity_loss.wait())
try:
await asyncio.wait(
[write_task, conn_event_task],
return_when=asyncio.FIRST_COMPLETED)
if self.connectivity_loss.is_set():
return None
else:
return write_task.result()
finally:
if not self.loop.is_closed():
if not write_task.done():
write_task.cancel()
if not conn_event_task.done():
conn_event_task.cancel()
async def proxy_to_backend(self):
buf = None
try:
while True:
await self.connectivity.wait()
if buf is not None:
data = buf
buf = None
else:
data = await self._read(self.client_sock, 4096)
if data == b'':
break
if self.connectivity_loss.is_set():
if data:
buf = data
continue
await self._write(self.backend_sock, data)
except ConnectionError:
pass
finally:
if not self.loop.is_closed():
self.loop.call_soon(self.close)
async def proxy_from_backend(self):
buf = None
try:
while True:
await self.connectivity.wait()
if buf is not None:
data = buf
buf = None
else:
data = await self._read(self.backend_sock, 4096)
if data == b'':
break
if self.connectivity_loss.is_set():
if data:
buf = data
continue
await self._write(self.client_sock, data)
except ConnectionError:
pass
finally:
if not self.loop.is_closed():
self.loop.call_soon(self.close)
================================================
FILE: asyncpg/_version.py
================================================
# This file MUST NOT contain anything but the __version__ assignment.
#
# When making a release, change the value of __version__
# to an appropriate value, and open a pull request against
# the correct branch (master if making a new feature release).
# The commit message MUST contain a properly formatted release
# log, and the commit must be signed.
#
# The release automation will: build and test the packages for the
# supported platforms, publish the packages on PyPI, merge the PR
# to the target branch, create a Git tag pointing to the commit.
from __future__ import annotations
import typing
__version__: typing.Final = '0.32.0.dev0'
================================================
FILE: asyncpg/cluster.py
================================================
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
import asyncio
import os
import os.path
import platform
import random
import re
import shutil
import socket
import string
import subprocess
import sys
import tempfile
import textwrap
import time
import asyncpg
from asyncpg import serverversion
_system = platform.uname().system
if _system == 'Windows':
def platform_exe(name):
if name.endswith('.exe'):
return name
return name + '.exe'
else:
def platform_exe(name):
return name
def find_available_port():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind(('127.0.0.1', 0))
return sock.getsockname()[1]
except Exception:
return None
finally:
sock.close()
def _world_readable_mkdtemp(suffix=None, prefix=None, dir=None):
name = "".join(random.choices(string.ascii_lowercase, k=8))
if dir is None:
dir = tempfile.gettempdir()
if prefix is None:
prefix = tempfile.gettempprefix()
if suffix is None:
suffix = ""
fn = os.path.join(dir, prefix + name + suffix)
os.mkdir(fn, 0o755)
return fn
def _mkdtemp(suffix=None, prefix=None, dir=None):
if _system == 'Windows' and os.environ.get("GITHUB_ACTIONS"):
# Due to mitigations introduced in python/cpython#118486
# when Python runs in a session created via an SSH connection
# tempfile.mkdtemp creates directories that are not accessible.
return _world_readable_mkdtemp(suffix, prefix, dir)
else:
return tempfile.mkdtemp(suffix, prefix, dir)
class ClusterError(Exception):
pass
class Cluster:
def __init__(self, data_dir, *, pg_config_path=None):
self._data_dir = data_dir
self._pg_config_path = pg_config_path
self._pg_bin_dir = (
os.environ.get('PGINSTALLATION')
or os.environ.get('PGBIN')
)
self._pg_ctl = None
self._daemon_pid = None
self._daemon_process = None
self._connection_addr = None
self._connection_spec_override = None
def get_pg_version(self):
return self._pg_version
def is_managed(self):
return True
def get_data_dir(self):
return self._data_dir
def get_status(self):
if self._pg_ctl is None:
self._init_env()
process = subprocess.run(
[self._pg_ctl, 'status', '-D', self._data_dir],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.stdout, process.stderr
if (process.returncode == 4 or not os.path.exists(self._data_dir) or
not os.listdir(self._data_dir)):
return 'not-initialized'
elif process.returncode == 3:
return 'stopped'
elif process.returncode == 0:
r = re.match(r'.*PID\s?:\s+(\d+).*', stdout.decode())
if not r:
raise ClusterError(
'could not parse pg_ctl status output: {}'.format(
stdout.decode()))
self._daemon_pid = int(r.group(1))
return self._test_connection(timeout=0)
else:
raise ClusterError(
'pg_ctl status exited with status {:d}: {}'.format(
process.returncode, stderr))
async def connect(self, loop=None, **kwargs):
conn_info = self.get_connection_spec()
conn_info.update(kwargs)
return await asyncpg.connect(loop=loop, **conn_info)
def init(self, **settings):
"""Initialize cluster."""
if self.get_status() != 'not-initialized':
raise ClusterError(
'cluster in {!r} has already been initialized'.format(
self._data_dir))
settings = dict(settings)
if 'encoding' not in settings:
settings['encoding'] = 'UTF-8'
if settings:
settings_args = ['--{}={}'.format(k, v)
for k, v in settings.items()]
extra_args = ['-o'] + [' '.join(settings_args)]
else:
extra_args = []
os.makedirs(self._data_dir, exist_ok=True)
process = subprocess.run(
[self._pg_ctl, 'init', '-D', self._data_dir] + extra_args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
cwd=self._data_dir,
)
output = process.stdout
if process.returncode != 0:
raise ClusterError(
'pg_ctl init exited with status {:d}:\n{}'.format(
process.returncode, output.decode()))
return output.decode()
def start(self, wait=60, *, server_settings={}, **opts):
"""Start the cluster."""
status = self.get_status()
if status == 'running':
return
elif status == 'not-initialized':
raise ClusterError(
'cluster in {!r} has not been initialized'.format(
self._data_dir))
port = opts.pop('port', None)
if port == 'dynamic':
port = find_available_port()
extra_args = ['--{}={}'.format(k, v) for k, v in opts.items()]
extra_args.append('--port={}'.format(port))
sockdir = server_settings.get('unix_socket_directories')
if sockdir is None:
sockdir = server_settings.get('unix_socket_directory')
if sockdir is None and _system != 'Windows':
sockdir = tempfile.gettempdir()
ssl_key = server_settings.get('ssl_key_file')
if ssl_key:
# Make sure server certificate key file has correct permissions.
keyfile = os.path.join(self._data_dir, 'srvkey.pem')
shutil.copy(ssl_key, keyfile)
os.chmod(keyfile, 0o600)
server_settings = server_settings.copy()
server_settings['ssl_key_file'] = keyfile
if sockdir is not None:
if self._pg_version < (9, 3):
sockdir_opt = 'unix_socket_directory'
else:
sockdir_opt = 'unix_socket_directories'
server_settings[sockdir_opt] = sockdir
for k, v in server_settings.items():
extra_args.extend(['-c', '{}={}'.format(k, v)])
if _system == 'Windows':
# On Windows we have to use pg_ctl as direct execution
# of postgres daemon under an Administrative account
# is not permitted and there is no easy way to drop
# privileges.
if os.getenv('ASYNCPG_DEBUG_SERVER'):
stdout = sys.stdout
print(
'asyncpg.cluster: Running',
' '.join([
self._pg_ctl, 'start', '-D', self._data_dir,
'-o', ' '.join(extra_args)
]),
file=sys.stderr,
)
else:
stdout = subprocess.DEVNULL
process = subprocess.run(
[self._pg_ctl, 'start', '-D', self._data_dir,
'-o', ' '.join(extra_args)],
stdout=stdout,
stderr=subprocess.STDOUT,
cwd=self._data_dir,
)
if process.returncode != 0:
if process.stderr:
stderr = ':\n{}'.format(process.stderr.decode())
else:
stderr = ''
raise ClusterError(
'pg_ctl start exited with status {:d}{}'.format(
process.returncode, stderr))
else:
if os.getenv('ASYNCPG_DEBUG_SERVER'):
stdout = sys.stdout
else:
stdout = subprocess.DEVNULL
self._daemon_process = \
subprocess.Popen(
[self._postgres, '-D', self._data_dir, *extra_args],
stdout=stdout,
stderr=subprocess.STDOUT,
cwd=self._data_dir,
)
self._daemon_pid = self._daemon_process.pid
self._test_connection(timeout=wait)
def reload(self):
"""Reload server configuration."""
status = self.get_status()
if status != 'running':
raise ClusterError('cannot reload: cluster is not running')
process = subprocess.run(
[self._pg_ctl, 'reload', '-D', self._data_dir],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=self._data_dir,
)
stderr = process.stderr
if process.returncode != 0:
raise ClusterError(
'pg_ctl stop exited with status {:d}: {}'.format(
process.returncode, stderr.decode()))
def stop(self, wait=60):
process = subprocess.run(
[self._pg_ctl, 'stop', '-D', self._data_dir, '-t', str(wait),
'-m', 'fast'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=self._data_dir,
)
stderr = process.stderr
if process.returncode != 0:
raise ClusterError(
'pg_ctl stop exited with status {:d}: {}'.format(
process.returncode, stderr.decode()))
if (self._daemon_process is not None and
self._daemon_process.returncode is None):
self._daemon_process.kill()
def destroy(self):
status = self.get_status()
if status == 'stopped' or status == 'not-initialized':
shutil.rmtree(self._data_dir)
else:
raise ClusterError('cannot destroy {} cluster'.format(status))
def _get_connection_spec(self):
if self._connection_addr is None:
self._connection_addr = self._connection_addr_from_pidfile()
if self._connection_addr is not None:
if self._connection_spec_override:
args = self._connection_addr.copy()
args.update(self._connection_spec_override)
return args
else:
return self._connection_addr
def get_connection_spec(self):
status = self.get_status()
if status != 'running':
raise ClusterError('cluster is not running')
return self._get_connection_spec()
def override_connection_spec(self, **kwargs):
self._connection_spec_override = kwargs
def reset_wal(self, *, oid=None, xid=None):
status = self.get_status()
if status == 'not-initialized':
raise ClusterError(
'cannot modify WAL status: cluster is not initialized')
if status == 'running':
raise ClusterError(
'cannot modify WAL status: cluster is running')
opts = []
if oid is not None:
opts.extend(['-o', str(oid)])
if xid is not None:
opts.extend(['-x', str(xid)])
if not opts:
return
opts.append(self._data_dir)
try:
reset_wal = self._find_pg_binary('pg_resetwal')
except ClusterError:
reset_wal = self._find_pg_binary('pg_resetxlog')
process = subprocess.run(
[reset_wal] + opts,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stderr = process.stderr
if process.returncode != 0:
raise ClusterError(
'pg_resetwal exited with status {:d}: {}'.format(
process.returncode, stderr.decode()))
def reset_hba(self):
"""Remove all records from pg_hba.conf."""
status = self.get_status()
if status == 'not-initialized':
raise ClusterError(
'cannot modify HBA records: cluster is not initialized')
pg_hba = os.path.join(self._data_dir, 'pg_hba.conf')
try:
with open(pg_hba, 'w'):
pass
except IOError as e:
raise ClusterError(
'cannot modify HBA records: {}'.format(e)) from e
def add_hba_entry(self, *, type='host', database, user, address=None,
auth_method, auth_options=None):
"""Add a record to pg_hba.conf."""
status = self.get_status()
if status == 'not-initialized':
raise ClusterError(
'cannot modify HBA records: cluster is not initialized')
if type not in {'local', 'host', 'hostssl', 'hostnossl'}:
raise ValueError('invalid HBA record type: {!r}'.format(type))
pg_hba = os.path.join(self._data_dir, 'pg_hba.conf')
record = '{} {} {}'.format(type, database, user)
if type != 'local':
if address is None:
raise ValueError(
'{!r} entry requires a valid address'.format(type))
else:
record += ' {}'.format(address)
record += ' {}'.format(auth_method)
if auth_options is not None:
record += ' ' + ' '.join(
'{}={}'.format(k, v) for k, v in auth_options)
try:
with open(pg_hba, 'a') as f:
print(record, file=f)
except IOError as e:
raise ClusterError(
'cannot modify HBA records: {}'.format(e)) from e
def trust_local_connections(self):
self.reset_hba()
if _system != 'Windows':
self.add_hba_entry(type='local', database='all',
user='all', auth_method='trust')
self.add_hba_entry(type='host', address='127.0.0.1/32',
database='all', user='all',
auth_method='trust')
self.add_hba_entry(type='host', address='::1/128',
database='all', user='all',
auth_method='trust')
status = self.get_status()
if status == 'running':
self.reload()
def trust_local_replication_by(self, user):
if _system != 'Windows':
self.add_hba_entry(type='local', database='replication',
user=user, auth_method='trust')
self.add_hba_entry(type='host', address='127.0.0.1/32',
database='replication', user=user,
auth_method='trust')
self.add_hba_entry(type='host', address='::1/128',
database='replication', user=user,
auth_method='trust')
status = self.get_status()
if status == 'running':
self.reload()
def _init_env(self):
if not self._pg_bin_dir:
pg_config = self._find_pg_config(self._pg_config_path)
pg_config_data = self._run_pg_config(pg_config)
self._pg_bin_dir = pg_config_data.get('bindir')
if not self._pg_bin_dir:
raise ClusterError(
'pg_config output did not provide the BINDIR value')
self._pg_ctl = self._find_pg_binary('pg_ctl')
self._postgres = self._find_pg_binary('postgres')
self._pg_version = self._get_pg_version()
def _connection_addr_from_pidfile(self):
pidfile = os.path.join(self._data_dir, 'postmaster.pid')
try:
with open(pidfile, 'rt') as f:
piddata = f.read()
except FileNotFoundError:
return None
lines = piddata.splitlines()
if len(lines) < 6:
# A complete postgres pidfile is at least 6 lines
return None
pmpid = int(lines[0])
if self._daemon_pid and pmpid != self._daemon_pid:
# This might be an old pidfile left from previous postgres
# daemon run.
return None
portnum = lines[3]
sockdir = lines[4]
hostaddr = lines[5]
if sockdir:
if sockdir[0] != '/':
# Relative sockdir
sockdir = os.path.normpath(
os.path.join(self._data_dir, sockdir))
host_str = sockdir
else:
host_str = hostaddr
if host_str == '*':
host_str = 'localhost'
elif host_str == '0.0.0.0':
host_str = '127.0.0.1'
elif host_str == '::':
host_str = '::1'
return {
'host': host_str,
'port': portnum
}
def _test_connection(self, timeout=60):
self._connection_addr = None
loop = asyncio.new_event_loop()
try:
for i in range(timeout):
if self._connection_addr is None:
conn_spec = self._get_connection_spec()
if conn_spec is None:
time.sleep(1)
continue
try:
con = loop.run_until_complete(
asyncpg.connect(database='postgres',
user='postgres',
timeout=5, loop=loop,
**self._connection_addr))
except (OSError, asyncio.TimeoutError,
asyncpg.CannotConnectNowError,
asyncpg.PostgresConnectionError):
time.sleep(1)
continue
except asyncpg.PostgresError:
# Any other error other than ServerNotReadyError or
# ConnectionError is interpreted to indicate the server is
# up.
break
else:
loop.run_until_complete(con.close())
break
finally:
loop.close()
return 'running'
def _run_pg_config(self, pg_config_path):
process = subprocess.run(
pg_config_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.stdout, process.stderr
if process.returncode != 0:
raise ClusterError('pg_config exited with status {:d}: {}'.format(
process.returncode, stderr))
else:
config = {}
for line in stdout.splitlines():
k, eq, v = line.decode('utf-8').partition('=')
if eq:
config[k.strip().lower()] = v.strip()
return config
def _find_pg_config(self, pg_config_path):
if pg_config_path is None:
pg_install = (
os.environ.get('PGINSTALLATION')
or os.environ.get('PGBIN')
)
if pg_install:
pg_config_path = platform_exe(
os.path.join(pg_install, 'pg_config'))
else:
pathenv = os.environ.get('PATH').split(os.pathsep)
for path in pathenv:
pg_config_path = platform_exe(
os.path.join(path, 'pg_config'))
if os.path.exists(pg_config_path):
break
else:
pg_config_path = None
if not pg_config_path:
raise ClusterError('could not find pg_config executable')
if not os.path.isfile(pg_config_path):
raise ClusterError('{!r} is not an executable'.format(
pg_config_path))
return pg_config_path
def _find_pg_binary(self, binary):
bpath = platform_exe(os.path.join(self._pg_bin_dir, binary))
if not os.path.isfile(bpath):
raise ClusterError(
'could not find {} executable: '.format(binary) +
'{!r} does not exist or is not a file'.format(bpath))
return bpath
def _get_pg_version(self):
process = subprocess.run(
[self._postgres, '--version'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.stdout, process.stderr
if process.returncode != 0:
raise ClusterError(
'postgres --version exited with status {:d}: {}'.format(
process.returncode, stderr))
version_string = stdout.decode('utf-8').strip(' \n')
prefix = 'postgres (PostgreSQL) '
if not version_string.startswith(prefix):
raise ClusterError(
'could not determine server version from {!r}'.format(
version_string))
version_string = version_string[len(prefix):]
return serverversion.split_server_version_string(version_string)
class TempCluster(Cluster):
def __init__(self, *,
data_dir_suffix=None, data_dir_prefix=None,
data_dir_parent=None, pg_config_path=None):
self._data_dir = _mkdtemp(suffix=data_dir_suffix,
prefix=data_dir_prefix,
dir=data_dir_parent)
super().__init__(self._data_dir, pg_config_path=pg_config_path)
class HotStandbyCluster(TempCluster):
def __init__(self, *,
master, replication_user,
data_dir_suffix=None, data_dir_prefix=None,
data_dir_parent=None, pg_config_path=None):
self._master = master
self._repl_user = replication_user
super().__init__(
data_dir_suffix=data_dir_suffix,
data_dir_prefix=data_dir_prefix,
data_dir_parent=data_dir_parent,
pg_config_path=pg_config_path)
def _init_env(self):
super()._init_env()
self._pg_basebackup = self._find_pg_binary('pg_basebackup')
def init(self, **settings):
"""Initialize cluster."""
if self.get_status() != 'not-initialized':
raise ClusterError(
'cluster in {!r} has already been initialized'.format(
self._data_dir))
process = subprocess.run(
[self._pg_basebackup, '-h', self._master['host'],
'-p', self._master['port'], '-D', self._data_dir,
'-U', self._repl_user],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = process.stdout
if process.returncode != 0:
raise ClusterError(
'pg_basebackup init exited with status {:d}:\n{}'.format(
process.returncode, output.decode()))
if self._pg_version < (12, 0):
with open(os.path.join(self._data_dir, 'recovery.conf'), 'w') as f:
f.write(textwrap.dedent("""\
standby_mode = 'on'
primary_conninfo = 'host={host} port={port} user={user}'
""".format(
host=self._master['host'],
port=self._master['port'],
user=self._repl_user)))
else:
f = open(os.path.join(self._data_dir, 'standby.signal'), 'w')
f.close()
return output.decode()
def start(self, wait=60, *, server_settings={}, **opts):
if self._pg_version >= (12, 0):
server_settings = server_settings.copy()
server_settings['primary_conninfo'] = (
'"host={host} port={port} user={user}"'.format(
host=self._master['host'],
port=self._master['port'],
user=self._repl_user,
)
)
super().start(wait=wait, server_settings=server_settings, **opts)
class RunningCluster(Cluster):
def __init__(self, **kwargs):
self.conn_spec = kwargs
def is_managed(self):
return False
def get_connection_spec(self):
return dict(self.conn_spec)
def get_status(self):
return 'running'
def init(self, **settings):
pass
def start(self, wait=60, **settings):
pass
def stop(self, wait=60):
pass
def destroy(self):
pass
def reset_hba(self):
raise ClusterError('cannot modify HBA records of unmanaged cluster')
def add_hba_entry(self, *, type='host', database, user, address=None,
auth_method, auth_options=None):
raise ClusterError('cannot modify HBA records of unmanaged cluster')
================================================
FILE: asyncpg/compat.py
================================================
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
from __future__ import annotations
import enum
import pathlib
import platform
import typing
import sys
if typing.TYPE_CHECKING:
import asyncio
SYSTEM: typing.Final = platform.uname().system
if sys.platform == 'win32':
import ctypes.wintypes
CSIDL_APPDATA: typing.Final = 0x001a
def get_pg_home_directory() -> pathlib.Path | None:
# We cannot simply use expanduser() as that returns the user's
# home directory, whereas Postgres stores its config in
# %AppData% on Windows.
buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
r = ctypes.windll.shell32.SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, buf)
if r:
return None
else:
return pathlib.Path(buf.value) / 'postgresql'
else:
def get_pg_home_directory() -> pathlib.Path | None:
try:
return pathlib.Path.home()
except (RuntimeError, KeyError):
return None
async def wait_closed(stream: asyncio.StreamWriter) -> None:
# Not all asyncio versions have StreamWriter.wait_closed().
if hasattr(stream, 'wait_closed'):
try:
await stream.wait_closed()
except ConnectionResetError:
# On Windows wait_closed() sometimes propagates
# ConnectionResetError which is totally unnecessary.
pass
if sys.version_info < (3, 12):
def markcoroutinefunction(c): # type: ignore
pass
else:
from inspect import markcoroutinefunction # noqa: F401
if sys.version_info < (3, 12):
from ._asyncio_compat import wait_for as wait_for # noqa: F401
else:
from asyncio import wait_for as wait_for # noqa: F401
if sys.version_info < (3, 11):
from ._asyncio_compat import timeout_ctx as timeout # noqa: F401
else:
from asyncio import timeout as timeout # noqa: F401
if sys.version_info < (3, 9):
from typing import ( # noqa: F401
Awaitable as Awaitable,
)
else:
from collections.abc import ( # noqa: F401
Awaitable as Awaitable,
)
if sys.version_info < (3, 11):
class StrEnum(str, enum.Enum):
__str__ = str.__str__
__repr__ = enum.Enum.__repr__
else:
from enum import StrEnum as StrEnum # noqa: F401
================================================
FILE: asyncpg/connect_utils.py
================================================
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
from __future__ import annotations
import asyncio
import configparser
import collections
from collections.abc import Callable
import enum
import functools
import getpass
import os
import pathlib
import platform
import random
import re
import socket
import ssl as ssl_module
import stat
import struct
import sys
import typing
import urllib.parse
import warnings
import inspect
from . import compat
from . import exceptions
from . import protocol
class SSLMode(enum.IntEnum):
disable = 0
allow = 1
prefer = 2
require = 3
verify_ca = 4
verify_full = 5
@classmethod
def parse(cls, sslmode):
if isinstance(sslmode, cls):
return sslmode
return getattr(cls, sslmode.replace('-', '_'))
class SSLNegotiation(compat.StrEnum):
postgres = "postgres"
direct = "direct"
_ConnectionParameters = collections.namedtuple(
'ConnectionParameters',
[
'user',
'password',
'database',
'ssl',
'sslmode',
'ssl_negotiation',
'server_settings',
'target_session_attrs',
'krbsrvname',
'gsslib',
])
_ClientConfiguration = collections.namedtuple(
'ConnectionConfiguration',
[
'command_timeout',
'statement_cache_size',
'max_cached_statement_lifetime',
'max_cacheable_statement_size',
])
_system = platform.uname().system
if _system == 'Windows':
PGPASSFILE = 'pgpass.conf'
else:
PGPASSFILE = '.pgpass'
PG_SERVICEFILE = '.pg_service.conf'
def _read_password_file(passfile: pathlib.Path) \
-> typing.List[typing.Tuple[str, ...]]:
passtab = []
try:
if not passfile.exists():
return []
if not passfile.is_file():
warnings.warn(
'password file {!r} is not a plain file'.format(passfile))
return []
if _system != 'Windows':
if passfile.stat().st_mode & (stat.S_IRWXG | stat.S_IRWXO):
warnings.warn(
'password file {!r} has group or world access; '
'permissions should be u=rw (0600) or less'.format(
passfile))
return []
with passfile.open('rt') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
# Skip empty lines and comments.
continue
# Backslash escapes both itself and the colon,
# which is a record separator.
line = line.replace(R'\\', '\n')
passtab.append(tuple(
p.replace('\n', R'\\')
for p in re.split(r'(?<!\\):', line, maxsplit=4)
))
except IOError:
pass
return passtab
def _read_password_from_pgpass(
*, passfile: typing.Optional[pathlib.Path],
hosts: typing.List[str],
ports: typing.List[int],
database: str,
user: str):
"""Parse the pgpass file and return the matching password.
:return:
Password string, if found, ``None`` otherwise.
"""
passtab = _read_password_file(passfile)
if not passtab:
return None
for host, port in zip(hosts, ports):
if host.startswith('/'):
# Unix sockets get normalized into 'localhost'
host = 'localhost'
for phost, pport, pdatabase, puser, ppassword in passtab:
if phost != '*' and phost != host:
continue
if pport != '*' and pport != str(port):
continue
if pdatabase != '*' and pdatabase != database:
continue
if puser != '*' and puser != user:
continue
# Found a match.
return ppassword
return None
def _validate_port_spec(hosts, port):
if isinstance(port, list) and len(port) > 1:
# If there is a list of ports, its length must
# match that of the host list.
if len(port) != len(hosts):
raise exceptions.ClientConfigurationError(
'could not match {} port numbers to {} hosts'.format(
len(port), len(hosts)))
elif isinstance(port, list) and len(port) == 1:
port = [port[0] for _ in range(len(hosts))]
else:
port = [port for _ in range(len(hosts))]
return port
def _parse_hostlist(hostlist, port, *, unquote=False):
if ',' in hostlist:
# A comma-separated list of host addresses.
hostspecs = hostlist.split(',')
else:
hostspecs = [hostlist]
hosts = []
hostlist_ports = []
if not port:
portspec = os.environ.get('PGPORT')
if portspec:
if ',' in portspec:
default_port = [int(p) for p in portspec.split(',')]
else:
default_port = int(portspec)
else:
default_port = 5432
default_port = _validate_port_spec(hostspecs, default_port)
else:
port = _validate_port_spec(hostspecs, port)
for i, hostspec in enumerate(hostspecs):
if hostspec[0] == '/':
# Unix socket
addr = hostspec
hostspec_port = ''
elif hostspec[0] == '[':
# IPv6 address
m = re.match(r'(?:\[([^\]]+)\])(?::([0-9]+))?', hostspec)
if m:
addr = m.group(1)
hostspec_port = m.group(2)
else:
raise exceptions.ClientConfigurationError(
'invalid IPv6 address in the connection URI: {!r}'.format(
hostspec
)
)
else:
# IPv4 address
addr, _, hostspec_port = hostspec.partition(':')
if unquote:
addr = urllib.parse.unquote(addr)
hosts.append(addr)
if not port:
if hostspec_port:
if unquote:
hostspec_port = urllib.parse.unquote(hostspec_port)
hostlist_ports.append(int(hostspec_port))
else:
hostlist_ports.append(default_port[i])
if not port:
port = hostlist_ports
return hosts, port
def _parse_tls_version(tls_version):
if tls_version.startswith('SSL'):
raise exceptions.ClientConfigurationError(
f"Unsupported TLS version: {tls_version}"
)
try:
return ssl_module.TLSVersion[tls_version.replace('.', '_')]
except KeyError:
raise exceptions.ClientConfigurationError(
f"No such TLS version: {tls_version}"
)
def _dot_postgresql_path(filename) -> typing.Optional[pathlib.Path]:
try:
homedir = pathlib.Path.home()
except (RuntimeError, KeyError):
return None
return (homedir / '.postgresql' / filename).resolve()
def _parse_connect_dsn_and_args(*, dsn, host, port, user,
password, passfile, database, ssl,
service, servicefile,
direct_tls, server_settings,
target_session_attrs, krbsrvname, gsslib):
# `auth_hosts` is the version of host information for the purposes
# of reading the pgpass file.
auth_hosts = None
sslcert = sslkey = sslrootcert = sslcrl = sslpassword = None
ssl_min_protocol_version = ssl_max_protocol_version = None
sslnegotiation = None
if dsn:
parsed = urllib.parse.urlparse(dsn)
query = None
if parsed.query:
query = urllib.parse.parse_qs(parsed.query, strict_parsing=True)
for key, val in query.items():
if isinstance(val, list):
query[key] = val[-1]
if 'service' in query:
val = query.pop('service')
if not service and val:
service = val
connection_service_file = servicefile
if connection_service_file is None:
connection_service_file = os.getenv('PGSERVICEFILE')
if connection_service_file is None:
homedir = compat.get_pg_home_directory()
if homedir:
connection_service_file = homedir / PG_SERVICEFILE
else:
connection_service_file = None
else:
connection_service_file = pathlib.Path(connection_service_file)
if parsed.scheme not in {'postgresql', 'postgres'}:
raise exceptions.ClientConfigurationError(
'invalid DSN: scheme is expected to be either '
'"postgresql" or "postgres", got {!r}'.format(parsed.scheme))
if parsed.netloc:
if '@' in parsed.netloc:
dsn_auth, _, dsn_hostspec = parsed.netloc.partition('@')
else:
dsn_hostspec = parsed.netloc
dsn_auth = ''
else:
dsn_auth = dsn_hostspec = ''
if dsn_auth:
dsn_user, _, dsn_password = dsn_auth.partition(':')
else:
dsn_user = dsn_password = ''
if not host and dsn_hostspec:
host, port = _parse_hostlist(dsn_hostspec, port, unquote=True)
if parsed.path and database is None:
dsn_database = parsed.path
if dsn_database.startswith('/'):
dsn_database = dsn_database[1:]
database = urllib.parse.unquote(dsn_database)
if user is None and dsn_user:
user = urllib.parse.unquote(dsn_user)
if password is None and dsn_password:
password = urllib.parse.unquote(dsn_password)
if query:
if 'port' in query:
val = query.pop('port')
if not port and val:
port = [int(p) for p in val.split(',')]
if 'host' in query:
val = query.pop('host')
if not host and val:
host, port = _parse_hostlist(val, port)
if 'dbname' in query:
val = query.pop('dbname')
if database is None:
database = val
if 'database' in query:
val = query.pop('database')
if database is None:
database = val
if 'user' in query:
val = query.pop('user')
if user is None:
user = val
if 'password' in query:
val = query.pop('password')
if password is None:
password = val
if 'passfile' in query:
val = query.pop('passfile')
if passfile is None:
passfile = val
if 'sslmode' in query:
val = query.pop('sslmode')
if ssl is None:
ssl = val
if 'sslcert' in query:
sslcert = query.pop('sslcert')
if 'sslkey' in query:
sslkey = query.pop('sslkey')
if 'sslrootcert' in query:
sslrootcert = query.pop('sslrootcert')
if 'sslnegotiation' in query:
sslnegotiation = query.pop('sslnegotiation')
if 'sslcrl' in query:
sslcrl = query.pop('sslcrl')
if 'sslpassword' in query:
sslpassword = query.pop('sslpassword')
if 'ssl_min_protocol_version' in query:
ssl_min_protocol_version = query.pop(
'ssl_min_protocol_version'
)
if 'ssl_max_protocol_version' in query:
ssl_max_protocol_version = query.pop(
'ssl_max_protocol_version'
)
if 'target_session_attrs' in query:
dsn_target_session_attrs = query.pop(
'target_session_attrs'
)
if target_session_attrs is None:
target_session_attrs = dsn_target_session_attrs
if 'krbsrvname' in query:
val = query.pop('krbsrvname')
if krbsrvname is None:
krbsrvname = val
if 'gsslib' in query:
val = query.pop('gsslib')
if gsslib is None:
gsslib = val
if 'service' in query:
val = query.pop('service')
if service is None:
service = val
if query:
if server_settings is None:
server_settings = query
else:
server_settings = {**query, **server_settings}
if connection_service_file is not None and service is not None:
pg_service = configparser.ConfigParser()
pg_service.read(connection_service_file)
if service in pg_service.sections():
service_params = pg_service[service]
if 'port' in service_params:
val = service_params.pop('port')
if not port and val:
port = [int(p) for p in val.split(',')]
if 'host' in service_params:
val = service_params.pop('host')
if not host and val:
host, port = _parse_hostlist(val, port)
if 'dbname' in service_params:
val = service_params.pop('dbname')
if database is None:
database = val
if 'database' in service_params:
val = service_params.pop('database')
if database is None:
database = val
if 'user' in service_params:
val = service_params.pop('user')
if user is None:
user = val
if 'password' in service_params:
val = service_params.pop('password')
if password is None:
password = val
if 'passfile' in service_params:
val = service_params.pop('passfile')
if passfile is None:
passfile = val
if 'sslmode' in service_params:
val = service_params.pop('sslmode')
if ssl is None:
ssl = val
if 'sslcert' in service_params:
val = service_params.pop('sslcert')
if sslcert is None:
sslcert = val
if 'sslkey' in service_params:
val = service_params.pop('sslkey')
if sslkey is None:
sslkey = val
if 'sslrootcert' in service_params:
val = service_params.pop('sslrootcert')
if sslrootcert is None:
sslrootcert = val
if 'sslnegotiation' in service_params:
val = service_params.pop('sslnegotiation')
if sslnegotiation is None:
sslnegotiation = val
if 'sslcrl' in service_params:
val = service_params.pop('sslcrl')
if sslcrl is None:
sslcrl = val
if 'sslpassword' in service_params:
val = service_params.pop('sslpassword')
if sslpassword is None:
sslpassword = val
if 'ssl_min_protocol_version' in service_params:
val = service_params.pop(
'ssl_min_protocol_version'
)
if ssl_min_protocol_version is None:
ssl_min_protocol_version = val
if 'ssl_max_protocol_version' in service_params:
val = service_params.pop(
'ssl_max_protocol_version'
)
if ssl_max_protocol_version is None:
ssl_max_protocol_version = val
if 'target_session_attrs' in service_params:
dsn_target_session_attrs = service_params.pop(
'target_session_attrs'
)
if target_session_attrs is None:
target_session_attrs = dsn_target_session_attrs
if 'krbsrvname' in service_params:
val = service_params.pop('krbsrvname')
if krbsrvname is None:
krbsrvname = val
if 'gsslib' in service_params:
val = service_params.pop('gsslib')
if gsslib is None:
gsslib = val
if not service:
service = os.environ.get('PGSERVICE')
if not host:
hostspec = os.environ.get('PGHOST')
if hostspec:
host, port = _parse_hostlist(hostspec, port)
if not host:
auth_hosts = ['localhost']
if _system == 'Windows':
host = ['localhost']
else:
host = ['/run/postgresql', '/var/run/postgresql',
'/tmp', '/private/tmp', 'localhost']
if not isinstance(host, (list, tuple)):
host = [host]
if auth_hosts is None:
auth_hosts = host
if not port:
portspec = os.environ.get('PGPORT')
if portspec:
if ',' in portspec:
port = [int(p) for p in portspec.split(',')]
else:
port = int(portspec)
else:
port = 5432
elif isinstance(port, (list, tuple)):
port = [int(p) for p in port]
else:
port = int(port)
port = _validate_port_spec(host, port)
if user is None:
user = os.getenv('PGUSER')
if not user:
user = getpass.getuser()
if password is None:
password = os.getenv('PGPASSWORD')
if database is None:
database = os.getenv('PGDATABASE')
if database is None:
database = user
if user is None:
raise exceptions.ClientConfigurationError(
'could not determine user name to connect with')
if database is None:
raise exceptions.ClientConfigurationError(
'could not determine database name to connect to')
if password is None:
if passfile is None:
passfile = os.getenv('PGPASSFILE')
if passfile is None:
homedir = compat.get_pg_home_directory()
if homedir:
passfile = homedir / PGPASSFILE
else:
passfile = None
else:
passfile = pathlib.Path(passfile)
if passfile is not None:
password = _read_password_from_pgpass(
hosts=auth_hosts, ports=port,
database=database, user=user,
passfile=passfile)
addrs = []
have_tcp_addrs = False
for h, p in zip(host, port):
if h.startswith('/'):
# UNIX socket name
if '.s.PGSQL.' not in h:
h = os.path.join(h, '.s.PGSQL.{}'.format(p))
addrs.append(h)
else:
# TCP host/port
addrs.append((h, p))
have_tcp_addrs = True
if not addrs:
raise exceptions.InternalClientError(
'could not determine the database address to connect to')
if ssl is None:
ssl = os.getenv('PGSSLMODE')
if ssl is None and have_tcp_addrs:
ssl = 'prefer'
if direct_tls is not None:
sslneg = (
SSLNegotiation.direct if direct_tls else SSLNegotiation.postgres
)
else:
if sslnegotiation is None:
sslnegotiation = os.environ.get("PGSSLNEGOTIATION")
if sslnegotiation is not None:
try:
sslneg = SSLNegotiation(sslnegotiation)
except ValueError:
modes = ', '.join(
m.name.replace('_', '-')
for m in SSLNegotiation
)
raise exceptions.ClientConfigurationError(
f'`sslnegotiation` parameter must be one of: {modes}'
) from None
else:
sslneg = SSLNegotiation.postgres
if isinstance(ssl, (str, SSLMode)):
try:
sslmode = SSLMode.parse(ssl)
except AttributeError:
modes = ', '.join(m.name.replace('_', '-') for m in SSLMode)
raise exceptions.ClientConfigurationError(
'`sslmode` parameter must be one of: {}'.format(modes)
) from None
# docs at https://www.postgresql.org/docs/10/static/libpq-connect.html
if sslmode < SSLMode.allow:
ssl = False
else:
ssl = ssl_module.SSLContext(ssl_module.PROTOCOL_TLS_CLIENT)
ssl.check_hostname = sslmode >= SSLMode.verify_full
if sslmode < SSLMode.require:
ssl.verify_mode = ssl_module.CERT_NONE
else:
if sslrootcert is None:
sslrootcert = os.getenv('PGSSLROOTCERT')
if sslrootcert:
ssl.load_verify_locations(cafile=sslrootcert)
ssl.verify_mode = ssl_module.CERT_REQUIRED
else:
try:
sslrootcert = _dot_postgresql_path('root.crt')
if sslrootcert is not None:
ssl.load_verify_locations(cafile=sslrootcert)
else:
raise exceptions.ClientConfigurationError(
'cannot determine location of user '
'PostgreSQL configuration directory'
)
except (
exceptions.ClientConfigurationError,
FileNotFoundError,
NotADirectoryError,
):
if sslmode > SSLMode.require:
if sslrootcert is None:
sslrootcert = '~/.postgresql/root.crt'
detail = (
'Could not determine location of user '
'home directory (HOME is either unset, '
'inaccessible, or does not point to a '
'valid directory)'
)
else:
detail = None
raise exceptions.ClientConfigurationError(
f'root certificate file "{sslrootcert}" does '
f'not exist or cannot be accessed',
hint='Provide the certificate file directly '
f'or make sure "{sslrootcert}" '
'exists and is readable.',
detail=detail,
)
elif sslmode == SSLMode.require:
ssl.verify_mode = ssl_module.CERT_NONE
else:
assert False, 'unreachable'
else:
ssl.verify_mode = ssl_module.CERT_REQUIRED
if sslcrl is None:
sslcrl = os.getenv('PGSSLCRL')
if sslcrl:
ssl.load_verify_locations(cafile=sslcrl)
ssl.verify_flags |= ssl_module.VERIFY_CRL_CHECK_CHAIN
else:
sslcrl = _dot_postgresql_path('root.crl')
if sslcrl is not None:
try:
ssl.load_verify_locations(cafile=sslcrl)
except (
FileNotFoundError,
NotADirectoryError,
):
pass
else:
ssl.verify_flags |= \
ssl_module.VERIFY_CRL_CHECK_CHAIN
if sslkey is None:
sslkey = os.getenv('PGSSLKEY')
if not sslkey:
sslkey = _dot_postgresql_path('postgresql.key')
if sslkey is not None and not sslkey.exists():
sslkey = None
if not sslpassword:
sslpassword = ''
if sslcert is None:
sslcert = os.getenv('PGSSLCERT')
if sslcert:
ssl.load_cert_chain(
sslcert, keyfile=sslkey, password=lambda: sslpassword
)
else:
sslcert = _dot_postgresql_path('postgresql.crt')
if sslcert is not None:
try:
ssl.load_cert_chain(
sslcert,
keyfile=sslkey,
password=lambda: sslpassword
)
except (FileNotFoundError, NotADirectoryError):
pass
# OpenSSL 1.1.1 keylog file, copied from create_default_context()
if hasattr(ssl, 'keylog_filename'):
keylogfile = os.environ.get('SSLKEYLOGFILE')
if keylogfile and not sys.flags.ignore_environment:
ssl.keylog_filename = keylogfile
if ssl_min_protocol_version is None:
ssl_min_protocol_version = os.getenv('PGSSLMINPROTOCOLVERSION')
if ssl_min_protocol_version:
ssl.minimum_version = _parse_tls_version(
ssl_min_protocol_version
)
else:
ssl.minimum_version = _parse_tls_version('TLSv1.2')
if ssl_max_protocol_version is None:
ssl_max_protocol_version = os.getenv('PGSSLMAXPROTOCOLVERSION')
if ssl_max_protocol_version:
ssl.maximum_version = _parse_tls_version(
ssl_max_protocol_version
)
elif ssl is True:
ssl = ssl_module.create_default_context()
sslmode = SSLMode.verify_full
else:
sslmode = SSLMode.disable
if server_settings is not None and (
not isinstance(server_settings, dict) or
not all(isinstance(k, str) for k in server_settings) or
not all(isinstance(v, str) for v in server_settings.values())):
raise exceptions.ClientConfigurationError(
'server_settings is expected to be None or '
'a Dict[str, str]')
if target_session_attrs is None:
target_session_attrs = os.getenv(
"PGTARGETSESSIONATTRS", SessionAttribute.any
)
try:
target_session_attrs = SessionAttribute(target_session_attrs)
except ValueError:
raise exceptions.ClientConfigurationError(
"target_session_attrs is expected to be one of "
"{!r}"
", got {!r}".format(
SessionAttribute.__members__.values, target_session_attrs
)
) from None
if krbsrvname is None:
krbsrvname = os.getenv('PGKRBSRVNAME')
if gsslib is None:
gsslib = os.getenv('PGGSSLIB')
if gsslib is None:
gsslib = 'sspi' if _system == 'Windows' else 'gssapi'
if gsslib not in {'gssapi', 'sspi'}:
raise exceptions.ClientConfigurationError(
"gsslib parameter must be either 'gssapi' or 'sspi'"
", got {!r}".format(gsslib))
params = _ConnectionParameters(
user=user, password=password, database=database, ssl=ssl,
sslmode=sslmode, ssl_negotiation=sslneg,
server_settings=server_settings,
target_session_attrs=target_session_attrs,
krbsrvname=krbsrvname, gsslib=gsslib)
return addrs, params
def _parse_connect_arguments(*, dsn, host, port, user, password, passfile,
database, command_timeout,
statement_cache_size,
max_cached_statement_lifetime,
max_cacheable_statement_size,
ssl, direct_tls, server_settings,
target_session_attrs, krbsrvname, gsslib,
service, servicefile):
local_vars = locals()
for var_name in {'max_cacheable_statement_size',
'max_cached_statement_lifetime',
'statement_cache_size'}:
var_val = local_vars[var_name]
if var_val is None or isinstance(var_val, bool) or var_val < 0:
raise ValueError(
'{} is expected to be greater '
'or equal to 0, got {!r}'.format(var_name, var_val))
if command_timeout is not None:
try:
if isinstance(command_timeout, bool):
raise ValueError
command_timeout = float(command_timeout)
if command_timeout <= 0:
raise ValueError
except ValueError:
raise ValueError(
'invalid command_timeout value: '
'expected greater than 0 float (got {!r})'.format(
command_timeout)) from None
addrs, params = _parse_connect_dsn_and_args(
dsn=dsn, host=host, port=port, user=user,
password=password, passfile=passfile, ssl=ssl,
direct_tls=direct_tls, database=database,
server_settings=server_settings,
target_session_attrs=target_session_attrs,
krbsrvname=krbsrvname, gsslib=gsslib,
service=service, servicefile=servicefile)
config = _ClientConfiguration(
command_timeout=command_timeout,
statement_cache_size=statement_cache_size,
max_cached_statement_lifetime=max_cached_statement_lifetime,
max_cacheable_statement_size=max_cacheable_statement_size,)
return addrs, params, config
class TLSUpgradeProto(asyncio.Protocol):
def __init__(
self,
loop: asyncio.AbstractEventLoop,
host: str,
port: int,
ssl_context: ssl_module.SSLContext,
ssl_is_advisory: bool,
) -> None:
self.on_data = _create_future(loop)
self.host = host
self.port = port
self.ssl_context = ssl_context
self.ssl_is_advisory = ssl_is_advisory
def data_received(self, data: bytes) -> None:
if data == b'S':
self.on_data.set_result(True)
elif (self.ssl_is_advisory and
self.ssl_context.verify_mode == ssl_module.CERT_NONE and
data == b'N'):
# ssl_is_advisory will imply that ssl.verify_mode == CERT_NONE,
# since the only way to get ssl_is_advisory is from
# sslmode=prefer. But be extra sure to disallow insecure
# connections when the ssl context asks for real security.
self.on_data.set_result(False)
else:
self.on_data.set_exception(
ConnectionError(
'PostgreSQL server at "{host}:{port}" '
'rejected SSL upgrade'.format(
host=self.host, port=self.port)))
def connection_lost(self, exc: typing.Optional[Exception]) -> None:
if not self.on_data.done():
if exc is None:
exc = ConnectionError('unexpected connection_lost() call')
self.on_data.set_exception(exc)
_ProctolFactoryR = typing.TypeVar(
"_ProctolFactoryR", bound=asyncio.protocols.Protocol
)
async def _create_ssl_connection(
# TODO: The return type is a specific combination of subclasses of
# asyncio.protocols.Protocol that we can't express. For now, having the
# return type be dependent on signature of the factory is an improvement
protocol_factory: Callable[[], _ProctolFactoryR],
host: str,
port: int,
*,
loop: asyncio.AbstractEventLoop,
ssl_context: ssl_module.SSLContext,
ssl_is_advisory: bool = False,
) -> typing.Tuple[asyncio.Transport, _ProctolFactoryR]:
tr, pr = await loop.create_connection(
lambda: TLSUpgradeProto(loop, host, port,
ssl_context, ssl_is_advisory),
host, port)
tr.write(struct.pack('!ll', 8, 80877103)) # SSLRequest message.
try:
do_ssl_upgrade = await pr.on_data
except (Exception, asyncio.CancelledError):
tr.close()
raise
if hasattr(loop, 'start_tls'):
if do_ssl_upgrade:
try:
new_tr = await loop.start_tls(
tr, pr, ssl_context, server_hostname=host)
assert new_tr is not None
except (Exception, asyncio.CancelledError):
tr.close()
raise
else:
new_tr = tr
pg_proto = protocol_factory()
pg_proto.is_ssl = do_ssl_upgrade
pg_proto.connection_made(new_tr)
new_tr.set_protocol(pg_proto)
return new_tr, pg_proto
else:
conn_factory = functools.partial(
loop.create_connection, protocol_factory)
if do_ssl_upgrade:
conn_factory = functools.partial(
conn_factory, ssl=ssl_context, server_hostname=host)
sock = _get_socket(tr)
sock = sock.dup()
_set_nodelay(sock)
tr.close()
try:
new_tr, pg_proto = await conn_factory(sock=sock)
pg_proto.is_ssl = do_ssl_upgrade
return new_tr, pg_proto
except (Exception, asyncio.CancelledError):
sock.close()
raise
async def _connect_addr(
*,
addr,
loop,
params,
config,
connection_class,
record_class
):
assert loop is not None
params_input = params
if callable(params.password):
password = params.password()
if inspect.isawaitable(password):
password = await password
params = params._replace(password=password)
args = (addr, loop, config, connection_class, record_class, params_input)
# prepare the params (which attempt has ssl) for the 2 attempts
if params.sslmode == SSLMode.allow:
params_retry = params
params = params._replace(ssl=None)
elif params.sslmode == SSLMode.prefer:
params_retry = params._replace(ssl=None)
else:
# skip retry if we don't have to
return await __connect_addr(params, False, *args)
# first attempt
try:
return await __connect_addr(params, True, *args)
except _RetryConnectSignal:
pass
# second attempt
return await __connect_addr(params_retry, False, *args)
class _RetryConnectSignal(Exception):
pass
async def __connect_addr(
params,
retry,
addr,
loop,
config,
connection_class,
record_class,
params_input,
):
connected = _create_future(loop)
proto_factory = lambda: protocol.Protocol(
addr, connected, params, record_class, loop)
if isinstance(addr, str):
# UNIX socket
connector = loop.create_unix_connection(proto_factory, addr)
elif params.ssl and params.ssl_negotiation is SSLNegotiation.direct:
# if ssl and ssl_negotiation is `direct`, skip STARTTLS and perform
# direct SSL connection
connector = loop.create_connection(
proto_factory, *addr, ssl=params.ssl
)
elif params.ssl:
connector = _create_ssl_connection(
proto_factory, *addr, loop=loop, ssl_context=params.ssl,
ssl_is_advisory=params.sslmode == SSLMode.prefer)
else:
connector = loop.create_connection(proto_factory, *addr)
tr, pr = await connector
try:
await connected
except (
exceptions.InvalidAuthorizationSpecificationError,
exceptions.ConnectionDoesNotExistError, # seen on Windows
):
tr.close()
# retry=True here is a redundant check because we don't want to
# accidentally raise the internal _RetryConnectSignal to the user
if retry and (
params.sslmode == SSLMode.allow and not pr.is_ssl or
params.sslmode == SSLMode.prefer and pr.is_ssl
):
# Trigger retry when:
# 1. First attempt with sslmode=allow, ssl=None failed
# 2. First attempt with sslmode=prefer, ssl=ctx failed while the
# server claimed to support SSL (returning "S" for SSLRequest)
# (likely because pg_hba.conf rejected the connection)
raise _RetryConnectSignal()
else:
# but will NOT retry if:
# 1. First attempt with sslmode=prefer failed but the server
# doesn't support SSL (returning 'N' for SSLRequest), because
# we already tried to connect without SSL thru ssl_is_advisory
# 2. Second attempt with sslmode=prefer, ssl=None failed
# 3. Second attempt with sslmode=allow, ssl=ctx failed
# 4. Any other sslmode
raise
except (Exception, asyncio.CancelledError):
tr.close()
raise
con = connection_class(pr, tr, loop, addr, config, params_input)
pr.set_connection(con)
return con
class SessionAttribute(str, enum.Enum):
any = 'any'
primary = 'primary'
standby = 'standby'
prefer_standby = 'prefer-standby'
read_write = "read-write"
read_only = "read-only"
def _accept_in_hot_standby(should_be_in_hot_standby: bool):
"""
If the server didn't report "in_hot_standby" at startup, we must determine
the state by checking "SELECT pg_catalog.pg_is_in_recovery()".
If the server allows a connection and states it is in recovery it must
be a replica/standby server.
"""
async def can_be_used(connection):
settings = connection.get_settings()
hot_standby_status = getattr(settings, 'in_hot_standby', None)
if hot_standby_status is not None:
is_in_hot_standby = hot_standby_status == 'on'
else:
is_in_hot_standby = await connection.fetchval(
"SELECT pg_catalog.pg_is_in_recovery()"
)
return is_in_hot_standby == should_be_in_hot_standby
return can_be_used
def _accept_read_only(should_be_read_only: bool):
"""
Verify the server has not set default_transaction_read_only=True
"""
async def can_be_used(connection):
settings = connection.get_settings()
is_readonly = getattr(settings, 'default_transaction_read_only', 'off')
if is_readonly == "on":
return should_be_read_only
return await _accept_in_hot_standby(should_be_read_only)(connection)
return can_be_used
async def _accept_any(_):
return True
target_attrs_check = {
SessionAttribute.any: _accept_any,
SessionAttribute.primary: _accept_in_hot_standby(False),
SessionAttribute.standby: _accept_in_hot_standby(True),
SessionAttribute.prefer_standby: _accept_in_hot_standby(True),
SessionAttribute.read_write: _accept_read_only(False),
SessionAttribute.read_only: _accept_read_only(True),
}
async def _can_use_connection(connection, attr: SessionAttribute):
can_use = target_attrs_check[attr]
return await can_use(connection)
async def _connect(*, loop, connection_class, record_class, **kwargs):
if loop is None:
loop = asyncio.get_event_loop()
addrs, params, config = _parse_connect_arguments(**kwargs)
target_attr = params.target_session_attrs
candidates = []
chosen_connection = None
last_error = None
try:
for addr in addrs:
try:
conn = await _connect_addr(
addr=addr,
loop=loop,
params=params,
config=config,
connection_class=connection_class,
record_class=record_class,
)
candidates.append(conn)
if await _can_use_connection(conn, target_attr):
chosen_connection = conn
break
except OSError as ex:
last_error = ex
else:
if target_attr == SessionAttribute.prefer_standby and candidates:
chosen_connection = random.choice(candidates)
finally:
async def _close_candidates(conns, chosen):
await asyncio.gather(
*(c.close() for c in conns if c is not chosen),
return_exceptions=True
)
if candidates:
asyncio.create_task(
_close_candidates(candidates, chosen_connection))
if chosen_connection:
return chosen_connection
raise last_error or exceptions.TargetServerAttributeNotMatched(
'None of the hosts match the target attribute requirement '
'{!r}'.format(target_attr)
)
async def _cancel(*, loop, addr, params: _ConnectionParameters,
backend_pid, backend_secret):
class CancelProto(asyncio.Protocol):
def __init__(self):
self.on_disconnect = _create_future(loop)
self.is_ssl = False
def connection_lost(self, exc):
if not self.on_disconnect.done():
self.on_disconnect.set_result(True)
if isinstance(addr, str):
tr, pr = await loop.create_unix_connection(CancelProto, addr)
else:
if params.ssl and params.sslmode != SSLMode.allow:
tr, pr = await _create_ssl_connection(
CancelProto,
*addr,
loop=loop,
ssl_context=params.ssl,
ssl_is_advisory=params.sslmode == SSLMode.prefer)
else:
tr, pr = await loop.create_connection(
CancelProto, *addr)
_set_nodelay(_get_socket(tr))
# Pack a CancelRequest message
msg = struct.pack('!llll', 16, 80877102, backend_pid, backend_secret)
try:
tr.write(msg)
await pr.on_disconnect
finally:
tr.close()
def _get_socket(transport):
sock = transport.get_extra_info('socket')
if sock is None:
# Shouldn't happen with any asyncio-complaint event loop.
raise ConnectionError(
'could not get the socket for transport {!r}'.format(transport))
return sock
def _set_nodelay(sock):
if not hasattr(socket, 'AF_UNIX') or sock.family != socket.AF_UNIX:
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
def _create_future(loop):
try:
create_future = loop.create_future
except AttributeError:
return asyncio.Future(loop=loop)
else:
return create_future()
================================================
FILE: asyncpg/connection.py
================================================
# Copyright (C) 2016-present the asyncpg authors and contributors
# <see AUTHORS file>
#
# This module is part of asyncpg and is released under
# the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
import asyncio
import asyncpg
import collections
import collections.abc
import contextlib
import functools
import itertools
import inspect
import os
import sys
import time
import traceback
import typing
import warnings
import weakref
from . import compat
from . import connect_utils
from . import cursor
from . import exceptions
from . import introspection
from . import prepared_stmt
from . import protocol
from . import serverversion
from . import transaction
from . import utils
class ConnectionMeta(type):
def __instancecheck__(cls, instance):
mro = type(instance).__mro__
return Connection in mro or _ConnectionProxy in mro
class Connection(metaclass=ConnectionMeta):
"""A representation of a database session.
Connections are created by calling :func:`~asyncpg.connection.connect`.
"""
__slots__ = ('_protocol', '_transport', '_loop',
'_top_xact', '_aborted',
'_pool_release_ctr', '_stmt_cache', '_stmts_to_close',
'_stmt_cache_enabled',
'_listeners', '_server_version', '_server_caps',
'_intro_query', '_reset_query', '_proxy',
'_stmt_exclusive_section', '_config', '_params', '_addr',
'_log_listeners', '_termination_listeners', '_cancellations',
'_source_traceback', '_query_loggers', '__weakref__')
def __init__(self, protocol, transport, loop,
addr,
config: connect_utils._ClientConfiguration,
params: connect_utils._ConnectionParameters):
self._protocol = protocol
self._transport = transport
self._loop = loop
self._top_xact = None
self._aborted = False
# Incremented every time the connection is released back to a pool.
# Used to catch invalid references to connection-related resources
# post-release (e.g. explicit prepared statements).
self._pool_release_ctr = 0
self._addr = addr
self._config = config
self._params = params
self._stmt_cache = _StatementCache(
loop=loop,
max_size=config.statement_cache_size,
on_remove=functools.partial(
_weak_maybe_gc_stmt, weakref.ref(self)),
max_lifetime=config.max_cached_statement_lifetime)
self._stmts_to_close = set()
self._stmt_cache_enabled = config.statement_cache_size > 0
self._listeners = {}
self._log_listeners = set()
self._cancellations = set()
self._termination_listeners = set()
self._query_loggers = set()
settings = self._protocol.get_settings()
ver_string = settings.server_version
self._server_version = \
serverversion.split_server_version_string(ver_string)
self._server_caps = _detect_server_capabilities(
self._server_version, settings)
if self._server_version < (14, 0):
self._intro_query = introspection.INTRO_LOOKUP_TYPES_13
else:
self._intro_query = introspection.INTRO_LOOKUP_TYPES
self._reset_query = None
self._proxy = None
# Used to serialize operations that might involve anonymous
# statements. Specifically, we want to make the following
# operation atomic:
# ("prepare an anonymous statement", "use the statement")
#
# Used for `con.fetchval()`, `con.fetch()`, `con.fetchrow()`,
# `con.execute()`, and `con.executemany()`.
self._stmt_exclusive_section = _Atomic()
if loop.get_debug():
self._source_traceback = _extract_stack()
else:
self._source_traceback = None
def __del__(self):
if not self.is_closed() and self._protocol is not None:
if self._source_traceback:
msg = "unclosed connection {!r}; created at:\n {}".format(
self, self._source_traceback)
else:
msg = (
"unclosed connection {!r}; run in asyncio debug "
"mode to show the traceback of connection "
"origin".format(self)
)
warnings.warn(msg, ResourceWarning)
if not self._loop.is_closed():
self.terminate()
async def add_listener(self, channel, callback):
"""Add a listener for Postgres notifications.
:param str channel: Channel to listen on.
:param callable callback:
A callable or a coroutine function receiving the following
arguments:
**connection**: a Connection the callback is registered with;
**pid**: PID of the Postgres server that sent the notification;
**channel**: name of the channel the notification was sent to;
**payload**: the payload.
.. versionchanged:: 0.24.0
The ``callback`` argument may be a coroutine function.
"""
self._check_open()
if channel not in self._listeners:
await self.fetch('LISTEN {}'.format(utils._quote_ident(channel)))
self._listeners[channel] = set()
self._listeners[channel].add(_Callback.from_callable(callback))
async def remove_listener(self, channel, callback):
"""Remove a listening callback on the specified channel."""
if self.is_closed():
return
if channel not in self._listeners:
return
cb = _Callback.from_callable(callback)
if cb not in self._listeners[channel]:
return
self._listeners[channel].remove(cb)
if not self._listeners[channel]:
del self._listeners[channel]
await self.fetch('UNLISTEN {}'.format(utils._quote_ident(channel)))
def add_log_listener(self, callback):
"""Add a listener for Postgres log messages.
It will be called when asyncronous NoticeResponse is received
from the connection. Possible message types are: WARNING, NOTICE,
DEBUG, INFO, or LOG.
:param callable callback:
A callable or a coroutine function receiving the following
arguments:
**connection**: a Connection the callback is registered with;
**message**: the `exceptions.PostgresLogMessage` message.
.. versionadded:: 0.12.0
.. versionchanged:: 0.24.0
The ``callback`` argument may be a coroutine function.
"""
if self.is_closed():
raise exceptions.InterfaceError('connection is closed')
self._log_listeners.add(_Callback.from_callable(callback))
def remove_log_listener(self, callback):
"""Remove a listening callback for log messages.
.. versionadded:: 0.12.0
"""
self._log_listeners.discard(_Callback.from_callable(callback))
def add_termination_listener(self, callback):
"""Add a listener that will be called when the connection is closed.
:param callable callback:
A callable or a coroutine function receiving one argument:
**connection**: a Connection the callback is registered with.
.. versionadded:: 0.21.0
.. versionchanged:: 0.24.0
The ``callback`` argument may be a coroutine function.
"""
self._termination_listeners.add(_Callback.from_callable(callback))
def remove_termination_listener(self, callback):
"""Remove a listening callback for connection termination.
:param callable callback:
The callable or coroutine function that was passed to
:meth:`Connection.add_termination_listener`.
.. versionadded:: 0.21.0
"""
self._termination_listeners.discard(_Callback.from_callable(callback))
def add_query_logger(self, callback):
"""Add a logger that will be called when queries are executed.
:param callable callback:
A callable or a coroutine function receiving one argument:
**record**, a LoggedQuery containing `query`, `args`, `timeout`,
`elapsed`, `exception`, `conn_addr`, and `conn_params`.
.. versionadded:: 0.29.0
"""
self._query_loggers.add(_Callback.from_callable(callback))
def remove_query_logger(self, callback):
"""Remove a query logger callback.
:param callable callback:
The callable or coroutine function that was passed to
:meth:`Connection.add_query_logger`.
.. versionadded:: 0.29.0
"""
self._query_loggers.discard(_Callback.from_callable(callback))
def get_server_pid(self):
"""Return the PID of the Postgres server the connection is bound to."""
return self._protocol.get_server_pid()
def get_server_version(self):
"""Return the version of the connected PostgreSQL server.
The returned value is a named tuple similar to that in
``sys.version_info``:
.. code-block:: pycon
>>> con.get_server_version()
ServerVersion(major=9, minor=6, micro=1,
releaselevel='final', serial=0)
.. versionadded:: 0.8.0
"""
return self._server_version
def get_settings(self):
"""Return connection settings.
:return: :class:`~asyncpg.ConnectionSettings`.
"""
return self._protocol.get_settings()
def transaction(self, *, isolation=None, readonly=False,
deferrable=False):
"""Create a :class:`~transaction.Transaction` object.
Refer to `PostgreSQL documentation`_ on the meaning of transaction
parameters.
:param isolation: Transaction isolation mode, can be one of:
`'serializable'`, `'repeatable_read'`,
`'read_uncommitted'`, `'read_committed'`. If not
specified, the behavior is up to the server and
session, which is usually ``read_committed``.
:param readonly: Specifies whether or not this transaction is
read-only.
:param deferrable: Specifies whether or not this transaction is
deferrable.
.. _`PostgreSQL documentation`:
https://www.postgresql.org/docs/
current/static/sql-set-transaction.html
"""
self._check_open()
return transaction.Transaction(self, isolation, readonly, deferrable)
def is_in_transaction(self):
"""Return True if Connection is currently inside a transaction.
:return bool: True if inside transaction, False otherwise.
.. versionadded:: 0.16.0
"""
return self._protocol.is_in_transaction()
async def execute(
self,
query: str,
*args,
timeout: typing.Optional[float]=None,
) -> str:
"""Execute an SQL command (or commands).
This method can execute many SQL commands at once, when no arguments
are provided.
Example:
.. code-block:: pycon
>>> await con.execute('''
... CREATE TABLE mytab (a int);
... INSERT INTO mytab (a) VALUES (100), (200), (300);
... ''')
INSERT 0 3
>>> await con.execute('''
... INSERT INTO mytab (a) VALUES ($1), ($2)
... ''', 10, 20)
INSERT 0 2
:param args: Query arguments.
:param float timeout: Optional timeout value in seconds.
:return str: Status of the last SQL command.
.. versionchanged:: 0.5.4
Made it possible to pass query arguments.
"""
self._check_open()
if not args:
if self._query_loggers:
with self._time_and_log(query, args, timeout):
result = await self._protocol.query(query, timeout)
else:
result = await self._protocol.query(query, timeout)
return result
_, status, _ = await self._execute(
query,
args,
0,
timeout,
return_status=True,
)
return status.decode()
async def executemany(
self,
command: str,
args,
*,
timeout: typing.Optional[float]=None,
):
"""Execute an SQL *command* for each sequence of arguments in *args*.
Example:
.. code-block:: pycon
>>> await con.executemany('''
... INSERT INTO mytab (a) VALUES ($1, $2, $3);
... ''', [(1, 2, 3), (4, 5, 6)])
:param command: Command to execute.
:param args: An iterable containing sequences of arguments.
:param float timeout: Optional timeout value in seconds.
:return None: This method discards the results of the operations.
.. versionadded:: 0.7.0
.. versionchanged:: 0.11.0
`timeout` became a keyword-only parameter.
.. versionchanged:: 0.22.0
``executemany()`` is now an atomic operation, which means that
either all executions succeed, or none at all. This is in contrast
to prior versions, where the effect of already-processed iterations
would remain in place when an error has occurred, unless
``executemany()`` was called in a transaction.
"""
self._check_open()
return await self._executemany(command, args, timeout)
async def _get_statement(
self,
query,
timeout,
*,
named: typing.Union[str, bool, None] = False,
use_cache=True,
ignore_custom_codec=False,
record_class=None
):
if record_class is None:
record_class = self._protocol.get_record_class()
else:
_check_record_class(record_class)
if use_cache:
statement = self._stmt_cache.get(
(query, record_class, ignore_custom_codec)
)
if statement is not None:
return statement
# Only use the cache when:
# * `statement_cache_size` is greater than 0;
# * query size is less than `max_cacheable_statement_size`.
use_cache = (
self._stmt_cache_enabled
and (
not self._config.max_cacheable_statement_size
or len(query) <= self._config.max_cacheable_statement_size
)
)
if isinstance(named, str):
stmt_name = named
elif use_cache or named:
stmt_name = self._get_unique_id('stmt')
else:
stmt_name = ''
statement = await self._protocol.prepare(
stmt_name,
query,
timeout,
record_class=record_class,
ignore_custom_codec=ignore_custom_codec,
)
need_reprepare = False
types_with_missing_codecs = statement._init_types()
tries = 0
while types_with_missing_codecs:
settings = self._protocol.get_settings()
# Introspect newly seen types and populate the
# codec cache.
types, intro_stmt = await self._introspect_types(
types_with_missing_codecs, timeout)
settings.register_data_types(types)
# The introspection query has used an anonymous statement,
# which has blown away the anonymous statement we've prepared
# for the query, so we need to re-prepare it.
need_reprepare = not intro_stmt.name and not statement.name
types_with_missing_codecs = statement._init_types()
tries += 1
if tries > 5:
# In the vast majority of cases there will be only
# one iteration. In rare cases, there might be a race
# with reload_schema_state(), which would cause a
# second try. More than five is clearly a bug.
raise exceptions.InternalClientError(
'could not resolve query result and/or argument types '
'in {} attempts'.format(tries)
)
# Now that types have been resolved, populate the codec pipeline
# for the statement.
statement._init_codecs()
if (
need_reprepare
or (not statement.name and not self._stmt_cache_enabled)
):
# Mark this anonymous prepared statement as "unprepared",
# causing it to get re-Parsed in next bind_execute.
# We always do this when stmt_cache_size is set to 0 assuming
# people are running PgBouncer which is mishandling implicit
# transactions.
statement.mark_unprepared()
if use_cache:
self._stmt_cache.put(
(query, record_class, ignore_custom_codec), statement)
# If we've just created a new statement object, check if there
# are any statements for GC.
if self._stmts_to_close:
await self._cleanup_stmts()
return statement
async def _introspect_types(self, typeoids, timeout):
if self._server_caps.jit:
try:
cfgrow, _ = await self.__execute(
"""
SELECT
current_setting('jit') AS cur,
set_config('jit', 'off', false) AS new
""",
(),
0,
timeout,
ignore_custom_codec=True,
)
jit_state = cfgrow[0]['cur']
except exceptions.UndefinedObjectError:
jit_state = 'off'
else:
jit_state = 'off'
result = await self.__execute(
self._intro_query,
(list(typeoids),),
0,
timeout,
ignore_custom_codec=True,
)
if jit_state != 'off':
await self.__execute(
"""
SELECT
set_config('jit', $1, false)
""",
(jit_state,),
0,
timeout,
ignore_custom_codec=True,
)
return result
async def _introspect_type(self, typename, schema):
if schema == 'pg_catalog' and not typename.endswith("[]"):
typeoid = protocol.BUILTIN_TYPE_NAME_MAP.get(typename.lower())
if typeoid is not None:
return introspection.TypeRecord((typeoid, None, b"b"))
rows = await self._execute(
introspection.TYPE_BY_NAME,
[typename, schema],
limit=1,
timeout=None,
ignore_custom_codec=True,
)
if not rows:
raise ValueError(
'unknown type: {}.{}'.format(schema, typename))
return rows[0]
def cursor(
self,
query,
*args,
prefetch=None,
timeout=None,
record_class=None
):
"""Return a *cursor factory* for the specified query.
:param args:
Query arguments.
:param int prefetch:
The number of rows the *cursor iterator*
will prefetch (defaults to ``50``.)
:param float timeout:
Optional timeout in seconds.
:param type record_class:
If specified, the class to use for records returned by this cursor.
Must be a subclass of :class:`~asyncpg.Record`. If not specified,
a per-connection *record_class* is used.
:return:
A :class:`~cursor.CursorFactory` object.
.. versionchanged:: 0.22.0
Added the *record_class* parameter.
"""
self._check_open()
return cursor.CursorFactory(
self,
query,
None,
args,
prefetch,
timeout,
record_class,
)
async def prepare(
self,
query,
*,
name=None,
timeout=None,
record_class=None,
):
"""Create a *prepared statement* for the specified query.
:param str query:
Text of the query to create a prepared statement for.
:param str name:
Optional name of the returned prepared statement. If not
specified, the name is auto-generated.
:param float timeout:
Optional timeout value in seconds.
:param type record_class:
If specified, the class to use for records returned by the
prepared statement. Must be a subclass of
:class:`~asyncpg.Record`. If not specified, a per-connection
*record_class* is used.
:return:
A :class:`~prepared_stmt.PreparedStatement` instance.
.. versionchanged:: 0.22.0
Added the *record_class* parameter.
.. versionchanged:: 0.25.0
Added the *name* parameter.
"""
return await self._prepare(
query,
name=name,
timeout=timeout,
record_class=record_class,
)
async def _prepare(
self,
query,
*,
name: typing.Union[str, bool, None] = None,
timeout=None,
use_cache: bool=False,
record_class=None
):
self._check_open()
if name is None:
name = self._stmt_cache_enabled
stmt = await self._get_statement(
query,
timeout,
named=name,
use_cache=use_cache,
record_class=record_class,
)
return prepared_stmt.PreparedStatement(self, query, stmt)
async def fetch(
self,
query,
*args,
timeout=None,
record_class=None
) -> list:
"""Run a query and return the results as a list of :class:`Record`.
:param str query:
Query text.
:param args:
Query arguments.
:param float timeout:
Optional timeout value in seconds.
:param type record_class:
If specified, the class to use for records returned by this method.
Must be a subclass of :class:`~asyncpg.Record`. If not specified,
a per-connection *record_class* is used.
:return list:
A list of :class:`~asyncpg.Record` instances. If specified, the
actual type of list elements would be *record_class*.
.. versionchanged:: 0.22.0
Added the *record_class* parameter.
"""
self._check_open()
return await self._execute(
query,
args,
0,
timeout,
record_class=record_class,
)
async def fetchval(self, query, *args, column=0, timeout=None):
"""Run a query and return a value in the first row.
:param str query: Query text.
:param args: Query arguments.
:param int column: Numeric index within the record of the value to
return (defaults to 0).
:param float timeout: Optional timeout value in seconds.
If not specified, defaults to the value of
``command_timeout`` argument to the ``Connection``
instance constructor.
:return: The value of the specified column of the first record, or
None if no records were returned by the query.
"""
self._check_open()
data = await self._execute(query, args, 1, timeout)
if not data:
return None
return data[0][column]
async def fetchrow(
self,
query,
*args,
timeout=None,
record_class=None
):
"""Run a query and return the first row.
:param str query:
Query text
:param args:
Query arguments
:param float timeout:
Optional timeout value in seconds.
:param type record_class:
If specified, the class to use for the value returned by this
method. Must be a subclass of :class:`~asyncpg.Record`.
If not specified, a per-connection *record_class* is used.
:return:
The first row as a :class:`~asyncpg.Record` instance, or None if
no records were returned by the query. If specified,
*record_class* is used as the type for the result value.
.. versionchanged:: 0.22.0
Added the *record_class* parameter.
"""
self._check_open()
data = await self._execute(
query,
args,
1,
timeout,
record_class=record_class,
)
if not data:
return None
return data[0]
async def fetchmany(
self,
query,
args,
*,
timeout: typing.Optional[float]=None,
record_class=None,
):
"""Run a query for each sequence of arguments in *args*
and return the results as a list of :class:`Record`.
:param query:
Query to execute.
:param args:
An iterable containing sequences of arguments for the query.
:param float timeout:
Optional timeout value in seconds.
:param type record_class:
If specified, the class to use for records returned by this method.
Must be a subclass of :class:`~asyncpg.Record`. If not specified,
a per-connection *record_class* is used.
:return list:
A list of :class:`~asyncpg.Record` instances. If specified, the
actual type of list elements would be *record_class*.
Example:
.. code-block:: pycon
>>> rows = await con.fetchmany('''
... INSERT INTO mytab (a, b) VALUES ($1, $2) RETURNING a;
... ''', [('x', 1), ('y', 2), ('z', 3)])
>>> rows
[<Record row=('x',)>, <Record row=('y',)>, <Record row=('z',)>]
.. versionadded:: 0.30.0
"""
self._check_open()
return await self._executemany(
query, args, timeout, return_rows=True, record_class=record_class
)
async def copy_from_table(self, table_name, *, output,
columns=None, schema_name=None, timeout=None,
format=None, oids=None, delimiter=None,
null=None, header=None, quote=None,
escape=None, force_quote=None, encoding=None):
"""Copy table contents to a file or file-like object.
:param str table_name:
The name of the table to copy data from.
:param output:
A :term:`path-like object <python:path-like object>`,
or a :term:`file-like object <python:file-like object>`, or
a :term:`coroutine function <python:coroutine function>`
that takes a ``bytes`` instance as a sole argument.
:param list columns:
An optional list of column names to copy.
:param str schema_name:
An optional schema name to qualify the table.
:param float timeout:
Optional timeout value in seconds.
The remaining keyword arguments are ``COPY`` statement options,
see `COPY statement documentation`_ for details.
:return: The status string of the COPY command.
Example:
.. code-block:: pycon
>>> import asyncpg
>>> import asyncio
>>> async def run():
... con = await asyncpg.connect(user='postgres')
... result = await con.copy_from_table(
... 'mytable', columns=('foo', 'bar'),
... output='file.csv', format='csv')
... print(result)
...
>>> asyncio.run(run())
'COPY 100'
.. _`COPY statement documentation`:
https://www.postgresql.org/docs/current/static/sql-copy.html
.. versionadded:: 0.11.0
"""
tabname = utils._quote_ident(table_name)
if schema_name:
tabname = utils._quote_ident(schema_name) + '.' + tabname
if columns:
cols = '({})'.format(
', '.join(utils._quote_ident(c) for c in columns))
else:
cols = ''
opts = self._format_copy_opts(
format=format, oids=oids, delimiter=delimiter,
null=null, header=header, quote=quote, escape=escape,
force_quote=force_quote, encoding=encoding
)
copy_stmt = 'COPY {tab}{cols} TO STDOUT {opts}'.format(
tab=tabname, cols=cols, opts=opts)
return await self._copy_out(copy_stmt, output, timeout)
async def copy_from_query(self, query, *args, output,
timeout=None, format=None, oids=None,
delimiter=None, null=None, header=None,
quote=None, escape=None, force_quote=None,
encoding=None):
"""Copy the results of a query to a file or file-like object.
:param str query:
The query to copy the results of.
:param args:
Query arguments.
:param output:
A :term:`path-like object <python:path-like object>`,
or a :term:`file-like object <python:file-like object>`, or
a :term:`coroutine function <python:coroutine function>`
that takes a ``bytes`` instance as a sole argument.
:param float timeout:
Optional timeout value in seconds.
The remaining keyword arguments are ``COPY`` statement options,
see `COPY statement documentation`_ for details.
:return: The status string of the COPY command.
Example:
.. code-block:: pycon
>>> import asyncpg
>>> import asyncio
>>> async def run():
... con = await asyncpg.connect(user='postgres')
... result = await con.copy_from_query(
... 'SELECT foo, bar FROM mytable WHERE foo > $1', 10,
... output='file.csv', format='csv')
... print(result)
...
>>> asyncio.run(run())
'COPY 10'
.. _`COPY statement documentation`:
https://www.postgresql.org/docs/current/static/sql-copy.html
.. versionadded:: 0.11.0
"""
opts = self._format_copy_opts(
format=format, oids=oids, delimiter=delimiter,
null=null, header=header, quote=quote, escape=escape,
force_quote=force_quote, encoding=encoding
)
if args:
query = await utils._mogrify(self, query, args)
copy_stmt = 'COPY ({query}) TO STDOUT {opts}'.format(
query=query, opts=opts)
return await self._copy_out(copy_stmt, output, timeout)
async def copy_to_table(self, table_name, *, source,
columns=None, schema_name=None, timeout=None,
format=None, oids=None, freeze=None,
delimiter=None, null=None, header=None,
quote=None, escape=None, force_quote=None,
force_not_null=None, force_null=None,
encoding=None, where=None):
"""Copy data to the specified table.
:param str table_name:
The name of the table to copy data to.
:param source:
A :term:`path-like object <python:path-like object>`,
or a :term:`file-like object <python:file-like object>`, or
an :term:`asynchronous iterable <python:asynchronous iterable>`
that returns ``bytes``, or an object supporting the
:ref:`buffer protocol <python:bufferobjects>`.
:param list columns:
An optional list of column names to copy.
:param str schema_name:
An optional schema name to qualify the table.
:param str where:
An optional SQL expression used to filter rows when copying.
.. note::
Usage of this parameter requires support for the
``COPY FROM ... WHERE`` syntax, introduced in
PostgreSQL version 12.
:param float timeout:
Optional timeout value in seconds.
The remaining keyword arguments are ``COPY`` statement options,
see `COPY statement documentation`_ for details.
:return: The status string of the COPY command.
Example:
.. code-block:: pycon
>>> import asyncpg
>>> import asyncio
>>> async def run():
... con = await asyncpg.connect(user='postgres')
... result = await con.copy_to_table(
... 'mytable', source='datafile.tbl')
... print(result)
...
>>> asyncio.run(run())
'COPY 140000'
.. _`COPY statement documentation`:
https://www.postgresql.org/docs/current/static/sql-copy.html
.. versionadded:: 0.11.0
.. versionadded:: 0.29.0
Added the *where* parameter.
"""
tabname = utils._quote_ident(table_name)
if schema_name:
tabname = utils._quote_ident(schema_name) + '.' + tabname
if columns:
cols = '({})'.format(
', '.join(utils._quote_ident(c) for c in columns))
else:
cols = ''
cond = self._format_copy_where(where)
opts = self._format_copy_opts(
format=format, oids=oids, freeze=freeze, delimiter=delimiter,
null=null, header=header, quote=quote, escape=escape,
force_not_null=force_not_null, force_null=force_null,
encoding=encoding
)
copy_stmt = 'COPY {tab}{cols} FROM STDIN {opts} {cond}'.format(
tab=tabname, cols=cols, opts=opts, cond=cond)
return await self._copy_in(copy_stmt, source, timeout)
async def copy_records_to_table(self, table_name, *, records,
columns=None, schema_name=None,
timeout=None, where=None):
"""Copy a list of records to the specified table using binary COPY.
:param str table_name:
The name of the table to copy data to.
:param records:
An iterable returning row tuples to copy into the table.
:term:`Asynchronous iterables <python:asynchronous iterable>`
are also supported.
:param list columns:
An optional list of column names to copy.
:param str schema_name:
An optional schema name to qualify the table.
:param str where:
An optional SQL expression used to filter rows when copying.
.. note::
Usage of this parameter requires support for the
``COPY FROM ... WHERE`` syntax, introduced in
PostgreSQL version 12.
:param float timeout:
Optional timeout value in seconds.
:return: The status string of the COPY command.
Example:
.. code-block:: pycon
>>> import asyncpg
>>> import asyncio
>>> async def run():
... con = await asyncpg.connect(user='postgres')
... result = await con.copy_records_to_table(
... 'mytable', records=[
... (1, 'foo', 'bar'),
... (2, 'ham', 'spam')])
... print(result)
...
>>> asyncio.run(run())
'COPY 2'
Asynchronous record iterables are also supported:
.. code-block:: pycon
>>> import asyncpg
>>> import asyncio
>>> async def run():
... con = await asyncpg.connect(user='postgres')
... async def record_gen(size):
... for i in range(size):
... yield (i,)
... result = await con.copy_records_to_table(
... 'mytable', records=record_gen(100))
... print(result)
...
>>> asyncio.run(run())
'COPY 100'
.. versionadded:: 0.11.0
.. versionchanged:: 0.24.0
The ``records`` argument may be an asynchronous iterable.
.. versionadded:: 0.29.0
Added the *where* parameter.
"""
tabname = utils._quote_ident(table_name)
if schema_name:
tabname = utils._quote_ident(schema_name) + '.' + tabname
if columns:
col_list = ', '.join(utils._quote_ident(c) for c in columns)
cols = '({})'.format(col_list)
else:
col_list = '*'
cols = ''
intro_query = 'SELECT {cols} FROM {tab} LIMIT 1'.format(
tab=tabname, cols=col_list)
intro_ps = await self.prepare(intro_query)
cond = self._format_copy_where(where)
opts = '(FORMAT binary)'
copy_stmt = 'COPY {tab}{cols} FROM STDIN {opts} {cond}'.format(
tab=tabname, cols=cols, opts=opts, cond=cond)
return await self._protocol.copy_in(
copy_stmt, None, None, records, intro_ps._state, timeout)
def _format_copy_where(self, where):
if where and not self._server_caps.sql_copy_from_where:
raise exceptions.UnsupportedServerFeatureError(
'the `where` parameter requires PostgreSQL 12 or later')
if where:
where_clause = 'WHERE ' + where
else:
where_clause = ''
return where_clause
def _format_copy_opts(self, *, format=None, oids=None, freeze=None,
delimiter=None, null=None, header=None, quote=None,
escape=None, force_quote=None, force_not_null=None,
force_null=None, encoding=None):
kwargs = dict(locals())
kwargs.pop('self')
opts = []
if force_quote is not None and isinstance(force_quote, bool):
kwargs.pop('force_quote')
if force_quote:
opts.append('FORCE_QUOTE *')
for k, v in kwargs.items():
if v is not None:
if k in ('force_not_null', 'force_null', 'force_quote'):
v = '(' + ', '.join(utils._quote_ident(c) for c in v) + ')'
elif k in ('oids', 'freeze', 'header'):
v = str(v)
else:
v = utils._quote_literal(v)
opts.append('{} {}'.format(k.upper(), v))
if opts:
return '(' + ', '.join(opts) + ')'
else:
return ''
async def _copy_out(self, copy_stmt, output, timeout):
try:
path = os.fspath(output)
except TypeError:
# output is not a path-like object
path = None
writer = None
opened_by_us = False
run_in_executor = self._loop.run_in_executor
if path is not None:
# a path
f = await run_in_executor(None, open, path, 'wb')
opened_by_us = True
elif hasattr(output, 'write'):
# file-like
f = output
elif callable(output):
# assuming calling output returns an awaitable.
writer = output
else:
raise TypeError(
'output is expected to be a file-like object, '
'a path-like object or a coroutine function, '
'not {}'.format(type(output).__name__)
)
if writer is None:
async def _writer(data):
await run_in_executor(None, f.write, data)
writer = _writer
try:
return await self._protocol.copy_out(copy_stmt, writer, timeout)
finally:
if opened_by_us:
f.close()
async def _copy_in(self, copy_stmt, source, timeout):
try:
path = os.fspath(source)
except TypeError:
# source is not a path-like object
path = None
f = None
reader = None
data = None
opened_by_us = False
run_in_executor = self._loop.run_in_executor
if path is not None:
# a path
f = await run_in_executor(None, open, path, 'rb')
opened_by_us = True
elif hasattr(source, 'read'):
# file-like
f = source
elif isinstance(source, collections.abc.AsyncIterable):
# assuming calling output returns an awaitable.
# copy_in() is designed to handle very large amounts of data, and
# the source async iterable is allowed to return an arbitrary
# amount of data on every iteration.
reader = source
else:
# assuming source is an instance supporting the buffer protocol.
data = source
if f is not None:
# Copying from a file-like object.
class _Reader:
def __aiter__(self):
return self
async def __anext__(self):
data = await run_in_executor(None, f.read, 524288)
if len(data) == 0:
raise StopAsyncIteration
else:
return data
reader = _Reader()
try:
return await self._protocol.copy_in(
copy_stmt, reader, data, None, None, timeout)
finally:
if opened_by_us:
await run_in_executor(None, f.close)
async def set_type_codec(self, typename, *,
schema='public', encoder, decoder,
format='text'):
"""Set an encoder/decoder pair for the specified data type.
:param typename:
Name of the data type the codec is for.
:param schema:
Schema name of the data type the codec is for
(defaults to ``'public'``)
:param format:
The type of the argument received by the *decoder* callback,
and the type of the *encoder* callback return value.
If *format* is ``'text'`` (the default), the exchange datum is a
``str`` instance containing valid text representation of the
data type.
If *format* is ``'binary'``, the exchange datum is a ``bytes``
instance containing valid _binary_ representation of the
data type.
If *format* is ``'tuple'``, the exchange datum is a type-specific
``tuple`` of values. The table below lists supported data
types and their format for this mode.
+-----------------+---------------------------------------------+
| Type | Tuple layout |
+=================+=============================================+
| ``interval`` | (``months``, ``days``, ``microseconds``) |
+-----------------+---------------------------------------------+
| ``date`` | (``date ordinal relative to Jan 1 2000``,) |
| | ``-2^31`` for negative infinity timestamp |
| | ``2^31-1`` for positive infinity timestamp. |
+-----------------+---------------------------------------------+
| ``timestamp`` | (``microseconds relative to Jan 1 2000``,) |
| | ``-2^63`` for negative infinity timestamp |
| | ``2^63-1`` for positive infinity timestamp. |
+-----------------+---------------------------------------------+
| ``timestamp | (``microseconds relative to Jan 1 2000 |
| with time zone``| UTC``,) |
| | ``-2^63`` for negative infinity timestamp |
| | ``2^63-1`` for positive infinity timestamp. |
+-----------------+---------------------------------------------+
| ``time`` | (``microseconds``,) |
+-----------------+---------------------------------------------+
| ``time with | (``microseconds``, |
| time zone`` | ``time zone offset in seconds``) |
+-----------------+---------------------------------------------+
| any composite | Composite value elements |
| type | |
+-----------------+---------------------------------------------+
:param encoder:
Callable accepting a Python object as a single argument and
returning a value encoded according to *format*.
:param decoder:
Callable accepting a single argument encoded according to *format*
and returning a decoded Python object.
Example:
.. code-block:: pycon
>>> import asyncpg
>>> import asyncio
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> async def run():
... con = await asyncpg.connect(user='postgres')
... def encoder(delta):
... ndelta = delta.normalized()
... return (ndelta.years * 12 + ndelta.months,
... ndelta.days,
... ((ndelta.hours * 3600 +
... ndelta.minutes * 60 +
... ndelta.seconds) * 1000000 +
... ndelta.microseconds))
... def decoder(tup):
... return relativedelta(months=tup[0], days=tup[1],
... microseconds=tup[2])
... await con.set_type_codec(
... 'interval', schema='pg_catalog', encoder=encoder,
... decoder=decoder, format='tuple')
... result = await con.fetchval(
... "SELECT '2 years 3 mons 1 day'::interval")
... print(result)
... print(datetime.datetime(2002, 1, 1) + result)
...
>>> asyncio.run(run())
relativedelta(years=+2, months=+3, days=+1)
2004-04-02 00:00:00
.. versionadded:: 0.12.0
Added the ``format`` keyword argument and support for 'tuple'
format.
.. versionchanged:: 0.12.0
The ``binary`` keyword argument is deprecated in favor of
``format``.
.. versionchanged:: 0.13.0
The ``binary`` keyword argument was removed in favor of
``format``.
.. versionchanged:: 0.29.0
Custom codecs for composite types are now supported with
``format='tuple'``.
.. note::
It is recommended to use the ``'binary'`` or ``'tuple'`` *format*
whenever possible and if the underlying type supports it. Asyncpg
currently does not support text I/O for composite and range types,
and some other functionality, such as
:meth:`Connection.copy_to_table`, does not support types with text
codecs.
"""
self._check_open()
settings = self._protocol.get_settings()
typeinfo = await self._introspect_type(typename, schema)
full_typeinfos = []
if introspection.is_scalar_type(typeinfo):
kind = 'scalar'
elif introspection.is_composite_type(typeinfo):
if format != 'tuple':
raise exceptions.UnsupportedClientFeatureError(
'only tuple-format codecs can be used on composite types',
hint="Use `set_type_codec(..., format='tuple')` and "
"pass/interpret data as a Python tuple. See an "
"example at https://magicstack.github.io/asyncpg/"
"current/usage.html#example-decoding-complex-types",
)
kind = 'composite'
full_typeinfos, _ = await self._introspect_types(
(typeinfo['oid'],), 10)
else:
raise exceptions.InterfaceError(
f'cannot use custom codec on type {schema}.{typename}: '
f'it is neither a scalar type nor a composite type'
)
if introspection.is_domain_type(typeinfo):
raise exceptions.UnsupportedClientFeatureError(
'custom codecs on domain types are not supported',
hint='Set the codec on the base type.',
detail=(
'PostgreSQL does not distinguish domains from '
'their base types in query results at the protocol level.'
)
)
oid = typeinfo['oid']
settings.add_python_codec(
oid, typename, schema, full_typeinfos, kind,
encoder, decoder, format)
# Statement cache is no longer valid due to codec changes.
self._drop_local_statement_cache()
async def reset_type_codec(self, typename, *, schema='public'):
"""Reset *typename* codec to the default implementation.
:param typename:
Name of the data type the codec is for.
:param schema:
Schema name of the data type the codec is for
(defaults to ``'public'``)
.. versionadded:: 0.12.0
"""
typeinfo = await self._introspect_type(typename, schema)
self._protocol.get_settings().remove_python_codec(
typeinfo['oid'], typename, schema)
# Statement cache is no longer valid due to codec changes.
self._drop_local_statement_cache()
async def set_builtin_type_codec(self, typename, *,
schema='public', codec_name,
format=None):
"""Set a builtin codec for the specified scalar data type.
This method has two uses. The first is to register a builtin
codec for an extension type without a stable OID, such as 'hstore'.
The second use is to declare that an extension type or a
user-defined type is wire-compatible with a certain builtin
data type and should be exchanged as such.
:param typename:
Name of the data type the codec is for.
:param schema:
Schema name of the data type the codec is for
(defaults to ``'public'``).
:param codec_name:
The name of the builtin codec to use for the type.
This should be either the name of a known core type
(such as ``"int"``), or the name of a supported extension
type. Currently, the only supported extension type is
``"pg_contrib.hstore"``.
:param format:
If *format* is ``None`` (the default), all formats supported
by the target codec are declared to be supported for *typename*.
If *format* is ``'text'`` or ``'binary'``, then only the
specified format is declared to be supported for *typename*.
.. versionchanged:: 0.18.0
The *codec_name* argument can be the name of any known
core data type. Added the *format* keyword argument.
"""
self._check_open()
typeinfo = await self._introspect_type(typename, schema)
if not introspection.is_scalar_type(typeinfo):
raise exceptions.InterfaceError(
'cannot alias non-scalar type {}.{}'.format(
schema, typename))
oid = typeinfo['oid']
self._protocol.get_settings().set_builtin_type_codec(
oid, typename, schema, 'scalar', codec_name, format)
# Statement cache is no longer valid due to codec changes.
self._drop_local_statement_cache()
def is_closed(self):
"""Return ``True`` if the connection is closed, ``False`` otherwise.
:return bool: ``True`` if the connection is closed, ``False``
otherwise.
"""
return self._aborted or not self._protocol.is_connected()
async def close(self, *, timeout=None):
"""Close the connection gracefully.
:param float timeout:
Optional timeout value in seconds.
.. versionchanged:: 0.14.0
Added the *timeout* parameter.
"""
try:
if not self.is_closed():
await self._protocol.close(timeout)
except (Exception, asyncio.CancelledError):
# If we fail to close gracefully, abort the connection.
self._abort()
raise
finally:
self._cleanup()
def terminate(self):
"""Terminate the connection without waiting for pending data."""
if not self.is_closed():
self._abort()
self._cleanup()
async def _reset(self):
self._check_open()
self._listeners.clear()
self._log_listeners.clear()
if self._protocol.is_in_transaction() or self._top_xact is not None:
if self._top_xact is None or not self._top_xact._managed:
# Managed transactions are guaranteed to __aexit__
# correctly.
self._loop.call_exception_handler({
'message': 'Resetting connection with an '
'active transaction {!r}'.format(self)
})
self._top_xact = None
await self.execute("ROLLBACK")
async def reset(self, *, timeout=None):
"""Reset the connection state.
Calling this will reset the connection session state to a state
resembling that of a newly obtained connection. Namely, an open
transaction (if any) is rolled back, open cursors are closed,
all `LISTEN <https://www.postgresql.org/docs/current/sql-listen.html>`_
registrations are removed, all session configuration
variables are reset to their default values, and all advisory locks
are released.
Note that the above describes the default query returned by
:meth:`Connection.get_reset_query`. If one overloads the method
by subclassing ``Connection``, then this method will do whatever
the overloaded method returns, except open transactions are always
terminated and any callbacks registered by
:meth:`Connection.add_listener` or :meth:`Connection.add_log_listener`
are removed.
:param float timeout:
A timeout for resetting the connection. If not specified, defaults
to no timeout.
"""
async with compat.timeout(timeout):
await self._reset()
reset_query = self.get_reset_query()
if reset_query:
await self.execute(reset_query)
def _abort(self):
# Put the connection into the aborted state.
self._aborted = True
self._protocol.abort()
self._protocol = None
def _cleanup(self):
self._call_termination_listeners()
# Free the resources associated with this connection.
# This must be called when a connection is terminated.
if self._proxy is not None:
# Connection is a member of a pool, so let the pool
# know that this connection is dead.
self._proxy._holder._release_on_close()
self._mark_stmts_as_closed()
self._listeners.clear()
self._log_listeners.clear()
self._query_loggers.clear()
self._clean_tasks()
def _clean_tasks(self):
# Wrap-up any remaining tasks associated with this connection.
if self._cancellations:
for fut in self._cancellations:
if not fut.done():
fut.cancel()
self._cancellations.clear()
def _check_open(self):
if self.is_closed():
raise exceptions.InterfaceError('connection is closed')
def _get_unique_id(self, prefix):
global _uid
_uid += 1
return '__asyncpg_{}_{:x}__'.format(prefix, _uid)
def _mark_stmts_as_closed(self):
for stmt in self._stmt_cache.iter_statements():
stmt.mark_closed()
for stmt in self._stmts_to_close:
stmt.mark_closed()
self._stmt_cache.clear()
self._stmts_to_close.clear()
def _maybe_gc_stmt(self, stmt):
if (
stmt.refs == 0
and stmt.name
and not self._stmt_cache.has(
(stmt.query, stmt.record_class, stmt.ignore_custom_codec)
)
):
# If low-level `stmt` isn't referenced from any high-level
# `PreparedStatement` object and is not in the `_stmt_cache`:
#
# * mark it as closed, which will make it non-usable
# for any `PreparedStatement` or for methods like
# `Connection.fetch()`.
#
# * schedule it to be formally closed on the server.
stmt.mark_closed()
self._stmts_to_close.add(stmt)
async def _cleanup_stmts(self):
# Called whenever we create a new prepared statement in
# `Connection._get_statement()` and `_stmts_to_close` is
# not empty.
to_close = self._stmts_to_close
self._stmts_to_close = set()
for stmt in to_close:
# It is imperative that statements are cleaned properly,
# so we ignore the timeout.
await self._protocol.close_statement(stmt, protocol.NO_TIMEOUT)
async def _cancel(self, waiter):
try:
# Open new connection to the server
await connect_utils._cancel(
loop=self._loop, addr=self._addr, params=self._params,
backend_pid=self._protocol.backend_pid,
backend_secret=self._protocol.backend_secret)
except ConnectionResetError as ex:
# On some systems Postgres will reset the connection
# after processing the cancellation command.
if not waiter.done():
waiter.set_exception(ex)
except asyncio.CancelledError:
# There are two scenarios in which the cancellation
# itself will be cancelled: 1) the connection is being closed,
# 2) the event loop is being shut down.
# In either case we do not care about the propagation of
# the CancelledError, and don't want the loop to warn about
# an unretrieved exception.
pass
except (Exception, asyncio.CancelledError) as ex:
if not waiter.done():
waiter.set_exception(ex)
finally:
self._cancellations.discard(
asyncio.current_task(self._loop))
if not waiter.done():
waiter.set_result(None)
def _cancel_current_command(self, waiter):
self._cancellations.add(self._loop.create_task(self._cancel(waiter)))
def _process_log_message(self, fields, last_query):
if not self._log_listeners:
return
message = exceptions.PostgresLogMessage.new(fields, query=last_query)
con_ref = self._unwrap()
for cb in self._log_listeners:
if cb.is_async:
self._loop.create_task(cb.cb(con_ref, message))
else:
self._loop.call_soon(cb.cb, con_ref, message)
def _call_termination_listeners(self):
if not self._termination_listeners:
return
con_ref = self._unwrap()
for cb in self._ter
gitextract_qed7mic1/
├── .clang-format
├── .clangd
├── .flake8
├── .github/
│ ├── ISSUE_TEMPLATE.md
│ ├── RELEASING.rst
│ ├── release_log.py
│ └── workflows/
│ ├── install-krb5.sh
│ ├── install-postgres.sh
│ ├── release.yml
│ └── tests.yml
├── .gitignore
├── .gitmodules
├── AUTHORS
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── asyncpg/
│ ├── .gitignore
│ ├── __init__.py
│ ├── _asyncio_compat.py
│ ├── _testbase/
│ │ ├── __init__.py
│ │ └── fuzzer.py
│ ├── _version.py
│ ├── cluster.py
│ ├── compat.py
│ ├── connect_utils.py
│ ├── connection.py
│ ├── connresource.py
│ ├── cursor.py
│ ├── exceptions/
│ │ ├── __init__.py
│ │ └── _base.py
│ ├── introspection.py
│ ├── pool.py
│ ├── prepared_stmt.py
│ ├── protocol/
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── codecs/
│ │ │ ├── __init__.py
│ │ │ ├── array.pyx
│ │ │ ├── base.pxd
│ │ │ ├── base.pyx
│ │ │ ├── pgproto.pyx
│ │ │ ├── range.pyx
│ │ │ ├── record.pyx
│ │ │ └── textutils.pyx
│ │ ├── consts.pxi
│ │ ├── coreproto.pxd
│ │ ├── coreproto.pyx
│ │ ├── cpythonx.pxd
│ │ ├── encodings.pyx
│ │ ├── pgtypes.pxi
│ │ ├── prepared_stmt.pxd
│ │ ├── prepared_stmt.pyx
│ │ ├── protocol.pxd
│ │ ├── protocol.pyi
│ │ ├── protocol.pyx
│ │ ├── record/
│ │ │ ├── pythoncapi_compat.h
│ │ │ ├── pythoncapi_compat_extras.h
│ │ │ ├── recordobj.c
│ │ │ └── recordobj.h
│ │ ├── record.pyi
│ │ ├── recordcapi.pxd
│ │ ├── scram.pxd
│ │ ├── scram.pyx
│ │ ├── settings.pxd
│ │ └── settings.pyx
│ ├── serverversion.py
│ ├── transaction.py
│ ├── types.py
│ └── utils.py
├── docs/
│ ├── .gitignore
│ ├── Makefile
│ ├── _static/
│ │ └── theme_overrides.css
│ ├── api/
│ │ └── index.rst
│ ├── conf.py
│ ├── faq.rst
│ ├── index.rst
│ ├── installation.rst
│ ├── requirements.txt
│ └── usage.rst
├── pyproject.toml
├── setup.py
├── tests/
│ ├── __init__.py
│ ├── certs/
│ │ ├── ca.cert.pem
│ │ ├── ca.crl.pem
│ │ ├── ca.key.pem
│ │ ├── client.cert.pem
│ │ ├── client.csr.pem
│ │ ├── client.key.pem
│ │ ├── client.key.protected.pem
│ │ ├── client_ca.cert.pem
│ │ ├── client_ca.cert.srl
│ │ ├── client_ca.key.pem
│ │ ├── gen.py
│ │ ├── server.cert.pem
│ │ ├── server.crl.pem
│ │ └── server.key.pem
│ ├── test__environment.py
│ ├── test__sourcecode.py
│ ├── test_adversity.py
│ ├── test_cache_invalidation.py
│ ├── test_cancellation.py
│ ├── test_codecs.py
│ ├── test_connect.py
│ ├── test_copy.py
│ ├── test_cursor.py
│ ├── test_exceptions.py
│ ├── test_execute.py
│ ├── test_introspection.py
│ ├── test_listeners.py
│ ├── test_logging.py
│ ├── test_pool.py
│ ├── test_prepare.py
│ ├── test_record.py
│ ├── test_subinterpreters.py
│ ├── test_test.py
│ ├── test_timeout.py
│ ├── test_transaction.py
│ ├── test_types.py
│ └── test_utils.py
└── tools/
├── generate_exceptions.py
└── generate_type_map.py
SYMBOL INDEX (1440 symbols across 53 files)
FILE: .github/release_log.py
function main (line 19) | def main():
FILE: asyncpg/_asyncio_compat.py
function wait_for (line 25) | async def wait_for(fut: compat.Awaitable[_T], timeout: float | None) -> _T:
function _cancel_and_wait (line 75) | async def _cancel_and_wait(fut: asyncio.Future[_T]) -> None:
function _release_waiter (line 92) | def _release_waiter(waiter: asyncio.Future[typing.Any], *args: object) -...
FILE: asyncpg/_testbase/__init__.py
function silence_asyncio_long_exec_warning (line 31) | def silence_asyncio_long_exec_warning():
function with_timeout (line 44) | def with_timeout(timeout):
class TestCaseMeta (line 52) | class TestCaseMeta(type(unittest.TestCase)):
method _iter_methods (line 56) | def _iter_methods(bases, ns):
method __new__ (line 77) | def __new__(mcls, name, bases, ns):
class TestCase (line 98) | class TestCase(unittest.TestCase, metaclass=TestCaseMeta):
method setUpClass (line 101) | def setUpClass(cls):
method tearDownClass (line 111) | def tearDownClass(cls):
method setUp (line 115) | def setUp(self):
method tearDown (line 119) | def tearDown(self):
method assertRunUnder (line 143) | def assertRunUnder(self, delta):
method assertLoopErrorHandlerCalled (line 156) | def assertLoopErrorHandlerCalled(self, msg_re: str):
method loop_exception_handler (line 179) | def loop_exception_handler(self, loop, context):
method _format_loop_exception (line 183) | def _format_loop_exception(self, context, n):
function _init_cluster (line 221) | def _init_cluster(ClusterCls, cluster_kwargs, initdb_options=None):
function _get_initdb_options (line 229) | def _get_initdb_options(initdb_options=None):
function _init_default_cluster (line 242) | def _init_default_cluster(initdb_options=None):
function _shutdown_cluster (line 262) | def _shutdown_cluster(cluster):
function create_pool (line 269) | def create_pool(dsn=None, *,
class ClusterTestCase (line 298) | class ClusterTestCase(TestCase):
method get_server_settings (line 300) | def get_server_settings(cls):
method new_cluster (line 313) | def new_cluster(cls, ClusterCls, *, cluster_kwargs={}, initdb_options=...
method start_cluster (line 320) | def start_cluster(cls, cluster, *, server_settings={}):
method setup_cluster (line 324) | def setup_cluster(cls):
method setUpClass (line 332) | def setUpClass(cls):
method tearDownClass (line 338) | def tearDownClass(cls):
method get_connection_spec (line 347) | def get_connection_spec(cls, kwargs={}):
method connect (line 360) | def connect(cls, **kwargs):
method setUp (line 364) | def setUp(self):
method tearDown (line 368) | def tearDown(self):
method create_pool (line 374) | def create_pool(self, pool_class=pg_pool.Pool,
class ProxiedClusterTestCase (line 383) | class ProxiedClusterTestCase(ClusterTestCase):
method get_server_settings (line 385) | def get_server_settings(cls):
method get_proxy_settings (line 391) | def get_proxy_settings(cls):
method setUpClass (line 395) | def setUpClass(cls):
method tearDownClass (line 410) | def tearDownClass(cls):
method get_connection_spec (line 415) | def get_connection_spec(cls, kwargs):
method tearDown (line 421) | def tearDown(self):
function with_connection_options (line 426) | def with_connection_options(**options):
class ConnectedTestCase (line 437) | class ConnectedTestCase(ClusterTestCase):
method setUp (line 439) | def setUp(self):
method tearDown (line 448) | def tearDown(self):
class HotStandbyTestCase (line 456) | class HotStandbyTestCase(ClusterTestCase):
method setup_cluster (line 459) | def setup_cluster(cls):
method get_cluster_connection_spec (line 504) | def get_cluster_connection_spec(cls, cluster, kwargs={}):
method get_connection_spec (line 517) | def get_connection_spec(cls, kwargs={}):
method connect_primary (line 533) | def connect_primary(cls, **kwargs):
method connect_standby (line 538) | def connect_standby(cls, **kwargs):
FILE: asyncpg/_testbase/fuzzer.py
class StopServer (line 16) | class StopServer(Exception):
class TCPFuzzingProxy (line 20) | class TCPFuzzingProxy:
method __init__ (line 21) | def __init__(self, *, listening_addr: str='127.0.0.1',
method _wait (line 38) | async def _wait(self, work):
method start (line 57) | def start(self):
method stop (line 65) | def stop(self):
method _stop (line 69) | def _stop(self):
method _start_thread (line 72) | def _start_thread(self, started_event):
method _main (line 94) | async def _main(self, started_event):
method listen (line 108) | async def listen(self):
method trigger_connectivity_loss (line 126) | def trigger_connectivity_loss(self):
method _trigger_connectivity_loss (line 129) | def _trigger_connectivity_loss(self):
method restore_connectivity (line 133) | def restore_connectivity(self):
method _restore_connectivity (line 136) | def _restore_connectivity(self):
method reset (line 140) | def reset(self):
method _close_connection (line 143) | def _close_connection(self, connection):
method close_all_connections (line 148) | def close_all_connections(self):
class Connection (line 153) | class Connection:
method __init__ (line 154) | def __init__(self, client_sock, backend_sock, proxy):
method close (line 165) | def close(self):
method handle (line 181) | async def handle(self):
method _read (line 212) | async def _read(self, sock, n):
method _write (line 234) | async def _write(self, sock, data):
method proxy_to_backend (line 256) | async def proxy_to_backend(self):
method proxy_from_backend (line 282) | async def proxy_from_backend(self):
FILE: asyncpg/cluster.py
function platform_exe (line 30) | def platform_exe(name):
function platform_exe (line 35) | def platform_exe(name):
function find_available_port (line 39) | def find_available_port():
function _world_readable_mkdtemp (line 50) | def _world_readable_mkdtemp(suffix=None, prefix=None, dir=None):
function _mkdtemp (line 63) | def _mkdtemp(suffix=None, prefix=None, dir=None):
class ClusterError (line 73) | class ClusterError(Exception):
class Cluster (line 77) | class Cluster:
method __init__ (line 78) | def __init__(self, data_dir, *, pg_config_path=None):
method get_pg_version (line 91) | def get_pg_version(self):
method is_managed (line 94) | def is_managed(self):
method get_data_dir (line 97) | def get_data_dir(self):
method get_status (line 100) | def get_status(self):
method connect (line 127) | async def connect(self, loop=None, **kwargs):
method init (line 132) | def init(self, **settings):
method start (line 167) | def start(self, wait=60, *, server_settings={}, **opts):
method reload (line 262) | def reload(self):
method stop (line 282) | def stop(self, wait=60):
method destroy (line 302) | def destroy(self):
method _get_connection_spec (line 309) | def _get_connection_spec(self):
method get_connection_spec (line 321) | def get_connection_spec(self):
method override_connection_spec (line 328) | def override_connection_spec(self, **kwargs):
method reset_wal (line 331) | def reset_wal(self, *, oid=None, xid=None):
method reset_hba (line 367) | def reset_hba(self):
method add_hba_entry (line 383) | def add_hba_entry(self, *, type='host', database, user, address=None,
method trust_local_connections (line 418) | def trust_local_connections(self):
method trust_local_replication_by (line 434) | def trust_local_replication_by(self, user):
method _init_env (line 448) | def _init_env(self):
method _connection_addr_from_pidfile (line 462) | def _connection_addr_from_pidfile(self):
method _test_connection (line 508) | def _test_connection(self, timeout=60):
method _run_pg_config (line 545) | def _run_pg_config(self, pg_config_path):
method _find_pg_config (line 563) | def _find_pg_config(self, pg_config_path):
method _find_pg_binary (line 591) | def _find_pg_binary(self, binary):
method _get_pg_version (line 601) | def _get_pg_version(self):
class TempCluster (line 623) | class TempCluster(Cluster):
method __init__ (line 624) | def __init__(self, *,
class HotStandbyCluster (line 633) | class HotStandbyCluster(TempCluster):
method __init__ (line 634) | def __init__(self, *,
method _init_env (line 646) | def _init_env(self):
method init (line 650) | def init(self, **settings):
method start (line 685) | def start(self, wait=60, *, server_settings={}, **opts):
class RunningCluster (line 699) | class RunningCluster(Cluster):
method __init__ (line 700) | def __init__(self, **kwargs):
method is_managed (line 703) | def is_managed(self):
method get_connection_spec (line 706) | def get_connection_spec(self):
method get_status (line 709) | def get_status(self):
method init (line 712) | def init(self, **settings):
method start (line 715) | def start(self, wait=60, **settings):
method stop (line 718) | def stop(self, wait=60):
method destroy (line 721) | def destroy(self):
method reset_hba (line 724) | def reset_hba(self):
method add_hba_entry (line 727) | def add_hba_entry(self, *, type='host', database, user, address=None,
FILE: asyncpg/compat.py
function get_pg_home_directory (line 26) | def get_pg_home_directory() -> pathlib.Path | None:
function get_pg_home_directory (line 38) | def get_pg_home_directory() -> pathlib.Path | None:
function wait_closed (line 45) | async def wait_closed(stream: asyncio.StreamWriter) -> None:
function markcoroutinefunction (line 57) | def markcoroutinefunction(c): # type: ignore
class StrEnum (line 84) | class StrEnum(str, enum.Enum):
FILE: asyncpg/connect_utils.py
class SSLMode (line 36) | class SSLMode(enum.IntEnum):
method parse (line 45) | def parse(cls, sslmode):
class SSLNegotiation (line 51) | class SSLNegotiation(compat.StrEnum):
function _read_password_file (line 94) | def _read_password_file(passfile: pathlib.Path) \
function _read_password_from_pgpass (line 137) | def _read_password_from_pgpass(
function _validate_port_spec (line 174) | def _validate_port_spec(hosts, port):
function _parse_hostlist (line 190) | def _parse_hostlist(hostlist, port, *, unquote=False):
function _parse_tls_version (line 254) | def _parse_tls_version(tls_version):
function _dot_postgresql_path (line 267) | def _dot_postgresql_path(filename) -> typing.Optional[pathlib.Path]:
function _parse_connect_dsn_and_args (line 276) | def _parse_connect_dsn_and_args(*, dsn, host, port, user,
function _parse_connect_arguments (line 862) | def _parse_connect_arguments(*, dsn, host, port, user, password, passfile,
class TLSUpgradeProto (line 911) | class TLSUpgradeProto(asyncio.Protocol):
method __init__ (line 912) | def __init__(
method data_received (line 926) | def data_received(self, data: bytes) -> None:
method connection_lost (line 944) | def connection_lost(self, exc: typing.Optional[Exception]) -> None:
function _create_ssl_connection (line 956) | async def _create_ssl_connection(
function _connect_addr (line 1022) | async def _connect_addr(
class _RetryConnectSignal (line 1062) | class _RetryConnectSignal(Exception):
function __connect_addr (line 1066) | async def __connect_addr(
class SessionAttribute (line 1141) | class SessionAttribute(str, enum.Enum):
function _accept_in_hot_standby (line 1150) | def _accept_in_hot_standby(should_be_in_hot_standby: bool):
function _accept_read_only (line 1171) | def _accept_read_only(should_be_read_only: bool):
function _accept_any (line 1186) | async def _accept_any(_):
function _can_use_connection (line 1200) | async def _can_use_connection(connection, attr: SessionAttribute):
function _connect (line 1205) | async def _connect(*, loop, connection_class, record_class, **kwargs):
function _cancel (line 1255) | async def _cancel(*, loop, addr, params: _ConnectionParameters,
function _get_socket (line 1293) | def _get_socket(transport):
function _set_nodelay (line 1302) | def _set_nodelay(sock):
function _create_future (line 1307) | def _create_future(loop):
FILE: asyncpg/connection.py
class ConnectionMeta (line 36) | class ConnectionMeta(type):
method __instancecheck__ (line 38) | def __instancecheck__(cls, instance):
class Connection (line 43) | class Connection(metaclass=ConnectionMeta):
method __init__ (line 59) | def __init__(self, protocol, transport, loop,
method __del__ (line 123) | def __del__(self):
method add_listener (line 139) | async def add_listener(self, channel, callback):
method remove_listener (line 161) | async def remove_listener(self, channel, callback):
method add_log_listener (line 175) | def add_log_listener(self, callback):
method remove_log_listener (line 197) | def remove_log_listener(self, callback):
method add_termination_listener (line 204) | def add_termination_listener(self, callback):
method remove_termination_listener (line 218) | def remove_termination_listener(self, callback):
method add_query_logger (line 229) | def add_query_logger(self, callback):
method remove_query_logger (line 241) | def remove_query_logger(self, callback):
method get_server_pid (line 252) | def get_server_pid(self):
method get_server_version (line 256) | def get_server_version(self):
method get_settings (line 272) | def get_settings(self):
method transaction (line 279) | def transaction(self, *, isolation=None, readonly=False,
method is_in_transaction (line 305) | def is_in_transaction(self):
method execute (line 314) | async def execute(
method executemany (line 366) | async def executemany(
method _get_statement (line 403) | async def _get_statement(
method _introspect_types (line 505) | async def _introspect_types(self, typeoids, timeout):
method _introspect_type (line 547) | async def _introspect_type(self, typename, schema):
method cursor (line 567) | def cursor(
method prepare (line 606) | async def prepare(
method _prepare (line 645) | async def _prepare(
method fetch (line 666) | async def fetch(
method fetchval (line 702) | async def fetchval(self, query, *args, column=0, timeout=None):
method fetchrow (line 723) | async def fetchrow(
method fetchmany (line 763) | async def fetchmany(
method copy_from_table (line 806) | async def copy_from_table(self, table_name, *, output,
method copy_from_query (line 878) | async def copy_from_query(self, query, *args, output,
method copy_to_table (line 940) | async def copy_to_table(self, table_name, *, source,
method copy_records_to_table (line 1028) | async def copy_records_to_table(self, table_name, *, records,
method _format_copy_where (line 1130) | def _format_copy_where(self, where):
method _format_copy_opts (line 1142) | def _format_copy_opts(self, *, format=None, oids=None, freeze=None,
method _copy_out (line 1171) | async def _copy_out(self, copy_stmt, output, timeout):
method _copy_in (line 1210) | async def _copy_in(self, copy_stmt, source, timeout):
method set_type_codec (line 1262) | async def set_type_codec(self, typename, *,
method reset_type_codec (line 1424) | async def reset_type_codec(self, typename, *, schema='public'):
method set_builtin_type_codec (line 1444) | async def set_builtin_type_codec(self, typename, *,
method is_closed (line 1494) | def is_closed(self):
method close (line 1502) | async def close(self, *, timeout=None):
method terminate (line 1521) | def terminate(self):
method _reset (line 1527) | async def _reset(self):
method reset (line 1544) | async def reset(self, *, timeout=None):
method _abort (line 1573) | def _abort(self):
method _cleanup (line 1579) | def _cleanup(self):
method _clean_tasks (line 1595) | def _clean_tasks(self):
method _check_open (line 1603) | def _check_open(self):
method _get_unique_id (line 1607) | def _get_unique_id(self, prefix):
method _mark_stmts_as_closed (line 1612) | def _mark_stmts_as_closed(self):
method _maybe_gc_stmt (line 1622) | def _maybe_gc_stmt(self, stmt):
method _cleanup_stmts (line 1641) | async def _cleanup_stmts(self):
method _cancel (line 1652) | async def _cancel(self, waiter):
method _cancel_current_command (line 1681) | def _cancel_current_command(self, waiter):
method _process_log_message (line 1684) | def _process_log_message(self, fields, last_query):
method _call_termination_listeners (line 1697) | def _call_termination_listeners(self):
method _process_notification (line 1710) | def _process_notification(self, pid, channel, payload):
method _unwrap (line 1721) | def _unwrap(self):
method get_reset_query (line 1732) | def get_reset_query(self):
method _set_proxy (line 1761) | def _set_proxy(self, proxy):
method _check_listeners (line 1769) | def _check_listeners(self, listeners, listener_type):
method _on_release (line 1781) | def _on_release(self, stacklevel=1):
method _drop_local_statement_cache (line 1792) | def _drop_local_statement_cache(self):
method _drop_global_statement_cache (line 1795) | def _drop_global_statement_cache(self):
method _drop_local_type_cache (line 1804) | def _drop_local_type_cache(self):
method _drop_global_type_cache (line 1807) | def _drop_global_type_cache(self):
method reload_schema_state (line 1816) | async def reload_schema_state(self):
method _execute (line 1861) | async def _execute(
method query_logger (line 1885) | def query_logger(self, callback):
method _time_and_log (line 1915) | def _time_and_log(self, query, args, timeout):
method __execute (line 1940) | async def __execute(
method _executemany (line 1979) | async def _executemany(
method _do_execute (line 2002) | async def _do_execute(
function connect (line 2083) | async def connect(dsn=None, *,
class _StatementCacheEntry (line 2469) | class _StatementCacheEntry:
method __init__ (line 2473) | def __init__(self, cache, query, statement):
class _StatementCache (line 2480) | class _StatementCache:
method __init__ (line 2485) | def __init__(self, *, loop, max_size, on_remove, max_lifetime):
method __len__ (line 2510) | def __len__(self):
method get_max_size (line 2513) | def get_max_size(self):
method set_max_size (line 2516) | def set_max_size(self, new_size):
method get_max_lifetime (line 2521) | def get_max_lifetime(self):
method set_max_lifetime (line 2524) | def set_max_lifetime(self, new_lifetime):
method get (line 2532) | def get(self, query, *, promote=True):
method has (line 2555) | def has(self, query):
method put (line 2558) | def put(self, query, statement):
method iter_statements (line 2569) | def iter_statements(self):
method clear (line 2572) | def clear(self):
method _set_entry_timeout (line 2585) | def _set_entry_timeout(self, entry):
method _new_entry (line 2594) | def _new_entry(self, query, statement):
method _on_entry_expired (line 2599) | def _on_entry_expired(self, entry):
method _clear_entry_callback (line 2606) | def _clear_entry_callback(self, entry):
method _maybe_cleanup (line 2610) | def _maybe_cleanup(self):
class _Callback (line 2621) | class _Callback(typing.NamedTuple):
method from_callable (line 2627) | def from_callable(cls, cb: typing.Callable[..., None]) -> '_Callback':
class _Atomic (line 2641) | class _Atomic:
method __init__ (line 2644) | def __init__(self):
method __enter__ (line 2647) | def __enter__(self):
method __exit__ (line 2653) | def __exit__(self, t, e, tb):
class _ConnectionProxy (line 2657) | class _ConnectionProxy:
function _detect_server_capabilities (line 2676) | def _detect_server_capabilities(server_version, connection_settings):
function _extract_stack (line 2725) | def _extract_stack(limit=10):
function _check_record_class (line 2746) | def _check_record_class(record_class):
function _weak_maybe_gc_stmt (line 2767) | def _weak_maybe_gc_stmt(weak_ref, stmt):
FILE: asyncpg/connresource.py
function guarded (line 14) | def guarded(meth):
class ConnectionResource (line 25) | class ConnectionResource:
method __init__ (line 28) | def __init__(self, connection):
method _check_conn_validity (line 32) | def _check_conn_validity(self, meth_name):
FILE: asyncpg/cursor.py
class CursorFactory (line 14) | class CursorFactory(connresource.ConnectionResource):
method __init__ (line 30) | def __init__(
method __aiter__ (line 51) | def __aiter__(self):
method __await__ (line 64) | def __await__(self):
method __del__ (line 77) | def __del__(self):
class BaseCursor (line 83) | class BaseCursor(connresource.ConnectionResource):
method __init__ (line 94) | def __init__(self, connection, query, state, args, record_class):
method _check_ready (line 105) | def _check_ready(self):
method _bind_exec (line 118) | async def _bind_exec(self, n, timeout):
method _bind (line 133) | async def _bind(self, timeout):
method _exec (line 149) | async def _exec(self, n, timeout):
method _close_portal (line 161) | async def _close_portal(self, timeout):
method __repr__ (line 172) | def __repr__(self):
method __del__ (line 188) | def __del__(self):
class CursorIterator (line 194) | class CursorIterator(BaseCursor):
method __init__ (line 198) | def __init__(
method __aiter__ (line 219) | def __aiter__(self):
method __anext__ (line 223) | async def __anext__(self):
class Cursor (line 250) | class Cursor(BaseCursor):
method _init (line 255) | async def _init(self, timeout):
method fetch (line 269) | async def fetch(self, n, *, timeout=None):
method fetchrow (line 287) | async def fetchrow(self, *, timeout=None):
method forward (line 304) | async def forward(self, n, *, timeout=None) -> int:
FILE: asyncpg/exceptions/__init__.py
class PostgresWarning (line 8) | class PostgresWarning(_base.PostgresLogMessage, Warning):
class DynamicResultSetsReturned (line 12) | class DynamicResultSetsReturned(PostgresWarning):
class ImplicitZeroBitPadding (line 16) | class ImplicitZeroBitPadding(PostgresWarning):
class NullValueEliminatedInSetFunction (line 20) | class NullValueEliminatedInSetFunction(PostgresWarning):
class PrivilegeNotGranted (line 24) | class PrivilegeNotGranted(PostgresWarning):
class PrivilegeNotRevoked (line 28) | class PrivilegeNotRevoked(PostgresWarning):
class StringDataRightTruncation (line 32) | class StringDataRightTruncation(PostgresWarning):
class DeprecatedFeature (line 36) | class DeprecatedFeature(PostgresWarning):
class NoData (line 40) | class NoData(PostgresWarning):
class NoAdditionalDynamicResultSetsReturned (line 44) | class NoAdditionalDynamicResultSetsReturned(NoData):
class SQLStatementNotYetCompleteError (line 48) | class SQLStatementNotYetCompleteError(_base.PostgresError):
class PostgresConnectionError (line 52) | class PostgresConnectionError(_base.PostgresError):
class ConnectionDoesNotExistError (line 56) | class ConnectionDoesNotExistError(PostgresConnectionError):
class ConnectionFailureError (line 60) | class ConnectionFailureError(PostgresConnectionError):
class ClientCannotConnectError (line 64) | class ClientCannotConnectError(PostgresConnectionError):
class ConnectionRejectionError (line 68) | class ConnectionRejectionError(PostgresConnectionError):
class TransactionResolutionUnknownError (line 72) | class TransactionResolutionUnknownError(PostgresConnectionError):
class ProtocolViolationError (line 76) | class ProtocolViolationError(PostgresConnectionError):
class TriggeredActionError (line 80) | class TriggeredActionError(_base.PostgresError):
class FeatureNotSupportedError (line 84) | class FeatureNotSupportedError(_base.PostgresError):
class InvalidCachedStatementError (line 88) | class InvalidCachedStatementError(FeatureNotSupportedError):
class InvalidTransactionInitiationError (line 92) | class InvalidTransactionInitiationError(_base.PostgresError):
class LocatorError (line 96) | class LocatorError(_base.PostgresError):
class InvalidLocatorSpecificationError (line 100) | class InvalidLocatorSpecificationError(LocatorError):
class InvalidGrantorError (line 104) | class InvalidGrantorError(_base.PostgresError):
class InvalidGrantOperationError (line 108) | class InvalidGrantOperationError(InvalidGrantorError):
class InvalidRoleSpecificationError (line 112) | class InvalidRoleSpecificationError(_base.PostgresError):
class DiagnosticsError (line 116) | class DiagnosticsError(_base.PostgresError):
class StackedDiagnosticsAccessedWithoutActiveHandlerError (line 120) | class StackedDiagnosticsAccessedWithoutActiveHandlerError(DiagnosticsErr...
class InvalidArgumentForXqueryError (line 124) | class InvalidArgumentForXqueryError(_base.PostgresError):
class CaseNotFoundError (line 128) | class CaseNotFoundError(_base.PostgresError):
class CardinalityViolationError (line 132) | class CardinalityViolationError(_base.PostgresError):
class DataError (line 136) | class DataError(_base.PostgresError):
class ArraySubscriptError (line 140) | class ArraySubscriptError(DataError):
class CharacterNotInRepertoireError (line 144) | class CharacterNotInRepertoireError(DataError):
class DatetimeFieldOverflowError (line 148) | class DatetimeFieldOverflowError(DataError):
class DivisionByZeroError (line 152) | class DivisionByZeroError(DataError):
class ErrorInAssignmentError (line 156) | class ErrorInAssignmentError(DataError):
class EscapeCharacterConflictError (line 160) | class EscapeCharacterConflictError(DataError):
class IndicatorOverflowError (line 164) | class IndicatorOverflowError(DataError):
class IntervalFieldOverflowError (line 168) | class IntervalFieldOverflowError(DataError):
class InvalidArgumentForLogarithmError (line 172) | class InvalidArgumentForLogarithmError(DataError):
class InvalidArgumentForNtileFunctionError (line 176) | class InvalidArgumentForNtileFunctionError(DataError):
class InvalidArgumentForNthValueFunctionError (line 180) | class InvalidArgumentForNthValueFunctionError(DataError):
class InvalidArgumentForPowerFunctionError (line 184) | class InvalidArgumentForPowerFunctionError(DataError):
class InvalidArgumentForWidthBucketFunctionError (line 188) | class InvalidArgumentForWidthBucketFunctionError(DataError):
class InvalidCharacterValueForCastError (line 192) | class InvalidCharacterValueForCastError(DataError):
class InvalidDatetimeFormatError (line 196) | class InvalidDatetimeFormatError(DataError):
class InvalidEscapeCharacterError (line 200) | class InvalidEscapeCharacterError(DataError):
class InvalidEscapeOctetError (line 204) | class InvalidEscapeOctetError(DataError):
class InvalidEscapeSequenceError (line 208) | class InvalidEscapeSequenceError(DataError):
class NonstandardUseOfEscapeCharacterError (line 212) | class NonstandardUseOfEscapeCharacterError(DataError):
class InvalidIndicatorParameterValueError (line 216) | class InvalidIndicatorParameterValueError(DataError):
class InvalidParameterValueError (line 220) | class InvalidParameterValueError(DataError):
class InvalidPrecedingOrFollowingSizeError (line 224) | class InvalidPrecedingOrFollowingSizeError(DataError):
class InvalidRegularExpressionError (line 228) | class InvalidRegularExpressionError(DataError):
class InvalidRowCountInLimitClauseError (line 232) | class InvalidRowCountInLimitClauseError(DataError):
class InvalidRowCountInResultOffsetClauseError (line 236) | class InvalidRowCountInResultOffsetClauseError(DataError):
class InvalidTablesampleArgumentError (line 240) | class InvalidTablesampleArgumentError(DataError):
class InvalidTablesampleRepeatError (line 244) | class InvalidTablesampleRepeatError(DataError):
class InvalidTimeZoneDisplacementValueError (line 248) | class InvalidTimeZoneDisplacementValueError(DataError):
class InvalidUseOfEscapeCharacterError (line 252) | class InvalidUseOfEscapeCharacterError(DataError):
class MostSpecificTypeMismatchError (line 256) | class MostSpecificTypeMismatchError(DataError):
class NullValueNotAllowedError (line 260) | class NullValueNotAllowedError(DataError):
class NullValueNoIndicatorParameterError (line 264) | class NullValueNoIndicatorParameterError(DataError):
class NumericValueOutOfRangeError (line 268) | class NumericValueOutOfRangeError(DataError):
class SequenceGeneratorLimitExceededError (line 272) | class SequenceGeneratorLimitExceededError(DataError):
class StringDataLengthMismatchError (line 276) | class StringDataLengthMismatchError(DataError):
class StringDataRightTruncationError (line 280) | class StringDataRightTruncationError(DataError):
class SubstringError (line 284) | class SubstringError(DataError):
class TrimError (line 288) | class TrimError(DataError):
class UnterminatedCStringError (line 292) | class UnterminatedCStringError(DataError):
class ZeroLengthCharacterStringError (line 296) | class ZeroLengthCharacterStringError(DataError):
class PostgresFloatingPointError (line 300) | class PostgresFloatingPointError(DataError):
class InvalidTextRepresentationError (line 304) | class InvalidTextRepresentationError(DataError):
class InvalidBinaryRepresentationError (line 308) | class InvalidBinaryRepresentationError(DataError):
class BadCopyFileFormatError (line 312) | class BadCopyFileFormatError(DataError):
class UntranslatableCharacterError (line 316) | class UntranslatableCharacterError(DataError):
class NotAnXmlDocumentError (line 320) | class NotAnXmlDocumentError(DataError):
class InvalidXmlDocumentError (line 324) | class InvalidXmlDocumentError(DataError):
class InvalidXmlContentError (line 328) | class InvalidXmlContentError(DataError):
class InvalidXmlCommentError (line 332) | class InvalidXmlCommentError(DataError):
class InvalidXmlProcessingInstructionError (line 336) | class InvalidXmlProcessingInstructionError(DataError):
class DuplicateJsonObjectKeyValueError (line 340) | class DuplicateJsonObjectKeyValueError(DataError):
class InvalidArgumentForSQLJsonDatetimeFunctionError (line 344) | class InvalidArgumentForSQLJsonDatetimeFunctionError(DataError):
class InvalidJsonTextError (line 348) | class InvalidJsonTextError(DataError):
class InvalidSQLJsonSubscriptError (line 352) | class InvalidSQLJsonSubscriptError(DataError):
class MoreThanOneSQLJsonItemError (line 356) | class MoreThanOneSQLJsonItemError(DataError):
class NoSQLJsonItemError (line 360) | class NoSQLJsonItemError(DataError):
class NonNumericSQLJsonItemError (line 364) | class NonNumericSQLJsonItemError(DataError):
class NonUniqueKeysInAJsonObjectError (line 368) | class NonUniqueKeysInAJsonObjectError(DataError):
class SingletonSQLJsonItemRequiredError (line 372) | class SingletonSQLJsonItemRequiredError(DataError):
class SQLJsonArrayNotFoundError (line 376) | class SQLJsonArrayNotFoundError(DataError):
class SQLJsonMemberNotFoundError (line 380) | class SQLJsonMemberNotFoundError(DataError):
class SQLJsonNumberNotFoundError (line 384) | class SQLJsonNumberNotFoundError(DataError):
class SQLJsonObjectNotFoundError (line 388) | class SQLJsonObjectNotFoundError(DataError):
class TooManyJsonArrayElementsError (line 392) | class TooManyJsonArrayElementsError(DataError):
class TooManyJsonObjectMembersError (line 396) | class TooManyJsonObjectMembersError(DataError):
class SQLJsonScalarRequiredError (line 400) | class SQLJsonScalarRequiredError(DataError):
class SQLJsonItemCannotBeCastToTargetTypeError (line 404) | class SQLJsonItemCannotBeCastToTargetTypeError(DataError):
class IntegrityConstraintViolationError (line 408) | class IntegrityConstraintViolationError(_base.PostgresError):
class RestrictViolationError (line 412) | class RestrictViolationError(IntegrityConstraintViolationError):
class NotNullViolationError (line 416) | class NotNullViolationError(IntegrityConstraintViolationError):
class ForeignKeyViolationError (line 420) | class ForeignKeyViolationError(IntegrityConstraintViolationError):
class UniqueViolationError (line 424) | class UniqueViolationError(IntegrityConstraintViolationError):
class CheckViolationError (line 428) | class CheckViolationError(IntegrityConstraintViolationError):
class ExclusionViolationError (line 432) | class ExclusionViolationError(IntegrityConstraintViolationError):
class InvalidCursorStateError (line 436) | class InvalidCursorStateError(_base.PostgresError):
class InvalidTransactionStateError (line 440) | class InvalidTransactionStateError(_base.PostgresError):
class ActiveSQLTransactionError (line 444) | class ActiveSQLTransactionError(InvalidTransactionStateError):
class BranchTransactionAlreadyActiveError (line 448) | class BranchTransactionAlreadyActiveError(InvalidTransactionStateError):
class HeldCursorRequiresSameIsolationLevelError (line 452) | class HeldCursorRequiresSameIsolationLevelError(InvalidTransactionStateE...
class InappropriateAccessModeForBranchTransactionError (line 456) | class InappropriateAccessModeForBranchTransactionError(
class InappropriateIsolationLevelForBranchTransactionError (line 461) | class InappropriateIsolationLevelForBranchTransactionError(
class NoActiveSQLTransactionForBranchTransactionError (line 466) | class NoActiveSQLTransactionForBranchTransactionError(
class ReadOnlySQLTransactionError (line 471) | class ReadOnlySQLTransactionError(InvalidTransactionStateError):
class SchemaAndDataStatementMixingNotSupportedError (line 475) | class SchemaAndDataStatementMixingNotSupportedError(
class NoActiveSQLTransactionError (line 480) | class NoActiveSQLTransactionError(InvalidTransactionStateError):
class InFailedSQLTransactionError (line 484) | class InFailedSQLTransactionError(InvalidTransactionStateError):
class IdleInTransactionSessionTimeoutError (line 488) | class IdleInTransactionSessionTimeoutError(InvalidTransactionStateError):
class TransactionTimeoutError (line 492) | class TransactionTimeoutError(InvalidTransactionStateError):
class InvalidSQLStatementNameError (line 496) | class InvalidSQLStatementNameError(_base.PostgresError):
class TriggeredDataChangeViolationError (line 500) | class TriggeredDataChangeViolationError(_base.PostgresError):
class InvalidAuthorizationSpecificationError (line 504) | class InvalidAuthorizationSpecificationError(_base.PostgresError):
class InvalidPasswordError (line 508) | class InvalidPasswordError(InvalidAuthorizationSpecificationError):
class DependentPrivilegeDescriptorsStillExistError (line 512) | class DependentPrivilegeDescriptorsStillExistError(_base.PostgresError):
class DependentObjectsStillExistError (line 516) | class DependentObjectsStillExistError(
class InvalidTransactionTerminationError (line 521) | class InvalidTransactionTerminationError(_base.PostgresError):
class SQLRoutineError (line 525) | class SQLRoutineError(_base.PostgresError):
class FunctionExecutedNoReturnStatementError (line 529) | class FunctionExecutedNoReturnStatementError(SQLRoutineError):
class ModifyingSQLDataNotPermittedError (line 533) | class ModifyingSQLDataNotPermittedError(SQLRoutineError):
class ProhibitedSQLStatementAttemptedError (line 537) | class ProhibitedSQLStatementAttemptedError(SQLRoutineError):
class ReadingSQLDataNotPermittedError (line 541) | class ReadingSQLDataNotPermittedError(SQLRoutineError):
class InvalidCursorNameError (line 545) | class InvalidCursorNameError(_base.PostgresError):
class ExternalRoutineError (line 549) | class ExternalRoutineError(_base.PostgresError):
class ContainingSQLNotPermittedError (line 553) | class ContainingSQLNotPermittedError(ExternalRoutineError):
class ModifyingExternalRoutineSQLDataNotPermittedError (line 557) | class ModifyingExternalRoutineSQLDataNotPermittedError(ExternalRoutineEr...
class ProhibitedExternalRoutineSQLStatementAttemptedError (line 561) | class ProhibitedExternalRoutineSQLStatementAttemptedError(
class ReadingExternalRoutineSQLDataNotPermittedError (line 566) | class ReadingExternalRoutineSQLDataNotPermittedError(ExternalRoutineError):
class ExternalRoutineInvocationError (line 570) | class ExternalRoutineInvocationError(_base.PostgresError):
class InvalidSqlstateReturnedError (line 574) | class InvalidSqlstateReturnedError(ExternalRoutineInvocationError):
class NullValueInExternalRoutineNotAllowedError (line 578) | class NullValueInExternalRoutineNotAllowedError(
class TriggerProtocolViolatedError (line 583) | class TriggerProtocolViolatedError(ExternalRoutineInvocationError):
class SrfProtocolViolatedError (line 587) | class SrfProtocolViolatedError(ExternalRoutineInvocationError):
class EventTriggerProtocolViolatedError (line 591) | class EventTriggerProtocolViolatedError(ExternalRoutineInvocationError):
class SavepointError (line 595) | class SavepointError(_base.PostgresError):
class InvalidSavepointSpecificationError (line 599) | class InvalidSavepointSpecificationError(SavepointError):
class InvalidCatalogNameError (line 603) | class InvalidCatalogNameError(_base.PostgresError):
class InvalidSchemaNameError (line 607) | class InvalidSchemaNameError(_base.PostgresError):
class TransactionRollbackError (line 611) | class TransactionRollbackError(_base.PostgresError):
class TransactionIntegrityConstraintViolationError (line 615) | class TransactionIntegrityConstraintViolationError(TransactionRollbackEr...
class SerializationError (line 619) | class SerializationError(TransactionRollbackError):
class StatementCompletionUnknownError (line 623) | class StatementCompletionUnknownError(TransactionRollbackError):
class DeadlockDetectedError (line 627) | class DeadlockDetectedError(TransactionRollbackError):
class SyntaxOrAccessError (line 631) | class SyntaxOrAccessError(_base.PostgresError):
class PostgresSyntaxError (line 635) | class PostgresSyntaxError(SyntaxOrAccessError):
class InsufficientPrivilegeError (line 639) | class InsufficientPrivilegeError(SyntaxOrAccessError):
class CannotCoerceError (line 643) | class CannotCoerceError(SyntaxOrAccessError):
class GroupingError (line 647) | class GroupingError(SyntaxOrAccessError):
class WindowingError (line 651) | class WindowingError(SyntaxOrAccessError):
class InvalidRecursionError (line 655) | class InvalidRecursionError(SyntaxOrAccessError):
class InvalidForeignKeyError (line 659) | class InvalidForeignKeyError(SyntaxOrAccessError):
class InvalidNameError (line 663) | class InvalidNameError(SyntaxOrAccessError):
class NameTooLongError (line 667) | class NameTooLongError(SyntaxOrAccessError):
class ReservedNameError (line 671) | class ReservedNameError(SyntaxOrAccessError):
class DatatypeMismatchError (line 675) | class DatatypeMismatchError(SyntaxOrAccessError):
class IndeterminateDatatypeError (line 679) | class IndeterminateDatatypeError(SyntaxOrAccessError):
class CollationMismatchError (line 683) | class CollationMismatchError(SyntaxOrAccessError):
class IndeterminateCollationError (line 687) | class IndeterminateCollationError(SyntaxOrAccessError):
class WrongObjectTypeError (line 691) | class WrongObjectTypeError(SyntaxOrAccessError):
class GeneratedAlwaysError (line 695) | class GeneratedAlwaysError(SyntaxOrAccessError):
class UndefinedColumnError (line 699) | class UndefinedColumnError(SyntaxOrAccessError):
class UndefinedFunctionError (line 703) | class UndefinedFunctionError(SyntaxOrAccessError):
class UndefinedTableError (line 707) | class UndefinedTableError(SyntaxOrAccessError):
class UndefinedParameterError (line 711) | class UndefinedParameterError(SyntaxOrAccessError):
class UndefinedObjectError (line 715) | class UndefinedObjectError(SyntaxOrAccessError):
class DuplicateColumnError (line 719) | class DuplicateColumnError(SyntaxOrAccessError):
class DuplicateCursorError (line 723) | class DuplicateCursorError(SyntaxOrAccessError):
class DuplicateDatabaseError (line 727) | class DuplicateDatabaseError(SyntaxOrAccessError):
class DuplicateFunctionError (line 731) | class DuplicateFunctionError(SyntaxOrAccessError):
class DuplicatePreparedStatementError (line 735) | class DuplicatePreparedStatementError(SyntaxOrAccessError):
class DuplicateSchemaError (line 739) | class DuplicateSchemaError(SyntaxOrAccessError):
class DuplicateTableError (line 743) | class DuplicateTableError(SyntaxOrAccessError):
class DuplicateAliasError (line 747) | class DuplicateAliasError(SyntaxOrAccessError):
class DuplicateObjectError (line 751) | class DuplicateObjectError(SyntaxOrAccessError):
class AmbiguousColumnError (line 755) | class AmbiguousColumnError(SyntaxOrAccessError):
class AmbiguousFunctionError (line 759) | class AmbiguousFunctionError(SyntaxOrAccessError):
class AmbiguousParameterError (line 763) | class AmbiguousParameterError(SyntaxOrAccessError):
class AmbiguousAliasError (line 767) | class AmbiguousAliasError(SyntaxOrAccessError):
class InvalidColumnReferenceError (line 771) | class InvalidColumnReferenceError(SyntaxOrAccessError):
class InvalidColumnDefinitionError (line 775) | class InvalidColumnDefinitionError(SyntaxOrAccessError):
class InvalidCursorDefinitionError (line 779) | class InvalidCursorDefinitionError(SyntaxOrAccessError):
class InvalidDatabaseDefinitionError (line 783) | class InvalidDatabaseDefinitionError(SyntaxOrAccessError):
class InvalidFunctionDefinitionError (line 787) | class InvalidFunctionDefinitionError(SyntaxOrAccessError):
class InvalidPreparedStatementDefinitionError (line 791) | class InvalidPreparedStatementDefinitionError(SyntaxOrAccessError):
class InvalidSchemaDefinitionError (line 795) | class InvalidSchemaDefinitionError(SyntaxOrAccessError):
class InvalidTableDefinitionError (line 799) | class InvalidTableDefinitionError(SyntaxOrAccessError):
class InvalidObjectDefinitionError (line 803) | class InvalidObjectDefinitionError(SyntaxOrAccessError):
class WithCheckOptionViolationError (line 807) | class WithCheckOptionViolationError(_base.PostgresError):
class InsufficientResourcesError (line 811) | class InsufficientResourcesError(_base.PostgresError):
class DiskFullError (line 815) | class DiskFullError(InsufficientResourcesError):
class OutOfMemoryError (line 819) | class OutOfMemoryError(InsufficientResourcesError):
class TooManyConnectionsError (line 823) | class TooManyConnectionsError(InsufficientResourcesError):
class ConfigurationLimitExceededError (line 827) | class ConfigurationLimitExceededError(InsufficientResourcesError):
class ProgramLimitExceededError (line 831) | class ProgramLimitExceededError(_base.PostgresError):
class StatementTooComplexError (line 835) | class StatementTooComplexError(ProgramLimitExceededError):
class TooManyColumnsError (line 839) | class TooManyColumnsError(ProgramLimitExceededError):
class TooManyArgumentsError (line 843) | class TooManyArgumentsError(ProgramLimitExceededError):
class ObjectNotInPrerequisiteStateError (line 847) | class ObjectNotInPrerequisiteStateError(_base.PostgresError):
class ObjectInUseError (line 851) | class ObjectInUseError(ObjectNotInPrerequisiteStateError):
class CantChangeRuntimeParamError (line 855) | class CantChangeRuntimeParamError(ObjectNotInPrerequisiteStateError):
class LockNotAvailableError (line 859) | class LockNotAvailableError(ObjectNotInPrerequisiteStateError):
class UnsafeNewEnumValueUsageError (line 863) | class UnsafeNewEnumValueUsageError(ObjectNotInPrerequisiteStateError):
class OperatorInterventionError (line 867) | class OperatorInterventionError(_base.PostgresError):
class QueryCanceledError (line 871) | class QueryCanceledError(OperatorInterventionError):
class AdminShutdownError (line 875) | class AdminShutdownError(OperatorInterventionError):
class CrashShutdownError (line 879) | class CrashShutdownError(OperatorInterventionError):
class CannotConnectNowError (line 883) | class CannotConnectNowError(OperatorInterventionError):
class DatabaseDroppedError (line 887) | class DatabaseDroppedError(OperatorInterventionError):
class IdleSessionTimeoutError (line 891) | class IdleSessionTimeoutError(OperatorInterventionError):
class PostgresSystemError (line 895) | class PostgresSystemError(_base.PostgresError):
class PostgresIOError (line 899) | class PostgresIOError(PostgresSystemError):
class UndefinedFileError (line 903) | class UndefinedFileError(PostgresSystemError):
class DuplicateFileError (line 907) | class DuplicateFileError(PostgresSystemError):
class FileNameTooLongError (line 911) | class FileNameTooLongError(PostgresSystemError):
class SnapshotTooOldError (line 915) | class SnapshotTooOldError(_base.PostgresError):
class ConfigFileError (line 919) | class ConfigFileError(_base.PostgresError):
class LockFileExistsError (line 923) | class LockFileExistsError(ConfigFileError):
class FDWError (line 927) | class FDWError(_base.PostgresError):
class FDWColumnNameNotFoundError (line 931) | class FDWColumnNameNotFoundError(FDWError):
class FDWDynamicParameterValueNeededError (line 935) | class FDWDynamicParameterValueNeededError(FDWError):
class FDWFunctionSequenceError (line 939) | class FDWFunctionSequenceError(FDWError):
class FDWInconsistentDescriptorInformationError (line 943) | class FDWInconsistentDescriptorInformationError(FDWError):
class FDWInvalidAttributeValueError (line 947) | class FDWInvalidAttributeValueError(FDWError):
class FDWInvalidColumnNameError (line 951) | class FDWInvalidColumnNameError(FDWError):
class FDWInvalidColumnNumberError (line 955) | class FDWInvalidColumnNumberError(FDWError):
class FDWInvalidDataTypeError (line 959) | class FDWInvalidDataTypeError(FDWError):
class FDWInvalidDataTypeDescriptorsError (line 963) | class FDWInvalidDataTypeDescriptorsError(FDWError):
class FDWInvalidDescriptorFieldIdentifierError (line 967) | class FDWInvalidDescriptorFieldIdentifierError(FDWError):
class FDWInvalidHandleError (line 971) | class FDWInvalidHandleError(FDWError):
class FDWInvalidOptionIndexError (line 975) | class FDWInvalidOptionIndexError(FDWError):
class FDWInvalidOptionNameError (line 979) | class FDWInvalidOptionNameError(FDWError):
class FDWInvalidStringLengthOrBufferLengthError (line 983) | class FDWInvalidStringLengthOrBufferLengthError(FDWError):
class FDWInvalidStringFormatError (line 987) | class FDWInvalidStringFormatError(FDWError):
class FDWInvalidUseOfNullPointerError (line 991) | class FDWInvalidUseOfNullPointerError(FDWError):
class FDWTooManyHandlesError (line 995) | class FDWTooManyHandlesError(FDWError):
class FDWOutOfMemoryError (line 999) | class FDWOutOfMemoryError(FDWError):
class FDWNoSchemasError (line 1003) | class FDWNoSchemasError(FDWError):
class FDWOptionNameNotFoundError (line 1007) | class FDWOptionNameNotFoundError(FDWError):
class FDWReplyHandleError (line 1011) | class FDWReplyHandleError(FDWError):
class FDWSchemaNotFoundError (line 1015) | class FDWSchemaNotFoundError(FDWError):
class FDWTableNotFoundError (line 1019) | class FDWTableNotFoundError(FDWError):
class FDWUnableToCreateExecutionError (line 1023) | class FDWUnableToCreateExecutionError(FDWError):
class FDWUnableToCreateReplyError (line 1027) | class FDWUnableToCreateReplyError(FDWError):
class FDWUnableToEstablishConnectionError (line 1031) | class FDWUnableToEstablishConnectionError(FDWError):
class PLPGSQLError (line 1035) | class PLPGSQLError(_base.PostgresError):
class RaiseError (line 1039) | class RaiseError(PLPGSQLError):
class NoDataFoundError (line 1043) | class NoDataFoundError(PLPGSQLError):
class TooManyRowsError (line 1047) | class TooManyRowsError(PLPGSQLError):
class AssertError (line 1051) | class AssertError(PLPGSQLError):
class InternalServerError (line 1055) | class InternalServerError(_base.PostgresError):
class DataCorruptedError (line 1059) | class DataCorruptedError(InternalServerError):
class IndexCorruptedError (line 1063) | class IndexCorruptedError(InternalServerError):
FILE: asyncpg/exceptions/_base.py
function _is_asyncpg_class (line 21) | def _is_asyncpg_class(cls):
class PostgresMessageMeta (line 26) | class PostgresMessageMeta(type):
method __new__ (line 50) | def __new__(mcls, name, bases, dct):
method get_message_class_for_sqlstate (line 74) | def get_message_class_for_sqlstate(mcls, code):
class PostgresMessage (line 78) | class PostgresMessage(metaclass=PostgresMessageMeta):
method _get_error_class (line 81) | def _get_error_class(cls, fields):
method _get_error_dict (line 86) | def _get_error_dict(cls, fields, query):
method _make_constructor (line 100) | def _make_constructor(cls, fields, query=None):
method as_dict (line 156) | def as_dict(self):
class PostgresError (line 165) | class PostgresError(PostgresMessage, Exception):
method __str__ (line 168) | def __str__(self):
method new (line 178) | def new(cls, fields, query=None):
class FatalPostgresError (line 185) | class FatalPostgresError(PostgresError):
class UnknownPostgresError (line 189) | class UnknownPostgresError(FatalPostgresError):
class InterfaceMessage (line 193) | class InterfaceMessage:
method __init__ (line 194) | def __init__(self, *, detail=None, hint=None):
method __str__ (line 198) | def __str__(self):
class InterfaceError (line 208) | class InterfaceError(InterfaceMessage, Exception):
method __init__ (line 211) | def __init__(self, msg, *, detail=None, hint=None):
method with_msg (line 215) | def with_msg(self, msg):
class ClientConfigurationError (line 225) | class ClientConfigurationError(InterfaceError, ValueError):
class DataError (line 229) | class DataError(InterfaceError, ValueError):
class UnsupportedClientFeatureError (line 233) | class UnsupportedClientFeatureError(InterfaceError):
class UnsupportedServerFeatureError (line 237) | class UnsupportedServerFeatureError(InterfaceError):
class InterfaceWarning (line 241) | class InterfaceWarning(InterfaceMessage, UserWarning):
method __init__ (line 244) | def __init__(self, msg, *, detail=None, hint=None):
class InternalClientError (line 249) | class InternalClientError(Exception):
class ProtocolError (line 253) | class ProtocolError(InternalClientError):
class TargetServerAttributeNotMatched (line 257) | class TargetServerAttributeNotMatched(InternalClientError):
class OutdatedSchemaCacheError (line 261) | class OutdatedSchemaCacheError(InternalClientError):
method __init__ (line 264) | def __init__(self, msg, *, schema=None, data_type=None, position=None):
class PostgresLogMessage (line 271) | class PostgresLogMessage(PostgresMessage):
method __str__ (line 274) | def __str__(self):
method __setattr__ (line 277) | def __setattr__(self, name, val):
method new (line 282) | def new(cls, fields, query=None):
FILE: asyncpg/introspection.py
function TypeRecord (line 272) | def TypeRecord(
function is_scalar_type (line 284) | def is_scalar_type(typeinfo: protocol.Record) -> bool:
function is_domain_type (line 291) | def is_domain_type(typeinfo: protocol.Record) -> bool:
function is_composite_type (line 295) | def is_composite_type(typeinfo: protocol.Record) -> bool:
FILE: asyncpg/pool.py
class PoolConnectionProxyMeta (line 28) | class PoolConnectionProxyMeta(type):
method __new__ (line 30) | def __new__(
method _wrap_connection_method (line 58) | def _wrap_connection_method(
class PoolConnectionProxy (line 78) | class PoolConnectionProxy(connection._ConnectionProxy,
method __init__ (line 84) | def __init__(
method __getattr__ (line 91) | def __getattr__(self, attr: str) -> Any:
method _detach (line 95) | def _detach(self) -> Optional[connection.Connection]:
method __repr__ (line 103) | def __repr__(self) -> str:
class PoolConnectionHolder (line 112) | class PoolConnectionHolder:
method __init__ (line 120) | def __init__(
method is_connected (line 141) | def is_connected(self) -> bool:
method is_idle (line 144) | def is_idle(self) -> bool:
method connect (line 147) | async def connect(self) -> None:
method acquire (line 158) | async def acquire(self) -> PoolConnectionProxy:
method release (line 195) | async def release(self, timeout: Optional[float]) -> None:
method wait_until_released (line 258) | async def wait_until_released(self) -> None:
method close (line 264) | async def close(self) -> None:
method terminate (line 270) | def terminate(self) -> None:
method _setup_inactive_callback (line 276) | def _setup_inactive_callback(self) -> None:
method _maybe_cancel_inactive_callback (line 285) | def _maybe_cancel_inactive_callback(self) -> None:
method _deactivate_inactive_connection (line 290) | def _deactivate_inactive_connection(self) -> None:
method _release_on_close (line 304) | def _release_on_close(self) -> None:
method _release (line 309) | def _release(self) -> None:
class Pool (line 329) | class Pool:
method __init__ (line 348) | def __init__(self, *connect_args,
method _async__init__ (line 429) | async def _async__init__(self):
method _initialize (line 445) | async def _initialize(self):
method is_closing (line 478) | def is_closing(self):
method get_size (line 485) | def get_size(self):
method get_min_size (line 492) | def get_min_size(self):
method get_max_size (line 499) | def get_max_size(self):
method get_idle_size (line 506) | def get_idle_size(self):
method set_connect_args (line 513) | def set_connect_args(self, dsn=None, **connect_kwargs):
method _get_new_connection (line 537) | async def _get_new_connection(self):
method execute (line 577) | async def execute(
method executemany (line 594) | async def executemany(
method fetch (line 613) | async def fetch(
method fetchval (line 636) | async def fetchval(self, query, *args, column=0, timeout=None):
method fetchrow (line 650) | async def fetchrow(self, query, *args, timeout=None, record_class=None):
method fetchmany (line 667) | async def fetchmany(self, query, args, *, timeout=None, record_class=N...
method copy_from_table (line 683) | async def copy_from_table(
method copy_from_query (line 728) | async def copy_from_query(
method copy_to_table (line 770) | async def copy_to_table(
method copy_records_to_table (line 823) | async def copy_records_to_table(
method acquire (line 852) | def acquire(self, *, timeout=None):
method _acquire (line 877) | async def _acquire(self, timeout):
method release (line 901) | async def release(self, connection, *, timeout=None):
method close (line 939) | async def close(self):
method _warn_on_long_close (line 984) | def _warn_on_long_close(self):
method terminate (line 990) | def terminate(self):
method expire_connections (line 999) | async def expire_connections(self):
method _check_init (line 1009) | def _check_init(self):
method _drop_statement_cache (line 1020) | def _drop_statement_cache(self):
method _drop_type_cache (line 1026) | def _drop_type_cache(self):
method __await__ (line 1032) | def __await__(self):
method __aenter__ (line 1035) | async def __aenter__(self):
method __aexit__ (line 1039) | async def __aexit__(self, *exc):
class PoolAcquireContext (line 1043) | class PoolAcquireContext:
method __init__ (line 1047) | def __init__(self, pool: Pool, timeout: Optional[float]) -> None:
method __aenter__ (line 1053) | async def __aenter__(self):
method __aexit__ (line 1059) | async def __aexit__(
method __await__ (line 1070) | def __await__(self):
function create_pool (line 1075) | def create_pool(dsn=None, *,
FILE: asyncpg/prepared_stmt.py
class PreparedStatement (line 16) | class PreparedStatement(connresource.ConnectionResource):
method __init__ (line 21) | def __init__(self, connection, query, state):
method get_name (line 29) | def get_name(self) -> str:
method get_query (line 37) | def get_query(self) -> str:
method get_statusmsg (line 48) | def get_statusmsg(self) -> str:
method get_parameters (line 62) | def get_parameters(self):
method get_attributes (line 79) | def get_attributes(self):
method cursor (line 104) | def cursor(self, *args, prefetch=None,
method explain (line 126) | async def explain(self, *args, analyze=False):
method fetch (line 168) | async def fetch(self, *args, timeout=None):
method fetchval (line 181) | async def fetchval(self, *args, column=0, timeout=None):
method fetchrow (line 200) | async def fetchrow(self, *args, timeout=None):
method fetchmany (line 215) | async def fetchmany(self, args, *, timeout=None):
method executemany (line 236) | async def executemany(self, args, *, timeout: typing.Optional[float]=N...
method __do_execute (line 254) | async def __do_execute(self, executor):
method __bind_execute (line 267) | async def __bind_execute(self, args, limit, timeout):
method _check_open (line 274) | def _check_open(self, meth_name):
method _check_conn_validity (line 280) | def _check_conn_validity(self, meth_name):
method __del__ (line 284) | def __del__(self):
FILE: asyncpg/protocol/protocol.pyi
class ConnectionSettings (line 43) | class ConnectionSettings(asyncpg.pgproto.pgproto.CodecContext):
method __init__ (line 45) | def __init__(self, conn_key: object) -> None: ...
method add_python_codec (line 46) | def add_python_codec(
method clear_type_cache (line 57) | def clear_type_cache(self) -> None: ...
method get_data_codec (line 58) | def get_data_codec(
method get_text_codec (line 61) | def get_text_codec(self) -> CodecInfo: ...
method register_data_types (line 62) | def register_data_types(self, types: Iterable[object]) -> None: ...
method remove_python_codec (line 63) | def remove_python_codec(
method set_builtin_type_codec (line 66) | def set_builtin_type_codec(
method __getattr__ (line 75) | def __getattr__(self, name: str) -> Any: ...
method __reduce__ (line 76) | def __reduce__(self) -> Any: ...
class PreparedStatementState (line 79) | class PreparedStatementState(Generic[_Record]):
method __init__ (line 88) | def __init__(
method _get_parameters (line 96) | def _get_parameters(self) -> tuple[Type, ...]: ...
method _get_attributes (line 97) | def _get_attributes(self) -> tuple[Attribute, ...]: ...
method _init_types (line 98) | def _init_types(self) -> set[int]: ...
method _init_codecs (line 99) | def _init_codecs(self) -> None: ...
method attach (line 100) | def attach(self) -> None: ...
method detach (line 101) | def detach(self) -> None: ...
method mark_closed (line 102) | def mark_closed(self) -> None: ...
method mark_unprepared (line 103) | def mark_unprepared(self) -> None: ...
method __reduce__ (line 104) | def __reduce__(self) -> Any: ...
class CoreProtocol (line 106) | class CoreProtocol:
method __init__ (line 110) | def __init__(self, addr: object, con_params: _ConnectionParameters) ->...
method is_in_transaction (line 111) | def is_in_transaction(self) -> bool: ...
method __reduce__ (line 112) | def __reduce__(self) -> Any: ...
class BaseProtocol (line 114) | class BaseProtocol(CoreProtocol, Generic[_Record]):
method __init__ (line 118) | def __init__(
method set_connection (line 126) | def set_connection(self, connection: object) -> None: ...
method get_server_pid (line 127) | def get_server_pid(self, *args: object, **kwargs: object) -> int: ...
method get_settings (line 128) | def get_settings(self, *args: object, **kwargs: object) -> ConnectionS...
method get_record_class (line 129) | def get_record_class(self) -> type[_Record]: ...
method abort (line 130) | def abort(self) -> None: ...
method bind (line 131) | async def bind(
method bind_execute (line 139) | async def bind_execute(
method bind_execute (line 149) | async def bind_execute(
method bind_execute (line 159) | async def bind_execute(
method bind_execute_many (line 168) | async def bind_execute_many(
method close (line 175) | async def close(self, timeout: _TimeoutType) -> None: ...
method _get_timeout (line 176) | def _get_timeout(self, timeout: _TimeoutType) -> float | None: ...
method _is_cancelling (line 177) | def _is_cancelling(self) -> bool: ...
method _wait_for_cancellation (line 178) | async def _wait_for_cancellation(self) -> None: ...
method close_statement (line 179) | async def close_statement(
method copy_in (line 182) | async def copy_in(self, *args: object, **kwargs: object) -> str: ...
method copy_out (line 183) | async def copy_out(self, *args: object, **kwargs: object) -> str: ...
method execute (line 184) | async def execute(self, *args: object, **kwargs: object) -> Any: ...
method is_closed (line 185) | def is_closed(self, *args: object, **kwargs: object) -> Any: ...
method is_connected (line 186) | def is_connected(self, *args: object, **kwargs: object) -> Any: ...
method data_received (line 187) | def data_received(self, data: object) -> None: ...
method connection_made (line 188) | def connection_made(self, transport: object) -> None: ...
method connection_lost (line 189) | def connection_lost(self, exc: Exception | None) -> None: ...
method pause_writing (line 190) | def pause_writing(self, *args: object, **kwargs: object) -> Any: ...
method prepare (line 192) | async def prepare(
method prepare (line 203) | async def prepare(
method close_portal (line 213) | async def close_portal(self, portal_name: str, timeout: _TimeoutType) ...
method query (line 214) | async def query(self, *args: object, **kwargs: object) -> str: ...
method resume_writing (line 215) | def resume_writing(self, *args: object, **kwargs: object) -> Any: ...
method __reduce__ (line 216) | def __reduce__(self) -> Any: ...
class Codec (line 219) | class Codec:
method __reduce__ (line 221) | def __reduce__(self) -> Any: ...
class DataCodecConfig (line 223) | class DataCodecConfig:
method __init__ (line 225) | def __init__(self) -> None: ...
method add_python_codec (line 226) | def add_python_codec(
method add_types (line 238) | def add_types(self, types: Iterable[object]) -> Any: ...
method clear_type_cache (line 239) | def clear_type_cache(self) -> None: ...
method declare_fallback_codec (line 240) | def declare_fallback_codec(self, oid: int, name: str, schema: str) -> ...
method remove_python_codec (line 241) | def remove_python_codec(
method set_builtin_type_codec (line 244) | def set_builtin_type_codec(
method __reduce__ (line 253) | def __reduce__(self) -> Any: ...
class Protocol (line 255) | class Protocol(BaseProtocol[_Record], asyncio.protocols.Protocol): ...
class Timer (line 257) | class Timer:
method __init__ (line 258) | def __init__(self, budget: float | None) -> None: ...
method __enter__ (line 259) | def __enter__(self) -> None: ...
method __exit__ (line 260) | def __exit__(self, et: object, e: object, tb: object) -> None: ...
method get_remaining_budget (line 261) | def get_remaining_budget(self) -> float: ...
method has_budget_greater_than (line 262) | def has_budget_greater_than(self, amount: float) -> bool: ...
class SCRAMAuthentication (line 265) | class SCRAMAuthentication:
FILE: asyncpg/protocol/record.pyi
class Record (line 13) | class Record:
method get (line 15) | def get(self, key: str) -> Any | None: ...
method get (line 17) | def get(self, key: str, default: _T) -> Any | _T: ...
method items (line 18) | def items(self) -> Iterator[tuple[str, Any]]: ...
method keys (line 19) | def keys(self) -> Iterator[str]: ...
method values (line 20) | def values(self) -> Iterator[Any]: ...
method __getitem__ (line 22) | def __getitem__(self, index: str) -> Any: ...
method __getitem__ (line 24) | def __getitem__(self, index: int) -> Any: ...
method __getitem__ (line 26) | def __getitem__(self, index: slice) -> tuple[Any, ...]: ...
method __iter__ (line 27) | def __iter__(self) -> Iterator[Any]: ...
method __contains__ (line 28) | def __contains__(self, x: object) -> bool: ...
method __len__ (line 29) | def __len__(self) -> int: ...
FILE: asyncpg/protocol/record/pythoncapi_compat.h
function PyObject (line 64) | static inline PyObject* _Py_NewRef(PyObject *obj)
function PyObject (line 75) | static inline PyObject* _Py_XNewRef(PyObject *obj)
function _Py_SET_REFCNT (line 86) | static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
function _Py_SET_TYPE (line 133) | static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
function _Py_SET_SIZE (line 143) | static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
function PyCodeObject (line 153) | static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
function PyCodeObject (line 161) | static inline PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame)
function PyFrameObject (line 171) | static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame)
function PyFrameObject (line 179) | static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame)
function PyObject (line 190) | static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame)
function PyObject (line 206) | static inline PyObject* PyFrame_GetGlobals(PyFrameObject *frame)
function PyObject (line 215) | static inline PyObject* PyFrame_GetBuiltins(PyFrameObject *frame)
function PyFrame_GetLasti (line 224) | static inline int PyFrame_GetLasti(PyFrameObject *frame)
function PyObject (line 243) | static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *n...
function PyObject (line 276) | static inline PyObject*
function PyInterpreterState (line 297) | static inline PyInterpreterState *
function PyFrameObject (line 308) | static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
function PyFrameObject (line 316) | static inline PyFrameObject*
function PyInterpreterState (line 328) | static inline PyInterpreterState* PyInterpreterState_Get(void)
function PyThreadState_GetID (line 348) | static inline uint64_t PyThreadState_GetID(PyThreadState *tstate)
function PyThreadState_EnterTracing (line 357) | static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
function PyThreadState_LeaveTracing (line 370) | static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
function PyObject (line 387) | static inline PyObject* PyObject_CallNoArgs(PyObject *func)
function PyObject (line 398) | static inline PyObject* PyObject_CallOneArg(PyObject *func, PyObject *arg)
function PyModule_AddObjectRef (line 407) | static inline int
function PyModule_AddType (line 432) | static inline int PyModule_AddType(PyObject *module, PyTypeObject *type)
function PyObject_GC_IsTracked (line 456) | static inline int PyObject_GC_IsTracked(PyObject* obj)
function PyObject_GC_IsFinalized (line 465) | static inline int PyObject_GC_IsFinalized(PyObject *obj)
function _Py_IS_TYPE (line 475) | static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
function PyFloat_Pack2 (line 487) | static inline int PyFloat_Pack2(double x, char *p, int le)
function PyFloat_Unpack2 (line 490) | static inline double PyFloat_Unpack2(const char *p, int le)
function PyFloat_Pack4 (line 501) | static inline int PyFloat_Pack4(double x, char *p, int le)
function PyFloat_Pack8 (line 504) | static inline int PyFloat_Pack8(double x, char *p, int le)
function PyFloat_Unpack4 (line 507) | static inline double PyFloat_Unpack4(const char *p, int le)
function PyFloat_Unpack8 (line 510) | static inline double PyFloat_Unpack8(const char *p, int le)
function PyObject (line 517) | static inline PyObject* PyCode_GetCode(PyCodeObject *code)
function PyObject (line 526) | static inline PyObject* PyCode_GetVarnames(PyCodeObject *code)
function PyObject (line 534) | static inline PyObject* PyCode_GetFreevars(PyCodeObject *code)
function PyObject (line 542) | static inline PyObject* PyCode_GetCellvars(PyCodeObject *code)
function PyObject (line 561) | static inline PyObject* PyImport_AddModuleRef(const char *name)
function PyWeakref_GetRef (line 570) | static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
function Py_ssize_t (line 601) | static inline Py_ssize_t PyVectorcall_NARGS(size_t n)
function PyObject (line 610) | static inline PyObject*
function PyObject_GetOptionalAttr (line 686) | static inline int
function PyObject_GetOptionalAttrString (line 708) | static inline int
function PyMapping_GetOptionalItem (line 732) | static inline int
function PyMapping_GetOptionalItemString (line 746) | static inline int
function PyMapping_HasKeyWithError (line 769) | static inline int
function PyMapping_HasKeyStringWithError (line 778) | static inline int
function PyObject_HasAttrWithError (line 792) | static inline int
function PyObject_HasAttrStringWithError (line 801) | static inline int
function PyDict_GetItemRef (line 815) | static inline int
function PyDict_GetItemStringRef (line 835) | static inline int
function PyModule_Add (line 857) | static inline int
function Py_IsFinalizing (line 872) | static inline int Py_IsFinalizing(void)
function PyDict_ContainsString (line 886) | static inline int PyDict_ContainsString(PyObject *op, const char *key)
function PyLong_AsInt (line 901) | static inline int PyLong_AsInt(PyObject *obj)
function PyObject_VisitManagedDict (line 923) | static inline int
function PyObject_ClearManagedDict (line 934) | static inline void
function PyThreadState (line 948) | static inline PyThreadState*
function PyUnicode_EqualToUTF8AndSize (line 958) | static inline int
function PyUnicode_EqualToUTF8 (line 1021) | static inline int
function PyList_Extend (line 1031) | static inline int
function PyList_Clear (line 1037) | static inline int
function PyDict_Pop (line 1046) | static inline int
function PyDict_PopString (line 1088) | static inline int
type Py_ssize_t (line 1108) | typedef Py_ssize_t Py_hash_t;
function Py_hash_t (line 1114) | static inline Py_hash_t Py_HashPointer(const void *ptr)
type _PyTime_t (line 1128) | typedef _PyTime_t PyTime_t;
function PyTime_AsSecondsDouble (line 1132) | static inline double PyTime_AsSecondsDouble(PyTime_t t)
function PyTime_Monotonic (line 1135) | static inline int PyTime_Monotonic(PyTime_t *result)
function PyTime_Time (line 1138) | static inline int PyTime_Time(PyTime_t *result)
function PyTime_PerfCounter (line 1141) | static inline int PyTime_PerfCounter(PyTime_t *result)
function PyObject (line 1240) | static inline PyObject* Py_GetConstant(unsigned int constant_id)
function PyObject (line 1293) | static inline PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
function PyObject (line 1304) | static inline PyObject *
function PyDict_SetDefaultRef (line 1316) | static inline int
type PyUnicodeWriter (line 1362) | typedef struct PyUnicodeWriter PyUnicodeWriter;
function PyUnicodeWriter_Discard (line 1364) | static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
function PyUnicodeWriter (line 1370) | static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length)
function PyObject (line 1395) | static inline PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
function PyUnicodeWriter_WriteChar (line 1403) | static inline int
function PyUnicodeWriter_WriteStr (line 1415) | static inline int
function PyUnicodeWriter_WriteRepr (line 1428) | static inline int
function PyUnicodeWriter_WriteUTF8 (line 1441) | static inline int
function PyUnicodeWriter_WriteASCII (line 1459) | static inline int
function PyUnicodeWriter_WriteWideChar (line 1471) | static inline int
function PyUnicodeWriter_WriteSubstring (line 1489) | static inline int
function PyUnicodeWriter_Format (line 1511) | static inline int
function PyLong_GetSign (line 1530) | static inline int PyLong_GetSign(PyObject *obj, int *sign)
function PyLong_IsPositive (line 1544) | static inline int PyLong_IsPositive(PyObject *obj)
function PyLong_IsNegative (line 1553) | static inline int PyLong_IsNegative(PyObject *obj)
function PyLong_IsZero (line 1562) | static inline int PyLong_IsZero(PyObject *obj)
function PyUnicode_Equal (line 1575) | static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
function PyObject (line 1605) | static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable)
function Py_hash_t (line 1613) | static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
function PyIter_NextItem (line 1634) | static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
function PyObject (line 1665) | static inline PyObject* PyLong_FromInt32(int32_t value)
function PyObject (line 1671) | static inline PyObject* PyLong_FromInt64(int64_t value)
function PyObject (line 1677) | static inline PyObject* PyLong_FromUInt32(uint32_t value)
function PyObject (line 1683) | static inline PyObject* PyLong_FromUInt64(uint64_t value)
function PyLong_AsInt32 (line 1689) | static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
function PyLong_AsInt64 (line 1700) | static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
function PyLong_AsUInt32 (line 1711) | static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
function PyLong_AsUInt64 (line 1729) | static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
function _PyLong_SetSignAndDigitCount (line 1745) | static inline void
function Py_ssize_t (line 1757) | static inline Py_ssize_t
function digit (line 1767) | static inline digit*
type PyLongLayout (line 1777) | typedef struct PyLongLayout {
type PyLongExport (line 1784) | typedef struct PyLongExport {
type PyLongWriter (line 1792) | typedef struct PyLongWriter PyLongWriter;
function PyLongLayout (line 1794) | static inline const PyLongLayout*
function PyLong_Export (line 1807) | static inline int
function PyLong_FreeExport (line 1850) | static inline void
function PyLongWriter (line 1861) | static inline PyLongWriter*
function PyLongWriter_Discard (line 1880) | static inline void
function PyObject (line 1889) | static inline PyObject*
function FILE (line 1954) | static inline FILE* Py_fopen(PyObject *path, const char *mode)
function Py_fclose (line 1987) | static inline int Py_fclose(FILE *file)
function PyObject (line 1995) | static inline PyObject*
function PyConfig_GetInt (line 2187) | static inline int
function PyUnstable_Object_IsUniquelyReferenced (line 2217) | static inline int PyUnstable_Object_IsUniquelyReferenced(PyObject *obj)
function PyObject (line 2234) | static inline PyObject*
function PyObject (line 2251) | static inline PyObject*
function PySys_GetOptionalAttrString (line 2266) | static inline int
function PySys_GetOptionalAttr (line 2280) | static inline int
type PyBytesWriter (line 2299) | typedef struct PyBytesWriter {
function Py_ssize_t (line 2305) | static inline Py_ssize_t
function _PyBytesWriter_Resize_impl (line 2317) | static inline int
function Py_ssize_t (line 2375) | static inline Py_ssize_t
function PyBytesWriter_Discard (line 2381) | static inline void
function PyBytesWriter (line 2392) | static inline PyBytesWriter*
function PyObject (line 2419) | static inline PyObject*
function PyObject (line 2446) | static inline PyObject*
function PyObject (line 2452) | static inline PyObject*
function PyBytesWriter_Resize (line 2465) | static inline int
function PyBytesWriter_Grow (line 2479) | static inline int
function PyBytesWriter_WriteBytes (line 2510) | static inline int
function PyBytesWriter_Format (line 2536) | static inline int
FILE: asyncpg/protocol/record/pythoncapi_compat_extras.h
function PyObject (line 12) | PyObject *
FILE: asyncpg/protocol/record/recordobj.c
type record_freelist_state (line 30) | typedef struct {
type record_module_state (line 35) | typedef struct {
function record_module_state (line 44) | static inline record_module_state *
function record_module_state (line 55) | static inline record_module_state *
type PyModuleDef (line 68) | struct PyModuleDef
function record_module_state (line 70) | static inline record_module_state *
function record_freelist_state (line 79) | static inline record_freelist_state *
function PyObject (line 102) | PyObject *
function record_dealloc (line 170) | static void
function record_traverse (line 216) | static int
function Py_hash_t (line 244) | static Py_hash_t
function Py_ssize_t (line 272) | static Py_ssize_t
function record_contains (line 279) | static int
function PyObject (line 289) | static PyObject *
function PyObject (line 300) | static PyObject *
type item_by_name_result_t (line 422) | typedef enum item_by_name_result {
function item_by_name_result_t (line 431) | static item_by_name_result_t
function PyObject (line 476) | static PyObject *
function PyObject (line 546) | static PyObject *
function PyObject (line 625) | static PyObject *
function PyObject (line 639) | static PyObject *
function PyObject (line 652) | static PyObject *
function PyObject (line 663) | static PyObject *
function PyObject (line 676) | static PyObject *
function PyObject (line 712) | static PyObject *
type ApgRecordIterObject (line 773) | typedef struct {
function record_iter_dealloc (line 778) | static void
function record_iter_traverse (line 788) | static int
function PyObject (line 795) | static PyObject *
function PyObject (line 818) | static PyObject *
function PyObject (line 852) | static PyObject *
type ApgRecordItemsObject (line 868) | typedef struct {
function record_items_dealloc (line 874) | static void
function record_items_traverse (line 885) | static int
function PyObject (line 893) | static PyObject *
function PyObject (line 942) | static PyObject *
function PyObject (line 976) | static PyObject *
function record_desc_dealloc (line 1003) | static void
function record_desc_traverse (line 1014) | static int
function PyObject (line 1022) | static PyObject *
function PyObject (line 1066) | static PyObject *
function PyObject (line 1091) | static PyObject *
function record_module_exec (line 1163) | static int
function record_module_traverse (line 1204) | static int
function record_module_clear (line 1220) | static int
function record_module_free (line 1257) | static void
type PyModuleDef (line 1274) | struct PyModuleDef
function PyMODINIT_FUNC (line 1285) | PyMODINIT_FUNC
FILE: asyncpg/protocol/record/recordobj.h
type ApgRecordDescObject (line 7) | typedef struct {
type ApgRecordObject (line 14) | typedef struct {
FILE: asyncpg/serverversion.py
class _VersionDict (line 24) | class _VersionDict(typing.TypedDict):
function split_server_version_string (line 32) | def split_server_version_string(version_string: str) -> ServerVersion:
FILE: asyncpg/transaction.py
class TransactionState (line 14) | class TransactionState(enum.Enum):
class Transaction (line 36) | class Transaction(connresource.ConnectionResource):
method __init__ (line 47) | def __init__(self, connection, isolation, readonly, deferrable):
method __aenter__ (line 63) | async def __aenter__(self):
method __aexit__ (line 70) | async def __aexit__(self, extype, ex, tb):
method start (line 96) | async def start(self):
method __check_state_base (line 153) | def __check_state_base(self, opname):
method __check_state (line 167) | def __check_state(self, opname):
method __commit (line 175) | async def __commit(self):
method __rollback (line 194) | async def __rollback(self):
method commit (line 214) | async def commit(self):
method rollback (line 222) | async def rollback(self):
method __repr__ (line 229) | def __repr__(self):
FILE: asyncpg/types.py
class Type (line 26) | class Type(typing.NamedTuple):
class Attribute (line 41) | class Attribute(typing.NamedTuple):
class ServerVersion (line 51) | class ServerVersion(typing.NamedTuple):
class _RangeValue (line 62) | class _RangeValue(typing.Protocol):
method __eq__ (line 63) | def __eq__(self, __value: object) -> bool:
method __lt__ (line 66) | def __lt__(self, __other: Self, /) -> bool:
method __gt__ (line 69) | def __gt__(self, __other: Self, /) -> bool:
class Range (line 76) | class Range(typing.Generic[_RV]):
method __init__ (line 87) | def __init__(
method lower (line 107) | def lower(self) -> _RV | None:
method lower_inc (line 111) | def lower_inc(self) -> bool:
method lower_inf (line 115) | def lower_inf(self) -> bool:
method upper (line 119) | def upper(self) -> _RV | None:
method upper_inc (line 123) | def upper_inc(self) -> bool:
method upper_inf (line 127) | def upper_inf(self) -> bool:
method isempty (line 131) | def isempty(self) -> bool:
method _issubset_lower (line 134) | def _issubset_lower(self, other: Self) -> bool:
method _issubset_upper (line 145) | def _issubset_upper(self, other: Self) -> bool:
method issubset (line 156) | def issubset(self, other: Self) -> bool:
method issuperset (line 164) | def issuperset(self, other: Self) -> bool:
method __bool__ (line 167) | def __bool__(self) -> bool:
method __eq__ (line 170) | def __eq__(self, other: object) -> bool:
method __hash__ (line 188) | def __hash__(self) -> int:
method __repr__ (line 197) | def __repr__(self) -> str:
FILE: asyncpg/utils.py
function _quote_ident (line 11) | def _quote_ident(ident):
function _quote_literal (line 15) | def _quote_literal(string):
function _mogrify (line 19) | async def _mogrify(conn, query, args):
FILE: setup.py
function git_commitish (line 60) | def git_commitish():
class VersionMixin (line 78) | class VersionMixin:
method _fix_version (line 80) | def _fix_version(self, filename):
class sdist (line 95) | class sdist(setuptools_sdist.sdist, VersionMixin):
method make_release_tree (line 97) | def make_release_tree(self, base_dir, files):
class build_py (line 102) | class build_py(setuptools_build_py.build_py, VersionMixin):
method build_module (line 104) | def build_module(self, module, module_file, package):
class build_ext (line 113) | class build_ext(setuptools_build_ext.build_ext):
method initialize_options (line 124) | def initialize_options(self):
method finalize_options (line 153) | def finalize_options(self):
FILE: tests/__init__.py
function suite (line 13) | def suite():
FILE: tests/certs/gen.py
function _new_cert (line 12) | def _new_cert(issuer=None, is_issuer=False, serial_number=None, **subject):
function _write_cert (line 132) | def _write_cert(path, cert_key_pair, password=None):
function new_ca (line 154) | def new_ca(path, **subject):
function new_cert (line 160) | def new_cert(
function new_crl (line 170) | def new_crl(path, issuer, cert):
function main (line 190) | def main():
FILE: tests/test__environment.py
class TestEnvironment (line 17) | class TestEnvironment(tb.ConnectedTestCase):
method test_environment_server_version (line 20) | async def test_environment_server_version(self):
method test_environment_asyncpg_version (line 35) | async def test_environment_asyncpg_version(self):
FILE: tests/test__sourcecode.py
function find_root (line 13) | def find_root():
class TestCodeQuality (line 17) | class TestCodeQuality(unittest.TestCase):
method test_flake8 (line 19) | def test_flake8(self):
method test_mypy (line 42) | def test_mypy(self):
FILE: tests/test_adversity.py
class TestConnectionLoss (line 21) | class TestConnectionLoss(tb.ProxiedClusterTestCase):
method test_connection_close_timeout (line 23) | async def test_connection_close_timeout(self):
method test_pool_acquire_timeout (line 30) | async def test_pool_acquire_timeout(self):
method test_pool_release_timeout (line 47) | async def test_pool_release_timeout(self):
method test_pool_handles_abrupt_connection_loss (line 59) | async def test_pool_handles_abrupt_connection_loss(self):
FILE: tests/test_cache_invalidation.py
class TestCacheInvalidation (line 15) | class TestCacheInvalidation(tb.ConnectedTestCase):
method _get_cached_statements (line 17) | def _get_cached_statements(self, connection=None):
method _check_statements_are_not_closed (line 22) | def _check_statements_are_not_closed(self, statements):
method _check_statements_are_closed (line 26) | def _check_statements_are_closed(self, statements):
method test_prepare_cache_invalidation_silent (line 30) | async def test_prepare_cache_invalidation_silent(self):
method test_prepare_cache_invalidation_in_transaction (line 51) | async def test_prepare_cache_invalidation_in_transaction(self):
method test_prepare_cache_invalidation_in_pool (line 78) | async def test_prepare_cache_invalidation_in_pool(self):
method test_type_cache_invalidation_in_transaction (line 125) | async def test_type_cache_invalidation_in_transaction(self):
method test_type_cache_invalidation_in_cancelled_transaction (line 156) | async def test_type_cache_invalidation_in_cancelled_transaction(self):
method test_prepared_type_cache_invalidation (line 195) | async def test_prepared_type_cache_invalidation(self):
method test_type_cache_invalidation_on_drop_type_attr (line 250) | async def test_type_cache_invalidation_on_drop_type_attr(self):
method test_type_cache_invalidation_on_change_attr (line 278) | async def test_type_cache_invalidation_on_change_attr(self):
method test_type_cache_invalidation_in_pool (line 309) | async def test_type_cache_invalidation_in_pool(self):
FILE: tests/test_cancellation.py
class TestCancellation (line 14) | class TestCancellation(tb.ConnectedTestCase):
method test_cancellation_01 (line 16) | async def test_cancellation_01(self):
method test_cancellation_02 (line 67) | async def test_cancellation_02(self):
method test_cancellation_03 (line 74) | async def test_cancellation_03(self):
method test_cancellation_04 (line 91) | async def test_cancellation_04(self):
FILE: tests/test_codecs.py
function _timezone (line 23) | def _timezone(offset):
function _system_timezone (line 28) | def _system_timezone():
class TestCodecs (line 468) | class TestCodecs(tb.ConnectedTestCase):
method test_standard_codecs (line 470) | async def test_standard_codecs(self):
method test_all_builtin_types_handled (line 546) | async def test_all_builtin_types_handled(self):
method test_void (line 555) | async def test_void(self):
method test_bitstring (line 560) | def test_bitstring(self):
method test_interval (line 587) | async def test_interval(self):
method test_numeric (line 600) | async def test_numeric(self):
method test_unhandled_type_fallback (line 667) | async def test_unhandled_type_fallback(self):
method test_invalid_input (line 687) | async def test_invalid_input(self):
method test_arrays (line 791) | async def test_arrays(self):
method test_composites (line 897) | async def test_composites(self):
method test_domains (line 976) | async def test_domains(self):
method test_range_types (line 1011) | async def test_range_types(self):
method test_multirange_types (line 1060) | async def test_multirange_types(self):
method test_extra_codec_alias (line 1113) | async def test_extra_codec_alias(self):
method test_custom_codec_text (line 1186) | async def test_custom_codec_text(self):
method test_custom_codec_binary (line 1240) | async def test_custom_codec_binary(self):
method test_custom_codec_on_domain (line 1320) | async def test_custom_codec_on_domain(self):
method test_custom_codec_on_stdsql_types (line 1338) | async def test_custom_codec_on_stdsql_types(self):
method test_custom_codec_on_enum (line 1371) | async def test_custom_codec_on_enum(self):
method test_custom_codec_on_enum_array (line 1388) | async def test_custom_codec_on_enum_array(self):
method test_custom_codec_override_binary (line 1416) | async def test_custom_codec_override_binary(self):
method test_custom_codec_override_text (line 1440) | async def test_custom_codec_override_text(self):
method test_custom_codec_override_tuple (line 1487) | async def test_custom_codec_override_tuple(self):
method test_custom_codec_composite_tuple (line 1547) | async def test_custom_codec_composite_tuple(self):
method test_custom_codec_composite_non_tuple (line 1574) | async def test_custom_codec_composite_non_tuple(self):
method test_timetz_encoding (line 1594) | async def test_timetz_encoding(self):
method test_composites_in_arrays (line 1615) | async def test_composites_in_arrays(self):
method test_table_as_composite (line 1637) | async def test_table_as_composite(self):
method test_relacl_array_type (line 1655) | async def test_relacl_array_type(self):
method test_enum (line 1744) | async def test_enum(self):
method test_unknown_type_text_fallback (line 1769) | async def test_unknown_type_text_fallback(self):
method test_enum_in_array (line 1853) | async def test_enum_in_array(self):
method test_enum_and_range (line 1873) | async def test_enum_and_range(self):
method test_enum_in_composite (line 1898) | async def test_enum_in_composite(self):
method test_enum_function_return (line 1916) | async def test_enum_function_return(self):
method test_no_result (line 1937) | async def test_no_result(self):
method test_array_with_custom_json_text_codec (line 1941) | async def test_array_with_custom_json_text_codec(self):
class TestCodecsLargeOIDs (line 1980) | class TestCodecsLargeOIDs(tb.ConnectedTestCase):
method setup_cluster (line 1984) | def setup_cluster(cls):
method test_custom_codec_large_oid (line 1989) | async def test_custom_codec_large_oid(self):
FILE: tests/test_connect.py
function mock_dot_postgresql (line 60) | def mock_dot_postgresql(*, ca=True, crl=False, client=False, protected=F...
function mock_no_home_dir (line 86) | def mock_no_home_dir():
function mock_dev_null_home_dir (line 94) | def mock_dev_null_home_dir():
class TestSettings (line 102) | class TestSettings(tb.ConnectedTestCase):
method test_get_settings_01 (line 104) | async def test_get_settings_01(self):
method test_server_version_01 (line 109) | async def test_server_version_01(self):
method test_server_version_02 (line 119) | def test_server_version_02(self):
class BaseTestAuthentication (line 143) | class BaseTestAuthentication(tb.ConnectedTestCase):
method setUp (line 146) | def setUp(self):
method tearDown (line 202) | def tearDown(self):
class TestAuthentication (line 219) | class TestAuthentication(BaseTestAuthentication):
method _try_connect (line 228) | async def _try_connect(self, **kwargs):
method test_auth_bad_user (line 241) | async def test_auth_bad_user(self):
method test_auth_trust (line 246) | async def test_auth_trust(self):
method test_auth_reject (line 250) | async def test_auth_reject(self):
method test_auth_password_cleartext (line 256) | async def test_auth_password_cleartext(self):
method test_auth_password_cleartext_callable (line 269) | async def test_auth_password_cleartext_callable(self):
method test_auth_password_cleartext_callable_coroutine (line 288) | async def test_auth_password_cleartext_callable_coroutine(self):
method test_auth_password_cleartext_callable_awaitable (line 307) | async def test_auth_password_cleartext_callable_awaitable(self):
method test_auth_password_md5 (line 326) | async def test_auth_password_md5(self):
method test_auth_password_scram_sha_256 (line 337) | async def test_auth_password_scram_sha_256(self):
method test_auth_md5_unsupported (line 385) | async def test_auth_md5_unsupported(self, _):
class TestGssAuthentication (line 397) | class TestGssAuthentication(BaseTestAuthentication):
method setUpClass (line 399) | def setUpClass(cls):
method get_server_settings (line 424) | def get_server_settings(cls):
method setup_cluster (line 430) | def setup_cluster(cls):
method test_auth_gssapi_ok (line 435) | async def test_auth_gssapi_ok(self):
method test_auth_gssapi_bad_srvname (line 439) | async def test_auth_gssapi_bad_srvname(self):
method test_auth_gssapi_bad_user (line 447) | async def test_auth_gssapi_bad_user(self):
class TestSspiAuthentication (line 457) | class TestSspiAuthentication(BaseTestAuthentication):
method setUpClass (line 459) | def setUpClass(cls):
method test_auth_sspi (line 467) | async def test_auth_sspi(self):
class TestConnectParams (line 479) | class TestConnectParams(tb.TestCase):
method environ (line 1109) | def environ(self, **kwargs):
method run_testcase (line 1131) | def run_testcase(self, testcase):
method test_test_connect_params_environ (line 1213) | def test_test_connect_params_environ(self):
method test_test_connect_params_run_testcase (line 1240) | def test_test_connect_params_run_testcase(self):
method test_connect_params (line 1255) | def test_connect_params(self):
method test_connect_connection_service_file (line 1259) | def test_connect_connection_service_file(self):
method test_connect_pgpass_regular (line 1364) | def test_connect_pgpass_regular(self):
method test_connect_pgpass_badness_mode (line 1538) | def test_connect_pgpass_badness_mode(self):
method test_connect_pgpass_badness_non_file (line 1562) | def test_connect_pgpass_badness_non_file(self):
method test_connect_pgpass_nonexistent (line 1583) | def test_connect_pgpass_nonexistent(self):
method test_connect_pgpass_inaccessible_file (line 1601) | def test_connect_pgpass_inaccessible_file(self):
method test_connect_pgpass_inaccessible_directory (line 1622) | def test_connect_pgpass_inaccessible_directory(self):
method test_connect_args_validation (line 1646) | async def test_connect_args_validation(self):
class TestConnection (line 1659) | class TestConnection(tb.ConnectedTestCase):
method test_connection_isinstance (line 1661) | async def test_connection_isinstance(self):
method test_connection_use_after_close (line 1666) | async def test_connection_use_after_close(self):
method test_connection_ssl_to_no_ssl_server (line 1698) | async def test_connection_ssl_to_no_ssl_server(self):
method test_connection_sslmode_no_ssl_server (line 1709) | async def test_connection_sslmode_no_ssl_server(self):
method test_connection_implicit_host (line 1747) | async def test_connection_implicit_host(self):
method test_connection_no_home_dir (line 1756) | async def test_connection_no_home_dir(self):
class BaseTestSSLConnection (line 1796) | class BaseTestSSLConnection(tb.ConnectedTestCase):
method get_server_settings (line 1798) | def get_server_settings(cls):
method setup_cluster (line 1813) | def setup_cluster(cls):
method setUp (line 1818) | def setUp(self):
method tearDown (line 1835) | def tearDown(self):
method _add_hba_entry (line 1847) | def _add_hba_entry(self):
class TestSSLConnection (line 1852) | class TestSSLConnection(BaseTestSSLConnection):
method _add_hba_entry (line 1853) | def _add_hba_entry(self):
method test_ssl_connection_custom_context (line 1864) | async def test_ssl_connection_custom_context(self):
method test_ssl_connection_sslmode (line 1883) | async def test_ssl_connection_sslmode(self):
method test_ssl_connection_default_context (line 1943) | async def test_ssl_connection_default_context(self):
method test_ssl_connection_pool (line 1956) | async def test_ssl_connection_pool(self):
method test_executemany_uvloop_ssl_issue_700 (line 1981) | async def test_executemany_uvloop_ssl_issue_700(self):
method test_tls_version (line 2005) | async def test_tls_version(self):
class TestClientSSLConnection (line 2058) | class TestClientSSLConnection(BaseTestSSLConnection):
method _add_hba_entry (line 2059) | def _add_hba_entry(self):
method test_ssl_connection_client_auth_fails_with_wrong_setup (line 2070) | async def test_ssl_connection_client_auth_fails_with_wrong_setup(self):
method _test_works (line 2086) | async def _test_works(self, **conn_args):
method test_ssl_connection_client_auth_custom_context (line 2094) | async def test_ssl_connection_client_auth_custom_context(self):
method test_ssl_connection_client_auth_dsn (line 2111) | async def test_ssl_connection_client_auth_dsn(self):
method test_ssl_connection_client_auth_env (line 2128) | async def test_ssl_connection_client_auth_env(self):
method test_ssl_connection_client_auth_dot_postgresql (line 2142) | async def test_ssl_connection_client_auth_dot_postgresql(self):
class TestNoSSLConnection (line 2151) | class TestNoSSLConnection(BaseTestSSLConnection):
method _add_hba_entry (line 2152) | def _add_hba_entry(self):
method test_nossl_connection_sslmode (line 2163) | async def test_nossl_connection_sslmode(self):
method test_nossl_connection_prefer_cancel (line 2205) | async def test_nossl_connection_prefer_cancel(self):
method test_nossl_connection_pool (line 2219) | async def test_nossl_connection_pool(self):
class TestConnectionGC (line 2243) | class TestConnectionGC(tb.ClusterTestCase):
method _run_no_explicit_close_test (line 2245) | async def _run_no_explicit_close_test(self):
method test_no_explicit_close_no_debug (line 2268) | async def test_no_explicit_close_no_debug(self):
method test_no_explicit_close_with_debug (line 2279) | async def test_no_explicit_close_with_debug(self):
class TestConnectionAttributes (line 2294) | class TestConnectionAttributes(tb.HotStandbyTestCase):
method _run_connection_test (line 2296) | async def _run_connection_test(
method test_target_server_attribute_port (line 2303) | async def test_target_server_attribute_port(self):
method test_target_attribute_not_matched (line 2327) | async def test_target_attribute_not_matched(self):
method test_prefer_standby_when_standby_is_up (line 2348) | async def test_prefer_standby_when_standby_is_up(self):
method test_prefer_standby_picks_master_when_standby_is_down (line 2355) | async def test_prefer_standby_picks_master_when_standby_is_down(self):
function _get_connected_host (line 2375) | def _get_connected_host(con):
FILE: tests/test_copy.py
class TestCopyFrom (line 19) | class TestCopyFrom(tb.ConnectedTestCase):
method test_copy_from_table_basics (line 21) | async def test_copy_from_table_basics(self):
method test_copy_from_table_large_rows (line 85) | async def test_copy_from_table_large_rows(self):
method test_copy_from_query_basics (line 120) | async def test_copy_from_query_basics(self):
method test_copy_from_query_with_args (line 146) | async def test_copy_from_query_with_args(self):
method test_copy_from_query_to_path (line 171) | async def test_copy_from_query_to_path(self):
method test_copy_from_query_to_path_like (line 193) | async def test_copy_from_query_to_path_like(self):
method test_copy_from_query_to_bad_output (line 223) | async def test_copy_from_query_to_bad_output(self):
method test_copy_from_query_to_sink (line 234) | async def test_copy_from_query_to_sink(self):
method test_copy_from_query_cancellation_explicit (line 261) | async def test_copy_from_query_cancellation_explicit(self):
method test_copy_from_query_cancellation_on_sink_error (line 283) | async def test_copy_from_query_cancellation_on_sink_error(self):
method test_copy_from_query_cancellation_while_waiting_for_data (line 302) | async def test_copy_from_query_cancellation_while_waiting_for_data(self):
method test_copy_from_query_timeout_1 (line 322) | async def test_copy_from_query_timeout_1(self):
method test_copy_from_query_timeout_2 (line 340) | async def test_copy_from_query_timeout_2(self):
class TestCopyTo (line 364) | class TestCopyTo(tb.ConnectedTestCase):
method test_copy_to_table_basics (line 366) | async def test_copy_to_table_basics(self):
method test_copy_to_table_large_rows (line 462) | async def test_copy_to_table_large_rows(self):
method test_copy_to_table_from_bytes_like (line 489) | async def test_copy_to_table_from_bytes_like(self):
method test_copy_to_table_fail_in_source_1 (line 501) | async def test_copy_to_table_fail_in_source_1(self):
method test_copy_to_table_fail_in_source_2 (line 526) | async def test_copy_to_table_fail_in_source_2(self):
method test_copy_to_table_timeout (line 555) | async def test_copy_to_table_timeout(self):
method test_copy_to_table_from_file_path (line 584) | async def test_copy_to_table_from_file_path(self):
method test_copy_records_to_table_1 (line 626) | async def test_copy_records_to_table_1(self):
method test_copy_records_to_table_where (line 650) | async def test_copy_records_to_table_where(self):
method test_copy_records_to_table_async (line 679) | async def test_copy_records_to_table_async(self):
method test_copy_records_to_table_no_binary_codec (line 703) | async def test_copy_records_to_table_no_binary_codec(self):
FILE: tests/test_cursor.py
class TestIterableCursor (line 14) | class TestIterableCursor(tb.ConnectedTestCase):
method test_cursor_iterable_01 (line 16) | async def test_cursor_iterable_01(self):
method test_cursor_iterable_02 (line 31) | async def test_cursor_iterable_02(self):
method test_cursor_iterable_03 (line 51) | async def test_cursor_iterable_03(self):
method test_cursor_iterable_04 (line 65) | async def test_cursor_iterable_04(self):
method test_cursor_iterable_05 (line 74) | async def test_cursor_iterable_05(self):
method test_cursor_iterable_06 (line 83) | async def test_cursor_iterable_06(self):
class TestCursor (line 104) | class TestCursor(tb.ConnectedTestCase):
method test_cursor_01 (line 106) | async def test_cursor_01(self):
method test_cursor_02 (line 112) | async def test_cursor_02(self):
method test_cursor_03 (line 150) | async def test_cursor_03(self):
method test_cursor_04 (line 157) | async def test_cursor_04(self):
FILE: tests/test_exceptions.py
class TestExceptions (line 12) | class TestExceptions(tb.ConnectedTestCase):
method test_exceptions_exported (line 14) | def test_exceptions_exported(self):
method test_exceptions_unpacking (line 25) | async def test_exceptions_unpacking(self):
method test_exceptions_str (line 36) | async def test_exceptions_str(self):
FILE: tests/test_execute.py
class TestExecuteScript (line 15) | class TestExecuteScript(tb.ConnectedTestCase):
method test_execute_script_1 (line 17) | async def test_execute_script_1(self):
method test_execute_script_2 (line 29) | async def test_execute_script_2(self):
method test_execute_script_3 (line 43) | async def test_execute_script_3(self):
method test_execute_script_check_transactionality (line 52) | async def test_execute_script_check_transactionality(self):
method test_execute_exceptions_1 (line 66) | async def test_execute_exceptions_1(self):
method test_execute_script_interrupted_close (line 72) | async def test_execute_script_interrupted_close(self):
method test_execute_script_interrupted_terminate (line 85) | async def test_execute_script_interrupted_terminate(self):
class TestExecuteMany (line 102) | class TestExecuteMany(tb.ConnectedTestCase):
method setUp (line 103) | def setUp(self):
method tearDown (line 108) | def tearDown(self):
method test_executemany_basic (line 112) | async def test_executemany_basic(self):
method test_executemany_returning (line 142) | async def test_executemany_returning(self):
method test_executemany_bad_input (line 181) | async def test_executemany_bad_input(self):
method test_executemany_error_in_input_gen (line 200) | async def test_executemany_error_in_input_gen(self):
method test_executemany_server_failure (line 215) | async def test_executemany_server_failure(self):
method test_executemany_server_failure_after_writes (line 225) | async def test_executemany_server_failure_after_writes(self):
method test_executemany_server_failure_during_writes (line 235) | async def test_executemany_server_failure_during_writes(self):
method test_executemany_client_failure_after_writes (line 256) | async def test_executemany_client_failure_after_writes(self):
method test_executemany_timeout (line 264) | async def test_executemany_timeout(self):
method test_executemany_timeout_flow_control (line 272) | async def test_executemany_timeout_flow_control(self):
method test_executemany_client_failure_in_transaction (line 304) | async def test_executemany_client_failure_in_transaction(self):
method test_executemany_client_server_failure_conflict (line 319) | async def test_executemany_client_server_failure_conflict(self):
method test_executemany_prepare (line 328) | async def test_executemany_prepare(self):
FILE: tests/test_introspection.py
class SlowIntrospectionConnection (line 18) | class SlowIntrospectionConnection(apg_con.Connection):
method _introspect_types (line 22) | async def _introspect_types(self, *args, **kwargs):
class TestIntrospection (line 28) | class TestIntrospection(tb.ConnectedTestCase):
method setUpClass (line 30) | def setUpClass(cls):
method tearDownClass (line 37) | def tearDownClass(cls):
method get_server_settings (line 47) | def get_server_settings(cls):
method setUp (line 52) | def setUp(self):
method _add_custom_codec (line 56) | async def _add_custom_codec(self, conn):
method test_introspection_on_large_db (line 67) | async def test_introspection_on_large_db(self):
method test_introspection_no_stmt_cache_01 (line 82) | async def test_introspection_no_stmt_cache_01(self):
method test_introspection_no_stmt_cache_02 (line 103) | async def test_introspection_no_stmt_cache_02(self):
method test_introspection_no_stmt_cache_03 (line 125) | async def test_introspection_no_stmt_cache_03(self):
method test_introspection_sticks_for_ps (line 135) | async def test_introspection_sticks_for_ps(self):
method test_introspection_retries_after_cache_bust (line 160) | async def test_introspection_retries_after_cache_bust(self):
method test_introspection_loads_basetypes_of_domains (line 201) | async def test_introspection_loads_basetypes_of_domains(self):
FILE: tests/test_listeners.py
class TestListeners (line 17) | class TestListeners(tb.ClusterTestCase):
method test_listen_01 (line 19) | async def test_listen_01(self):
method test_listen_02 (line 72) | async def test_listen_02(self):
method test_listen_notletters (line 90) | async def test_listen_notletters(self):
method test_dangling_listener_warns (line 108) | async def test_dangling_listener_warns(self):
class TestLogListeners (line 121) | class TestLogListeners(tb.ConnectedTestCase):
method test_log_listener_01 (line 126) | async def test_log_listener_01(self):
method test_log_listener_02 (line 230) | async def test_log_listener_02(self):
method test_log_listener_03 (line 271) | async def test_log_listener_03(self):
method test_dangling_log_listener_warns (line 301) | async def test_dangling_log_listener_warns(self):
class TestConnectionTerminationListener (line 318) | class TestConnectionTerminationListener(tb.ProxiedClusterTestCase):
method test_connection_termination_callback_called_on_remote (line 320) | async def test_connection_termination_callback_called_on_remote(self):
method test_connection_termination_callback_called_on_local (line 344) | async def test_connection_termination_callback_called_on_local(self):
FILE: tests/test_logging.py
class LogCollector (line 7) | class LogCollector:
method __init__ (line 8) | def __init__(self):
method __call__ (line 11) | def __call__(self, record):
class TestQueryLogging (line 15) | class TestQueryLogging(tb.ConnectedTestCase):
method test_logging_context (line 17) | async def test_logging_context(self):
method test_error_logging (line 40) | async def test_error_logging(self):
FILE: tests/test_pool.py
class SlowResetConnection (line 30) | class SlowResetConnection(pg_connection.Connection):
method reset (line 32) | async def reset(self, *, timeout=None):
class SlowCancelConnection (line 37) | class SlowCancelConnection(pg_connection.Connection):
method _cancel (line 39) | async def _cancel(self, waiter):
class TestPool (line 44) | class TestPool(tb.ConnectedTestCase):
method test_pool_01 (line 46) | async def test_pool_01(self):
method test_pool_02 (line 61) | async def test_pool_02(self):
method test_pool_03 (line 75) | async def test_pool_03(self):
method test_pool_04 (line 86) | async def test_pool_04(self):
method test_pool_05 (line 109) | async def test_pool_05(self):
method test_pool_06 (line 123) | async def test_pool_06(self):
method test_pool_07 (line 137) | async def test_pool_07(self):
method test_pool_08 (line 197) | async def test_pool_08(self):
method test_pool_09 (line 205) | async def test_pool_09(self):
method test_pool_10 (line 223) | async def test_pool_10(self):
method test_pool_11 (line 233) | async def test_pool_11(self):
method test_pool_12 (line 290) | async def test_pool_12(self):
method test_pool_13 (line 300) | async def test_pool_13(self):
method test_pool_init_run_until_complete (line 314) | def test_pool_init_run_until_complete(self):
method test_pool_exception_in_setup_and_init (line 319) | async def test_pool_exception_in_setup_and_init(self):
method test_pool_auth (line 362) | async def test_pool_auth(self):
method test_pool_handles_task_cancel_in_acquire_with_timeout (line 412) | async def test_pool_handles_task_cancel_in_acquire_with_timeout(self):
method test_pool_handles_task_cancel_in_release (line 432) | async def test_pool_handles_task_cancel_in_release(self):
method test_pool_handles_query_cancel_in_release (line 453) | async def test_pool_handles_query_cancel_in_release(self):
method test_pool_no_acquire_deadlock (line 474) | async def test_pool_no_acquire_deadlock(self):
method test_pool_config_persistence (line 489) | async def test_pool_config_persistence(self):
method test_pool_release_in_xact (line 518) | async def test_pool_release_in_xact(self):
method test_pool_connection_methods (line 547) | async def test_pool_connection_methods(self):
method test_pool_connection_execute_many (line 598) | async def test_pool_connection_execute_many(self):
method test_pool_max_inactive_time_01 (line 626) | async def test_pool_max_inactive_time_01(self):
method test_pool_max_inactive_time_02 (line 645) | async def test_pool_max_inactive_time_02(self):
method test_pool_max_inactive_time_03 (line 668) | async def test_pool_max_inactive_time_03(self):
method test_pool_max_inactive_time_04 (line 688) | async def test_pool_max_inactive_time_04(self):
method test_pool_max_inactive_time_05 (line 719) | async def test_pool_max_inactive_time_05(self):
method test_pool_handles_inactive_connection_errors (line 737) | async def test_pool_handles_inactive_connection_errors(self):
method test_pool_size_and_capacity (line 757) | async def test_pool_size_and_capacity(self):
method test_pool_closing (line 778) | async def test_pool_closing(self):
method test_pool_handles_transaction_exit_in_asyncgen_1 (line 789) | async def test_pool_handles_transaction_exit_in_asyncgen_1(self):
method test_pool_handles_transaction_exit_in_asyncgen_2 (line 810) | async def test_pool_handles_transaction_exit_in_asyncgen_2(self):
method test_pool_handles_asyncgen_finalization (line 834) | async def test_pool_handles_asyncgen_finalization(self):
method test_pool_close_waits_for_release (line 855) | async def test_pool_close_waits_for_release(self):
method test_pool_close_timeout (line 878) | async def test_pool_close_timeout(self):
method test_pool_expire_connections (line 897) | async def test_pool_expire_connections(self):
method test_pool_set_connection_args (line 910) | async def test_pool_set_connection_args(self):
method test_pool_init_race (line 953) | async def test_pool_init_race(self):
method test_pool_init_and_use_race (line 967) | async def test_pool_init_and_use_race(self):
method test_pool_remote_close (line 982) | async def test_pool_remote_close(self):
class TestPoolReconnectWithTargetSessionAttrs (line 1009) | class TestPoolReconnectWithTargetSessionAttrs(tb.ClusterTestCase):
method setup_cluster (line 1012) | def setup_cluster(cls):
method simulate_cluster_recovery_mode (line 1016) | async def simulate_cluster_recovery_mode(self):
method test_full_reconnect_on_node_change_role (line 1034) | async def test_full_reconnect_on_node_change_role(self):
class TestHotStandby (line 1073) | class TestHotStandby(tb.HotStandbyTestCase):
method create_pool (line 1074) | def create_pool(self, **kwargs):
method test_standby_pool_01 (line 1079) | async def test_standby_pool_01(self):
method test_standby_cursors (line 1095) | async def test_standby_cursors(self):
FILE: tests/test_prepare.py
class TestPrepare (line 17) | class TestPrepare(tb.ConnectedTestCase):
method test_prepare_01 (line 19) | async def test_prepare_01(self):
method test_prepare_02 (line 33) | async def test_prepare_02(self):
method test_prepare_03 (line 37) | async def test_prepare_03(self):
method test_prepare_04 (line 65) | async def test_prepare_04(self):
method test_prepare_05_unknownoid (line 83) | async def test_prepare_05_unknownoid(self):
method test_prepare_06_interrupted_close (line 87) | async def test_prepare_06_interrupted_close(self):
method test_prepare_07_interrupted_terminate (line 103) | async def test_prepare_07_interrupted_terminate(self):
method test_prepare_08_big_result (line 120) | async def test_prepare_08_big_result(self):
method test_prepare_09_raise_error (line 129) | async def test_prepare_09_raise_error(self):
method test_prepare_10_stmt_lru (line 144) | async def test_prepare_10_stmt_lru(self):
method test_prepare_11_stmt_gc (line 197) | async def test_prepare_11_stmt_gc(self):
method test_prepare_12_stmt_gc (line 216) | async def test_prepare_12_stmt_gc(self):
method test_prepare_13_connect (line 243) | async def test_prepare_13_connect(self):
method test_prepare_14_explain (line 254) | async def test_prepare_14_explain(self):
method test_prepare_15_stmt_gc_cache_disabled (line 284) | async def test_prepare_15_stmt_gc_cache_disabled(self):
method test_prepare_16_command_result (line 314) | async def test_prepare_16_command_result(self):
method test_prepare_17_stmt_closed_lru (line 341) | async def test_prepare_17_stmt_closed_lru(self):
method test_prepare_18_empty_result (line 350) | async def test_prepare_18_empty_result(self):
method test_prepare_19_concurrent_calls (line 361) | async def test_prepare_19_concurrent_calls(self):
method test_prepare_20_concurrent_calls (line 375) | async def test_prepare_20_concurrent_calls(self):
method test_prepare_21_errors (line 397) | async def test_prepare_21_errors(self):
method test_prepare_22_empty (line 405) | async def test_prepare_22_empty(self):
method test_prepare_statement_invalid (line 415) | async def test_prepare_statement_invalid(self):
method test_prepare_23_no_stmt_cache_seq (line 434) | async def test_prepare_23_no_stmt_cache_seq(self):
method test_prepare_24_max_lifetime (line 465) | async def test_prepare_24_max_lifetime(self):
method test_prepare_25_max_lifetime_reset (line 486) | async def test_prepare_25_max_lifetime_reset(self):
method test_prepare_26_max_lifetime_max_size (line 502) | async def test_prepare_26_max_lifetime_max_size(self):
method test_prepare_27_max_cacheable_statement_size (line 518) | async def test_prepare_27_max_cacheable_statement_size(self):
method test_prepare_28_max_args (line 538) | async def test_prepare_28_max_args(self):
method test_prepare_29_duplicates (line 548) | async def test_prepare_29_duplicates(self):
method test_prepare_30_invalid_arg_count (line 561) | async def test_prepare_30_invalid_arg_count(self):
method test_prepare_31_pgbouncer_note (line 572) | async def test_prepare_31_pgbouncer_note(self):
method test_prepare_does_not_use_cache (line 597) | async def test_prepare_does_not_use_cache(self):
method test_prepare_explicitly_named (line 604) | async def test_prepare_explicitly_named(self):
method test_prepare_fetchmany (line 615) | async def test_prepare_fetchmany(self):
FILE: tests/test_record.py
class CustomRecord (line 25) | class CustomRecord(asyncpg.Record):
class AnotherCustomRecord (line 29) | class AnotherCustomRecord(asyncpg.Record):
class TestRecord (line 33) | class TestRecord(tb.ConnectedTestCase):
method checkref (line 36) | def checkref(self, *objs):
method test_record_gc (line 48) | def test_record_gc(self):
method test_record_freelist_ok (line 73) | def test_record_freelist_ok(self):
method test_record_len_getindex (line 78) | def test_record_len_getindex(self):
method test_record_slice (line 104) | def test_record_slice(self):
method test_record_immutable (line 113) | def test_record_immutable(self):
method test_record_repr (line 118) | def test_record_repr(self):
method test_record_iter (line 144) | def test_record_iter(self):
method test_record_values (line 150) | def test_record_values(self):
method test_record_keys (line 157) | def test_record_keys(self):
method test_record_items (line 163) | def test_record_items(self):
method test_record_hash (line 200) | def test_record_hash(self):
method test_record_contains (line 221) | def test_record_contains(self):
method test_record_cmp (line 233) | def test_record_cmp(self):
method test_record_get (line 284) | def test_record_get(self):
method test_record_not_pickleable (line 291) | def test_record_not_pickleable(self):
method test_record_empty (line 296) | def test_record_empty(self):
method test_record_duplicate_colnames (line 311) | async def test_record_duplicate_colnames(self):
method test_record_isinstance (line 341) | async def test_record_isinstance(self):
method test_record_no_new (line 346) | async def test_record_no_new(self):
method test_record_subclass_01 (line 355) | async def test_record_subclass_01(self):
method test_record_subclass_02 (line 380) | async def test_record_subclass_02(self):
method test_record_subclass_03 (line 427) | async def test_record_subclass_03(self):
method test_record_subclass_04 (line 474) | async def test_record_subclass_04(self):
method test_record_subclass_05 (line 520) | async def test_record_subclass_05(self):
method test_record_subclass_06 (line 537) | async def test_record_subclass_06(self):
FILE: tests/test_subinterpreters.py
class TestSubinterpreters (line 17) | class TestSubinterpreters(unittest.TestCase):
method test_record_module_loads_in_subinterpreter (line 18) | def test_record_module_loads_in_subinterpreter(self) -> None:
method test_record_module_state_isolation (line 35) | def test_record_module_state_isolation(self) -> None:
FILE: tests/test_test.py
class BaseSimpleTestCase (line 16) | class BaseSimpleTestCase:
method test_tests_zero_error (line 18) | async def test_tests_zero_error(self):
class TestTests (line 23) | class TestTests(unittest.TestCase):
method test_tests_fail_1 (line 25) | def test_tests_fail_1(self):
class TestHelpers (line 38) | class TestHelpers(tb.TestCase):
method test_tests_assertLoopErrorHandlerCalled_01 (line 40) | async def test_tests_assertLoopErrorHandlerCalled_01(self):
FILE: tests/test_timeout.py
class TestTimeout (line 18) | class TestTimeout(tb.ConnectedTestCase):
method test_timeout_01 (line 20) | async def test_timeout_01(self):
method test_timeout_02 (line 28) | async def test_timeout_02(self):
method test_timeout_03 (line 38) | async def test_timeout_03(self):
method test_timeout_04 (line 48) | async def test_timeout_04(self):
method test_timeout_05 (line 65) | async def test_timeout_05(self):
method test_timeout_06 (line 74) | async def test_timeout_06(self):
method test_invalid_timeout (line 112) | async def test_invalid_timeout(self):
class TestConnectionCommandTimeout (line 127) | class TestConnectionCommandTimeout(tb.ConnectedTestCase):
method test_command_timeout_01 (line 130) | async def test_command_timeout_01(self):
class SlowPrepareConnection (line 139) | class SlowPrepareConnection(pg_connection.Connection):
method _get_statement (line 141) | async def _get_statement(self, query, timeout, **kwargs):
class TestTimeoutCoversPrepare (line 146) | class TestTimeoutCoversPrepare(tb.ConnectedTestCase):
method test_timeout_covers_prepare_01 (line 150) | async def test_timeout_covers_prepare_01(self):
FILE: tests/test_transaction.py
class TestTransaction (line 13) | class TestTransaction(tb.ConnectedTestCase):
method test_transaction_regular (line 15) | async def test_transaction_regular(self):
method test_transaction_nested (line 47) | async def test_transaction_nested(self):
method test_transaction_interface_errors (line 113) | async def test_transaction_interface_errors(self):
method test_transaction_within_manual_transaction (line 162) | async def test_transaction_within_manual_transaction(self):
method test_isolation_level (line 183) | async def test_isolation_level(self):
method test_nested_isolation_level (line 214) | async def test_nested_isolation_level(self):
FILE: tests/test_types.py
class TestTypes (line 13) | class TestTypes(tb.TestCase):
method test_range_issubset (line 15) | def test_range_issubset(self):
FILE: tests/test_utils.py
class TestUtils (line 14) | class TestUtils(tb.ConnectedTestCase):
method test_mogrify_simple (line 16) | async def test_mogrify_simple(self):
method test_mogrify_multiple (line 32) | async def test_mogrify_multiple(self):
FILE: tools/generate_exceptions.py
function _get_error_name (line 39) | def _get_error_name(sqlstatename, msgtype, sqlstate):
function main (line 68) | def main():
FILE: tools/generate_type_map.py
function runner (line 46) | async def runner(args):
function main (line 113) | def main():
Condensed preview — 121 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,191K chars).
[
{
"path": ".clang-format",
"chars": 441,
"preview": "# A clang-format style that approximates Python's PEP 7\nBasedOnStyle: Google\nAlwaysBreakAfterReturnType: All\nAllowShortI"
},
{
"path": ".clangd",
"chars": 77,
"preview": "Diagnostics:\n Includes:\n IgnoreHeader:\n - \"pythoncapi_compat.*\\\\.h\"\n"
},
{
"path": ".flake8",
"chars": 252,
"preview": "[flake8]\nselect = C90,E,F,W,Y0\nignore = E402,E731,W503,W504,E252\nexclude = .git,__pycache__,build,dist,.eggs,.github,.lo"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 855,
"preview": "<!--\nThank you for reporting an issue/feature request.\n\nIf this is a feature request, please disregard this template. I"
},
{
"path": ".github/RELEASING.rst",
"chars": 1502,
"preview": "Releasing asyncpg\n=================\n\nWhen making an asyncpg release follow the below checklist.\n\n1. Remove the ``.dev0``"
},
{
"path": ".github/release_log.py",
"chars": 1292,
"preview": "#!/usr/bin/env python3\n#\n# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This"
},
{
"path": ".github/workflows/install-krb5.sh",
"chars": 1242,
"preview": "#!/bin/bash\n\nset -Eexuo pipefail\nshopt -s nullglob\n\nif [[ $OSTYPE == linux* ]]; then\n if [ \"$(id -u)\" = \"0\" ]; then\n "
},
{
"path": ".github/workflows/install-postgres.sh",
"chars": 2137,
"preview": "#!/bin/bash\n\nset -Eexuo pipefail\nshopt -s nullglob\n\nif [[ $OSTYPE == linux* ]]; then\n PGVERSION=${PGVERSION:-12}\n\n "
},
{
"path": ".github/workflows/release.yml",
"chars": 6655,
"preview": "name: Release\n\non:\n pull_request:\n branches:\n - \"master\"\n - \"ci\"\n - \"[0-9]+.[0-9x]+*\"\n paths:\n "
},
{
"path": ".github/workflows/tests.yml",
"chars": 4495,
"preview": "name: Tests\n\non:\n push:\n branches:\n - master\n - ci\n pull_request:\n branches:\n - master\n\njobs:\n t"
},
{
"path": ".gitignore",
"chars": 362,
"preview": "*._*\n*.pyc\n*.pyo\n*.ymlc\n*.ymlc~\n*.scssc\n*.so\n*.pyd\n*~\n.#*\n.DS_Store\n.project\n.pydevproject\n.settings\n.idea\n/.ropeproject"
},
{
"path": ".gitmodules",
"chars": 106,
"preview": "[submodule \"asyncpg/pgproto\"]\n\tpath = asyncpg/pgproto\n\turl = https://github.com/MagicStack/py-pgproto.git\n"
},
{
"path": "AUTHORS",
"chars": 130,
"preview": "Main contributors\n=================\n\nMagicStack Inc.:\n Elvis Pranskevichus <elvis@magic.io>\n Yury Selivanov <yury@"
},
{
"path": "LICENSE",
"chars": 11466,
"preview": "Copyright (C) 2016-present the asyncpg authors and contributors.\n\n Apache License\n "
},
{
"path": "MANIFEST.in",
"chars": 239,
"preview": "recursive-include docs *.py *.rst Makefile *.css\nrecursive-include examples *.py\nrecursive-include tests *.py *.pem\nrecu"
},
{
"path": "Makefile",
"chars": 956,
"preview": ".PHONY: compile debug test quicktest clean all\n\n\nPYTHON ?= python\nROOT = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))"
},
{
"path": "README.rst",
"chars": 2990,
"preview": "asyncpg -- A fast PostgreSQL Database Client Library for Python/asyncio\n================================================"
},
{
"path": "asyncpg/.gitignore",
"chars": 7,
"preview": "*.html\n"
},
{
"path": "asyncpg/__init__.py",
"chars": 647,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/_asyncio_compat.py",
"chars": 2540,
"preview": "# Backports from Python/Lib/asyncio for older Pythons\n#\n# Copyright (c) 2001-2023 Python Software Foundation; All Rights"
},
{
"path": "asyncpg/_testbase/__init__.py",
"chars": 16499,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/_testbase/fuzzer.py",
"chars": 9804,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/_version.py",
"chars": 646,
"preview": "# This file MUST NOT contain anything but the __version__ assignment.\n#\n# When making a release, change the value of __v"
},
{
"path": "asyncpg/cluster.py",
"chars": 24476,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/compat.py",
"chars": 2459,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/connect_utils.py",
"chars": 43438,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/connection.py",
"chars": 99069,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/connresource.py",
"chars": 1384,
"preview": "\n# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of async"
},
{
"path": "asyncpg/cursor.py",
"chars": 9160,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/exceptions/__init__.py",
"chars": 29157,
"preview": "# GENERATED FROM postgresql/src/backend/utils/errcodes.txt\n# DO NOT MODIFY, use tools/generate_exceptions.py to update\n\n"
},
{
"path": "asyncpg/exceptions/_base.py",
"chars": 9260,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/introspection.py",
"chars": 9340,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/pool.py",
"chars": 42368,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/prepared_stmt.py",
"chars": 9783,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/.gitignore",
"chars": 5,
"preview": "/*.c\n"
},
{
"path": "asyncpg/protocol/__init__.py",
"chars": 359,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/codecs/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "asyncpg/protocol/codecs/array.pyx",
"chars": 29486,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/codecs/base.pxd",
"chars": 6614,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/codecs/base.pyx",
"chars": 34460,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/codecs/pgproto.pyx",
"chars": 17175,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/codecs/range.pyx",
"chars": 6359,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/codecs/record.pyx",
"chars": 2362,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/codecs/textutils.pyx",
"chars": 2011,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/consts.pxi",
"chars": 381,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/coreproto.pxd",
"chars": 6215,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/coreproto.pyx",
"chars": 41005,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/cpythonx.pxd",
"chars": 613,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/encodings.pyx",
"chars": 1634,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/pgtypes.pxi",
"chars": 6918,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/prepared_stmt.pxd",
"chars": 1115,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/prepared_stmt.pyx",
"chars": 13036,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/protocol.pxd",
"chars": 1927,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/protocol.pyi",
"chars": 9108,
"preview": "import asyncio\nimport asyncio.protocols\nimport hmac\nfrom codecs import CodecInfo\nfrom collections.abc import Callable, I"
},
{
"path": "asyncpg/protocol/protocol.pyx",
"chars": 34473,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/record/pythoncapi_compat.h",
"chars": 69898,
"preview": "// Header file providing new C API functions to old Python versions.\n//\n// File distributed under the Zero Clause BSD (0"
},
{
"path": "asyncpg/protocol/record/pythoncapi_compat_extras.h",
"chars": 1962,
"preview": "#ifndef PYTHONCAPI_COMPAT_EXTRAS\n#define PYTHONCAPI_COMPAT_EXTRAS\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <Pyt"
},
{
"path": "asyncpg/protocol/record/recordobj.c",
"chars": 34423,
"preview": "/* Big parts of this file are copied (with modifications) from\n CPython/Objects/tupleobject.c.\n\n Portions Copyright "
},
{
"path": "asyncpg/protocol/record/recordobj.h",
"chars": 699,
"preview": "#ifndef APG_RECORDOBJ_H\n#define APG_RECORDOBJ_H\n\n#include <Python.h>\n\n\ntypedef struct {\n PyObject_HEAD\n PyObject *"
},
{
"path": "asyncpg/protocol/record.pyi",
"chars": 741,
"preview": "from typing import (\n Any,\n TypeVar,\n overload,\n)\n\nfrom collections.abc import Iterator\n\n\n_T = TypeVar(\"_T\")\n\n\n"
},
{
"path": "asyncpg/protocol/recordcapi.pxd",
"chars": 360,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/scram.pxd",
"chars": 1299,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/scram.pyx",
"chars": 14594,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/settings.pxd",
"chars": 1066,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/protocol/settings.pyx",
"chars": 3777,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/serverversion.py",
"chars": 2133,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/transaction.py",
"chars": 8497,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/types.py",
"chars": 5512,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "asyncpg/utils.py",
"chars": 1495,
"preview": "# Copyright (C) 2016-present the ayncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncpg"
},
{
"path": "docs/.gitignore",
"chars": 18,
"preview": "_build\n_templates\n"
},
{
"path": "docs/Makefile",
"chars": 7614,
"preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHINXBUILD "
},
{
"path": "docs/_static/theme_overrides.css",
"chars": 266,
"preview": "/* override table width restrictions */\n@media screen and (min-width: 767px) {\n\n .wy-table-responsive table td {\n "
},
{
"path": "docs/api/index.rst",
"chars": 9249,
"preview": ".. _asyncpg-api-reference:\n\n=============\nAPI Reference\n=============\n\n.. module:: asyncpg\n :synopsis: A fast Postgre"
},
{
"path": "docs/conf.py",
"chars": 2379,
"preview": "#!/usr/bin/env python3\n\nimport os\nimport sys\n\nsys.path.insert(0, os.path.abspath('..'))\n\nversion_file = os.path.join(os."
},
{
"path": "docs/faq.rst",
"chars": 3709,
"preview": ".. _asyncpg-faq:\n\n\nFrequently Asked Questions\n==========================\n\nDoes asyncpg support DB-API?\n~~~~~~~~~~~~~~~~~"
},
{
"path": "docs/index.rst",
"chars": 917,
"preview": ".. image:: https://github.com/MagicStack/asyncpg/workflows/Tests/badge.svg\n :target: https://github.com/MagicStack/asy"
},
{
"path": "docs/installation.rst",
"chars": 2134,
"preview": ".. _asyncpg-installation:\n\n\nInstallation\n============\n\n**asyncpg** has no external dependencies when not using GSSAPI/SS"
},
{
"path": "docs/requirements.txt",
"chars": 39,
"preview": "sphinxcontrib-asyncio\nsphinx_rtd_theme\n"
},
{
"path": "docs/usage.rst",
"chars": 18172,
"preview": ".. _asyncpg-examples:\n\n\nasyncpg Usage\n=============\n\nThe interaction with the database normally starts with a call to\n:f"
},
{
"path": "pyproject.toml",
"chars": 3710,
"preview": "[project]\nname = \"asyncpg\"\ndescription = \"An asyncio PostgreSQL driver\"\nauthors = [{name = \"MagicStack Inc\", email = \"he"
},
{
"path": "setup.py",
"chars": 8706,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/__init__.py",
"chars": 627,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/certs/ca.cert.pem",
"chars": 2191,
"preview": "-----BEGIN CERTIFICATE-----\nMIIGJjCCBA6gAwIBAgIICJCUmtkcj2MwDQYJKoZIhvcNAQELBQAwgaExCzAJBgNV\nBAYTAkNBMRAwDgYDVQQIDAdPbnR"
},
{
"path": "tests/certs/ca.crl.pem",
"chars": 1097,
"preview": "-----BEGIN X509 CRL-----\nMIIDAjCB6wIBATANBgkqhkiG9w0BAQsFADCBoTELMAkGA1UEBhMCQ0ExEDAOBgNV\nBAgMB09udGFyaW8xEDAOBgNVBAcMB1"
},
{
"path": "tests/certs/ca.key.pem",
"chars": 3243,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEAj/qApdKq0XkpVo/sr3xs+vFEKpuo6C/VYHgNE73PEttyGt0u\n98HE03RoSEMDDmiLlsvptyd"
},
{
"path": "tests/certs/client.cert.pem",
"chars": 1452,
"preview": "-----BEGIN CERTIFICATE-----\nMIIEAzCCAuugAwIBAgIUPfej8IQ/5bCrihqWImrq2vKPOq0wDQYJKoZIhvcNAQEL\nBQAwgaMxCzAJBgNVBAYTAkNBMRA"
},
{
"path": "tests/certs/client.csr.pem",
"chars": 1066,
"preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIIC2zCCAcMCAQAwgZUxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdPbnRhcmlvMRAw\nDgYDVQQHDAdUb3JvbnR"
},
{
"path": "tests/certs/client.key.pem",
"chars": 1675,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAmOI/0iT8pFEsr0Yy+gfybUs74bKuvwbPfoumYokxH8+nBMv7\nWk6RhIaE7JPcLD3+RZYslEK"
},
{
"path": "tests/certs/client.key.protected.pem",
"chars": 1766,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,B222CD7D00828606A07DBC489D400921\n\nLRHsNGUsD"
},
{
"path": "tests/certs/client_ca.cert.pem",
"chars": 1505,
"preview": "-----BEGIN CERTIFICATE-----\nMIIEKTCCAxGgAwIBAgIUKmL8tfNS9LIB6GLB9RpZpTyk3uIwDQYJKoZIhvcNAQEL\nBQAwgaMxCzAJBgNVBAYTAkNBMRA"
},
{
"path": "tests/certs/client_ca.cert.srl",
"chars": 41,
"preview": "3DF7A3F0843FE5B0AB8A1A96226AEADAF28F3AAD\n"
},
{
"path": "tests/certs/client_ca.key.pem",
"chars": 1679,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAptRYfxKiWExfZguQDva53bIqYa4lJwZA86Qu0peBUcsdE6zy\nHNgVv4XSMim1FH12KQ4KPKu"
},
{
"path": "tests/certs/gen.py",
"chars": 6930,
"preview": "import datetime\nimport os\n\nfrom cryptography import x509\nfrom cryptography.hazmat import backends\nfrom cryptography.hazm"
},
{
"path": "tests/certs/server.cert.pem",
"chars": 2451,
"preview": "-----BEGIN CERTIFICATE-----\nMIIG5jCCBM6gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgaExCzAJBgNVBAYTAkNB\nMRAwDgYDVQQIDAdPbnRhcmlvMRA"
},
{
"path": "tests/certs/server.crl.pem",
"chars": 1097,
"preview": "-----BEGIN X509 CRL-----\nMIIDAjCB6wIBATANBgkqhkiG9w0BAQsFADCBoTELMAkGA1UEBhMCQ0ExEDAOBgNV\nBAgMB09udGFyaW8xEDAOBgNVBAcMB1"
},
{
"path": "tests/certs/server.key.pem",
"chars": 3243,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKQIBAAKCAgEA3F017q/obCM1SsHY5dFz72pFgVMhBIZ6kdIInbFv7RmEykZz\nubbJnrgwgYDO5FKGUNO+a80"
},
{
"path": "tests/test__environment.py",
"chars": 1441,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test__sourcecode.py",
"chars": 2214,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_adversity.py",
"chars": 3176,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_cache_invalidation.py",
"chars": 16559,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_cancellation.py",
"chars": 3119,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_codecs.py",
"chars": 68302,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_connect.py",
"chars": 82962,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_copy.py",
"chars": 21958,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_cursor.py",
"chars": 5923,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_exceptions.py",
"chars": 2024,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_execute.py",
"chars": 12170,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_introspection.py",
"chars": 7536,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_listeners.py",
"chars": 11656,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_logging.py",
"chars": 1550,
"preview": "import asyncio\n\nfrom asyncpg import _testbase as tb\nfrom asyncpg import exceptions\n\n\nclass LogCollector:\n def __init_"
},
{
"path": "tests/test_pool.py",
"chars": 38666,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_prepare.py",
"chars": 22707,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_record.py",
"chars": 18447,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_subinterpreters.py",
"chars": 2055,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_test.py",
"chars": 1289,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_timeout.py",
"chars": 6493,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_transaction.py",
"chars": 9623,
"preview": "# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncp"
},
{
"path": "tests/test_types.py",
"chars": 2088,
"preview": "# Copyright (C) 2016-present the ayncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncpg"
},
{
"path": "tests/test_utils.py",
"chars": 1198,
"preview": "# Copyright (C) 2016-present the ayncpg authors and contributors\n# <see AUTHORS file>\n#\n# This module is part of asyncpg"
},
{
"path": "tools/generate_exceptions.py",
"chars": 5257,
"preview": "#!/usr/bin/env python3\n#\n# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This"
},
{
"path": "tools/generate_type_map.py",
"chars": 3717,
"preview": "#!/usr/bin/env python3\n#\n# Copyright (C) 2016-present the asyncpg authors and contributors\n# <see AUTHORS file>\n#\n# This"
}
]
About this extraction
This page contains the full source code of the MagicStack/asyncpg GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 121 files (1.1 MB), approximately 271.9k tokens, and a symbol index with 1440 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.