Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into client-encoding-test
Browse files Browse the repository at this point in the history
  • Loading branch information
fantix committed Aug 17, 2023
2 parents a8b3188 + 89d5bd0 commit cf86d1b
Show file tree
Hide file tree
Showing 39 changed files with 953 additions and 345 deletions.
12 changes: 0 additions & 12 deletions .coveragerc

This file was deleted.

2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[flake8]
ignore = E402,E731,W503,W504,E252
exclude = .git,__pycache__,build,dist,.eggs,.github,.local,.venv
exclude = .git,__pycache__,build,dist,.eggs,.github,.local,.venv,.tox
14 changes: 6 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: "3.x"
- run: pip install cibuildwheel==2.10.2
- run: pip install cibuildwheel==2.13.1
- id: set-matrix
run: |
MATRIX_INCLUDE=$(
{
cibuildwheel --print-build-identifiers --platform linux --arch x86_64,aarch64 | grep cp | jq -Rc '{"only": inputs, "os": "ubuntu-latest"}' \
&& cibuildwheel --print-build-identifiers --platform macos --arch x86_64,arm64 | grep cp | jq -Rc '{"only": inputs, "os": "macos-latest"}' \
&& cibuildwheel --print-build-identifiers --platform windows --arch x86,AMD64 | grep cp | jq -Rc '{"only": inputs, "os": "windows-latest"}'
cibuildwheel --print-build-identifiers --platform linux --arch x86_64,aarch64 | grep cp | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \
&& cibuildwheel --print-build-identifiers --platform macos --arch x86_64,arm64 | grep cp | jq -nRc '{"only": inputs, "os": "macos-latest"}' \
&& cibuildwheel --print-build-identifiers --platform windows --arch x86,AMD64 | grep cp | jq -nRc '{"only": inputs, "os": "windows-latest"}'
} | jq -sc
)
echo "include=$MATRIX_INCLUDE" >> $GITHUB_OUTPUT
Expand Down Expand Up @@ -118,13 +118,11 @@ jobs:
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v2

- uses: pypa/cibuildwheel@v2.10.2
- uses: pypa/cibuildwheel@v2.13.1
with:
only: ${{ matrix.only }}
env:
CIBW_BUILD_VERBOSITY: 1
CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28

- uses: actions/upload-artifact@v3
with:
Expand Down Expand Up @@ -152,7 +150,7 @@ jobs:

- name: Build docs
run: |
pip install -e .[dev]
pip install -e .[docs]
make htmldocs
- name: Checkout gh-pages
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
# job.
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
os: [ubuntu-latest, macos-latest, windows-latest]
loop: [asyncio, uvloop]
exclude:
Expand Down
15 changes: 7 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,26 @@ clean:


compile:
$(PYTHON) setup.py build_ext --inplace --cython-always
env ASYNCPG_BUILD_CYTHON_ALWAYS=1 $(PYTHON) -m pip install -e .


debug:
ASYNCPG_DEBUG=1 $(PYTHON) setup.py build_ext --inplace

env ASYNCPG_DEBUG=1 $(PYTHON) -m pip install -e .

test:
PYTHONASYNCIODEBUG=1 $(PYTHON) setup.py test
$(PYTHON) setup.py test
USE_UVLOOP=1 $(PYTHON) setup.py 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) setup.py test
$(PYTHON) -m unittest -v tests.suite


htmldocs:
$(PYTHON) setup.py build_ext --inplace
$(PYTHON) -m pip install -e .[docs]
$(MAKE) -C docs html
11 changes: 5 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ 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.7 or later and is supported for PostgreSQL
asyncpg requires Python 3.8 or later and is supported for PostgreSQL
versions 9.5 to 15. Older PostgreSQL versions or other databases implementing
the PostgreSQL protocol *may* work, but are not being actively tested.

Expand All @@ -28,15 +28,14 @@ The project documentation can be found
Performance
-----------

In our testing asyncpg is, on average, **3x** faster than psycopg2
(and its asyncio variant -- aiopg).
In our testing asyncpg is, on average, **5x** faster than psycopg3.

.. image:: https://raw.githubusercontent.com/MagicStack/asyncpg/master/performance.png
:target: https://gistpreview.github.io/?b8eac294ac85da177ff82f784ff2cb60
.. 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 November 2020 (click on the chart to see full details).
in June 2023 (click on the chart to see full details).


Features
Expand Down
90 changes: 90 additions & 0 deletions asyncpg/_testbase/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,3 +435,93 @@ def tearDown(self):
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)
2 changes: 1 addition & 1 deletion asyncpg/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
# supported platforms, publish the packages on PyPI, merge the PR
# to the target branch, create a Git tag pointing to the commit.

__version__ = '0.28.0.dev0'
__version__ = '0.29.0.dev0'
2 changes: 1 addition & 1 deletion asyncpg/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ def init(self, **settings):
'pg_basebackup init exited with status {:d}:\n{}'.format(
process.returncode, output.decode()))

if self._pg_version <= (11, 0):
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'
Expand Down
10 changes: 7 additions & 3 deletions asyncpg/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import asyncio
import pathlib
import platform
import typing


SYSTEM = platform.uname().system
Expand All @@ -18,7 +19,7 @@

CSIDL_APPDATA = 0x001a

def get_pg_home_directory() -> pathlib.Path:
def get_pg_home_directory() -> typing.Optional[pathlib.Path]:
# We cannot simply use expanduser() as that returns the user's
# home directory, whereas Postgres stores its config in
# %AppData% on Windows.
Expand All @@ -30,8 +31,11 @@ def get_pg_home_directory() -> pathlib.Path:
return pathlib.Path(buf.value) / 'postgresql'

else:
def get_pg_home_directory() -> pathlib.Path:
return pathlib.Path.home()
def get_pg_home_directory() -> typing.Optional[pathlib.Path]:
try:
return pathlib.Path.home()
except (RuntimeError, KeyError):
return None


async def wait_closed(stream):
Expand Down
Loading

0 comments on commit cf86d1b

Please sign in to comment.