pum 1.3.0__tar.gz → 1.3.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.
- {pum-1.3.0 → pum-1.3.1}/PKG-INFO +1 -1
- {pum-1.3.0 → pum-1.3.1}/pum/schema_migrations.py +19 -23
- {pum-1.3.0 → pum-1.3.1}/pum.egg-info/PKG-INFO +1 -1
- {pum-1.3.0 → pum-1.3.1}/pum.egg-info/SOURCES.txt +0 -1
- pum-1.3.0/test/test_transaction_fix.py +0 -100
- {pum-1.3.0 → pum-1.3.1}/LICENSE +0 -0
- {pum-1.3.0 → pum-1.3.1}/README.md +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/__init__.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/changelog.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/checker.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/cli.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/config_model.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/connection.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/dependency_handler.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/dumper.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/exceptions.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/feedback.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/hook.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/info.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/parameter.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/pum_config.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/report_generator.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/role_manager.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/sql_content.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum/upgrader.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum.egg-info/dependency_links.txt +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum.egg-info/entry_points.txt +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum.egg-info/requires.txt +0 -0
- {pum-1.3.0 → pum-1.3.1}/pum.egg-info/top_level.txt +0 -0
- {pum-1.3.0 → pum-1.3.1}/pyproject.toml +0 -0
- {pum-1.3.0 → pum-1.3.1}/requirements/base.txt +0 -0
- {pum-1.3.0 → pum-1.3.1}/requirements/development.txt +0 -0
- {pum-1.3.0 → pum-1.3.1}/requirements/html.txt +0 -0
- {pum-1.3.0 → pum-1.3.1}/setup.cfg +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_changelog.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_checker.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_config.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_dumper.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_feedback.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_hooks.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_roles.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_schema_migrations.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_sql_content.py +0 -0
- {pum-1.3.0 → pum-1.3.1}/test/test_upgrader.py +0 -0
{pum-1.3.0 → pum-1.3.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pum
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: Pum stands for "Postgres Upgrades Manager". It is a Database migration management tool very similar to flyway-db or Liquibase, based on metadata tables.
|
|
5
5
|
Author-email: Denis Rouzaud <denis@opengis.ch>
|
|
6
6
|
License-Expression: GPL-2.0-or-later
|
|
@@ -74,10 +74,9 @@ class SchemaMigrations:
|
|
|
74
74
|
"schema": psycopg.sql.Literal(self.config.config.pum.migration_table_schema),
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return result[0] if result else False
|
|
77
|
+
cursor = SqlContent(query).execute(connection, parameters=parameters)
|
|
78
|
+
result = cursor._pum_results[0] if cursor._pum_results else None
|
|
79
|
+
return result[0] if result else False
|
|
81
80
|
|
|
82
81
|
def exists_in_other_schemas(self, connection: psycopg.Connection) -> list[str]:
|
|
83
82
|
"""Check if the schema_migrations information table exists in other schemas.
|
|
@@ -100,9 +99,8 @@ class SchemaMigrations:
|
|
|
100
99
|
parameters = {
|
|
101
100
|
"schema": psycopg.sql.Literal(self.config.config.pum.migration_table_schema),
|
|
102
101
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return [row[0] for row in (cursor._pum_results or [])]
|
|
102
|
+
cursor = SqlContent(query).execute(connection, parameters=parameters)
|
|
103
|
+
return [row[0] for row in (cursor._pum_results or [])]
|
|
106
104
|
|
|
107
105
|
def create(
|
|
108
106
|
self,
|
|
@@ -346,14 +344,13 @@ INSERT INTO {table} (
|
|
|
346
344
|
"table": self.migration_table_identifier,
|
|
347
345
|
}
|
|
348
346
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
return packaging.version.parse(row[0])
|
|
347
|
+
cursor = SqlContent(query).execute(connection, parameters=parameters)
|
|
348
|
+
row = cursor._pum_results[0] if cursor._pum_results else None
|
|
349
|
+
if row is None:
|
|
350
|
+
raise PumSchemaMigrationNoBaselineError(
|
|
351
|
+
f"Baseline version not found in the {self.migration_table_identifier_str} table."
|
|
352
|
+
)
|
|
353
|
+
return packaging.version.parse(row[0])
|
|
357
354
|
|
|
358
355
|
def migration_details(self, connection: psycopg.Connection, version: str | None = None) -> dict:
|
|
359
356
|
"""Return the migration details from the migration table.
|
|
@@ -404,14 +401,13 @@ INSERT INTO {table} (
|
|
|
404
401
|
"version": psycopg.sql.Literal(version),
|
|
405
402
|
}
|
|
406
403
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
return dict(zip([desc[0] for desc in cursor._pum_description], row, strict=False))
|
|
404
|
+
cursor = SqlContent(query).execute(connection, parameters=parameters)
|
|
405
|
+
row = cursor._pum_results[0] if cursor._pum_results else None
|
|
406
|
+
if row is None:
|
|
407
|
+
raise PumSchemaMigrationError(
|
|
408
|
+
f"Migration details not found for version {version} in the {self.migration_table_identifier_str} table."
|
|
409
|
+
)
|
|
410
|
+
return dict(zip([desc[0] for desc in cursor._pum_description], row, strict=False))
|
|
415
411
|
|
|
416
412
|
def compare(self, connection: psycopg.Connection) -> int:
|
|
417
413
|
"""Compare the migrations details in the database to the changelogs in the source.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pum
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: Pum stands for "Postgres Upgrades Manager". It is a Database migration management tool very similar to flyway-db or Liquibase, based on metadata tables.
|
|
5
5
|
Author-email: Denis Rouzaud <denis@opengis.ch>
|
|
6
6
|
License-Expression: GPL-2.0-or-later
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
import psycopg
|
|
5
|
-
|
|
6
|
-
from pum.pum_config import PumConfig
|
|
7
|
-
from pum.schema_migrations import SchemaMigrations
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class TestTransactionFix(unittest.TestCase):
|
|
11
|
-
"""Test that verifies the transaction fix prevents 'idle in transaction' state."""
|
|
12
|
-
|
|
13
|
-
def setUp(self) -> None:
|
|
14
|
-
"""Set up the test environment."""
|
|
15
|
-
self.pg_service = "pum_test"
|
|
16
|
-
|
|
17
|
-
def test_schema_migrations_exists_transaction_state(self) -> None:
|
|
18
|
-
"""Test that schema_migrations.exists() doesn't leave connection in 'idle in transaction'."""
|
|
19
|
-
test_dir = Path("test") / "data" / "single_changelog"
|
|
20
|
-
cfg = PumConfig(test_dir, pum={"module": "test_single_changelog"})
|
|
21
|
-
sm = SchemaMigrations(cfg)
|
|
22
|
-
|
|
23
|
-
with psycopg.connect(f"service={self.pg_service}") as conn:
|
|
24
|
-
# Clean up any existing table
|
|
25
|
-
with conn.transaction():
|
|
26
|
-
conn.execute("DROP TABLE IF EXISTS public.pum_migrations")
|
|
27
|
-
|
|
28
|
-
# Initial state should be IDLE
|
|
29
|
-
self.assertEqual(conn.info.transaction_status.name, "IDLE")
|
|
30
|
-
|
|
31
|
-
# Call exists() which executes a query
|
|
32
|
-
sm.exists(conn)
|
|
33
|
-
|
|
34
|
-
# After the call, connection should still be IDLE (not "IDLE_IN_TRANSACTION")
|
|
35
|
-
# This will FAIL if the transaction block is not used in exists()
|
|
36
|
-
transaction_status = conn.info.transaction_status.name
|
|
37
|
-
self.assertEqual(
|
|
38
|
-
transaction_status,
|
|
39
|
-
"IDLE",
|
|
40
|
-
f"Connection in '{transaction_status}' state after exists() - should use transaction block",
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
def test_schema_migrations_baseline_transaction_state(self) -> None:
|
|
44
|
-
"""Test that schema_migrations.baseline() doesn't leave connection in 'idle in transaction'."""
|
|
45
|
-
test_dir = Path("test") / "data" / "single_changelog"
|
|
46
|
-
cfg = PumConfig(test_dir, pum={"module": "test_single_changelog"})
|
|
47
|
-
sm = SchemaMigrations(cfg)
|
|
48
|
-
|
|
49
|
-
with psycopg.connect(f"service={self.pg_service}") as conn:
|
|
50
|
-
# Create the migrations table with some data
|
|
51
|
-
with conn.transaction():
|
|
52
|
-
sm.create(conn)
|
|
53
|
-
sm.set_baseline(conn, "1.0.0", commit=False)
|
|
54
|
-
|
|
55
|
-
# Initial state should be IDLE
|
|
56
|
-
self.assertEqual(conn.info.transaction_status.name, "IDLE")
|
|
57
|
-
|
|
58
|
-
# Call baseline() which executes a query
|
|
59
|
-
sm.baseline(conn)
|
|
60
|
-
|
|
61
|
-
# After the call, connection should still be IDLE
|
|
62
|
-
transaction_status = conn.info.transaction_status.name
|
|
63
|
-
self.assertEqual(
|
|
64
|
-
transaction_status,
|
|
65
|
-
"IDLE",
|
|
66
|
-
f"Connection in '{transaction_status}' state after baseline() - should use transaction block",
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
# Clean up
|
|
70
|
-
with conn.transaction():
|
|
71
|
-
conn.execute("DROP TABLE IF EXISTS public.pum_migrations")
|
|
72
|
-
|
|
73
|
-
def test_multiple_queries_without_transaction_causes_idle_in_transaction(self) -> None:
|
|
74
|
-
"""Test that demonstrates the problem: queries without transaction blocks cause 'idle in transaction'."""
|
|
75
|
-
with psycopg.connect(f"service={self.pg_service}") as conn:
|
|
76
|
-
# Start with IDLE state
|
|
77
|
-
self.assertEqual(conn.info.transaction_status.name, "IDLE")
|
|
78
|
-
|
|
79
|
-
# Execute a query WITHOUT using a transaction block
|
|
80
|
-
# This simulates the old buggy behavior
|
|
81
|
-
cursor = conn.cursor()
|
|
82
|
-
cursor.execute("SELECT 1")
|
|
83
|
-
cursor.fetchone()
|
|
84
|
-
cursor.close()
|
|
85
|
-
|
|
86
|
-
# Now the connection is stuck in INTRANS (idle in transaction)
|
|
87
|
-
transaction_status = conn.info.transaction_status.name
|
|
88
|
-
self.assertEqual(
|
|
89
|
-
transaction_status,
|
|
90
|
-
"INTRANS",
|
|
91
|
-
"Without transaction blocks, connection gets stuck in INTRANS (idle in transaction)",
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
# Need to explicitly commit to get back to IDLE
|
|
95
|
-
conn.commit()
|
|
96
|
-
self.assertEqual(conn.info.transaction_status.name, "IDLE")
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if __name__ == "__main__":
|
|
100
|
-
unittest.main()
|
{pum-1.3.0 → pum-1.3.1}/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|