pytest-postgresql 5.1.1__tar.gz → 6.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/CHANGES.rst +60 -1
  2. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/PKG-INFO +8 -6
  3. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/README.rst +6 -4
  4. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pyproject.toml +8 -4
  5. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/__init__.py +1 -1
  6. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/config.py +18 -3
  7. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/executor.py +12 -5
  8. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/executor_noop.py +8 -3
  9. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/factories/__init__.py +3 -3
  10. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/factories/client.py +24 -6
  11. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/factories/noprocess.py +6 -6
  12. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/factories/process.py +6 -6
  13. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/janitor.py +37 -39
  14. pytest_postgresql-6.0.1/pytest_postgresql/loader.py +32 -0
  15. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/plugin.py +1 -1
  16. pytest_postgresql-6.0.1/pytest_postgresql/retry.py +48 -0
  17. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql.egg-info/PKG-INFO +8 -6
  18. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql.egg-info/SOURCES.txt +2 -1
  19. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/tests/test_executor.py +1 -0
  20. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/tests/test_janitor.py +15 -3
  21. pytest_postgresql-6.0.1/tests/test_loader.py +20 -0
  22. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/tests/test_noopexecutor.py +1 -0
  23. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/tests/test_postgres_options_plugin.py +9 -0
  24. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/tests/test_postgresql.py +1 -0
  25. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/tests/test_template_database.py +1 -0
  26. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/tests/test_version.py +1 -0
  27. pytest-postgresql-5.1.1/pytest_postgresql/retry.py +0 -33
  28. pytest-postgresql-5.1.1/pytest_postgresql/sql.py +0 -13
  29. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/AUTHORS.rst +0 -0
  30. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/CONTRIBUTING.rst +0 -0
  31. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/COPYING +0 -0
  32. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/COPYING.lesser +0 -0
  33. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/MANIFEST.in +0 -0
  34. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/exceptions.py +0 -0
  35. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql/py.typed +0 -0
  36. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql.egg-info/dependency_links.txt +0 -0
  37. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql.egg-info/entry_points.txt +0 -0
  38. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql.egg-info/requires.txt +0 -0
  39. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql.egg-info/top_level.txt +0 -0
  40. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/pytest_postgresql.egg-info/zip-safe +0 -0
  41. {pytest-postgresql-5.1.1 → pytest_postgresql-6.0.1}/setup.cfg +0 -0
@@ -3,6 +3,65 @@ CHANGELOG
3
3
 
4
4
  .. towncrier release notes start
5
5
 
6
+ 6.0.1 (2024-08-14)
7
+ ==================
8
+
9
+ Bugfixes
10
+ --------
11
+
12
+ - Fixed a long-standing bug, where calls to pg_ctl weren't getting `LC_*` and `LANG` envvars,
13
+ which caused issues on some systems not recognizing --auth parameter. (`#343 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/343>`__)
14
+
15
+
16
+ Miscellaneus
17
+ ------------
18
+
19
+ - `#945 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/945>`__
20
+
21
+
22
+ 6.0.0 (2024-03-11)
23
+ ==================
24
+
25
+ Breaking changes
26
+ ----------------
27
+
28
+ - DatabaseJanitor class now accepts only keyword arguments. (`#899 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/899>`__)
29
+
30
+
31
+ Bugfixes
32
+ --------
33
+
34
+ - Fix the remaining `DepcrecationWarning` for `datetime.datetime.utcnow` on Python 3.12. (`#896 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/896>`__)
35
+
36
+
37
+ Deprecations
38
+ ------------
39
+
40
+ - Deprecated load parameter on a client fixture.
41
+ Developers are encouraged to either use the load function/parameter
42
+ for process fixture, or create an intermediate fixture placed between client
43
+ and tests themselves to fill in the data. (`#850 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/850>`__)
44
+
45
+
46
+ Features
47
+ --------
48
+
49
+ - Now all sql files used to initialise database for tests, has to be passed as pathlib.Path instance.
50
+
51
+ This helps the DatabaseJanitor choose correct behaviour based on parameter. (`#638 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/638>`__)
52
+ - Have separate parameters for template database name and database name in DatabaseJanitor.
53
+ It'll make it much clearer to understand the code and Janitor's behaviour. (`#672 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/672>`__)
54
+ - Template databases are now created with is_template flag turned on, and not by setting allow_connections to false.
55
+
56
+ The allow_connections flag being set to false is used strictly right before we attempt to drop the database. (`#914 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/914>`__)
57
+
58
+
59
+ Miscellaneus
60
+ ------------
61
+
62
+ - `#865 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/865>`__, `#882 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/882>`__, `#893 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/893>`__, `#900 <https://github.com/ClearcodeHQ/pytest-postgresql/issues/900>`__
63
+
64
+
6
65
  5.1.1 (2024-03-07)
7
66
  ==================
8
67
 
@@ -385,4 +444,4 @@ Bugfix
385
444
  - create command line and pytest.ini configuration options for executable
386
445
  - create command line and pytest.ini configuration options for host
387
446
  - create command line and pytest.ini configuration options for port
388
- - Extracted code from pytest-dbfixtures
447
+ - Extracted code from pytest-postgresql
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytest-postgresql
3
- Version: 5.1.1
3
+ Version: 6.0.1
4
4
  Summary: Postgresql fixtures and fixture factories for Pytest.
5
5
  Author-email: Grzegorz Śliwiński <fizyk+pypi@fizyk.dev>
6
6
  Project-URL: Source, https://github.com/ClearcodeHQ/pytest-postgresql
7
7
  Project-URL: Bug Tracker, https://github.com/ClearcodeHQ/pytest-postgresql/issues
8
- Project-URL: Changelog, https://github.com/ClearcodeHQ/pytest-postgresql/blob/v5.1.1/CHANGES.rst
8
+ Project-URL: Changelog, https://github.com/ClearcodeHQ/pytest-postgresql/blob/v6.0.1/CHANGES.rst
9
9
  Keywords: tests,pytest,fixture,postgresql
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Environment :: Web Environment
@@ -141,9 +141,10 @@ Client specific loads the database each test
141
141
 
142
142
  .. code-block:: python
143
143
 
144
+ from pathlib import Path
144
145
  postgresql_my_with_schema = factories.postgresql(
145
146
  'postgresql_my_proc',
146
- load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
147
+ load=[Path("schemafile.sql"), Path("otherschema.sql"), "import.path.to.function", "import.path.to:otherfunction", load_this]
147
148
  )
148
149
 
149
150
  .. warning::
@@ -152,12 +153,13 @@ Client specific loads the database each test
152
153
 
153
154
 
154
155
  The process fixture performs the load once per test session, and loads the data into the template database.
155
- Client fixture then creates test database out of the template database each test, which significantly speeds up the tests.
156
+ Client fixture then creates test database out of the template database each test, which significantly **speeds up the tests**.
156
157
 
157
158
  .. code-block:: python
158
159
 
160
+ from pathlib import Path
159
161
  postgresql_my_proc = factories.postgresql_proc(
160
- load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
162
+ load=[Path("schemafile.sql"), Path("otherschema.sql"), "import.path.to.function", "import.path.to:otherfunction", load_this]
161
163
  )
162
164
 
163
165
 
@@ -511,7 +513,7 @@ it'll be on a docker machine or running remotely or locally.
511
513
  Using SQLAlchemy to initialise basic database state
512
514
  +++++++++++++++++++++++++++++++++++++++++++++++++++
513
515
 
514
- How to use SQLAlchemy for common initalisation:
516
+ How to use SQLAlchemy for common initialisation:
515
517
 
516
518
  .. code-block:: python
517
519
 
@@ -104,9 +104,10 @@ Client specific loads the database each test
104
104
 
105
105
  .. code-block:: python
106
106
 
107
+ from pathlib import Path
107
108
  postgresql_my_with_schema = factories.postgresql(
108
109
  'postgresql_my_proc',
109
- load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
110
+ load=[Path("schemafile.sql"), Path("otherschema.sql"), "import.path.to.function", "import.path.to:otherfunction", load_this]
110
111
  )
111
112
 
112
113
  .. warning::
@@ -115,12 +116,13 @@ Client specific loads the database each test
115
116
 
116
117
 
117
118
  The process fixture performs the load once per test session, and loads the data into the template database.
118
- Client fixture then creates test database out of the template database each test, which significantly speeds up the tests.
119
+ Client fixture then creates test database out of the template database each test, which significantly **speeds up the tests**.
119
120
 
120
121
  .. code-block:: python
121
122
 
123
+ from pathlib import Path
122
124
  postgresql_my_proc = factories.postgresql_proc(
123
- load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
125
+ load=[Path("schemafile.sql"), Path("otherschema.sql"), "import.path.to.function", "import.path.to:otherfunction", load_this]
124
126
  )
125
127
 
126
128
 
@@ -474,7 +476,7 @@ it'll be on a docker machine or running remotely or locally.
474
476
  Using SQLAlchemy to initialise basic database state
475
477
  +++++++++++++++++++++++++++++++++++++++++++++++++++
476
478
 
477
- How to use SQLAlchemy for common initalisation:
479
+ How to use SQLAlchemy for common initialisation:
478
480
 
479
481
  .. code-block:: python
480
482
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pytest-postgresql"
3
- version = "5.1.1"
3
+ version = "6.0.1"
4
4
  description = "Postgresql fixtures and fixture factories for Pytest."
5
5
  readme = "README.rst"
6
6
  keywords = ["tests", "pytest", "fixture", "postgresql"]
@@ -39,7 +39,7 @@ requires-python = ">= 3.8"
39
39
  [project.urls]
40
40
  "Source" = "https://github.com/ClearcodeHQ/pytest-postgresql"
41
41
  "Bug Tracker" = "https://github.com/ClearcodeHQ/pytest-postgresql/issues"
42
- "Changelog" = "https://github.com/ClearcodeHQ/pytest-postgresql/blob/v5.1.1/CHANGES.rst"
42
+ "Changelog" = "https://github.com/ClearcodeHQ/pytest-postgresql/blob/v6.0.1/CHANGES.rst"
43
43
 
44
44
  [project.entry-points."pytest11"]
45
45
  pytest_postgresql = "pytest_postgresql.plugin"
@@ -95,16 +95,20 @@ showcontent = true
95
95
  name = "Bugfixes"
96
96
  showcontent = true
97
97
 
98
+ [tool.towncrier.fragment.deprecate]
99
+ name = "Deprecations"
100
+ showcontent = true
101
+
98
102
  [tool.towncrier.fragment.break]
99
103
  name = "Breaking changes"
100
104
  showcontent = true
101
105
 
102
106
  [tool.towncrier.fragment.misc]
103
107
  name = "Miscellaneus"
104
- showcontent = true
108
+ showcontent = false
105
109
 
106
110
  [tool.tbump.version]
107
- current = "5.1.1"
111
+ current = "6.0.1"
108
112
 
109
113
  # Example of a semver regexp.
110
114
  # Make sure this matches current_version before
@@ -18,4 +18,4 @@
18
18
  # along with pytest-postgresql. If not, see <http://www.gnu.org/licenses/>.
19
19
  """Main module for pytest-postgresql."""
20
20
 
21
- __version__ = "5.1.1"
21
+ __version__ = "6.0.1"
@@ -1,5 +1,7 @@
1
1
  """Plugin's configuration."""
2
- from typing import Any, List, Optional, TypedDict
2
+
3
+ from pathlib import Path
4
+ from typing import Any, List, Optional, TypedDict, Union
3
5
 
4
6
  from pytest import FixtureRequest
5
7
 
@@ -16,7 +18,7 @@ class PostgresqlConfigDict(TypedDict):
16
18
  startparams: str
17
19
  unixsocketdir: str
18
20
  dbname: str
19
- load: List[str]
21
+ load: List[Union[Path, str]]
20
22
  postgres_options: str
21
23
 
22
24
 
@@ -27,6 +29,8 @@ def get_config(request: FixtureRequest) -> PostgresqlConfigDict:
27
29
  name = "postgresql_" + option
28
30
  return request.config.getoption(name) or request.config.getini(name)
29
31
 
32
+ load_paths = detect_paths(get_postgresql_option("load"))
33
+
30
34
  return PostgresqlConfigDict(
31
35
  exec=get_postgresql_option("exec"),
32
36
  host=get_postgresql_option("host"),
@@ -37,6 +41,17 @@ def get_config(request: FixtureRequest) -> PostgresqlConfigDict:
37
41
  startparams=get_postgresql_option("startparams"),
38
42
  unixsocketdir=get_postgresql_option("unixsocketdir"),
39
43
  dbname=get_postgresql_option("dbname"),
40
- load=get_postgresql_option("load"),
44
+ load=load_paths,
41
45
  postgres_options=get_postgresql_option("postgres_options"),
42
46
  )
47
+
48
+
49
+ def detect_paths(load_paths: List[str]) -> List[Union[Path, str]]:
50
+ """Convert path to sql files to Path instances."""
51
+ converted_load_paths: List[Union[Path, str]] = []
52
+ for path in load_paths:
53
+ if path.endswith(".sql"):
54
+ converted_load_paths.append(Path(path))
55
+ else:
56
+ converted_load_paths.append(path)
57
+ return converted_load_paths
@@ -3,18 +3,18 @@
3
3
 
4
4
  # This file is part of pytest-postgresql.
5
5
 
6
- # pytest-dbfixtures is free software: you can redistribute it and/or modify
6
+ # pytest-postgresql is free software: you can redistribute it and/or modify
7
7
  # it under the terms of the GNU Lesser General Public License as published by
8
8
  # the Free Software Foundation, either version 3 of the License, or
9
9
  # (at your option) any later version.
10
10
 
11
- # pytest-dbfixtures is distributed in the hope that it will be useful,
11
+ # pytest-postgresql is distributed in the hope that it will be useful,
12
12
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
13
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
14
  # GNU Lesser General Public License for more details.
15
15
 
16
16
  # You should have received a copy of the GNU Lesser General Public License
17
- # along with pytest-dbfixtures. If not, see <http://www.gnu.org/licenses/>.
17
+ # along with pytest-postgresql. If not, see <http://www.gnu.org/licenses/>.
18
18
  """PostgreSQL executor crafter around pg_ctl."""
19
19
 
20
20
  import os.path
@@ -131,6 +131,11 @@ class PostgreSQLExecutor(TCPExecutor):
131
131
  },
132
132
  )
133
133
 
134
+ @property
135
+ def template_dbname(self) -> str:
136
+ """Return the template database name."""
137
+ return f"{self.dbname}_tmpl"
138
+
134
139
  def start(self: T) -> T:
135
140
  """Add check for postgresql version before starting process."""
136
141
  if self.version < self.MIN_SUPPORTED_VERSION:
@@ -172,11 +177,13 @@ class PostgreSQLExecutor(TCPExecutor):
172
177
  password_file.write(password)
173
178
  password_file.flush()
174
179
  init_directory += ["-o", " ".join(options)]
175
- subprocess.check_output(init_directory)
180
+ # Passing envvars to command to avoid weird MacOs error.
181
+ subprocess.check_output(init_directory, env=self._envvars)
176
182
  else:
177
183
  options += ["--auth=trust"]
178
184
  init_directory += ["-o", " ".join(options)]
179
- subprocess.check_output(init_directory)
185
+ # Passing envvars to command to avoid weird MacOs error.
186
+ subprocess.check_output(init_directory, env=self._envvars)
180
187
 
181
188
  self._directory_initialised = True
182
189
 
@@ -3,18 +3,18 @@
3
3
 
4
4
  # This file is part of pytest-postgresql.
5
5
 
6
- # pytest-dbfixtures is free software: you can redistribute it and/or modify
6
+ # pytest-postgresql is free software: you can redistribute it and/or modify
7
7
  # it under the terms of the GNU Lesser General Public License as published by
8
8
  # the Free Software Foundation, either version 3 of the License, or
9
9
  # (at your option) any later version.
10
10
 
11
- # pytest-dbfixtures is distributed in the hope that it will be useful,
11
+ # pytest-postgresql is distributed in the hope that it will be useful,
12
12
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
13
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
14
  # GNU Lesser General Public License for more details.
15
15
 
16
16
  # You should have received a copy of the GNU Lesser General Public License
17
- # along with pytest-dbfixtures. If not, see <http://www.gnu.org/licenses/>.
17
+ # along with pytest-postgresql. If not, see <http://www.gnu.org/licenses/>.
18
18
  """PostgreSQL Noop executor providing connection details for postgres client."""
19
19
  from typing import Any, Optional, Union
20
20
 
@@ -56,6 +56,11 @@ class NoopExecutor:
56
56
  self.dbname = dbname
57
57
  self._version: Any = None
58
58
 
59
+ @property
60
+ def template_dbname(self) -> str:
61
+ """Return the template database name."""
62
+ return f"{self.dbname}_tmpl"
63
+
59
64
  @property
60
65
  def version(self) -> Any:
61
66
  """Get postgresql's version."""
@@ -3,18 +3,18 @@
3
3
 
4
4
  # This file is part of pytest-postgresql.
5
5
 
6
- # pytest-dbfixtures is free software: you can redistribute it and/or modify
6
+ # pytest-postgresql is free software: you can redistribute it and/or modify
7
7
  # it under the terms of the GNU Lesser General Public License as published by
8
8
  # the Free Software Foundation, either version 3 of the License, or
9
9
  # (at your option) any later version.
10
10
 
11
- # pytest-dbfixtures is distributed in the hope that it will be useful,
11
+ # pytest-postgresql is distributed in the hope that it will be useful,
12
12
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
13
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
14
  # GNU Lesser General Public License for more details.
15
15
 
16
16
  # You should have received a copy of the GNU Lesser General Public License
17
- # along with pytest-dbfixtures. If not, see <http://www.gnu.org/licenses/>.
17
+ # along with pytest-postgresql. If not, see <http://www.gnu.org/licenses/>.
18
18
  """Fixture factories for postgresql fixtures."""
19
19
 
20
20
  from pytest_postgresql.factories.client import postgresql
@@ -3,19 +3,21 @@
3
3
 
4
4
  # This file is part of pytest-postgresql.
5
5
 
6
- # pytest-dbfixtures is free software: you can redistribute it and/or modify
6
+ # pytest-postgresql is free software: you can redistribute it and/or modify
7
7
  # it under the terms of the GNU Lesser General Public License as published by
8
8
  # the Free Software Foundation, either version 3 of the License, or
9
9
  # (at your option) any later version.
10
10
 
11
- # pytest-dbfixtures is distributed in the hope that it will be useful,
11
+ # pytest-postgresql is distributed in the hope that it will be useful,
12
12
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
13
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
14
  # GNU Lesser General Public License for more details.
15
15
 
16
16
  # You should have received a copy of the GNU Lesser General Public License
17
- # along with pytest-dbfixtures. If not, see <http://www.gnu.org/licenses/>.
17
+ # along with pytest-postgresql. If not, see <http://www.gnu.org/licenses/>.
18
18
  """Fixture factory for postgresql client."""
19
+ import warnings
20
+ from pathlib import Path
19
21
  from typing import Callable, Iterator, List, Optional, Union
20
22
 
21
23
  import psycopg
@@ -31,7 +33,7 @@ from pytest_postgresql.janitor import DatabaseJanitor
31
33
  def postgresql(
32
34
  process_fixture_name: str,
33
35
  dbname: Optional[str] = None,
34
- load: Optional[List[Union[Callable, str]]] = None,
36
+ load: Optional[List[Union[Callable, str, Path]]] = None,
35
37
  isolation_level: "Optional[psycopg.IsolationLevel]" = None,
36
38
  ) -> Callable[[FixtureRequest], Iterator[Connection]]:
37
39
  """Return connection fixture factory for PostgreSQL.
@@ -63,9 +65,25 @@ def postgresql(
63
65
  pg_options = proc_fixture.options
64
66
  pg_db = dbname or proc_fixture.dbname
65
67
  pg_load = load or []
66
-
68
+ if pg_load:
69
+ warnings.warn(
70
+ message=(
71
+ "Load is deprecated on a client fixture. "
72
+ "You should either process fixture load parameter to pre-fill database, "
73
+ "or add a fixture between client and a test, "
74
+ "that will fill the database with the data."
75
+ ),
76
+ category=DeprecationWarning,
77
+ )
67
78
  with DatabaseJanitor(
68
- pg_user, pg_host, pg_port, pg_db, proc_fixture.version, pg_password, isolation_level
79
+ user=pg_user,
80
+ host=pg_host,
81
+ port=pg_port,
82
+ dbname=pg_db,
83
+ template_dbname=proc_fixture.template_dbname,
84
+ version=proc_fixture.version,
85
+ password=pg_password,
86
+ isolation_level=isolation_level,
69
87
  ) as janitor:
70
88
  db_connection: Connection = psycopg.connect(
71
89
  dbname=pg_db,
@@ -3,20 +3,21 @@
3
3
 
4
4
  # This file is part of pytest-postgresql.
5
5
 
6
- # pytest-dbfixtures is free software: you can redistribute it and/or modify
6
+ # pytest-postgresql is free software: you can redistribute it and/or modify
7
7
  # it under the terms of the GNU Lesser General Public License as published by
8
8
  # the Free Software Foundation, either version 3 of the License, or
9
9
  # (at your option) any later version.
10
10
 
11
- # pytest-dbfixtures is distributed in the hope that it will be useful,
11
+ # pytest-postgresql is distributed in the hope that it will be useful,
12
12
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
13
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
14
  # GNU Lesser General Public License for more details.
15
15
 
16
16
  # You should have received a copy of the GNU Lesser General Public License
17
- # along with pytest-dbfixtures. If not, see <http://www.gnu.org/licenses/>.
17
+ # along with pytest-postgresql. If not, see <http://www.gnu.org/licenses/>.
18
18
  """Fixture factory for existing postgresql server."""
19
19
  import os
20
+ from pathlib import Path
20
21
  from typing import Callable, Iterator, List, Optional, Union
21
22
 
22
23
  import pytest
@@ -42,7 +43,7 @@ def postgresql_noproc(
42
43
  password: Optional[str] = None,
43
44
  dbname: Optional[str] = None,
44
45
  options: str = "",
45
- load: Optional[List[Union[Callable, str]]] = None,
46
+ load: Optional[List[Union[Callable, str, Path]]] = None,
46
47
  ) -> Callable[[FixtureRequest], Iterator[NoopExecutor]]:
47
48
  """Postgresql noprocess factory.
48
49
 
@@ -80,12 +81,11 @@ def postgresql_noproc(
80
81
  dbname=pg_dbname,
81
82
  options=pg_options,
82
83
  )
83
- template_dbname = f"{noop_exec.dbname}_tmpl"
84
84
  with DatabaseJanitor(
85
85
  user=noop_exec.user,
86
86
  host=noop_exec.host,
87
87
  port=noop_exec.port,
88
- dbname=template_dbname,
88
+ template_dbname=noop_exec.template_dbname,
89
89
  version=noop_exec.version,
90
90
  password=noop_exec.password,
91
91
  ) as janitor:
@@ -3,22 +3,23 @@
3
3
 
4
4
  # This file is part of pytest-postgresql.
5
5
 
6
- # pytest-dbfixtures is free software: you can redistribute it and/or modify
6
+ # pytest-postgresql is free software: you can redistribute it and/or modify
7
7
  # it under the terms of the GNU Lesser General Public License as published by
8
8
  # the Free Software Foundation, either version 3 of the License, or
9
9
  # (at your option) any later version.
10
10
 
11
- # pytest-dbfixtures is distributed in the hope that it will be useful,
11
+ # pytest-postgresql is distributed in the hope that it will be useful,
12
12
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
13
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
14
  # GNU Lesser General Public License for more details.
15
15
 
16
16
  # You should have received a copy of the GNU Lesser General Public License
17
- # along with pytest-dbfixtures. If not, see <http://www.gnu.org/licenses/>.
17
+ # along with pytest-postgresql. If not, see <http://www.gnu.org/licenses/>.
18
18
  """Fixture factory for postgresql process."""
19
19
  import os.path
20
20
  import platform
21
21
  import subprocess
22
+ from pathlib import Path
22
23
  from typing import Callable, Iterator, List, Optional, Set, Tuple, Union
23
24
 
24
25
  import pytest
@@ -54,7 +55,7 @@ def postgresql_proc(
54
55
  startparams: Optional[str] = None,
55
56
  unixsocketdir: Optional[str] = None,
56
57
  postgres_options: Optional[str] = None,
57
- load: Optional[List[Union[Callable, str]]] = None,
58
+ load: Optional[List[Union[Callable, str, Path]]] = None,
58
59
  ) -> Callable[[FixtureRequest, TempPathFactory], Iterator[PostgreSQLExecutor]]:
59
60
  """Postgresql process factory.
60
61
 
@@ -135,12 +136,11 @@ def postgresql_proc(
135
136
  # start server
136
137
  with postgresql_executor:
137
138
  postgresql_executor.wait_for_postgres()
138
- template_dbname = f"{postgresql_executor.dbname}_tmpl"
139
139
  with DatabaseJanitor(
140
140
  user=postgresql_executor.user,
141
141
  host=postgresql_executor.host,
142
142
  port=postgresql_executor.port,
143
- dbname=template_dbname,
143
+ template_dbname=postgresql_executor.template_dbname,
144
144
  version=postgresql_executor.version,
145
145
  password=postgresql_executor.password,
146
146
  ) as janitor:
@@ -1,7 +1,7 @@
1
1
  """Database Janitor."""
2
- import re
2
+
3
3
  from contextlib import contextmanager
4
- from functools import partial
4
+ from pathlib import Path
5
5
  from types import TracebackType
6
6
  from typing import Callable, Iterator, Optional, Type, TypeVar, Union
7
7
 
@@ -9,8 +9,8 @@ import psycopg
9
9
  from packaging.version import parse
10
10
  from psycopg import Connection, Cursor
11
11
 
12
+ from pytest_postgresql.loader import build_loader
12
13
  from pytest_postgresql.retry import retry
13
- from pytest_postgresql.sql import loader
14
14
 
15
15
  Version = type(parse("1"))
16
16
 
@@ -23,11 +23,13 @@ class DatabaseJanitor:
23
23
 
24
24
  def __init__(
25
25
  self,
26
+ *,
26
27
  user: str,
27
28
  host: str,
28
29
  port: Union[str, int],
29
- dbname: str,
30
30
  version: Union[str, float, Version], # type: ignore[valid-type]
31
+ dbname: Optional[str] = None,
32
+ template_dbname: Optional[str] = None,
31
33
  password: Optional[str] = None,
32
34
  isolation_level: "Optional[psycopg.IsolationLevel]" = None,
33
35
  connection_timeout: int = 60,
@@ -38,6 +40,7 @@ class DatabaseJanitor:
38
40
  :param host: postgresql host
39
41
  :param port: postgresql port
40
42
  :param dbname: database name
43
+ :param dbname: template database name
41
44
  :param version: postgresql version number
42
45
  :param password: optional postgresql password
43
46
  :param isolation_level: optional postgresql isolation level
@@ -49,7 +52,10 @@ class DatabaseJanitor:
49
52
  self.password = password
50
53
  self.host = host
51
54
  self.port = port
55
+ # At least one of the dbname or template_dbname has to be filled.
56
+ assert any([dbname, template_dbname])
52
57
  self.dbname = dbname
58
+ self.template_dbname = template_dbname
53
59
  self._connection_timeout = connection_timeout
54
60
  self.isolation_level = isolation_level
55
61
  if not isinstance(version, Version):
@@ -59,36 +65,33 @@ class DatabaseJanitor:
59
65
 
60
66
  def init(self) -> None:
61
67
  """Create database in postgresql."""
62
- template_name = f"{self.dbname}_tmpl"
63
68
  with self.cursor() as cur:
64
- if self.dbname.endswith("_tmpl"):
65
- result = False
66
- else:
67
- cur.execute(
68
- "SELECT EXISTS "
69
- "(SELECT datname FROM pg_catalog.pg_database WHERE datname= %s);",
70
- (template_name,),
71
- )
72
- row = cur.fetchone()
73
- result = (row is not None) and row[0]
74
- if not result:
69
+ if self.is_template():
70
+ cur.execute(f'CREATE DATABASE "{self.template_dbname}" WITH is_template = true;')
71
+ elif self.template_dbname is None:
75
72
  cur.execute(f'CREATE DATABASE "{self.dbname}";')
76
73
  else:
77
- # All template database does not allow connection:
78
- self._dont_datallowconn(cur, template_name)
79
74
  # And make sure no-one is left connected to the template database.
80
- # Otherwise Creating database from template will fail
81
- self._terminate_connection(cur, template_name)
82
- cur.execute(f'CREATE DATABASE "{self.dbname}" TEMPLATE "{template_name}";')
75
+ # Otherwise, Creating database from template will fail
76
+ self._terminate_connection(cur, self.template_dbname)
77
+ cur.execute(f'CREATE DATABASE "{self.dbname}" TEMPLATE "{self.template_dbname}";')
78
+
79
+ def is_template(self) -> bool:
80
+ """Determine whether the DatabaseJanitor maintains template or database."""
81
+ return self.dbname is None
83
82
 
84
83
  def drop(self) -> None:
85
84
  """Drop database in postgresql."""
86
85
  # We cannot drop the database while there are connections to it, so we
87
86
  # terminate all connections first while not allowing new connections.
87
+ db_to_drop = self.template_dbname if self.is_template() else self.dbname
88
+ assert db_to_drop
88
89
  with self.cursor() as cur:
89
- self._dont_datallowconn(cur, self.dbname)
90
- self._terminate_connection(cur, self.dbname)
91
- cur.execute(f'DROP DATABASE IF EXISTS "{self.dbname}";')
90
+ self._dont_datallowconn(cur, db_to_drop)
91
+ self._terminate_connection(cur, db_to_drop)
92
+ if self.is_template():
93
+ cur.execute(f'ALTER DATABASE "{db_to_drop}" with is_template false;')
94
+ cur.execute(f'DROP DATABASE IF EXISTS "{db_to_drop}";')
92
95
 
93
96
  @staticmethod
94
97
  def _dont_datallowconn(cur: Cursor, dbname: str) -> None:
@@ -103,28 +106,23 @@ class DatabaseJanitor:
103
106
  (dbname,),
104
107
  )
105
108
 
106
- def load(self, load: Union[Callable, str]) -> None:
109
+ def load(self, load: Union[Callable, str, Path]) -> None:
107
110
  """Load data into a database.
108
111
 
109
- Either runs a passed loader if it's callback,
110
- or runs predefined loader if it's sql file.
112
+ Expects:
113
+
114
+ * a Path to sql file, that'll be loaded
115
+ * an import path to import callable
116
+ * a callable that expects: host, port, user, dbname and password arguments.
117
+
111
118
  """
112
- if isinstance(load, str):
113
- if "/" in load:
114
- _loader: Callable = partial(loader, load)
115
- else:
116
- loader_parts = re.split("[.:]", load, 2)
117
- import_path = ".".join(loader_parts[:-1])
118
- loader_name = loader_parts[-1]
119
- _temp_import = __import__(import_path, globals(), locals(), fromlist=[loader_name])
120
- _loader = getattr(_temp_import, loader_name)
121
- else:
122
- _loader = load
119
+ db_to_load = self.template_dbname if self.is_template() else self.dbname
120
+ _loader = build_loader(load)
123
121
  _loader(
124
122
  host=self.host,
125
123
  port=self.port,
126
124
  user=self.user,
127
- dbname=self.dbname,
125
+ dbname=db_to_load,
128
126
  password=self.password,
129
127
  )
130
128
 
@@ -0,0 +1,32 @@
1
+ """Loader helper functions."""
2
+
3
+ import re
4
+ from functools import partial
5
+ from pathlib import Path
6
+ from typing import Any, Callable, Union
7
+
8
+ import psycopg
9
+
10
+
11
+ def build_loader(load: Union[Callable, str, Path]) -> Callable:
12
+ """Build a loader callable."""
13
+ if isinstance(load, Path):
14
+ return partial(sql, load)
15
+ elif isinstance(load, str):
16
+ loader_parts = re.split("[.:]", load, 2)
17
+ import_path = ".".join(loader_parts[:-1])
18
+ loader_name = loader_parts[-1]
19
+ _temp_import = __import__(import_path, globals(), locals(), fromlist=[loader_name])
20
+ _loader: Callable = getattr(_temp_import, loader_name)
21
+ return _loader
22
+ else:
23
+ return load
24
+
25
+
26
+ def sql(sql_filename: Path, **kwargs: Any) -> None:
27
+ """Database loader for sql files."""
28
+ db_connection = psycopg.connect(**kwargs)
29
+ with open(sql_filename, "r") as _fd:
30
+ with db_connection.cursor() as cur:
31
+ cur.execute(_fd.read())
32
+ db_connection.commit()
@@ -3,7 +3,7 @@
3
3
 
4
4
  # This file is part of pytest-postgresql.
5
5
 
6
- # pytest-dbfixtures is free software: you can redistribute it and/or modify
6
+ # pytest-postgresql is free software: you can redistribute it and/or modify
7
7
  # it under the terms of the GNU Lesser General Public License as published by
8
8
  # the Free Software Foundation, either version 3 of the License, or
9
9
  # (at your option) any later version.
@@ -0,0 +1,48 @@
1
+ """Small retry callable in case of specific error occurred."""
2
+
3
+ import datetime
4
+ import sys
5
+ from time import sleep
6
+ from typing import Callable, Type, TypeVar
7
+
8
+ T = TypeVar("T")
9
+
10
+
11
+ def retry(
12
+ func: Callable[[], T],
13
+ timeout: int = 60,
14
+ possible_exception: Type[Exception] = Exception,
15
+ ) -> T:
16
+ """Attempt to retry the function for timeout time.
17
+
18
+ Most often used for connecting to postgresql database as,
19
+ especially on macos on github-actions, first few tries fails
20
+ with this message:
21
+
22
+ ... ::
23
+ FATAL: the database system is starting up
24
+ """
25
+ time: datetime.datetime = get_current_datetime()
26
+ timeout_diff: datetime.timedelta = datetime.timedelta(seconds=timeout)
27
+ i = 0
28
+ while True:
29
+ i += 1
30
+ try:
31
+ res = func()
32
+ return res
33
+ except possible_exception as e:
34
+ if time + timeout_diff < get_current_datetime():
35
+ raise TimeoutError(f"Failed after {i} attempts") from e
36
+ sleep(1)
37
+
38
+
39
+ def get_current_datetime() -> datetime.datetime:
40
+ """Get the current datetime."""
41
+ # To ensure the current datetime retrieval is adjusted with the latest
42
+ # versions of Python while ensuring retro-compatibility with
43
+ # Python 3.8, 3.9 and 3.10, we check what version of Python is
44
+ # being used before deciding how to operate
45
+ if sys.version_info.major == 3 and sys.version_info.minor > 10:
46
+ return datetime.datetime.now(datetime.UTC)
47
+
48
+ return datetime.datetime.utcnow()
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytest-postgresql
3
- Version: 5.1.1
3
+ Version: 6.0.1
4
4
  Summary: Postgresql fixtures and fixture factories for Pytest.
5
5
  Author-email: Grzegorz Śliwiński <fizyk+pypi@fizyk.dev>
6
6
  Project-URL: Source, https://github.com/ClearcodeHQ/pytest-postgresql
7
7
  Project-URL: Bug Tracker, https://github.com/ClearcodeHQ/pytest-postgresql/issues
8
- Project-URL: Changelog, https://github.com/ClearcodeHQ/pytest-postgresql/blob/v5.1.1/CHANGES.rst
8
+ Project-URL: Changelog, https://github.com/ClearcodeHQ/pytest-postgresql/blob/v6.0.1/CHANGES.rst
9
9
  Keywords: tests,pytest,fixture,postgresql
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Environment :: Web Environment
@@ -141,9 +141,10 @@ Client specific loads the database each test
141
141
 
142
142
  .. code-block:: python
143
143
 
144
+ from pathlib import Path
144
145
  postgresql_my_with_schema = factories.postgresql(
145
146
  'postgresql_my_proc',
146
- load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
147
+ load=[Path("schemafile.sql"), Path("otherschema.sql"), "import.path.to.function", "import.path.to:otherfunction", load_this]
147
148
  )
148
149
 
149
150
  .. warning::
@@ -152,12 +153,13 @@ Client specific loads the database each test
152
153
 
153
154
 
154
155
  The process fixture performs the load once per test session, and loads the data into the template database.
155
- Client fixture then creates test database out of the template database each test, which significantly speeds up the tests.
156
+ Client fixture then creates test database out of the template database each test, which significantly **speeds up the tests**.
156
157
 
157
158
  .. code-block:: python
158
159
 
160
+ from pathlib import Path
159
161
  postgresql_my_proc = factories.postgresql_proc(
160
- load=["schemafile.sql", "otherschema.sql", "import.path.to.function", "import.path.to:otherfunction", load_this]
162
+ load=[Path("schemafile.sql"), Path("otherschema.sql"), "import.path.to.function", "import.path.to:otherfunction", load_this]
161
163
  )
162
164
 
163
165
 
@@ -511,7 +513,7 @@ it'll be on a docker machine or running remotely or locally.
511
513
  Using SQLAlchemy to initialise basic database state
512
514
  +++++++++++++++++++++++++++++++++++++++++++++++++++
513
515
 
514
- How to use SQLAlchemy for common initalisation:
516
+ How to use SQLAlchemy for common initialisation:
515
517
 
516
518
  .. code-block:: python
517
519
 
@@ -12,10 +12,10 @@ pytest_postgresql/exceptions.py
12
12
  pytest_postgresql/executor.py
13
13
  pytest_postgresql/executor_noop.py
14
14
  pytest_postgresql/janitor.py
15
+ pytest_postgresql/loader.py
15
16
  pytest_postgresql/plugin.py
16
17
  pytest_postgresql/py.typed
17
18
  pytest_postgresql/retry.py
18
- pytest_postgresql/sql.py
19
19
  pytest_postgresql.egg-info/PKG-INFO
20
20
  pytest_postgresql.egg-info/SOURCES.txt
21
21
  pytest_postgresql.egg-info/dependency_links.txt
@@ -29,6 +29,7 @@ pytest_postgresql/factories/noprocess.py
29
29
  pytest_postgresql/factories/process.py
30
30
  tests/test_executor.py
31
31
  tests/test_janitor.py
32
+ tests/test_loader.py
32
33
  tests/test_noopexecutor.py
33
34
  tests/test_postgres_options_plugin.py
34
35
  tests/test_postgresql.py
@@ -1,4 +1,5 @@
1
1
  """Test various executor behaviours."""
2
+
2
3
  import sys
3
4
  from typing import Any
4
5
 
@@ -1,4 +1,5 @@
1
1
  """Database Janitor tests."""
2
+
2
3
  import sys
3
4
  from typing import Any
4
5
  from unittest.mock import MagicMock, patch
@@ -14,14 +15,18 @@ VERSION = parse("10")
14
15
  @pytest.mark.parametrize("version", (VERSION, 10, "10"))
15
16
  def test_version_cast(version: Any) -> None:
16
17
  """Test that version is cast to Version object."""
17
- janitor = DatabaseJanitor("user", "host", "1234", "database_name", version)
18
+ janitor = DatabaseJanitor(
19
+ user="user", host="host", port="1234", dbname="database_name", version=version
20
+ )
18
21
  assert janitor.version == VERSION
19
22
 
20
23
 
21
24
  @patch("pytest_postgresql.janitor.psycopg.connect")
22
25
  def test_cursor_selects_postgres_database(connect_mock: MagicMock) -> None:
23
26
  """Test that the cursor requests the postgres database."""
24
- janitor = DatabaseJanitor("user", "host", "1234", "database_name", 10)
27
+ janitor = DatabaseJanitor(
28
+ user="user", host="host", port="1234", dbname="database_name", version=10
29
+ )
25
30
  with janitor.cursor():
26
31
  connect_mock.assert_called_once_with(
27
32
  dbname="postgres", user="user", password=None, host="host", port="1234"
@@ -31,7 +36,14 @@ def test_cursor_selects_postgres_database(connect_mock: MagicMock) -> None:
31
36
  @patch("pytest_postgresql.janitor.psycopg.connect")
32
37
  def test_cursor_connects_with_password(connect_mock: MagicMock) -> None:
33
38
  """Test that the cursor requests the postgres database."""
34
- janitor = DatabaseJanitor("user", "host", "1234", "database_name", 10, "some_password")
39
+ janitor = DatabaseJanitor(
40
+ user="user",
41
+ host="host",
42
+ port="1234",
43
+ dbname="database_name",
44
+ version=10,
45
+ password="some_password",
46
+ )
35
47
  with janitor.cursor():
36
48
  connect_mock.assert_called_once_with(
37
49
  dbname="postgres", user="user", password="some_password", host="host", port="1234"
@@ -0,0 +1,20 @@
1
+ """Tests for the `build_loader` function."""
2
+
3
+ from pathlib import Path
4
+
5
+ from pytest_postgresql.loader import build_loader, sql
6
+ from tests.loader import load_database
7
+
8
+
9
+ def test_loader_callables() -> None:
10
+ """Test handling callables in build_loader."""
11
+ assert load_database == build_loader(load_database)
12
+ assert load_database == build_loader("tests.loader:load_database")
13
+
14
+
15
+ def test_loader_sql() -> None:
16
+ """Test returning partial running sql for the sql file path."""
17
+ sql_path = Path("test_sql/eidastats.sql")
18
+ loader_func = build_loader(sql_path)
19
+ assert loader_func.args == (sql_path,) # type: ignore
20
+ assert loader_func.func == sql # type: ignore
@@ -1,4 +1,5 @@
1
1
  """Test for NoopExecutor."""
2
+
2
3
  import psycopg
3
4
 
4
5
  from pytest_postgresql.executor import PostgreSQLExecutor
@@ -1,4 +1,5 @@
1
1
  """Test behavior of postgres_options passed in different ways."""
2
+
2
3
  from pathlib import Path
3
4
 
4
5
  import pytest
@@ -32,3 +33,11 @@ def test_postgres_options_config_in_ini(pointed_pytester: Pytester) -> None:
32
33
  pointed_pytester.makefile(".ini", pytest="[pytest]\npostgresql_postgres_options = -N 16\n")
33
34
  ret = pointed_pytester.runpytest("test_postgres_options.py")
34
35
  ret.assert_outcomes(passed=1)
36
+
37
+
38
+ def test_postgres_loader_in_cli(pointed_pytester: Pytester) -> None:
39
+ """Check that command line arguments are honored."""
40
+ pointed_pytester.copy_example("test_load.py")
41
+ test_sql_path = pointed_pytester.copy_example("test.sql")
42
+ ret = pointed_pytester.runpytest(f"--postgresql-load={test_sql_path}", "test_load.py")
43
+ ret.assert_outcomes(passed=1)
@@ -1,4 +1,5 @@
1
1
  """All tests for pytest-postgresql."""
2
+
2
3
  import decimal
3
4
 
4
5
  import pytest
@@ -1,4 +1,5 @@
1
1
  """Template database tests."""
2
+
2
3
  import pytest
3
4
  from psycopg import Connection
4
5
 
@@ -1,4 +1,5 @@
1
1
  """Auxiliary tests."""
2
+
2
3
  import pytest
3
4
 
4
5
  from pytest_postgresql.executor import PostgreSQLExecutor
@@ -1,33 +0,0 @@
1
- """Small retry callable in case of specific error occurred."""
2
-
3
- from datetime import datetime, timedelta
4
- from time import sleep
5
- from typing import Callable, Type, TypeVar
6
-
7
- T = TypeVar("T")
8
-
9
-
10
- def retry(
11
- func: Callable[[], T], timeout: int = 60, possible_exception: Type[Exception] = Exception
12
- ) -> T:
13
- """Attempt to retry the function for timeout time.
14
-
15
- Most often used for connecting to postgresql database as,
16
- especially on macos on github-actions, first few tries fails
17
- with this message:
18
-
19
- ... ::
20
- FATAL: the database system is starting up
21
- """
22
- time: datetime = datetime.utcnow()
23
- timeout_diff: timedelta = timedelta(seconds=timeout)
24
- i = 0
25
- while True:
26
- i += 1
27
- try:
28
- res = func()
29
- return res
30
- except possible_exception as e:
31
- if time + timeout_diff < datetime.utcnow():
32
- raise TimeoutError(f"Failed after {i} attempts") from e
33
- sleep(1)
@@ -1,13 +0,0 @@
1
- """SQL Loader function."""
2
- from typing import Any
3
-
4
- import psycopg
5
-
6
-
7
- def loader(sql_filename: str, **kwargs: Any) -> None:
8
- """Database loader for sql files."""
9
- db_connection = psycopg.connect(**kwargs)
10
- with open(sql_filename, "r") as _fd:
11
- with db_connection.cursor() as cur:
12
- cur.execute(_fd.read())
13
- db_connection.commit()