openmodule 14.1.0__tar.gz → 14.2.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 (253) hide show
  1. {openmodule-14.1.0 → openmodule-14.2.0}/ChangeLog +21 -10
  2. {openmodule-14.1.0 → openmodule-14.2.0}/PKG-INFO +1 -1
  3. {openmodule-14.1.0 → openmodule-14.2.0}/docs/testing.md +17 -0
  4. {openmodule-14.1.0 → openmodule-14.2.0}/docs/utils.md +22 -1
  5. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/access_service.py +5 -0
  6. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/base.py +5 -19
  7. openmodule-14.2.0/openmodule/models/signals.py +43 -0
  8. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/settings.py +9 -0
  9. openmodule-14.2.0/openmodule/utils/signal_listener.py +174 -0
  10. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule.egg-info/PKG-INFO +1 -1
  11. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule.egg-info/SOURCES.txt +4 -0
  12. openmodule-14.2.0/openmodule.egg-info/pbr.json +1 -0
  13. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule.egg-info/requires.txt +1 -1
  14. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_commands/__init__.py +6 -3
  15. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_commands/translate.py +7 -5
  16. openmodule-14.2.0/openmodule_test/signal_simulator.py +58 -0
  17. {openmodule-14.1.0 → openmodule-14.2.0}/requirements.txt +1 -1
  18. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_model.py +1 -11
  19. openmodule-14.2.0/tests/test_utils_signal.py +230 -0
  20. openmodule-14.1.0/openmodule.egg-info/pbr.json +0 -1
  21. {openmodule-14.1.0 → openmodule-14.2.0}/.gitlab-ci.yml +0 -0
  22. {openmodule-14.1.0 → openmodule-14.2.0}/AUTHORS +0 -0
  23. {openmodule-14.1.0 → openmodule-14.2.0}/LICENSE +0 -0
  24. {openmodule-14.1.0 → openmodule-14.2.0}/README.md +0 -0
  25. {openmodule-14.1.0 → openmodule-14.2.0}/docs/access_service.md +0 -0
  26. {openmodule-14.1.0 → openmodule-14.2.0}/docs/anonymization.md +0 -0
  27. {openmodule-14.1.0 → openmodule-14.2.0}/docs/cleanup.md +0 -0
  28. {openmodule-14.1.0 → openmodule-14.2.0}/docs/coding_standard.md +0 -0
  29. {openmodule-14.1.0 → openmodule-14.2.0}/docs/commands.md +0 -0
  30. {openmodule-14.1.0 → openmodule-14.2.0}/docs/connection_status_listener.md +0 -0
  31. {openmodule-14.1.0 → openmodule-14.2.0}/docs/csv_export.md +0 -0
  32. {openmodule-14.1.0 → openmodule-14.2.0}/docs/database.md +0 -0
  33. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated.md +0 -0
  34. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/README.md +0 -0
  35. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/access_service/openmodule/models/access_service.py +0 -0
  36. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/access_service/openmodule/utils/access_service.py +0 -0
  37. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/access_service/openmodule_test/access_service.py +0 -0
  38. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/access_service/tests/test_utils_access_service.py +0 -0
  39. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/api/openmodule/utils/api.py +0 -0
  40. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/api/openmodule_test/api.py +0 -0
  41. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/api/tests/test_utils_api.py +0 -0
  42. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/package_reader/openmodule/utils/package_reader.py +0 -0
  43. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/package_reader/openmodule_test/fake_package_creator.py +0 -0
  44. {openmodule-14.1.0 → openmodule-14.2.0}/docs/deprecated_code/package_reader/tests/test_package_reader.py +0 -0
  45. {openmodule-14.1.0 → openmodule-14.2.0}/docs/event_sending.md +0 -0
  46. {openmodule-14.1.0 → openmodule-14.2.0}/docs/getting_started.md +0 -0
  47. {openmodule-14.1.0 → openmodule-14.2.0}/docs/health.md +0 -0
  48. {openmodule-14.1.0 → openmodule-14.2.0}/docs/images/broker.drawio.png +0 -0
  49. {openmodule-14.1.0 → openmodule-14.2.0}/docs/known_issues.md +0 -0
  50. {openmodule-14.1.0 → openmodule-14.2.0}/docs/migrations.md +0 -0
  51. {openmodule-14.1.0 → openmodule-14.2.0}/docs/package_reader.md +0 -0
  52. {openmodule-14.1.0 → openmodule-14.2.0}/docs/rpc.md +0 -0
  53. {openmodule-14.1.0 → openmodule-14.2.0}/docs/sentry.md +0 -0
  54. {openmodule-14.1.0 → openmodule-14.2.0}/docs/settings.md +0 -0
  55. {openmodule-14.1.0 → openmodule-14.2.0}/docs/settings_provider.md +0 -0
  56. {openmodule-14.1.0 → openmodule-14.2.0}/docs/translation.md +0 -0
  57. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/__init__.py +0 -0
  58. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/alert.py +0 -0
  59. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/config.py +0 -0
  60. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/connection_status.py +0 -0
  61. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/core.py +0 -0
  62. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/database/custom_types.py +0 -0
  63. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/database/database.py +0 -0
  64. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/database/env.py +0 -0
  65. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/database/migration.py +0 -0
  66. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/dispatcher.py +0 -0
  67. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/health.py +0 -0
  68. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/logging.py +0 -0
  69. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/messaging.py +0 -0
  70. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/__init__.py +0 -0
  71. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/alert.py +0 -0
  72. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/io.py +0 -0
  73. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/kv_store.py +0 -0
  74. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/presence.py +0 -0
  75. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/privacy.py +0 -0
  76. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/rpc.py +0 -0
  77. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/settings.py +0 -0
  78. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/validation.py +0 -0
  79. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/models/vehicle.py +0 -0
  80. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/rpc/__init__.py +0 -0
  81. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/rpc/client.py +0 -0
  82. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/rpc/common.py +0 -0
  83. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/rpc/server.py +0 -0
  84. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/sentry.py +0 -0
  85. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/threading.py +0 -0
  86. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/__init__.py +0 -0
  87. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/access_service.py +0 -0
  88. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/charset.py +0 -0
  89. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/cleanup.py +0 -0
  90. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/csv_export.py +0 -0
  91. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/databox.py +0 -0
  92. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/db_helper.py +0 -0
  93. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/eventlog.py +0 -0
  94. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/io.py +0 -0
  95. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/kv_store.py +0 -0
  96. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/matching.py +0 -0
  97. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/misc_functions.py +0 -0
  98. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/package_reader.py +0 -0
  99. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/presence.py +0 -0
  100. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/schema.py +0 -0
  101. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/translation.py +0 -0
  102. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule/utils/validation.py +0 -0
  103. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule.egg-info/dependency_links.txt +0 -0
  104. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule.egg-info/not-zip-safe +0 -0
  105. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule.egg-info/top_level.txt +0 -0
  106. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_commands/setup.cfg +0 -0
  107. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_commands/setup.py +0 -0
  108. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/__init__.py +0 -0
  109. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/alert.py +0 -0
  110. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/connection_status.py +0 -0
  111. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/core.py +0 -0
  112. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/database.py +0 -0
  113. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/eventlistener.py +0 -0
  114. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/files.py +0 -0
  115. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/gate.py +0 -0
  116. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/health.py +0 -0
  117. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/interrupt.py +0 -0
  118. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/io_simulator.py +0 -0
  119. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/package_reader.py +0 -0
  120. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/presence.py +0 -0
  121. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/requirements.txt +0 -0
  122. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/rpc.py +0 -0
  123. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/sentry.py +0 -0
  124. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/settings.py +0 -0
  125. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/setup.cfg +0 -0
  126. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/setup.py +0 -0
  127. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/utils.py +0 -0
  128. {openmodule-14.1.0 → openmodule-14.2.0}/openmodule_test/zeromq.py +0 -0
  129. {openmodule-14.1.0 → openmodule-14.2.0}/setup.cfg +0 -0
  130. {openmodule-14.1.0 → openmodule-14.2.0}/setup.py +0 -0
  131. {openmodule-14.1.0 → openmodule-14.2.0}/test-requirements.txt +0 -0
  132. {openmodule-14.1.0 → openmodule-14.2.0}/tests/__init__.py +0 -0
  133. {openmodule-14.1.0 → openmodule-14.2.0}/tests/config.py +0 -0
  134. {openmodule-14.1.0 → openmodule-14.2.0}/tests/database_models_migration.py +0 -0
  135. {openmodule-14.1.0 → openmodule-14.2.0}/tests/database_models_test.py +0 -0
  136. {openmodule-14.1.0 → openmodule-14.2.0}/tests/invalid_database/alembic/README +0 -0
  137. {openmodule-14.1.0 → openmodule-14.2.0}/tests/invalid_database/alembic/__init__.py +0 -0
  138. {openmodule-14.1.0 → openmodule-14.2.0}/tests/invalid_database/alembic/env.py +0 -0
  139. {openmodule-14.1.0 → openmodule-14.2.0}/tests/invalid_database/alembic/script.py.mako +0 -0
  140. {openmodule-14.1.0 → openmodule-14.2.0}/tests/invalid_database/alembic/versions/ff26e54332f9_datetime_models.py +0 -0
  141. {openmodule-14.1.0 → openmodule-14.2.0}/tests/invalid_database/alembic.ini +0 -0
  142. {openmodule-14.1.0 → openmodule-14.2.0}/tests/invalid_database/makemigration.sh +0 -0
  143. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_double_column_delete_error/alembic/__init__.py +0 -0
  144. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_double_column_delete_error/alembic/env.py +0 -0
  145. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_double_column_delete_error/alembic/script.py.mako +0 -0
  146. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_double_column_delete_error/alembic/versions/812a3e5b8517_initial.py +0 -0
  147. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_double_column_delete_error/alembic/versions/a7ea100a784f_key_error.py +0 -0
  148. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_double_column_delete_error/alembic.ini +0 -0
  149. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_double_column_delete_error/makemigration.sh +0 -0
  150. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_no_such_table_error/alembic/__init__.py +0 -0
  151. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_no_such_table_error/alembic/env.py +0 -0
  152. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_no_such_table_error/alembic/script.py.mako +0 -0
  153. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_no_such_table_error/alembic/versions/812a3e5b8517_initial.py +0 -0
  154. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_no_such_table_error/alembic/versions/a7ea100a784f_no_such_table_error.py +0 -0
  155. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_no_such_table_error/alembic.ini +0 -0
  156. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_no_such_table_error/makemigration.sh +0 -0
  157. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/__init__.py +0 -0
  158. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/alembic/__init__.py +0 -0
  159. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/alembic/env.py +0 -0
  160. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/alembic/script.py.mako +0 -0
  161. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/alembic/versions/19789aa5361c_initial.py +0 -0
  162. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/alembic/versions/19d887929ae7_alter.py +0 -0
  163. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/alembic/versions/__init__.py +0 -0
  164. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/alembic.ini +0 -0
  165. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/alembic_migration_test_database.sqlite3 +0 -0
  166. {openmodule-14.1.0 → openmodule-14.2.0}/tests/migration_test_database/makemigration.sh +0 -0
  167. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/configs/config.py +0 -0
  168. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/configs/test_config.py +0 -0
  169. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/configs/test_config_1.py +0 -0
  170. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/standard_schemes/DEFAULT-10.yml +0 -0
  171. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/standard_schemes/DEFAULT-20.yml +0 -0
  172. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/standard_schemes/LEGACY-0.yml +0 -0
  173. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/translation/locale/de/LC_MESSAGES/translation.mo +0 -0
  174. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/translation/locale/de/LC_MESSAGES/translation.po +0 -0
  175. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/translation/locale/en/LC_MESSAGES/translation.mo +0 -0
  176. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/translation/locale/en/LC_MESSAGES/translation.po +0 -0
  177. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/translation/locale/translation.pot +0 -0
  178. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/translation/translate.sh +0 -0
  179. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/A-10.yml +0 -0
  180. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/A-20.yml +0 -0
  181. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/DEFAULT-10.yml +0 -0
  182. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/DEFAULT-20.yml +0 -0
  183. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/DEFAULT-30.yml +0 -0
  184. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/LEGACY-0.yml +0 -0
  185. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/TEST-10.yml +0 -0
  186. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/TEST-20.yml +0 -0
  187. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/TEST-30.yml +0 -0
  188. {openmodule-14.1.0 → openmodule-14.2.0}/tests/resources/utils_matching/TEST-40.yml +0 -0
  189. {openmodule-14.1.0 → openmodule-14.2.0}/tests/sentry_main.py +0 -0
  190. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_access_service_database/alembic/__init__.py +0 -0
  191. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_access_service_database/alembic/env.py +0 -0
  192. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_access_service_database/alembic/script.py.mako +0 -0
  193. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_access_service_database/alembic/versions/7bd4fcd38fde_removed_nfc_and_pin.py +0 -0
  194. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_access_service_database/alembic/versions/9ca98a2e5674_added_parksettings_id.py +0 -0
  195. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_access_service_database/alembic/versions/c821971f9230_initial.py +0 -0
  196. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_access_service_database/alembic.ini +0 -0
  197. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_access_service_database/makemigration.sh +0 -0
  198. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_alembic_migrations.py +0 -0
  199. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_alert.py +0 -0
  200. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_checks.py +0 -0
  201. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_config.py +0 -0
  202. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_connection_status.py +0 -0
  203. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_core.py +0 -0
  204. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_database/alembic/__init__.py +0 -0
  205. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_database/alembic/env.py +0 -0
  206. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_database/alembic/script.py.mako +0 -0
  207. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_database/alembic/versions/32b8c728abbf_initial.py +0 -0
  208. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_database/alembic.ini +0 -0
  209. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_database/makemigration.sh +0 -0
  210. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_database.py +0 -0
  211. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_dispatcher.py +0 -0
  212. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_health.py +0 -0
  213. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_interrupt.py +0 -0
  214. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_io_listen.py +0 -0
  215. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_database/alembic/__init__.py +0 -0
  216. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_database/alembic/env.py +0 -0
  217. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_database/alembic/script.py.mako +0 -0
  218. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_database/alembic/versions/9c5c944221f4_deprecated_kv_entry_example.py +0 -0
  219. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_database/alembic/versions/c55a69026a25_initial.py +0 -0
  220. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_database/alembic.ini +0 -0
  221. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_database/makemigration.sh +0 -0
  222. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_multiple_database/alembic/README +0 -0
  223. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_multiple_database/alembic/__init__.py +0 -0
  224. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_multiple_database/alembic/env.py +0 -0
  225. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_multiple_database/alembic/script.py.mako +0 -0
  226. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_multiple_database/alembic/versions/cdb3214131a9_initial.py +0 -0
  227. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_multiple_database/alembic.ini +0 -0
  228. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_kv_store_multiple_database/makemigration.sh +0 -0
  229. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_logging.py +0 -0
  230. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_messaging.py +0 -0
  231. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_mockrpcclient.py +0 -0
  232. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_rpc.py +0 -0
  233. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_schema.py +0 -0
  234. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_sentry.py +0 -0
  235. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_test_alert.py +0 -0
  236. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_test_gate.py +0 -0
  237. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_test_zeromq.py +0 -0
  238. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_access_service.py +0 -0
  239. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_charset.py +0 -0
  240. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_cleanup.py +0 -0
  241. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_csv_export.py +0 -0
  242. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_databox.py +0 -0
  243. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_eventlog.py +0 -0
  244. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_kv_store.py +0 -0
  245. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_kv_store_multiple.py +0 -0
  246. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_matching.py +0 -0
  247. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_misc_functions.py +0 -0
  248. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_package_reader.py +0 -0
  249. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_presence.py +0 -0
  250. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_settings.py +0 -0
  251. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_validation.py +0 -0
  252. {openmodule-14.1.0 → openmodule-14.2.0}/tests/test_utils_vehicle.py +0 -0
  253. {openmodule-14.1.0 → openmodule-14.2.0}/tox.ini +0 -0
@@ -1,6 +1,27 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ v14.2.0
5
+ -------
6
+
7
+ * OM-1001: CostEntryData from settings models, added valid\_from and valid\_to to AccessCheckAccess and type hints for io/signals and io/inputs settings
8
+ * docs
9
+ * fixed testcase
10
+ * maybe fixing openmodule\_test
11
+
12
+ v14.2.0.rc0
13
+ -----------
14
+
15
+ * improvements for signal simulator
16
+ * test util for signals
17
+ * fixed testcase
18
+ * added SignalListener
19
+
20
+ v14.1.1
21
+ -------
22
+
23
+ * OM-1000: added --library flag for openmodule commands so "\_\_READABLE\_NAME" and "\_\_DESCRIPTION" are not added there
24
+
4
25
  v14.1.0
5
26
  -------
6
27
 
@@ -176,9 +197,6 @@ v12.0.0.rc0
176
197
  -----------
177
198
 
178
199
  * Removed parking\_area\_id from AccessCheckAccess changed gate permission check in AccessService to new behavior
179
- * removed Gate and GateType (now from settings models)
180
- * fixed testcases and removed backend (deprecated in v11)
181
- * newer settings-models
182
200
 
183
201
  v11.1.1
184
202
  -------
@@ -197,10 +215,3 @@ v11.0.3
197
215
  * Fixed typo, added compute\_id as label to all metrics, convert all label values to string
198
216
  * touch to get rid of skip ci on my commit
199
217
  * docs update [skip ci]
200
- * main test function deprecated and documentation for main tests added
201
-
202
- v11.0.2
203
- -------
204
-
205
- * fixed get\_no\_exception in SettingsMocker
206
- * Update database.md [skip ci]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openmodule
3
- Version: 14.1.0
3
+ Version: 14.2.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
@@ -267,6 +267,23 @@ presence_sim.enter(self.presence_sim.vehicle().lpr("A", "G ARIVO1"))
267
267
  on_enter.wait_for_call()
268
268
  ```
269
269
 
270
+ ### SignalSimulator
271
+
272
+ Util class for simulating signals
273
+
274
+ ```python
275
+ signal_simulator = SignalSimulator(lambda x: core().publish(x, "signal"))
276
+ # add_signal registers signals for RPC callbacks but does not emit signal message
277
+ signal_simulator.add_signal(False, None, SignalType.open, gate="einfahrt") # generates correct signal einfahrt-open
278
+ signal_simulator.add_signal(True, {"a": "b"}, SignalType.custom, signal_name="custom1")
279
+ # (change and) emit signals message
280
+ signal_simulator.set_signal("einfahrt-open", True)
281
+ signal_simulator.set_signal("custom1", True, {"a": "c"})
282
+ # register signal RPCs with callbacks from signal_simulator, which will automatically answer with correct response
283
+ rpc_server.register_handler("signal", "trigger_signals", TriggerSignalsRequest, TriggerSignalsResponse,
284
+ signal_simulator.trigger_signal_callback, register_schema=False)
285
+ ```
286
+
270
287
  ### MockRPCClient
271
288
 
272
289
  This is a fake RPCClient where you can either specify callback functions for RPCs or even the responses.
@@ -15,7 +15,28 @@ presence_listener = PresenceListener(core.messages)
15
15
  presence_listener.on_enter.append(some_function)
16
16
  ```
17
17
 
18
- ### Databox Upload
18
+ ## Signals
19
+
20
+ Helper class for listening on signals.
21
+ ```python
22
+ from openmodule.utils.signal_listener import SignalListener, FilterType
23
+
24
+ signal_listener = SignalListener(core.messages, core.rpc_client)
25
+ # register a listener for a signal with a filter_type specifying when the function should be called and optional tag
26
+ signal_listener.add_listener("gate1-open", FilterType.any_edge, some_function, tag="tag1")
27
+ signal_listener.add_listener("gate2-present_decision", FilterType.any_change, some_function2, tag="tag2")
28
+ # get the current value (and additional_data) of a signal, if unknown then RPC is called to get value
29
+ value = signal_listener.get_value("gate1-open")
30
+ value, additional_data = signal_listener.get_value_and_additional_data("gate1-open")
31
+ # trigger resending of signals via trigger_signals RPC for registered signals with specific tag
32
+ # or all registered signals if tag is None
33
+ signal_listener.trigger_signals(tag="tag1")
34
+ # remove listeners with specific tag or all if tag is None
35
+ signal_listener.remove_listener(tag="tag1")
36
+ ```
37
+
38
+
39
+ ## Databox Upload
19
40
 
20
41
  In the openmodule we have a utils function to simplify the upload with the databox service. The prerequisite is,
21
42
  that the upload folder `/data/om_service_databox_1/upload` is mounted correctly in the compose file to the `settings.DATABOX_UPLOAD_DIR` (default: `/upload`)
@@ -65,12 +65,17 @@ class AccessCheckAccess(OpenModuleModel):
65
65
  category: AccessCategory # category used for sorting and eventlog
66
66
  used_medium: Medium # medium of the access
67
67
  access_data: Dict # complete access data, will be used only for display and debug purposes
68
+ valid_from: Optional[datetime] # access is valid from this time. Only used for reservations
69
+ valid_to: Optional[datetime] # access is valid until this time. Only used for reservations
68
70
 
69
71
  accepted: bool # if access service decided access can enter
70
72
  reject_reason: Optional[AccessCheckRejectReason] # only if not accepted: reason for not accepted
71
73
  # additional infos shown in events if reject reason is "custom". Required if reject_reason == "custom"
72
74
  supplementary_infos: Optional[str]
73
75
 
76
+ _tz_valid_from = timezone_validator("valid_from")
77
+ _tz_valid_to = timezone_validator("valid_to")
78
+
74
79
  @root_validator(skip_on_failure=True)
75
80
  def root_validation(cls, values):
76
81
  # if category is handauf, medium_display_name must be set
@@ -5,16 +5,17 @@ from datetime import datetime
5
5
  from decimal import Decimal
6
6
  from enum import Enum
7
7
  from json.encoder import ESCAPE_ASCII
8
- from typing import Optional, Union
8
+ from typing import Optional, Union, Dict
9
9
 
10
10
  import orjson
11
11
  import zmq
12
12
  from dateutil.tz import UTC
13
- from pydantic import Field, BaseModel, validator, root_validator
13
+ from pydantic import Field, BaseModel, validator
14
14
  from pydantic.main import ROOT_KEY
15
15
 
16
16
  from openmodule import config, sentry
17
17
  from openmodule.config import settings
18
+ from settings_models.settings.common import CostEntryData as SettingsModelsCostEntryData
18
19
 
19
20
 
20
21
  def _donotuse(v, *, default):
@@ -171,20 +172,5 @@ class Gateway(OpenModuleModel):
171
172
  return f"{self.gate}/{self.direction}"
172
173
 
173
174
 
174
- class CostEntryData(OpenModuleModel):
175
- entry_type: str
176
- value: Optional[Union[int, str]]
177
- group: Optional[str]
178
- account_id: str
179
- source: Optional[str] # if None, source will be set to service name on default: e.g. "service_iocontroller"
180
- source_id: Optional[str]
181
- idempotency_key: Optional[str]
182
-
183
- @root_validator
184
- def set_value_type(cls, values):
185
- if values["entry_type"] in ["rate_change", "rate_validation", "partial_rate_change"]:
186
- values["value"] = str(values["value"])
187
- elif values["entry_type"] in ["static_cost", "pending_static_cost", "amount_validation", "time_validation"
188
- "payment"]:
189
- values["value"] = int(values["value"])
190
- return values
175
+ # to be not breaking
176
+ CostEntryData = SettingsModelsCostEntryData
@@ -0,0 +1,43 @@
1
+ from enum import Enum
2
+ from typing import Optional, Dict, Union, List
3
+
4
+ from openmodule.models.base import ZMQMessage, OpenModuleModel
5
+
6
+
7
+ class SignalType(str, Enum):
8
+ permanently_closed = "permanently_closed"
9
+ shortterm_full = "shortterm_full"
10
+ open = "open"
11
+ present_raw = "present_raw"
12
+ present_decision = "present_decision"
13
+ traffic_light_green = "traffic_light_green"
14
+ traffic_light_red = "traffic_light_red"
15
+ area_full = "area_full"
16
+ parkinglot_full = "parkinglot_full"
17
+ custom = "custom"
18
+
19
+
20
+ class SignalMessage(ZMQMessage):
21
+ signal: str
22
+ type: Union[SignalType, str] # union so we can add new types without updating all services using signals
23
+ gate: Optional[str]
24
+ parking_area_id: Optional[str]
25
+ value: bool
26
+ additional_data: Optional[Dict]
27
+
28
+
29
+ class GetSignalValueRequest(OpenModuleModel):
30
+ signal: str
31
+
32
+
33
+ class GetSignalValueResponse(OpenModuleModel):
34
+ value: bool
35
+ additional_data: Optional[Dict]
36
+
37
+
38
+ class TriggerSignalsRequest(OpenModuleModel):
39
+ signals: List[str] # list of signals which current value should be sent
40
+
41
+
42
+ class TriggerSignalsResponse(OpenModuleModel):
43
+ success: bool
@@ -10,6 +10,7 @@ from settings_models.settings.device_keys import PairingKey, Certificate, Otp
10
10
  from settings_models.settings.enforcement import EnforcementSettings
11
11
  from settings_models.settings.gate_control import GateMode, DayMode
12
12
  from settings_models.settings.intercom import IntercomSettings
13
+ from settings_models.settings.io import SignalDefinitions, InputDefinitions
13
14
 
14
15
  from openmodule import sentry
15
16
  from openmodule.core import core
@@ -195,6 +196,14 @@ class SettingsProvider:
195
196
  def get(self, key: Literal["feature_flags"]) -> dict: # pragma: no cover
196
197
  ...
197
198
 
199
+ @overload
200
+ def get(self, key: Literal["io/signals"]) -> SignalDefinitions: # pragma: no cover
201
+ ...
202
+
203
+ @overload
204
+ def get(self, key: Literal["io/inputs"]) -> InputDefinitions: # pragma: no cover
205
+ ...
206
+
198
207
  def get(self, key: str, scope: str = "", custom_type: Optional[Type[T]] = None) -> Optional[T]:
199
208
  key_scope = join_key(key, scope)
200
209
  with self._cache_lock:
@@ -0,0 +1,174 @@
1
+ import logging
2
+ import threading
3
+ from enum import Enum
4
+ from typing import Optional, Dict, Callable, List, Tuple
5
+
6
+ import zmq
7
+ from openmodule.dispatcher import MessageDispatcher
8
+ from openmodule.models.signals import SignalMessage, SignalType, GetSignalValueRequest, GetSignalValueResponse, \
9
+ TriggerSignalsRequest, TriggerSignalsResponse
10
+ from openmodule.rpc import RPCClient
11
+
12
+
13
+ class ChangeType(str, Enum):
14
+ rising_edge = "rising_edge" # value changed from 0 to 1
15
+ falling_edge = "falling_edge" # value change from 1 to 0
16
+ data_change = "data_change" # value is 1, additional data is set and no rising_edge
17
+ none = "none" # value unchanged and not data_change
18
+
19
+
20
+ class FilterType(str, Enum):
21
+ rising_edge = "rising_edge" # only rising edges
22
+ falling_edge = "falling_edge" # only falling edges
23
+ any_edge = "any_edge" # rising and falling edges
24
+ data_change = "data_change" # all messages with value true (including rising edges) and additional_data set
25
+ any_change = "any_change" # rising and falling edges and additional_data changes
26
+ any = "any" # no filtering of changes (also when nothing changes)
27
+
28
+ def matches_change(self, change_type: ChangeType) -> bool:
29
+ if self.value == FilterType.rising_edge:
30
+ return change_type == ChangeType.rising_edge
31
+ elif self.value == FilterType.falling_edge:
32
+ return change_type == ChangeType.falling_edge
33
+ elif self.value == FilterType.any_edge:
34
+ return change_type in [ChangeType.rising_edge, ChangeType.falling_edge]
35
+ elif self.value == FilterType.data_change:
36
+ return change_type in [ChangeType.rising_edge, ChangeType.data_change]
37
+ elif self.value == FilterType.any_change:
38
+ return change_type != ChangeType.none
39
+ elif self.value == FilterType.any:
40
+ return True
41
+ else:
42
+ raise TypeError("unknown change type")
43
+
44
+
45
+ class Signal:
46
+ def __init__(self, signal_message: SignalMessage, change_type: ChangeType):
47
+ self.signal: str = signal_message.signal
48
+ self.type: SignalType = signal_message.type
49
+ self.value: bool = signal_message.value
50
+ self.additional_data: Optional[Dict] = signal_message.additional_data
51
+ self.gate: Optional[str] = signal_message.gate
52
+ self.parking_area_id: Optional[str] = signal_message.parking_area_id
53
+ self.change_type: ChangeType = change_type
54
+
55
+
56
+ class Listener:
57
+ def __init__(self, signal_name: str, filter_type: FilterType, callback: Callable[[Signal], None],
58
+ tag: Optional[str]):
59
+ self.signal_name = signal_name
60
+ self.filter_type = filter_type
61
+ self.callback = callback
62
+ self.tag = tag
63
+
64
+ def matches(self, signal_name: str, change_type: ChangeType) -> bool:
65
+ return self.signal_name == signal_name and self.filter_type.matches_change(change_type)
66
+
67
+
68
+ class SignalListener:
69
+ def __init__(self, dispatcher: MessageDispatcher, rpc_client: RPCClient):
70
+ assert not dispatcher.is_multi_threaded, (
71
+ "you cannot use a multithreaded message dispatcher for the SignalListener. It is highly reliant "
72
+ "on receiving messages in the correct order!"
73
+ )
74
+ self.current_states: Dict[str, Tuple[bool, Optional[dict]]] = dict()
75
+ self.listeners: List[Listener] = list()
76
+ self.listeners_lock = threading.Lock()
77
+ self.log = logging.getLogger(self.__class__.__name__)
78
+ self.rpc_client = rpc_client
79
+ dispatcher.register_handler("signal", SignalMessage, self._on_signal_message, match_type=False)
80
+
81
+ def add_listener(self, signal_name: str, filter_type: FilterType, callback: Callable[[Signal], None],
82
+ tag: Optional[str]):
83
+ """
84
+ Calls the given callback method whenever a signal message is received and the circumstances fulfill the given
85
+ filter_type
86
+ :param signal_name: signal name that needs to experience a rising edge to call the callback
87
+ :param filter_type: One of the available FilterType
88
+ :param callback: the function that is called when a rising edge occurs on listen_to
89
+ :param tag: a tag to group listeners for later removal
90
+ """
91
+ with self.listeners_lock:
92
+ self.listeners.append(Listener(signal_name, filter_type, callback, tag))
93
+
94
+ def remove_listener(self, tag: Optional[str] = None):
95
+ """
96
+ :param tag: all listeners with this tag are removed. If no tag is given, all listeners are removed
97
+ """
98
+ with self.listeners_lock:
99
+ self.listeners = [listener for listener in self.listeners if tag is not None and listener.tag != tag]
100
+
101
+ def get_value(self, signal_name: str) -> bool:
102
+ """
103
+ returns the current value of a signal.
104
+ If no value is available yet, it will be requested via rpc.
105
+ If no answer to RPC, log exception/error and return False
106
+ :param signal_name: Name of signal to get value from
107
+ """
108
+ return self.get_value_and_additional_data(signal_name)[0]
109
+
110
+ def get_value_and_additional_data(self, signal_name: str) -> Tuple[bool, Optional[dict]]:
111
+ """
112
+ returns the current value of a signal including additional_data.
113
+ If no value is available yet, it will be requested via rpc.
114
+ If no answer to RPC, log exception/error and return (False, None)
115
+ :param signal_name: Name of signal to get value from
116
+ """
117
+ if signal_name not in self.current_states:
118
+ try:
119
+ res = self.rpc_client.rpc("signal", "get_value", GetSignalValueRequest(signal=signal_name),
120
+ GetSignalValueResponse, timeout=1.0)
121
+ self.current_states[signal_name] = (res.value, res.additional_data)
122
+ except RPCClient.Exception:
123
+ self.log.exception("Error while getting signal value. Assuming False.")
124
+ self.current_states[signal_name] = (False, None)
125
+
126
+ return self.current_states[signal_name]
127
+
128
+ def trigger_signals(self, tag: Optional[str] = None, timeout: float = 3.0) -> bool:
129
+ """
130
+ :param tag: if given, only signals of listeners with given tag are triggered
131
+ """
132
+ try:
133
+ with self.listeners_lock:
134
+ if tag is None:
135
+ signals_to_trigger = list({l.signal_name for l in self.listeners})
136
+ else:
137
+ signals_to_trigger = list({l.signal_name for l in self.listeners if l.tag == tag})
138
+ res = self.rpc_client.rpc("signal", "trigger_signals", TriggerSignalsRequest(signals=signals_to_trigger),
139
+ TriggerSignalsResponse, timeout)
140
+ if not res.success:
141
+ self.log.error("Failed to trigger all registered signals.")
142
+ return res.success
143
+ except RPCClient.Exception:
144
+ self.log.exception("Error while triggering signals.")
145
+ return False
146
+
147
+ def _on_signal_message(self, message: SignalMessage):
148
+ """
149
+ This handler receives all IO Messages, saves any changes and calls any listeners registered in the IoListener
150
+ """
151
+ old_state = self.current_states.get(message.signal)
152
+ old_value = old_state and old_state[0] # only value without additional_data
153
+ self.current_states[message.signal] = (message.value, message.additional_data)
154
+ if old_value != message.value and message.value:
155
+ change_type = ChangeType.rising_edge
156
+ elif old_value != message.value:
157
+ change_type = ChangeType.falling_edge
158
+ elif message.value and message.additional_data:
159
+ change_type = ChangeType.data_change
160
+ else:
161
+ change_type = ChangeType.none
162
+ with self.listeners_lock:
163
+ for listener in self.listeners:
164
+ """
165
+ Handles the registered listeners the same as the dispatcher.
166
+ Is copied here because all messages are needed to keep current_states up to date.
167
+ """
168
+ if listener.matches(message.signal, change_type):
169
+ try:
170
+ listener.callback(Signal(message, change_type))
171
+ except zmq.ContextTerminated:
172
+ raise
173
+ except Exception as e:
174
+ self.log.exception("Error in signal callback")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openmodule
3
- Version: 14.1.0
3
+ Version: 14.2.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
@@ -74,6 +74,7 @@ openmodule/models/presence.py
74
74
  openmodule/models/privacy.py
75
75
  openmodule/models/rpc.py
76
76
  openmodule/models/settings.py
77
+ openmodule/models/signals.py
77
78
  openmodule/models/validation.py
78
79
  openmodule/models/vehicle.py
79
80
  openmodule/rpc/__init__.py
@@ -96,6 +97,7 @@ openmodule/utils/package_reader.py
96
97
  openmodule/utils/presence.py
97
98
  openmodule/utils/schema.py
98
99
  openmodule/utils/settings.py
100
+ openmodule/utils/signal_listener.py
99
101
  openmodule/utils/translation.py
100
102
  openmodule/utils/validation.py
101
103
  openmodule_commands/__init__.py
@@ -121,6 +123,7 @@ openmodule_test/sentry.py
121
123
  openmodule_test/settings.py
122
124
  openmodule_test/setup.cfg
123
125
  openmodule_test/setup.py
126
+ openmodule_test/signal_simulator.py
124
127
  openmodule_test/utils.py
125
128
  openmodule_test/zeromq.py
126
129
  tests/__init__.py
@@ -162,6 +165,7 @@ tests/test_utils_misc_functions.py
162
165
  tests/test_utils_package_reader.py
163
166
  tests/test_utils_presence.py
164
167
  tests/test_utils_settings.py
168
+ tests/test_utils_signal.py
165
169
  tests/test_utils_validation.py
166
170
  tests/test_utils_vehicle.py
167
171
  tests/invalid_database/alembic.ini
@@ -0,0 +1 @@
1
+ {"git_version": "3b899ae", "is_release": true}
@@ -9,7 +9,7 @@ alembic<2,>=1.5.4
9
9
  requests~=2.32
10
10
  python-dateutil>=2.7.2
11
11
  python-dotenv==0.15.0
12
- arivo-settings_models<2,>=1.2.0
12
+ arivo-settings_models<2,>=1.3.0
13
13
  arivo-schedule~=1.2.2
14
14
 
15
15
  [commands]
@@ -16,11 +16,13 @@ def openmodule_makemessages():
16
16
  parser.add_argument('--hardware', help='The service is only a hardware package with no actual code. '
17
17
  'Only translate hardware keywords.',
18
18
  required=False, action="count")
19
+ parser.add_argument('--library', help='Do not add __READABLE_NAME and __DESCRIPTION.',
20
+ required=False, action="count")
19
21
  parser.add_argument('--languages', help='Languages to translate to (lowercase iso2)', nargs="*",
20
22
  default=["en", "de"])
21
23
  args = parser.parse_args()
22
24
  create_translation(args.out, args.files, args.packages, args.force_dir, args.no_translate, args.hardware,
23
- args.languages)
25
+ args.library, args.languages)
24
26
 
25
27
 
26
28
  def openmodule_translate():
@@ -40,9 +42,10 @@ def openmodule_check_translation():
40
42
  parser.add_argument('--hardware', help='The service is only a hardware package with no actual code. '
41
43
  'Only translate hardware keywords.',
42
44
  required=False, action="count")
45
+ parser.add_argument('--library', help='Do not add __READABLE_NAME and __DESCRIPTION.',
46
+ required=False, action="count")
43
47
  parser.add_argument('--languages', help='Languages to translate to (lowercase iso2)', nargs="*",
44
48
  default=["en", "de"])
45
49
  args = parser.parse_args()
46
50
  sys.exit(check_translations(args.dir, args.files, args.packages, bool(args.ignore_keywords), args.hardware,
47
- args.languages))
48
-
51
+ args.library, args.languages))
@@ -32,7 +32,7 @@ def get_filenames(files, packages):
32
32
  return filenames
33
33
 
34
34
 
35
- def create_translation(out, files, packages, force_dir, no_translate, hardware, languages):
35
+ def create_translation(out, files, packages, force_dir, no_translate, hardware, library, languages):
36
36
  global keywords
37
37
 
38
38
  if not force_dir:
@@ -61,7 +61,7 @@ def create_translation(out, files, packages, force_dir, no_translate, hardware,
61
61
  if package_dirs is None:
62
62
  return
63
63
 
64
- keywords_to_add = keywords
64
+ keywords_to_add = [] if library else keywords
65
65
  if hardware:
66
66
  files = []
67
67
  packages = []
@@ -107,6 +107,9 @@ def create_translation(out, files, packages, force_dir, no_translate, hardware,
107
107
  lang_dir(language, "translation.po")])
108
108
  if not no_translate:
109
109
  poedit(out, language)
110
+ if library:
111
+ subprocess.check_output(["msgattrib", "-o", lang_dir(language, "translation.po"), "--no-obsolete",
112
+ lang_dir(language, "translation.po")])
110
113
 
111
114
  print("Finished translation")
112
115
  finally:
@@ -127,7 +130,7 @@ def poedit(out, language):
127
130
  MSG_EMTPY_REGEX = re.compile(r'^msgid\s*"(.*?)".*?\n.*?\n?^msgstr(\[\d*\])?\s*"(.*?)"', re.DOTALL)
128
131
 
129
132
 
130
- def check_translations(directory, files, packages, check_keywords, hardware, languages):
133
+ def check_translations(directory, files, packages, check_keywords, hardware, library, languages):
131
134
  global keywords
132
135
 
133
136
  def out_dir(path):
@@ -140,7 +143,7 @@ def check_translations(directory, files, packages, check_keywords, hardware, lan
140
143
  if package_dirs is None:
141
144
  return
142
145
 
143
- keywords_to_add = keywords
146
+ keywords_to_add = [] if library else keywords
144
147
  if hardware:
145
148
  files = []
146
149
  packages = []
@@ -154,7 +157,6 @@ def check_translations(directory, files, packages, check_keywords, hardware, lan
154
157
  filenames = get_filenames(files, packages)
155
158
 
156
159
  with open(PACKAGE_DATA_FILE, "w") as tmp:
157
- tmp.write('from openmodule.utils.translation import _\n')
158
160
  for x in keywords_to_add:
159
161
  tmp.write(f'_("{x}")\n')
160
162
  try:
@@ -0,0 +1,58 @@
1
+ from typing import Callable, Optional
2
+
3
+ from openmodule.models.signals import SignalMessage, TriggerSignalsRequest, TriggerSignalsResponse, \
4
+ GetSignalValueRequest, GetSignalValueResponse, SignalType
5
+ from openmodule.rpc import RPCClient
6
+
7
+
8
+ class SignalSimulator:
9
+ def __init__(self, emit: Callable[[SignalMessage], None]):
10
+ self.emit = emit
11
+ self._signals = {}
12
+
13
+ def add_signal(self, value: bool, additional_data: Optional[dict], signal_type: SignalType,
14
+ gate: Optional[str] = None, parking_area_id: Optional[str] = None,
15
+ signal_name: Optional[str] = None):
16
+ if signal_type == SignalType.custom:
17
+ assert signal_name is not None
18
+ signal_msg = SignalMessage(signal=signal_name, type=signal_type, gate=gate, parking_area_id=parking_area_id,
19
+ value=value, additional_data=additional_data)
20
+ elif signal_type == SignalType.parkinglot_full:
21
+ signal_name = "parkinglot_full"
22
+ signal_msg = SignalMessage(signal=signal_name, type=signal_type,
23
+ value=value, additional_data=additional_data)
24
+ elif signal_type == SignalType.area_full:
25
+ assert parking_area_id is not None
26
+ signal_name = f"{parking_area_id}-area_full"
27
+ signal_msg = SignalMessage(signal=signal_name, type=signal_type, parking_area_id=parking_area_id,
28
+ value=value, additional_data=additional_data)
29
+ else:
30
+ assert gate is not None
31
+ signal_name = f"{gate}-{signal_type}"
32
+ signal_msg = SignalMessage(signal=signal_name, type=signal_type, gate=gate,
33
+ value=value, additional_data=additional_data)
34
+ self._signals[signal_msg.signal] = signal_msg
35
+
36
+ def remove_signal(self, signal: str):
37
+ self._signals.pop(signal, None)
38
+
39
+ def set_signal(self, signal: str, value: bool, additional_data: Optional[dict] = None):
40
+ self._signals[signal].value = value
41
+ self._signals[signal].additional_data = additional_data
42
+ self.emit(self._signals[signal])
43
+
44
+ def trigger_signal_callback(self, request: TriggerSignalsRequest, _):
45
+ res = TriggerSignalsResponse(success=True)
46
+ for signal in request.signals:
47
+ if signal in self._signals:
48
+ self.emit(self._signals[signal])
49
+ else:
50
+ res.success = False
51
+ return res
52
+
53
+ def get_value_callback(self, request: GetSignalValueRequest, _):
54
+ if request.signal in self._signals:
55
+ return GetSignalValueResponse(value=self._signals[request.signal].value,
56
+ additional_data=self._signals[request.signal].additional_data)
57
+ else:
58
+ raise RPCClient.TimeoutError()
@@ -9,5 +9,5 @@ alembic>=1.5.4,<2
9
9
  requests~=2.32
10
10
  python-dateutil>=2.7.2
11
11
  python-dotenv==0.15.0
12
- arivo-settings_models>=1.2.0,<2
12
+ arivo-settings_models>=1.3.0,<2
13
13
  arivo-schedule~=1.2.2
@@ -1,5 +1,4 @@
1
1
  import json
2
-
3
2
  from datetime import datetime, timedelta
4
3
  from typing import Optional
5
4
  from unittest import TestCase
@@ -8,8 +7,7 @@ import freezegun
8
7
  import orjson
9
8
  from pydantic import ValidationError
10
9
 
11
- from openmodule import sentry
12
- from openmodule.models.base import OpenModuleModel, ZMQMessage, Gateway, timezone_validator, CostEntryData
10
+ from openmodule.models.base import OpenModuleModel, ZMQMessage, Gateway, timezone_validator
13
11
 
14
12
 
15
13
  class TestModel(OpenModuleModel):
@@ -138,11 +136,3 @@ class ZMQMessageTestCase(TestCase):
138
136
 
139
137
  res1.pop("timestamp")
140
138
  self.assertDictEqual(res1, {"name": "tä\nst", "type": "tö\tst"})
141
-
142
-
143
- class CostEntryDataTextCase(TestCase):
144
- def test_type_parsing(self):
145
- res = CostEntryData.parse_raw(b'{"entry_type": "static_cost", "value": 10, "account_id": "0"}')
146
- self.assertTrue(isinstance(res.value, int))
147
- res = CostEntryData.parse_raw(b'{"entry_type": "rate_change", "value": "10", "account_id": "0"}')
148
- self.assertTrue(isinstance(res.value, str))