diff --git a/.bumpversion.cfg b/.bumpversion.cfg
deleted file mode 100644
index 80aaba9..0000000
--- a/.bumpversion.cfg
+++ /dev/null
@@ -1,20 +0,0 @@
-[bumpversion]
-current_version = 2.2.0
-commit = True
-tag = True
-message = "Release {new_version}"
-
-[bumpversion:file:setup.py]
-search = version='{current_version}'
-replace = version='{new_version}'
-
-[bumpversion:file:src/pytest_postgresql/__init__.py]
-
-[bumpversion:file:README.rst]
-
-[bumpversion:file:CHANGES.rst]
-search = unreleased
- -------
-replace = {new_version}
- -------
-
diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index 1e01055..0000000
--- a/.coveragerc
+++ /dev/null
@@ -1,2 +0,0 @@
-[run]
-source = pytest_postgresql
diff --git a/.dependabot/config.yml b/.dependabot/config.yml
deleted file mode 100644
index c77885a..0000000
--- a/.dependabot/config.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-version: 1
-update_configs:
- - package_manager: "python"
- directory: "/"
- update_schedule: "daily"
- automerged_updates:
- - match:
- dependency_name: "*"
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE.rst b/.github/ISSUE_TEMPLATE.rst
deleted file mode 100644
index 0946e37..0000000
--- a/.github/ISSUE_TEMPLATE.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-### What action do you want to perform
-
-
-### What are the results
-
-
-### What are the expected results
\ No newline at end of file
diff --git a/.github/PULL_REQUEST_TEMPLATE.rst b/.github/PULL_REQUEST_TEMPLATE.rst
deleted file mode 100644
index 8f849ce..0000000
--- a/.github/PULL_REQUEST_TEMPLATE.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-Fixes #[ISSUE_NUMBER_HERE].
-
-Changes proposed.
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 8df19ab..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,38 +0,0 @@
-*.py[cod]
-
-# C extensions
-*.so
-
-# Packages
-*.egg
-*.egg-info
-dist
-build
-eggs
-parts
-bin
-var
-sdist
-develop-eggs
-.installed.cfg
-lib
-lib64
-.cache
-.pytest_cache
-
-# Installer logs
-pip-log.txt
-
-# Unit test / coverage reports
-.coverage
-.tox
-nosetests.xml
-
-# Translations
-*.mo
-
-# Mr Developer
-.mr.developer.cfg
-.project
-.pydevproject
-.idea
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 7def26d..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-dist: xenial
-language: python
-python:
-- 3.5
-- 3.6
-- 3.7
-- 3.8-dev
-- pypy3
-# blocklist branches
-branches:
- except:
- - requires-io-master
- - /^dependabot.*$/
-install:
-- pip install -r requirements-test.txt
-- pip install coveralls wheel
-script:
-- py.test -n 0
-after_success:
-- coveralls
-jobs:
- include:
- - stage: xdist
- python: 3.7
- script: py.test -n 1
- - stage: linters
- python: 3.7
- install:
- - pip install -r requirements-lint.txt
- script:
- - pycodestyle
- - pydocstyle
- - pylint pytest_postgresql tests
- - pyroma .
- after_success: skip
- - stage: osx
- language: generic
- os: osx
- before_install:
- - pip3 install virtualenv
- - virtualenv venv -p python3
- - source venv/bin/activate
- script:
- - py.test -n 0
- - stage: deploy
- python: 3.7
- if: tag IS present
- script: skip
- deploy:
- provider: pypi
- user: thearoom
- password:
- secure: FAN5dMk+ktvFdfZX6OjKy9+XWwbTrJcZ4OrV6LVKNyZdsVRi0+iE6opSQXH8HjO6DCXsyHkZDD8a6f81y/Cc3j6QsRItnJwjQllu4dNce5LYHZNA/sQ9O8mgC9+DrPWzPYRlMkSgG9eVH3tI8UX1P7Wh4yuJLbQbNkWw8ZX7j+HSwZtYLPhP2uBp7xMF5rYO+9PcIA/I0QI0AkfRQtYtwSp3QAjKUVWnWXnUQOILey5wP+3ENYVojKmYSocmOtbKUUNfExgZIep8gsZXx60fuBQLRSG0XhDxud51nGKvzNegqQoN5Mpt61VslT7trS/D6zOzMCUTqNwbg/gMrebU5IMZm5ijJSKkvw5Cl30Yc5+cZ0o7N9NbepBjlEX3ByDUnDk7bfSRHukJw9lG5+mBHLi+aJ9+ZPEqUcIHuYzv6+yvjlGPkETqlxkCunU6HzwrsD5QdYwqcY4PLHf7Onx3I2Vjg4XxZO27BDbhvpOTF4SaAk45ALi9y10Gu7FSswp44/l5k54Ur1/JPhSmFGIO8XZJZ7mLGftextYLEmQuai7IKmu46rZ3ffzEpIk0lP5xi2NWyQvD9DHEJSMKxc4koVKb72lLbl69aVp+6vKRH4VtJ1E5/Hybrxe9bbz+upQ4xRdXjRAml4xAnGeBcH5hf2owbijYuoU26qOHKl68Ej0=
- on:
- tags: true
- all_branches: true
- repo: ClearcodeHQ/pytest-postgresql
- distributions: bdist_wheel
diff --git a/CHANGES.rst b/CHANGES.rst
index 56a5cc4..6352d09 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,99 +1,276 @@
CHANGELOG
=========
+3.1.3
+----------
+
+Cherry picked from v4.x
+
+Misc
+++++
+
+- Import FixtureRequest from pytest, not private _pytest.
+ Require at least pytest 6.2
+- Replace tmpdir_factory with tmp_path_factory
+- Add Postgresql 14 to the CI
+
+3.1.2
+----------
+
+Bugfix
+++++++
+
+- Database can be created by DatabaseJanitor or the client fixture when an isolation
+ level is specified.
+
+3.1.1
+----------
+
+Misc
+++++
+
+- rely on `get_port` functionality delivered by `port_for`
+
+3.1.0
+----------
+
+Features
+++++++++
+
+- Added type annotations and compatibitlity with PEP 561
+
+Misc
+++++
+
+- pre-commit configuration
+
+3.0.2
+----------
+
+Bugfix
+++++++
+
+- Changed `UPDATE pg_database SET` to `ALTER`. System tables should not be updated.
+
+3.0.1
+----------
+
+Bugfix
+++++++
+
+- Fixed DatabaseJanitor port type hint to int from str
+- Changed retry definition to not fail if psycopg2 is not installed.
+ Now the default is Exception.
+
+Misc
+++++
+
+- Support python 3.7 and up
+
+3.0.0
+----------
+
+Features
+++++++++
+
+- Ability to create template database once for the process fixture and
+ re-recreate a clean database out of it every test. Not only it does provide some
+ common db initialisation between tests but also can speed up tests significantly,
+ especially if the initialisation has lots of operations to perform.
+- DatabaseJanitor can now define a `connection_timeout` parameter.
+ How long will it try to connect to database before raising a TimeoutError
+- Updated supported python versions
+- Unified temporary directory handling in fixture. Settled on tmpdir_factory.
+- Fully moved to the Github Actions as CI/CD pipeline
+
+Deprecations
+++++++++++++
+
+- Deprecated support for `logs_prefix` process fixture factory argument,
+ `--postgresql-logsprefix` pytest command line option and `postgresql_logsprefix`
+ ini configuration option. tmpdir_factory now builds pretty unique temporary directory structure.
+
+Backward Incompatibilities
+++++++++++++++++++++++++++
+
+- Dropped support for postgresql 9.5 and down
+- Removed init_postgresql_database and drop_postgresql_database functions.
+ They were long deprecated and their role perfectly covered by DatabaseJanitor class.
+- `pytest_postgresql.factories.get_config` was moved to `pytest_postgresql.config.get_config`
+- all `db_name` keywords and attributes were renamed to `dbname`
+- postgresql_nooproc fixture was renamed to postgresql_noproc
+
+Bugfix
+++++++
+
+- Use `postgresql_logsprefix` and `--postgresql-logsprefix` again.
+ They were stopped being used somewhere along the way.
+- Sometimes pytest-postrgesql would fail to start postgresql with
+ "FATAL: the database system is starting up" message. It's not really a fatal error,
+ but a message indicating that the process still starts. Now pytest-postgresql will wait properly in this cases.
+
+2.6.1
+----------
+
+- [bugfix] To not fail loading code if no postgresql version is installed.
+ Fallback for janitor and process fixture only, if called upon.
+
+2.6.0
+----------
+
+- [enhancement] add ability to pass options to pg_ctl's -o flag to send arguments to the underlying postgres executable
+ Use `postgres_options` as fixture argument, `--postgresql-postgres-options` as pytest starting option or
+ `postgresql_postgres_options` as pytest.ini configuration option
+
+2.5.3
+----------
+
+- [enhancement] Add ability to set up isolation level for fixture and janitor
+
+2.5.2
+----------
+
+- [fix] Status checks for running postgres depend on pg_ctl status code,
+ not on pg_ctl log language. Fixes starting on systems without C locale.
+ Thanks @Martin Meyries.
+
+
+2.5.1
+----------
+
+- [fix] Added LC_* env vars to running initdb and other utilities.
+ Now all tools and server are using same, C locale
+
+
+2.5.0
+----------
+
+- [feature] Ability to define default schema to initialize database with
+- [docs] Added more examples to readme on how to use the plugin
+
+
+2.4.1
+----------
+
+- [enhancement] extract NoopExecutor into it's own submodule
+- [bugfix] Ignore occasional `ProcessFinishedWithError` error on executor exit.
+- [bugfix] Fixed setting custom password for process fixture
+- [bugfix] Fix version detection, to allow for two-digit minor version part
+
+2.4.0
+----------
+
+- [feature] Drop support for pyhon 3.5
+- [enhancement] require at least mirakuru 2.3.0 (executor's stop method parameter's change)
+- [bug] pass password to DatabaseJanitor in client's factory
+
+2.3.0
+----------
+
+- [feature] Allow to set password for postgresql. Use it throughout the flow.
+- [bugfix] Default Janitor's connections to postgres database. When using custom users,
+ postgres attempts to use user's database and it might not exist.
+- [bugfix] NoopExecutor connects to read version by context manager to properly handle cases
+ where it can't connect to the server.
+
+2.2.1
+----------
+
+- [bugfix] Fix drop_postgresql_database to actually use DatabaseJanitor.drop instead of an init
+
2.2.0
--------
+----------
-- [feature] ability to properly connect to already existing postgresql server using ``postgresql_noproc`` fixture.
+- [feature] ability to properly connect to already existing postgresql server using ``postgresql_nooproc`` fixture.
2.1.0
--------
+----------
- [enhancement] Gather helper functions maintaining postgresql database in DatabaseJanitor class.
- [deprecate] Deprecate ``init_postgresql_database`` in favour of ``DatabaseJanitor.init``
- [deprecate] Deprecate ``drop_postgresql_database`` in favour of ``DatabaseJanitor.drop``
2.0.0
--------
+----------
- [feature] Drop support for python 2.7. From now on, only support python 3.5 and up
- [feature] Ability to configure database name through plugin options
- [enhancement] Use tmpdir_factory. Drop ``logsdir`` parameter
- [ehnancement] Support only Postgresql 9.0 and up
- [bugfix] Always start postgresql with LC_ALL, LC_TYPE and LANG set to C.UTF-8.
It makes postgresql start in english.
1.4.1
--------
+----------
- [bugfix] Allow creating test databse with hyphens
1.4.0
--------
+----------
- [enhancements] Ability to configure additional options for postgresql process and connection
- [bugfix] - removed hard dependency on ``psycopg2``, allowing any of its alternative packages, like
``psycopg2-binary``, to be used.
- [maintenance] Drop support for python 3.4 and use 3.7 instead
1.3.4
--------
+----------
- [bugfix] properly detect if executor running and clean after executor is being stopped
.. note::
Previously if a test failed, there was a possibility of the executor being removed when python was closing,
causing it to print ignored errors on already unloaded modules.
1.3.3
--------
+----------
- [enhancement] use executor's context manager to start/stop postrgesql server in a fixture
1.3.2
--------
+----------
- [bugfix] version regexp to correctly catch postgresql 10
1.3.1
--------
+----------
- [enhancement] explicitly turn off logging_collector
1.3.0
--------
+----------
- [feature] pypy compatibility
1.2.0
--------
+----------
- [bugfix] - disallow connection to database before it gets dropped.
.. note::
Otherwise it caused random test subprocess to connect again and this the drop was unsucessfull which resulted in many more test failes on setup.
- [cleanup] - removed path.py dependency
1.1.1
--------
+----------
- [bugfix] - Fixing the default pg_ctl path creation
1.1.0
--------
+----------
- [feature] - migrate usage of getfuncargvalue to getfixturevalue. require at least pytest 3.0.0
1.0.0
--------
+----------
- create command line and pytest.ini configuration options for postgresql starting parameters
- create command line and pytest.ini configuration options for postgresql username
- make the port random by default
- create command line and pytest.ini configuration options for executable
- create command line and pytest.ini configuration options for host
- create command line and pytest.ini configuration options for port
- Extracted code from pytest-dbfixtures
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 95a474b..1f581d5 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -1,44 +1,52 @@
Contribute to pytest-postgresql
==============
Thank you for taking time to contribute to pytest-postgresql!
The following is a set of guidelines for contributing to pytest-postgresql. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request.
Bug Reports
-----------
#. Use a clear and descriptive title for the issue - it'll be much easier to identify the problem.
#. Describe the steps to reproduce the problems in as many details as possible.
#. If possible, provide a code snippet to reproduce the issue.
Feature requests/proposals
--------------------------
#. Use a clear and descriptive title for the proposal
#. Provide as detailed description as possible
* Use case is great to have
#. There'll be a bit of discussion for the feature. Don't worry, if it is to be accepted, we'd like to support it, so we need to understand it thoroughly.
Pull requests
-------------
#. Start with a bug report or feature request
#. Use a clear and descriptive title
#. Provide a description - which issue does it refers to, and what part of the issue is being solved
#. Be ready for code review :)
Commits
-------
#. Make sure commits are atomic, and each atomic change is being followed by test.
#. If the commit solves part of the issue reported, include *refs #[Issue number]* in a commit message.
#. If the commit solves whole issue reported, please refer to `Closing issues via commit messages `_ for ways to close issues when commits will be merged.
Coding style
------------
-#. All python coding style are being enforced by `Pylama `_ and configured in pylama.ini file.
-#. Additional, not always mandatory checks are being performed by `QuantifiedCode `_
+#. Coding style is being handled by black and doublechecked by flake8 and pydocstyle
+ * We provide a `pre-commit `_ configuration for invoking these on commit.
+
+Testing
+-------
+
+# Tests are writen using pytest.
+# PR tests run on Github Actions.
+# In order to run the tests locally you need to have one version of postgres installed. And pass envvar named `POSTGRES` with used version number
+# If you encounter any test failures due to locale issues, make sure that both `en_US.UTF-8` and `de_DE.UTF-8` are enabled in `/etc/locale.gen` and then run `sudo locale-gen`.
diff --git a/MANIFEST.in b/MANIFEST.in
index 2174f20..114ed9f 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,3 @@
include *.rst *.py
+include src/pytest_postgresql/py.typed
recursive-include src/pytest_postgresql *.py
-recursive-include docs *
-prune docs/build
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..7ece1fe
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,787 @@
+Metadata-Version: 2.1
+Name: pytest-postgresql
+Version: 3.1.3
+Summary: Postgresql fixtures and fixture factories for Pytest.
+Home-page: https://github.com/ClearcodeHQ/pytest-postgresql
+Maintainer: Grzegorz Śliwiński
+Maintainer-email: fizyk+pypi@fizyk.net.pl
+License: LGPLv3+
+Keywords: tests,py.test,pytest,fixture,postgresql
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Software Development :: Testing
+Classifier: Framework :: Pytest
+Requires-Python: >=3.7
+Description-Content-Type: text/x-rst
+Provides-Extra: tests
+License-File: COPYING
+License-File: COPYING.lesser
+License-File: AUTHORS.rst
+
+.. image:: https://raw.githubusercontent.com/ClearcodeHQ/pytest-postgresql/master/logo.png
+ :width: 100px
+ :height: 100px
+
+pytest-postgresql
+=================
+
+.. image:: https://img.shields.io/pypi/v/pytest-postgresql.svg
+ :target: https://pypi.python.org/pypi/pytest-postgresql/
+ :alt: Latest PyPI version
+
+.. image:: https://img.shields.io/pypi/wheel/pytest-postgresql.svg
+ :target: https://pypi.python.org/pypi/pytest-postgresql/
+ :alt: Wheel Status
+
+.. image:: https://img.shields.io/pypi/pyversions/pytest-postgresql.svg
+ :target: https://pypi.python.org/pypi/pytest-postgresql/
+ :alt: Supported Python Versions
+
+.. image:: https://img.shields.io/pypi/l/pytest-postgresql.svg
+ :target: https://pypi.python.org/pypi/pytest-postgresql/
+ :alt: License
+
+What is this?
+=============
+
+This is a pytest plugin, that enables you to test your code that relies on a running PostgreSQL Database.
+It allows you to specify fixtures for PostgreSQL process and client.
+
+How to use
+==========
+
+.. warning::
+
+ Tested on PostgreSQL versions >= 9.6. See tests for more details.
+
+Install with:
+
+.. code-block:: sh
+
+ pip install pytest-postgresql
+
+You will also need to install ``psycopg2`` (2.9 or newer), or one of its alternative packagings such as ``psycopg2-binary``
+(pre-compiled wheels) or ``psycopg2cffi`` (CFFI based, useful on PyPy).
+
+Plugin contains three fixtures:
+
+* **postgresql** - it's a client fixture that has functional scope.
+ After each test it ends all leftover connections, and drops test database
+ from PostgreSQL ensuring repeatability.
+ This fixture returns already connected psycopg2 connection.
+
+* **postgresql_proc** - session scoped fixture, that starts PostgreSQL instance
+ at it's first use and stops at the end of the tests.
+* **postgresql_noproc** - a noprocess fixture, that's connecting to already
+ running postgresql instance.
+ For example on dockerized test environments, or CI providing postgresql services
+
+Simply include one of these fixtures into your tests fixture list.
+
+You can also create additional postgresql client and process fixtures if you'd need to:
+
+
+.. code-block:: python
+
+ from pytest_postgresql import factories
+
+ postgresql_my_proc = factories.postgresql_proc(
+ port=None, unixsocketdir='/var/run')
+ postgresql_my = factories.postgresql('postgresql_my_proc')
+
+.. note::
+
+ Each PostgreSQL process fixture can be configured in a different way than the others through the fixture factory arguments.
+
+Sample test
+
+.. code-block:: python
+
+ def test_example_postgres(postgresql):
+ """Check main postgresql fixture."""
+ cur = postgresql.cursor()
+ cur.execute("CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);")
+ postgresql.commit()
+ cur.close()
+
+If you want the database fixture to be automatically populated with your schema there are two ways:
+
+#. client fixture specific
+#. process fixture specific
+
+Both are accepting same set of possible loaders:
+
+* sql file path
+* loading function import path (string)
+* actual loading function
+
+That function will receive **host**, **port**, **user**, **dbname** and **password** kwargs and will have to perform
+connection to the database inside. However, you'll be able to run SQL files or even trigger programmatically database
+migrations you have.
+
+Client specific loads the database each test
+
+.. code-block:: python
+
+ postgresql_my_with_schema = factories.postgresql(
+ 'postgresql_my_proc',
+ load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
+ )
+
+.. warning::
+
+ This way, the database will still be dropped each time.
+
+
+The process fixture performs the load once per test session, and loads the data into the template database.
+Client fixture then creates test database out of the template database each test, which significantly speeds up the tests.
+
+.. code-block:: python
+
+ postgresql_my_proc = factories.postgresql_proc(
+ load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
+ )
+
+
+.. code-block:: bash
+
+ pytest --postgresql-populate-template=path.to.loading_function --postgresql-populate-template=path.to.other:loading_function --postgresql-populate-template=path/to/file.sql
+
+
+The loading_function from example will receive , and have to commit that.
+Connecting to already existing postgresql database
+--------------------------------------------------
+
+Some projects are using already running postgresql servers (ie on docker instances).
+In order to connect to them, one would be using the ``postgresql_noproc`` fixture.
+
+.. code-block:: python
+
+ postgresql_external = factories.postgresql('postgresql_noproc')
+
+By default the ``postgresql_noproc`` fixture would connect to postgresql instance using **5432** port. Standard configuration options apply to it.
+
+These are the configuration options that are working on all levels with the ``postgresql_noproc`` fixture:
+
+Configuration
+=============
+
+You can define your settings in three ways, it's fixture factory argument, command line option and pytest.ini configuration option.
+You can pick which you prefer, but remember that these settings are handled in the following order:
+
+ * ``Fixture factory argument``
+ * ``Command line option``
+ * ``Configuration option in your pytest.ini file``
+
+
+.. list-table:: Configuration options
+ :header-rows: 1
+
+ * - PostgreSQL option
+ - Fixture factory argument
+ - Command line option
+ - pytest.ini option
+ - Noop process fixture
+ - Default
+ * - Path to executable
+ - executable
+ - --postgresql-exec
+ - postgresql_exec
+ - -
+ - /usr/lib/postgresql/9.6/bin/pg_ctl
+ * - host
+ - host
+ - --postgresql-host
+ - postgresql_host
+ - yes
+ - 127.0.0.1
+ * - port
+ - port
+ - --postgresql-port
+ - postgresql_port
+ - yes (5432)
+ - random
+ * - postgresql user
+ - user
+ - --postgresql-user
+ - postgresql_user
+ - yes
+ - postgres
+ * - password
+ - password
+ - --postgresql-password
+ - postgresql_password
+ - yes
+ -
+ * - Starting parameters (extra pg_ctl arguments)
+ - startparams
+ - --postgresql-startparams
+ - postgresql_startparams
+ - -
+ - -w
+ * - Postgres exe extra arguments (passed via pg_ctl's -o argument)
+ - postgres_options
+ - --postgresql-postgres-options
+ - postgresql_postgres_options
+ - -
+ -
+ * - Log filename's prefix
+ - logsprefix
+ - --postgresql-logsprefix
+ - postgresql_logsprefix
+ - -
+ -
+ * - Location for unixsockets
+ - unixsocket
+ - --postgresql-unixsocketdir
+ - postgresql_unixsocketdir
+ - -
+ - $TMPDIR
+ * - Database name
+ - dbname
+ - --postgresql-dbname
+ - postgresql_dbname
+ - -
+ - test
+ * - Default Schema either in sql files or import path to function that will load it (list of values for each)
+ - load
+ - --postgresql-load
+ - postgresql_load
+ - yes
+ -
+ * - PostgreSQL connection options
+ - options
+ - --postgresql-options
+ - postgresql_options
+ - yes
+ -
+
+
+Example usage:
+
+* pass it as an argument in your own fixture
+
+ .. code-block:: python
+
+ postgresql_proc = factories.postgresql_proc(
+ port=8888)
+
+* use ``--postgresql-port`` command line option when you run your tests
+
+ .. code-block::
+
+ py.test tests --postgresql-port=8888
+
+
+* specify your port as ``postgresql_port`` in your ``pytest.ini`` file.
+
+ To do so, put a line like the following under the ``[pytest]`` section of your ``pytest.ini``:
+
+ .. code-block:: ini
+
+ [pytest]
+ postgresql_port = 8888
+
+Examples
+========
+
+Populating database for tests
+-----------------------------
+
+With SQLAlchemy
++++++++++++++++
+
+This example shows how to populate database and create an SQLAlchemy's ORM connection:
+
+Sample below is simplified session fixture from
+`pyramid_fullauth `_ tests:
+
+.. code-block:: python
+
+ from sqlalchemy import create_engine
+ from sqlalchemy.orm import scoped_session, sessionmaker
+ from sqlalchemy.pool import NullPool
+ from zope.sqlalchemy import register
+
+
+ @pytest.fixture
+ def db_session(postgresql):
+ """Session for SQLAlchemy."""
+ from pyramid_fullauth.models import Base
+
+ connection = f'postgresql+psycopg2://{postgresql.info.user}:@{postgresql.info.host}:{postgresql.info.port}/{postgresql.info.dbname}'
+
+ engine = create_engine(connection, echo=False, poolclass=NullPool)
+ pyramid_basemodel.Session = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
+ pyramid_basemodel.bind_engine(
+ engine, pyramid_basemodel.Session, should_create=True, should_drop=True)
+
+ yield pyramid_basemodel.Session
+
+ transaction.commit()
+ Base.metadata.drop_all(engine)
+
+
+ @pytest.fixture
+ def user(db_session):
+ """Test user fixture."""
+ from pyramid_fullauth.models import User
+ from tests.tools import DEFAULT_USER
+
+ new_user = User(**DEFAULT_USER)
+ db_session.add(new_user)
+ transaction.commit()
+ return new_user
+
+
+ def test_remove_last_admin(db_session, user):
+ """
+ Sample test checks internal login, but shows usage in tests with SQLAlchemy
+ """
+ user = db_session.merge(user)
+ user.is_admin = True
+ transaction.commit()
+ user = db_session.merge(user)
+
+ with pytest.raises(AttributeError):
+ user.is_admin = False
+.. note::
+
+ See the original code at `pyramid_fullauth's conftest file `_.
+ Depending on your needs, that in between code can fire alembic migrations in case of sqlalchemy stack or any other code
+
+Maintaining database state outside of the fixtures
+--------------------------------------------------
+
+It is possible and appears it's used in other libraries for tests,
+to maintain database state with the use of the ``pytest-postgresql`` database
+managing functionality:
+
+For this import DatabaseJanitor and use its init and drop methods:
+
+
+.. code-block:: python
+
+ import pytest
+ from pytest_postgresql.janitor import DatabaseJanitor
+
+ @pytest.fixture
+ def database(postgresql_proc):
+ # variable definition
+
+ janitor = DatabaseJanitor(
+ postgresql_proc.user,
+ postgresql_proc.host,
+ postgresql_proc.port,
+ "my_test_database",
+ postgresql_proc.version,
+ password="secret_password,
+ ):
+ janitor.init()
+ yield psycopg2.connect(
+ dbname="my_test_database",
+ user=postgresql_proc.user,
+ password="secret_password",
+ host=postgresql_proc.host,
+ port=postgresql_proc.port,
+ )
+ janitor.drop()
+
+or use it as a context manager:
+
+.. code-block:: python
+
+ import pytest
+ from pytest_postgresql.janitor import DatabaseJanitor
+
+ @pytest.fixture
+ def database(postgresql_proc):
+ # variable definition
+
+ with DatabaseJanitor(
+ postgresql_proc.user,
+ postgresql_proc.host,
+ postgresql_proc.port,
+ "my_test_database",
+ postgresql_proc.version,
+ password="secret_password,
+ ):
+ yield psycopg2.connect(
+ dbname="my_test_database",
+ user=postgresql_proc.user,
+ password="secret_password",
+ host=postgresql_proc.host,
+ port=postgresql_proc.port,
+ )
+
+.. note::
+
+ DatabaseJanitor manages the state of the database, but you'll have to create
+ connection to use in test code yourself.
+
+ You can optionally pass in a recognized postgresql ISOLATION_LEVEL for
+ additional control.
+
+.. note::
+
+ See DatabaseJanitor usage in python's warehouse test code https://github.com/pypa/warehouse/blob/5d15bfe/tests/conftest.py#L127
+
+Connecting to Postgresql (in a docker)
+--------------------------------------
+
+To connect to a docker run postgresql and run test on it, use noproc fixtures.
+
+.. code-block:: sh
+
+ docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres
+
+This will start postgresql in a docker container, however using a postgresql installed locally is not much different.
+
+In tests, make sure that all your tests are using **postgresql_noproc** fixture like that:
+
+.. code-block:: python
+
+ postgresql_in_docker = factories.postgresql_noproc()
+ postresql = factories.postgresql("postgresql_in_docker", db_name="test")
+
+
+ def test_postgres_docker(postresql):
+ """Run test."""
+ cur = postgresql.cursor()
+ cur.execute("CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);")
+ postgresql.commit()
+ cur.close()
+
+And run tests:
+
+.. code-block:: sh
+
+ pytest --postgresql-host=172.17.0.2 --postgresql-password=mysecretpassword
+
+Using a common database initialisation between tests
+----------------------------------------------------
+
+If you've got several tests that require common initialisation, you need to define a `load` and pass it to
+your custom postgresql process fixture:
+
+.. code-block:: python
+
+ import pytest_postgresql.factories
+ def load_database(**kwargs):
+ db_connection: connection = psycopg2.connect(**kwargs)
+ with db_connection.cursor() as cur:
+ cur.execute("CREATE TABLE stories (id serial PRIMARY KEY, name varchar);")
+ cur.execute(
+ "INSERT INTO stories (name) VALUES"
+ "('Silmarillion'), ('Star Wars'), ('The Expanse'), ('Battlestar Galactica')"
+ )
+ db_connection.commit()
+
+ postgresql_proc = factories.postgresql_proc(
+ load=[load_database],
+ )
+
+ postgresql = factories.postgresql(
+ "postgresql_proc",
+ )
+
+You can also define your own database name by passing same dbname value
+to **both** factories.
+
+The way this will work is that the process fixture will populate template database,
+which in turn will be used automatically by client fixture to create a test database from scratch.
+Fast, clean and no dangling transactions, that could be accidentally rolled back.
+
+Same approach will work with noproces fixture, while connecting to already running postgresql instance whether
+it'll be on a docker machine or running remotely or locally.
+
+CHANGELOG
+=========
+
+3.1.3
+----------
+
+Cherry picked from v4.x
+
+Misc
+++++
+
+- Import FixtureRequest from pytest, not private _pytest.
+ Require at least pytest 6.2
+- Replace tmpdir_factory with tmp_path_factory
+- Add Postgresql 14 to the CI
+
+3.1.2
+----------
+
+Bugfix
+++++++
+
+- Database can be created by DatabaseJanitor or the client fixture when an isolation
+ level is specified.
+
+3.1.1
+----------
+
+Misc
+++++
+
+- rely on `get_port` functionality delivered by `port_for`
+
+3.1.0
+----------
+
+Features
+++++++++
+
+- Added type annotations and compatibitlity with PEP 561
+
+Misc
+++++
+
+- pre-commit configuration
+
+3.0.2
+----------
+
+Bugfix
+++++++
+
+- Changed `UPDATE pg_database SET` to `ALTER`. System tables should not be updated.
+
+3.0.1
+----------
+
+Bugfix
+++++++
+
+- Fixed DatabaseJanitor port type hint to int from str
+- Changed retry definition to not fail if psycopg2 is not installed.
+ Now the default is Exception.
+
+Misc
+++++
+
+- Support python 3.7 and up
+
+3.0.0
+----------
+
+Features
+++++++++
+
+- Ability to create template database once for the process fixture and
+ re-recreate a clean database out of it every test. Not only it does provide some
+ common db initialisation between tests but also can speed up tests significantly,
+ especially if the initialisation has lots of operations to perform.
+- DatabaseJanitor can now define a `connection_timeout` parameter.
+ How long will it try to connect to database before raising a TimeoutError
+- Updated supported python versions
+- Unified temporary directory handling in fixture. Settled on tmpdir_factory.
+- Fully moved to the Github Actions as CI/CD pipeline
+
+Deprecations
+++++++++++++
+
+- Deprecated support for `logs_prefix` process fixture factory argument,
+ `--postgresql-logsprefix` pytest command line option and `postgresql_logsprefix`
+ ini configuration option. tmpdir_factory now builds pretty unique temporary directory structure.
+
+Backward Incompatibilities
+++++++++++++++++++++++++++
+
+- Dropped support for postgresql 9.5 and down
+- Removed init_postgresql_database and drop_postgresql_database functions.
+ They were long deprecated and their role perfectly covered by DatabaseJanitor class.
+- `pytest_postgresql.factories.get_config` was moved to `pytest_postgresql.config.get_config`
+- all `db_name` keywords and attributes were renamed to `dbname`
+- postgresql_nooproc fixture was renamed to postgresql_noproc
+
+Bugfix
+++++++
+
+- Use `postgresql_logsprefix` and `--postgresql-logsprefix` again.
+ They were stopped being used somewhere along the way.
+- Sometimes pytest-postrgesql would fail to start postgresql with
+ "FATAL: the database system is starting up" message. It's not really a fatal error,
+ but a message indicating that the process still starts. Now pytest-postgresql will wait properly in this cases.
+
+2.6.1
+----------
+
+- [bugfix] To not fail loading code if no postgresql version is installed.
+ Fallback for janitor and process fixture only, if called upon.
+
+2.6.0
+----------
+
+- [enhancement] add ability to pass options to pg_ctl's -o flag to send arguments to the underlying postgres executable
+ Use `postgres_options` as fixture argument, `--postgresql-postgres-options` as pytest starting option or
+ `postgresql_postgres_options` as pytest.ini configuration option
+
+2.5.3
+----------
+
+- [enhancement] Add ability to set up isolation level for fixture and janitor
+
+2.5.2
+----------
+
+- [fix] Status checks for running postgres depend on pg_ctl status code,
+ not on pg_ctl log language. Fixes starting on systems without C locale.
+ Thanks @Martin Meyries.
+
+
+2.5.1
+----------
+
+- [fix] Added LC_* env vars to running initdb and other utilities.
+ Now all tools and server are using same, C locale
+
+
+2.5.0
+----------
+
+- [feature] Ability to define default schema to initialize database with
+- [docs] Added more examples to readme on how to use the plugin
+
+
+2.4.1
+----------
+
+- [enhancement] extract NoopExecutor into it's own submodule
+- [bugfix] Ignore occasional `ProcessFinishedWithError` error on executor exit.
+- [bugfix] Fixed setting custom password for process fixture
+- [bugfix] Fix version detection, to allow for two-digit minor version part
+
+2.4.0
+----------
+
+- [feature] Drop support for pyhon 3.5
+- [enhancement] require at least mirakuru 2.3.0 (executor's stop method parameter's change)
+- [bug] pass password to DatabaseJanitor in client's factory
+
+2.3.0
+----------
+
+- [feature] Allow to set password for postgresql. Use it throughout the flow.
+- [bugfix] Default Janitor's connections to postgres database. When using custom users,
+ postgres attempts to use user's database and it might not exist.
+- [bugfix] NoopExecutor connects to read version by context manager to properly handle cases
+ where it can't connect to the server.
+
+2.2.1
+----------
+
+- [bugfix] Fix drop_postgresql_database to actually use DatabaseJanitor.drop instead of an init
+
+2.2.0
+----------
+
+- [feature] ability to properly connect to already existing postgresql server using ``postgresql_nooproc`` fixture.
+
+2.1.0
+----------
+
+- [enhancement] Gather helper functions maintaining postgresql database in DatabaseJanitor class.
+- [deprecate] Deprecate ``init_postgresql_database`` in favour of ``DatabaseJanitor.init``
+- [deprecate] Deprecate ``drop_postgresql_database`` in favour of ``DatabaseJanitor.drop``
+
+2.0.0
+----------
+
+- [feature] Drop support for python 2.7. From now on, only support python 3.5 and up
+- [feature] Ability to configure database name through plugin options
+- [enhancement] Use tmpdir_factory. Drop ``logsdir`` parameter
+- [ehnancement] Support only Postgresql 9.0 and up
+- [bugfix] Always start postgresql with LC_ALL, LC_TYPE and LANG set to C.UTF-8.
+ It makes postgresql start in english.
+
+1.4.1
+----------
+
+- [bugfix] Allow creating test databse with hyphens
+
+1.4.0
+----------
+
+- [enhancements] Ability to configure additional options for postgresql process and connection
+- [bugfix] - removed hard dependency on ``psycopg2``, allowing any of its alternative packages, like
+ ``psycopg2-binary``, to be used.
+- [maintenance] Drop support for python 3.4 and use 3.7 instead
+
+1.3.4
+----------
+
+- [bugfix] properly detect if executor running and clean after executor is being stopped
+
+ .. note::
+
+ Previously if a test failed, there was a possibility of the executor being removed when python was closing,
+ causing it to print ignored errors on already unloaded modules.
+
+1.3.3
+----------
+
+- [enhancement] use executor's context manager to start/stop postrgesql server in a fixture
+
+1.3.2
+----------
+
+- [bugfix] version regexp to correctly catch postgresql 10
+
+1.3.1
+----------
+
+- [enhancement] explicitly turn off logging_collector
+
+1.3.0
+----------
+
+- [feature] pypy compatibility
+
+1.2.0
+----------
+
+- [bugfix] - disallow connection to database before it gets dropped.
+
+ .. note::
+
+ Otherwise it caused random test subprocess to connect again and this the drop was unsucessfull which resulted in many more test failes on setup.
+
+- [cleanup] - removed path.py dependency
+
+1.1.1
+----------
+
+- [bugfix] - Fixing the default pg_ctl path creation
+
+1.1.0
+----------
+
+- [feature] - migrate usage of getfuncargvalue to getfixturevalue. require at least pytest 3.0.0
+
+1.0.0
+----------
+
+- create command line and pytest.ini configuration options for postgresql starting parameters
+- create command line and pytest.ini configuration options for postgresql username
+- make the port random by default
+- create command line and pytest.ini configuration options for executable
+- create command line and pytest.ini configuration options for host
+- create command line and pytest.ini configuration options for port
+- Extracted code from pytest-dbfixtures
+
+
diff --git a/README.rst b/README.rst
index 6306bc1..c54587b 100644
--- a/README.rst
+++ b/README.rst
@@ -1,231 +1,476 @@
.. image:: https://raw.githubusercontent.com/ClearcodeHQ/pytest-postgresql/master/logo.png
:width: 100px
:height: 100px
pytest-postgresql
=================
.. image:: https://img.shields.io/pypi/v/pytest-postgresql.svg
:target: https://pypi.python.org/pypi/pytest-postgresql/
:alt: Latest PyPI version
.. image:: https://img.shields.io/pypi/wheel/pytest-postgresql.svg
:target: https://pypi.python.org/pypi/pytest-postgresql/
:alt: Wheel Status
.. image:: https://img.shields.io/pypi/pyversions/pytest-postgresql.svg
:target: https://pypi.python.org/pypi/pytest-postgresql/
:alt: Supported Python Versions
.. image:: https://img.shields.io/pypi/l/pytest-postgresql.svg
:target: https://pypi.python.org/pypi/pytest-postgresql/
:alt: License
-Package status
---------------
-
-.. image:: https://travis-ci.org/ClearcodeHQ/pytest-postgresql.svg?branch=v2.2.0
- :target: https://travis-ci.org/ClearcodeHQ/pytest-postgresql
- :alt: Tests
-
-.. image:: https://coveralls.io/repos/ClearcodeHQ/pytest-postgresql/badge.png?branch=v2.2.0
- :target: https://coveralls.io/r/ClearcodeHQ/pytest-postgresql?branch=v2.2.0
- :alt: Coverage Status
-
What is this?
=============
This is a pytest plugin, that enables you to test your code that relies on a running PostgreSQL Database.
It allows you to specify fixtures for PostgreSQL process and client.
How to use
==========
.. warning::
- Tested on PostgreSQL versions > 9.x. See tests for more details.
+ Tested on PostgreSQL versions >= 9.6. See tests for more details.
Install with:
.. code-block:: sh
pip install pytest-postgresql
-You will also need to install ``psycopg2``, or one of its alternative packagings such as ``psycopg2-binary``
+You will also need to install ``psycopg2`` (2.9 or newer), or one of its alternative packagings such as ``psycopg2-binary``
(pre-compiled wheels) or ``psycopg2cffi`` (CFFI based, useful on PyPy).
-Plugin contains two fixtures:
+Plugin contains three fixtures:
-* **postgresql** - it's a client fixture that has functional scope. After each test it ends all leftover connections, and drops test database from PostgreSQL ensuring repeatability.
-* **postgresql_proc** - session scoped fixture, that starts PostgreSQL instance at it's first use and stops at the end of the tests.
+* **postgresql** - it's a client fixture that has functional scope.
+ After each test it ends all leftover connections, and drops test database
+ from PostgreSQL ensuring repeatability.
+ This fixture returns already connected psycopg2 connection.
+
+* **postgresql_proc** - session scoped fixture, that starts PostgreSQL instance
+ at it's first use and stops at the end of the tests.
+* **postgresql_noproc** - a noprocess fixture, that's connecting to already
+ running postgresql instance.
+ For example on dockerized test environments, or CI providing postgresql services
Simply include one of these fixtures into your tests fixture list.
You can also create additional postgresql client and process fixtures if you'd need to:
.. code-block:: python
from pytest_postgresql import factories
postgresql_my_proc = factories.postgresql_proc(
port=None, unixsocketdir='/var/run')
postgresql_my = factories.postgresql('postgresql_my_proc')
.. note::
Each PostgreSQL process fixture can be configured in a different way than the others through the fixture factory arguments.
+Sample test
+
+.. code-block:: python
+
+ def test_example_postgres(postgresql):
+ """Check main postgresql fixture."""
+ cur = postgresql.cursor()
+ cur.execute("CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);")
+ postgresql.commit()
+ cur.close()
+
+If you want the database fixture to be automatically populated with your schema there are two ways:
+
+#. client fixture specific
+#. process fixture specific
+
+Both are accepting same set of possible loaders:
+
+* sql file path
+* loading function import path (string)
+* actual loading function
+
+That function will receive **host**, **port**, **user**, **dbname** and **password** kwargs and will have to perform
+connection to the database inside. However, you'll be able to run SQL files or even trigger programmatically database
+migrations you have.
+
+Client specific loads the database each test
+
+.. code-block:: python
+
+ postgresql_my_with_schema = factories.postgresql(
+ 'postgresql_my_proc',
+ load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
+ )
+
+.. warning::
+
+ This way, the database will still be dropped each time.
+
+
+The process fixture performs the load once per test session, and loads the data into the template database.
+Client fixture then creates test database out of the template database each test, which significantly speeds up the tests.
+
+.. code-block:: python
+
+ postgresql_my_proc = factories.postgresql_proc(
+ load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
+ )
+
+
+.. code-block:: bash
+
+ pytest --postgresql-populate-template=path.to.loading_function --postgresql-populate-template=path.to.other:loading_function --postgresql-populate-template=path/to/file.sql
+
+
+The loading_function from example will receive , and have to commit that.
Connecting to already existing postgresql database
--------------------------------------------------
Some projects are using already running postgresql servers (ie on docker instances).
-In order to connect to them, one would be using the ``postgresql_nooproc`` fixture.
+In order to connect to them, one would be using the ``postgresql_noproc`` fixture.
.. code-block:: python
- postgresql_external = factories.postgresql('postgresql_nooproc')
+ postgresql_external = factories.postgresql('postgresql_noproc')
-By default the ``postgresql_nooproc`` fixture would connect to postgresql instance using **5432** port. Standard configuration options apply to it.
+By default the ``postgresql_noproc`` fixture would connect to postgresql instance using **5432** port. Standard configuration options apply to it.
-These are the configuration options that are working on all levels with the ``postgresql_nooproc`` fixture:
+These are the configuration options that are working on all levels with the ``postgresql_noproc`` fixture:
Configuration
=============
You can define your settings in three ways, it's fixture factory argument, command line option and pytest.ini configuration option.
You can pick which you prefer, but remember that these settings are handled in the following order:
* ``Fixture factory argument``
* ``Command line option``
* ``Configuration option in your pytest.ini file``
.. list-table:: Configuration options
:header-rows: 1
* - PostgreSQL option
- Fixture factory argument
- Command line option
- pytest.ini option
- - Noop process fixrture
+ - Noop process fixture
- Default
* - Path to executable
- executable
- --postgresql-exec
- postgresql_exec
- -
- - /usr/lib/postgresql/9.1/bin/pg_ctl
+ - /usr/lib/postgresql/9.6/bin/pg_ctl
* - host
- host
- --postgresql-host
- postgresql_host
- yes
- 127.0.0.1
* - port
- port
- --postgresql-port
- postgresql_port
- - yes (5436)
+ - yes (5432)
- random
* - postgresql user
- user
- --postgresql-user
- postgresql_user
- yes
- postgres
- * - Starting parameters
+ * - password
+ - password
+ - --postgresql-password
+ - postgresql_password
+ - yes
+ -
+ * - Starting parameters (extra pg_ctl arguments)
- startparams
- --postgresql-startparams
- postgresql_startparams
- -
- -w
+ * - Postgres exe extra arguments (passed via pg_ctl's -o argument)
+ - postgres_options
+ - --postgresql-postgres-options
+ - postgresql_postgres_options
+ - -
+ -
* - Log filename's prefix
- logsprefix
- --postgresql-logsprefix
- postgresql_logsprefix
- -
-
* - Location for unixsockets
- unixsocket
- --postgresql-unixsocketdir
- postgresql_unixsocketdir
- -
- $TMPDIR
* - Database name
- - db_name
+ - dbname
- --postgresql-dbname
- postgresql_dbname
- -
- test
+ * - Default Schema either in sql files or import path to function that will load it (list of values for each)
+ - load
+ - --postgresql-load
+ - postgresql_load
+ - yes
+ -
* - PostgreSQL connection options
- options
- --postgresql-options
- postgresql_options
- yes
-
Example usage:
* pass it as an argument in your own fixture
.. code-block:: python
postgresql_proc = factories.postgresql_proc(
port=8888)
* use ``--postgresql-port`` command line option when you run your tests
.. code-block::
py.test tests --postgresql-port=8888
* specify your port as ``postgresql_port`` in your ``pytest.ini`` file.
To do so, put a line like the following under the ``[pytest]`` section of your ``pytest.ini``:
.. code-block:: ini
[pytest]
postgresql_port = 8888
+Examples
+========
+
+Populating database for tests
+-----------------------------
+
+With SQLAlchemy
++++++++++++++++
+
+This example shows how to populate database and create an SQLAlchemy's ORM connection:
+
+Sample below is simplified session fixture from
+`pyramid_fullauth `_ tests:
+
+.. code-block:: python
+
+ from sqlalchemy import create_engine
+ from sqlalchemy.orm import scoped_session, sessionmaker
+ from sqlalchemy.pool import NullPool
+ from zope.sqlalchemy import register
+
+
+ @pytest.fixture
+ def db_session(postgresql):
+ """Session for SQLAlchemy."""
+ from pyramid_fullauth.models import Base
+
+ connection = f'postgresql+psycopg2://{postgresql.info.user}:@{postgresql.info.host}:{postgresql.info.port}/{postgresql.info.dbname}'
+
+ engine = create_engine(connection, echo=False, poolclass=NullPool)
+ pyramid_basemodel.Session = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
+ pyramid_basemodel.bind_engine(
+ engine, pyramid_basemodel.Session, should_create=True, should_drop=True)
+
+ yield pyramid_basemodel.Session
+
+ transaction.commit()
+ Base.metadata.drop_all(engine)
+
+
+ @pytest.fixture
+ def user(db_session):
+ """Test user fixture."""
+ from pyramid_fullauth.models import User
+ from tests.tools import DEFAULT_USER
+
+ new_user = User(**DEFAULT_USER)
+ db_session.add(new_user)
+ transaction.commit()
+ return new_user
+
+
+ def test_remove_last_admin(db_session, user):
+ """
+ Sample test checks internal login, but shows usage in tests with SQLAlchemy
+ """
+ user = db_session.merge(user)
+ user.is_admin = True
+ transaction.commit()
+ user = db_session.merge(user)
+
+ with pytest.raises(AttributeError):
+ user.is_admin = False
+.. note::
+
+ See the original code at `pyramid_fullauth's conftest file `_.
+ Depending on your needs, that in between code can fire alembic migrations in case of sqlalchemy stack or any other code
+
Maintaining database state outside of the fixtures
--------------------------------------------------
It is possible and appears it's used in other libraries for tests,
to maintain database state with the use of the ``pytest-postgresql`` database
managing functionality:
-For this import DatabaseJanitor and use it's init and drop methods:
+For this import DatabaseJanitor and use its init and drop methods:
.. code-block:: python
- from pytest_postgresql.factories import DatabaseJanitor
+ import pytest
+ from pytest_postgresql.janitor import DatabaseJanitor
+
+ @pytest.fixture
+ def database(postgresql_proc):
+ # variable definition
+
+ janitor = DatabaseJanitor(
+ postgresql_proc.user,
+ postgresql_proc.host,
+ postgresql_proc.port,
+ "my_test_database",
+ postgresql_proc.version,
+ password="secret_password,
+ ):
+ janitor.init()
+ yield psycopg2.connect(
+ dbname="my_test_database",
+ user=postgresql_proc.user,
+ password="secret_password",
+ host=postgresql_proc.host,
+ port=postgresql_proc.port,
+ )
+ janitor.drop()
- # variable definition
+or use it as a context manager:
- janitor = DatabaseJanitor(user, host, port, db_name, version)
- janitor.init()
- # your code, or yield
- janitor.drop()
- # at this moment you'll have clean database step
+.. code-block:: python
-or use it as a context manager:
+ import pytest
+ from pytest_postgresql.janitor import DatabaseJanitor
+
+ @pytest.fixture
+ def database(postgresql_proc):
+ # variable definition
+
+ with DatabaseJanitor(
+ postgresql_proc.user,
+ postgresql_proc.host,
+ postgresql_proc.port,
+ "my_test_database",
+ postgresql_proc.version,
+ password="secret_password,
+ ):
+ yield psycopg2.connect(
+ dbname="my_test_database",
+ user=postgresql_proc.user,
+ password="secret_password",
+ host=postgresql_proc.host,
+ port=postgresql_proc.port,
+ )
+
+.. note::
+
+ DatabaseJanitor manages the state of the database, but you'll have to create
+ connection to use in test code yourself.
+
+ You can optionally pass in a recognized postgresql ISOLATION_LEVEL for
+ additional control.
+
+.. note::
+
+ See DatabaseJanitor usage in python's warehouse test code https://github.com/pypa/warehouse/blob/5d15bfe/tests/conftest.py#L127
+
+Connecting to Postgresql (in a docker)
+--------------------------------------
+
+To connect to a docker run postgresql and run test on it, use noproc fixtures.
+
+.. code-block:: sh
+
+ docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres
+
+This will start postgresql in a docker container, however using a postgresql installed locally is not much different.
+
+In tests, make sure that all your tests are using **postgresql_noproc** fixture like that:
.. code-block:: python
- from pytest_postgresql.factories import DatabaseJanitor
+ postgresql_in_docker = factories.postgresql_noproc()
+ postresql = factories.postgresql("postgresql_in_docker", db_name="test")
+
- # variable definition
+ def test_postgres_docker(postresql):
+ """Run test."""
+ cur = postgresql.cursor()
+ cur.execute("CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);")
+ postgresql.commit()
+ cur.close()
- with DatabaseJanitor(user, host, port, db_name, version):
- # do something here
+And run tests:
-Package resources
------------------
+.. code-block:: sh
+
+ pytest --postgresql-host=172.17.0.2 --postgresql-password=mysecretpassword
+
+Using a common database initialisation between tests
+----------------------------------------------------
-* Bug tracker: https://github.com/ClearcodeHQ/pytest-postgresql/issues
+If you've got several tests that require common initialisation, you need to define a `load` and pass it to
+your custom postgresql process fixture:
+
+.. code-block:: python
+ import pytest_postgresql.factories
+ def load_database(**kwargs):
+ db_connection: connection = psycopg2.connect(**kwargs)
+ with db_connection.cursor() as cur:
+ cur.execute("CREATE TABLE stories (id serial PRIMARY KEY, name varchar);")
+ cur.execute(
+ "INSERT INTO stories (name) VALUES"
+ "('Silmarillion'), ('Star Wars'), ('The Expanse'), ('Battlestar Galactica')"
+ )
+ db_connection.commit()
+
+ postgresql_proc = factories.postgresql_proc(
+ load=[load_database],
+ )
+
+ postgresql = factories.postgresql(
+ "postgresql_proc",
+ )
+
+You can also define your own database name by passing same dbname value
+to **both** factories.
+
+The way this will work is that the process fixture will populate template database,
+which in turn will be used automatically by client fixture to create a test database from scratch.
+Fast, clean and no dangling transactions, that could be accidentally rolled back.
+
+Same approach will work with noproces fixture, while connecting to already running postgresql instance whether
+it'll be on a docker machine or running remotely or locally.
diff --git a/docs/Makefile b/docs/Makefile
deleted file mode 100644
index fe20658..0000000
--- a/docs/Makefile
+++ /dev/null
@@ -1,153 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = build
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
-
-.PHONY: help clean html html_venv dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
- @echo "Please use \`make ' where is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " singlehtml to make a single large HTML file"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " devhelp to make HTML files and a Devhelp project"
- @echo " epub to make an epub"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " texinfo to make Texinfo files"
- @echo " info to make Texinfo files and run them through makeinfo"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
-
-clean:
- -rm -rf $(BUILDDIR)/*
-
-html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Subscribepyramidplugin.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Subscribepyramidplugin.qhc"
-
-devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
- @echo
- @echo "Build finished."
- @echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/Subscribepyramidplugin"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Subscribepyramidplugin"
- @echo "# devhelp"
-
-epub:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make' in that directory to run these through (pdf)latex" \
- "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through pdflatex..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo
- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
- @echo "Run \`make' in that directory to run these through makeinfo" \
- "(use \`make info' here to do that automatically)."
-
-info:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo "Running Texinfo files through makeinfo..."
- make -C $(BUILDDIR)/texinfo info
- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
- @echo
- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/make.bat b/docs/make.bat
deleted file mode 100644
index 0c5f8f6..0000000
--- a/docs/make.bat
+++ /dev/null
@@ -1,190 +0,0 @@
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
-set I18NSPHINXOPTS=%SPHINXOPTS% source
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^` where ^ is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Subscribepyramidplugin.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Subscribepyramidplugin.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-:end
diff --git a/docs/source/authors.rst b/docs/source/authors.rst
deleted file mode 100644
index 0181789..0000000
--- a/docs/source/authors.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-.. _authors:
-
-.. include:: ../../AUTHORS.rst
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
deleted file mode 100644
index cca3726..0000000
--- a/docs/source/changelog.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-.. _changelog:
-
-.. include:: ../../CHANGES.rst
diff --git a/docs/source/conf.py b/docs/source/conf.py
deleted file mode 100644
index fcd61b2..0000000
--- a/docs/source/conf.py
+++ /dev/null
@@ -1,312 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 2016 by Clearcode
-# and associates (see AUTHORS).
-
-# This file is part of pytest-postgresql.
-
-# pytest-postgresql is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# pytest-postgresql is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public License
-# along with pytest-postgresql. If not, see .
-
-
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-# sys.path.insert(0, os.path.abspath('.'))
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-# needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc',
- 'sphinx.ext.viewcode',
- 'sphinx.ext.intersphinx']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-# source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = 'pytest-postgresql'
-basename = ''.join(project.split('.'))
-author = 'Clearcode - The A Room'
-copyright = '2016, ' + author
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-
-from pypt import __version__
-
-# The full version, including alpha/beta/rc tags.
-release = __version__
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-# language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-# today = ''
-# Else, today_fmt is used as the format for a strftime call.
-# today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = []
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-# default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-# add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-# add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-# show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-# modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-# html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# " version documentation".
-# html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-# html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-# html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-# html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-# html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-# html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-# html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-# html_additional_pages = {}
-
-# If false, no module index is generated.
-# html_domain_indices = True
-
-# If false, no index is generated.
-# html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-# html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-# html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-# html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-# html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-# html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-# html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = basename + 'doc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
- # The paper size ('letterpaper' or 'a4paper').
- #'papersize': 'letterpaper',
-
- # The font size ('10pt', '11pt' or '12pt').
- #'pointsize': '10pt',
-
- # Additional stuff for the LaTeX preamble.
- #'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
- ('index', basename + '.tex', project + ' Documentation',
- author, 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-# latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-# latex_use_parts = False
-
-# If true, show page references after internal links.
-# latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-# latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-# latex_appendices = []
-
-# If false, no module index is generated.
-# latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', basename, project + ' Documentation',
- [author], 1)
-]
-
-# If true, show URL addresses after external links.
-# man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', basename, project + ' Documentation',
- author, basename, 'One line description of project.',
- 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-# texinfo_appendices = []
-
-# If false, no module index is generated.
-# texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-# texinfo_show_urls = 'footnote'
-
-
-# -- Options for Epub output ---------------------------------------------------
-
-# Bibliographic Dublin Core info.
-epub_title = project
-epub_author = author
-epub_publisher = author
-epub_copyright = '2016, ' + author
-
-# The language of the text. It defaults to the language option
-# or en if the language is not set.
-# epub_language = ''
-
-# The scheme of the identifier. Typical schemes are ISBN or URL.
-# epub_scheme = ''
-
-# The unique identifier of the text. This can be a ISBN number
-# or the project homepage.
-# epub_identifier = ''
-
-# A unique identification for the text.
-# epub_uid = ''
-
-# A tuple containing the cover image and cover page html template filenames.
-# epub_cover = ()
-
-# HTML files that should be inserted before the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-# epub_pre_files = []
-
-# HTML files shat should be inserted after the pages created by sphinx.
-# The format is a list of tuples containing the path and title.
-# epub_post_files = []
-
-# A list of files that should not be packed into the epub file.
-# epub_exclude_files = []
-
-# The depth of the table of contents in toc.ncx.
-# epub_tocdepth = 3
-
-# Allow duplicate toc entries.
-# epub_tocdup = True
-
-# Autodoc configuration:
-
-autoclass_content = 'both'
-autodoc_default_flags = ['members', 'show-inheritance']
-
-# Intersphinx configuration
-intersphinx_mapping = {'python': ('http://docs.python.org/', None)}
diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst
deleted file mode 100644
index 2b6578f..0000000
--- a/docs/source/contributing.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-.. _contributing:
-
-.. include:: ../../CONTRIBUTING.rst
diff --git a/docs/source/index.rst b/docs/source/index.rst
deleted file mode 100644
index a27d625..0000000
--- a/docs/source/index.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-.. include:: ../../README.rst
-
-Contents
---------
-
-.. toctree::
- :maxdepth: 2
-
- contributing
- changelog
-
-
-License
--------
-
-Copyright (c) 2016 by pypt authors and contributors. See :ref:`authors`
-
-This module is part of pytest-postgresql and is released under
-the MIT License (MIT): http://opensource.org/licenses/MIT
diff --git a/logo.png b/logo.png
deleted file mode 100644
index f667660..0000000
Binary files a/logo.png and /dev/null differ
diff --git a/logo.svg b/logo.svg
deleted file mode 100644
index fc9a109..0000000
--- a/logo.svg
+++ /dev/null
@@ -1,238 +0,0 @@
-
-
diff --git a/pylintrc b/pylintrc
deleted file mode 100644
index 6227ca0..0000000
--- a/pylintrc
+++ /dev/null
@@ -1,479 +0,0 @@
-[MASTER]
-
-# A comma-separated list of package or module names from where C extensions may
-# be loaded. Extensions are loading into the active Python interpreter and may
-# run arbitrary code.
-extension-pkg-whitelist=
-
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS
-
-# Add files or directories matching the regex patterns to the blacklist. The
-# regex matches against base names, not paths.
-ignore-patterns=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
-# number of processors available to use.
-jobs=1
-
-# Control the amount of potential inferred values when inferring a single
-# object. This can help the performance when dealing with large functions or
-# complex, nested conditions.
-limit-inference-results=100
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# Specify a configuration file.
-#rcfile=
-
-# When enabled, pylint would attempt to guess common misconfiguration and emit
-# user-friendly hints instead of false-positive error messages.
-suggestion-mode=yes
-
-# Allow loading of arbitrary C extensions. Extensions are imported into the
-# active Python interpreter and may run arbitrary code.
-unsafe-load-any-extension=no
-
-
-[MESSAGES CONTROL]
-
-# Only show warnings with the listed confidence levels. Leave empty to show
-# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
-confidence=
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifiers separated by comma (,) or put this
-# option multiple times (only on the command line, not in the configuration
-# file where it should appear only once). You can also use "--disable=all" to
-# disable everything first and then reenable specific checks. For example, if
-# you want to run only the similarities checker, you can use "--disable=all
-# --enable=similarities". If you want to run only the classes checker, but have
-# no Warning level messages displayed, use "--disable=all --enable=classes
-# --disable=W".
-disable=
-
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once). See also the "--disable" option for examples.
-enable=c-extension-no-member
-
-
-[REPORTS]
-
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Template used to display messages. This is a python new-style format string
-# used to format the message information. See doc for all details.
-#msg-template=
-
-# Set the output format. Available formats are text, parseable, colorized, json
-# and msvs (visual studio). You can also give a reporter class, e.g.
-# mypackage.mymodule.MyReporterClass.
-output-format=text
-
-# Tells whether to display a full report or only the messages.
-reports=no
-
-# Activate the evaluation score.
-score=yes
-
-
-[REFACTORING]
-
-# Maximum number of nested blocks for function / method body
-max-nested-blocks=5
-
-# Complete name of functions that never returns. When checking for
-# inconsistent-return-statements if a never returning function is called then
-# it will be considered as an explicit return statement and no message will be
-# printed.
-never-returning-functions=sys.exit
-
-
-[FORMAT]
-
-# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
-expected-line-ending-format=
-
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=^\s*(# )??$
-
-# Number of spaces of indent required inside a hanging or continued line.
-indent-after-paren=4
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string=' '
-
-# Maximum number of characters on a single line.
-max-line-length=100
-
-# Maximum number of lines in a module.
-max-module-lines=1000
-
-# List of optional constructs for which whitespace checking is disabled. `dict-
-# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
-# `trailing-comma` allows a space between comma and closing bracket: (a, ).
-# `empty-line` allows space-only lines.
-no-space-check=trailing-comma,
- dict-separator
-
-# Allow the body of a class to be on the same line as the declaration if body
-# contains single statement.
-single-line-class-stmt=no
-
-# Allow the body of an if to be on the same line as the test if there is no
-# else.
-single-line-if-stmt=no
-
-
-[BASIC]
-
-# Naming style matching correct argument names.
-argument-naming-style=snake_case
-
-# Regular expression matching correct argument names. Overrides argument-
-# naming-style.
-#argument-rgx=
-
-# Naming style matching correct attribute names.
-attr-naming-style=snake_case
-
-# Regular expression matching correct attribute names. Overrides attr-naming-
-# style.
-#attr-rgx=
-
-# Bad variable names which should always be refused, separated by a comma.
-bad-names=foo,
- bar,
- baz,
- toto,
- tutu,
- tata
-
-# Naming style matching correct class attribute names.
-class-attribute-naming-style=any
-
-# Regular expression matching correct class attribute names. Overrides class-
-# attribute-naming-style.
-#class-attribute-rgx=
-
-# Naming style matching correct class names.
-class-naming-style=PascalCase
-
-# Regular expression matching correct class names. Overrides class-naming-
-# style.
-#class-rgx=
-
-# Naming style matching correct constant names.
-const-naming-style=UPPER_CASE
-
-# Regular expression matching correct constant names. Overrides const-naming-
-# style.
-#const-rgx=
-
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=-1
-
-# Naming style matching correct function names.
-function-naming-style=snake_case
-
-# Regular expression matching correct function names. Overrides function-
-# naming-style.
-#function-rgx=
-
-# Good variable names which should always be accepted, separated by a comma.
-good-names=i,
- j,
- k,
- ex,
- Run,
- _
-
-# Include a hint for the correct naming format with invalid-name.
-include-naming-hint=no
-
-# Naming style matching correct inline iteration names.
-inlinevar-naming-style=any
-
-# Regular expression matching correct inline iteration names. Overrides
-# inlinevar-naming-style.
-#inlinevar-rgx=
-
-# Naming style matching correct method names.
-method-naming-style=snake_case
-
-# Regular expression matching correct method names. Overrides method-naming-
-# style.
-#method-rgx=
-
-# Naming style matching correct module names.
-module-naming-style=snake_case
-
-# Regular expression matching correct module names. Overrides module-naming-
-# style.
-#module-rgx=
-
-# Colon-delimited sets of names that determine each other's naming style when
-# the name regexes allow several styles.
-name-group=
-
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=^_
-
-# List of decorators that produce properties, such as abc.abstractproperty. Add
-# to this list to register other decorators that produce valid properties.
-# These decorators are taken in consideration only for invalid-name.
-property-classes=abc.abstractproperty
-
-# Naming style matching correct variable names.
-variable-naming-style=snake_case
-
-# Regular expression matching correct variable names. Overrides variable-
-# naming-style.
-#variable-rgx=
-
-
-[SPELLING]
-
-# Limits count of emitted suggestions for spelling mistakes.
-max-spelling-suggestions=4
-
-# Spelling dictionary name. Available dictionaries: none. To make it working
-# install python-enchant package..
-spelling-dict=
-
-# List of comma separated words that should not be checked.
-spelling-ignore-words=
-
-# A path to a file that contains private dictionary; one word per line.
-spelling-private-dict-file=
-
-# Tells whether to store unknown words to indicated private dictionary in
-# --spelling-private-dict-file option instead of raising a message.
-spelling-store-unknown-words=no
-
-
-[TYPECHECK]
-
-# List of decorators that produce context managers, such as
-# contextlib.contextmanager. Add to this list to register other decorators that
-# produce valid context managers.
-contextmanager-decorators=contextlib.contextmanager
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E1101 when accessed. Python regular
-# expressions are accepted.
-generated-members=
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# Tells whether to warn about missing members when the owner of the attribute
-# is inferred to be None.
-ignore-none=yes
-
-# This flag controls whether pylint should warn about no-member and similar
-# checks whenever an opaque object is returned when inferring. The inference
-# can return multiple potential results while evaluating a Python object, but
-# some branches might not be evaluated, which results in partial inference. In
-# that case, it might be useful to still emit no-member and other checks for
-# the rest of the inferred objects.
-ignore-on-opaque-inference=yes
-
-# List of class names for which member attributes should not be checked (useful
-# for classes with dynamically set attributes). This supports the use of
-# qualified names.
-ignored-classes=optparse.Values,thread._local,_thread._local
-
-# List of module names for which member attributes should not be checked
-# (useful for modules/projects where namespaces are manipulated during runtime
-# and thus existing member attributes cannot be deduced by static analysis. It
-# supports qualified module names, as well as Unix pattern matching.
-ignored-modules=
-
-# Show a hint with possible names when a member name was not found. The aspect
-# of finding the hint is based on edit distance.
-missing-member-hint=yes
-
-# The minimum edit distance a name should have in order to be considered a
-# similar match for a missing member name.
-missing-member-hint-distance=1
-
-# The total number of similar names that should be taken in consideration when
-# showing a hint for a missing member.
-missing-member-max-choices=1
-
-
-[VARIABLES]
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-# Tells whether unused global variables should be treated as a violation.
-allow-global-unused-variables=yes
-
-# List of strings which can identify a callback function by name. A callback
-# name must start or end with one of those strings.
-callbacks=cb_,
- _cb
-
-# A regular expression matching the name of dummy variables (i.e. expected to
-# not be used).
-dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore.
-ignored-argument-names=_.*|^ignored_|^unused_
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# List of qualified module names which can have objects that can redefine
-# builtins.
-redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,
- XXX,
- TODO
-
-
-[LOGGING]
-
-# Logging modules to check that the string format arguments are in logging
-# function parameter format.
-logging-modules=logging
-
-
-[SIMILARITIES]
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-# Ignore imports when computing similarities.
-ignore-imports=no
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-
-[CLASSES]
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,
- __new__,
- setUp
-
-# List of member names, which should be excluded from the protected access
-# warning.
-exclude-protected=_asdict,
- _fields,
- _replace,
- _source,
- _make
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-# List of valid names for the first argument in a metaclass class method.
-valid-metaclass-classmethod-first-arg=cls
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method.
-max-args=13
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=7
-
-# Maximum number of boolean expressions in an if statement.
-max-bool-expr=5
-
-# Maximum number of branch for function / method body.
-max-branches=12
-
-# Maximum number of locals for function / method body.
-max-locals=15
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-# Maximum number of return / yield for function / method body.
-max-returns=6
-
-# Maximum number of statements in function / method body.
-max-statements=50
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-
-[IMPORTS]
-
-# Allow wildcard imports from modules that define __all__.
-allow-wildcard-with-all=no
-
-# Analyse import fallback blocks. This can be used to support both Python 2 and
-# 3 compatible code, which means that the block might have code that exists
-# only in one or another interpreter, leading to false positives when analysed.
-analyse-fallback-blocks=no
-
-# Deprecated modules which should not be used, separated by a comma.
-deprecated-modules=optparse,tkinter.tix
-
-# Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled).
-ext-import-graph=
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled).
-import-graph=
-
-# Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled).
-int-import-graph=
-
-# Force import order to recognize a module as part of the standard
-# compatibility libraries.
-known-standard-library=
-
-# Force import order to recognize a module as part of a third party library.
-known-third-party=enchant
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "Exception".
-overgeneral-exceptions=Exception
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..a6e8882
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,8 @@
+[build-system]
+requires = ["setuptools >= 40.6.0", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[tool.black]
+line-length = 100
+target-version = ['py38']
+include = '.*\.pyi?$'
diff --git a/pytest.ini b/pytest.ini
deleted file mode 100644
index 143010f..0000000
--- a/pytest.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[pytest]
-addopts = --max-slave-restart=0 --showlocals --verbose --cov src/pytest_postgresql --cov tests
-postgresql_exec = /usr/lib/postgresql/10/bin/pg_ctl
-testpaths = tests
-xfail_strict = true
diff --git a/requirements-lint.txt b/requirements-lint.txt
deleted file mode 100644
index 6b2c25f..0000000
--- a/requirements-lint.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-# linters
-pycodestyle==2.5.0
-pydocstyle==4.0.1
-pylint==2.4.2
-pygments
-pyroma==2.5
--r requirements-test.txt
\ No newline at end of file
diff --git a/requirements-test.txt b/requirements-test.txt
deleted file mode 100644
index f9ecd3b..0000000
--- a/requirements-test.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-# test runs requirements (versions we'll be testing against) - automatically updated by requires.io
-pip>=9 # minimum installation requirements
-setuptools>=21 # minimum installation requirements
-coverage==4.5.4 # pytest-cov
-pytest==5.2.1
-psycopg2-binary==2.8.3; platform_python_implementation != "PyPy"
-psycopg2cffi==2.8.1; platform_python_implementation == "PyPy"
-port-for==0.4
-mirakuru==2.1.0; python_version>'3.5'
--e .[tests]
diff --git a/setup.cfg b/setup.cfg
index b72fc5f..fc0ab9f 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,7 +1,74 @@
-[pycodestyle]
-max-line-length = 80
+[metadata]
+name = pytest-postgresql
+version = 3.1.3
+url = https://github.com/ClearcodeHQ/pytest-postgresql
+description = Postgresql fixtures and fixture factories for Pytest.
+long_description = file: README.rst, CHANGES.rst
+long_description_content_type = text/x-rst
+keywords = tests, py.test, pytest, fixture, postgresql
+license = LGPLv3+
+maintainer = Grzegorz Śliwiński
+maintainer_email = fizyk+pypi@fizyk.net.pl
+classifiers =
+ Development Status :: 5 - Production/Stable
+ Environment :: Web Environment
+ Intended Audience :: Developers
+ License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
+ Natural Language :: English
+ Operating System :: OS Independent
+ Programming Language :: Python
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Programming Language :: Python :: 3 :: Only
+ Topic :: Software Development :: Libraries :: Python Modules
+ Topic :: Software Development :: Testing
+ Framework :: Pytest
+
+[options]
+zip_safe = False
+include_package_data = True
+python_requires = >= 3.7
+packages = find:
+package_dir =
+ =src
+install_requires =
+ pytest>=6.2.0
+ port-for
+ mirakuru>=2.3.0
+
+[options.entry_points]
+pytest11 =
+ pytest_postgresql = pytest_postgresql.plugin
+
+[options.packages.find]
+where = src
+
+[options.package_data]
+pytest_postgresql = py.typed
+
+[options.extras_require]
+tests =
+ pytest-cov
+ pytest-xdist
+
+[flake8]
+max-line-length = 100
exclude = docs/*,build/*,venv/*
[pydocstyle]
ignore = D203,D212
-match = '(?!docs|build|venv).*\.py'
\ No newline at end of file
+match = '(?!docs|build|venv).*\.py'
+
+[tool:pytest]
+addopts = --max-worker-restart=0 --showlocals --verbose --cov src/pytest_postgresql --cov tests
+testpaths = tests
+xfail_strict = true
+pytester_example_dir = tests/examples
+norecursedirs = examples
+
+[egg_info]
+tag_build =
+tag_date = 0
+
diff --git a/setup.py b/setup.py
index e886937..d989978 100644
--- a/setup.py
+++ b/setup.py
@@ -1,102 +1,22 @@
# -*- coding: utf-8 -*-
-# Copyright (C) 2016 by Clearcode
+# Copyright (C) 2016-2020 by Clearcode
# and associates (see AUTHORS).
# This file is part of pytest-postgresql.
# pytest-postgresql is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# pytest-postgresql is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with pytest-postgresql. If not, see .
"""pytest-postgresql setup.py module."""
+from setuptools import setup
-import os
-from setuptools import setup, find_packages
-
-here = os.path.dirname(__file__)
-
-
-def read(fname):
- """
- Read given file's content.
-
- :param str fname: file name
- :returns: file contents
- :rtype: str
- """
- return open(os.path.join(here, fname)).read()
-
-
-requirements = [
- 'pytest>=3.0.0',
- 'port-for',
- 'mirakuru>=2.0.0'
-]
-
-test_requires = [
- 'pytest-cov==2.7.1',
- 'pytest-xdist==1.29.0',
-]
-
-extras_require = {
- 'docs': ['sphinx'],
- 'tests': test_requires,
-}
-
-setup_requires = [
- 'setuptools>=21',
- 'pip>=9'
-]
-
-
-setup(
- name='pytest-postgresql',
- version='2.2.0',
- description='Postgresql fixtures and fixture factories for Pytest.',
- long_description=(
- read('README.rst') + '\n\n' + read('CHANGES.rst')
- ),
- keywords='tests py.test pytest fixture postgresql',
- author='Clearcode - The A Room',
- author_email='thearoom@clearcode.cc',
- url='https://github.com/ClearcodeHQ/pytest-postgresql',
- license='LGPLv3+',
- python_requires='>=3.5',
- classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Web Environment',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: '
- 'GNU Lesser General Public License v3 or later (LGPLv3+)',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3 :: Only',
- 'Topic :: Software Development :: Libraries :: Python Modules',
- ],
- package_dir={'': 'src'},
- packages=find_packages('src'),
- install_requires=requirements,
- tests_require=test_requires,
- setup_requires=setup_requires,
- test_suite='tests',
- entry_points={
- 'pytest11': [
- 'pytest_postgresql = pytest_postgresql.plugin'
- ]},
- include_package_data=True,
- zip_safe=False,
- extras_require=extras_require,
-)
+setup()
diff --git a/src/pytest_postgresql.egg-info/PKG-INFO b/src/pytest_postgresql.egg-info/PKG-INFO
new file mode 100644
index 0000000..7ece1fe
--- /dev/null
+++ b/src/pytest_postgresql.egg-info/PKG-INFO
@@ -0,0 +1,787 @@
+Metadata-Version: 2.1
+Name: pytest-postgresql
+Version: 3.1.3
+Summary: Postgresql fixtures and fixture factories for Pytest.
+Home-page: https://github.com/ClearcodeHQ/pytest-postgresql
+Maintainer: Grzegorz Śliwiński
+Maintainer-email: fizyk+pypi@fizyk.net.pl
+License: LGPLv3+
+Keywords: tests,py.test,pytest,fixture,postgresql
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Software Development :: Testing
+Classifier: Framework :: Pytest
+Requires-Python: >=3.7
+Description-Content-Type: text/x-rst
+Provides-Extra: tests
+License-File: COPYING
+License-File: COPYING.lesser
+License-File: AUTHORS.rst
+
+.. image:: https://raw.githubusercontent.com/ClearcodeHQ/pytest-postgresql/master/logo.png
+ :width: 100px
+ :height: 100px
+
+pytest-postgresql
+=================
+
+.. image:: https://img.shields.io/pypi/v/pytest-postgresql.svg
+ :target: https://pypi.python.org/pypi/pytest-postgresql/
+ :alt: Latest PyPI version
+
+.. image:: https://img.shields.io/pypi/wheel/pytest-postgresql.svg
+ :target: https://pypi.python.org/pypi/pytest-postgresql/
+ :alt: Wheel Status
+
+.. image:: https://img.shields.io/pypi/pyversions/pytest-postgresql.svg
+ :target: https://pypi.python.org/pypi/pytest-postgresql/
+ :alt: Supported Python Versions
+
+.. image:: https://img.shields.io/pypi/l/pytest-postgresql.svg
+ :target: https://pypi.python.org/pypi/pytest-postgresql/
+ :alt: License
+
+What is this?
+=============
+
+This is a pytest plugin, that enables you to test your code that relies on a running PostgreSQL Database.
+It allows you to specify fixtures for PostgreSQL process and client.
+
+How to use
+==========
+
+.. warning::
+
+ Tested on PostgreSQL versions >= 9.6. See tests for more details.
+
+Install with:
+
+.. code-block:: sh
+
+ pip install pytest-postgresql
+
+You will also need to install ``psycopg2`` (2.9 or newer), or one of its alternative packagings such as ``psycopg2-binary``
+(pre-compiled wheels) or ``psycopg2cffi`` (CFFI based, useful on PyPy).
+
+Plugin contains three fixtures:
+
+* **postgresql** - it's a client fixture that has functional scope.
+ After each test it ends all leftover connections, and drops test database
+ from PostgreSQL ensuring repeatability.
+ This fixture returns already connected psycopg2 connection.
+
+* **postgresql_proc** - session scoped fixture, that starts PostgreSQL instance
+ at it's first use and stops at the end of the tests.
+* **postgresql_noproc** - a noprocess fixture, that's connecting to already
+ running postgresql instance.
+ For example on dockerized test environments, or CI providing postgresql services
+
+Simply include one of these fixtures into your tests fixture list.
+
+You can also create additional postgresql client and process fixtures if you'd need to:
+
+
+.. code-block:: python
+
+ from pytest_postgresql import factories
+
+ postgresql_my_proc = factories.postgresql_proc(
+ port=None, unixsocketdir='/var/run')
+ postgresql_my = factories.postgresql('postgresql_my_proc')
+
+.. note::
+
+ Each PostgreSQL process fixture can be configured in a different way than the others through the fixture factory arguments.
+
+Sample test
+
+.. code-block:: python
+
+ def test_example_postgres(postgresql):
+ """Check main postgresql fixture."""
+ cur = postgresql.cursor()
+ cur.execute("CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);")
+ postgresql.commit()
+ cur.close()
+
+If you want the database fixture to be automatically populated with your schema there are two ways:
+
+#. client fixture specific
+#. process fixture specific
+
+Both are accepting same set of possible loaders:
+
+* sql file path
+* loading function import path (string)
+* actual loading function
+
+That function will receive **host**, **port**, **user**, **dbname** and **password** kwargs and will have to perform
+connection to the database inside. However, you'll be able to run SQL files or even trigger programmatically database
+migrations you have.
+
+Client specific loads the database each test
+
+.. code-block:: python
+
+ postgresql_my_with_schema = factories.postgresql(
+ 'postgresql_my_proc',
+ load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
+ )
+
+.. warning::
+
+ This way, the database will still be dropped each time.
+
+
+The process fixture performs the load once per test session, and loads the data into the template database.
+Client fixture then creates test database out of the template database each test, which significantly speeds up the tests.
+
+.. code-block:: python
+
+ postgresql_my_proc = factories.postgresql_proc(
+ load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
+ )
+
+
+.. code-block:: bash
+
+ pytest --postgresql-populate-template=path.to.loading_function --postgresql-populate-template=path.to.other:loading_function --postgresql-populate-template=path/to/file.sql
+
+
+The loading_function from example will receive , and have to commit that.
+Connecting to already existing postgresql database
+--------------------------------------------------
+
+Some projects are using already running postgresql servers (ie on docker instances).
+In order to connect to them, one would be using the ``postgresql_noproc`` fixture.
+
+.. code-block:: python
+
+ postgresql_external = factories.postgresql('postgresql_noproc')
+
+By default the ``postgresql_noproc`` fixture would connect to postgresql instance using **5432** port. Standard configuration options apply to it.
+
+These are the configuration options that are working on all levels with the ``postgresql_noproc`` fixture:
+
+Configuration
+=============
+
+You can define your settings in three ways, it's fixture factory argument, command line option and pytest.ini configuration option.
+You can pick which you prefer, but remember that these settings are handled in the following order:
+
+ * ``Fixture factory argument``
+ * ``Command line option``
+ * ``Configuration option in your pytest.ini file``
+
+
+.. list-table:: Configuration options
+ :header-rows: 1
+
+ * - PostgreSQL option
+ - Fixture factory argument
+ - Command line option
+ - pytest.ini option
+ - Noop process fixture
+ - Default
+ * - Path to executable
+ - executable
+ - --postgresql-exec
+ - postgresql_exec
+ - -
+ - /usr/lib/postgresql/9.6/bin/pg_ctl
+ * - host
+ - host
+ - --postgresql-host
+ - postgresql_host
+ - yes
+ - 127.0.0.1
+ * - port
+ - port
+ - --postgresql-port
+ - postgresql_port
+ - yes (5432)
+ - random
+ * - postgresql user
+ - user
+ - --postgresql-user
+ - postgresql_user
+ - yes
+ - postgres
+ * - password
+ - password
+ - --postgresql-password
+ - postgresql_password
+ - yes
+ -
+ * - Starting parameters (extra pg_ctl arguments)
+ - startparams
+ - --postgresql-startparams
+ - postgresql_startparams
+ - -
+ - -w
+ * - Postgres exe extra arguments (passed via pg_ctl's -o argument)
+ - postgres_options
+ - --postgresql-postgres-options
+ - postgresql_postgres_options
+ - -
+ -
+ * - Log filename's prefix
+ - logsprefix
+ - --postgresql-logsprefix
+ - postgresql_logsprefix
+ - -
+ -
+ * - Location for unixsockets
+ - unixsocket
+ - --postgresql-unixsocketdir
+ - postgresql_unixsocketdir
+ - -
+ - $TMPDIR
+ * - Database name
+ - dbname
+ - --postgresql-dbname
+ - postgresql_dbname
+ - -
+ - test
+ * - Default Schema either in sql files or import path to function that will load it (list of values for each)
+ - load
+ - --postgresql-load
+ - postgresql_load
+ - yes
+ -
+ * - PostgreSQL connection options
+ - options
+ - --postgresql-options
+ - postgresql_options
+ - yes
+ -
+
+
+Example usage:
+
+* pass it as an argument in your own fixture
+
+ .. code-block:: python
+
+ postgresql_proc = factories.postgresql_proc(
+ port=8888)
+
+* use ``--postgresql-port`` command line option when you run your tests
+
+ .. code-block::
+
+ py.test tests --postgresql-port=8888
+
+
+* specify your port as ``postgresql_port`` in your ``pytest.ini`` file.
+
+ To do so, put a line like the following under the ``[pytest]`` section of your ``pytest.ini``:
+
+ .. code-block:: ini
+
+ [pytest]
+ postgresql_port = 8888
+
+Examples
+========
+
+Populating database for tests
+-----------------------------
+
+With SQLAlchemy
++++++++++++++++
+
+This example shows how to populate database and create an SQLAlchemy's ORM connection:
+
+Sample below is simplified session fixture from
+`pyramid_fullauth `_ tests:
+
+.. code-block:: python
+
+ from sqlalchemy import create_engine
+ from sqlalchemy.orm import scoped_session, sessionmaker
+ from sqlalchemy.pool import NullPool
+ from zope.sqlalchemy import register
+
+
+ @pytest.fixture
+ def db_session(postgresql):
+ """Session for SQLAlchemy."""
+ from pyramid_fullauth.models import Base
+
+ connection = f'postgresql+psycopg2://{postgresql.info.user}:@{postgresql.info.host}:{postgresql.info.port}/{postgresql.info.dbname}'
+
+ engine = create_engine(connection, echo=False, poolclass=NullPool)
+ pyramid_basemodel.Session = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
+ pyramid_basemodel.bind_engine(
+ engine, pyramid_basemodel.Session, should_create=True, should_drop=True)
+
+ yield pyramid_basemodel.Session
+
+ transaction.commit()
+ Base.metadata.drop_all(engine)
+
+
+ @pytest.fixture
+ def user(db_session):
+ """Test user fixture."""
+ from pyramid_fullauth.models import User
+ from tests.tools import DEFAULT_USER
+
+ new_user = User(**DEFAULT_USER)
+ db_session.add(new_user)
+ transaction.commit()
+ return new_user
+
+
+ def test_remove_last_admin(db_session, user):
+ """
+ Sample test checks internal login, but shows usage in tests with SQLAlchemy
+ """
+ user = db_session.merge(user)
+ user.is_admin = True
+ transaction.commit()
+ user = db_session.merge(user)
+
+ with pytest.raises(AttributeError):
+ user.is_admin = False
+.. note::
+
+ See the original code at `pyramid_fullauth's conftest file `_.
+ Depending on your needs, that in between code can fire alembic migrations in case of sqlalchemy stack or any other code
+
+Maintaining database state outside of the fixtures
+--------------------------------------------------
+
+It is possible and appears it's used in other libraries for tests,
+to maintain database state with the use of the ``pytest-postgresql`` database
+managing functionality:
+
+For this import DatabaseJanitor and use its init and drop methods:
+
+
+.. code-block:: python
+
+ import pytest
+ from pytest_postgresql.janitor import DatabaseJanitor
+
+ @pytest.fixture
+ def database(postgresql_proc):
+ # variable definition
+
+ janitor = DatabaseJanitor(
+ postgresql_proc.user,
+ postgresql_proc.host,
+ postgresql_proc.port,
+ "my_test_database",
+ postgresql_proc.version,
+ password="secret_password,
+ ):
+ janitor.init()
+ yield psycopg2.connect(
+ dbname="my_test_database",
+ user=postgresql_proc.user,
+ password="secret_password",
+ host=postgresql_proc.host,
+ port=postgresql_proc.port,
+ )
+ janitor.drop()
+
+or use it as a context manager:
+
+.. code-block:: python
+
+ import pytest
+ from pytest_postgresql.janitor import DatabaseJanitor
+
+ @pytest.fixture
+ def database(postgresql_proc):
+ # variable definition
+
+ with DatabaseJanitor(
+ postgresql_proc.user,
+ postgresql_proc.host,
+ postgresql_proc.port,
+ "my_test_database",
+ postgresql_proc.version,
+ password="secret_password,
+ ):
+ yield psycopg2.connect(
+ dbname="my_test_database",
+ user=postgresql_proc.user,
+ password="secret_password",
+ host=postgresql_proc.host,
+ port=postgresql_proc.port,
+ )
+
+.. note::
+
+ DatabaseJanitor manages the state of the database, but you'll have to create
+ connection to use in test code yourself.
+
+ You can optionally pass in a recognized postgresql ISOLATION_LEVEL for
+ additional control.
+
+.. note::
+
+ See DatabaseJanitor usage in python's warehouse test code https://github.com/pypa/warehouse/blob/5d15bfe/tests/conftest.py#L127
+
+Connecting to Postgresql (in a docker)
+--------------------------------------
+
+To connect to a docker run postgresql and run test on it, use noproc fixtures.
+
+.. code-block:: sh
+
+ docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres
+
+This will start postgresql in a docker container, however using a postgresql installed locally is not much different.
+
+In tests, make sure that all your tests are using **postgresql_noproc** fixture like that:
+
+.. code-block:: python
+
+ postgresql_in_docker = factories.postgresql_noproc()
+ postresql = factories.postgresql("postgresql_in_docker", db_name="test")
+
+
+ def test_postgres_docker(postresql):
+ """Run test."""
+ cur = postgresql.cursor()
+ cur.execute("CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);")
+ postgresql.commit()
+ cur.close()
+
+And run tests:
+
+.. code-block:: sh
+
+ pytest --postgresql-host=172.17.0.2 --postgresql-password=mysecretpassword
+
+Using a common database initialisation between tests
+----------------------------------------------------
+
+If you've got several tests that require common initialisation, you need to define a `load` and pass it to
+your custom postgresql process fixture:
+
+.. code-block:: python
+
+ import pytest_postgresql.factories
+ def load_database(**kwargs):
+ db_connection: connection = psycopg2.connect(**kwargs)
+ with db_connection.cursor() as cur:
+ cur.execute("CREATE TABLE stories (id serial PRIMARY KEY, name varchar);")
+ cur.execute(
+ "INSERT INTO stories (name) VALUES"
+ "('Silmarillion'), ('Star Wars'), ('The Expanse'), ('Battlestar Galactica')"
+ )
+ db_connection.commit()
+
+ postgresql_proc = factories.postgresql_proc(
+ load=[load_database],
+ )
+
+ postgresql = factories.postgresql(
+ "postgresql_proc",
+ )
+
+You can also define your own database name by passing same dbname value
+to **both** factories.
+
+The way this will work is that the process fixture will populate template database,
+which in turn will be used automatically by client fixture to create a test database from scratch.
+Fast, clean and no dangling transactions, that could be accidentally rolled back.
+
+Same approach will work with noproces fixture, while connecting to already running postgresql instance whether
+it'll be on a docker machine or running remotely or locally.
+
+CHANGELOG
+=========
+
+3.1.3
+----------
+
+Cherry picked from v4.x
+
+Misc
+++++
+
+- Import FixtureRequest from pytest, not private _pytest.
+ Require at least pytest 6.2
+- Replace tmpdir_factory with tmp_path_factory
+- Add Postgresql 14 to the CI
+
+3.1.2
+----------
+
+Bugfix
+++++++
+
+- Database can be created by DatabaseJanitor or the client fixture when an isolation
+ level is specified.
+
+3.1.1
+----------
+
+Misc
+++++
+
+- rely on `get_port` functionality delivered by `port_for`
+
+3.1.0
+----------
+
+Features
+++++++++
+
+- Added type annotations and compatibitlity with PEP 561
+
+Misc
+++++
+
+- pre-commit configuration
+
+3.0.2
+----------
+
+Bugfix
+++++++
+
+- Changed `UPDATE pg_database SET` to `ALTER`. System tables should not be updated.
+
+3.0.1
+----------
+
+Bugfix
+++++++
+
+- Fixed DatabaseJanitor port type hint to int from str
+- Changed retry definition to not fail if psycopg2 is not installed.
+ Now the default is Exception.
+
+Misc
+++++
+
+- Support python 3.7 and up
+
+3.0.0
+----------
+
+Features
+++++++++
+
+- Ability to create template database once for the process fixture and
+ re-recreate a clean database out of it every test. Not only it does provide some
+ common db initialisation between tests but also can speed up tests significantly,
+ especially if the initialisation has lots of operations to perform.
+- DatabaseJanitor can now define a `connection_timeout` parameter.
+ How long will it try to connect to database before raising a TimeoutError
+- Updated supported python versions
+- Unified temporary directory handling in fixture. Settled on tmpdir_factory.
+- Fully moved to the Github Actions as CI/CD pipeline
+
+Deprecations
+++++++++++++
+
+- Deprecated support for `logs_prefix` process fixture factory argument,
+ `--postgresql-logsprefix` pytest command line option and `postgresql_logsprefix`
+ ini configuration option. tmpdir_factory now builds pretty unique temporary directory structure.
+
+Backward Incompatibilities
+++++++++++++++++++++++++++
+
+- Dropped support for postgresql 9.5 and down
+- Removed init_postgresql_database and drop_postgresql_database functions.
+ They were long deprecated and their role perfectly covered by DatabaseJanitor class.
+- `pytest_postgresql.factories.get_config` was moved to `pytest_postgresql.config.get_config`
+- all `db_name` keywords and attributes were renamed to `dbname`
+- postgresql_nooproc fixture was renamed to postgresql_noproc
+
+Bugfix
+++++++
+
+- Use `postgresql_logsprefix` and `--postgresql-logsprefix` again.
+ They were stopped being used somewhere along the way.
+- Sometimes pytest-postrgesql would fail to start postgresql with
+ "FATAL: the database system is starting up" message. It's not really a fatal error,
+ but a message indicating that the process still starts. Now pytest-postgresql will wait properly in this cases.
+
+2.6.1
+----------
+
+- [bugfix] To not fail loading code if no postgresql version is installed.
+ Fallback for janitor and process fixture only, if called upon.
+
+2.6.0
+----------
+
+- [enhancement] add ability to pass options to pg_ctl's -o flag to send arguments to the underlying postgres executable
+ Use `postgres_options` as fixture argument, `--postgresql-postgres-options` as pytest starting option or
+ `postgresql_postgres_options` as pytest.ini configuration option
+
+2.5.3
+----------
+
+- [enhancement] Add ability to set up isolation level for fixture and janitor
+
+2.5.2
+----------
+
+- [fix] Status checks for running postgres depend on pg_ctl status code,
+ not on pg_ctl log language. Fixes starting on systems without C locale.
+ Thanks @Martin Meyries.
+
+
+2.5.1
+----------
+
+- [fix] Added LC_* env vars to running initdb and other utilities.
+ Now all tools and server are using same, C locale
+
+
+2.5.0
+----------
+
+- [feature] Ability to define default schema to initialize database with
+- [docs] Added more examples to readme on how to use the plugin
+
+
+2.4.1
+----------
+
+- [enhancement] extract NoopExecutor into it's own submodule
+- [bugfix] Ignore occasional `ProcessFinishedWithError` error on executor exit.
+- [bugfix] Fixed setting custom password for process fixture
+- [bugfix] Fix version detection, to allow for two-digit minor version part
+
+2.4.0
+----------
+
+- [feature] Drop support for pyhon 3.5
+- [enhancement] require at least mirakuru 2.3.0 (executor's stop method parameter's change)
+- [bug] pass password to DatabaseJanitor in client's factory
+
+2.3.0
+----------
+
+- [feature] Allow to set password for postgresql. Use it throughout the flow.
+- [bugfix] Default Janitor's connections to postgres database. When using custom users,
+ postgres attempts to use user's database and it might not exist.
+- [bugfix] NoopExecutor connects to read version by context manager to properly handle cases
+ where it can't connect to the server.
+
+2.2.1
+----------
+
+- [bugfix] Fix drop_postgresql_database to actually use DatabaseJanitor.drop instead of an init
+
+2.2.0
+----------
+
+- [feature] ability to properly connect to already existing postgresql server using ``postgresql_nooproc`` fixture.
+
+2.1.0
+----------
+
+- [enhancement] Gather helper functions maintaining postgresql database in DatabaseJanitor class.
+- [deprecate] Deprecate ``init_postgresql_database`` in favour of ``DatabaseJanitor.init``
+- [deprecate] Deprecate ``drop_postgresql_database`` in favour of ``DatabaseJanitor.drop``
+
+2.0.0
+----------
+
+- [feature] Drop support for python 2.7. From now on, only support python 3.5 and up
+- [feature] Ability to configure database name through plugin options
+- [enhancement] Use tmpdir_factory. Drop ``logsdir`` parameter
+- [ehnancement] Support only Postgresql 9.0 and up
+- [bugfix] Always start postgresql with LC_ALL, LC_TYPE and LANG set to C.UTF-8.
+ It makes postgresql start in english.
+
+1.4.1
+----------
+
+- [bugfix] Allow creating test databse with hyphens
+
+1.4.0
+----------
+
+- [enhancements] Ability to configure additional options for postgresql process and connection
+- [bugfix] - removed hard dependency on ``psycopg2``, allowing any of its alternative packages, like
+ ``psycopg2-binary``, to be used.
+- [maintenance] Drop support for python 3.4 and use 3.7 instead
+
+1.3.4
+----------
+
+- [bugfix] properly detect if executor running and clean after executor is being stopped
+
+ .. note::
+
+ Previously if a test failed, there was a possibility of the executor being removed when python was closing,
+ causing it to print ignored errors on already unloaded modules.
+
+1.3.3
+----------
+
+- [enhancement] use executor's context manager to start/stop postrgesql server in a fixture
+
+1.3.2
+----------
+
+- [bugfix] version regexp to correctly catch postgresql 10
+
+1.3.1
+----------
+
+- [enhancement] explicitly turn off logging_collector
+
+1.3.0
+----------
+
+- [feature] pypy compatibility
+
+1.2.0
+----------
+
+- [bugfix] - disallow connection to database before it gets dropped.
+
+ .. note::
+
+ Otherwise it caused random test subprocess to connect again and this the drop was unsucessfull which resulted in many more test failes on setup.
+
+- [cleanup] - removed path.py dependency
+
+1.1.1
+----------
+
+- [bugfix] - Fixing the default pg_ctl path creation
+
+1.1.0
+----------
+
+- [feature] - migrate usage of getfuncargvalue to getfixturevalue. require at least pytest 3.0.0
+
+1.0.0
+----------
+
+- create command line and pytest.ini configuration options for postgresql starting parameters
+- create command line and pytest.ini configuration options for postgresql username
+- make the port random by default
+- create command line and pytest.ini configuration options for executable
+- create command line and pytest.ini configuration options for host
+- create command line and pytest.ini configuration options for port
+- Extracted code from pytest-dbfixtures
+
+
diff --git a/src/pytest_postgresql.egg-info/SOURCES.txt b/src/pytest_postgresql.egg-info/SOURCES.txt
new file mode 100644
index 0000000..0edc2c7
--- /dev/null
+++ b/src/pytest_postgresql.egg-info/SOURCES.txt
@@ -0,0 +1,31 @@
+AUTHORS.rst
+CHANGES.rst
+CONTRIBUTING.rst
+COPYING
+COPYING.lesser
+MANIFEST.in
+README.rst
+pyproject.toml
+setup.cfg
+setup.py
+src/pytest_postgresql/__init__.py
+src/pytest_postgresql/compat.py
+src/pytest_postgresql/config.py
+src/pytest_postgresql/executor.py
+src/pytest_postgresql/executor_noop.py
+src/pytest_postgresql/janitor.py
+src/pytest_postgresql/plugin.py
+src/pytest_postgresql/py.typed
+src/pytest_postgresql/retry.py
+src/pytest_postgresql/sql.py
+src/pytest_postgresql.egg-info/PKG-INFO
+src/pytest_postgresql.egg-info/SOURCES.txt
+src/pytest_postgresql.egg-info/dependency_links.txt
+src/pytest_postgresql.egg-info/entry_points.txt
+src/pytest_postgresql.egg-info/not-zip-safe
+src/pytest_postgresql.egg-info/requires.txt
+src/pytest_postgresql.egg-info/top_level.txt
+src/pytest_postgresql/factories/__init__.py
+src/pytest_postgresql/factories/client.py
+src/pytest_postgresql/factories/noprocess.py
+src/pytest_postgresql/factories/process.py
\ No newline at end of file
diff --git a/src/pytest_postgresql.egg-info/dependency_links.txt b/src/pytest_postgresql.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/pytest_postgresql.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/src/pytest_postgresql.egg-info/entry_points.txt b/src/pytest_postgresql.egg-info/entry_points.txt
new file mode 100644
index 0000000..942a6b9
--- /dev/null
+++ b/src/pytest_postgresql.egg-info/entry_points.txt
@@ -0,0 +1,2 @@
+[pytest11]
+pytest_postgresql = pytest_postgresql.plugin
diff --git a/src/pytest_postgresql.egg-info/not-zip-safe b/src/pytest_postgresql.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/pytest_postgresql.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/src/pytest_postgresql.egg-info/requires.txt b/src/pytest_postgresql.egg-info/requires.txt
new file mode 100644
index 0000000..35fbf3f
--- /dev/null
+++ b/src/pytest_postgresql.egg-info/requires.txt
@@ -0,0 +1,7 @@
+pytest>=6.2.0
+port-for
+mirakuru>=2.3.0
+
+[tests]
+pytest-cov
+pytest-xdist
diff --git a/src/pytest_postgresql.egg-info/top_level.txt b/src/pytest_postgresql.egg-info/top_level.txt
new file mode 100644
index 0000000..906e435
--- /dev/null
+++ b/src/pytest_postgresql.egg-info/top_level.txt
@@ -0,0 +1 @@
+pytest_postgresql
diff --git a/src/pytest_postgresql/__init__.py b/src/pytest_postgresql/__init__.py
index 3123a60..4907289 100644
--- a/src/pytest_postgresql/__init__.py
+++ b/src/pytest_postgresql/__init__.py
@@ -1,27 +1,27 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016 by Clearcode
# and associates (see AUTHORS).
# This file is part of pytest-postgresql.
# pytest-postgresql is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# pytest-postgresql is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with pytest-postgresql. If not, see .
"""Main module for pytest-postgresql."""
try:
- import psycopg2cffi.compat # pylint:disable=import-error
+ import psycopg2cffi.compat
except ImportError:
pass
else:
psycopg2cffi.compat.register()
-__version__ = '2.2.0'
+__version__ = "3.1.3"
diff --git a/src/pytest_postgresql/compat.py b/src/pytest_postgresql/compat.py
new file mode 100644
index 0000000..f84875b
--- /dev/null
+++ b/src/pytest_postgresql/compat.py
@@ -0,0 +1,37 @@
+"""pscypog2 Compatibility module."""
+from typing import Any, TYPE_CHECKING
+from platform import python_implementation
+
+
+__all__ = ("psycopg2", "cursor", "connection", "check_for_psycopg2")
+
+
+try:
+ import psycopg2
+except ImportError:
+ psycopg2 = False
+
+if not psycopg2:
+ if not TYPE_CHECKING:
+ # if there's no postgres, just go with the flow.
+ cursor = Any
+ connection = Any
+elif python_implementation() == "PyPy":
+ from psycopg2cffi._impl.cursor import Cursor as cursor
+ from psycopg2cffi._impl.connection import Connection as connection
+else:
+ from psycopg2._psycopg import cursor, connection
+
+
+def check_for_psycopg2() -> None:
+ """
+ Function checks whether psycopg2 was imported.
+
+ Raises ImportError if not.
+ """
+ if not psycopg2:
+ raise ImportError(
+ "No module named psycopg2. Please install either "
+ "psycopg2 or psycopg2-binary package for CPython "
+ "or psycopg2cffi for Pypy."
+ )
diff --git a/src/pytest_postgresql/config.py b/src/pytest_postgresql/config.py
new file mode 100644
index 0000000..926aaa2
--- /dev/null
+++ b/src/pytest_postgresql/config.py
@@ -0,0 +1,25 @@
+from pytest import FixtureRequest
+
+
+def get_config(request: FixtureRequest) -> dict:
+ """Return a dictionary with config options."""
+ config = {}
+ options = [
+ "exec",
+ "host",
+ "port",
+ "user",
+ "password",
+ "options",
+ "startparams",
+ "logsprefix",
+ "unixsocketdir",
+ "dbname",
+ "load",
+ "postgres_options",
+ ]
+ for option in options:
+ option_name = "postgresql_" + option
+ conf = request.config.getoption(option_name) or request.config.getini(option_name)
+ config[option] = conf
+ return config
diff --git a/src/pytest_postgresql/executor.py b/src/pytest_postgresql/executor.py
index ce962b9..079db44 100644
--- a/src/pytest_postgresql/executor.py
+++ b/src/pytest_postgresql/executor.py
@@ -1,214 +1,231 @@
-
-# Copyright (C) 2013 by Clearcode
+# Copyright (C) 2016-2020 by Clearcode
# and associates (see AUTHORS).
-# This file is part of pytest-dbfixtures.
+# This file is part of pytest-postgresql.
# pytest-dbfixtures is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# pytest-dbfixtures is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with pytest-dbfixtures. If not, see .
"""PostgreSQL executor crafter around pg_ctl."""
import os.path
+import platform
import re
import shutil
import subprocess
+import tempfile
import time
+from typing import TypeVar, Optional, Any
from pkg_resources import parse_version
from mirakuru import TCPExecutor
-from mirakuru.base import ExecutorType
+from mirakuru.exceptions import ProcessFinishedWithError
+
+_LOCALE = "C.UTF-8"
+
+if platform.system() == "Darwin":
+ _LOCALE = "en_US.UTF-8"
+
+
+T = TypeVar("T", bound="PostgreSQLExecutor")
class PostgreSQLUnsupported(Exception):
- """Exception raised when postgresql<9.0 would be detected."""
+ """Exception raised when unsupported postgresql would be detected."""
-# pylint:disable=too-many-instance-attributes
class PostgreSQLExecutor(TCPExecutor):
"""
PostgreSQL executor running on pg_ctl.
Based over an `pg_ctl program
- `_
+ `_
"""
- BASE_PROC_START_COMMAND = ' '.join((
- "{executable} start -D {datadir}",
- "-o \"-F -p {port} -c log_destination='stderr'",
- "-c logging_collector=off -c %s='{unixsocketdir}'\"",
+ BASE_PROC_START_COMMAND = (
+ "{executable} start -D {datadir} "
+ "-o \"-F -p {port} -c log_destination='stderr' "
+ "-c logging_collector=off "
+ "-c unix_socket_directories='{unixsocketdir}' {postgres_options}\" "
"-l {logfile} {startparams}"
- ))
-
- VERSION_RE = re.compile(r'.* (?P\d+\.\d)')
- MIN_SUPPORTED_VERSION = parse_version('9.0')
-
- def __init__(self, executable, host, port,
- datadir, unixsocketdir, logfile, startparams,
- shell=False, timeout=60, sleep=0.1, user='postgres',
- options=''):
+ )
+
+ VERSION_RE = re.compile(r".* (?P\d+\.\d+)")
+ MIN_SUPPORTED_VERSION = parse_version("9.6")
+
+ def __init__(
+ self,
+ executable: str,
+ host: str,
+ port: int,
+ datadir: str,
+ unixsocketdir: str,
+ logfile: str,
+ startparams: str,
+ shell: bool = False,
+ timeout: Optional[int] = 60,
+ sleep: float = 0.1,
+ user: str = "postgres",
+ password: str = "",
+ dbname: Optional[str] = None,
+ options: str = "",
+ postgres_options: str = "",
+ ):
"""
Initialize PostgreSQLExecutor executor.
- :param str executable: pg_ctl location
- :param str host: host under which process is accessible
- :param int port: port under which process is accessible
- :param str datadir: path to postgresql datadir
- :param str unixsocketdir: path to socket directory
- :param pathlib.Path logfile: path to logfile for postgresql
- :param str startparams: additional start parameters
- :param bool shell: see `subprocess.Popen`
- :param int timeout: time to wait for process to start or stop.
+ :param executable: pg_ctl location
+ :param host: host under which process is accessible
+ :param port: port under which process is accessible
+ :param datadir: path to postgresql datadir
+ :param unixsocketdir: path to socket directory
+ :param logfile: path to logfile for postgresql
+ :param startparams: additional start parameters
+ :param shell: see `subprocess.Popen`
+ :param timeout: time to wait for process to start or stop.
if None, wait indefinitely.
- :param float sleep: how often to check for start/stop condition
- :param str user: [default] postgresql's username used to manage
+ :param sleep: how often to check for start/stop condition
+ :param user: postgresql's username used to manage
and access PostgreSQL
+ :param password: optional password for the user
+ :param dbname: database name (might not yet exist)
+ :param options:
+ :param postgres_options: extra arguments to `postgres start`
"""
self._directory_initialised = False
self.executable = executable
self.user = user
+ self.password = password
+ self.dbname = dbname
self.options = options
self.datadir = datadir
self.unixsocketdir = unixsocketdir
self.logfile = logfile
self.startparams = startparams
- command = self.proc_start_command().format(
+ self.postgres_options = postgres_options
+ command = self.BASE_PROC_START_COMMAND.format(
executable=self.executable,
datadir=self.datadir,
port=port,
unixsocketdir=self.unixsocketdir,
logfile=self.logfile,
startparams=self.startparams,
+ postgres_options=self.postgres_options,
)
super().__init__(
command,
host,
port,
shell=shell,
timeout=timeout,
sleep=sleep,
envvars={
- 'LC_ALL': 'C.UTF-8',
- 'LC_CTYPE': 'C.UTF-8',
- 'LANG': 'C.UTF-8',
- }
+ "LC_ALL": _LOCALE,
+ "LC_CTYPE": _LOCALE,
+ "LANG": _LOCALE,
+ },
)
- def start(self: ExecutorType) -> ExecutorType:
+ def start(self: T) -> T:
"""Add check for postgresql version before starting process."""
if self.version < self.MIN_SUPPORTED_VERSION:
raise PostgreSQLUnsupported(
- 'Your version of PostgreSQL is not supported. '
- 'Consider updating to PostgreSQL {0} at least. '
- 'The currently installed version of PostgreSQL: {1}.'
- .format(self.MIN_SUPPORTED_VERSION, self.version))
+ f"Your version of PostgreSQL is not supported. "
+ f"Consider updating to PostgreSQL {self.MIN_SUPPORTED_VERSION} at least. "
+ f"The currently installed version of PostgreSQL: {self.version}."
+ )
self.init_directory()
return super().start()
- def clean_directory(self):
+ def clean_directory(self) -> None:
"""Remove directory created for postgresql run."""
if os.path.isdir(self.datadir):
shutil.rmtree(self.datadir)
self._directory_initialised = False
- def init_directory(self):
+ def init_directory(self) -> None:
"""
Initialize postgresql data directory.
See `Initialize postgresql data directory
`_
"""
# only make sure it's removed if it's handled by this exact process
if self._directory_initialised:
return
# remove old one if exists first.
self.clean_directory()
- init_directory = (
- self.executable, 'initdb',
- '-o "--auth=trust --username=%s"' % self.user,
- '-D %s' % self.datadir,
- )
- subprocess.check_output(' '.join(init_directory), shell=True)
+ init_directory = [self.executable, "initdb", "--pgdata", self.datadir]
+ options = ["--username=%s" % self.user]
+
+ if self.password:
+ with tempfile.NamedTemporaryFile() as password_file:
+ options += ["--auth=password", "--pwfile=%s" % password_file.name]
+ if hasattr(self.password, "encode"):
+ password = self.password.encode("utf-8")
+ else:
+ password = self.password # type: ignore[assignment]
+ password_file.write(password)
+ password_file.flush()
+ init_directory += ["-o", " ".join(options)]
+ subprocess.check_output(init_directory)
+ else:
+ options += ["--auth=trust"]
+ init_directory += ["-o", " ".join(options)]
+ subprocess.check_output(init_directory)
+
self._directory_initialised = True
- def wait_for_postgres(self):
+ def wait_for_postgres(self) -> None:
"""Wait for postgresql being started."""
- if '-w' not in self.startparams:
+ if "-w" not in self.startparams:
return
- # Cast to str since Python 3.5 however still needs string.
- # Python 3.6 it's possible to pass a A Pathlike object.
- logfile_path = str(self.logfile)
- # wait until logfile is created
- while not os.path.isfile(logfile_path):
- time.sleep(1)
-
- start_info = 'database system is ready to accept connections'
- # wait for expected message.
+ # wait until server is running
while 1:
- with open(logfile_path, 'r') as content_file:
- content = content_file.read()
- if start_info in content:
- break
+ if self.running():
+ break
time.sleep(1)
- def proc_start_command(self):
- """Based on postgres version return proper start command."""
- if self.version > parse_version('9.2'):
- unix_socket_dir_arg_name = 'unix_socket_directories'
- else:
- unix_socket_dir_arg_name = 'unix_socket_directory'
- return self.BASE_PROC_START_COMMAND % unix_socket_dir_arg_name
-
@property
- def version(self):
+ def version(self) -> Any:
"""Detect postgresql version."""
- version_string = subprocess.check_output(
- [self.executable, '--version']).decode('utf-8')
+ version_string = subprocess.check_output([self.executable, "--version"]).decode("utf-8")
matches = self.VERSION_RE.search(version_string)
- return parse_version(matches.groupdict()['version'])
+ assert matches is not None
+ return parse_version(matches.groupdict()["version"])
- def running(self):
- """Check if server is still running."""
+ def running(self) -> bool:
+ """Check if server is running."""
if not os.path.exists(self.datadir):
return False
+ status_code = subprocess.getstatusoutput(f"{self.executable} status -D {self.datadir}")[0]
+ return status_code == 0
- try:
- output = subprocess.check_output(
- '{pg_ctl} status -D {datadir}'.format(
- pg_ctl=self.executable,
- datadir=self.datadir
- ),
- shell=True
- ).decode('utf-8')
- except subprocess.CalledProcessError as ex:
- if b'pg_ctl: no server running' in ex.output:
- return False
- raise
-
- return "pg_ctl: server is running" in output
-
- def stop(self, sig=None):
+ def stop(self: T, sig: Optional[int] = None, exp_sig: Optional[int] = None) -> T:
"""Issue a stop request to executable."""
subprocess.check_output(
- '{pg_ctl} stop -D {datadir} -m f'.format(
- pg_ctl=self.executable,
- datadir=self.datadir,
- ),
- shell=True)
- super().stop(sig)
-
- def __del__(self):
+ f"{self.executable} stop -D {self.datadir} -m f",
+ shell=True,
+ )
+ try:
+ super().stop(sig, exp_sig)
+ except ProcessFinishedWithError:
+ # Finished, leftovers ought to be cleaned afterwards anyway
+ pass
+ return self
+
+ def __del__(self) -> None:
"""Make sure the directories are properly removed at the end."""
try:
super().__del__()
finally:
self.clean_directory()
diff --git a/src/pytest_postgresql/executor_noop.py b/src/pytest_postgresql/executor_noop.py
new file mode 100644
index 0000000..226c94a
--- /dev/null
+++ b/src/pytest_postgresql/executor_noop.py
@@ -0,0 +1,92 @@
+# Copyright (C) 2020 by Clearcode
+# and associates (see AUTHORS).
+
+# This file is part of pytest-postgresql.
+
+# pytest-dbfixtures is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# pytest-dbfixtures is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with pytest-dbfixtures. If not, see .
+"""PostgreSQL Noop executor providing connection details for postgres client."""
+from typing import Union, Optional, Any
+
+from pkg_resources import parse_version
+
+from pytest_postgresql.compat import check_for_psycopg2, psycopg2
+
+
+class NoopExecutor:
+ """
+ Nooperator executor.
+
+ This executor actually does nothing more than provide connection details
+ for existing PostgreSQL server. I.E. one already started either on machine
+ or with the use of containerisation like kubernetes or docker compose.
+ """
+
+ def __init__(
+ self,
+ host: str,
+ port: Union[str, int],
+ user: str,
+ options: str,
+ password: Optional[str] = None,
+ dbname: Optional[str] = None,
+ ):
+ """
+ Initialize nooperator executor mock.
+
+ :param host: Postgresql hostname
+ :param port: Postgresql port
+ :param user: Postgresql username
+ :param options: Additional connection options
+ :param password: postgresql password
+ :param dbname: postgresql database name
+ """
+ self.host = host
+ self.port = int(port)
+ self.user = user
+ self.options = options
+ self.password = password
+ self.dbname = dbname
+ self._version: Any = None
+
+ @property
+ def version(self) -> Any:
+ """Get postgresql's version."""
+ if not self._version:
+ check_for_psycopg2()
+ # could be called before self.dbname will be created.
+ # Use default postgres database
+ with psycopg2.connect(
+ dbname="postgres",
+ user=self.user,
+ host=self.host,
+ port=self.port,
+ password=self.password,
+ options=self.options,
+ ) as connection:
+ version = str(connection.server_version)
+ # Pad the version for releases before 10
+ # if not we get 90524 instead of 090524
+ if len(version) < 6:
+ version = "0" + version
+ version_parts = []
+
+ # extract version parts to construct a two-part version
+ for i in range(0, len(version), 2):
+ j = i + 2
+ part = version[i:j]
+ if not int(part):
+ continue
+ version_parts.append(part)
+ self._version = parse_version(".".join(version_parts[:2]))
+ return self._version
diff --git a/src/pytest_postgresql/factories.py b/src/pytest_postgresql/factories.py
deleted file mode 100644
index e861f2d..0000000
--- a/src/pytest_postgresql/factories.py
+++ /dev/null
@@ -1,297 +0,0 @@
-# Copyright (C) 2013-2016 by Clearcode
-# and associates (see AUTHORS).
-
-# This file is part of pytest-dbfixtures.
-
-# pytest-dbfixtures is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# pytest-dbfixtures is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public License
-# along with pytest-dbfixtures. If not, see .
-"""Fixture factories for postgresql fixtures."""
-
-import os.path
-import platform
-import subprocess
-from tempfile import gettempdir
-from warnings import warn
-
-import pytest
-from pkg_resources import parse_version
-
-from pytest_postgresql.janitor import DatabaseJanitor, psycopg2
-from pytest_postgresql.executor import PostgreSQLExecutor
-from pytest_postgresql.port import get_port
-
-
-class NoopExecutor: # pylint: disable=too-few-public-methods
- """Nooperator executor."""
-
- def __init__(self, host, port, user, options):
- """
- Initialize nooperator executor mock.
-
- :param str host: Postgresql hostname
- :param str|int port: Postrgesql port
- :param str user: Postgresql username
- :param str options: Additional connection options
- """
- self.host = host
- self.port = int(port)
- self.user = user
- self.options = options
- self._version = None
-
- @property
- def version(self):
- """Get postgresql's version."""
- if self._version:
- return self._version
- try:
- connection = psycopg2.connect(
- dbname='postgres',
- user=self.user,
- host=self.host,
- port=self.port,
- options=self.options
- )
- version = str(connection.server_version)
- self._version = parse_version(
- '.'.join([
- version[i: i+2] for i in range(0, len(version), 2)
- if int(version[i: i+2])
- ])
- )
- return self._version
- finally:
- connection.close()
-
-
-def get_config(request):
- """Return a dictionary with config options."""
- config = {}
- options = [
- 'exec', 'host', 'port', 'user', 'options', 'startparams',
- 'logsprefix', 'unixsocketdir', 'dbname'
- ]
- for option in options:
- option_name = 'postgresql_' + option
- conf = request.config.getoption(option_name) or \
- request.config.getini(option_name)
- config[option] = conf
- return config
-
-
-def init_postgresql_database(user, host, port, db_name):
- """
- Create database in postgresql.
-
- :param str user: postgresql username
- :param str host: postgresql host
- :param str port: postgresql port
- :param str db_name: database name
- """
- warn(
- 'init_postgresql_database is deprecated, '
- 'use DatabaseJanitor.init istead.',
- DeprecationWarning
- )
- DatabaseJanitor(user, host, port, db_name, 0.0).init()
-
-
-def drop_postgresql_database(user, host, port, db_name, version):
- """
- Drop databse in postgresql.
-
- :param str user: postgresql username
- :param str host: postgresql host
- :param str port: postgresql port
- :param str db_name: database name
- :param packaging.version.Version version: postgresql version number
- """
- warn(
- 'drop_postgresql_database is deprecated, '
- 'use DatabaseJanitor.drop istead.',
- DeprecationWarning
- )
- DatabaseJanitor(user, host, port, db_name, version).init()
-
-
-def postgresql_proc(
- executable=None, host=None, port=-1, user=None, options='',
- startparams=None, unixsocketdir=None, logs_prefix='',
-):
- """
- Postgresql process factory.
-
- :param str executable: path to postgresql_ctl
- :param str host: hostname
- :param str|int|tuple|set|list port:
- exact port (e.g. '8000', 8000)
- randomly selected port (None) - any random available port
- -1 - command line or pytest.ini configured port
- [(2000,3000)] or (2000,3000) - random available port from a given range
- [{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
- [(2000,3000), {4002,4003}] - random of given range and set
- :param str user: postgresql username
- :param str options: Postgresql connection options
- :param str startparams: postgresql starting parameters
- :param str unixsocketdir: directory to create postgresql's unixsockets
- :param str logs_prefix: prefix for log filename
- :rtype: func
- :returns: function which makes a postgresql process
- """
- @pytest.fixture(scope='session')
- def postgresql_proc_fixture(request, tmpdir_factory):
- """
- Process fixture for PostgreSQL.
-
- :param FixtureRequest request: fixture request object
- :rtype: pytest_dbfixtures.executors.TCPExecutor
- :returns: tcp executor
- """
- config = get_config(request)
- postgresql_ctl = executable or config['exec']
- # check if that executable exists, as it's no on system PATH
- # only replace if executable isn't passed manually
- if not os.path.exists(postgresql_ctl) and executable is None:
- pg_bindir = subprocess.check_output(
- ['pg_config', '--bindir'], universal_newlines=True
- ).strip()
- postgresql_ctl = os.path.join(pg_bindir, 'pg_ctl')
-
- pg_host = host or config['host']
- pg_port = get_port(port) or get_port(config['port'])
- datadir = os.path.join(
- gettempdir(), 'postgresqldata.{}'.format(pg_port))
- pg_user = user or config['user']
- pg_options = options or config['options']
- pg_unixsocketdir = unixsocketdir or config['unixsocketdir']
- pg_startparams = startparams or config['startparams']
- logfile_path = tmpdir_factory.mktemp("data").join(
- '{prefix}postgresql.{port}.log'.format(
- prefix=logs_prefix,
- port=pg_port
- )
- )
-
- if platform.system() == 'FreeBSD':
- with (datadir / 'pg_hba.conf').open(mode='a') as conf_file:
- conf_file.write('host all all 0.0.0.0/0 trust\n')
-
- postgresql_executor = PostgreSQLExecutor(
- executable=postgresql_ctl,
- host=pg_host,
- port=pg_port,
- user=pg_user,
- options=pg_options,
- datadir=datadir,
- unixsocketdir=pg_unixsocketdir,
- logfile=logfile_path,
- startparams=pg_startparams,
- )
- # start server
- with postgresql_executor:
- postgresql_executor.wait_for_postgres()
-
- yield postgresql_executor
-
- return postgresql_proc_fixture
-
-
-def postgresql_noproc(host=None, port=None, user=None, options=''):
- """
- Postgresql noprocess factory.
-
- :param str host: hostname
- :param str|int port: exact port (e.g. '8000', 8000)
- :param str user: postgresql username
- :param str options: Postgresql connection options
- :rtype: func
- :returns: function which makes a postgresql process
- """
- @pytest.fixture(scope='session')
- def postgresql_noproc_fixture(request):
- """
- Noop Process fixture for PostgreSQL.
-
- :param FixtureRequest request: fixture request object
- :rtype: pytest_dbfixtures.executors.TCPExecutor
- :returns: tcp executor-like object
- """
- config = get_config(request)
- pg_host = host or config['host']
- pg_port = port or config['port'] or 5432
- pg_user = user or config['user']
- pg_options = options or config['options']
-
- noop_exec = NoopExecutor(
- host=pg_host,
- port=pg_port,
- user=pg_user,
- options=pg_options,
- )
-
- yield noop_exec
-
- return postgresql_noproc_fixture
-
-
-def postgresql(process_fixture_name, db_name=None):
- """
- Return connection fixture factory for PostgreSQL.
-
- :param str process_fixture_name: name of the process fixture
- :param str db_name: database name
- :rtype: func
- :returns: function which makes a connection to postgresql
- """
- @pytest.fixture
- def postgresql_factory(request):
- """
- Fixture factory for PostgreSQL.
-
- :param FixtureRequest request: fixture request object
- :rtype: psycopg2.connection
- :returns: postgresql client
- """
- config = get_config(request)
- if not psycopg2:
- raise ImportError(
- 'No module named psycopg2. Please install either '
- 'psycopg2 or psycopg2-binary package for CPython '
- 'or psycopg2cffi for Pypy.'
- )
- proc_fixture = request.getfixturevalue(process_fixture_name)
-
- # _, config = try_import('psycopg2', request)
- pg_host = proc_fixture.host
- pg_port = proc_fixture.port
- pg_user = proc_fixture.user
- pg_options = proc_fixture.options
- pg_db = db_name or config['dbname']
-
- with DatabaseJanitor(
- pg_user, pg_host, pg_port, pg_db, proc_fixture.version
- ):
- connection = psycopg2.connect(
- dbname=pg_db,
- user=pg_user,
- host=pg_host,
- port=pg_port,
- options=pg_options
- )
- yield connection
- connection.close()
-
- return postgresql_factory
-
-
-__all__ = ('postgresql', 'postgresql_proc')
diff --git a/src/pytest_postgresql/factories/__init__.py b/src/pytest_postgresql/factories/__init__.py
new file mode 100644
index 0000000..c2a7eaa
--- /dev/null
+++ b/src/pytest_postgresql/factories/__init__.py
@@ -0,0 +1,24 @@
+# Copyright (C) 2013-2021 by Clearcode
+# and associates (see AUTHORS).
+
+# This file is part of pytest-postgresql.
+
+# pytest-dbfixtures is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# pytest-dbfixtures is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with pytest-dbfixtures. If not, see .
+"""Fixture factories for postgresql fixtures."""
+
+from pytest_postgresql.factories.process import postgresql_proc
+from pytest_postgresql.factories.noprocess import postgresql_noproc
+from pytest_postgresql.factories.client import postgresql
+
+__all__ = ("postgresql_proc", "postgresql_noproc", "postgresql")
diff --git a/src/pytest_postgresql/factories/client.py b/src/pytest_postgresql/factories/client.py
new file mode 100644
index 0000000..054c9dd
--- /dev/null
+++ b/src/pytest_postgresql/factories/client.py
@@ -0,0 +1,87 @@
+# Copyright (C) 2013-2021 by Clearcode
+# and associates (see AUTHORS).
+
+# This file is part of pytest-postgresql.
+
+# pytest-dbfixtures is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# pytest-dbfixtures is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with pytest-dbfixtures. If not, see .
+"""Fixture factory for postgresql client."""
+from typing import List, Optional, Callable, Union
+
+import pytest
+from pytest import FixtureRequest
+
+from pytest_postgresql.compat import connection, check_for_psycopg2, psycopg2
+from pytest_postgresql.config import get_config
+from pytest_postgresql.executor import PostgreSQLExecutor
+from pytest_postgresql.executor_noop import NoopExecutor
+from pytest_postgresql.janitor import DatabaseJanitor
+
+
+def postgresql(
+ process_fixture_name: str,
+ dbname: Optional[str] = None,
+ load: Optional[List[Union[Callable, str]]] = None,
+ isolation_level: Optional[int] = None,
+) -> Callable[[FixtureRequest], connection]:
+ """
+ Return connection fixture factory for PostgreSQL.
+
+ :param process_fixture_name: name of the process fixture
+ :param dbname: database name
+ :param load: SQL, function or function import paths to automatically load
+ into our test database
+ :param isolation_level: optional postgresql isolation level
+ defaults to server's default
+ :returns: function which makes a connection to postgresql
+ """
+
+ @pytest.fixture
+ def postgresql_factory(request: FixtureRequest) -> connection:
+ """
+ Fixture factory for PostgreSQL.
+
+ :param request: fixture request object
+ :returns: postgresql client
+ """
+ config = get_config(request)
+ check_for_psycopg2()
+ proc_fixture: Union[PostgreSQLExecutor, NoopExecutor] = request.getfixturevalue(
+ process_fixture_name
+ )
+
+ pg_host = proc_fixture.host
+ pg_port = proc_fixture.port
+ pg_user = proc_fixture.user
+ pg_password = proc_fixture.password
+ pg_options = proc_fixture.options
+ pg_db = dbname or config["dbname"]
+ pg_load = load or config["load"] # TODO: only a fixture param should be left here.
+
+ with DatabaseJanitor(
+ pg_user, pg_host, pg_port, pg_db, proc_fixture.version, pg_password, isolation_level
+ ) as janitor:
+ db_connection: connection = psycopg2.connect(
+ dbname=pg_db,
+ user=pg_user,
+ password=pg_password,
+ host=pg_host,
+ port=pg_port,
+ options=pg_options,
+ )
+ for load_element in pg_load:
+ janitor.load(load_element)
+ yield db_connection
+ db_connection.close()
+
+ return postgresql_factory
diff --git a/src/pytest_postgresql/factories/noprocess.py b/src/pytest_postgresql/factories/noprocess.py
new file mode 100644
index 0000000..7207aa1
--- /dev/null
+++ b/src/pytest_postgresql/factories/noprocess.py
@@ -0,0 +1,89 @@
+# Copyright (C) 2013-2021 by Clearcode
+# and associates (see AUTHORS).
+
+# This file is part of pytest-postgresql.
+
+# pytest-dbfixtures is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# pytest-dbfixtures is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with pytest-dbfixtures. If not, see .
+"""Fixture factory for existing postgresql server."""
+from typing import Union, Callable, List, Iterator, Optional
+
+import pytest
+from pytest import FixtureRequest
+
+from pytest_postgresql.config import get_config
+from pytest_postgresql.executor_noop import NoopExecutor
+from pytest_postgresql.janitor import DatabaseJanitor
+
+
+def postgresql_noproc(
+ host: Optional[str] = None,
+ port: Union[str, int, None] = None,
+ user: Optional[str] = None,
+ password: Optional[str] = None,
+ dbname: Optional[str] = None,
+ options: str = "",
+ load: Optional[List[Union[Callable, str]]] = None,
+) -> Callable[[FixtureRequest], Iterator[NoopExecutor]]:
+ """
+ Postgresql noprocess factory.
+
+ :param host: hostname
+ :param port: exact port (e.g. '8000', 8000)
+ :param user: postgresql username
+ :param password: postgresql password
+ :param dbname: postgresql database name
+ :param options: Postgresql connection options
+ :param load: List of functions used to initialize database's template.
+ :returns: function which makes a postgresql process
+ """
+
+ @pytest.fixture(scope="session")
+ def postgresql_noproc_fixture(request: FixtureRequest) -> Iterator[NoopExecutor]:
+ """
+ Noop Process fixture for PostgreSQL.
+
+ :param request: fixture request object
+ :returns: tcp executor-like object
+ """
+ config = get_config(request)
+ pg_host = host or config["host"]
+ pg_port = port or config["port"] or 5432
+ pg_user = user or config["user"]
+ pg_password = password or config["password"]
+ pg_dbname = dbname or config["dbname"]
+ pg_options = options or config["options"]
+ pg_load = load or config["load"]
+
+ noop_exec = NoopExecutor(
+ host=pg_host,
+ port=pg_port,
+ user=pg_user,
+ password=pg_password,
+ dbname=pg_dbname,
+ options=pg_options,
+ )
+ template_dbname = f"{noop_exec.dbname}_tmpl"
+ with DatabaseJanitor(
+ user=noop_exec.user,
+ host=noop_exec.host,
+ port=noop_exec.port,
+ dbname=template_dbname,
+ version=noop_exec.version,
+ password=noop_exec.password,
+ ) as janitor:
+ for load_element in pg_load:
+ janitor.load(load_element)
+ yield noop_exec
+
+ return postgresql_noproc_fixture
diff --git a/src/pytest_postgresql/factories/process.py b/src/pytest_postgresql/factories/process.py
new file mode 100644
index 0000000..d178f3b
--- /dev/null
+++ b/src/pytest_postgresql/factories/process.py
@@ -0,0 +1,159 @@
+# Copyright (C) 2013-2021 by Clearcode
+# and associates (see AUTHORS).
+
+# This file is part of pytest-postgresql.
+
+# pytest-dbfixtures is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# pytest-dbfixtures is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with pytest-dbfixtures. If not, see .
+"""Fixture factory for postgresql process."""
+import os.path
+import platform
+import subprocess
+from typing import Union, Callable, List, Iterator, Optional, Tuple, Set
+from warnings import warn
+
+import pytest
+from pytest import FixtureRequest, TempPathFactory
+from port_for import get_port
+
+from pytest_postgresql.config import get_config
+from pytest_postgresql.executor import PostgreSQLExecutor
+from pytest_postgresql.janitor import DatabaseJanitor
+
+
+def postgresql_proc(
+ executable: Optional[str] = None,
+ host: Optional[str] = None,
+ port: Union[
+ None,
+ str,
+ int,
+ Tuple[int, int],
+ Set[int],
+ List[str],
+ List[int],
+ List[Tuple[int, int]],
+ List[Set[int]],
+ List[Union[Set[int], Tuple[int, int]]],
+ List[Union[str, int, Tuple[int, int], Set[int]]],
+ ] = -1,
+ user: Optional[str] = None,
+ password: Optional[str] = None,
+ dbname: Optional[str] = None,
+ options: str = "",
+ startparams: Optional[str] = None,
+ unixsocketdir: Optional[str] = None,
+ logs_prefix: str = "",
+ postgres_options: Optional[str] = None,
+ load: Optional[List[Union[Callable, str]]] = None,
+) -> Callable[[FixtureRequest, TempPathFactory], Iterator[PostgreSQLExecutor]]:
+ """
+ Postgresql process factory.
+
+ :param executable: path to postgresql_ctl
+ :param host: hostname
+ :param port:
+ exact port (e.g. '8000', 8000)
+ randomly selected port (None) - any random available port
+ -1 - command line or pytest.ini configured port
+ [(2000,3000)] or (2000,3000) - random available port from a given range
+ [{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
+ [(2000,3000), {4002,4003}] - random of given range and set
+ :param user: postgresql username
+ :param password: postgresql password
+ :param dbname: postgresql database name
+ :param options: Postgresql connection options
+ :param startparams: postgresql starting parameters
+ :param unixsocketdir: directory to create postgresql's unixsockets
+ :param logs_prefix: prefix for log filename
+ :param postgres_options: Postgres executable options for use by pg_ctl
+ :param load: List of functions used to initialize database's template.
+ :returns: function which makes a postgresql process
+ """
+
+ @pytest.fixture(scope="session")
+ def postgresql_proc_fixture(
+ request: FixtureRequest, tmp_path_factory: TempPathFactory
+ ) -> Iterator[PostgreSQLExecutor]:
+ """
+ Process fixture for PostgreSQL.
+
+ :param request: fixture request object
+ :param tmp_path_factory: temporary path object (fixture)
+ :returns: tcp executor
+ """
+ config = get_config(request)
+ postgresql_ctl = executable or config["exec"]
+ logfile_prefix = logs_prefix or config["logsprefix"]
+ pg_dbname = dbname or config["dbname"]
+ pg_load = load or config["load"]
+
+ # check if that executable exists, as it's no on system PATH
+ # only replace if executable isn't passed manually
+ if not os.path.exists(postgresql_ctl) and executable is None:
+ pg_bindir = subprocess.check_output(
+ ["pg_config", "--bindir"], universal_newlines=True
+ ).strip()
+ postgresql_ctl = os.path.join(pg_bindir, "pg_ctl")
+
+ tmpdir = tmp_path_factory.mktemp(f"pytest-postgresql-{request.fixturename}")
+
+ if logfile_prefix:
+ warn(
+ f"logfile_prefix and logsprefix config option is deprecated, "
+ f"and will be dropped in future releases. All fixture related "
+ f"data resides within {tmpdir}",
+ DeprecationWarning,
+ )
+
+ pg_port = get_port(port) or get_port(config["port"])
+ assert pg_port is not None
+ datadir = tmpdir / f"data-{pg_port}"
+ datadir.mkdir()
+ logfile_path = tmpdir / f"{logfile_prefix}postgresql.{pg_port}.log"
+
+ if platform.system() == "FreeBSD":
+ with (datadir / "pg_hba.conf").open(mode="a") as conf_file:
+ conf_file.write("host all all 0.0.0.0/0 trust\n")
+
+ postgresql_executor = PostgreSQLExecutor(
+ executable=postgresql_ctl,
+ host=host or config["host"],
+ port=pg_port,
+ user=user or config["user"],
+ password=password or config["password"],
+ dbname=pg_dbname,
+ options=options or config["options"],
+ datadir=str(datadir),
+ unixsocketdir=unixsocketdir or config["unixsocketdir"],
+ logfile=str(logfile_path),
+ startparams=startparams or config["startparams"],
+ postgres_options=postgres_options or config["postgres_options"],
+ )
+ # start server
+ with postgresql_executor:
+ postgresql_executor.wait_for_postgres()
+ template_dbname = f"{postgresql_executor.dbname}_tmpl"
+ with DatabaseJanitor(
+ user=postgresql_executor.user,
+ host=postgresql_executor.host,
+ port=postgresql_executor.port,
+ dbname=template_dbname,
+ version=postgresql_executor.version,
+ password=postgresql_executor.password,
+ ) as janitor:
+ for load_element in pg_load:
+ janitor.load(load_element)
+ yield postgresql_executor
+
+ return postgresql_proc_fixture
diff --git a/src/pytest_postgresql/janitor.py b/src/pytest_postgresql/janitor.py
index ea4e591..fa82a30 100644
--- a/src/pytest_postgresql/janitor.py
+++ b/src/pytest_postgresql/janitor.py
@@ -1,97 +1,169 @@
"""Database Janitor."""
+import re
from contextlib import contextmanager
+from functools import partial
from types import TracebackType
-from typing import TypeVar, Union, Optional, Type, Any
+from typing import TypeVar, Union, Optional, Type, Callable
from pkg_resources import parse_version
-Version = type(parse_version('1')) # pylint:disable=invalid-name
-
-try:
- import psycopg2
- try:
- from psycopg2._psycopg import cursor
- except ImportError:
- from psycopg2cffi._impl.cursor import Cursor as cursor
-except ImportError:
- psycopg2 = False
- # if there's no postgres, just go with the flow.
- cursor = Any # pylint:disable=invalid-name
+
+from pytest_postgresql.compat import psycopg2, cursor, check_for_psycopg2, connection
+from pytest_postgresql.retry import retry
+from pytest_postgresql.sql import loader
+
+Version = type(parse_version("1"))
+
DatabaseJanitorType = TypeVar("DatabaseJanitorType", bound="DatabaseJanitor")
class DatabaseJanitor:
"""Manage database state for specific tasks."""
def __init__(
- self,
- user: str,
- host: str,
- port: str,
- db_name: str,
- version: Union[str, float, Version]
+ self,
+ user: str,
+ host: str,
+ port: Union[str, int],
+ dbname: str,
+ version: Union[str, float, Version], # type: ignore[valid-type]
+ password: Optional[str] = None,
+ isolation_level: Optional[int] = None,
+ connection_timeout: int = 60,
) -> None:
"""
Initialize janitor.
:param user: postgresql username
:param host: postgresql host
:param port: postgresql port
- :param db_name: database name
+ :param dbname: database name
:param version: postgresql version number
+ :param password: optional postgresql password
+ :param isolation_level: optional postgresql isolation level
+ defaults to server's default
+ :param connection_timeout: how long to retry connection before
+ raising a TimeoutError
"""
self.user = user
+ self.password = password
self.host = host
self.port = port
- self.db_name = db_name
+ self.dbname = dbname
+ self._connection_timeout = connection_timeout
+ check_for_psycopg2()
+ self.isolation_level = isolation_level
if not isinstance(version, Version):
self.version = parse_version(str(version))
else:
self.version = version
def init(self) -> None:
"""Create database in postgresql."""
+ template_name = f"{self.dbname}_tmpl"
with self.cursor() as cur:
- cur.execute('CREATE DATABASE "{}";'.format(self.db_name))
+ if self.dbname.endswith("_tmpl"):
+ result = False
+ else:
+ cur.execute(
+ "SELECT EXISTS "
+ "(SELECT datname FROM pg_catalog.pg_database WHERE datname= %s);",
+ (template_name,),
+ )
+ result = cur.fetchone()[0]
+ if not result:
+ cur.execute(f'CREATE DATABASE "{self.dbname}";')
+ else:
+ # All template database does not allow connection:
+ self._dont_datallowconn(cur, template_name)
+ # And make sure no-one is left connected to the template database.
+ # Otherwise Creating database from template will fail
+ self._terminate_connection(cur, template_name)
+ cur.execute(f'CREATE DATABASE "{self.dbname}" TEMPLATE "{template_name}";')
def drop(self) -> None:
"""Drop database in postgresql."""
# We cannot drop the database while there are connections to it, so we
# terminate all connections first while not allowing new connections.
- if self.version >= parse_version('9.2'):
- pid_column = 'pid'
- else:
- pid_column = 'procpid'
with self.cursor() as cur:
- cur.execute(
- 'UPDATE pg_database SET datallowconn=false WHERE datname = %s;',
- (self.db_name,))
- cur.execute(
- 'SELECT pg_terminate_backend(pg_stat_activity.{})'
- 'FROM pg_stat_activity '
- 'WHERE pg_stat_activity.datname = %s;'.format(pid_column),
- (self.db_name,))
- cur.execute('DROP DATABASE IF EXISTS "{}";'.format(self.db_name))
+ self._dont_datallowconn(cur, self.dbname)
+ self._terminate_connection(cur, self.dbname)
+ cur.execute(f'DROP DATABASE IF EXISTS "{self.dbname}";')
+
+ @staticmethod
+ def _dont_datallowconn(cur: cursor, dbname: str) -> None:
+ cur.execute(f'ALTER DATABASE "{dbname}" with allow_connections false;')
+
+ @staticmethod
+ def _terminate_connection(cur: cursor, dbname: str) -> None:
+ cur.execute(
+ "SELECT pg_terminate_backend(pg_stat_activity.pid)"
+ "FROM pg_stat_activity "
+ "WHERE pg_stat_activity.datname = %s;",
+ (dbname,),
+ )
+
+ def load(self, load: Union[Callable, str]) -> None:
+ """
+ Loads data into a database.
+
+ Either runs a passed loader if it's callback,
+ or runs predefined loader if it's sql file.
+ """
+ if isinstance(load, str):
+ if "/" in load:
+ _loader: Callable = partial(loader, load)
+ else:
+ loader_parts = re.split("[.:]", load, 2)
+ import_path = ".".join(loader_parts[:-1])
+ loader_name = loader_parts[-1]
+ _temp_import = __import__(import_path, globals(), locals(), fromlist=[loader_name])
+ _loader = getattr(_temp_import, loader_name)
+ else:
+ _loader = load
+ _loader(
+ host=self.host,
+ port=self.port,
+ user=self.user,
+ dbname=self.dbname,
+ password=self.password,
+ )
@contextmanager
def cursor(self) -> cursor:
"""Return postgresql cursor."""
- conn = psycopg2.connect(user=self.user, host=self.host, port=self.port)
- conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
+
+ def connect() -> connection:
+ return psycopg2.connect(
+ dbname="postgres",
+ user=self.user,
+ password=self.password,
+ host=self.host,
+ port=self.port,
+ )
+
+ conn = retry(
+ connect, timeout=self._connection_timeout, possible_exception=psycopg2.OperationalError
+ )
+ if self.isolation_level:
+ conn.set_isolation_level(self.isolation_level)
+ # We must not run a transaction since we create a database.
+ conn.autocommit = True
cur = conn.cursor()
try:
yield cur
finally:
cur.close()
conn.close()
def __enter__(self: DatabaseJanitorType) -> DatabaseJanitorType:
self.init()
return self
def __exit__(
- self: DatabaseJanitorType,
- exc_type: Optional[Type[BaseException]],
- exc_val: Optional[BaseException],
- exc_tb: Optional[TracebackType]) -> None:
+ self: DatabaseJanitorType,
+ exc_type: Optional[Type[BaseException]],
+ exc_val: Optional[BaseException],
+ exc_tb: Optional[TracebackType],
+ ) -> None:
self.drop()
diff --git a/src/pytest_postgresql/plugin.py b/src/pytest_postgresql/plugin.py
index bff07c3..3347ac5 100644
--- a/src/pytest_postgresql/plugin.py
+++ b/src/pytest_postgresql/plugin.py
@@ -1,159 +1,134 @@
# Copyright (C) 2016 by Clearcode
# and associates (see AUTHORS).
# This file is part of pytest-postgresql.
# pytest-dbfixtures is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# pytest-postgresql is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with pytest-postgresql. If not, see .
"""Plugin module of pytest-postgresql."""
from tempfile import gettempdir
from pytest_postgresql import factories
+from _pytest.config.argparsing import Parser
-# pylint:disable=invalid-name
-_help_executable = 'Path to PostgreSQL executable'
-_help_host = 'Host at which PostgreSQL will accept connections'
-_help_port = 'Port at which PostgreSQL will accept connections'
+_help_executable = "Path to PostgreSQL executable"
+_help_host = "Host at which PostgreSQL will accept connections"
+_help_port = "Port at which PostgreSQL will accept connections"
_help_user = "PostgreSQL username"
+_help_password = "PostgreSQL password"
_help_options = "PostgreSQL connection options"
_help_startparams = "Starting parameters for the PostgreSQL"
_help_logsprefix = "Prefix for the log files"
_help_unixsocketdir = "Location of the socket directory"
_help_dbname = "Default database name"
+_help_load = "Dotted-style or entrypoint-style path to callable or path to SQL File"
+_help_postgres_options = "Postgres executable extra parameters. Passed via the -o option to pg_ctl"
-def pytest_addoption(parser):
+def pytest_addoption(parser: Parser) -> None:
"""Configure options for pytest-postgresql."""
parser.addini(
- name='postgresql_exec',
- help=_help_executable,
- default='/usr/lib/postgresql/9.1/bin/pg_ctl'
+ name="postgresql_exec", help=_help_executable, default="/usr/lib/postgresql/9.6/bin/pg_ctl"
)
- parser.addini(
- name='postgresql_host',
- help=_help_host,
- default='127.0.0.1'
- )
+ parser.addini(name="postgresql_host", help=_help_host, default="127.0.0.1")
parser.addini(
- name='postgresql_port',
+ name="postgresql_port",
help=_help_port,
default=None,
)
- parser.addini(
- name='postgresql_user',
- help=_help_user,
- default='postgres'
- )
+ parser.addini(name="postgresql_user", help=_help_user, default="postgres")
- parser.addini(
- name='postgresql_options',
- help=_help_options,
- default=''
- )
+ parser.addini(name="postgresql_password", help=_help_password, default=None)
- parser.addini(
- name='postgresql_startparams',
- help=_help_startparams,
- default='-w'
- )
+ parser.addini(name="postgresql_options", help=_help_options, default="")
- parser.addini(
- name='postgresql_logsprefix',
- help=_help_logsprefix,
- default=''
- )
+ parser.addini(name="postgresql_startparams", help=_help_startparams, default="-w")
- parser.addini(
- name='postgresql_unixsocketdir',
- help=_help_unixsocketdir,
- default=gettempdir()
- )
+ parser.addini(name="postgresql_logsprefix", help=_help_logsprefix, default="")
- parser.addini(
- name='postgresql_dbname',
- help=_help_dbname,
- default='tests'
- )
+ parser.addini(name="postgresql_unixsocketdir", help=_help_unixsocketdir, default=gettempdir())
+
+ parser.addini(name="postgresql_dbname", help=_help_dbname, default="tests")
+
+ parser.addini(name="postgresql_load", type="pathlist", help=_help_load, default=None)
+ parser.addini(name="postgresql_postgres_options", help=_help_postgres_options, default="")
parser.addoption(
- '--postgresql-exec',
- action='store',
- metavar='path',
- dest='postgresql_exec',
- help=_help_executable
+ "--postgresql-exec",
+ action="store",
+ metavar="path",
+ dest="postgresql_exec",
+ help=_help_executable,
)
parser.addoption(
- '--postgresql-host',
- action='store',
- dest='postgresql_host',
+ "--postgresql-host",
+ action="store",
+ dest="postgresql_host",
help=_help_host,
)
+ parser.addoption("--postgresql-port", action="store", dest="postgresql_port", help=_help_port)
+
+ parser.addoption("--postgresql-user", action="store", dest="postgresql_user", help=_help_user)
+
parser.addoption(
- '--postgresql-port',
- action='store',
- dest='postgresql_port',
- help=_help_port
+ "--postgresql-password", action="store", dest="postgresql_password", help=_help_password
)
parser.addoption(
- '--postgresql-user',
- action='store',
- dest='postgresql_user',
- help=_help_user
+ "--postgresql-options", action="store", dest="postgresql_options", help=_help_options
)
parser.addoption(
- '--postgresql-options',
- action='store',
- dest='postgresql_options',
- help=_help_options
+ "--postgresql-startparams",
+ action="store",
+ dest="postgresql_startparams",
+ help=_help_startparams,
)
parser.addoption(
- '--postgresql-startparams',
- action='store',
- dest='postgresql_startparams',
- help=_help_startparams
+ "--postgresql-logsprefix",
+ action="store",
+ dest="postgresql_logsprefix",
+ help=_help_logsprefix,
)
parser.addoption(
- '--postgresql-logsprefix',
- action='store',
- dest='postgresql_logsprefix',
- help=_help_logsprefix
+ "--postgresql-unixsocketdir",
+ action="store",
+ dest="postgresql_unixsocketdir",
+ help=_help_unixsocketdir,
)
parser.addoption(
- '--postgresql-unixsocketdir',
- action='store',
- dest='postgresql_unixsocketdir',
- help=_help_unixsocketdir
+ "--postgresql-dbname", action="store", dest="postgresql_dbname", help=_help_dbname
)
+ parser.addoption("--postgresql-load", action="append", dest="postgresql_load", help=_help_load)
+
parser.addoption(
- '--postgresql-dbname',
- action='store',
- dest='postgresql_dbname',
- help=_help_dbname
+ "--postgresql-postgres-options",
+ action="store",
+ dest="postgresql_postgres_options",
+ help=_help_postgres_options,
)
postgresql_proc = factories.postgresql_proc()
-postgresql_nooproc = factories.postgresql_noproc()
-postgresql = factories.postgresql('postgresql_proc')
+postgresql_noproc = factories.postgresql_noproc()
+postgresql = factories.postgresql("postgresql_proc")
diff --git a/src/pytest_postgresql/port.py b/src/pytest_postgresql/port.py
deleted file mode 100644
index 01ea434..0000000
--- a/src/pytest_postgresql/port.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (C) 2016 by Clearcode
-# and associates (see AUTHORS).
-
-# This file is part of pytest-postgresql.
-
-# pytest-postgresql is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# pytest-postgresql is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public License
-# along with pytest-postgresql. If not, see .
-"""Helpers for port-for package."""
-from itertools import chain
-
-import port_for
-
-
-class InvalidPortsDefinition(ValueError):
- """Exception raised if ports definition is not a valid string."""
-
- def __init__(self, ports):
- """Construct InvalidPortsDefinition exception."""
- super().__init__(
- 'Unknown format of ports: {}.\n'.format(ports) + (
- 'You should provide a ports range "[(4000,5000)]"'
- 'or "(4000,5000)" or a comma-separated ports set'
- '"[{4000,5000,6000}]" or list of ints "[400,5000,6000,8000]"'
- 'or all of them "[(20000, 30000), {48889, 50121}, 4000, 4004]"'
- )
- )
-
-
-def get_port(ports):
- """
- Retun a random available port.
-
- If there's only one port passed (e.g. 5000 or '5000') function
- does not check if port is available.
- it there's -1 passed as an argument, function returns None.
- When a range or list of ports is passed `port_for` external package
- is used in order to find a free port.
-
- :param str|int|tuple|set|list port:
- exact port (e.g. '8000', 8000)
- randomly selected port (None) - any random available port
- [(2000,3000)] or (2000,3000) - random available port from a given range
- [{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
- [(2000,3000), {4002,4003}] -random of given orange and set
- :returns: a random free port
- :raises: ValueError
- """
- if ports == -1:
- return None
- if not ports:
- return port_for.select_random(None)
-
- try:
- return int(ports)
- except TypeError:
- pass
-
- ports_set = set()
-
- try:
- if not isinstance(ports, list):
- ports = [ports]
- ranges = port_for.utils.ranges_to_set(filter_by_type(ports, tuple))
- nums = set(filter_by_type(ports, int))
- sets = set(chain(*filter_by_type(ports, (set, frozenset))))
- ports_set = ports_set.union(ranges, sets, nums)
- except ValueError:
- raise InvalidPortsDefinition
-
- return port_for.select_random(ports_set)
-
-
-def filter_by_type(lst, type_of):
- """Return a list of elements with given type."""
- return [e for e in lst if isinstance(e, type_of)]
diff --git a/src/pytest_postgresql/py.typed b/src/pytest_postgresql/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/src/pytest_postgresql/retry.py b/src/pytest_postgresql/retry.py
new file mode 100644
index 0000000..f3d3178
--- /dev/null
+++ b/src/pytest_postgresql/retry.py
@@ -0,0 +1,35 @@
+"""Small retry callable in case of specific error occured"""
+
+from datetime import datetime, timedelta
+from time import sleep
+from typing import Callable, TypeVar, Type
+
+
+T = TypeVar("T")
+
+
+def retry(
+ func: Callable[[], T], timeout: int = 60, possible_exception: Type[Exception] = Exception
+) -> T:
+ """
+ Attempt to retry the function for timeout time.
+
+ Most often used for connecting to postgresql database as,
+ especially on macos on github-actions, first few tries fails
+ with this message:
+
+ ... ::
+ FATAL: the database system is starting up
+ """
+ time: datetime = datetime.utcnow()
+ timeout_diff: timedelta = timedelta(seconds=timeout)
+ i = 0
+ while True:
+ i += 1
+ try:
+ res = func()
+ return res
+ except possible_exception as e:
+ if time + timeout_diff < datetime.utcnow():
+ raise TimeoutError(f"Faile after {i} attempts") from e
+ sleep(1)
diff --git a/src/pytest_postgresql/sql.py b/src/pytest_postgresql/sql.py
new file mode 100644
index 0000000..0a051e6
--- /dev/null
+++ b/src/pytest_postgresql/sql.py
@@ -0,0 +1,12 @@
+from typing import Dict
+
+from pytest_postgresql.compat import psycopg2
+
+
+def loader(sql_filename: str, **kwargs: Dict) -> None:
+ """Database loader for sql files"""
+ db_connection = psycopg2.connect(**kwargs)
+ with open(sql_filename, "r") as _fd:
+ with db_connection.cursor() as cur:
+ cur.execute(_fd.read())
+ db_connection.commit()
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index 3177959..0000000
--- a/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""Main test module."""
diff --git a/tests/conftest.py b/tests/conftest.py
deleted file mode 100644
index 5670a6a..0000000
--- a/tests/conftest.py
+++ /dev/null
@@ -1,21 +0,0 @@
-"""Tests main conftest file."""
-from pytest_postgresql import factories
-
-
-PG_CTL = '/usr/lib/postgresql/{ver}/bin/pg_ctl'
-
-# pylint:disable=invalid-name
-postgresql92 = factories.postgresql_proc(PG_CTL.format(ver='9.2'), port=None)
-postgresql93 = factories.postgresql_proc(PG_CTL.format(ver='9.3'), port=None)
-postgresql94 = factories.postgresql_proc(PG_CTL.format(ver='9.4'), port=None)
-postgresql95 = factories.postgresql_proc(PG_CTL.format(ver='9.5'), port=None)
-postgresql96 = factories.postgresql_proc(PG_CTL.format(ver='9.6'), port=None)
-postgresql10 = factories.postgresql_proc(PG_CTL.format(ver='10'), port=None)
-postgresql11 = factories.postgresql_proc(PG_CTL.format(ver='11'), port=None)
-
-postgresql_proc2 = factories.postgresql_proc(port=9876)
-postgresql2 = factories.postgresql('postgresql_proc2', db_name='test-db')
-
-postgresql_rand_proc = factories.postgresql_proc(port=None)
-postgresql_rand = factories.postgresql('postgresql_rand_proc')
-# pylint:enable=invalid-name
diff --git a/tests/test_executor.py b/tests/test_executor.py
deleted file mode 100644
index 59461b2..0000000
--- a/tests/test_executor.py
+++ /dev/null
@@ -1,34 +0,0 @@
-"""Test various executor behaviours."""
-import pytest
-from pkg_resources import parse_version
-
-from pytest_postgresql.executor import PostgreSQLExecutor, PostgreSQLUnsupported
-from pytest_postgresql.factories import get_config
-from pytest_postgresql.port import get_port
-
-
-class PatchedPostgreSQLExecutor(PostgreSQLExecutor):
- """PostgreSQLExecutor that always says it's 8.9 version."""
-
- @property
- def version(self):
- """Overwrite version, to always return highes unsupported version."""
- return parse_version('8.9')
-
-
-def test_unsupported_version(request):
- """Check that the error gets raised on unsupported postgres version."""
- config = get_config(request)
- executor = PatchedPostgreSQLExecutor(
- executable=config['exec'],
- host=config['host'],
- port=get_port(config['port']),
- datadir='/tmp/error',
- unixsocketdir=config['unixsocketdir'],
- logfile='/tmp/version.error.log',
- startparams=config['startparams'],
-
- )
-
- with pytest.raises(PostgreSQLUnsupported):
- executor.start()
diff --git a/tests/test_janitor.py b/tests/test_janitor.py
deleted file mode 100644
index 6ec558d..0000000
--- a/tests/test_janitor.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Database Janitor tests."""
-import pytest
-from pkg_resources import parse_version
-
-from pytest_postgresql.janitor import DatabaseJanitor
-
-VERSION = parse_version('9.2')
-
-
-@pytest.mark.parametrize('version', (VERSION, 9.2, '9.2'))
-def test_version_cast(version):
- """Test that version is cast to Version object."""
- janitor = DatabaseJanitor(None, None, None, None, version)
- assert janitor.version == VERSION
diff --git a/tests/test_noopexecutor.py b/tests/test_noopexecutor.py
deleted file mode 100644
index 0e4203b..0000000
--- a/tests/test_noopexecutor.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""Test for NoopExecutor."""
-
-from pytest_postgresql.factories import NoopExecutor
-
-
-def test_nooproc_version(postgresql_proc):
- """Test the way postgresql version is being read."""
- postgresql_nooproc = NoopExecutor(
- postgresql_proc.host,
- postgresql_proc.port,
- postgresql_proc.user,
- postgresql_proc.options
- )
- assert postgresql_proc.version == postgresql_nooproc.version
-
-
-def test_nooproc_cached_version(postgresql_proc):
- """Test that the version is being cached."""
- postgresql_nooproc = NoopExecutor(
- postgresql_proc.host,
- postgresql_proc.port,
- postgresql_proc.user,
- postgresql_proc.options
- )
- ver = postgresql_nooproc.version
- with postgresql_proc.stopped():
- assert ver == postgresql_nooproc.version
diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py
deleted file mode 100644
index 83f33b8..0000000
--- a/tests/test_postgresql.py
+++ /dev/null
@@ -1,68 +0,0 @@
-"""All tests for pytest-postgresql."""
-import platform
-import psycopg2
-import pytest
-
-
-QUERY = "CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);"
-
-
-@pytest.mark.skipif(
- platform.system() == 'Darwin',
- reason='These fixtures are only for linux'
-)
-@pytest.mark.parametrize('postgres', (
- 'postgresql94',
- 'postgresql95',
- 'postgresql96',
- 'postgresql10',
- pytest.param('postgresql11', marks=pytest.mark.xfail),
-))
-def test_postgresql_proc(request, postgres):
- """Test different postgresql versions."""
- postgresql_proc = request.getfixturevalue(postgres)
- assert postgresql_proc.running() is True
-
-
-def test_main_postgres(postgresql):
- """Check main postgresql fixture."""
- cur = postgresql.cursor()
- cur.execute(QUERY)
- postgresql.commit()
- cur.close()
-
-
-def test_two_postgreses(postgresql, postgresql2):
- """Check two postgresql fixtures on one test."""
- cur = postgresql.cursor()
- cur.execute(QUERY)
- postgresql.commit()
- cur.close()
-
- cur = postgresql2.cursor()
- cur.execute(QUERY)
- postgresql2.commit()
- cur.close()
-
-
-def test_rand_postgres_port(postgresql_rand):
- """Check if postgres fixture can be started on random port."""
- assert postgresql_rand.status == psycopg2.extensions.STATUS_READY
-
-
-@pytest.mark.parametrize('_', range(2))
-def test_postgres_terminate_connection(
- postgresql, _):
- """
- Test that connections are terminated between tests.
-
- And check that only one exists at a time.
- """
- cur = postgresql.cursor()
- cur.execute(
- 'SELECT * FROM pg_stat_activity '
- 'WHERE backend_type = \'client backend\';'
- )
- existing_connections = cur.fetchall()
- assert len(existing_connections) == 1, 'there is always only one connection'
- cur.close()
diff --git a/tests/test_version.py b/tests/test_version.py
deleted file mode 100644
index 0459b4c..0000000
--- a/tests/test_version.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Auxiliary tests."""
-import pytest
-
-from pytest_postgresql.executor import PostgreSQLExecutor
-
-
-@pytest.mark.parametrize('ctl_input, version', (
- ('pg_ctl (PostgreSQL) 9.6.6', '9.6'),
- ('pg_ctl (PostgreSQL) 9.5', '9.5'),
- ('pg_ctl (PostgreSQL) 9.4.1', '9.4'),
- ('pg_ctl (PostgreSQL) 10.0', '10.0'),
- ('pg_ctl (PostgreSQL) 10.1', '10.1'),
-))
-def test_versions(ctl_input, version):
- """Check correctness of the version regexp."""
- match = PostgreSQLExecutor.VERSION_RE.search(ctl_input)
- assert match.groupdict()['version'] == version