openmodule 13.4.0__tar.gz → 13.5.0__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 (246) hide show
  1. {openmodule-13.4.0 → openmodule-13.5.0}/AUTHORS +1 -0
  2. {openmodule-13.4.0 → openmodule-13.5.0}/ChangeLog +7 -9
  3. {openmodule-13.4.0/openmodule.egg-info → openmodule-13.5.0}/PKG-INFO +1 -1
  4. {openmodule-13.4.0 → openmodule-13.5.0}/docs/migrations.md +6 -0
  5. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/core.py +2 -2
  6. openmodule-13.5.0/openmodule/database/database.py +169 -0
  7. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/database/env.py +0 -1
  8. openmodule-13.4.0/openmodule/database/database.py → openmodule-13.5.0/openmodule/database/migration.py +20 -120
  9. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/base.py +18 -3
  10. {openmodule-13.4.0 → openmodule-13.5.0/openmodule.egg-info}/PKG-INFO +1 -1
  11. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule.egg-info/SOURCES.txt +15 -1
  12. openmodule-13.5.0/openmodule.egg-info/pbr.json +1 -0
  13. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/database.py +16 -1
  14. {openmodule-13.4.0 → openmodule-13.5.0}/tests/invalid_database/alembic/env.py +1 -1
  15. {openmodule-13.4.0/tests/test_access_service_database → openmodule-13.5.0/tests/migration_double_column_delete_error}/alembic/env.py +1 -1
  16. openmodule-13.5.0/tests/migration_double_column_delete_error/alembic/versions/812a3e5b8517_initial.py +62 -0
  17. openmodule-13.5.0/tests/migration_double_column_delete_error/alembic/versions/a7ea100a784f_key_error.py +40 -0
  18. openmodule-13.5.0/tests/migration_double_column_delete_error/alembic.ini +85 -0
  19. openmodule-13.5.0/tests/migration_double_column_delete_error/makemigration.sh +21 -0
  20. openmodule-13.5.0/tests/migration_no_such_table_error/alembic/env.py +4 -0
  21. openmodule-13.5.0/tests/migration_no_such_table_error/alembic/versions/812a3e5b8517_initial.py +62 -0
  22. openmodule-13.5.0/tests/migration_no_such_table_error/alembic/versions/a7ea100a784f_no_such_table_error.py +39 -0
  23. openmodule-13.5.0/tests/migration_no_such_table_error/alembic.ini +85 -0
  24. openmodule-13.5.0/tests/migration_no_such_table_error/makemigration.sh +21 -0
  25. {openmodule-13.4.0 → openmodule-13.5.0}/tests/migration_test_database/alembic/env.py +1 -1
  26. openmodule-13.5.0/tests/test_access_service_database/alembic/env.py +4 -0
  27. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_alembic_migrations.py +3 -1
  28. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_checks.py +2 -2
  29. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_database/alembic/env.py +1 -1
  30. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_database.py +31 -3
  31. openmodule-13.5.0/tests/test_kv_store_database/alembic/__init__.py +0 -0
  32. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_database/alembic/env.py +1 -1
  33. openmodule-13.5.0/tests/test_kv_store_database/alembic/script.py.mako +24 -0
  34. openmodule-13.5.0/tests/test_kv_store_multiple_database/alembic/__init__.py +0 -0
  35. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_multiple_database/alembic/env.py +1 -1
  36. openmodule-13.5.0/tests/test_kv_store_multiple_database/alembic/script.py.mako +24 -0
  37. openmodule-13.4.0/openmodule/checks.py +0 -28
  38. openmodule-13.4.0/openmodule.egg-info/pbr.json +0 -1
  39. {openmodule-13.4.0 → openmodule-13.5.0}/.gitlab-ci.yml +0 -0
  40. {openmodule-13.4.0 → openmodule-13.5.0}/LICENSE +0 -0
  41. {openmodule-13.4.0 → openmodule-13.5.0}/README.md +0 -0
  42. {openmodule-13.4.0 → openmodule-13.5.0}/docs/access_service.md +0 -0
  43. {openmodule-13.4.0 → openmodule-13.5.0}/docs/anonymization.md +0 -0
  44. {openmodule-13.4.0 → openmodule-13.5.0}/docs/cleanup.md +0 -0
  45. {openmodule-13.4.0 → openmodule-13.5.0}/docs/coding_standard.md +0 -0
  46. {openmodule-13.4.0 → openmodule-13.5.0}/docs/commands.md +0 -0
  47. {openmodule-13.4.0 → openmodule-13.5.0}/docs/connection_status_listener.md +0 -0
  48. {openmodule-13.4.0 → openmodule-13.5.0}/docs/csv_export.md +0 -0
  49. {openmodule-13.4.0 → openmodule-13.5.0}/docs/database.md +0 -0
  50. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated.md +0 -0
  51. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/README.md +0 -0
  52. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/access_service/openmodule/models/access_service.py +0 -0
  53. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/access_service/openmodule/utils/access_service.py +0 -0
  54. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/access_service/openmodule_test/access_service.py +0 -0
  55. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/access_service/tests/test_utils_access_service.py +0 -0
  56. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/api/openmodule/utils/api.py +0 -0
  57. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/api/openmodule_test/api.py +0 -0
  58. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/api/tests/test_utils_api.py +0 -0
  59. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/package_reader/openmodule/utils/package_reader.py +0 -0
  60. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/package_reader/openmodule_test/fake_package_creator.py +0 -0
  61. {openmodule-13.4.0 → openmodule-13.5.0}/docs/deprecated_code/package_reader/tests/test_package_reader.py +0 -0
  62. {openmodule-13.4.0 → openmodule-13.5.0}/docs/event_sending.md +0 -0
  63. {openmodule-13.4.0 → openmodule-13.5.0}/docs/getting_started.md +0 -0
  64. {openmodule-13.4.0 → openmodule-13.5.0}/docs/health.md +0 -0
  65. {openmodule-13.4.0 → openmodule-13.5.0}/docs/images/broker.drawio.png +0 -0
  66. {openmodule-13.4.0 → openmodule-13.5.0}/docs/known_issues.md +0 -0
  67. {openmodule-13.4.0 → openmodule-13.5.0}/docs/package_reader.md +0 -0
  68. {openmodule-13.4.0 → openmodule-13.5.0}/docs/rpc.md +0 -0
  69. {openmodule-13.4.0 → openmodule-13.5.0}/docs/settings.md +0 -0
  70. {openmodule-13.4.0 → openmodule-13.5.0}/docs/settings_provider.md +0 -0
  71. {openmodule-13.4.0 → openmodule-13.5.0}/docs/testing.md +0 -0
  72. {openmodule-13.4.0 → openmodule-13.5.0}/docs/translation.md +0 -0
  73. {openmodule-13.4.0 → openmodule-13.5.0}/docs/utils.md +0 -0
  74. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/__init__.py +0 -0
  75. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/alert.py +0 -0
  76. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/config.py +0 -0
  77. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/connection_status.py +0 -0
  78. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/database/custom_types.py +0 -0
  79. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/dispatcher.py +0 -0
  80. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/health.py +0 -0
  81. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/logging.py +0 -0
  82. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/messaging.py +0 -0
  83. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/__init__.py +0 -0
  84. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/access_service.py +0 -0
  85. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/alert.py +0 -0
  86. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/io.py +0 -0
  87. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/kv_store.py +0 -0
  88. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/presence.py +0 -0
  89. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/privacy.py +0 -0
  90. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/rpc.py +0 -0
  91. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/settings.py +0 -0
  92. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/validation.py +0 -0
  93. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/models/vehicle.py +0 -0
  94. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/rpc/__init__.py +0 -0
  95. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/rpc/client.py +0 -0
  96. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/rpc/common.py +0 -0
  97. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/rpc/server.py +0 -0
  98. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/sentry.py +0 -0
  99. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/threading.py +0 -0
  100. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/__init__.py +0 -0
  101. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/access_service.py +0 -0
  102. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/charset.py +0 -0
  103. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/cleanup.py +0 -0
  104. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/csv_export.py +0 -0
  105. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/databox.py +0 -0
  106. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/db_helper.py +0 -0
  107. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/eventlog.py +0 -0
  108. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/io.py +0 -0
  109. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/kv_store.py +0 -0
  110. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/matching.py +0 -0
  111. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/misc_functions.py +0 -0
  112. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/package_reader.py +0 -0
  113. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/presence.py +0 -0
  114. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/schema.py +0 -0
  115. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/settings.py +0 -0
  116. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/translation.py +0 -0
  117. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule/utils/validation.py +0 -0
  118. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule.egg-info/dependency_links.txt +0 -0
  119. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule.egg-info/not-zip-safe +0 -0
  120. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule.egg-info/requires.txt +0 -0
  121. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule.egg-info/top_level.txt +0 -0
  122. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_commands/__init__.py +0 -0
  123. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_commands/setup.cfg +0 -0
  124. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_commands/setup.py +0 -0
  125. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_commands/translate.py +0 -0
  126. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/__init__.py +0 -0
  127. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/alert.py +0 -0
  128. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/connection_status.py +0 -0
  129. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/core.py +0 -0
  130. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/eventlistener.py +0 -0
  131. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/files.py +0 -0
  132. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/gate.py +0 -0
  133. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/health.py +0 -0
  134. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/interrupt.py +0 -0
  135. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/io_simulator.py +0 -0
  136. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/package_reader.py +0 -0
  137. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/presence.py +0 -0
  138. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/requirements.txt +0 -0
  139. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/rpc.py +0 -0
  140. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/settings.py +0 -0
  141. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/setup.cfg +0 -0
  142. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/setup.py +0 -0
  143. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/utils.py +0 -0
  144. {openmodule-13.4.0 → openmodule-13.5.0}/openmodule_test/zeromq.py +0 -0
  145. {openmodule-13.4.0 → openmodule-13.5.0}/requirements.txt +0 -0
  146. {openmodule-13.4.0 → openmodule-13.5.0}/setup.cfg +0 -0
  147. {openmodule-13.4.0 → openmodule-13.5.0}/setup.py +0 -0
  148. {openmodule-13.4.0 → openmodule-13.5.0}/test-requirements.txt +0 -0
  149. {openmodule-13.4.0 → openmodule-13.5.0}/tests/__init__.py +0 -0
  150. {openmodule-13.4.0 → openmodule-13.5.0}/tests/config.py +0 -0
  151. {openmodule-13.4.0 → openmodule-13.5.0}/tests/database_models_migration.py +0 -0
  152. {openmodule-13.4.0 → openmodule-13.5.0}/tests/database_models_test.py +0 -0
  153. {openmodule-13.4.0 → openmodule-13.5.0}/tests/invalid_database/alembic/README +0 -0
  154. {openmodule-13.4.0 → openmodule-13.5.0}/tests/invalid_database/alembic/__init__.py +0 -0
  155. {openmodule-13.4.0 → openmodule-13.5.0}/tests/invalid_database/alembic/script.py.mako +0 -0
  156. {openmodule-13.4.0 → openmodule-13.5.0}/tests/invalid_database/alembic/versions/ff26e54332f9_datetime_models.py +0 -0
  157. {openmodule-13.4.0 → openmodule-13.5.0}/tests/invalid_database/alembic.ini +0 -0
  158. {openmodule-13.4.0 → openmodule-13.5.0}/tests/invalid_database/makemigration.sh +0 -0
  159. {openmodule-13.4.0/tests/migration_test_database → openmodule-13.5.0/tests/migration_double_column_delete_error/alembic}/__init__.py +0 -0
  160. {openmodule-13.4.0/tests/migration_test_database → openmodule-13.5.0/tests/migration_double_column_delete_error}/alembic/script.py.mako +0 -0
  161. {openmodule-13.4.0/tests/migration_test_database → openmodule-13.5.0/tests/migration_no_such_table_error}/alembic/__init__.py +0 -0
  162. {openmodule-13.4.0/tests/test_access_service_database → openmodule-13.5.0/tests/migration_no_such_table_error}/alembic/script.py.mako +0 -0
  163. {openmodule-13.4.0/tests/migration_test_database/alembic/versions → openmodule-13.5.0/tests/migration_test_database}/__init__.py +0 -0
  164. {openmodule-13.4.0/tests/test_access_service_database → openmodule-13.5.0/tests/migration_test_database}/alembic/__init__.py +0 -0
  165. {openmodule-13.4.0/tests/test_database → openmodule-13.5.0/tests/migration_test_database}/alembic/script.py.mako +0 -0
  166. {openmodule-13.4.0 → openmodule-13.5.0}/tests/migration_test_database/alembic/versions/19789aa5361c_initial.py +0 -0
  167. {openmodule-13.4.0 → openmodule-13.5.0}/tests/migration_test_database/alembic/versions/19d887929ae7_alter.py +0 -0
  168. {openmodule-13.4.0/tests/test_database/alembic → openmodule-13.5.0/tests/migration_test_database/alembic/versions}/__init__.py +0 -0
  169. {openmodule-13.4.0 → openmodule-13.5.0}/tests/migration_test_database/alembic.ini +0 -0
  170. {openmodule-13.4.0 → openmodule-13.5.0}/tests/migration_test_database/alembic_migration_test_database.sqlite3 +0 -0
  171. {openmodule-13.4.0 → openmodule-13.5.0}/tests/migration_test_database/makemigration.sh +0 -0
  172. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/configs/config.py +0 -0
  173. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/configs/test_config.py +0 -0
  174. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/configs/test_config_1.py +0 -0
  175. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/standard_schemes/DEFAULT-10.yml +0 -0
  176. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/standard_schemes/DEFAULT-20.yml +0 -0
  177. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/standard_schemes/LEGACY-0.yml +0 -0
  178. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/translation/locale/de/LC_MESSAGES/translation.mo +0 -0
  179. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/translation/locale/de/LC_MESSAGES/translation.po +0 -0
  180. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/translation/locale/en/LC_MESSAGES/translation.mo +0 -0
  181. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/translation/locale/en/LC_MESSAGES/translation.po +0 -0
  182. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/translation/locale/translation.pot +0 -0
  183. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/translation/translate.sh +0 -0
  184. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/A-10.yml +0 -0
  185. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/A-20.yml +0 -0
  186. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/DEFAULT-10.yml +0 -0
  187. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/DEFAULT-20.yml +0 -0
  188. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/DEFAULT-30.yml +0 -0
  189. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/LEGACY-0.yml +0 -0
  190. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/TEST-10.yml +0 -0
  191. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/TEST-20.yml +0 -0
  192. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/TEST-30.yml +0 -0
  193. {openmodule-13.4.0 → openmodule-13.5.0}/tests/resources/utils_matching/TEST-40.yml +0 -0
  194. {openmodule-13.4.0/tests/test_kv_store_database → openmodule-13.5.0/tests/test_access_service_database}/alembic/__init__.py +0 -0
  195. {openmodule-13.4.0/tests/test_kv_store_database → openmodule-13.5.0/tests/test_access_service_database}/alembic/script.py.mako +0 -0
  196. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_access_service_database/alembic/versions/7bd4fcd38fde_removed_nfc_and_pin.py +0 -0
  197. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_access_service_database/alembic/versions/9ca98a2e5674_added_parksettings_id.py +0 -0
  198. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_access_service_database/alembic/versions/c821971f9230_initial.py +0 -0
  199. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_access_service_database/alembic.ini +0 -0
  200. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_access_service_database/makemigration.sh +0 -0
  201. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_alert.py +0 -0
  202. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_config.py +0 -0
  203. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_connection_status.py +0 -0
  204. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_core.py +0 -0
  205. {openmodule-13.4.0/tests/test_kv_store_multiple_database → openmodule-13.5.0/tests/test_database}/alembic/__init__.py +0 -0
  206. {openmodule-13.4.0/tests/test_kv_store_multiple_database → openmodule-13.5.0/tests/test_database}/alembic/script.py.mako +0 -0
  207. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_database/alembic/versions/32b8c728abbf_initial.py +0 -0
  208. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_database/alembic.ini +0 -0
  209. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_database/makemigration.sh +0 -0
  210. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_dispatcher.py +0 -0
  211. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_health.py +0 -0
  212. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_interrupt.py +0 -0
  213. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_io_listen.py +0 -0
  214. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_database/alembic/versions/9c5c944221f4_deprecated_kv_entry_example.py +0 -0
  215. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_database/alembic/versions/c55a69026a25_initial.py +0 -0
  216. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_database/alembic.ini +0 -0
  217. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_database/makemigration.sh +0 -0
  218. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_multiple_database/alembic/README +0 -0
  219. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_multiple_database/alembic/versions/cdb3214131a9_initial.py +0 -0
  220. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_multiple_database/alembic.ini +0 -0
  221. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_kv_store_multiple_database/makemigration.sh +0 -0
  222. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_messaging.py +0 -0
  223. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_mockrpcclient.py +0 -0
  224. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_model.py +0 -0
  225. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_rpc.py +0 -0
  226. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_schema.py +0 -0
  227. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_sentry.py +0 -0
  228. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_test_alert.py +0 -0
  229. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_test_gate.py +0 -0
  230. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_test_zeromq.py +0 -0
  231. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_access_service.py +0 -0
  232. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_charset.py +0 -0
  233. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_cleanup.py +0 -0
  234. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_csv_export.py +0 -0
  235. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_databox.py +0 -0
  236. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_eventlog.py +0 -0
  237. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_kv_store.py +0 -0
  238. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_kv_store_multiple.py +0 -0
  239. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_matching.py +0 -0
  240. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_misc_functions.py +0 -0
  241. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_package_reader.py +0 -0
  242. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_presence.py +0 -0
  243. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_settings.py +0 -0
  244. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_validation.py +0 -0
  245. {openmodule-13.4.0 → openmodule-13.5.0}/tests/test_utils_vehicle.py +0 -0
  246. {openmodule-13.4.0 → openmodule-13.5.0}/tox.ini +0 -0
@@ -1,6 +1,7 @@
1
1
  Kevin Koller <k.koller@accessio.at>
2
2
  Kevin Koller <k.koller@arivo.co>
3
3
  Matthias Mietschnig <m.mietschnig@arivo.co>
4
+ Maximilian Bialek <m.bialek@arivo.co>
4
5
  Philipp Reitter <i@philipp.ninja>
5
6
  Philipp Reitter <p.reitter@accessio.at>
6
7
  Philipp Reitter <p.reitter@gmail.com>
@@ -1,6 +1,12 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ v13.5.0
5
+ -------
6
+
7
+ * document breaking changes
8
+ * OM-405: remove database imports from non-database services + isolate migration process to exclude alembic import in the main process
9
+
4
10
  v13.4.0
5
11
  -------
6
12
 
@@ -16,6 +22,7 @@ v13.2.0
16
22
 
17
23
  * OM 187 Alembic migration test mixin
18
24
  * add a testcase for expiring session data while adding new models (noticed in OM-327)
25
+ * OM-184 Openmodule Database: Migration Backups and Fix in Operations "pre\_downgrade()" and "post\_downgrade()"
19
26
  * Aktualisierung der Dokumentation
20
27
  * OM-255
21
28
 
@@ -157,11 +164,6 @@ v11.1.0.rc5
157
164
  -----------
158
165
 
159
166
  * again no language set in testing
160
-
161
- v11.1.0.rc4
162
- -----------
163
-
164
- * arivo-schedule in public pip
165
167
  * removed mock rpcs from schema
166
168
 
167
169
  v11.0.3
@@ -213,7 +215,3 @@ v10.0.2.rc1
213
215
  -----------
214
216
 
215
217
  * Refactor for backend class for controller v2
216
-
217
- v10.0.1
218
- -------
219
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openmodule
3
- Version: 13.4.0
3
+ Version: 13.5.0
4
4
  Summary: Libraries for developing the arivo openmodule
5
5
  Home-page: https://gitlab.com/arivo-public/device-python/openmodule.git
6
6
  Author: ARIVO
@@ -1,5 +1,11 @@
1
1
  # Breaking Version Changes
2
2
 
3
+ ## 13.5.0:
4
+ * changes in env.py of alembic: <br>
5
+ `from openmodule.database.database import run_env_py` -> <br>
6
+ `from openmodule.database.migration import run_env_py`
7
+
8
+
3
9
  ## 13.0.0
4
10
  * access_service:
5
11
  * changes in AccessCheckAccess (removed media field) and AccessCheckResponse (removed error field)
@@ -11,7 +11,6 @@ from typing import Optional
11
11
 
12
12
  from openmodule.alert import AlertHandler
13
13
  from openmodule.config import validate_config_module
14
- from openmodule.database.database import Database
15
14
  from openmodule.dispatcher import ZMQMessageDispatcher
16
15
  from openmodule.health import HealthHandlerType, Healthz, HealthPingMessage
17
16
  from openmodule.logging import init_logging
@@ -23,7 +22,7 @@ from openmodule.connection_status import ConnectionStatusListener
23
22
 
24
23
 
25
24
  class OpenModuleCore(threading.Thread):
26
- database: Optional[Database] = None
25
+ database = None
27
26
 
28
27
  def __init__(self, context, config, messages_executor=None):
29
28
  super().__init__(target=get_thread_wrapper(self._run))
@@ -54,6 +53,7 @@ class OpenModuleCore(threading.Thread):
54
53
  match_type=True, register_schema=False)
55
54
 
56
55
  def init_database(self):
56
+ from openmodule.database.database import Database
57
57
  if self.config.TESTING:
58
58
  self.database = Database(self.config.DATABASE_FOLDER, self.config.NAME, alembic_path="../src/database")
59
59
  else:
@@ -0,0 +1,169 @@
1
+ import os
2
+ import threading
3
+ import types
4
+ from typing import Optional, Tuple
5
+
6
+ from sqlalchemy import create_engine, event
7
+ from sqlalchemy.engine import Engine
8
+ from sqlalchemy.orm import sessionmaker, Session
9
+ from sqlalchemy.pool import StaticPool
10
+
11
+ from multiprocessing import Process, Pipe, ProcessError
12
+ import traceback
13
+
14
+
15
+ class MigrationError(BaseException):
16
+ # Exception wrapper to create exception with traceback from child process
17
+ pass
18
+
19
+
20
+ class MigrationProcess(Process):
21
+ def __init__(self, *args, **kwargs):
22
+ super().__init__(*args, **kwargs)
23
+ self._parent_conn, self._child_conn = Pipe()
24
+ self._exception: Optional[Tuple[Exception, str]] = None
25
+
26
+ def run(self):
27
+ try:
28
+ super().run()
29
+ self._child_conn.send(None)
30
+ except Exception as e:
31
+ tb = traceback.format_exc()
32
+ self._child_conn.send((e, tb))
33
+
34
+ @property
35
+ def exception(self) -> Optional[Tuple[Exception, str]]:
36
+ if self._parent_conn.poll():
37
+ self._exception = self._parent_conn.recv()
38
+ return self._exception
39
+
40
+
41
+ @event.listens_for(Engine, "connect")
42
+ def set_sqlite_pragma(dbapi_connection, connection_record):
43
+ cursor = dbapi_connection.cursor()
44
+ cursor.execute("PRAGMA foreign_keys=ON")
45
+ cursor.close()
46
+
47
+
48
+ active_databases = {}
49
+
50
+
51
+ def execute_migration(engine: Engine, alembic_path: Optional[str] = None):
52
+ def isolated_migration_process():
53
+ nonlocal engine, alembic_path
54
+ from openmodule.database.migration import migrate_database
55
+ migrate_database(engine, alembic_path)
56
+
57
+ p = MigrationProcess(target=isolated_migration_process)
58
+ try:
59
+ p.start()
60
+ p.join(timeout=5 * 60) # default 5 min timeout -> exception/sentry in service
61
+ except ProcessError:
62
+ raise
63
+ finally:
64
+ if p.is_alive():
65
+ p.kill() # send SIGKILL
66
+ p.join() # wait for death
67
+ p.close() # release all resources associated with the process
68
+
69
+ if p.exitcode is None:
70
+ raise TimeoutError("The duration of the migration exceeded the timeout")
71
+
72
+ if p.exception is not None:
73
+ # piped exception with full traceback from child process -> if migration failed e.g. bad migration file
74
+ e, tb = p.exception
75
+ raise MigrationError(tb) from e
76
+
77
+
78
+ def database_path(db_folder, db_name):
79
+ return os.path.join(db_folder, db_name) + ".sqlite3"
80
+
81
+
82
+ def get_database(db_folder: str, name: str, alembic_path: Optional[str] = None):
83
+ global active_databases
84
+ tmp = database_path(db_folder, name)
85
+ assert active_databases.get(tmp) is None, f"database {tmp} already exists," \
86
+ f" check if it was shutdown before a new one was created"
87
+ os.makedirs(db_folder, exist_ok=True)
88
+ path = f"sqlite:///{tmp}"
89
+ engine = create_engine(path, poolclass=StaticPool, connect_args={'check_same_thread': False})
90
+
91
+ # migration executed in a separate process -> no alembic import in main process
92
+ execute_migration(engine, alembic_path)
93
+
94
+ active_databases[tmp] = engine
95
+
96
+ return engine
97
+
98
+
99
+ class DatabaseContext:
100
+ def __init__(self, database: 'Database', expire_on_commit=True):
101
+ self.database = database
102
+ self.expire_on_commit = expire_on_commit
103
+
104
+ def __enter__(self) -> Session:
105
+ return self.database.__enter__(expire_on_commit=self.expire_on_commit)
106
+
107
+ def __exit__(self, exc_type, exc_val, exc_tb):
108
+ return self.database.__exit__(exc_type, exc_val, exc_tb)
109
+
110
+
111
+ class SessionWrapper(Session):
112
+ _closed = False
113
+
114
+ def __getattribute__(self, item):
115
+ attr = super().__getattribute__(item)
116
+ if isinstance(attr, types.MethodType) and self._closed:
117
+ raise AssertionError("Session is already closed")
118
+ return attr
119
+
120
+ def close(self):
121
+ super().close()
122
+ self._closed = True
123
+
124
+
125
+ class Database:
126
+ active_session: Optional[Session]
127
+
128
+ def __init__(self, database_folder, name="database", alembic_path=None):
129
+ self.db_folder = database_folder
130
+ self.name = name
131
+ self._engine = get_database(database_folder, name, alembic_path)
132
+ self._session = sessionmaker(bind=self._engine, class_=SessionWrapper)
133
+ self.active_session = None
134
+ self.lock = threading.RLock()
135
+
136
+ def is_open(self):
137
+ return bool(self._session)
138
+
139
+ def shutdown(self):
140
+ assert self.is_open(), "database is already closed, you called shutdown twice somewhere"
141
+
142
+ with self.lock:
143
+ self._session = None
144
+ global active_databases
145
+ active_databases.pop(database_path(self.db_folder, self.name), None)
146
+
147
+ def __call__(self, expire_on_commit=True) -> DatabaseContext:
148
+ return DatabaseContext(self, expire_on_commit=expire_on_commit)
149
+
150
+ def __enter__(self, expire_on_commit=True) -> Session:
151
+ assert self._session, "Session is already closed"
152
+ self.lock.acquire()
153
+ self.active_session = self._session(expire_on_commit=expire_on_commit)
154
+ return self.active_session
155
+
156
+ def flush(self, objects=None):
157
+ assert self._session and self.active_session, "Session is already closed"
158
+ self.active_session.flush(objects)
159
+
160
+ def __exit__(self, exc_type, exc_val, exc_tb):
161
+ try:
162
+ if exc_type is None:
163
+ self.active_session.commit()
164
+ else:
165
+ self.active_session.rollback()
166
+ finally:
167
+ self.active_session.close()
168
+ self.active_session = None
169
+ self.lock.release()
@@ -4,7 +4,6 @@ from alembic import context
4
4
  from sqlalchemy import engine_from_config
5
5
  from sqlalchemy import pool
6
6
 
7
- from openmodule.checks import check_invalid_database_column_type
8
7
  from openmodule.database.custom_types import CustomType
9
8
 
10
9
  # this is the Alembic Config object, which provides
@@ -2,39 +2,18 @@ import datetime
2
2
  import os
3
3
  import shutil
4
4
  import sys
5
- import threading
6
- import types
7
5
  import warnings
8
6
  from typing import Optional
9
-
7
+
10
8
  from alembic import command, context
11
9
  from alembic.autogenerate import comparators, renderers
12
10
  from alembic.config import Config
13
11
  from alembic.operations import Operations, MigrateOperation
14
12
  from alembic.runtime.migration import MigrationContext
15
- from sqlalchemy import create_engine, event, MetaData
13
+
14
+ from sqlalchemy import MetaData, DateTime
16
15
  from sqlalchemy.engine import Engine
17
16
  from sqlalchemy.engine.reflection import Inspector
18
- from sqlalchemy.orm import sessionmaker, Session
19
- from sqlalchemy.pool import StaticPool
20
-
21
- from openmodule.checks import check_invalid_database_column_type
22
-
23
-
24
- def drop_alembic_tmp_tables(op):
25
- conn = op.get_bind()
26
- inspector = Inspector.from_engine(conn)
27
- tables = inspector.get_table_names()
28
- for table in tables:
29
- if table.startswith("_alembic_tmp_"):
30
- op.drop_table(table)
31
-
32
-
33
- @event.listens_for(Engine, "connect")
34
- def set_sqlite_pragma(dbapi_connection, connection_record):
35
- cursor = dbapi_connection.cursor()
36
- cursor.execute("PRAGMA foreign_keys=ON")
37
- cursor.close()
38
17
 
39
18
 
40
19
  @Operations.register_operation("pre_upgrade")
@@ -43,7 +22,9 @@ class PreUpgradeOp(MigrateOperation):
43
22
  def pre_upgrade(cls, operations, **kw):
44
23
  migration_context: MigrationContext = operations.migration_context
45
24
  basename, _ = os.path.splitext(os.path.basename(migration_context.connection.engine.url.database))
46
- filename = f"{basename}_{datetime.datetime.utcnow().strftime('%Y%m%d%H%M%S')}.sqlite3.backup"
25
+ timestamp = datetime.datetime.utcnow().strftime('%Y%m%d%H%M%S')
26
+ migration_revision = migration_context.get_current_revision()
27
+ filename = f"{basename}_{timestamp}_{migration_revision}.sqlite3.backup"
47
28
 
48
29
  shutil.copy(migration_context.connection.engine.url.database,
49
30
  os.path.join(os.path.dirname(migration_context.connection.engine.url.database), filename))
@@ -96,7 +77,12 @@ class PostDowngradeOp(MigrateOperation):
96
77
  def pre_upgrade(operations, operation):
97
78
  # NOTE: This is currently in sync with pre_downgrade, if you want to have
98
79
  # different behavior, you'll need to change th pre_downgrade function below
99
- drop_alembic_tmp_tables(operations)
80
+ conn = operations.get_bind()
81
+ inspector = Inspector.from_engine(conn)
82
+ tables = inspector.get_table_names()
83
+ for table in tables:
84
+ if table.startswith("_alembic_tmp_"):
85
+ operations.drop_table(table)
100
86
  operations.execute("PRAGMA foreign_keys = OFF")
101
87
 
102
88
 
@@ -143,7 +129,7 @@ def add_pre_upgrade_hooks(autogen_context, upgrade_ops, schemas):
143
129
  upgrade_ops.ops.append(PostUpgradeOp())
144
130
 
145
131
 
146
- def alembic_config(connection, alembic_path):
132
+ def alembic_config(connection: Engine, alembic_path: str):
147
133
  alembic_cfg = Config(os.path.join(alembic_path, "alembic.ini"),
148
134
  attributes={
149
135
  "configure_logging": False,
@@ -153,16 +139,15 @@ def alembic_config(connection, alembic_path):
153
139
  return alembic_cfg
154
140
 
155
141
 
156
- def migrate_database(connection, alembic_path=None):
142
+ def migrate_database(connection: Engine, alembic_path: Optional[str] = None):
157
143
  if alembic_path is None:
158
144
  alembic_path = os.path.join(os.getcwd(), "database")
159
145
  assert os.path.exists(os.path.abspath(alembic_path)), f"alembic path {os.path.abspath(alembic_path)} does not exist"
160
146
  config = alembic_config(connection, alembic_path)
161
147
  command.upgrade(config, "head")
162
- assert connection.execute("PRAGMA foreign_keys").fetchone()[0] == 1, "foreign keys are not enabled"
163
148
 
164
-
165
- active_databases = {}
149
+ check = connection.execute("PRAGMA foreign_keys").fetchone()
150
+ assert check is not None and check[0] == 1, "foreign keys are not enabled"
166
151
 
167
152
 
168
153
  def register_bases(bases, show_deprecation_warning=True):
@@ -193,92 +178,7 @@ def run_env_py(bases):
193
178
  del sys.modules["openmodule.database.env"] # unload the module, so we can re-run it (mostly testcases)
194
179
 
195
180
 
196
- def database_path(db_folder, db_name):
197
- return os.path.join(db_folder, db_name) + ".sqlite3"
198
-
199
-
200
- def get_database(db_folder: str, name: str, alembic_path=None):
201
- global active_databases
202
- tmp = database_path(db_folder, name)
203
- assert active_databases.get(tmp) is None, f"database {tmp} already exists," \
204
- f" check if it was shutdown before a new one was created"
205
- os.makedirs(db_folder, exist_ok=True)
206
- path = f"sqlite:///{tmp}"
207
- engine = create_engine(path, poolclass=StaticPool, connect_args={'check_same_thread': False})
208
- migrate_database(engine, alembic_path)
209
- active_databases[tmp] = engine
210
-
211
- return engine
212
-
213
-
214
- class DatabaseContext:
215
- def __init__(self, database: 'Database', expire_on_commit=True):
216
- self.database = database
217
- self.expire_on_commit = expire_on_commit
218
-
219
- def __enter__(self) -> Session:
220
- return self.database.__enter__(expire_on_commit=self.expire_on_commit)
221
-
222
- def __exit__(self, exc_type, exc_val, exc_tb):
223
- return self.database.__exit__(exc_type, exc_val, exc_tb)
224
-
225
-
226
- class SessionWrapper(Session):
227
- _closed = False
228
-
229
- def __getattribute__(self, item):
230
- attr = super().__getattribute__(item)
231
- if isinstance(attr, types.MethodType) and self._closed:
232
- raise AssertionError("Session is already closed")
233
- return attr
234
-
235
- def close(self):
236
- super().close()
237
- self._closed = True
238
-
239
-
240
- class Database:
241
- active_session: Optional[Session]
242
-
243
- def __init__(self, database_folder, name="database", alembic_path=None):
244
- self.db_folder = database_folder
245
- self.name = name
246
- self._engine = get_database(database_folder, name, alembic_path)
247
- self._session = sessionmaker(bind=self._engine, class_=SessionWrapper)
248
- self.active_session = None
249
- self.lock = threading.RLock()
250
-
251
- def is_open(self):
252
- return bool(self._session)
253
-
254
- def shutdown(self):
255
- assert self.is_open(), "database is already closed, you called shutdown twice somewhere"
256
-
257
- with self.lock:
258
- self._session = None
259
- global active_databases
260
- active_databases.pop(database_path(self.db_folder, self.name), None)
261
-
262
- def __call__(self, expire_on_commit=True) -> DatabaseContext:
263
- return DatabaseContext(self, expire_on_commit=expire_on_commit)
264
-
265
- def __enter__(self, expire_on_commit=True) -> Session:
266
- assert self._session, "Session is already closed"
267
- self.lock.acquire()
268
- self.active_session = self._session(expire_on_commit=expire_on_commit)
269
- return self.active_session
270
-
271
- def flush(self, objects=None):
272
- assert self._session and self.active_session, "Session is already closed"
273
- self.active_session.flush(objects)
274
-
275
- def __exit__(self, exc_type, exc_val, exc_tb):
276
- try:
277
- if exc_type is None:
278
- self.active_session.commit()
279
- else:
280
- self.active_session.rollback()
281
- finally:
282
- self.active_session.close()
283
- self.active_session = None
284
- self.lock.release()
181
+ def check_invalid_database_column_type(typ):
182
+ from openmodule import config
183
+ if config.run_checks():
184
+ assert not isinstance(typ, DateTime), "Do NOT use DateTime fields, use TZDateTime fields instead"
@@ -22,12 +22,27 @@ def _donotuse(v, *, default):
22
22
 
23
23
 
24
24
  if config.run_checks():
25
- from openmodule import checks
26
-
27
- meta_kwargs = {"metaclass": checks.CheckingOpenModuleModel}
25
+ class CheckingOpenModuleModel(type(BaseModel), type):
26
+ def __new__(mcs, name, bases, dct):
27
+ cls = super().__new__(mcs, name, bases, dct)
28
+
29
+ # noinspection PyUnresolvedReferences
30
+ for field_name, field in cls.__fields__.items():
31
+ if field.type_ == datetime:
32
+ assert "_timezone_validator" in field.class_validators, (
33
+ "datetime fields must use the timezone_validator to ensure all datetime values "
34
+ "are always naive. Otherwise runtime errors may occur depending on the isoformat used.\n"
35
+ f"In class {name}, please add:\n"
36
+ f' _tz_{field_name} = timezone_validator("{field_name}")'
37
+ )
38
+
39
+ return cls
40
+
41
+ meta_kwargs = {"metaclass": CheckingOpenModuleModel}
28
42
  else:
29
43
  meta_kwargs = {}
30
44
 
45
+
31
46
  ESCAPE_ASCII = re.compile(r'([^ -~])')
32
47
 
33
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openmodule
3
- Version: 13.4.0
3
+ Version: 13.5.0
4
4
  Summary: Libraries for developing the arivo openmodule
5
5
  Home-page: https://gitlab.com/arivo-public/device-python/openmodule.git
6
6
  Author: ARIVO
@@ -43,7 +43,6 @@ docs/deprecated_code/package_reader/tests/test_package_reader.py
43
43
  docs/images/broker.drawio.png
44
44
  openmodule/__init__.py
45
45
  openmodule/alert.py
46
- openmodule/checks.py
47
46
  openmodule/config.py
48
47
  openmodule/connection_status.py
49
48
  openmodule/core.py
@@ -63,6 +62,7 @@ openmodule.egg-info/top_level.txt
63
62
  openmodule/database/custom_types.py
64
63
  openmodule/database/database.py
65
64
  openmodule/database/env.py
65
+ openmodule/database/migration.py
66
66
  openmodule/models/__init__.py
67
67
  openmodule/models/access_service.py
68
68
  openmodule/models/alert.py
@@ -167,6 +167,20 @@ tests/invalid_database/alembic/__init__.py
167
167
  tests/invalid_database/alembic/env.py
168
168
  tests/invalid_database/alembic/script.py.mako
169
169
  tests/invalid_database/alembic/versions/ff26e54332f9_datetime_models.py
170
+ tests/migration_double_column_delete_error/alembic.ini
171
+ tests/migration_double_column_delete_error/makemigration.sh
172
+ tests/migration_double_column_delete_error/alembic/__init__.py
173
+ tests/migration_double_column_delete_error/alembic/env.py
174
+ tests/migration_double_column_delete_error/alembic/script.py.mako
175
+ tests/migration_double_column_delete_error/alembic/versions/812a3e5b8517_initial.py
176
+ tests/migration_double_column_delete_error/alembic/versions/a7ea100a784f_key_error.py
177
+ tests/migration_no_such_table_error/alembic.ini
178
+ tests/migration_no_such_table_error/makemigration.sh
179
+ tests/migration_no_such_table_error/alembic/__init__.py
180
+ tests/migration_no_such_table_error/alembic/env.py
181
+ tests/migration_no_such_table_error/alembic/script.py.mako
182
+ tests/migration_no_such_table_error/alembic/versions/812a3e5b8517_initial.py
183
+ tests/migration_no_such_table_error/alembic/versions/a7ea100a784f_no_such_table_error.py
170
184
  tests/migration_test_database/__init__.py
171
185
  tests/migration_test_database/alembic.ini
172
186
  tests/migration_test_database/alembic_migration_test_database.sqlite3
@@ -0,0 +1 @@
1
+ {"git_version": "84be0cd", "is_release": true}
@@ -9,7 +9,10 @@ from sqlalchemy import MetaData
9
9
  from sqlalchemy.ext.automap import automap_base
10
10
 
11
11
  from openmodule.config import settings
12
- from openmodule.database.database import Database, database_path, alembic_config
12
+ from openmodule.database.database import Database, database_path
13
+ from openmodule.database.migration import alembic_config
14
+
15
+ from unittest.mock import patch
13
16
 
14
17
  _first_start = True
15
18
 
@@ -37,6 +40,7 @@ class SQLiteTestMixin(TestCase):
37
40
  database_folder: str = None # defaults to settings.DATABASE_FOLDER
38
41
  alembic_path = "../src/database"
39
42
  database_name = "database"
43
+ main_process_migration = True # change if migration should be performed in a separate process
40
44
 
41
45
  @classmethod
42
46
  def get_database_folder(cls):
@@ -44,6 +48,15 @@ class SQLiteTestMixin(TestCase):
44
48
 
45
49
  @classmethod
46
50
  def setUpClass(cls) -> None:
51
+ if cls.main_process_migration is True:
52
+ from openmodule.database.migration import migrate_database
53
+ # instead of migrating db in a child process we 'mock' it in the main process to prevent some errors
54
+ cls.patcher = patch(
55
+ 'openmodule.database.database.execute_migration',
56
+ new=lambda x, y: migrate_database(x, y)
57
+ )
58
+ cls.patcher.start()
59
+
47
60
  # we only know which databases are in use on tear down, so truncating only works in teardown
48
61
  # but in order to not be annoyed by failed tests which left broken databases, we delete all databases
49
62
  # once initially
@@ -75,6 +88,8 @@ class SQLiteTestMixin(TestCase):
75
88
  cls.database.shutdown()
76
89
  os.unlink(database_path(cls.get_database_folder(), cls.database_name))
77
90
  super().tearDownClass()
91
+ if cls.main_process_migration is True:
92
+ cls.patcher.stop()
78
93
 
79
94
 
80
95
  class AlembicMigrationTestMixin(SQLiteTestMixin):
@@ -1,7 +1,7 @@
1
1
  from sqlalchemy import Column, Integer, DateTime
2
2
  from sqlalchemy.ext.declarative import declarative_base
3
3
 
4
- from openmodule.database.database import run_env_py
4
+ from openmodule.database.migration import run_env_py
5
5
 
6
6
  Base = declarative_base()
7
7
 
@@ -1,4 +1,4 @@
1
- from openmodule.database.database import run_env_py
1
+ from openmodule.database.migration import run_env_py
2
2
  from tests.test_utils_access_service import Base
3
3
 
4
4
  run_env_py([Base])
@@ -0,0 +1,62 @@
1
+ """initial
2
+
3
+ Revision ID: 812a3e5b8517
4
+ Revises:
5
+ Create Date: 2024-05-23 10:26:28.032845
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+ from openmodule.database.custom_types import JSONEncodedDict
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = '812a3e5b8517'
14
+ down_revision = None
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade():
20
+ # ### commands auto generated by Alembic - please adjust! ###
21
+ op.pre_upgrade()
22
+ op.create_table('test_access_model',
23
+ sa.Column('key', sa.String(), nullable=False),
24
+ sa.Column('e_tag', sa.Integer(), nullable=False),
25
+ sa.Column('customer_id', sa.String(), nullable=True),
26
+ sa.Column('car_id', sa.String(), nullable=True),
27
+ sa.Column('group_id', sa.String(), nullable=True),
28
+ sa.Column('parksettings_id', sa.String(), nullable=True),
29
+ sa.Column('access_infos', JSONEncodedDict(), nullable=True),
30
+ sa.Column('lpr_id', sa.String(), nullable=True),
31
+ sa.Column('lpr_id_search', sa.String(), nullable=True),
32
+ sa.Column('lpr_country', sa.String(), nullable=True),
33
+ sa.Column('matching_scheme', sa.String(), nullable=True),
34
+ sa.Column('matching_version', sa.Integer(), nullable=True),
35
+ sa.Column('qr_id', sa.String(), nullable=True),
36
+ sa.Column('regex', sa.String(), nullable=True),
37
+ sa.PrimaryKeyConstraint('e_tag')
38
+ )
39
+ with op.batch_alter_table('test_access_model', schema=None) as batch_op:
40
+ batch_op.create_index(batch_op.f('ix_test_access_model_e_tag'), ['e_tag'], unique=False)
41
+ batch_op.create_index(batch_op.f('ix_test_access_model_key'), ['key'], unique=True)
42
+ batch_op.create_index(batch_op.f('ix_test_access_model_lpr_id_search'), ['lpr_id_search'], unique=False)
43
+ batch_op.create_index(batch_op.f('ix_test_access_model_qr_id'), ['qr_id'], unique=False)
44
+ batch_op.create_index(batch_op.f('ix_test_access_model_regex'), ['regex'], unique=False)
45
+
46
+ op.post_upgrade()
47
+ # ### end Alembic commands ###
48
+
49
+
50
+ def downgrade():
51
+ # ### commands auto generated by Alembic - please adjust! ###
52
+ op.pre_downgrade()
53
+ with op.batch_alter_table('test_access_model', schema=None) as batch_op:
54
+ batch_op.drop_index(batch_op.f('ix_test_access_model_regex'))
55
+ batch_op.drop_index(batch_op.f('ix_test_access_model_qr_id'))
56
+ batch_op.drop_index(batch_op.f('ix_test_access_model_lpr_id_search'))
57
+ batch_op.drop_index(batch_op.f('ix_test_access_model_key'))
58
+ batch_op.drop_index(batch_op.f('ix_test_access_model_e_tag'))
59
+
60
+ op.drop_table('test_access_model')
61
+ op.post_downgrade()
62
+ # ### end Alembic commands ###