half-orm-dev 0.17.3a6__tar.gz → 0.17.3a7__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 (66) hide show
  1. {half_orm_dev-0.17.3a6/half_orm_dev.egg-info → half_orm_dev-0.17.3a7}/PKG-INFO +1 -1
  2. half_orm_dev-0.17.3a7/half_orm_dev/scripts/repair-metadata.py +352 -0
  3. half_orm_dev-0.17.3a7/half_orm_dev/version.txt +1 -0
  4. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7/half_orm_dev.egg-info}/PKG-INFO +1 -1
  5. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev.egg-info/SOURCES.txt +1 -0
  6. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/pyproject.toml +1 -0
  7. half_orm_dev-0.17.3a6/half_orm_dev/version.txt +0 -1
  8. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/AUTHORS +0 -0
  9. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/LICENSE +0 -0
  10. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/README.md +0 -0
  11. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/__init__.py +0 -0
  12. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/__init__.py +0 -0
  13. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/__init__.py +0 -0
  14. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/apply.py +0 -0
  15. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/check.py +0 -0
  16. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/clone.py +0 -0
  17. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/init.py +0 -0
  18. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/migrate.py +0 -0
  19. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/patch.py +0 -0
  20. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/release.py +0 -0
  21. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/restore.py +0 -0
  22. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/sync.py +0 -0
  23. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/todo.py +0 -0
  24. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/undo.py +0 -0
  25. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/update.py +0 -0
  26. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/commands/upgrade.py +0 -0
  27. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli/main.py +0 -0
  28. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/cli_extension.py +0 -0
  29. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/database.py +0 -0
  30. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/decorators.py +0 -0
  31. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/hgit.py +0 -0
  32. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/migration_manager.py +0 -0
  33. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
  34. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
  35. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/modules.py +0 -0
  36. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/patch_manager.py +0 -0
  37. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/patch_validator.py +0 -0
  38. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
  39. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
  40. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
  41. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/patches/log +0 -0
  42. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
  43. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/release_file.py +0 -0
  44. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/release_manager.py +0 -0
  45. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/repo.py +0 -0
  46. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/.gitignore +0 -0
  47. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/MANIFEST.in +0 -0
  48. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/Pipfile +0 -0
  49. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/README +0 -0
  50. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/conftest_template +0 -0
  51. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/git-hooks/pre-commit +0 -0
  52. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
  53. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/init_module_template +0 -0
  54. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/module_template_1 +0 -0
  55. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/module_template_2 +0 -0
  56. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/module_template_3 +0 -0
  57. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/pyproject.toml +0 -0
  58. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/relation_test +0 -0
  59. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/sql_adapter +0 -0
  60. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/templates/warning +0 -0
  61. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev/utils.py +0 -0
  62. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev.egg-info/dependency_links.txt +0 -0
  63. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev.egg-info/requires.txt +0 -0
  64. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/half_orm_dev.egg-info/top_level.txt +0 -0
  65. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/setup.cfg +0 -0
  66. {half_orm_dev-0.17.3a6 → half_orm_dev-0.17.3a7}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: half_orm_dev
3
- Version: 0.17.3a6
3
+ Version: 0.17.3a7
4
4
  Summary: half_orm development Framework.
5
5
  Author-email: Joël Maïzi <joel.maizi@collorg.org>
6
6
  License-Expression: GPL-3.0-or-later
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Repair script for half-orm-dev metadata files.
4
+
5
+ This script regenerates all metadata-X.Y.Z.sql files with correct hop_release
6
+ entries by:
7
+ 1. Clearing half_orm_meta.hop_release (keeping only 0.0.0)
8
+ 2. For each version tag (vX.Y.Z or vX.Y.Z-rcN):
9
+ - Insert the version with the tag's date
10
+ - Generate metadata-X.Y.Z.sql (or metadata-X.Y.Z-rcN.sql)
11
+
12
+ Usage:
13
+ cd /path/to/your/project
14
+ python /path/to/half-orm-dev/scripts/repair-metadata.py [--dry-run]
15
+
16
+ Options:
17
+ --dry-run Show what would be done without modifying anything
18
+ --verbose Show detailed information
19
+ """
20
+
21
+ import argparse
22
+ import re
23
+ import subprocess
24
+ import sys
25
+ from datetime import datetime
26
+ from pathlib import Path
27
+ from typing import List, Tuple, Optional
28
+
29
+
30
+ def get_version_tags() -> List[Tuple[str, str, datetime]]:
31
+ """
32
+ Get all version tags with their dates from git.
33
+
34
+ Returns:
35
+ List of (tag_name, version_string, date) tuples sorted by version.
36
+ tag_name: e.g., "v0.1.0", "v0.1.0-rc1"
37
+ version_string: e.g., "0.1.0", "0.1.0-rc1"
38
+ date: datetime object
39
+ """
40
+ result = subprocess.run(
41
+ ['git', 'tag', '--format=%(refname:short) %(creatordate:iso)'],
42
+ capture_output=True, text=True, check=True
43
+ )
44
+
45
+ tags = []
46
+ for line in result.stdout.strip().split('\n'):
47
+ if not line.strip():
48
+ continue
49
+
50
+ parts = line.split(' ', 1)
51
+ if len(parts) != 2:
52
+ continue
53
+
54
+ tag_name, date_str = parts
55
+
56
+ # Match vX.Y.Z or vX.Y.Z-rcN
57
+ match = re.match(r'^v(\d+\.\d+\.\d+(?:-rc\d+)?)$', tag_name)
58
+ if not match:
59
+ continue
60
+
61
+ version_str = match.group(1)
62
+
63
+ # Parse date (format: "2025-11-21 15:09:14 +0100")
64
+ try:
65
+ # Remove timezone for simpler parsing
66
+ date_part = ' '.join(date_str.split()[:2])
67
+ date = datetime.strptime(date_part, '%Y-%m-%d %H:%M:%S')
68
+ except ValueError:
69
+ continue
70
+
71
+ tags.append((tag_name, version_str, date))
72
+
73
+ # Sort by version (handle X.Y.Z and X.Y.Z-rcN)
74
+ def version_key(item):
75
+ version_str = item[1]
76
+ # Split base version and rc part
77
+ if '-rc' in version_str:
78
+ base, rc = version_str.split('-rc')
79
+ rc_num = int(rc)
80
+ else:
81
+ base = version_str
82
+ rc_num = 9999 # Production comes after all RCs
83
+
84
+ parts = [int(p) for p in base.split('.')]
85
+ return (*parts, rc_num)
86
+
87
+ return sorted(tags, key=version_key)
88
+
89
+
90
+ def parse_version_string(version_str: str) -> Tuple[int, int, int, str, str]:
91
+ """
92
+ Parse version string into components.
93
+
94
+ Args:
95
+ version_str: e.g., "0.1.0" or "0.1.0-rc1"
96
+
97
+ Returns:
98
+ Tuple of (major, minor, patch, pre_release, pre_release_num)
99
+ """
100
+ if '-rc' in version_str:
101
+ base, rc = version_str.split('-rc')
102
+ pre_release = 'rc'
103
+ pre_release_num = rc
104
+ else:
105
+ base = version_str
106
+ pre_release = ''
107
+ pre_release_num = ''
108
+
109
+ parts = base.split('.')
110
+ return (int(parts[0]), int(parts[1]), int(parts[2]), pre_release, pre_release_num)
111
+
112
+
113
+ def find_model_dir() -> Optional[Path]:
114
+ """Find the .hop/model directory in current working directory."""
115
+ cwd = Path.cwd()
116
+ model_dir = cwd / ".hop" / "model"
117
+
118
+ if model_dir.is_dir():
119
+ return model_dir
120
+ return None
121
+
122
+
123
+ def get_database_name() -> Optional[str]:
124
+ """Get database name from half_orm config."""
125
+ try:
126
+ from half_orm.model import Model
127
+ model = Model._model
128
+ if model:
129
+ return model._dbname
130
+ except:
131
+ pass
132
+
133
+ # Try reading from .hop/config
134
+ config_path = Path.cwd() / ".hop" / "config"
135
+ if config_path.exists():
136
+ import configparser
137
+ config = configparser.ConfigParser()
138
+ config.read(config_path)
139
+ if 'database' in config and 'name' in config['database']:
140
+ return config['database']['name']
141
+
142
+ return None
143
+
144
+
145
+ def clear_hop_release_table(db_name: str, dry_run: bool = False) -> None:
146
+ """
147
+ Clear hop_release table keeping only 0.0.0.
148
+
149
+ Args:
150
+ db_name: Database name
151
+ dry_run: If True, only show what would be done
152
+ """
153
+ sql = "DELETE FROM half_orm_meta.hop_release WHERE NOT (major = 0 AND minor = 0 AND patch = 0);"
154
+
155
+ if dry_run:
156
+ print(f"Would execute: {sql}")
157
+ return
158
+
159
+ subprocess.run(
160
+ ['psql', '-d', db_name, '-c', sql],
161
+ check=True, capture_output=True
162
+ )
163
+
164
+
165
+ def insert_version(db_name: str, major: int, minor: int, patch: int,
166
+ pre_release: str, pre_release_num: str,
167
+ date: datetime, dry_run: bool = False) -> None:
168
+ """
169
+ Insert a version into hop_release table.
170
+
171
+ Args:
172
+ db_name: Database name
173
+ major, minor, patch: Version components
174
+ pre_release: 'rc' or ''
175
+ pre_release_num: RC number or ''
176
+ date: Release date
177
+ dry_run: If True, only show what would be done
178
+ """
179
+ date_str = date.strftime('%Y-%m-%d')
180
+ time_str = date.strftime('%H:%M:%S')
181
+
182
+ sql = f"""INSERT INTO half_orm_meta.hop_release
183
+ (major, minor, patch, pre_release, pre_release_num, date, time)
184
+ VALUES ({major}, {minor}, {patch}, '{pre_release}', '{pre_release_num}', '{date_str}', '{time_str}');"""
185
+
186
+ if dry_run:
187
+ print(f"Would execute: {sql}")
188
+ return
189
+
190
+ subprocess.run(
191
+ ['psql', '-d', db_name, '-c', sql],
192
+ check=True, capture_output=True
193
+ )
194
+
195
+
196
+ def generate_metadata_file(db_name: str, version_str: str, model_dir: Path,
197
+ dry_run: bool = False) -> Path:
198
+ """
199
+ Generate metadata-X.Y.Z.sql file using pg_dump.
200
+
201
+ Only keeps COPY blocks to avoid version-specific SET commands
202
+ and ensure compatibility across PostgreSQL versions.
203
+
204
+ Args:
205
+ db_name: Database name
206
+ version_str: Version string (e.g., "0.1.0" or "0.1.0-rc1")
207
+ model_dir: Path to model directory
208
+ dry_run: If True, only show what would be done
209
+
210
+ Returns:
211
+ Path to generated file
212
+ """
213
+ metadata_file = model_dir / f"metadata-{version_str}.sql"
214
+
215
+ if dry_run:
216
+ print(f"Would generate: {metadata_file}")
217
+ return metadata_file
218
+
219
+ # Dump to stdout
220
+ result = subprocess.run([
221
+ 'pg_dump', db_name,
222
+ '--data-only',
223
+ '--table=half_orm_meta.database',
224
+ '--table=half_orm_meta.hop_release',
225
+ '--table=half_orm_meta.hop_release_issue',
226
+ ], check=True, capture_output=True, text=True)
227
+
228
+ # Filter to keep only COPY blocks (COPY ... FROM stdin; ... \.)
229
+ filtered_lines = []
230
+ in_copy_block = False
231
+ for line in result.stdout.split('\n'):
232
+ if line.startswith('COPY '):
233
+ in_copy_block = True
234
+ if in_copy_block:
235
+ filtered_lines.append(line)
236
+ if line == '\\.':
237
+ in_copy_block = False
238
+ filtered_lines.append('') # Empty line between blocks
239
+
240
+ metadata_file.write_text('\n'.join(filtered_lines))
241
+
242
+ return metadata_file
243
+
244
+
245
+ def main():
246
+ parser = argparse.ArgumentParser(
247
+ description="Regenerate half-orm-dev metadata files from git tags.",
248
+ formatter_class=argparse.RawDescriptionHelpFormatter,
249
+ epilog=__doc__
250
+ )
251
+ parser.add_argument(
252
+ '--dry-run',
253
+ action='store_true',
254
+ help='Show what would be done without modifying anything'
255
+ )
256
+ parser.add_argument(
257
+ '--verbose',
258
+ action='store_true',
259
+ help='Show detailed information'
260
+ )
261
+ parser.add_argument(
262
+ '--database',
263
+ type=str,
264
+ help='Database name (auto-detected if not specified)'
265
+ )
266
+ parser.add_argument(
267
+ '--model-dir',
268
+ type=Path,
269
+ help='Path to model directory (default: .hop/model)'
270
+ )
271
+
272
+ args = parser.parse_args()
273
+
274
+ # Find model directory
275
+ if args.model_dir:
276
+ model_dir = args.model_dir
277
+ else:
278
+ model_dir = find_model_dir()
279
+
280
+ if model_dir is None or not model_dir.is_dir():
281
+ print("Error: Could not find .hop/model directory", file=sys.stderr)
282
+ print("Make sure you're in a half-orm-dev managed project directory", file=sys.stderr)
283
+ sys.exit(1)
284
+
285
+ # Get database name
286
+ db_name = args.database or get_database_name()
287
+ if not db_name:
288
+ print("Error: Could not determine database name", file=sys.stderr)
289
+ print("Use --database option to specify it", file=sys.stderr)
290
+ sys.exit(1)
291
+
292
+ print(f"Model directory: {model_dir}")
293
+ print(f"Database: {db_name}")
294
+ print()
295
+
296
+ if args.dry_run:
297
+ print("=== DRY RUN MODE - No changes will be made ===")
298
+ print()
299
+
300
+ # Get version tags
301
+ tags = get_version_tags()
302
+
303
+ if not tags:
304
+ print("No version tags found (expected format: vX.Y.Z or vX.Y.Z-rcN)")
305
+ sys.exit(0)
306
+
307
+ print(f"Found {len(tags)} version tags")
308
+ print()
309
+
310
+ # Step 1: Clear hop_release table (keep 0.0.0)
311
+ print("Step 1: Clearing hop_release table (keeping 0.0.0)...")
312
+ clear_hop_release_table(db_name, dry_run=args.dry_run)
313
+ print(" Done")
314
+ print()
315
+
316
+ # Step 2: Process each version
317
+ print("Step 2: Processing versions...")
318
+ for tag_name, version_str, date in tags:
319
+ major, minor, patch, pre_release, pre_release_num = parse_version_string(version_str)
320
+
321
+ if args.verbose:
322
+ print(f" {tag_name} -> {version_str} ({date})")
323
+
324
+ # Insert version with correct date
325
+ insert_version(
326
+ db_name, major, minor, patch,
327
+ pre_release, pre_release_num, date,
328
+ dry_run=args.dry_run
329
+ )
330
+
331
+ # Generate metadata file
332
+ metadata_file = generate_metadata_file(
333
+ db_name, version_str, model_dir,
334
+ dry_run=args.dry_run
335
+ )
336
+
337
+ print(f" ✓ {version_str} ({date.strftime('%Y-%m-%d')})")
338
+
339
+ print()
340
+ print("=" * 50)
341
+ print(f"Summary:")
342
+ print(f" Versions processed: {len(tags)}")
343
+
344
+ if not args.dry_run:
345
+ print()
346
+ print("Next steps:")
347
+ print(" 1. Review the changes: git status")
348
+ print(" 2. Commit: git add .hop/model/metadata-*.sql && git commit -m 'fix: regenerate metadata files'")
349
+
350
+
351
+ if __name__ == "__main__":
352
+ main()
@@ -0,0 +1 @@
1
+ 0.17.3-a7
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: half_orm_dev
3
- Version: 0.17.3a6
3
+ Version: 0.17.3a7
4
4
  Summary: half_orm development Framework.
5
5
  Author-email: Joël Maïzi <joel.maizi@collorg.org>
6
6
  License-Expression: GPL-3.0-or-later
@@ -45,6 +45,7 @@ half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql
45
45
  half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql
46
46
  half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql
47
47
  half_orm_dev/patches/sql/half_orm_meta.sql
48
+ half_orm_dev/scripts/repair-metadata.py
48
49
  half_orm_dev/templates/.gitignore
49
50
  half_orm_dev/templates/MANIFEST.in
50
51
  half_orm_dev/templates/Pipfile
@@ -47,6 +47,7 @@ half_orm_dev = [
47
47
  "templates/.gitignore",
48
48
  "db_patch_system/*",
49
49
  "patches/**/*",
50
+ "scripts/*",
50
51
  "version.txt"
51
52
  ]
52
53
 
@@ -1 +0,0 @@
1
- 0.17.3-a6
File without changes
File without changes