half-orm-dev 1.0.0a33__tar.gz → 1.0.0a34__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 (84) hide show
  1. {half_orm_dev-1.0.0a33/half_orm_dev.egg-info → half_orm_dev-1.0.0a34}/PKG-INFO +2 -2
  2. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/release.py +2 -2
  3. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/database.py +7 -1
  4. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/file_executor.py +1 -1
  5. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/release_manager.py +1 -1
  6. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/repo.py +22 -11
  7. half_orm_dev-1.0.0a34/half_orm_dev/version.txt +1 -0
  8. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34/half_orm_dev.egg-info}/PKG-INFO +2 -2
  9. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev.egg-info/requires.txt +1 -1
  10. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/setup.py +1 -1
  11. half_orm_dev-1.0.0a33/half_orm_dev/version.txt +0 -1
  12. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/AUTHORS +0 -0
  13. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/LICENSE +0 -0
  14. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/README.md +0 -0
  15. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/__init__.py +0 -0
  16. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/_bootstrap_runner.py +0 -0
  17. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/__init__.py +0 -0
  18. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/__init__.py +0 -0
  19. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/apply.py +0 -0
  20. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/check.py +0 -0
  21. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/clone.py +0 -0
  22. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/init.py +0 -0
  23. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/migrate.py +0 -0
  24. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/patch.py +0 -0
  25. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/recover.py +0 -0
  26. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/restore.py +0 -0
  27. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/revert_migration.py +0 -0
  28. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/rollback.py +0 -0
  29. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/set_git_origin.py +0 -0
  30. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/sync.py +0 -0
  31. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/todo.py +0 -0
  32. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/undo.py +0 -0
  33. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/commands/upgrade.py +0 -0
  34. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli/main.py +0 -0
  35. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/cli_extension.py +0 -0
  36. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/decorators.py +0 -0
  37. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/hgit.py +0 -0
  38. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migration_manager.py +0 -0
  39. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/0/17/1/00_move_to_hop.py +0 -0
  40. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/0/17/1/01_txt_to_toml.py +0 -0
  41. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/0/17/4/00_toml_dict_format.py +0 -0
  42. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/0/17/4/02_move_patches_to_subdirs.py +0 -0
  43. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/0/17/5/01_update_pyproject_dependency.py +0 -0
  44. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/0/18/0/00_add_async_support.py +0 -0
  45. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/0/18/0/01_update_default_tests.py +0 -0
  46. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/1/0/0/a20/01_update_gitignore.py +0 -0
  47. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/1/0/0/a33/00_metadata_to_data_sql.py +0 -0
  48. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/migrations/hop/BREAKING_CHANGES-1.0.0.md +0 -0
  49. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/modules.py +0 -0
  50. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/patch_manager.py +0 -0
  51. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/patch_validator.py +0 -0
  52. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/patches/0/1/0/00_half_orm_meta.database.sql +0 -0
  53. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/patches/0/1/0/01_alter_half_orm_meta.hop_release.sql +0 -0
  54. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/patches/0/1/0/02_half_orm_meta.view.hop_penultimate_release.sql +0 -0
  55. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/patches/log +0 -0
  56. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/patches/sql/half_orm_meta.sql +0 -0
  57. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/py.typed +0 -0
  58. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/release_file.py +0 -0
  59. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/scripts/repair-metadata.py +0 -0
  60. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/.gitignore +0 -0
  61. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/MANIFEST.in +0 -0
  62. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/README +0 -0
  63. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/conftest_template +0 -0
  64. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/git-hooks/pre-commit +0 -0
  65. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/git-hooks/pre-push +0 -0
  66. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/git-hooks/prepare-commit-msg +0 -0
  67. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/git-hooks/reference-transaction +0 -0
  68. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/init_module_template +0 -0
  69. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/module_template_1 +0 -0
  70. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/module_template_2 +0 -0
  71. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/module_template_3 +0 -0
  72. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/pyproject.toml +0 -0
  73. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/relation_test +0 -0
  74. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/sql_adapter +0 -0
  75. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/templates/warning +0 -0
  76. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/utils.py +0 -0
  77. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev/venv_setup.py +0 -0
  78. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev.egg-info/SOURCES.txt +0 -0
  79. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev.egg-info/dependency_links.txt +0 -0
  80. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev.egg-info/entry_points.txt +0 -0
  81. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/half_orm_dev.egg-info/top_level.txt +0 -0
  82. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/pyproject.toml +0 -0
  83. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/setup.cfg +0 -0
  84. {half_orm_dev-1.0.0a33 → half_orm_dev-1.0.0a34}/tests/test_bootstrap_runner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: half_orm_dev
3
- Version: 1.0.0a33
3
+ Version: 1.0.0a34
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
@@ -25,7 +25,7 @@ Requires-Dist: packaging
25
25
  Requires-Dist: pydash
26
26
  Requires-Dist: pytest
27
27
  Requires-Dist: pytest-asyncio
28
- Requires-Dist: half_orm<1.1.0,>=1.0.0rc16
28
+ Requires-Dist: half_orm<1.1.0,>=1.0.0
29
29
  Requires-Dist: tomli>=2.0.0; python_version < "3.11"
30
30
  Requires-Dist: tomli_w>=1.0.0
31
31
  Dynamic: license-file
@@ -180,7 +180,7 @@ def release_promote(target: str) -> None:
180
180
  2. Validate sequential version rule
181
181
  3. Acquire distributed lock on ho-prod
182
182
  4. Restore database and apply all patches
183
- 5. Generate schema-X.Y.Z.sql and metadata-X.Y.Z.sql
183
+ 5. Generate schema-X.Y.Z.sql and data-X.Y.Z.sql
184
184
  6. Update schema.sql symlink
185
185
  7. Rename RC file to production file (git mv)
186
186
  8. Commit and push promotion
@@ -203,7 +203,7 @@ def release_promote(target: str) -> None:
203
203
  Output:
204
204
  ✓ Promoted 1.3.5-rc1 → 1.3.5
205
205
  ✓ Generated schema-1.3.5.sql
206
- ✓ Generated metadata-1.3.5.sql
206
+ ✓ Generated data-1.3.5.sql
207
207
  ✓ Updated schema.sql → schema-1.3.5.sql
208
208
 
209
209
  \b
@@ -398,7 +398,11 @@ class Database:
398
398
  )
399
399
 
400
400
  # Filter to keep only COPY blocks (COPY ... FROM stdin; ... \.)
401
- # to avoid version-specific SET commands
401
+ # and the SELECT pg_catalog.setval(...) calls pg_dump emits
402
+ # after them - dropping those would leave every serial/identity
403
+ # sequence at its default start value, causing the next INSERT
404
+ # relying on it to collide with rows restored by COPY. Version-
405
+ # specific SET commands are what we actually want to avoid.
402
406
  content = temp_file.read_text()
403
407
  filtered_lines = []
404
408
  in_copy_block = False
@@ -410,6 +414,8 @@ class Database:
410
414
  if line == '\\.':
411
415
  in_copy_block = False
412
416
  filtered_lines.append('') # Empty line between blocks
417
+ elif not in_copy_block and line.startswith('SELECT pg_catalog.setval('):
418
+ filtered_lines.append(line)
413
419
 
414
420
  data_file.write_text('\n'.join(filtered_lines))
415
421
  except Exception as e:
@@ -59,7 +59,7 @@ def execute_sql_file_psql(file_path: Path, database, database_name: str) -> None
59
59
  FileExecutionError: If psql execution fails
60
60
  """
61
61
  try:
62
- database.execute_pg_command('psql', '-d', database_name, '-f', str(file_path))
62
+ database.execute_pg_command('psql', '-v', 'ON_ERROR_STOP=1', '-d', database_name, '-f', str(file_path))
63
63
  except Exception as e:
64
64
  raise FileExecutionError(f"psql execution failed for {file_path.name}: {e}") from e
65
65
 
@@ -306,7 +306,7 @@ class ReleaseManager:
306
306
  try:
307
307
  self._repo.database._generate_schema_sql(version_str, model_dir)
308
308
  click.echo(f" ✓ Generated schema-{version_str}.sql")
309
- click.echo(f" ✓ Generated metadata-{version_str}.sql")
309
+ click.echo(f" ✓ Generated data-{version_str}.sql")
310
310
  click.echo(f" ✓ Created symlink: schema.sql -> schema-{version_str}.sql")
311
311
  except Exception as e:
312
312
  raise ReleaseManagerError(f"Failed to generate schema files: {e}")
@@ -2362,11 +2362,22 @@ Files are executed **alphabetically** (not numerically parsed).
2362
2362
 
2363
2363
  ## Execution Context
2364
2364
 
2365
- Bootstrap scripts run:
2366
- - **Development**: Each `patch apply` (allows iteration on bootstrap)
2367
- - **Production**: Initial `clone` only (one-time setup)
2368
-
2369
- For production data changes, use **patches** (not bootstrap).
2365
+ Bootstrap scripts run **once**: when a brand-new instance is created via
2366
+ `clone`. They do NOT run on `patch apply`, `patch merge`, or
2367
+ `release promote` - there is no database reset between those, so a
2368
+ script that isn't independently idempotent would corrupt the database if
2369
+ it ran more than once.
2370
+
2371
+ Reserve `bootstrap/` for data that is genuinely specific to *this*
2372
+ instance (e.g. an initial admin account, a per-site secret) - never for
2373
+ reference/system data that every instance should have.
2374
+
2375
+ Reference/system data that every instance should ship with (e.g. a new
2376
+ system role) does NOT belong in `bootstrap/`: write it as ordinary
2377
+ idempotent DML in a **patch** instead. It reaches existing instances
2378
+ through the normal `hop upgrade` path, and gets captured automatically
2379
+ in `model/data-X.Y.Z.sql` (the schema+data snapshot restored by every
2380
+ `patch apply`) once shipped - `bootstrap/` scripts never are.
2370
2381
 
2371
2382
  ## Python Files
2372
2383
 
@@ -2733,7 +2744,7 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
2733
2744
  # 3. Load schema from model/schema.sql
2734
2745
  try:
2735
2746
  self.database.execute_pg_command(
2736
- 'psql', '-d', self.database_name, '-f', str(schema_path)
2747
+ 'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(schema_path)
2737
2748
  )
2738
2749
  except Exception as e:
2739
2750
  raise RepoError(f"Failed to load schema from {schema_path.name}: {e}") from e
@@ -2744,7 +2755,7 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
2744
2755
  if data_path and data_path.exists():
2745
2756
  try:
2746
2757
  self.database.execute_pg_command(
2747
- 'psql', '-d', self.database_name, '-f', str(data_path)
2758
+ 'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(data_path)
2748
2759
  )
2749
2760
  except Exception as e:
2750
2761
  raise RepoError(
@@ -2796,7 +2807,7 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
2796
2807
 
2797
2808
  try:
2798
2809
  self.database.execute_pg_command(
2799
- 'psql', '-d', self.database_name, '-f', str(schema_path)
2810
+ 'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(schema_path)
2800
2811
  )
2801
2812
  except Exception as e:
2802
2813
  raise RepoError(f"Failed to load schema from {schema_path.name}: {e}") from e
@@ -2805,7 +2816,7 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
2805
2816
  if data_path.exists():
2806
2817
  try:
2807
2818
  self.database.execute_pg_command(
2808
- 'psql', '-d', self.database_name, '-f', str(data_path)
2819
+ 'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(data_path)
2809
2820
  )
2810
2821
  except Exception as e:
2811
2822
  raise RepoError(
@@ -2862,7 +2873,7 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
2862
2873
  # 2. Load dump using psql
2863
2874
  try:
2864
2875
  self.database.execute_pg_command(
2865
- 'psql', '-d', self.database_name, '-f', str(dump_path)
2876
+ 'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(dump_path)
2866
2877
  )
2867
2878
  except Exception as e:
2868
2879
  raise RepoError(f"Failed to load dump from {dump_path.name}: {e}") from e
@@ -2987,7 +2998,7 @@ INSERT INTO public.roles (name) VALUES ('admin'), ('user');
2987
2998
 
2988
2999
  # Load release schema
2989
3000
  self.database.execute_pg_command(
2990
- 'psql', '-d', self.database_name, '-f', str(release_schema_path)
3001
+ 'psql', '-v', 'ON_ERROR_STOP=1', '-d', self.database_name, '-f', str(release_schema_path)
2991
3002
  )
2992
3003
 
2993
3004
  # Reload half_orm metadata cache
@@ -0,0 +1 @@
1
+ 1.0.0-a34
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: half_orm_dev
3
- Version: 1.0.0a33
3
+ Version: 1.0.0a34
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
@@ -25,7 +25,7 @@ Requires-Dist: packaging
25
25
  Requires-Dist: pydash
26
26
  Requires-Dist: pytest
27
27
  Requires-Dist: pytest-asyncio
28
- Requires-Dist: half_orm<1.1.0,>=1.0.0rc16
28
+ Requires-Dist: half_orm<1.1.0,>=1.0.0
29
29
  Requires-Dist: tomli>=2.0.0; python_version < "3.11"
30
30
  Requires-Dist: tomli_w>=1.0.0
31
31
  Dynamic: license-file
@@ -4,7 +4,7 @@ packaging
4
4
  pydash
5
5
  pytest
6
6
  pytest-asyncio
7
- half_orm<1.1.0,>=1.0.0rc16
7
+ half_orm<1.1.0,>=1.0.0
8
8
  tomli_w>=1.0.0
9
9
 
10
10
  [:python_version < "3.11"]
@@ -17,7 +17,7 @@ from setuptools import setup
17
17
  # for half_orm_dev 0.17.x where 3 <= x < 5, require half_orm >= 0.17.1
18
18
  HALF_ORM_MIN_VERSIONS = [
19
19
  (0, 17, 3, None, '0.17.3'), # 0.17.3+ requires half_orm >= 0.17.3 (CustomGroup support)
20
- (1, 0, 0, None, '1.0.0rc16'), # 1.0.0+ requires half_orm >= 1.0.0rc16 (with_half_orm_meta support)
20
+ (1, 0, 0, None, '1.0.0'), # 1.0.0+ requires half_orm >= 1.0.0 (stable release)
21
21
  ]
22
22
 
23
23
 
@@ -1 +0,0 @@
1
- 1.0.0-a33
File without changes
File without changes