arthexis 0.1.18__tar.gz → 0.1.19__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.

Potentially problematic release.


This version of arthexis might be problematic. Click here for more details.

Files changed (250) hide show
  1. {arthexis-0.1.18 → arthexis-0.1.19}/PKG-INFO +37 -10
  2. {arthexis-0.1.18 → arthexis-0.1.19}/README.md +27 -0
  3. {arthexis-0.1.18 → arthexis-0.1.19}/arthexis.egg-info/PKG-INFO +37 -10
  4. {arthexis-0.1.18 → arthexis-0.1.19}/arthexis.egg-info/SOURCES.txt +1 -1
  5. {arthexis-0.1.18 → arthexis-0.1.19}/arthexis.egg-info/requires.txt +9 -9
  6. {arthexis-0.1.18 → arthexis-0.1.19}/config/settings.py +1 -5
  7. {arthexis-0.1.18 → arthexis-0.1.19}/core/system.py +125 -0
  8. {arthexis-0.1.18 → arthexis-0.1.19}/core/tasks.py +0 -22
  9. {arthexis-0.1.18 → arthexis-0.1.19}/core/views.py +35 -4
  10. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/admin.py +1 -2
  11. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/models.py +18 -23
  12. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/tests.py +42 -34
  13. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/urls.py +0 -1
  14. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/views.py +2 -15
  15. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/admin.py +23 -2
  16. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/models.py +7 -0
  17. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/store.py +6 -4
  18. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/tests.py +14 -1
  19. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/views.py +65 -12
  20. {arthexis-0.1.18 → arthexis-0.1.19}/pages/admin.py +63 -10
  21. {arthexis-0.1.18 → arthexis-0.1.19}/pages/context_processors.py +11 -0
  22. {arthexis-0.1.18 → arthexis-0.1.19}/pages/middleware.py +3 -0
  23. {arthexis-0.1.18 → arthexis-0.1.19}/pages/models.py +35 -0
  24. {arthexis-0.1.18 → arthexis-0.1.19}/pages/tests.py +177 -34
  25. {arthexis-0.1.18 → arthexis-0.1.19}/pages/urls.py +2 -1
  26. {arthexis-0.1.18 → arthexis-0.1.19}/pages/views.py +70 -23
  27. arthexis-0.1.19/pyproject.toml +26 -0
  28. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_admin_client_report.py +11 -0
  29. arthexis-0.1.19/tests/test_admin_system_stop.py +127 -0
  30. arthexis-0.1.19/tests/test_client_report_form.py +30 -0
  31. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_client_report_generation.py +33 -0
  32. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_invitation_login_view.py +28 -0
  33. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_node_info_view.py +20 -0
  34. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_progress.py +29 -0
  35. arthexis-0.1.18/pyproject.toml +0 -26
  36. arthexis-0.1.18/tests/test_admin_system_stop.py +0 -63
  37. arthexis-0.1.18/tests/test_birthday_greetings.py +0 -30
  38. {arthexis-0.1.18 → arthexis-0.1.19}/LICENSE +0 -0
  39. {arthexis-0.1.18 → arthexis-0.1.19}/arthexis.egg-info/dependency_links.txt +0 -0
  40. {arthexis-0.1.18 → arthexis-0.1.19}/arthexis.egg-info/top_level.txt +0 -0
  41. {arthexis-0.1.18 → arthexis-0.1.19}/config/__init__.py +0 -0
  42. {arthexis-0.1.18 → arthexis-0.1.19}/config/active_app.py +0 -0
  43. {arthexis-0.1.18 → arthexis-0.1.19}/config/asgi.py +0 -0
  44. {arthexis-0.1.18 → arthexis-0.1.19}/config/auth_app.py +0 -0
  45. {arthexis-0.1.18 → arthexis-0.1.19}/config/celery.py +0 -0
  46. {arthexis-0.1.18 → arthexis-0.1.19}/config/context_processors.py +0 -0
  47. {arthexis-0.1.18 → arthexis-0.1.19}/config/horologia_app.py +0 -0
  48. {arthexis-0.1.18 → arthexis-0.1.19}/config/loadenv.py +0 -0
  49. {arthexis-0.1.18 → arthexis-0.1.19}/config/logging.py +0 -0
  50. {arthexis-0.1.18 → arthexis-0.1.19}/config/middleware.py +0 -0
  51. {arthexis-0.1.18 → arthexis-0.1.19}/config/offline.py +0 -0
  52. {arthexis-0.1.18 → arthexis-0.1.19}/config/settings_helpers.py +0 -0
  53. {arthexis-0.1.18 → arthexis-0.1.19}/config/urls.py +0 -0
  54. {arthexis-0.1.18 → arthexis-0.1.19}/config/wsgi.py +0 -0
  55. {arthexis-0.1.18 → arthexis-0.1.19}/core/__init__.py +0 -0
  56. {arthexis-0.1.18 → arthexis-0.1.19}/core/admin.py +0 -0
  57. {arthexis-0.1.18 → arthexis-0.1.19}/core/admin_history.py +0 -0
  58. {arthexis-0.1.18 → arthexis-0.1.19}/core/admindocs.py +0 -0
  59. {arthexis-0.1.18 → arthexis-0.1.19}/core/apps.py +0 -0
  60. {arthexis-0.1.18 → arthexis-0.1.19}/core/auto_upgrade.py +0 -0
  61. {arthexis-0.1.18 → arthexis-0.1.19}/core/backends.py +0 -0
  62. {arthexis-0.1.18 → arthexis-0.1.19}/core/changelog.py +0 -0
  63. {arthexis-0.1.18 → arthexis-0.1.19}/core/entity.py +0 -0
  64. {arthexis-0.1.18 → arthexis-0.1.19}/core/environment.py +0 -0
  65. {arthexis-0.1.18 → arthexis-0.1.19}/core/fields.py +0 -0
  66. {arthexis-0.1.18 → arthexis-0.1.19}/core/form_fields.py +0 -0
  67. {arthexis-0.1.18 → arthexis-0.1.19}/core/github_helper.py +0 -0
  68. {arthexis-0.1.18 → arthexis-0.1.19}/core/github_issues.py +0 -0
  69. {arthexis-0.1.18 → arthexis-0.1.19}/core/github_repos.py +0 -0
  70. {arthexis-0.1.18 → arthexis-0.1.19}/core/lcd_screen.py +0 -0
  71. {arthexis-0.1.18 → arthexis-0.1.19}/core/liveupdate.py +0 -0
  72. {arthexis-0.1.18 → arthexis-0.1.19}/core/log_paths.py +0 -0
  73. {arthexis-0.1.18 → arthexis-0.1.19}/core/mailer.py +0 -0
  74. {arthexis-0.1.18 → arthexis-0.1.19}/core/middleware.py +0 -0
  75. {arthexis-0.1.18 → arthexis-0.1.19}/core/models.py +0 -0
  76. {arthexis-0.1.18 → arthexis-0.1.19}/core/notifications.py +0 -0
  77. {arthexis-0.1.18 → arthexis-0.1.19}/core/public_wifi.py +0 -0
  78. {arthexis-0.1.18 → arthexis-0.1.19}/core/reference_utils.py +0 -0
  79. {arthexis-0.1.18 → arthexis-0.1.19}/core/release.py +0 -0
  80. {arthexis-0.1.18 → arthexis-0.1.19}/core/rfid_import_export.py +0 -0
  81. {arthexis-0.1.18 → arthexis-0.1.19}/core/sigil_builder.py +0 -0
  82. {arthexis-0.1.18 → arthexis-0.1.19}/core/sigil_context.py +0 -0
  83. {arthexis-0.1.18 → arthexis-0.1.19}/core/sigil_resolver.py +0 -0
  84. {arthexis-0.1.18 → arthexis-0.1.19}/core/temp_passwords.py +0 -0
  85. {arthexis-0.1.18 → arthexis-0.1.19}/core/test_system_info.py +0 -0
  86. {arthexis-0.1.18 → arthexis-0.1.19}/core/tests.py +0 -0
  87. {arthexis-0.1.18 → arthexis-0.1.19}/core/tests_liveupdate.py +0 -0
  88. {arthexis-0.1.18 → arthexis-0.1.19}/core/urls.py +0 -0
  89. {arthexis-0.1.18 → arthexis-0.1.19}/core/user_data.py +0 -0
  90. {arthexis-0.1.18 → arthexis-0.1.19}/core/widgets.py +0 -0
  91. {arthexis-0.1.18 → arthexis-0.1.19}/core/workgroup_urls.py +0 -0
  92. {arthexis-0.1.18 → arthexis-0.1.19}/core/workgroup_views.py +0 -0
  93. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/__init__.py +0 -0
  94. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/apps.py +0 -0
  95. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/backends.py +0 -0
  96. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/dns.py +0 -0
  97. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/feature_checks.py +0 -0
  98. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/lcd.py +0 -0
  99. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/reports.py +0 -0
  100. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/rfid_sync.py +0 -0
  101. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/signals.py +0 -0
  102. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/tasks.py +0 -0
  103. {arthexis-0.1.18 → arthexis-0.1.19}/nodes/utils.py +0 -0
  104. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/__init__.py +0 -0
  105. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/apps.py +0 -0
  106. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/consumers.py +0 -0
  107. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/evcs.py +0 -0
  108. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/evcs_discovery.py +0 -0
  109. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/reference_utils.py +0 -0
  110. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/routing.py +0 -0
  111. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/simulator.py +0 -0
  112. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/status_display.py +0 -0
  113. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/tasks.py +0 -0
  114. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/test_export_import.py +0 -0
  115. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/test_rfid.py +0 -0
  116. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/transactions_io.py +0 -0
  117. {arthexis-0.1.18 → arthexis-0.1.19}/ocpp/urls.py +0 -0
  118. {arthexis-0.1.18 → arthexis-0.1.19}/pages/__init__.py +0 -0
  119. {arthexis-0.1.18 → arthexis-0.1.19}/pages/apps.py +0 -0
  120. {arthexis-0.1.18 → arthexis-0.1.19}/pages/checks.py +0 -0
  121. {arthexis-0.1.18 → arthexis-0.1.19}/pages/defaults.py +0 -0
  122. {arthexis-0.1.18 → arthexis-0.1.19}/pages/forms.py +0 -0
  123. {arthexis-0.1.18 → arthexis-0.1.19}/pages/module_defaults.py +0 -0
  124. {arthexis-0.1.18 → arthexis-0.1.19}/pages/site_config.py +0 -0
  125. {arthexis-0.1.18 → arthexis-0.1.19}/pages/tasks.py +0 -0
  126. {arthexis-0.1.18 → arthexis-0.1.19}/pages/utils.py +0 -0
  127. {arthexis-0.1.18 → arthexis-0.1.19}/setup.cfg +0 -0
  128. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_acronym_capitalization.py +0 -0
  129. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_admin_doc_commands.py +0 -0
  130. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_admin_doc_model_groups.py +0 -0
  131. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_admin_history.py +0 -0
  132. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_admin_index_actions.py +0 -0
  133. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_admin_model_graph.py +0 -0
  134. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_admin_object_history.py +0 -0
  135. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_admin_profile_link.py +0 -0
  136. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_allowed_hosts_hostname.py +0 -0
  137. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_api_login_required.py +0 -0
  138. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_assistant_data_api.py +0 -0
  139. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_assistant_profile_admin.py +0 -0
  140. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_assistant_profile_api.py +0 -0
  141. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_auto_upgrade_scheduler.py +0 -0
  142. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_awg_admin.py +0 -0
  143. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_benchmark_command.py +0 -0
  144. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_build_pypi_command.py +0 -0
  145. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_celery_no_debug.py +0 -0
  146. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_changelog_builder.py +0 -0
  147. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_check_admin_command.py +0 -0
  148. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_check_migrations_script.py +0 -0
  149. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_check_pypi_command.py +0 -0
  150. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_clean_release_logs_command.py +0 -0
  151. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_client_report_schedule.py +0 -0
  152. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_csrf_failure.py +0 -0
  153. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_csrf_origin_subnet.py +0 -0
  154. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_dist_cleanup.py +0 -0
  155. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_email_collector.py +0 -0
  156. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_email_inbox.py +0 -0
  157. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_email_inbox_admin.py +0 -0
  158. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_email_inbox_search_action.py +0 -0
  159. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_email_outbox_admin.py +0 -0
  160. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_email_profiles.py +0 -0
  161. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_email_transaction.py +0 -0
  162. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_env_refresh_clean.py +0 -0
  163. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_env_refresh_pip.py +0 -0
  164. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_env_refresh_unlink.py +0 -0
  165. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_experience_admin_group.py +0 -0
  166. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_fixture_presence.py +0 -0
  167. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_footer_no_references.py +0 -0
  168. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_footer_presence.py +0 -0
  169. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_footer_render.py +0 -0
  170. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_git_checks.py +0 -0
  171. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_github_issue_reporting.py +0 -0
  172. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_install_script.py +0 -0
  173. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_language_switch.py +0 -0
  174. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_lcd_check_command.py +0 -0
  175. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_lcd_smbus2.py +0 -0
  176. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_localhost_admin_backend.py +0 -0
  177. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_log_paths.py +0 -0
  178. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_login_view_no_site.py +0 -0
  179. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_manage_debug_flag.py +0 -0
  180. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_manuals.py +0 -0
  181. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_mcp_asgi.py +0 -0
  182. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_mcp_auto_start.py +0 -0
  183. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_mcp_process.py +0 -0
  184. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_mcp_sigil_server.py +0 -0
  185. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_mcp_sigil_server_command.py +0 -0
  186. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_message_command.py +0 -0
  187. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_migrations.py +0 -0
  188. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_model_verbose_name_capitalization.py +0 -0
  189. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_network_setup_interactive.py +0 -0
  190. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_notifications_fallback.py +0 -0
  191. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_notify_command.py +0 -0
  192. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_ocpp_session_lock.py +0 -0
  193. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_odoo_product.py +0 -0
  194. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_odoo_profile.py +0 -0
  195. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_odoo_profile_admin.py +0 -0
  196. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_odoo_quote_report.py +0 -0
  197. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_offline.py +0 -0
  198. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_package_admin_next_release.py +0 -0
  199. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_power_admin_group.py +0 -0
  200. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_profile_inline_deletion.py +0 -0
  201. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_pypi_check.py +0 -0
  202. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_pypi_token.py +0 -0
  203. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_readme_language.py +0 -0
  204. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_reference_qr_code.py +0 -0
  205. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_reference_transaction_uuid.py +0 -0
  206. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_register_site_apps_command.py +0 -0
  207. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_build.py +0 -0
  208. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_build_flow.py +0 -0
  209. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_checklist.py +0 -0
  210. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_logs.py +0 -0
  211. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_manager_admin.py +0 -0
  212. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_packages.py +0 -0
  213. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_progress_pre_release_integration.py +0 -0
  214. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_push.py +0 -0
  215. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_release_tasks.py +0 -0
  216. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_render_nginx_sites.py +0 -0
  217. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_request_invite.py +0 -0
  218. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_rfid_admin_print_labels.py +0 -0
  219. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_rfid_admin_reference_clear.py +0 -0
  220. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_rfid_admin_scan_csrf.py +0 -0
  221. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_rfid_always_on.py +0 -0
  222. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_rfid_backend.py +0 -0
  223. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_rfid_background_reader.py +0 -0
  224. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_rfid_client_report.py +0 -0
  225. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_rfid_watch_command.py +0 -0
  226. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_role_marker_filtering.py +0 -0
  227. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_seed_data.py +0 -0
  228. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_send_invite_command.py +0 -0
  229. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_settings_helpers.py +0 -0
  230. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_shell_scripts.py +0 -0
  231. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_show_leads_command.py +0 -0
  232. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_sigil_builder.py +0 -0
  233. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_sigil_resolution.py +0 -0
  234. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_sites_utils.py +0 -0
  235. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_social_profile.py +0 -0
  236. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_staff_login_net_message.py +0 -0
  237. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_staff_required_decorator.py +0 -0
  238. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_switch_role_script.py +0 -0
  239. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_system_changelog_report.py +0 -0
  240. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_temp_passwords.py +0 -0
  241. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_totp_admin.py +0 -0
  242. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_totp_backend.py +0 -0
  243. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_uninstall_script.py +0 -0
  244. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_update_fixtures_command.py +0 -0
  245. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_upgrade_report.py +0 -0
  246. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_urls_autodiscover.py +0 -0
  247. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_user_data_admin.py +0 -0
  248. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_version_endpoint.py +0 -0
  249. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_version_file.py +0 -0
  250. {arthexis-0.1.18 → arthexis-0.1.19}/tests/test_vscode_manage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arthexis
3
- Version: 0.1.18
3
+ Version: 0.1.19
4
4
  Summary: Power & Energy Infrastructure
5
5
  Author-email: "Rafael J. Guillén-Osorio" <tecnologia@gelectriic.com>
6
6
  License-Expression: GPL-3.0-only
@@ -15,7 +15,7 @@ Requires-Dist: amqp==5.3.1
15
15
  Requires-Dist: annotated-types==0.7.0
16
16
  Requires-Dist: anyio==4.9.0
17
17
  Requires-Dist: asgiref==3.10.0
18
- Requires-Dist: atproto==0.0.61
18
+ Requires-Dist: atproto==0.0.62
19
19
  Requires-Dist: attrs==25.3.0
20
20
  Requires-Dist: autobahn==24.4.2
21
21
  Requires-Dist: Automat==25.4.16
@@ -41,7 +41,7 @@ Requires-Dist: defusedxml==0.7.1
41
41
  Requires-Dist: Django==5.2.7
42
42
  Requires-Dist: django-celery-beat==2.8.1
43
43
  Requires-Dist: django-debug-toolbar==6.0.0
44
- Requires-Dist: django-import-export==4.3.9
44
+ Requires-Dist: django-import-export==4.3.12
45
45
  Requires-Dist: django-object-actions==5.0.0
46
46
  Requires-Dist: django-otp==1.5.4
47
47
  Requires-Dist: django-timezone-field==7.1
@@ -53,28 +53,28 @@ Requires-Dist: h11==0.16.0
53
53
  Requires-Dist: httpcore==1.0.9
54
54
  Requires-Dist: httpx==0.28.1
55
55
  Requires-Dist: hyperlink==21.0.0
56
- Requires-Dist: idna==3.10
56
+ Requires-Dist: idna==3.11
57
57
  Requires-Dist: incremental==24.7.2
58
58
  Requires-Dist: kombu==5.5.4
59
59
  Requires-Dist: libipld==3.1.1
60
60
  Requires-Dist: Markdown==3.8.2
61
61
  Requires-Dist: mdx_truly_sane_lists==1.3
62
- Requires-Dist: mcp==1.16.0
62
+ Requires-Dist: mcp==1.18.0
63
63
  Requires-Dist: mfrc522==0.0.7; sys_platform == "linux"
64
64
  Requires-Dist: outcome==1.3.0.post0
65
65
  Requires-Dist: packaging==25.0
66
66
  Requires-Dist: pillow==11.3.0
67
67
  Requires-Dist: prompt_toolkit==3.0.51
68
- Requires-Dist: psutil==5.9.8
68
+ Requires-Dist: psutil==7.1.1
69
69
  Requires-Dist: psycopg==3.2.9
70
- Requires-Dist: psycopg-binary==3.2.9
70
+ Requires-Dist: psycopg-binary==3.2.11
71
71
  Requires-Dist: pyasn1==0.6.1
72
72
  Requires-Dist: pyasn1_modules==0.4.2
73
73
  Requires-Dist: pycparser==2.22
74
74
  Requires-Dist: pydantic==2.11.7
75
75
  Requires-Dist: pydantic_core==2.33.2
76
76
  Requires-Dist: pyOpenSSL==25.1.0
77
- Requires-Dist: pyperclip==1.9.0
77
+ Requires-Dist: pyperclip==1.11.0
78
78
  Requires-Dist: PySocks==1.7.1
79
79
  Requires-Dist: python-crontab==3.3.0
80
80
  Requires-Dist: python-dateutil==2.9.0.post0
@@ -99,7 +99,7 @@ Requires-Dist: trio-websocket==0.12.2
99
99
  Requires-Dist: Twisted==25.5.0
100
100
  Requires-Dist: twine==6.1.0
101
101
  Requires-Dist: txaio==25.6.1
102
- Requires-Dist: typing-inspection==0.4.1
102
+ Requires-Dist: typing-inspection==0.4.2
103
103
  Requires-Dist: typing_extensions==4.14.1
104
104
  Requires-Dist: tzdata==2025.2
105
105
  Requires-Dist: urllib3==2.5.0
@@ -108,7 +108,7 @@ Requires-Dist: wcwidth==0.2.13
108
108
  Requires-Dist: webencodings==0.5.1
109
109
  Requires-Dist: websocket-client==1.8.0
110
110
  Requires-Dist: websockets==13.1
111
- Requires-Dist: whitenoise==6.9.0
111
+ Requires-Dist: whitenoise==6.11.0
112
112
  Requires-Dist: plyer==2.1.0; sys_platform == "win32"
113
113
  Requires-Dist: wsproto==1.2.0
114
114
  Requires-Dist: zope.interface==7.2
@@ -212,10 +212,37 @@ Terminal nodes can start directly with the scripts below without installing; Con
212
212
  ### 4. Administration
213
213
  Visit [`http://localhost:8000/admin/`](http://localhost:8000/admin/) for the [Django admin](https://docs.djangoproject.com/en/stable/ref/contrib/admin/) and [`http://localhost:8000/admindocs/`](http://localhost:8000/admindocs/) for the [admindocs](https://docs.djangoproject.com/en/stable/ref/contrib/admin/admindocs/). Use `--port` with the start scripts or installer when you need to expose a different port.
214
214
 
215
+ ## Sigils
216
+
217
+ Sigils are bracketed tokens such as `[ENV.SMTP_PASSWORD]` that Arthexis expands at runtime. They make it possible to reference configuration secrets, system metadata, or records stored in other apps without duplicating values across the project.
218
+
219
+ ### Syntax at a glance
220
+
221
+ - `[PREFIX.KEY]` &mdash; returns a field or attribute. Hyphens and casing are normalized automatically.
222
+ - `[PREFIX=IDENTIFIER.FIELD]` &mdash; selects a specific record by primary key or any unique field.
223
+ - `[PREFIX:FIELD=VALUE.ATTRIBUTE]` &mdash; filters by a custom field instead of the primary key.
224
+ - `[PREFIX.FIELD=[OTHER.SIGIL]]` &mdash; nests sigils so the value after `=` resolves before the outer token.
225
+ - `[PREFIX]` &mdash; for entity prefixes, returns the serialized object in JSON; for configuration prefixes, resolves to an empty string when the key is missing.
226
+
227
+ The platform ships with three configuration prefixes:
228
+
229
+ - `ENV` reads environment variables.
230
+ - `CONF` reads Django settings.
231
+ - `SYS` exposes computed system information such as build metadata.
232
+
233
+ Additional prefixes are defined through **Sigil Roots**, which map a short code (for example `ROLE`, `ODOO`, or `USER`) to a Django model. You can review them from **Admin &rarr; Sigil Builder** (`/admin/sigil-builder/`), where a test console is also available.
234
+
235
+ Unknown prefixes remain in place (e.g. `[UNKNOWN.VALUE]`) and are logged. When the optional `gway` CLI is installed, the resolver will attempt to delegate unresolved tokens to it before falling back to the original text.
236
+
215
237
  ## Support
216
238
 
217
239
  Contact us at [tecnologia@gelectriic.com](mailto:tecnologia@gelectriic.com) or visit our [web page](https://www.gelectriic.com/) for [professional services](https://en.wikipedia.org/wiki/Professional_services) and [commercial support](https://en.wikipedia.org/wiki/Technical_support).
218
240
 
241
+ ## Project Guidelines
242
+
243
+ - [AGENTS](AGENTS.md) – operating handbook for repository workflows, testing, and release management.
244
+ - [DESIGN](DESIGN.md) – visual, UX, and branding guidance that all interfaces must follow.
245
+
219
246
  ## About Me
220
247
 
221
248
  > "What, you want to know about me too? Well, I enjoy [developing software](https://en.wikipedia.org/wiki/Software_development), [role-playing games](https://en.wikipedia.org/wiki/Role-playing_game), long walks on the [beach](https://en.wikipedia.org/wiki/Beach) and a fourth secret thing."
@@ -96,10 +96,37 @@ Terminal nodes can start directly with the scripts below without installing; Con
96
96
  ### 4. Administration
97
97
  Visit [`http://localhost:8000/admin/`](http://localhost:8000/admin/) for the [Django admin](https://docs.djangoproject.com/en/stable/ref/contrib/admin/) and [`http://localhost:8000/admindocs/`](http://localhost:8000/admindocs/) for the [admindocs](https://docs.djangoproject.com/en/stable/ref/contrib/admin/admindocs/). Use `--port` with the start scripts or installer when you need to expose a different port.
98
98
 
99
+ ## Sigils
100
+
101
+ Sigils are bracketed tokens such as `[ENV.SMTP_PASSWORD]` that Arthexis expands at runtime. They make it possible to reference configuration secrets, system metadata, or records stored in other apps without duplicating values across the project.
102
+
103
+ ### Syntax at a glance
104
+
105
+ - `[PREFIX.KEY]` &mdash; returns a field or attribute. Hyphens and casing are normalized automatically.
106
+ - `[PREFIX=IDENTIFIER.FIELD]` &mdash; selects a specific record by primary key or any unique field.
107
+ - `[PREFIX:FIELD=VALUE.ATTRIBUTE]` &mdash; filters by a custom field instead of the primary key.
108
+ - `[PREFIX.FIELD=[OTHER.SIGIL]]` &mdash; nests sigils so the value after `=` resolves before the outer token.
109
+ - `[PREFIX]` &mdash; for entity prefixes, returns the serialized object in JSON; for configuration prefixes, resolves to an empty string when the key is missing.
110
+
111
+ The platform ships with three configuration prefixes:
112
+
113
+ - `ENV` reads environment variables.
114
+ - `CONF` reads Django settings.
115
+ - `SYS` exposes computed system information such as build metadata.
116
+
117
+ Additional prefixes are defined through **Sigil Roots**, which map a short code (for example `ROLE`, `ODOO`, or `USER`) to a Django model. You can review them from **Admin &rarr; Sigil Builder** (`/admin/sigil-builder/`), where a test console is also available.
118
+
119
+ Unknown prefixes remain in place (e.g. `[UNKNOWN.VALUE]`) and are logged. When the optional `gway` CLI is installed, the resolver will attempt to delegate unresolved tokens to it before falling back to the original text.
120
+
99
121
  ## Support
100
122
 
101
123
  Contact us at [tecnologia@gelectriic.com](mailto:tecnologia@gelectriic.com) or visit our [web page](https://www.gelectriic.com/) for [professional services](https://en.wikipedia.org/wiki/Professional_services) and [commercial support](https://en.wikipedia.org/wiki/Technical_support).
102
124
 
125
+ ## Project Guidelines
126
+
127
+ - [AGENTS](AGENTS.md) – operating handbook for repository workflows, testing, and release management.
128
+ - [DESIGN](DESIGN.md) – visual, UX, and branding guidance that all interfaces must follow.
129
+
103
130
  ## About Me
104
131
 
105
132
  > "What, you want to know about me too? Well, I enjoy [developing software](https://en.wikipedia.org/wiki/Software_development), [role-playing games](https://en.wikipedia.org/wiki/Role-playing_game), long walks on the [beach](https://en.wikipedia.org/wiki/Beach) and a fourth secret thing."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arthexis
3
- Version: 0.1.18
3
+ Version: 0.1.19
4
4
  Summary: Power & Energy Infrastructure
5
5
  Author-email: "Rafael J. Guillén-Osorio" <tecnologia@gelectriic.com>
6
6
  License-Expression: GPL-3.0-only
@@ -15,7 +15,7 @@ Requires-Dist: amqp==5.3.1
15
15
  Requires-Dist: annotated-types==0.7.0
16
16
  Requires-Dist: anyio==4.9.0
17
17
  Requires-Dist: asgiref==3.10.0
18
- Requires-Dist: atproto==0.0.61
18
+ Requires-Dist: atproto==0.0.62
19
19
  Requires-Dist: attrs==25.3.0
20
20
  Requires-Dist: autobahn==24.4.2
21
21
  Requires-Dist: Automat==25.4.16
@@ -41,7 +41,7 @@ Requires-Dist: defusedxml==0.7.1
41
41
  Requires-Dist: Django==5.2.7
42
42
  Requires-Dist: django-celery-beat==2.8.1
43
43
  Requires-Dist: django-debug-toolbar==6.0.0
44
- Requires-Dist: django-import-export==4.3.9
44
+ Requires-Dist: django-import-export==4.3.12
45
45
  Requires-Dist: django-object-actions==5.0.0
46
46
  Requires-Dist: django-otp==1.5.4
47
47
  Requires-Dist: django-timezone-field==7.1
@@ -53,28 +53,28 @@ Requires-Dist: h11==0.16.0
53
53
  Requires-Dist: httpcore==1.0.9
54
54
  Requires-Dist: httpx==0.28.1
55
55
  Requires-Dist: hyperlink==21.0.0
56
- Requires-Dist: idna==3.10
56
+ Requires-Dist: idna==3.11
57
57
  Requires-Dist: incremental==24.7.2
58
58
  Requires-Dist: kombu==5.5.4
59
59
  Requires-Dist: libipld==3.1.1
60
60
  Requires-Dist: Markdown==3.8.2
61
61
  Requires-Dist: mdx_truly_sane_lists==1.3
62
- Requires-Dist: mcp==1.16.0
62
+ Requires-Dist: mcp==1.18.0
63
63
  Requires-Dist: mfrc522==0.0.7; sys_platform == "linux"
64
64
  Requires-Dist: outcome==1.3.0.post0
65
65
  Requires-Dist: packaging==25.0
66
66
  Requires-Dist: pillow==11.3.0
67
67
  Requires-Dist: prompt_toolkit==3.0.51
68
- Requires-Dist: psutil==5.9.8
68
+ Requires-Dist: psutil==7.1.1
69
69
  Requires-Dist: psycopg==3.2.9
70
- Requires-Dist: psycopg-binary==3.2.9
70
+ Requires-Dist: psycopg-binary==3.2.11
71
71
  Requires-Dist: pyasn1==0.6.1
72
72
  Requires-Dist: pyasn1_modules==0.4.2
73
73
  Requires-Dist: pycparser==2.22
74
74
  Requires-Dist: pydantic==2.11.7
75
75
  Requires-Dist: pydantic_core==2.33.2
76
76
  Requires-Dist: pyOpenSSL==25.1.0
77
- Requires-Dist: pyperclip==1.9.0
77
+ Requires-Dist: pyperclip==1.11.0
78
78
  Requires-Dist: PySocks==1.7.1
79
79
  Requires-Dist: python-crontab==3.3.0
80
80
  Requires-Dist: python-dateutil==2.9.0.post0
@@ -99,7 +99,7 @@ Requires-Dist: trio-websocket==0.12.2
99
99
  Requires-Dist: Twisted==25.5.0
100
100
  Requires-Dist: twine==6.1.0
101
101
  Requires-Dist: txaio==25.6.1
102
- Requires-Dist: typing-inspection==0.4.1
102
+ Requires-Dist: typing-inspection==0.4.2
103
103
  Requires-Dist: typing_extensions==4.14.1
104
104
  Requires-Dist: tzdata==2025.2
105
105
  Requires-Dist: urllib3==2.5.0
@@ -108,7 +108,7 @@ Requires-Dist: wcwidth==0.2.13
108
108
  Requires-Dist: webencodings==0.5.1
109
109
  Requires-Dist: websocket-client==1.8.0
110
110
  Requires-Dist: websockets==13.1
111
- Requires-Dist: whitenoise==6.9.0
111
+ Requires-Dist: whitenoise==6.11.0
112
112
  Requires-Dist: plyer==2.1.0; sys_platform == "win32"
113
113
  Requires-Dist: wsproto==1.2.0
114
114
  Requires-Dist: zope.interface==7.2
@@ -212,10 +212,37 @@ Terminal nodes can start directly with the scripts below without installing; Con
212
212
  ### 4. Administration
213
213
  Visit [`http://localhost:8000/admin/`](http://localhost:8000/admin/) for the [Django admin](https://docs.djangoproject.com/en/stable/ref/contrib/admin/) and [`http://localhost:8000/admindocs/`](http://localhost:8000/admindocs/) for the [admindocs](https://docs.djangoproject.com/en/stable/ref/contrib/admin/admindocs/). Use `--port` with the start scripts or installer when you need to expose a different port.
214
214
 
215
+ ## Sigils
216
+
217
+ Sigils are bracketed tokens such as `[ENV.SMTP_PASSWORD]` that Arthexis expands at runtime. They make it possible to reference configuration secrets, system metadata, or records stored in other apps without duplicating values across the project.
218
+
219
+ ### Syntax at a glance
220
+
221
+ - `[PREFIX.KEY]` &mdash; returns a field or attribute. Hyphens and casing are normalized automatically.
222
+ - `[PREFIX=IDENTIFIER.FIELD]` &mdash; selects a specific record by primary key or any unique field.
223
+ - `[PREFIX:FIELD=VALUE.ATTRIBUTE]` &mdash; filters by a custom field instead of the primary key.
224
+ - `[PREFIX.FIELD=[OTHER.SIGIL]]` &mdash; nests sigils so the value after `=` resolves before the outer token.
225
+ - `[PREFIX]` &mdash; for entity prefixes, returns the serialized object in JSON; for configuration prefixes, resolves to an empty string when the key is missing.
226
+
227
+ The platform ships with three configuration prefixes:
228
+
229
+ - `ENV` reads environment variables.
230
+ - `CONF` reads Django settings.
231
+ - `SYS` exposes computed system information such as build metadata.
232
+
233
+ Additional prefixes are defined through **Sigil Roots**, which map a short code (for example `ROLE`, `ODOO`, or `USER`) to a Django model. You can review them from **Admin &rarr; Sigil Builder** (`/admin/sigil-builder/`), where a test console is also available.
234
+
235
+ Unknown prefixes remain in place (e.g. `[UNKNOWN.VALUE]`) and are logged. When the optional `gway` CLI is installed, the resolver will attempt to delegate unresolved tokens to it before falling back to the original text.
236
+
215
237
  ## Support
216
238
 
217
239
  Contact us at [tecnologia@gelectriic.com](mailto:tecnologia@gelectriic.com) or visit our [web page](https://www.gelectriic.com/) for [professional services](https://en.wikipedia.org/wiki/Professional_services) and [commercial support](https://en.wikipedia.org/wiki/Technical_support).
218
240
 
241
+ ## Project Guidelines
242
+
243
+ - [AGENTS](AGENTS.md) – operating handbook for repository workflows, testing, and release management.
244
+ - [DESIGN](DESIGN.md) – visual, UX, and branding guidance that all interfaces must follow.
245
+
219
246
  ## About Me
220
247
 
221
248
  > "What, you want to know about me too? Well, I enjoy [developing software](https://en.wikipedia.org/wiki/Software_development), [role-playing games](https://en.wikipedia.org/wiki/Role-playing_game), long walks on the [beach](https://en.wikipedia.org/wiki/Beach) and a fourth secret thing."
@@ -131,7 +131,6 @@ tests/test_assistant_profile_api.py
131
131
  tests/test_auto_upgrade_scheduler.py
132
132
  tests/test_awg_admin.py
133
133
  tests/test_benchmark_command.py
134
- tests/test_birthday_greetings.py
135
134
  tests/test_build_pypi_command.py
136
135
  tests/test_celery_no_debug.py
137
136
  tests/test_changelog_builder.py
@@ -139,6 +138,7 @@ tests/test_check_admin_command.py
139
138
  tests/test_check_migrations_script.py
140
139
  tests/test_check_pypi_command.py
141
140
  tests/test_clean_release_logs_command.py
141
+ tests/test_client_report_form.py
142
142
  tests/test_client_report_generation.py
143
143
  tests/test_client_report_schedule.py
144
144
  tests/test_csrf_failure.py
@@ -2,7 +2,7 @@ amqp==5.3.1
2
2
  annotated-types==0.7.0
3
3
  anyio==4.9.0
4
4
  asgiref==3.10.0
5
- atproto==0.0.61
5
+ atproto==0.0.62
6
6
  attrs==25.3.0
7
7
  autobahn==24.4.2
8
8
  Automat==25.4.16
@@ -28,7 +28,7 @@ defusedxml==0.7.1
28
28
  Django==5.2.7
29
29
  django-celery-beat==2.8.1
30
30
  django-debug-toolbar==6.0.0
31
- django-import-export==4.3.9
31
+ django-import-export==4.3.12
32
32
  django-object-actions==5.0.0
33
33
  django-otp==1.5.4
34
34
  django-timezone-field==7.1
@@ -39,27 +39,27 @@ h11==0.16.0
39
39
  httpcore==1.0.9
40
40
  httpx==0.28.1
41
41
  hyperlink==21.0.0
42
- idna==3.10
42
+ idna==3.11
43
43
  incremental==24.7.2
44
44
  kombu==5.5.4
45
45
  libipld==3.1.1
46
46
  Markdown==3.8.2
47
47
  mdx_truly_sane_lists==1.3
48
- mcp==1.16.0
48
+ mcp==1.18.0
49
49
  outcome==1.3.0.post0
50
50
  packaging==25.0
51
51
  pillow==11.3.0
52
52
  prompt_toolkit==3.0.51
53
- psutil==5.9.8
53
+ psutil==7.1.1
54
54
  psycopg==3.2.9
55
- psycopg-binary==3.2.9
55
+ psycopg-binary==3.2.11
56
56
  pyasn1==0.6.1
57
57
  pyasn1_modules==0.4.2
58
58
  pycparser==2.22
59
59
  pydantic==2.11.7
60
60
  pydantic_core==2.33.2
61
61
  pyOpenSSL==25.1.0
62
- pyperclip==1.9.0
62
+ pyperclip==1.11.0
63
63
  PySocks==1.7.1
64
64
  python-crontab==3.3.0
65
65
  python-dateutil==2.9.0.post0
@@ -84,7 +84,7 @@ trio-websocket==0.12.2
84
84
  Twisted==25.5.0
85
85
  twine==6.1.0
86
86
  txaio==25.6.1
87
- typing-inspection==0.4.1
87
+ typing-inspection==0.4.2
88
88
  typing_extensions==4.14.1
89
89
  tzdata==2025.2
90
90
  urllib3==2.5.0
@@ -93,7 +93,7 @@ wcwidth==0.2.13
93
93
  webencodings==0.5.1
94
94
  websocket-client==1.8.0
95
95
  websockets==13.1
96
- whitenoise==6.9.0
96
+ whitenoise==6.11.0
97
97
  wsproto==1.2.0
98
98
  zope.interface==7.2
99
99
 
@@ -585,7 +585,7 @@ AUTH_PASSWORD_VALIDATORS = [
585
585
  LANGUAGE_CODE = "en-us"
586
586
 
587
587
  LANGUAGES = [
588
- ("es", _("Spanish")),
588
+ ("es", _("Spanish (Latin America)")),
589
589
  ("en", _("English")),
590
590
  ("it", _("Italian")),
591
591
  ("de", _("German")),
@@ -688,8 +688,4 @@ CELERY_BEAT_SCHEDULE = {
688
688
  "task": "core.tasks.heartbeat",
689
689
  "schedule": crontab(minute="*/5"),
690
690
  },
691
- "birthday_greetings": {
692
- "task": "core.tasks.birthday_greetings",
693
- "schedule": crontab(hour=9, minute=0),
694
- },
695
691
  }
@@ -13,8 +13,10 @@ import shutil
13
13
  import logging
14
14
  from typing import Callable, Iterable, Optional
15
15
 
16
+ from django import forms
16
17
  from django.conf import settings
17
18
  from django.contrib import admin, messages
19
+ from django.forms import modelformset_factory
18
20
  from django.template.response import TemplateResponse
19
21
  from django.http import HttpResponseRedirect
20
22
  from django.urls import path, reverse
@@ -32,6 +34,7 @@ from core.release import (
32
34
  _remote_with_credentials,
33
35
  )
34
36
  from core.tasks import check_github_updates
37
+ from core.models import Todo
35
38
  from utils import revision
36
39
 
37
40
 
@@ -1086,6 +1089,123 @@ def _system_upgrade_report_view(request):
1086
1089
  return TemplateResponse(request, "admin/system_upgrade_report.html", context)
1087
1090
 
1088
1091
 
1092
+ class PendingTodoForm(forms.ModelForm):
1093
+ mark_done = forms.BooleanField(required=False, label=_("Approve"))
1094
+
1095
+ class Meta:
1096
+ model = Todo
1097
+ fields = [
1098
+ "request",
1099
+ "request_details",
1100
+ "url",
1101
+ "generated_for_version",
1102
+ "generated_for_revision",
1103
+ "on_done_condition",
1104
+ ]
1105
+ widgets = {
1106
+ "request_details": forms.Textarea(attrs={"rows": 3}),
1107
+ "on_done_condition": forms.Textarea(attrs={"rows": 2}),
1108
+ }
1109
+
1110
+ def __init__(self, *args, **kwargs):
1111
+ super().__init__(*args, **kwargs)
1112
+ for name in [
1113
+ "request",
1114
+ "url",
1115
+ "generated_for_version",
1116
+ "generated_for_revision",
1117
+ ]:
1118
+ self.fields[name].widget.attrs.setdefault("class", "vTextField")
1119
+ for name in ["request_details", "on_done_condition"]:
1120
+ self.fields[name].widget.attrs.setdefault("class", "vLargeTextField")
1121
+
1122
+
1123
+ PendingTodoFormSet = modelformset_factory(Todo, form=PendingTodoForm, extra=0)
1124
+
1125
+
1126
+ def _system_pending_todos_report_view(request):
1127
+ queryset = (
1128
+ Todo.objects.filter(is_deleted=False, done_on__isnull=True)
1129
+ .order_by("request")
1130
+ )
1131
+ formset = PendingTodoFormSet(
1132
+ request.POST or None,
1133
+ queryset=queryset,
1134
+ prefix="todos",
1135
+ )
1136
+
1137
+ if request.method == "POST":
1138
+ if formset.is_valid():
1139
+ approved_count = 0
1140
+ edited_count = 0
1141
+ for form in formset.forms:
1142
+ mark_done = form.cleaned_data.get("mark_done")
1143
+ todo = form.save(commit=False)
1144
+ has_changes = form.has_changed()
1145
+ if mark_done and todo.done_on is None:
1146
+ todo.done_on = timezone.now()
1147
+ approved_count += 1
1148
+ has_changes = True
1149
+ if has_changes:
1150
+ todo.save()
1151
+ if form.has_changed():
1152
+ edited_count += 1
1153
+ if has_changes and form.has_changed():
1154
+ form.save_m2m()
1155
+
1156
+ if approved_count or edited_count:
1157
+ message_parts: list[str] = []
1158
+ if edited_count:
1159
+ message_parts.append(
1160
+ ngettext(
1161
+ "%(count)d TODO updated.",
1162
+ "%(count)d TODOs updated.",
1163
+ edited_count,
1164
+ )
1165
+ % {"count": edited_count}
1166
+ )
1167
+ if approved_count:
1168
+ message_parts.append(
1169
+ ngettext(
1170
+ "%(count)d TODO approved.",
1171
+ "%(count)d TODOs approved.",
1172
+ approved_count,
1173
+ )
1174
+ % {"count": approved_count}
1175
+ )
1176
+ messages.success(request, " ".join(message_parts))
1177
+ else:
1178
+ messages.info(
1179
+ request,
1180
+ _("No changes were applied to the pending TODOs."),
1181
+ )
1182
+ return HttpResponseRedirect(reverse("admin:system-pending-todos-report"))
1183
+ else:
1184
+ messages.error(request, _("Please correct the errors below."))
1185
+
1186
+ rows = [
1187
+ {
1188
+ "form": form,
1189
+ "todo": form.instance,
1190
+ }
1191
+ for form in formset.forms
1192
+ ]
1193
+
1194
+ context = admin.site.each_context(request)
1195
+ context.update(
1196
+ {
1197
+ "title": _("Pending TODOs Report"),
1198
+ "formset": formset,
1199
+ "rows": rows,
1200
+ }
1201
+ )
1202
+ return TemplateResponse(
1203
+ request,
1204
+ "admin/system_pending_todos_report.html",
1205
+ context,
1206
+ )
1207
+
1208
+
1089
1209
  def _trigger_upgrade_check() -> bool:
1090
1210
  """Return ``True`` when the upgrade check was queued asynchronously."""
1091
1211
 
@@ -1142,6 +1262,11 @@ def patch_admin_system_view() -> None:
1142
1262
  admin.site.admin_view(_system_changelog_report_view),
1143
1263
  name="system-changelog-report",
1144
1264
  ),
1265
+ path(
1266
+ "system/pending-todos-report/",
1267
+ admin.site.admin_view(_system_pending_todos_report_view),
1268
+ name="system-pending-todos-report",
1269
+ ),
1145
1270
  path(
1146
1271
  "system/upgrade-report/",
1147
1272
  admin.site.admin_view(_system_upgrade_report_view),
@@ -8,14 +8,9 @@ import urllib.error
8
8
  import urllib.request
9
9
 
10
10
  from celery import shared_task
11
- from django.conf import settings
12
- from django.contrib.auth import get_user_model
13
- from core import mailer
14
11
  from core import github_issues
15
12
  from django.utils import timezone
16
13
 
17
- from nodes.models import NetMessage
18
-
19
14
 
20
15
  AUTO_UPGRADE_HEALTH_DELAY_SECONDS = 30
21
16
  AUTO_UPGRADE_SKIP_LOCK_NAME = "auto_upgrade_skip_revisions.lck"
@@ -30,23 +25,6 @@ def heartbeat() -> None:
30
25
  logger.info("Heartbeat task executed")
31
26
 
32
27
 
33
- @shared_task
34
- def birthday_greetings() -> None:
35
- """Send birthday greetings to users via Net Message and email."""
36
- User = get_user_model()
37
- today = timezone.localdate()
38
- for user in User.objects.filter(birthday=today):
39
- NetMessage.broadcast("Happy bday!", user.username)
40
- if user.email:
41
- mailer.send(
42
- "Happy bday!",
43
- f"Happy bday! {user.username}",
44
- [user.email],
45
- settings.DEFAULT_FROM_EMAIL,
46
- fail_silently=True,
47
- )
48
-
49
-
50
28
  def _auto_upgrade_log_path(base_dir: Path) -> Path:
51
29
  """Return the log file used for auto-upgrade events."""
52
30
 
@@ -736,6 +736,34 @@ def _ensure_release_todo(
736
736
  return todo, fixture_path
737
737
 
738
738
 
739
+ def _todo_blocks_publish(todo: Todo, release: PackageRelease) -> bool:
740
+ """Return ``True`` when ``todo`` should block the release workflow."""
741
+
742
+ request = (todo.request or "").strip()
743
+ release_name = (release.package.name or "").strip()
744
+ if not request or not release_name:
745
+ return True
746
+
747
+ prefix = f"create release {release_name.lower()} "
748
+ if not request.lower().startswith(prefix):
749
+ return True
750
+
751
+ release_version = (release.version or "").strip()
752
+ generated_version = (todo.generated_for_version or "").strip()
753
+ if not release_version or release_version != generated_version:
754
+ return True
755
+
756
+ generated_revision = (todo.generated_for_revision or "").strip()
757
+ release_revision = (release.revision or "").strip()
758
+ if generated_revision and release_revision and generated_revision != release_revision:
759
+ return True
760
+
761
+ if not todo.is_seed_data:
762
+ return True
763
+
764
+ return False
765
+
766
+
739
767
  def _sync_release_with_revision(release: PackageRelease) -> tuple[bool, str]:
740
768
  """Ensure ``release`` matches the repository revision and version.
741
769
 
@@ -1885,12 +1913,15 @@ def release_progress(request, pk: int, action: str):
1885
1913
 
1886
1914
  pending_qs = Todo.objects.filter(is_deleted=False, done_on__isnull=True)
1887
1915
  pending_items = list(pending_qs)
1888
- if not pending_items:
1916
+ blocking_todos = [
1917
+ todo for todo in pending_items if _todo_blocks_publish(todo, release)
1918
+ ]
1919
+ if not blocking_todos:
1889
1920
  ctx["todos_ack"] = True
1890
1921
  ctx["todos_ack_auto"] = True
1891
1922
  elif ack_todos_requested:
1892
1923
  failures = []
1893
- for todo in pending_items:
1924
+ for todo in blocking_todos:
1894
1925
  result = todo.check_on_done_condition()
1895
1926
  if not result.passed:
1896
1927
  failures.append((todo, result))
@@ -1920,7 +1951,7 @@ def release_progress(request, pk: int, action: str):
1920
1951
  "url": todo.url,
1921
1952
  "request_details": todo.request_details,
1922
1953
  }
1923
- for todo in pending_items
1954
+ for todo in blocking_todos
1924
1955
  ]
1925
1956
  ctx["todos_required"] = True
1926
1957
 
@@ -1932,7 +1963,7 @@ def release_progress(request, pk: int, action: str):
1932
1963
  "started": ctx.get("started", False),
1933
1964
  }
1934
1965
  step_count = 0
1935
- if not pending_items:
1966
+ if not blocking_todos:
1936
1967
  ctx["todos_ack"] = True
1937
1968
  log_path = log_dir / log_name
1938
1969
  ctx.setdefault("log", log_name)
@@ -1565,7 +1565,7 @@ class NetMessageAdmin(EntityModelAdmin):
1565
1565
  search_fields = ("subject", "body")
1566
1566
  list_filter = ("complete", "filter_node_role", "filter_current_relation")
1567
1567
  ordering = ("-created",)
1568
- readonly_fields = ("complete", "confirmed_peers")
1568
+ readonly_fields = ("complete",)
1569
1569
  actions = ["send_messages"]
1570
1570
  fieldsets = (
1571
1571
  (None, {"fields": ("subject", "body")}),
@@ -1590,7 +1590,6 @@ class NetMessageAdmin(EntityModelAdmin):
1590
1590
  "node_origin",
1591
1591
  "target_limit",
1592
1592
  "propagated_to",
1593
- "confirmed_peers",
1594
1593
  "complete",
1595
1594
  )
1596
1595
  },