patera-migrate 0.2.0__py3-none-any.whl

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.
@@ -0,0 +1,3 @@
1
+ from .migrate import Migrate
2
+
3
+ __all__ = ["Migrate"]
@@ -0,0 +1,178 @@
1
+ """
2
+ Pyway implementation for Patera
3
+ """
4
+
5
+ import os
6
+ from urllib.parse import urlparse
7
+ from typing import Dict, Optional, cast
8
+ from patera import Patera
9
+ from patera.cli import CLIController, command
10
+ from patera.database.sql import SqlDatabase
11
+
12
+ from pathlib import Path
13
+ from pydantic import BaseModel, Field, ConfigDict
14
+
15
+ from pyway.configfile import ConfigFile as PywayConfigFile
16
+ from pyway.info import Info as PywayInfo
17
+ from pyway.migrate import Migrate as PywayMigrate
18
+ from pyway.validate import Validate as PywayValidate
19
+ from pyway.checksum import Checksum as PywayChecksum
20
+
21
+
22
+ class _PateraPywayConfigs(BaseModel):
23
+ model_config = ConfigDict(extra="allow")
24
+
25
+ MIGRATE_CLI_NAME: Optional[str] = Field(
26
+ "migrate", description="Name of the cli command prefix"
27
+ )
28
+ MIGRATE_DATABASE_MIGRATION_DIR: Optional[str] = Field("migrations", description="")
29
+ MIGRATE_SQL_MIGRATION_PREFIX: Optional[str] = Field("V", description="")
30
+ MIGRATE_SQL_MIGRATION_SEPARATOR: Optional[str] = Field("__", description="")
31
+ MIGRATE_SQL_MIGRATION_SUFFIXES: Optional[str] = Field(".sql", description="")
32
+ MIGRATE_TABLE: Optional[str] = Field("pyway_migrations", description="")
33
+ MIGRATE_CONFIG_FILE: Optional[str] = Field(".pyway.conf", description="")
34
+
35
+
36
+ class PywayCLIController(CLIController):
37
+ def __init__(self, app: Patera, extension: "Migrate"):
38
+ super().__init__(app)
39
+ self._ext = extension
40
+
41
+ def _get_configs_from_file(self) -> PywayConfigFile:
42
+ configs = {}
43
+ os.environ["PYWAY_DATABASE_MIGRATION_DIR"] = str(self._ext._migrations_path)
44
+ os.environ["PYWAY_CONFIG_FILE"] = str(self._ext._configs_path)
45
+ with open(str(self._ext._configs_path)) as config_file:
46
+ for line in config_file.readlines():
47
+ config, value = line.split(": ")
48
+ configs[config.strip()] = value.strip()
49
+ pyway_configs = PywayConfigFile(**configs)
50
+ return pyway_configs
51
+
52
+ def _clear_env_vars(self) -> None:
53
+ os.environ.pop("PYWAY_DATABASE_MIGRATION_DIR", None)
54
+ os.environ.pop("PYWAY_CONFIG_FILE", None)
55
+
56
+ @command("init", help="Initilizes Patera migration extension for database")
57
+ def init(self) -> None:
58
+ """Initilizes pyway configs"""
59
+ self._ext.create_pyway_config()
60
+
61
+ @command("info", help="Provides information about current migrations and db status")
62
+ def info(self) -> None:
63
+ pyway_configs = self._get_configs_from_file()
64
+ try:
65
+ pyway_info = PywayInfo(pyway_configs)
66
+ print(pyway_info.run())
67
+ finally:
68
+ self._clear_env_vars()
69
+
70
+ @command(
71
+ "validate",
72
+ help="Validate helps you verify that the migrations applied to the database match the ones available locally.",
73
+ )
74
+ def validate(self) -> None:
75
+ pyway_configs = self._get_configs_from_file()
76
+ try:
77
+ pyway_validate = PywayValidate(pyway_configs)
78
+ print(pyway_validate.run())
79
+ finally:
80
+ self._clear_env_vars()
81
+
82
+ @command("migrate", help="Perform database migration")
83
+ def migrate(self) -> None:
84
+ pyway_configs = self._get_configs_from_file()
85
+ try:
86
+ pyway_migrate = PywayMigrate(pyway_configs)
87
+ print(pyway_migrate.run())
88
+ finally:
89
+ self._clear_env_vars()
90
+
91
+ @command(
92
+ "checksum",
93
+ help="Updates a checksum in the database. This is for advanced use only, as it could put the pyway database out of sync with reality. ",
94
+ )
95
+ def checksum(self, checksum_file: str) -> None:
96
+ pyway_configs = self._get_configs_from_file()
97
+ pyway_configs.checksum_file = checksum_file # type: ignore
98
+ try:
99
+ pyway_checksum = PywayChecksum(pyway_configs)
100
+ print(pyway_checksum.run())
101
+ finally:
102
+ self._clear_env_vars()
103
+
104
+
105
+ class Migrate:
106
+ __db_name__: str
107
+
108
+ def __init__(self, app: Patera, db: SqlDatabase):
109
+ self._app = app
110
+ self._db = db
111
+ self.__db_name__ = db.__db_name__
112
+ self._configs = self._app.get_conf(self.configs_name, {})
113
+ self._configs = self._db.validate_configs(self._configs, _PateraPywayConfigs)
114
+ self._cli_controller = PywayCLIController(self._app, self)
115
+ self._cli_controller.set_ctrl_name(
116
+ cast(str, self._configs.get("MIGRATE_CLI_NAME"))
117
+ )
118
+ self._app.register_cli_controller(self._cli_controller)
119
+ self._migrations_path: Path = Path(self._app.root_path) / cast(
120
+ str, self._configs.get("MIGRATE_DATABASE_MIGRATION_DIR")
121
+ )
122
+ self._migrations_path.mkdir(exist_ok=True)
123
+ self._configs_path: Path = self._migrations_path / cast(
124
+ str, self._configs.get("MIGRATE_CONFIG_FILE")
125
+ )
126
+ # configs need to be initilized manually
127
+ # self.create_pyway_config()
128
+
129
+ def create_pyway_config(self) -> None:
130
+ if self._configs_path.exists():
131
+ return
132
+
133
+ db = self.parse_database_uri(self.database_uri)
134
+
135
+ lines = [
136
+ f"database_migration_dir: {self._configs.get('MIGRATE_DATABASE_MIGRATION_DIR')}",
137
+ f"database_table: {self._configs.get('MIGRATE_TABLE')}",
138
+ f"database_type: {db.get('type')}",
139
+ f"database_username: {db.get('username')}",
140
+ f"database_password: {db.get('password')}",
141
+ f"database_host: {db.get('host')}",
142
+ f"database_port: {db.get('port')}",
143
+ f"database_name: {db.get('database')}",
144
+ ]
145
+
146
+ filtered = [line for line in lines if not line.endswith(": None")]
147
+ self._configs_path.write_text("\n".join(filtered) + "\n")
148
+
149
+ def parse_database_uri(self, uri: str) -> Dict[str, Optional[str]]:
150
+ parsed = urlparse(uri)
151
+ db_type = parsed.scheme.split("+")[0]
152
+
153
+ if db_type == "sqlite":
154
+ return {
155
+ "type": "sqlite",
156
+ "username": None,
157
+ "password": None,
158
+ "host": None,
159
+ "port": None,
160
+ "database": parsed.path.lstrip("/"),
161
+ }
162
+
163
+ return {
164
+ "type": db_type,
165
+ "username": parsed.username,
166
+ "password": parsed.password,
167
+ "host": parsed.hostname,
168
+ "port": str(parsed.port) if parsed.port else None,
169
+ "database": parsed.path.lstrip("/") if parsed.path else None,
170
+ }
171
+
172
+ @property
173
+ def database_uri(self) -> str:
174
+ return self._db.db_uri
175
+
176
+ @property
177
+ def configs_name(self) -> str:
178
+ return self.__class__.__name__
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.3
2
+ Name: patera-migrate
3
+ Version: 0.2.0
4
+ Requires-Dist: patera
5
+ Requires-Dist: patera-database
6
+ Requires-Dist: pyway>=0.3.32
7
+ Requires-Python: >=3.13
@@ -0,0 +1,5 @@
1
+ patera/migrate/__init__.py,sha256=OYQG1pQmc0mepysteGF3z-0kk-Jhjj5-6fsR8GjGxjw,55
2
+ patera/migrate/migrate.py,sha256=ZnYN8MJI_hrEXevpFKWWqVGBrT3NjLOhorKQDjiNnlA,6749
3
+ patera_migrate-0.2.0.dist-info/WHEEL,sha256=mydTeHxOpFHo-DnYhAd_3ATePms-g4rrYvM7wJK8P-U,80
4
+ patera_migrate-0.2.0.dist-info/METADATA,sha256=6pBg0uExytOpWjKs2Qsw25FbZvngWJwvbLCSM_3gb2o,164
5
+ patera_migrate-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.10.9
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any