formkit-ninja 2.2__tar.gz → 2.4__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 (527) hide show
  1. formkit_ninja-2.4/.github/workflows/release.yml +111 -0
  2. {formkit_ninja-2.2 → formkit_ninja-2.4}/CHANGELOG.md +22 -0
  3. {formkit_ninja-2.2 → formkit_ninja-2.4}/PKG-INFO +1 -1
  4. formkit_ninja-2.4/docs/releasing.md +47 -0
  5. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/admin.py +67 -82
  6. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/formkit_schema.py +4 -0
  7. formkit_ninja-2.4/formkit_ninja/migrations/0042_formkitschemanode_list_filter.py +61 -0
  8. formkit_ninja-2.4/formkit_ninja/migrations/0043_remove_formkitschemanode_insert_insert_and_more.py +73 -0
  9. formkit_ninja-2.4/formkit_ninja/migrations/0044_backfill_code_scheme_pnds.py +71 -0
  10. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/models.py +77 -0
  11. {formkit_ninja-2.2 → formkit_ninja-2.4}/pyproject.toml +1 -1
  12. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_partisipanodepath_rewritten.py +8 -7
  13. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_admin.py +19 -1
  14. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_admin_best_practice.py +2 -2
  15. formkit_ninja-2.4/tests/test_code_scheme.py +115 -0
  16. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_complex_nodes.py +2 -2
  17. {formkit_ninja-2.2 → formkit_ninja-2.4}/uv.lock +1 -1
  18. formkit_ninja-2.2/formkit_ninja/htmlcov/.gitignore +0 -2
  19. formkit_ninja-2.2/formkit_ninja/htmlcov/__init___py.html +0 -99
  20. formkit_ninja-2.2/formkit_ninja/htmlcov/__main___py.html +0 -99
  21. formkit_ninja-2.2/formkit_ninja/htmlcov/admin_py.html +0 -615
  22. formkit_ninja-2.2/formkit_ninja/htmlcov/api_py.html +0 -577
  23. formkit_ninja-2.2/formkit_ninja/htmlcov/class_index.html +0 -3268
  24. formkit_ninja-2.2/formkit_ninja/htmlcov/coverage_html_cb_dd2e7eb5.js +0 -735
  25. formkit_ninja-2.2/formkit_ninja/htmlcov/favicon_32_cb_c827f16f.png +0 -0
  26. formkit_ninja-2.2/formkit_ninja/htmlcov/fields_py.html +0 -250
  27. formkit_ninja-2.2/formkit_ninja/htmlcov/formkit_schema_py.html +0 -695
  28. formkit_ninja-2.2/formkit_ninja/htmlcov/function_index.html +0 -3073
  29. formkit_ninja-2.2/formkit_ninja/htmlcov/index.html +0 -871
  30. formkit_ninja-2.2/formkit_ninja/htmlcov/keybd_closed_cb_900cfef5.png +0 -0
  31. formkit_ninja-2.2/formkit_ninja/htmlcov/models_py.html +0 -911
  32. formkit_ninja-2.2/formkit_ninja/htmlcov/status.json +0 -1
  33. formkit_ninja-2.2/formkit_ninja/htmlcov/style_cb_9ff733b0.css +0 -389
  34. formkit_ninja-2.2/formkit_ninja/htmlcov/triggers_py.html +0 -197
  35. formkit_ninja-2.2/formkit_ninja/htmlcov/urls_py.html +0 -108
  36. formkit_ninja-2.2/formkit_ninja/htmlcov/z_51fcec635d35c76c___init___py.html +0 -134
  37. formkit_ninja-2.2/formkit_ninja/htmlcov/z_51fcec635d35c76c_schemas_py.html +0 -99
  38. formkit_ninja-2.2/formkit_ninja/htmlcov/z_72798c8d109b1720___init___py.html +0 -99
  39. formkit_ninja-2.2/formkit_ninja/htmlcov/z_72798c8d109b1720_logger_py.html +0 -103
  40. formkit_ninja-2.2/formkit_ninja/htmlcov/z_72798c8d109b1720_type_convert_py.html +0 -460
  41. formkit_ninja-2.2/formkit_ninja/htmlcov/z_d0f9da560d0d1331___init___py.html +0 -99
  42. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0001_initial_py.html +0 -482
  43. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0002_alter_formcomponents_label_alter_formkitschema_key_py.html +0 -121
  44. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0003_delete_translatable_py.html +0 -114
  45. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0004_remove_formkitschema_key_and_more_py.html +0 -145
  46. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0005_option_last_updated_option_object_id_optionlabel_and_more_py.html +0 -169
  47. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0006_option_group_option_unique_option_id_py.html +0 -128
  48. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0007_alter_option_field_py.html +0 -124
  49. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0008_remove_option_label_py.html +0 -115
  50. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0009_formkitschemanode_text_content_and_more_py.html +0 -124
  51. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0010_alter_option_options_and_more_py.html +0 -169
  52. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0011_nodechildren_formkitschemanode_children_py.html +0 -143
  53. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0012_remove_formkitschemanode_group_remove_option_field_and_more_py.html +0 -142
  54. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0013_formkitschemanode_option_group_py.html +0 -119
  55. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0014_schemalabel_schemadescription_py.html +0 -180
  56. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0015_alter_formkitschema_label_py.html +0 -125
  57. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0016_alter_nodechildren_options_and_more_py.html +0 -219
  58. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0017_nodechildren_change_id_py.html +0 -115
  59. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0018_remove_formcomponents_order_on_insert_option_and_more_py.html +0 -207
  60. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0019_formkitschemanode_track_change_and_more_py.html +0 -136
  61. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0020_remove_formcomponents_order_on_update_option_and_more_py.html +0 -170
  62. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0021_formkitschemanode_is_active_py.html +0 -116
  63. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0022_formkitschemanode_soft_delete_py.html +0 -127
  64. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0023_formkitschemanodeevent_and_more_py.html +0 -272
  65. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0024_remove_formkitschemanode_insert_insert_and_more_py.html +0 -175
  66. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0025_remove_formkitschemanode_protect_deletes_and_more_py.html +0 -132
  67. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0026_remove_formkitschemanode_protect_node_deletes_and_updates_and_more_py.html +0 -147
  68. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0027_remove_formkitschemanode_insert_insert_and_more_py.html +0 -170
  69. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0028_migrate_additional_props_py.html +0 -137
  70. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0029_remove_formkitschemanode_insert_insert_and_more_py.html +0 -180
  71. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0030_migrate_more_props_py.html +0 -143
  72. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0031_remove_formkitschemanode_insert_insert_and_more_py.html +0 -190
  73. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0032_migrate_repeater_props_py.html +0 -154
  74. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9_0033_remove_formkitschemanode_insert_insert_and_more_py.html +0 -160
  75. formkit_ninja-2.2/formkit_ninja/htmlcov/z_de72b752a94110f9___init___py.html +0 -99
  76. formkit_ninja-2.2/formkit_ninja/htmlcov/z_ea3808ded160dd19___init___py.html +0 -99
  77. formkit_ninja-2.2/formkit_ninja/htmlcov/z_ea3808ded160dd19_check_valid_names_py.html +0 -117
  78. formkit_ninja-2.2/formkit_ninja/htmlcov/z_ea3808ded160dd19_import_forms_py.html +0 -123
  79. formkit_ninja-2.2/formkit_ninja/htmlcov/z_fd003194bc69d7fb___init___py.html +0 -99
  80. formkit_ninja-2.2/formkit_ninja/migrations/0042_formkitschemanode_list_filter.py +0 -41
  81. formkit_ninja-2.2/htmlcov/.gitignore +0 -2
  82. formkit_ninja-2.2/htmlcov/class_index.html +0 -3808
  83. formkit_ninja-2.2/htmlcov/coverage_html_cb_dd2e7eb5.js +0 -735
  84. formkit_ninja-2.2/htmlcov/favicon_32_cb_c827f16f.png +0 -0
  85. formkit_ninja-2.2/htmlcov/function_index.html +0 -6868
  86. formkit_ninja-2.2/htmlcov/index.html +0 -815
  87. formkit_ninja-2.2/htmlcov/keybd_closed_cb_900cfef5.png +0 -0
  88. formkit_ninja-2.2/htmlcov/status.json +0 -1
  89. formkit_ninja-2.2/htmlcov/style_cb_9ff733b0.css +0 -389
  90. formkit_ninja-2.2/htmlcov/z_2ac3eb8e1401bc8b___init___py.html +0 -99
  91. formkit_ninja-2.2/htmlcov/z_2ac3eb8e1401bc8b_apps_py.html +0 -113
  92. formkit_ninja-2.2/htmlcov/z_2ac3eb8e1401bc8b_handlers_py.html +0 -148
  93. formkit_ninja-2.2/htmlcov/z_2ac3eb8e1401bc8b_import_monitoring_py.html +0 -119
  94. formkit_ninja-2.2/htmlcov/z_2ac3eb8e1401bc8b_models_py.html +0 -439
  95. formkit_ninja-2.2/htmlcov/z_2ac3eb8e1401bc8b_querysets_py.html +0 -275
  96. formkit_ninja-2.2/htmlcov/z_2ac3eb8e1401bc8b_signals_py.html +0 -120
  97. formkit_ninja-2.2/htmlcov/z_2ac3eb8e1401bc8b_utils_py.html +0 -309
  98. formkit_ninja-2.2/htmlcov/z_319c17fd0771b8a8___init___py.html +0 -99
  99. formkit_ninja-2.2/htmlcov/z_319c17fd0771b8a8_add_schema_field_py.html +0 -308
  100. formkit_ninja-2.2/htmlcov/z_319c17fd0771b8a8_bootstrap_app_py.html +0 -284
  101. formkit_ninja-2.2/htmlcov/z_319c17fd0771b8a8_check_valid_names_py.html +0 -117
  102. formkit_ninja-2.2/htmlcov/z_319c17fd0771b8a8_create_schema_py.html +0 -347
  103. formkit_ninja-2.2/htmlcov/z_319c17fd0771b8a8_generate_all_schemas_py.html +0 -287
  104. formkit_ninja-2.2/htmlcov/z_319c17fd0771b8a8_generate_code_py.html +0 -242
  105. formkit_ninja-2.2/htmlcov/z_319c17fd0771b8a8_import_forms_py.html +0 -122
  106. formkit_ninja-2.2/htmlcov/z_336430bde916e5dc___init___py.html +0 -100
  107. formkit_ninja-2.2/htmlcov/z_336430bde916e5dc_schema_import_py.html +0 -149
  108. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c___init___py.html +0 -160
  109. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_converters_examples_py.html +0 -236
  110. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_converters_py.html +0 -626
  111. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_database_node_path_py.html +0 -422
  112. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_formatter_py.html +0 -189
  113. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_generation_pipeline_py.html +0 -154
  114. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_generator_config_py.html +0 -217
  115. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_generator_py.html +0 -790
  116. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_logger_py.html +0 -103
  117. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_node_factory_py.html +0 -212
  118. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_node_registry_py.html +0 -241
  119. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_plugins_py.html +0 -298
  120. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_schema_walker_py.html +0 -178
  121. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_template_loader_py.html +0 -195
  122. formkit_ninja-2.2/htmlcov/z_3d54085545bd272c_type_convert_py.html +0 -1198
  123. formkit_ninja-2.2/htmlcov/z_49d1c7cc3d8927e8___init___py.html +0 -133
  124. formkit_ninja-2.2/htmlcov/z_49d1c7cc3d8927e8_schemas_py.html +0 -99
  125. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1___init___py.html +0 -99
  126. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1___main___py.html +0 -99
  127. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_admin_code_generation_py.html +0 -419
  128. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_admin_py.html +0 -990
  129. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_api_py.html +0 -715
  130. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_code_generation_config_py.html +0 -256
  131. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_fields_py.html +0 -248
  132. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_formkit_schema_py.html +0 -712
  133. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_models_py.html +0 -1054
  134. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_notifications_py.html +0 -141
  135. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_triggers_py.html +0 -194
  136. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_urls_py.html +0 -108
  137. formkit_ninja-2.2/htmlcov/z_7688fa66c50fa3b1_utils_py.html +0 -123
  138. formkit_ninja-2.2/htmlcov/z_c3b4d83f5f06a6a6___init___py.html +0 -99
  139. formkit_ninja-2.2/htmlcov/z_f16099ef8f43d13f___init___py.html +0 -99
  140. {formkit_ninja-2.2 → formkit_ninja-2.4}/.agent/workflows/conventions.md +0 -0
  141. {formkit_ninja-2.2 → formkit_ninja-2.4}/.cursor/rules/001-github-issues.mdc +0 -0
  142. {formkit_ninja-2.2 → formkit_ninja-2.4}/.cursor/rules/002-issue-creation-guide.mdc +0 -0
  143. {formkit_ninja-2.2 → formkit_ninja-2.4}/.cursor/rules/003-commit-messages.mdc +0 -0
  144. {formkit_ninja-2.2 → formkit_ninja-2.4}/.cursor/rules/004-pytest-requirements.mdc +0 -0
  145. {formkit_ninja-2.2 → formkit_ninja-2.4}/.cursor/rules/005-database-container.mdc +0 -0
  146. {formkit_ninja-2.2 → formkit_ninja-2.4}/.cursorrules +0 -0
  147. {formkit_ninja-2.2 → formkit_ninja-2.4}/.flake8 +0 -0
  148. {formkit_ninja-2.2 → formkit_ninja-2.4}/.github/workflows/ci.yml +0 -0
  149. {formkit_ninja-2.2 → formkit_ninja-2.4}/.github/workflows/docs.yml +0 -0
  150. {formkit_ninja-2.2 → formkit_ninja-2.4}/.gitignore +0 -0
  151. {formkit_ninja-2.2 → formkit_ninja-2.4}/.pre-commit-config.yaml +0 -0
  152. {formkit_ninja-2.2 → formkit_ninja-2.4}/.vscode/extensions.json +0 -0
  153. {formkit_ninja-2.2 → formkit_ninja-2.4}/.vscode/launch.json +0 -0
  154. {formkit_ninja-2.2 → formkit_ninja-2.4}/.vscode/settings.json +0 -0
  155. {formkit_ninja-2.2 → formkit_ninja-2.4}/DEVELOPMENT.md +0 -0
  156. {formkit_ninja-2.2 → formkit_ninja-2.4}/FEATURES_COMPARISON.md +0 -0
  157. {formkit_ninja-2.2 → formkit_ninja-2.4}/NEW_USER_WORKFLOW_SUMMARY.md +0 -0
  158. {formkit_ninja-2.2 → formkit_ninja-2.4}/README.md +0 -0
  159. {formkit_ninja-2.2 → formkit_ninja-2.4}/SCHEMA_CONVERSION_SUMMARY.md +0 -0
  160. {formkit_ninja-2.2 → formkit_ninja-2.4}/TEST_COVERAGE_ANALYSIS.md +0 -0
  161. {formkit_ninja-2.2 → formkit_ninja-2.4}/debug_naming.py +0 -0
  162. {formkit_ninja-2.2 → formkit_ninja-2.4}/debug_partisipa.py +0 -0
  163. {formkit_ninja-2.2 → formkit_ninja-2.4}/demo_workflow.py +0 -0
  164. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/admin.md +0 -0
  165. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/classes.md +0 -0
  166. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/code_generation.md +0 -0
  167. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/database_code_generation.md +0 -0
  168. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/feature_matrix.md +0 -0
  169. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/index.md +0 -0
  170. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/inputs.md +0 -0
  171. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/multiple_schemas_options.md +0 -0
  172. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/options.md +0 -0
  173. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/quick_start.md +0 -0
  174. {formkit_ninja-2.2 → formkit_ninja-2.4}/docs/submission_architecture.md +0 -0
  175. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/__init__.py +0 -0
  176. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/__main__.py +0 -0
  177. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/admin_code_generation.py +0 -0
  178. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/api.py +0 -0
  179. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/code_generation_config.py +0 -0
  180. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/fields.py +0 -0
  181. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/fixtures/partisipa_contenttypes.json.gz +0 -0
  182. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/fixtures/partisipa_formkit_data.json.gz +0 -0
  183. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/form_submission/__init__.py +0 -0
  184. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/form_submission/apps.py +0 -0
  185. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/form_submission/import_monitoring.py +0 -0
  186. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/form_submission/models.py +0 -0
  187. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/form_submission/querysets.py +0 -0
  188. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/form_submission/signals.py +0 -0
  189. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/form_submission/utils.py +0 -0
  190. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/__init__.py +0 -0
  191. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/commands/__init__.py +0 -0
  192. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/commands/add_schema_field.py +0 -0
  193. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/commands/bootstrap_app.py +0 -0
  194. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/commands/check_valid_names.py +0 -0
  195. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/commands/create_schema.py +0 -0
  196. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/commands/generate_all_schemas.py +0 -0
  197. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/commands/generate_code.py +0 -0
  198. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/management/commands/import_forms.py +0 -0
  199. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0001_initial.py +0 -0
  200. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0002_alter_formcomponents_label_alter_formkitschema_key.py +0 -0
  201. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0003_delete_translatable.py +0 -0
  202. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0004_remove_formkitschema_key_and_more.py +0 -0
  203. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0005_option_last_updated_option_object_id_optionlabel_and_more.py +0 -0
  204. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0006_option_group_option_unique_option_id.py +0 -0
  205. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0007_alter_option_field.py +0 -0
  206. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0008_remove_option_label.py +0 -0
  207. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0009_formkitschemanode_text_content_and_more.py +0 -0
  208. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0010_alter_option_options_and_more.py +0 -0
  209. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0011_nodechildren_formkitschemanode_children.py +0 -0
  210. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0012_remove_formkitschemanode_group_remove_option_field_and_more.py +0 -0
  211. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0013_formkitschemanode_option_group.py +0 -0
  212. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0014_schemalabel_schemadescription.py +0 -0
  213. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0015_alter_formkitschema_label.py +0 -0
  214. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0016_alter_nodechildren_options_and_more.py +0 -0
  215. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0017_nodechildren_change_id.py +0 -0
  216. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0018_remove_formcomponents_order_on_insert_option_and_more.py +0 -0
  217. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0019_formkitschemanode_track_change_and_more.py +0 -0
  218. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0020_remove_formcomponents_order_on_update_option_and_more.py +0 -0
  219. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0021_formkitschemanode_is_active.py +0 -0
  220. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0022_formkitschemanode_soft_delete.py +0 -0
  221. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0023_formkitschemanodeevent_and_more.py +0 -0
  222. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0024_remove_formkitschemanode_insert_insert_and_more.py +0 -0
  223. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0025_remove_formkitschemanode_protect_deletes_and_more.py +0 -0
  224. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0026_remove_formkitschemanode_protect_node_deletes_and_updates_and_more.py +0 -0
  225. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0027_remove_formkitschemanode_insert_insert_and_more.py +0 -0
  226. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0028_migrate_additional_props.py +0 -0
  227. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0029_remove_formkitschemanode_insert_insert_and_more.py +0 -0
  228. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0030_migrate_more_props.py +0 -0
  229. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0031_remove_formkitschemanode_insert_insert_and_more.py +0 -0
  230. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0032_migrate_repeater_props.py +0 -0
  231. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0033_remove_formkitschemanode_insert_insert_and_more.py +0 -0
  232. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0034_codegenerationconfig_and_more.py +0 -0
  233. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0035_alter_codegenerationconfig_priority_submission_and_more.py +0 -0
  234. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0036_remove_formkitschemanode_insert_insert_and_more.py +0 -0
  235. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0037_alter_formkitschemanode_django_field_args_and_more.py +0 -0
  236. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0038_separatedsubmissionevent_submissionevent_and_more.py +0 -0
  237. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0039_remove_formkitschemanode_insert_insert_and_more.py +0 -0
  238. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0040_submissionfile_separatedsubmissionimport_and_more.py +0 -0
  239. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/0041_flag.py +0 -0
  240. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/migrations/__init__.py +0 -0
  241. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/notifications.py +0 -0
  242. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/__init__.py +0 -0
  243. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/converters.py +0 -0
  244. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/converters_examples.py +0 -0
  245. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/database_node_path.py +0 -0
  246. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/formatter.py +0 -0
  247. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/generation_pipeline.py +0 -0
  248. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/generator.py +0 -0
  249. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/generator_config.py +0 -0
  250. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/logger.py +0 -0
  251. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/node_factory.py +0 -0
  252. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/node_registry.py +0 -0
  253. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/plugins.py +0 -0
  254. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/schema_walker.py +0 -0
  255. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/template_loader.py +0 -0
  256. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/abstract_model.jinja2 +0 -0
  257. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/admin.jinja2 +0 -0
  258. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/admin.py.jinja2 +0 -0
  259. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/api.jinja2 +0 -0
  260. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/api.py.jinja2 +0 -0
  261. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/basemodel.jinja2 +0 -0
  262. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/model.jinja2 +0 -0
  263. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/models.py.jinja2 +0 -0
  264. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/schema.jinja2 +0 -0
  265. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/schemas.py.jinja2 +0 -0
  266. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/schemas_in.py.jinja2 +0 -0
  267. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/templates/signals.py.jinja2 +0 -0
  268. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/parser/type_convert.py +0 -0
  269. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/samples/__init__.py +0 -0
  270. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/samples/button-with-slot.html +0 -0
  271. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/samples/color_input.html +0 -0
  272. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/samples/date_input.html +0 -0
  273. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/samples/element.json +0 -0
  274. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/samples/form_generation_example.json +0 -0
  275. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/samples/meeting_type_node.json +0 -0
  276. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/samples/raw_values.json +0 -0
  277. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Balansu.json +0 -0
  278. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/CFM_12_FF_12.json +0 -0
  279. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/CFM_2_FF_4.json +0 -0
  280. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Dateofexitfromthecommittee.json +0 -0
  281. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Enterasensiblenumber.json +0 -0
  282. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF1_2_3.json +0 -0
  283. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF1_2_3_4.json +0 -0
  284. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF1_2_6.json +0 -0
  285. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_10.json +0 -0
  286. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_11.json +0 -0
  287. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_14.json +0 -0
  288. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_1_1.json +0 -0
  289. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_1_2_3.json +0 -0
  290. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_33_Finance_check.json +0 -0
  291. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_3_3_3.json +0 -0
  292. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_3_3_5.json +0 -0
  293. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FF_5_3_3.json +0 -0
  294. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FS5.json +0 -0
  295. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FS_4_3.json +0 -0
  296. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/FS_4_6.json +0 -0
  297. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Fathersname.json +0 -0
  298. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Formulariu_koko.json +0 -0
  299. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/HowmanyDollars.json +0 -0
  300. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/MoneyTestgroup.json +0 -0
  301. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Monitorizasaun_Projetu_teste.json +0 -0
  302. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Mothersname.json +0 -0
  303. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/NewGroup.json +0 -0
  304. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/None.json +0 -0
  305. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Numberofhousehold.json +0 -0
  306. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/NumeruBI.json +0 -0
  307. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/POM_1.json +0 -0
  308. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/POM_5.json +0 -0
  309. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Project.json +0 -0
  310. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF2_2_3.json +0 -0
  311. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF_1_1.json +0 -0
  312. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF_1_2.json +0 -0
  313. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF_1_3.json +0 -0
  314. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF_2_3.json +0 -0
  315. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF_4_1.json +0 -0
  316. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF_4_2.json +0 -0
  317. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF_4_3.json +0 -0
  318. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/SF_6_2.json +0 -0
  319. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Sex_father.json +0 -0
  320. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_13_2_1.json +0 -0
  321. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_13_2_2.json +0 -0
  322. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_13_2_3.json +0 -0
  323. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_13_2_4.json +0 -0
  324. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_13_3_2.json +0 -0
  325. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_6_1_1.json +0 -0
  326. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_6_1_2.json +0 -0
  327. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_6_2_1.json +0 -0
  328. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_6_2_2.json +0 -0
  329. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_6_3_2.json +0 -0
  330. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TF_6_4_1.json +0 -0
  331. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/TestForm.json +0 -0
  332. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Tests.json +0 -0
  333. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Testu.json +0 -0
  334. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/Thisisanumericinput.json +0 -0
  335. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/__init__.py +0 -0
  336. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/_dad.json +0 -0
  337. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/active_status.json +0 -0
  338. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/date_exit_committee.json +0 -0
  339. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/dfadfa.json +0 -0
  340. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/exit_details.json +0 -0
  341. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/ff1_2_3.json +0 -0
  342. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/fs_4_3.json +0 -0
  343. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/gettextAdministrativePost.json +0 -0
  344. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/gettextAldeia.json +0 -0
  345. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/gettextMunicipality.json +0 -0
  346. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/gettextPostuAdministrativu.json +0 -0
  347. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/gettextProjectname.json +0 -0
  348. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/gettextSuco.json +0 -0
  349. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/idayesno.json +0 -0
  350. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/koko_1.json +0 -0
  351. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/my_testing.json +0 -0
  352. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/name.json +0 -0
  353. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/project_name.json +0 -0
  354. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/round.json +0 -0
  355. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/schemas.py +0 -0
  356. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/set.json +0 -0
  357. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/schemas/test.json +0 -0
  358. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/services/__init__.py +0 -0
  359. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/services/schema_import.py +0 -0
  360. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/triggers.py +0 -0
  361. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/urls.py +0 -0
  362. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja/utils.py +0 -0
  363. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja.egg-info/PKG-INFO +0 -0
  364. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja.egg-info/SOURCES.txt +0 -0
  365. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja.egg-info/dependency_links.txt +0 -0
  366. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja.egg-info/requires.txt +0 -0
  367. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkit_ninja.egg-info/top_level.txt +0 -0
  368. {formkit_ninja-2.2 → formkit_ninja-2.4}/formkitninja.yaml +0 -0
  369. {formkit_ninja-2.2 → formkit_ninja-2.4}/issue_22.json +0 -0
  370. {formkit_ninja-2.2 → formkit_ninja-2.4}/manage.py +0 -0
  371. {formkit_ninja-2.2 → formkit_ninja-2.4}/mkdocs.yml +0 -0
  372. {formkit_ninja-2.2 → formkit_ninja-2.4}/test_generator_real_data.py +0 -0
  373. {formkit_ninja-2.2 → formkit_ninja-2.4}/test_generator_with_data.py +0 -0
  374. {formkit_ninja-2.2 → formkit_ninja-2.4}/test_output.txt +0 -0
  375. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/__init__.py +0 -0
  376. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/api.py +0 -0
  377. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/asgi.py +0 -0
  378. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/__init__.py +0 -0
  379. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/admin/__init__.py +0 -0
  380. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/admin/mainform.py +0 -0
  381. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/admin.py +0 -0
  382. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/api/__init__.py +0 -0
  383. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/api/mainform.py +0 -0
  384. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/apps.py +0 -0
  385. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/migrations/0001_initial.py +0 -0
  386. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/migrations/__init__.py +0 -0
  387. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/models/__init__.py +0 -0
  388. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/models/mainform.py +0 -0
  389. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/models.py +0 -0
  390. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/schemas/__init__.py +0 -0
  391. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/schemas/mainform.py +0 -0
  392. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/schemas_in/__init__.py +0 -0
  393. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/schemas_in/mainform.py +0 -0
  394. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/signals.py +0 -0
  395. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/tests.py +0 -0
  396. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/complex_app/views.py +0 -0
  397. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/manage.py +0 -0
  398. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/__init__.py +0 -0
  399. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/admin/__init__.py +0 -0
  400. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/admin/tf611.py +0 -0
  401. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/api/__init__.py +0 -0
  402. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/api/tf611.py +0 -0
  403. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/apps.py +0 -0
  404. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/migrations/0001_initial_tf611_models.py +0 -0
  405. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/migrations/__init__.py +0 -0
  406. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/models/__init__.py +0 -0
  407. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/models/tf611.py +0 -0
  408. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/models.py +0 -0
  409. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/schemas/__init__.py +0 -0
  410. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/schemas/tf611.py +0 -0
  411. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/schemas_in/__init__.py +0 -0
  412. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/schemas_in/tf611.py +0 -0
  413. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/partisipa/signals.py +0 -0
  414. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/__init__.py +0 -0
  415. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/admin/__init__.py +0 -0
  416. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/admin/personalinfo.py +0 -0
  417. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/admin.py +0 -0
  418. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/api/__init__.py +0 -0
  419. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/api/personalinfo.py +0 -0
  420. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/apps.py +0 -0
  421. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/migrations/0001_initial.py +0 -0
  422. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/migrations/__init__.py +0 -0
  423. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/models/__init__.py +0 -0
  424. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/models/personalinfo.py +0 -0
  425. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/models.py +0 -0
  426. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/schemas/__init__.py +0 -0
  427. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/schemas/personalinfo.py +0 -0
  428. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/schemas_in/__init__.py +0 -0
  429. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/schemas_in/personalinfo.py +0 -0
  430. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/signals.py +0 -0
  431. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/tests.py +0 -0
  432. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/sample_app/views.py +0 -0
  433. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/settings.py +0 -0
  434. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/urls.py +0 -0
  435. {formkit_ninja-2.2 → formkit_ninja-2.4}/testproject/wsgi.py +0 -0
  436. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/__init__.py +0 -0
  437. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/conftest.py +0 -0
  438. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/factories.py +0 -0
  439. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/fixtures/partisipa_complex_form.yaml +0 -0
  440. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/fixtures/partisipa_sample.yaml +0 -0
  441. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/fixtures.py +0 -0
  442. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/form_submission/test_flag.py +0 -0
  443. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/form_submission/test_models_new.py +0 -0
  444. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/form_submission/test_separated_submission_annotations.py +0 -0
  445. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/form_submission/test_submission_annotations.py +0 -0
  446. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/helpers/__init__.py +0 -0
  447. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/helpers/schema_reproduction.py +0 -0
  448. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/complex_nested_form/__init__.py +0 -0
  449. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/complex_nested_form/admin.py +0 -0
  450. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/complex_nested_form/api.py +0 -0
  451. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/complex_nested_form/models.py +0 -0
  452. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/complex_nested_form/schemas.py +0 -0
  453. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/complex_nested_form/schemas_in.py +0 -0
  454. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/simple_form/__init__.py +0 -0
  455. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/simple_form/admin.py +0 -0
  456. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/simple_form/api.py +0 -0
  457. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/simple_form/models.py +0 -0
  458. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/simple_form/schemas.py +0 -0
  459. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/fixtures/expected_output/simple_form/schemas_in.py +0 -0
  460. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/partisipanodepath.py +0 -0
  461. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/partisipanodepath_rewritten.py +0 -0
  462. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_api_to_codegen.py +0 -0
  463. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_ast_validation.py +0 -0
  464. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_backward_compatibility.py +0 -0
  465. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_converters.py +0 -0
  466. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_converters_examples.py +0 -0
  467. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_converters_extended.py +0 -0
  468. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_database_generation.py +0 -0
  469. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_database_node_path.py +0 -0
  470. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_default_converters.py +0 -0
  471. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_end_to_end_generation.py +0 -0
  472. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_extensions.py +0 -0
  473. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_formatter.py +0 -0
  474. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_generation_pipeline.py +0 -0
  475. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_generator.py +0 -0
  476. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_generator_config.py +0 -0
  477. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_generator_config_database.py +0 -0
  478. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_integration_generator.py +0 -0
  479. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_management_generate_code.py +0 -0
  480. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_node_factory.py +0 -0
  481. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_node_registry.py +0 -0
  482. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_partisipa_architecture.py +0 -0
  483. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_plugins.py +0 -0
  484. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_repeater_config.py +0 -0
  485. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_schema_walker.py +0 -0
  486. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_template_loader.py +0 -0
  487. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/parser/test_tf611_database_driven.py +0 -0
  488. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/services/test_schema_import_service.py +0 -0
  489. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_admin_code_generation.py +0 -0
  490. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_admin_node_creation.py +0 -0
  491. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_admin_preview.py +0 -0
  492. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_api_errors.py +0 -0
  493. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_autocomplete.py +0 -0
  494. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_conditional_logic.py +0 -0
  495. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_data_loss_roundtrip.py +0 -0
  496. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_database_source_of_truth.py +0 -0
  497. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_datepicker.py +0 -0
  498. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_extracted_schemas.py +0 -0
  499. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_fields.py +0 -0
  500. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_formkit_in.py +0 -0
  501. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_group.json +0 -0
  502. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_hidden_node.py +0 -0
  503. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_integration.py +0 -0
  504. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_issue_22.py +0 -0
  505. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_jinja_template.py +0 -0
  506. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_make_name_valid.py +0 -0
  507. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_management.py +0 -0
  508. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_management_commands.py +0 -0
  509. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_migrations.py +0 -0
  510. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_nested_structures.py +0 -0
  511. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_notifications.py +0 -0
  512. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_parser.py +0 -0
  513. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_partisipa_reproduction.py +0 -0
  514. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_partisipa_yaml.py +0 -0
  515. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_positional_args.py +0 -0
  516. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_pw.py +0 -0
  517. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_python_models.py +0 -0
  518. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_repeater_generation.py +0 -0
  519. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_repeater_nested.py +0 -0
  520. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_signals.py +0 -0
  521. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_submission_models.py +0 -0
  522. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_textarea.py +0 -0
  523. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_tf611_api_creation.py +0 -0
  524. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_type_convert.py +0 -0
  525. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_utils.py +0 -0
  526. {formkit_ninja-2.2 → formkit_ninja-2.4}/tests/test_valid_django_id.py +0 -0
  527. {formkit_ninja-2.2 → formkit_ninja-2.4}/tox.ini +0 -0
@@ -0,0 +1,111 @@
1
+ name: Release
2
+
3
+ # Automatic PyPI release on a version tag.
4
+ #
5
+ # To cut a release:
6
+ # 1. Bump `version` in pyproject.toml on main, commit, merge.
7
+ # 2. Tag the merged commit with the SAME version (no "v" prefix), e.g.:
8
+ # git tag 2.5 && git push origin 2.5
9
+ # 3. This workflow verifies the tag, builds, publishes to PyPI, and creates
10
+ # a GitHub Release with auto-generated notes.
11
+ #
12
+ # Publishing uses PyPI Trusted Publishing (OIDC) — no API token secret.
13
+ # ONE-TIME SETUP (maintainer, on PyPI):
14
+ # pypi.org -> project formkit-ninja -> Settings -> Publishing ->
15
+ # "Add a new trusted publisher" (GitHub Actions):
16
+ # Owner: catalpainternational
17
+ # Repository: formkit-ninja
18
+ # Workflow: release.yml
19
+ # Environment: pypi
20
+ # (For the very first publish on a brand-new project name, add it as a
21
+ # "pending publisher" instead.)
22
+
23
+ on:
24
+ push:
25
+ tags:
26
+ - "[0-9]+.[0-9]+"
27
+ - "[0-9]+.[0-9]+.[0-9]+"
28
+
29
+ permissions:
30
+ contents: read
31
+
32
+ jobs:
33
+ verify:
34
+ name: Verify tag
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ with:
39
+ fetch-depth: 0
40
+ - name: Tag must equal pyproject version
41
+ run: |
42
+ tag="${GITHUB_REF_NAME}"
43
+ ver="$(grep -m1 '^version' pyproject.toml | sed -E 's/^version *= *"([^"]+)".*/\1/')"
44
+ echo "tag=$tag pyproject=$ver"
45
+ if [ "$tag" != "$ver" ]; then
46
+ echo "::error::Tag '$tag' does not match pyproject version '$ver'. Bump pyproject.toml to match the tag."
47
+ exit 1
48
+ fi
49
+ - name: Tagged commit must be on main
50
+ run: |
51
+ git fetch --no-tags --depth=100 origin main
52
+ if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
53
+ echo "::error::Tagged commit $GITHUB_SHA is not on main. Release only from merged, CI-green main."
54
+ exit 1
55
+ fi
56
+
57
+ build:
58
+ name: Build distributions
59
+ needs: verify
60
+ runs-on: ubuntu-latest
61
+ steps:
62
+ - uses: actions/checkout@v4
63
+ - name: Install uv
64
+ uses: astral-sh/setup-uv@v4
65
+ with:
66
+ enable-cache: true
67
+ - name: Build sdist + wheel
68
+ run: uv build
69
+ - name: Check metadata
70
+ run: uv run --with twine twine check dist/*
71
+ - uses: actions/upload-artifact@v4
72
+ with:
73
+ name: dist
74
+ path: dist/
75
+
76
+ publish:
77
+ name: Publish to PyPI
78
+ needs: build
79
+ runs-on: ubuntu-latest
80
+ environment:
81
+ name: pypi
82
+ url: https://pypi.org/project/formkit-ninja/
83
+ permissions:
84
+ id-token: write # OIDC for Trusted Publishing
85
+ steps:
86
+ - uses: actions/download-artifact@v4
87
+ with:
88
+ name: dist
89
+ path: dist/
90
+ - name: Publish
91
+ uses: pypa/gh-action-pypi-publish@release/v1
92
+
93
+ github-release:
94
+ name: GitHub Release
95
+ needs: publish
96
+ runs-on: ubuntu-latest
97
+ permissions:
98
+ contents: write
99
+ steps:
100
+ - uses: actions/download-artifact@v4
101
+ with:
102
+ name: dist
103
+ path: dist/
104
+ - name: Create GitHub Release
105
+ env:
106
+ GH_TOKEN: ${{ github.token }}
107
+ run: |
108
+ gh release create "$GITHUB_REF_NAME" dist/* \
109
+ --repo "$GITHUB_REPOSITORY" \
110
+ --title "$GITHUB_REF_NAME" \
111
+ --generate-notes
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.4] - 2026-06-10
9
+
10
+ ### Added
11
+
12
+ - **`code_scheme` tag for geographic inputs** — a metadata field on `FormKitSchemaNode`
13
+ recording which administrative-code scheme a Suco / Postu Admin / Munisipiu input's
14
+ values use, so legacy and new identifier schemes can coexist on the same forms without
15
+ ambiguity.
16
+ - Choices: `pnds` (current PNDS zTable IDs), `estrada` (timor-locations pre-INTL pcodes),
17
+ `intl2024` (new INTL string pcodes); nullable for non-geographic nodes.
18
+ - Carried through the full JSON ↔ Pydantic ↔ database round-trip, covering both
19
+ `option_group`-backed options and JS-backed `$getLocations()` inputs.
20
+ - Surfaced in the node payload for downstream consumers (e.g. partisipa-import); added
21
+ to the schema-node admin filter and change form.
22
+ - formkit-ninja only records the tag — it does not validate or translate option values.
23
+
24
+ ### Migrations
25
+
26
+ - `0043` — adds the `code_scheme` column to `FormKitSchemaNode` (and its history model).
27
+ - `0044` — backfills existing geographic nodes (matched by field name, `$getLocations()`,
28
+ or a geographic `$ida()` group) to `pnds`.
29
+
8
30
  ## [0.8.1] - 2026-02-02
9
31
 
10
32
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: formkit-ninja
3
- Version: 2.2
3
+ Version: 2.4
4
4
  Summary: A Django-Ninja backend to specify FormKit schemas
5
5
  Author-email: Josh Brooks <josh@catalpa.io>
6
6
  Requires-Python: <3.15,>=3.10
@@ -0,0 +1,47 @@
1
+ # Releasing
2
+
3
+ Releases are automated by [`.github/workflows/release.yml`](../.github/workflows/release.yml).
4
+ Pushing a version tag builds the package, publishes it to PyPI, and creates a
5
+ GitHub Release.
6
+
7
+ ## Cut a release
8
+
9
+ 1. Bump `version` in `pyproject.toml` on a branch and merge it to `main`
10
+ (update `CHANGELOG.md` in the same PR).
11
+ 2. Tag the merged commit with the **same** version — no `v` prefix, matching the
12
+ existing tag style (`2.3`, `2.4`, …):
13
+
14
+ ```bash
15
+ git checkout main && git pull
16
+ git tag 2.5
17
+ git push origin 2.5
18
+ ```
19
+
20
+ 3. The workflow then:
21
+ - **verifies** the tag equals `pyproject.toml`'s `version` and that the commit
22
+ is on `main` (so you can't accidentally release un-merged or mismatched code);
23
+ - **builds** the sdist + wheel (`uv build`) and `twine check`s them;
24
+ - **publishes** to PyPI via Trusted Publishing;
25
+ - **creates** a GitHub Release with auto-generated notes.
26
+
27
+ If the tag and `pyproject` version disagree, the run fails fast — bump and re-tag.
28
+
29
+ ## One-time setup (maintainer)
30
+
31
+ Publishing uses **PyPI Trusted Publishing (OIDC)** — there is no API token secret
32
+ to manage. On [pypi.org](https://pypi.org), open the `formkit-ninja` project →
33
+ **Settings → Publishing → Add a new trusted publisher** (GitHub Actions):
34
+
35
+ | Field | Value |
36
+ |--------------|--------------------------------|
37
+ | Owner | `catalpainternational` |
38
+ | Repository | `formkit-ninja` |
39
+ | Workflow | `release.yml` |
40
+ | Environment | `pypi` |
41
+
42
+ The `pypi` GitHub environment already exists; add reviewers/protection to it if
43
+ you want a manual approval gate before each publish.
44
+
45
+ > Prefer an API token instead? Replace the `publish` job's OIDC step with
46
+ > `pypa/gh-action-pypi-publish@release/v1` configured with
47
+ > `password: ${{ secrets.PYPI_API_TOKEN }}` and add that repo secret.
@@ -32,6 +32,41 @@ logger = logging.getLogger(__name__)
32
32
  # The key of the dict provided is a JSON field on the model
33
33
  JsonFieldDefn = dict[str, tuple[str | tuple[str, str], ...]]
34
34
 
35
+ # Composable field sets for FormKitSchemaNode admin forms.
36
+ # Rule: promoted props (icon, title, readonly, etc.) are model fields only in forms;
37
+ # _json_fields is for node-only keys (e.g. name, $formkit, placeholder). The model
38
+ # syncs promoted columns to/from node on save and in get_node_values().
39
+ COMMON_NODE_FIELDS = (
40
+ "label",
41
+ "description",
42
+ "icon",
43
+ "title",
44
+ "code_scheme",
45
+ "readonly",
46
+ "sections_schema",
47
+ "is_active",
48
+ "protected",
49
+ )
50
+ CODE_GEN_FIELDS = (
51
+ "django_field_type",
52
+ "django_field_args",
53
+ "django_field_positional_args",
54
+ "pydantic_field_type",
55
+ "extra_imports",
56
+ "validators",
57
+ "list_filter",
58
+ )
59
+ AUDIT_FIELDS = ("created_by", "updated_by")
60
+
61
+ # Code generation fieldset shown at bottom of change form; also used to exclude from default fieldset
62
+ CODE_GEN_FIELDSET_TITLE = "Code Generation (Source of Truth)"
63
+ CODE_GEN_FIELDSET_FIELDS = CODE_GEN_FIELDS + (
64
+ "django_code_preview",
65
+ "pydantic_code_preview",
66
+ "formkit_node_preview",
67
+ )
68
+ CODE_GEN_GROUPED_FIELDS = frozenset(CODE_GEN_FIELDSET_FIELDS)
69
+
35
70
 
36
71
  class ItemAdmin(admin.ModelAdmin):
37
72
  list_display = ("name",)
@@ -163,19 +198,7 @@ class FormKitBaseForm(JSONMappingMixin, forms.ModelForm):
163
198
 
164
199
  class Meta:
165
200
  model = models.FormKitSchemaNode
166
- fields = (
167
- "label",
168
- "description",
169
- "is_active",
170
- "protected",
171
- "django_field_type",
172
- "django_field_args",
173
- "django_field_positional_args",
174
- "pydantic_field_type",
175
- "extra_imports",
176
- "validators",
177
- "list_filter",
178
- )
201
+ fields = COMMON_NODE_FIELDS + CODE_GEN_FIELDS + AUDIT_FIELDS
179
202
 
180
203
  # Code Generation Overrides
181
204
  django_field_type = forms.CharField(required=False)
@@ -231,20 +254,7 @@ class FormKitSchemaComponentInline(admin.TabularInline):
231
254
  class FormKitNodeGroupForm(FormKitBaseForm):
232
255
  class Meta:
233
256
  model = models.FormKitSchemaNode
234
- fields = (
235
- "label",
236
- "description",
237
- "additional_props",
238
- "is_active",
239
- "protected",
240
- "django_field_type",
241
- "django_field_args",
242
- "django_field_positional_args",
243
- "pydantic_field_type",
244
- "extra_imports",
245
- "validators",
246
- "list_filter",
247
- )
257
+ fields = COMMON_NODE_FIELDS + ("additional_props", "option_group") + CODE_GEN_FIELDS + AUDIT_FIELDS
248
258
 
249
259
  _json_fields = {
250
260
  "node": ("name", ("formkit", "$formkit"), "if_condition", ("html_id", "id")),
@@ -258,21 +268,7 @@ class FormKitNodeGroupForm(FormKitBaseForm):
258
268
  class FormKitNodeForm(FormKitBaseForm):
259
269
  class Meta:
260
270
  model = models.FormKitSchemaNode
261
- fields = (
262
- "label",
263
- "description",
264
- "additional_props",
265
- "option_group",
266
- "is_active",
267
- "protected",
268
- "django_field_type",
269
- "django_field_args",
270
- "django_field_positional_args",
271
- "pydantic_field_type",
272
- "extra_imports",
273
- "validators",
274
- "list_filter",
275
- )
271
+ fields = COMMON_NODE_FIELDS + ("additional_props", "option_group", "add_label", "up_control", "down_control") + CODE_GEN_FIELDS + AUDIT_FIELDS
276
272
 
277
273
  _json_fields = {
278
274
  "node": (
@@ -325,21 +321,18 @@ class FormKitNodeForm(FormKitBaseForm):
325
321
 
326
322
 
327
323
  class FormKitNodeRepeaterForm(FormKitNodeForm):
324
+ """Repeater node form. add_label, up_control, down_control are model fields (parent);
325
+ itemsClass/itemClass are node-only and mapped here."""
326
+
328
327
  def get_json_fields(self) -> JsonFieldDefn:
329
328
  return {
330
329
  "node": (
331
- *(super()._json_fields["node"]),
332
- "addLabel",
333
- "upControl",
334
- "downControl",
330
+ *(super().get_json_fields()["node"]),
335
331
  "itemsClass",
336
332
  "itemClass",
337
333
  )
338
334
  }
339
335
 
340
- addLabel = forms.CharField(required=False)
341
- upControl = forms.BooleanField(required=False)
342
- downControl = forms.BooleanField(required=False)
343
336
  itemsClass = forms.CharField(required=False)
344
337
  itemClass = forms.CharField(required=False)
345
338
  max = forms.IntegerField(required=False)
@@ -441,14 +434,22 @@ NODE_CONFIG: dict[type | str, dict[str, Any]] = {
441
434
  "fieldsets": [
442
435
  (
443
436
  "Repeater field properties",
444
- {"fields": ("addLabel", "upControl", "downControl", "itemsClass", "itemClass")},
437
+ {"fields": ("add_label", "up_control", "down_control", "itemsClass", "itemClass")},
445
438
  )
446
439
  ],
447
440
  },
448
441
  formkit_schema.FormKitSchemaDOMNode: {"form": FormKitElementForm},
449
442
  formkit_schema.FormKitSchemaComponent: {"form": FormKitComponentForm},
450
443
  formkit_schema.FormKitSchemaCondition: {"form": FormKitConditionForm},
451
- formkit_schema.FormKitSchemaProps: {"form": FormKitNodeForm},
444
+ formkit_schema.FormKitSchemaProps: {
445
+ "form": FormKitNodeForm,
446
+ "fieldsets": [
447
+ (
448
+ "Display & behaviour",
449
+ {"fields": ("icon", "title", "readonly", "sections_schema")},
450
+ ),
451
+ ],
452
+ },
452
453
  }
453
454
 
454
455
  # Admin site registration continues below...
@@ -458,6 +459,7 @@ NODE_CONFIG: dict[type | str, dict[str, Any]] = {
458
459
  class FormKitSchemaNodeAdmin(admin.ModelAdmin):
459
460
  list_display = (
460
461
  "label",
462
+ "title",
461
463
  "is_active",
462
464
  "short_id",
463
465
  "node_type",
@@ -468,9 +470,17 @@ class FormKitSchemaNodeAdmin(admin.ModelAdmin):
468
470
  "protected",
469
471
  "created",
470
472
  )
471
- readonly_fields = ("django_code_preview", "pydantic_code_preview", "formkit_node_preview", "created", "updated")
473
+ readonly_fields = (
474
+ "django_code_preview",
475
+ "pydantic_code_preview",
476
+ "formkit_node_preview",
477
+ "created",
478
+ "updated",
479
+ "created_by",
480
+ "updated_by",
481
+ )
472
482
  search_fields = ["label", "description", "id"]
473
- list_filter = ("is_active", "node_type", "protected", "option_group", "created", "updated")
483
+ list_filter = ("is_active", "node_type", "protected", "code_scheme", "option_group", "created", "updated")
474
484
  list_select_related = ("option_group",)
475
485
  list_per_page = 50
476
486
  date_hierarchy = "created"
@@ -518,40 +528,15 @@ class FormKitSchemaNodeAdmin(admin.ModelAdmin):
518
528
  break
519
529
 
520
530
  grouped_fields: set[str] = reduce(operator.or_, (set(opts["fields"]) for _, opts in fieldsets), set())
521
- # Also include code generation fields to avoid them being duplicated in the default fieldset
522
- code_gen_fields = {
523
- "django_field_type",
524
- "django_field_args",
525
- "django_field_positional_args",
526
- "pydantic_field_type",
527
- "extra_imports",
528
- "validators",
529
- "list_filter",
530
- "django_code_preview",
531
- "pydantic_code_preview",
532
- "formkit_node_preview",
533
- }
534
- grouped_fields.update(code_gen_fields)
531
+ grouped_fields.update(CODE_GEN_GROUPED_FIELDS)
535
532
  fieldsets.insert(0, (None, {"fields": [f for f in self.get_fields(request, obj) if f not in grouped_fields]}))
536
533
 
537
- # Add Code Generation Source of Truth fieldset
538
534
  fieldsets.append(
539
535
  (
540
- "Code Generation (Source of Truth)",
536
+ CODE_GEN_FIELDSET_TITLE,
541
537
  {
542
- "fields": (
543
- "django_field_type",
544
- "django_field_args",
545
- "django_field_positional_args",
546
- "pydantic_field_type",
547
- "extra_imports",
548
- "validators",
549
- "list_filter",
550
- "django_code_preview",
551
- "pydantic_code_preview",
552
- "formkit_node_preview",
553
- ),
554
- "description": ("These values are the source of truth for code generation. If empty, they are auto-resolved on save from global configs."),
538
+ "fields": CODE_GEN_FIELDSET_FIELDS,
539
+ "description": "These values are the source of truth for code generation. If empty, they are auto-resolved on save from global configs.",
555
540
  },
556
541
  )
557
542
  )
@@ -116,6 +116,10 @@ class FormKitSchemaProps(BaseModel):
116
116
  prefixIcon: str | None = Field(None)
117
117
  icon: str | None = Field(None)
118
118
  title: str | None = Field(None)
119
+ # Metadata tag for the geographic pcode scheme an input emits
120
+ # (e.g. "estrada" legacy ints vs "intl2024" string pcodes). Carried through
121
+ # to the node JSON so downstream consumers (partisipa-import) can route by it.
122
+ code_scheme: str | None = Field(None)
119
123
  classes: str | dict[str, str] | None = Field(None)
120
124
  readonly: bool | None = Field(None)
121
125
  sectionsSchema: dict[str, Any] | None = Field(None)
@@ -0,0 +1,61 @@
1
+ # Generated by Django 4.2.27 on 2026-03-03 09:19
2
+
3
+ import pgtrigger.compiler
4
+ import pgtrigger.migrations
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+ dependencies = [
10
+ ("formkit_ninja", "0041_flag"),
11
+ ]
12
+
13
+ operations = [
14
+ pgtrigger.migrations.RemoveTrigger(
15
+ model_name="formkitschemanode",
16
+ name="insert_insert",
17
+ ),
18
+ pgtrigger.migrations.RemoveTrigger(
19
+ model_name="formkitschemanode",
20
+ name="update_update",
21
+ ),
22
+ migrations.AddField(
23
+ model_name="formkitschemanode",
24
+ name="list_filter",
25
+ field=models.BooleanField(default=False, help_text="Include this field in generated ModelAdmin.list_filter."),
26
+ ),
27
+ migrations.AddField(
28
+ model_name="formkitschemanodeevent",
29
+ name="list_filter",
30
+ field=models.BooleanField(default=False, help_text="Include this field in generated ModelAdmin.list_filter."),
31
+ ),
32
+ pgtrigger.migrations.AddTrigger(
33
+ model_name="formkitschemanode",
34
+ trigger=pgtrigger.compiler.Trigger(
35
+ name="insert_insert",
36
+ sql=pgtrigger.compiler.UpsertTriggerSql(
37
+ func='INSERT INTO "formkit_ninja_formkitschemanodeevent" ("add_label", "additional_props", "created", "created_by_id", "description", "django_field_args", "django_field_positional_args", "django_field_type", "down_control", "extra_imports", "icon", "id", "is_active", "label", "list_filter", "max", "min", "node", "node_type", "option_group_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "protected", "pydantic_field_type", "readonly", "sections_schema", "step", "text_content", "title", "track_change", "up_control", "updated", "updated_by_id", "validators") VALUES (NEW."add_label", NEW."additional_props", NEW."created", NEW."created_by_id", NEW."description", NEW."django_field_args", NEW."django_field_positional_args", NEW."django_field_type", NEW."down_control", NEW."extra_imports", NEW."icon", NEW."id", NEW."is_active", NEW."label", NEW."list_filter", NEW."max", NEW."min", NEW."node", NEW."node_type", NEW."option_group_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."protected", NEW."pydantic_field_type", NEW."readonly", NEW."sections_schema", NEW."step", NEW."text_content", NEW."title", NEW."track_change", NEW."up_control", NEW."updated", NEW."updated_by_id", NEW."validators"); RETURN NULL;',
38
+ hash="ca97f0a9bb68ffec610387b7dbb092bb006f4522",
39
+ operation="INSERT",
40
+ pgid="pgtrigger_insert_insert_72c4c",
41
+ table="formkit_ninja_formkitschemanode",
42
+ when="AFTER",
43
+ ),
44
+ ),
45
+ ),
46
+ pgtrigger.migrations.AddTrigger(
47
+ model_name="formkitschemanode",
48
+ trigger=pgtrigger.compiler.Trigger(
49
+ name="update_update",
50
+ sql=pgtrigger.compiler.UpsertTriggerSql(
51
+ condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
52
+ func='INSERT INTO "formkit_ninja_formkitschemanodeevent" ("add_label", "additional_props", "created", "created_by_id", "description", "django_field_args", "django_field_positional_args", "django_field_type", "down_control", "extra_imports", "icon", "id", "is_active", "label", "list_filter", "max", "min", "node", "node_type", "option_group_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "protected", "pydantic_field_type", "readonly", "sections_schema", "step", "text_content", "title", "track_change", "up_control", "updated", "updated_by_id", "validators") VALUES (NEW."add_label", NEW."additional_props", NEW."created", NEW."created_by_id", NEW."description", NEW."django_field_args", NEW."django_field_positional_args", NEW."django_field_type", NEW."down_control", NEW."extra_imports", NEW."icon", NEW."id", NEW."is_active", NEW."label", NEW."list_filter", NEW."max", NEW."min", NEW."node", NEW."node_type", NEW."option_group_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."protected", NEW."pydantic_field_type", NEW."readonly", NEW."sections_schema", NEW."step", NEW."text_content", NEW."title", NEW."track_change", NEW."up_control", NEW."updated", NEW."updated_by_id", NEW."validators"); RETURN NULL;',
53
+ hash="2e35d6535c17e41582d263abff78490ad83436e1",
54
+ operation="UPDATE",
55
+ pgid="pgtrigger_update_update_d7c99",
56
+ table="formkit_ninja_formkitschemanode",
57
+ when="AFTER",
58
+ ),
59
+ ),
60
+ ),
61
+ ]
@@ -0,0 +1,73 @@
1
+ # Generated by Django 4.2.27 on 2026-06-10 06:48
2
+
3
+ import pgtrigger.compiler
4
+ import pgtrigger.migrations
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+ dependencies = [
10
+ ("formkit_ninja", "0042_formkitschemanode_list_filter"),
11
+ ]
12
+
13
+ operations = [
14
+ pgtrigger.migrations.RemoveTrigger(
15
+ model_name="formkitschemanode",
16
+ name="insert_insert",
17
+ ),
18
+ pgtrigger.migrations.RemoveTrigger(
19
+ model_name="formkitschemanode",
20
+ name="update_update",
21
+ ),
22
+ migrations.AddField(
23
+ model_name="formkitschemanode",
24
+ name="code_scheme",
25
+ field=models.CharField(
26
+ blank=True,
27
+ choices=[("pnds", "PNDS (zTable IDs — current)"), ("estrada", "Estrada (timor-locations pre-INTL pcodes)"), ("intl2024", "intl2024 (INTL string pcodes)")],
28
+ help_text="Metadata tag for the geographic pcode scheme this input emits (e.g. Suco/Postu/Munisipiu values). Read by downstream consumers such as partisipa-import; formkit-ninja does not validate or translate the values themselves.",
29
+ max_length=32,
30
+ null=True,
31
+ ),
32
+ ),
33
+ migrations.AddField(
34
+ model_name="formkitschemanodeevent",
35
+ name="code_scheme",
36
+ field=models.CharField(
37
+ blank=True,
38
+ choices=[("pnds", "PNDS (zTable IDs — current)"), ("estrada", "Estrada (timor-locations pre-INTL pcodes)"), ("intl2024", "intl2024 (INTL string pcodes)")],
39
+ help_text="Metadata tag for the geographic pcode scheme this input emits (e.g. Suco/Postu/Munisipiu values). Read by downstream consumers such as partisipa-import; formkit-ninja does not validate or translate the values themselves.",
40
+ max_length=32,
41
+ null=True,
42
+ ),
43
+ ),
44
+ pgtrigger.migrations.AddTrigger(
45
+ model_name="formkitschemanode",
46
+ trigger=pgtrigger.compiler.Trigger(
47
+ name="insert_insert",
48
+ sql=pgtrigger.compiler.UpsertTriggerSql(
49
+ func='INSERT INTO "formkit_ninja_formkitschemanodeevent" ("add_label", "additional_props", "code_scheme", "created", "created_by_id", "description", "django_field_args", "django_field_positional_args", "django_field_type", "down_control", "extra_imports", "icon", "id", "is_active", "label", "list_filter", "max", "min", "node", "node_type", "option_group_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "protected", "pydantic_field_type", "readonly", "sections_schema", "step", "text_content", "title", "track_change", "up_control", "updated", "updated_by_id", "validators") VALUES (NEW."add_label", NEW."additional_props", NEW."code_scheme", NEW."created", NEW."created_by_id", NEW."description", NEW."django_field_args", NEW."django_field_positional_args", NEW."django_field_type", NEW."down_control", NEW."extra_imports", NEW."icon", NEW."id", NEW."is_active", NEW."label", NEW."list_filter", NEW."max", NEW."min", NEW."node", NEW."node_type", NEW."option_group_id", _pgh_attach_context(), NOW(), \'insert\', NEW."id", NEW."protected", NEW."pydantic_field_type", NEW."readonly", NEW."sections_schema", NEW."step", NEW."text_content", NEW."title", NEW."track_change", NEW."up_control", NEW."updated", NEW."updated_by_id", NEW."validators"); RETURN NULL;',
50
+ hash="f1c63d16eac3a47e69e99b9139042e29dfe77d36",
51
+ operation="INSERT",
52
+ pgid="pgtrigger_insert_insert_72c4c",
53
+ table="formkit_ninja_formkitschemanode",
54
+ when="AFTER",
55
+ ),
56
+ ),
57
+ ),
58
+ pgtrigger.migrations.AddTrigger(
59
+ model_name="formkitschemanode",
60
+ trigger=pgtrigger.compiler.Trigger(
61
+ name="update_update",
62
+ sql=pgtrigger.compiler.UpsertTriggerSql(
63
+ condition="WHEN (OLD.* IS DISTINCT FROM NEW.*)",
64
+ func='INSERT INTO "formkit_ninja_formkitschemanodeevent" ("add_label", "additional_props", "code_scheme", "created", "created_by_id", "description", "django_field_args", "django_field_positional_args", "django_field_type", "down_control", "extra_imports", "icon", "id", "is_active", "label", "list_filter", "max", "min", "node", "node_type", "option_group_id", "pgh_context_id", "pgh_created_at", "pgh_label", "pgh_obj_id", "protected", "pydantic_field_type", "readonly", "sections_schema", "step", "text_content", "title", "track_change", "up_control", "updated", "updated_by_id", "validators") VALUES (NEW."add_label", NEW."additional_props", NEW."code_scheme", NEW."created", NEW."created_by_id", NEW."description", NEW."django_field_args", NEW."django_field_positional_args", NEW."django_field_type", NEW."down_control", NEW."extra_imports", NEW."icon", NEW."id", NEW."is_active", NEW."label", NEW."list_filter", NEW."max", NEW."min", NEW."node", NEW."node_type", NEW."option_group_id", _pgh_attach_context(), NOW(), \'update\', NEW."id", NEW."protected", NEW."pydantic_field_type", NEW."readonly", NEW."sections_schema", NEW."step", NEW."text_content", NEW."title", NEW."track_change", NEW."up_control", NEW."updated", NEW."updated_by_id", NEW."validators"); RETURN NULL;',
65
+ hash="b235a3efcf5b151e2b55767023c943dee28517b0",
66
+ operation="UPDATE",
67
+ pgid="pgtrigger_update_update_d7c99",
68
+ table="formkit_ninja_formkitschemanode",
69
+ when="AFTER",
70
+ ),
71
+ ),
72
+ ),
73
+ ]
@@ -0,0 +1,71 @@
1
+ # Explicit backfill: existing geographic inputs predate the scheme split and
2
+ # therefore speak the "pnds" scheme (their submitted values are PNDS zTable IDs,
3
+ # e.g. a zSuco PK — NOT estrada or intl2024 pcodes). Tag them so "old = pnds" is
4
+ # recorded in data rather than inferred from a NULL. New (intl2024) forms are
5
+ # tagged at authoring time and are unaffected.
6
+ import pgtrigger
7
+ from django.db import migrations
8
+
9
+ # Updating a "protected" node is blocked by the protect_node_deletes_and_updates
10
+ # trigger; bypass it (and history noise) for this one-off backfill.
11
+ _IGNORE = ("formkit_ninja.FormKitSchemaNode:protect_node_deletes_and_updates",)
12
+
13
+ # Field names that, by convention, denote a Timor-Leste administrative-geography
14
+ # input in these schemas.
15
+ GEO_NAMES = {
16
+ "municipality",
17
+ "district",
18
+ "administrative_post",
19
+ "suco",
20
+ "aldeia",
21
+ "munisipiu",
22
+ "postu_administrativu",
23
+ "postuadministrativu",
24
+ "suku",
25
+ }
26
+ # `$ida("<group>", ...)` group names that resolve to a geographic option table.
27
+ GEO_IDA_GROUPS = {"munisipiu", "postuadministrativu", "suku", "aldeia"}
28
+
29
+
30
+ def _is_geographic(node):
31
+ if not isinstance(node, dict):
32
+ return False
33
+ name = node.get("name")
34
+ if isinstance(name, str) and name.lower() in GEO_NAMES:
35
+ return True
36
+ options = node.get("options")
37
+ if isinstance(options, str):
38
+ opts = options.strip()
39
+ if opts == "$getLocations()":
40
+ return True
41
+ if opts.startswith("$ida(") and any(g in opts.lower() for g in GEO_IDA_GROUPS):
42
+ return True
43
+ return False
44
+
45
+
46
+ def set_pnds(apps, schema_editor):
47
+ Node = apps.get_model("formkit_ninja", "FormKitSchemaNode")
48
+ to_update = []
49
+ for node in Node.objects.filter(code_scheme__isnull=True).iterator():
50
+ if _is_geographic(node.node):
51
+ node.code_scheme = "pnds"
52
+ to_update.append(node)
53
+ if to_update:
54
+ with pgtrigger.ignore(*_IGNORE):
55
+ Node.objects.bulk_update(to_update, ["code_scheme"])
56
+
57
+
58
+ def unset_pnds(apps, schema_editor):
59
+ Node = apps.get_model("formkit_ninja", "FormKitSchemaNode")
60
+ with pgtrigger.ignore(*_IGNORE):
61
+ Node.objects.filter(code_scheme="pnds").update(code_scheme=None)
62
+
63
+
64
+ class Migration(migrations.Migration):
65
+ dependencies = [
66
+ ("formkit_ninja", "0043_remove_formkitschemanode_insert_insert_and_more"),
67
+ ]
68
+
69
+ operations = [
70
+ migrations.RunPython(set_pnds, unset_pnds),
71
+ ]