rcdb 2.2.9__tar.gz → 2.2.10__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 (218) hide show
  1. {rcdb-2.2.9/rcdb.egg-info → rcdb-2.2.10}/PKG-INFO +1 -1
  2. rcdb-2.2.10/rcdb/cli/add.py +141 -0
  3. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/app.py +2 -0
  4. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/provider.py +137 -133
  5. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/version.py +1 -1
  6. {rcdb-2.2.9 → rcdb-2.2.10/rcdb.egg-info}/PKG-INFO +1 -1
  7. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/SOURCES.txt +4 -0
  8. rcdb-2.2.10/tests/test_cli_add_condition.py +139 -0
  9. rcdb-2.2.10/tests/test_cli_add_file.py +105 -0
  10. rcdb-2.2.10/tests/test_cli_add_type.py +87 -0
  11. rcdb-2.2.10/tests/test_save_files.py +105 -0
  12. rcdb-2.2.9/tests/test_save_files.py +0 -54
  13. {rcdb-2.2.9 → rcdb-2.2.10}/MANIFEST.in +0 -0
  14. {rcdb-2.2.9 → rcdb-2.2.10}/README.md +0 -0
  15. {rcdb-2.2.9 → rcdb-2.2.10}/pyproject.toml +0 -0
  16. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/__init__.py +0 -0
  17. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/__main__.py +0 -0
  18. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/alias.py +0 -0
  19. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/app_context.py +0 -0
  20. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/__init__.py +0 -0
  21. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/__main__.py +0 -0
  22. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/context.py +0 -0
  23. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/db.py +0 -0
  24. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/info.py +0 -0
  25. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/ls.py +0 -0
  26. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/repair/__init__.py +0 -0
  27. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/repair/evio_files.py +0 -0
  28. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/rp.py +0 -0
  29. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/run.py +0 -0
  30. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/select.py +0 -0
  31. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/web.py +0 -0
  32. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/coda_parser.py +0 -0
  33. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/condition_query_builder.py +0 -0
  34. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/config_parser.py +0 -0
  35. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/constants.py +0 -0
  36. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/errors.py +0 -0
  37. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/file_archiver.py +0 -0
  38. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/halld_daq_config_parser.py +0 -0
  39. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/lexer.py +0 -0
  40. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/log_format.py +0 -0
  41. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/model.py +0 -0
  42. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/stopwatch.py +0 -0
  43. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/update.py +0 -0
  44. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/__init__.py +0 -0
  45. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/__init__.py +0 -0
  46. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/conditions.py +0 -0
  47. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/files.py +0 -0
  48. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/logs.py +0 -0
  49. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/runs.py +0 -0
  50. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/select_values.py +0 -0
  51. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/statistics.py +0 -0
  52. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/pagination.py +0 -0
  53. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/run_table.py +0 -0
  54. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.bootstrap.css +0 -0
  55. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.bootstrap.min.css +0 -0
  56. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.foundation.css +0 -0
  57. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.foundation.min.css +0 -0
  58. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.jqueryui.css +0 -0
  59. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.jqueryui.min.css +0 -0
  60. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/jquery.dataTables.css +0 -0
  61. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/jquery.dataTables.min.css +0 -0
  62. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/jquery.dataTables_themeroller.css +0 -0
  63. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_asc.png +0 -0
  64. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_asc_disabled.png +0 -0
  65. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_both.png +0 -0
  66. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_desc.png +0 -0
  67. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_desc_disabled.png +0 -0
  68. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.bootstrap.js +0 -0
  69. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.bootstrap.min.js +0 -0
  70. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.foundation.js +0 -0
  71. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.foundation.min.js +0 -0
  72. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.jqueryui.js +0 -0
  73. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.jqueryui.min.js +0 -0
  74. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/jquery.dataTables.js +0 -0
  75. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/jquery.dataTables.min.js +0 -0
  76. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.bootstrap.css +0 -0
  77. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.bootstrap.min.css +0 -0
  78. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.dataTables.css +0 -0
  79. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.dataTables.min.css +0 -0
  80. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.foundation.css +0 -0
  81. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.foundation.min.css +0 -0
  82. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.jqueryui.css +0 -0
  83. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.jqueryui.min.css +0 -0
  84. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/dataTables.responsive.js +0 -0
  85. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/dataTables.responsive.min.js +0 -0
  86. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.bootstrap.js +0 -0
  87. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.bootstrap.min.js +0 -0
  88. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.foundation.js +0 -0
  89. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.foundation.min.js +0 -0
  90. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.jqueryui.js +0 -0
  91. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.jqueryui.min.js +0 -0
  92. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.bootstrap.css +0 -0
  93. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.bootstrap.min.css +0 -0
  94. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.dataTables.css +0 -0
  95. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.dataTables.min.css +0 -0
  96. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.foundation.css +0 -0
  97. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.foundation.min.css +0 -0
  98. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.jqueryui.css +0 -0
  99. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.jqueryui.min.css +0 -0
  100. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/js/dataTables.rowReorder.js +0 -0
  101. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/js/dataTables.rowReorder.min.js +0 -0
  102. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/datatables.css +0 -0
  103. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/datatables.js +0 -0
  104. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/datatables.min.css +0 -0
  105. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/datatables.min.js +0 -0
  106. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap-theme.css +0 -0
  107. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap-theme.css.map +0 -0
  108. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap-theme.min.css +0 -0
  109. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap-theme.min.css.map +0 -0
  110. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap.css +0 -0
  111. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap.css.map +0 -0
  112. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap.min.css +0 -0
  113. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap.min.css.map +0 -0
  114. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/buttons.dataTables.min.css +0 -0
  115. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/dataTables.tableTools.css +0 -0
  116. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery-ui.min.css +0 -0
  117. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery-ui.structure.min.css +0 -0
  118. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery-ui.theme.min.css +0 -0
  119. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery.dataTables.min.css +0 -0
  120. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery.dataTables.yadcf.css +0 -0
  121. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery.jsonview.css +0 -0
  122. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/main.css +0 -0
  123. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/select.dataTables.min.css +0 -0
  124. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/webintellisense.css +0 -0
  125. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/favicon.png +0 -0
  126. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.eot +0 -0
  127. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.svg +0 -0
  128. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.ttf +0 -0
  129. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.woff +0 -0
  130. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.woff2 +0 -0
  131. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/humans.txt +0 -0
  132. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/img/glyphicons-halflings-white.png +0 -0
  133. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/img/glyphicons-halflings.png +0 -0
  134. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/img/logo.png +0 -0
  135. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/bootstrap.js +0 -0
  136. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/bootstrap.min.js +0 -0
  137. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/clipboard.min.js +0 -0
  138. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/copy_clipboard.js +0 -0
  139. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/dataTables.buttons.min.js +0 -0
  140. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/dataTables.select.min.js +0 -0
  141. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery-2.1.0.min.js +0 -0
  142. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery-2.1.4.min.js +0 -0
  143. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery-ui.min.js +0 -0
  144. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery.dataTables.min.js +0 -0
  145. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery.dataTables.yadcf.js +0 -0
  146. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery.flot.min.js +0 -0
  147. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery.jsonview.js +0 -0
  148. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/npm.js +0 -0
  149. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/webintellisense-ace.js +0 -0
  150. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/webintellisense-codemirror.js +0 -0
  151. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/webintellisense-textbox.js +0 -0
  152. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/webintellisense.js +0 -0
  153. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/robots.txt +0 -0
  154. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/style.css +0 -0
  155. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/404.html +0 -0
  156. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/admin/index.html +0 -0
  157. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/admin/layout.html +0 -0
  158. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/admin/user.html +0 -0
  159. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/admin/users.html +0 -0
  160. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/conditions/index.html +0 -0
  161. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/custom_column_run_table.html +0 -0
  162. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/default_run_table.html +0 -0
  163. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/errors/forbidden_page.html +0 -0
  164. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/errors/layout.html +0 -0
  165. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/errors/page_not_found.html +0 -0
  166. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/errors/server_error.html +0 -0
  167. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/files/index.html +0 -0
  168. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/files/info.html +0 -0
  169. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/files/not_found.html +0 -0
  170. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/create_profile.html +0 -0
  171. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/footers/help.html +0 -0
  172. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/login.html +0 -0
  173. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/login_openid.html +0 -0
  174. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/reauth.html +0 -0
  175. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/reset_password.html +0 -0
  176. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/search.html +0 -0
  177. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/signup.html +0 -0
  178. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/index.html +0 -0
  179. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/layout.html +0 -0
  180. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/layouts/base.html +0 -0
  181. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/layouts/base2.html +0 -0
  182. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/login.html +0 -0
  183. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/logs/index.html +0 -0
  184. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_ask_user_to_update_ie.html +0 -0
  185. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_form.html +0 -0
  186. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_google_analytics.html +0 -0
  187. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_misc.html +0 -0
  188. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_reset_password.html +0 -0
  189. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/render_pagination.html +0 -0
  190. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/run_search_box.html +0 -0
  191. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/conditions.html +0 -0
  192. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/example.html +0 -0
  193. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/index.html +0 -0
  194. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/info.html +0 -0
  195. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/not_found.html +0 -0
  196. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/select_values/index.html +0 -0
  197. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/settings/layout.html +0 -0
  198. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/settings/password.html +0 -0
  199. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/settings/profile.html +0 -0
  200. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/show_entries.html +0 -0
  201. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/statistics/index.html +0 -0
  202. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/user/index.html +0 -0
  203. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/user/profile.html +0 -0
  204. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/dependency_links.txt +0 -0
  205. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/entry_points.txt +0 -0
  206. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/requires.txt +0 -0
  207. {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/top_level.txt +0 -0
  208. {rcdb-2.2.9 → rcdb-2.2.10}/setup.cfg +0 -0
  209. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_coda_parser.py +0 -0
  210. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_conditions.py +0 -0
  211. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_config_parser.py +0 -0
  212. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_get_run_periods.py +0 -0
  213. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_get_runs.py +0 -0
  214. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_halld_run_config_parser.py +0 -0
  215. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_select_runs.py +0 -0
  216. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_select_values.py +0 -0
  217. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_sql_schema_version.py +0 -0
  218. {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_value_comparison.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rcdb
3
- Version: 2.2.9
3
+ Version: 2.2.10
4
4
  Summary: RCDB - Run Conditions DataBase
5
5
  Author-email: Dmitry Romanov <romanov@jlab.org>
6
6
  License-Expression: MIT
@@ -0,0 +1,141 @@
1
+ import click
2
+ from rcdb.provider import RCDBProvider
3
+ from rcdb.model import ConditionType, ConfigurationFile
4
+ from rcdb.cli.context import pass_rcdb_context
5
+ from rcdb import ConditionType as CT
6
+
7
+ # A helper mapping from short strings like 'bool','int','float' -> ConditionType.<XYZ>_FIELD
8
+ TYPE_MAP = {
9
+ "bool": CT.BOOL_FIELD,
10
+ "int": CT.INT_FIELD,
11
+ "float": CT.FLOAT_FIELD,
12
+ "string": CT.STRING_FIELD,
13
+ "json": CT.JSON_FIELD,
14
+ "time": CT.TIME_FIELD,
15
+ "blob": CT.BLOB_FIELD
16
+ }
17
+
18
+
19
+ @click.group("add", help="Add data to the RCDB (types, conditions, files).")
20
+ @pass_rcdb_context
21
+ def add_command(context):
22
+ """
23
+ The 'add' group command. See subcommands like:
24
+ rcdb add type - adds Condition Type
25
+ rcdb add condition - adds Condition to a run
26
+ rcdb add file - adds File and associate it to a run
27
+ """
28
+ pass
29
+
30
+
31
+ @add_command.command(name="type", help="Add a new condition type to the DB.")
32
+ @click.argument("name", required=True)
33
+ @click.option("--type", "value_type",
34
+ type=click.Choice(TYPE_MAP.keys(), case_sensitive=False),
35
+ default="float", show_default=True,
36
+ help="Data type of the condition (bool, int, float, string, json, time, blob).")
37
+ @click.option("--description", "-d",
38
+ default="",
39
+ help="Optional description.")
40
+ @pass_rcdb_context
41
+ def add_type(context, name, value_type, description):
42
+ """
43
+ Adds a new condition type with given NAME and --type/--description.
44
+
45
+ Example:
46
+ rcdb add type beam_current --type=float --description "Beam current in nA"
47
+ """
48
+ db = context.db
49
+ actual_type = TYPE_MAP[value_type.lower()]
50
+
51
+ # Create or verify
52
+ click.echo(f"Creating condition type '{name}' of type '{value_type}'")
53
+ ct = db.create_condition_type(name, actual_type, description)
54
+ click.echo("Done.")
55
+
56
+
57
+ @add_command.command(name="condition", help="Add or update a condition for a run.")
58
+ @click.argument("run_number", type=int)
59
+ @click.argument("condition_name", type=str)
60
+ @click.argument("value", required=True)
61
+ @click.option("--replace", "-r", is_flag=True,
62
+ help="If present, replace existing value if it already exists.")
63
+ @pass_rcdb_context
64
+ def add_condition(context, run_number, condition_name, value, replace):
65
+ """
66
+ Adds a condition to RUN_NUMBER called CONDITION_NAME with given VALUE.
67
+
68
+ Example:
69
+ rcdb add condition 1000 my_value 123.4
70
+ rcdb add condition 1000 event_count 10000 --replace
71
+ """
72
+ db = context.db
73
+
74
+ # 1) Ensure run exists
75
+ run = db.get_run(run_number)
76
+ if not run:
77
+ run = db.create_run(run_number)
78
+ click.echo(f"Created new run #{run_number}")
79
+
80
+ # 2) Look up condition type
81
+ try:
82
+ condition_type = db.get_condition_type(condition_name)
83
+ except:
84
+ click.echo(f"ERROR: No condition type '{condition_name}' found in DB. Create it first with:\n"
85
+ f" rcdb add type {condition_name} --type=<type>\n", err=True)
86
+ raise click.Abort()
87
+
88
+ # 3) Convert value if needed
89
+ # (If 'value' is obviously numeric, you can do more advanced type conversion here if you like)
90
+ # For now we store the raw string and rely on ConditionType conversion in RCDB:
91
+ # db.add_condition will do the right thing (if you pass an int for an INT_FIELD, float for FLOAT_FIELD, etc.)
92
+ # You might do a quick parse though, e.g. if condition_type.value_type is CT.FLOAT_FIELD => float(value), etc.
93
+
94
+ # 4) Add condition
95
+ db.add_condition(run, condition_type, value, replace=replace)
96
+ db.session.commit()
97
+ click.echo(f"Added condition '{condition_name}' = '{value}' to run {run_number}")
98
+
99
+
100
+ @add_command.command(name="file", help="Attach or add a file to a run in the DB.")
101
+ @click.argument("run_number", type=int)
102
+ @click.argument("file_path", type=str)
103
+ @click.option("--importance", "-i", default=0, type=int,
104
+ help="Importance level, default=0 (lowest).")
105
+ @click.option("--overwrite", is_flag=True, default=False,
106
+ help="Overwrite existing content for the same path & run.")
107
+ @click.option("--content", default=None,
108
+ help="Optional raw content to store. If not specified, reads from file_path on disk.")
109
+ @pass_rcdb_context
110
+ def add_file(context, run_number, file_path, importance, overwrite, content):
111
+ """
112
+ Adds or attaches a configuration file to RUN_NUMBER using FILE_PATH.
113
+
114
+ Example:
115
+ rcdb add file 1000 /path/to/coda_run.log
116
+ rcdb add file 1000 /path/to/config.txt --importance=2 --overwrite
117
+ """
118
+ db = context.db
119
+ run = db.get_run(run_number)
120
+ if not run:
121
+ run = db.create_run(run_number)
122
+ click.echo(f"Created new run #{run_number}")
123
+
124
+ if content:
125
+ # If user provides --content, we do not read from the file path.
126
+ # We'll just store the provided content under that path.
127
+ the_content = content
128
+ click.echo("Using the provided --content instead of reading from disk.")
129
+ else:
130
+ # Otherwise read from disk
131
+ try:
132
+ with open(file_path, "r") as f:
133
+ the_content = f.read()
134
+ except Exception as ex:
135
+ click.echo(f"ERROR: Cannot open/read file '{file_path}': {ex}", err=True)
136
+ raise click.Abort()
137
+
138
+ # Now add
139
+ db.add_configuration_file(run, file_path, content=the_content, overwrite=overwrite, importance=importance)
140
+ db.session.commit()
141
+ click.echo(f"File '{file_path}' attached to run {run_number}.")
@@ -15,6 +15,7 @@ from .db import db_command
15
15
  from .rp import rp_command
16
16
  from .web import web_command
17
17
  from .info import info_command
18
+ from .add import add_command
18
19
 
19
20
 
20
21
  pass_rcdb_context = click.make_pass_decorator(RcdbApplicationContext)
@@ -69,4 +70,5 @@ rcdb_cli.add_command(db_command)
69
70
  rcdb_cli.add_command(rp_command)
70
71
  rcdb_cli.add_command(web_command)
71
72
  rcdb_cli.add_command(info_command)
73
+ rcdb_cli.add_command(add_command)
72
74
 
@@ -711,8 +711,142 @@ class RCDBProvider(object):
711
711
 
712
712
  return query.first()
713
713
 
714
+ """
715
+ RCDB data provider that uses SQLAlchemy for accessing databases
716
+ """
717
+
718
+ # ------------------------------------------------
719
+ # Adds start time
720
+ # ------------------------------------------------
721
+ def add_run_start_time(self, run, dtm):
722
+ """
723
+ Sets staring time of run
724
+ """
725
+ assert (isinstance(dtm, datetime.datetime))
726
+
727
+ if not isinstance(run, Run): # run is given as run number not Run object
728
+ run = self.create_run(int(run))
729
+
730
+ if run.start_time == dtm:
731
+ return
732
+
733
+ log.debug(Lf("Setting start time '{}' to run '{}'", dtm, run.number))
734
+
735
+ run.start_time = dtm
736
+ self.session.commit()
737
+
738
+ # ------------------------------------------------
739
+ # Adds end time
740
+ # ------------------------------------------------
741
+ def add_run_end_time(self, run, dtm):
742
+ """Adds time of run"""
743
+ assert (isinstance(dtm, datetime.datetime))
744
+
745
+ if not isinstance(run, Run): # run is given as run number not Run object
746
+ run = self.create_run(int(run))
747
+
748
+ if run.end_time == dtm:
749
+ return
750
+
751
+ log.debug(Lf("Setting end time '{}' to run '{}'", dtm, run.number))
752
+ run.end_time = dtm
753
+ self.session.commit()
754
+
755
+ # ------------------------------------------------
756
+ #
757
+ # ------------------------------------------------
758
+ def add_configuration_file(self, run, path, content=None, overwrite=False, importance=0):
759
+ """Adds configuration file to run configuration. If such file exists
760
+ :param importance: 0 - HIGH importance, 1 - LOWER importance. Is used to show in WEB interface
761
+ :param overwrite: If this flag is true, such file for this run exists but checksumm is different,
762
+ file content will be overwritten
763
+ :param content: Content of a file. If not given, func tryes to open file by path.
764
+ :param path: Path of the file
765
+ :param run: Run number
766
+ """
767
+
768
+ def get_content():
769
+ if content:
770
+ return content
771
+ with open(path) as io_file:
772
+ return io_file.read()
773
+
774
+ log.debug("Processing configuration file")
775
+
776
+ if content is None:
777
+ log.debug(Lf("|- Content is not provided as func param, reading from FS '{}'", path))
778
+ check_sum = rcdb.file_archiver.get_file_sha256(path)
779
+ else:
780
+ log.debug(Lf("|- Content is NOT none, using it to put to DB", path))
781
+ check_sum = rcdb.file_archiver.get_string_sha256(content)
782
+
783
+ if not isinstance(run, Run): # run is given as run number not Run object
784
+ run = self.create_run(run)
785
+
786
+ if overwrite:
787
+ # If we have to potentially overwrite the file, we have to apply another logic
788
+ # First, we look at file with this name in this run
789
+ query = self.session.query(ConfigurationFile) \
790
+ .filter(ConfigurationFile.runs.contains(run)) \
791
+ .filter(ConfigurationFile.path == path) \
792
+ .order_by(desc(ConfigurationFile.id)) # we want latest
793
+ if query.count():
794
+ # There are file to overwrite!
795
+ conf_file = query.first()
796
+ conf_file.sha256 = check_sum
797
+ conf_file.path = path
798
+ conf_file.content = get_content()
799
+ conf_file.importance = importance
800
+ log.debug(Lf("|- File '{}' is getting overwritten", path))
801
+
802
+ self.session.commit()
803
+ return conf_file
804
+
805
+ # Overwrite = false or is not possible
806
+ # Look, do we have a file with such name and checksumm?
807
+ file_query = self.session.query(ConfigurationFile) \
808
+ .filter(ConfigurationFile.sha256 == check_sum, ConfigurationFile.path == path)
809
+
810
+ if not file_query.count():
811
+ # no such file found!
812
+ log.debug(Lf("|- File '{}' not found in DB", path))
813
+
814
+ # create file.
815
+ conf_file = ConfigurationFile()
816
+ conf_file.sha256 = check_sum
817
+ conf_file.path = path
818
+ conf_file.content = get_content()
819
+ conf_file.importance = importance
820
+
821
+ # put it to DB and associate with run
822
+ self.session.add(conf_file)
823
+ self.session.commit()
824
+
825
+ conf_file.runs.append(run)
826
+
827
+ # save and exit
828
+ self.session.commit()
829
+ self.add_log_record(conf_file, "File added to DB. Path: '{}'. Run: '{}'".format(path, run), run.number)
830
+ return conf_file
831
+
832
+ # such file already exists! Get it from database
833
+ conf_file = file_query.first()
834
+ log.debug(Lf("|- File '{}' found in DB by id: '{}'", path, conf_file.id))
835
+
836
+ # maybe... we even have this file in run conf?
837
+ if conf_file not in run.files:
838
+ conf_file.runs.append(run)
839
+ # run_conf.files.append(conf_file)
840
+ self.session.commit() # save and exit
841
+ self.add_log_record(conf_file, "File associated. Path: '{}'. Run: '{}'".format(path, run), run.number)
842
+ else:
843
+ log.debug(Lf("|- File already associated with run'{}'", run))
844
+
845
+ return conf_file
846
+
847
+
714
848
  def select_runs(self, search_str="", run_min=0, run_max=sys.maxsize, sort_desc=False):
715
- """ Searches RCDB for runs with e
849
+ """ Obsolete. Searches RCDB for runs with e
716
850
 
717
851
  :param sort_desc: if True result runs will by sorted descendant by run_number, ascendant if False
718
852
  :param run_min: minimum run to search
@@ -1283,138 +1417,8 @@ class RunSelectionResult(RcdbSelectionResult):
1283
1417
 
1284
1418
 
1285
1419
  class ConfigurationProvider(RCDBProvider):
1286
- """
1287
- RCDB data provider that uses SQLAlchemy for accessing databases
1288
- """
1289
-
1290
- # ------------------------------------------------
1291
- #
1292
- # ------------------------------------------------
1293
- def add_run_start_time(self, run, dtm):
1294
- """
1295
- Sets staring time of run
1296
- """
1297
- assert (isinstance(dtm, datetime.datetime))
1298
-
1299
- if not isinstance(run, Run): # run is given as run number not Run object
1300
- run = self.create_run(int(run))
1301
-
1302
- if run.start_time == dtm:
1303
- return
1304
-
1305
- log.debug(Lf("Setting start time '{}' to run '{}'", dtm, run.number))
1306
-
1307
- run.start_time = dtm
1308
- self.session.commit()
1309
-
1310
- # ------------------------------------------------
1311
- #
1312
- # ------------------------------------------------
1313
- def add_run_end_time(self, run, dtm):
1314
- """Adds time of run"""
1315
- assert (isinstance(dtm, datetime.datetime))
1316
-
1317
- if not isinstance(run, Run): # run is given as run number not Run object
1318
- run = self.create_run(int(run))
1319
-
1320
- if run.end_time == dtm:
1321
- return
1322
-
1323
- log.debug(Lf("Setting end time '{}' to run '{}'", dtm, run.number))
1324
- run.end_time = dtm
1325
- self.session.commit()
1326
-
1327
- # ------------------------------------------------
1328
- #
1329
- # ------------------------------------------------
1330
- def add_configuration_file(self, run, path, content=None, overwrite=False, importance=0):
1331
- """Adds configuration file to run configuration. If such file exists
1332
- :param importance: 0 - HIGH importance, 1 - LOWER importance. Is used to show in WEB interface
1333
- :param overwrite: If this flag is true, such file for this run exists but checksumm is different,
1334
- file content will be overwritten
1335
- :param content: Content of a file. If not given, func tryes to open file by path.
1336
- :param path: Path of the file
1337
- :param run: Run number
1338
- """
1339
-
1340
- def get_content():
1341
- if content:
1342
- return content
1343
- with open(path) as io_file:
1344
- return io_file.read()
1345
-
1346
- log.debug("Processing configuration file")
1347
-
1348
- if content is None:
1349
- log.debug(Lf("|- Content is not provided as func param, reading from FS '{}'", path))
1350
- check_sum = rcdb.file_archiver.get_file_sha256(path)
1351
- else:
1352
- log.debug(Lf("|- Content is NOT none, using it to put to DB", path))
1353
- check_sum = rcdb.file_archiver.get_string_sha256(content)
1354
-
1355
- if not isinstance(run, Run): # run is given as run number not Run object
1356
- run = self.create_run(run)
1357
-
1358
- if overwrite:
1359
- # If we have to potentially overwrite the file, we have to apply another logic
1360
- # First, we look at file with this name in this run
1361
- query = self.session.query(ConfigurationFile) \
1362
- .filter(ConfigurationFile.runs.contains(run)) \
1363
- .filter(ConfigurationFile.path == path) \
1364
- .order_by(desc(ConfigurationFile.id)) # we want latest
1365
- if query.count():
1366
- # There are file to overwrite!
1367
- conf_file = query.first()
1368
- conf_file.sha256 = check_sum
1369
- conf_file.path = path
1370
- conf_file.content = get_content()
1371
- conf_file.importance = importance
1372
- log.debug(Lf("|- File '{}' is getting overwritten", path))
1373
-
1374
- self.session.commit()
1375
- return conf_file
1376
-
1377
- # Overwrite = false or is not possible
1378
- # Look, do we have a file with such name and checksumm?
1379
- file_query = self.session.query(ConfigurationFile) \
1380
- .filter(ConfigurationFile.sha256 == check_sum, ConfigurationFile.path == path)
1381
-
1382
- if not file_query.count():
1383
- # no such file found!
1384
- log.debug(Lf("|- File '{}' not found in DB", path))
1385
-
1386
- # create file.
1387
- conf_file = ConfigurationFile()
1388
- conf_file.sha256 = check_sum
1389
- conf_file.path = path
1390
- conf_file.content = get_content()
1391
- conf_file.importance = importance
1392
-
1393
- # put it to DB and associate with run
1394
- self.session.add(conf_file)
1395
- self.session.commit()
1396
-
1397
- conf_file.runs.append(run)
1398
-
1399
- # save and exit
1400
- self.session.commit()
1401
- self.add_log_record(conf_file, "File added to DB. Path: '{}'. Run: '{}'".format(path, run), run.number)
1402
- return conf_file
1403
-
1404
- # such file already exists! Get it from database
1405
- conf_file = file_query.first()
1406
- log.debug(Lf("|- File '{}' found in DB by id: '{}'", path, conf_file.id))
1407
-
1408
- # maybe... we even have this file in run conf?
1409
- if conf_file not in run.files:
1410
- conf_file.runs.append(run)
1411
- # run_conf.files.append(conf_file)
1412
- self.session.commit() # save and exit
1413
- self.add_log_record(conf_file, "File associated. Path: '{}'. Run: '{}'".format(path, run), run.number)
1414
- else:
1415
- log.debug(Lf("|- File already associated with run'{}'", run))
1416
-
1417
- return conf_file
1420
+ """Obsolete. Still exists for backward compatibility. All methods moved to RCDBProvider"""
1421
+ pass
1418
1422
 
1419
1423
 
1420
1424
  def destroy_schema(db):
@@ -1,5 +1,5 @@
1
1
  # String version. Used both for setup.py and for internal code
2
- version = '2.2.9'
2
+ version = '2.2.10'
3
3
 
4
4
  # version as the tuple of ints
5
5
  version_tuple = tuple(int(val) for val in version.split('.'))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rcdb
3
- Version: 2.2.9
3
+ Version: 2.2.10
4
4
  Summary: RCDB - Run Conditions DataBase
5
5
  Author-email: Dmitry Romanov <romanov@jlab.org>
6
6
  License-Expression: MIT
@@ -28,6 +28,7 @@ rcdb.egg-info/requires.txt
28
28
  rcdb.egg-info/top_level.txt
29
29
  rcdb/cli/__init__.py
30
30
  rcdb/cli/__main__.py
31
+ rcdb/cli/add.py
31
32
  rcdb/cli/app.py
32
33
  rcdb/cli/context.py
33
34
  rcdb/cli/db.py
@@ -199,6 +200,9 @@ rcdb/web/templates/settings/profile.html
199
200
  rcdb/web/templates/statistics/index.html
200
201
  rcdb/web/templates/user/index.html
201
202
  rcdb/web/templates/user/profile.html
203
+ tests/test_cli_add_condition.py
204
+ tests/test_cli_add_file.py
205
+ tests/test_cli_add_type.py
202
206
  tests/test_coda_parser.py
203
207
  tests/test_conditions.py
204
208
  tests/test_config_parser.py
@@ -0,0 +1,139 @@
1
+ import os
2
+ import tempfile
3
+ import unittest
4
+ from click.testing import CliRunner
5
+
6
+ from rcdb.cli.app import rcdb_cli
7
+ from rcdb.provider import RCDBProvider, destroy_all_create_schema
8
+ from rcdb.model import ConditionType
9
+
10
+
11
+ class TestAddCondition(unittest.TestCase):
12
+ def setUp(self):
13
+ """
14
+ Creates a temporary SQLite file and initializes a fresh RCDB schema.
15
+ Then we disconnect so the file is not locked on Windows.
16
+ """
17
+ tmp_file = tempfile.NamedTemporaryFile(suffix=".db", delete=False)
18
+ self.db_file_name = tmp_file.name
19
+ tmp_file.close() # we only need the path
20
+
21
+ self.connection_str = "sqlite:///" + self.db_file_name
22
+
23
+ # Create the schema
24
+ self.db = RCDBProvider(self.connection_str, check_version=False)
25
+ destroy_all_create_schema(self.db)
26
+ self.db.session.commit() # Important: commit the new schema
27
+ self.db.disconnect()
28
+
29
+ def tearDown(self):
30
+ """
31
+ Disconnect if needed and remove the temporary .db file
32
+ """
33
+ try:
34
+ self.db.disconnect()
35
+ except:
36
+ pass
37
+ if os.path.exists(self.db_file_name):
38
+ try:
39
+ os.remove(self.db_file_name)
40
+ except:
41
+ pass
42
+
43
+ def test_add_condition_new_run(self):
44
+ """
45
+ Test adding a condition to a run that doesn't exist yet
46
+ => should create run #10 automatically.
47
+ """
48
+ # Reconnect, create the "beam_current" condition type, commit, then disconnect
49
+ self.db = RCDBProvider(self.connection_str, check_version=False)
50
+ self.db.create_condition_type("beam_current", ConditionType.FLOAT_FIELD, "Beam current")
51
+ self.db.session.commit()
52
+ self.db.disconnect()
53
+
54
+ runner = CliRunner()
55
+ result = runner.invoke(rcdb_cli, [
56
+ "--connection", self.connection_str,
57
+ "add", "condition", "10", "beam_current", "123.4"
58
+ ])
59
+
60
+ print("Output:\n", result.output)
61
+ if result.exception:
62
+ print("Exception:", result.exception)
63
+
64
+ self.assertEqual(result.exit_code, 0, msg=result.output)
65
+
66
+ # Check DB by reconnecting
67
+ self.db = RCDBProvider(self.connection_str, check_version=False)
68
+ run_10 = self.db.get_run(10)
69
+ self.assertIsNotNone(run_10, "Run #10 should be created automatically by 'add condition'")
70
+ val = run_10.get_condition_value("beam_current")
71
+ self.assertEqual(float(val), 123.4)
72
+
73
+ def test_add_condition_existing_run(self):
74
+ """
75
+ If run #5 exists, adding condition to it should just attach to the existing run.
76
+ Must also create the 'is_production' condition type so the CLI won't error.
77
+ """
78
+ self.db = RCDBProvider(self.connection_str, check_version=False)
79
+ # 1) Create run #5
80
+ self.db.create_run(5)
81
+ # 2) Also create 'is_production' condition type
82
+ self.db.create_condition_type("is_production", ConditionType.BOOL_FIELD, "Production run?")
83
+ self.db.session.commit()
84
+ self.db.disconnect()
85
+
86
+ runner = CliRunner()
87
+ result = runner.invoke(rcdb_cli, [
88
+ "--connection", self.connection_str,
89
+ "add", "condition", "5", "is_production", "True"
90
+ ])
91
+ self.assertEqual(result.exit_code, 0, msg=result.output)
92
+
93
+ # Check results
94
+ self.db = RCDBProvider(self.connection_str, check_version=False)
95
+ run_5 = self.db.get_run(5)
96
+ self.assertIsNotNone(run_5)
97
+
98
+ val = run_5.get_condition_value("is_production")
99
+ self.assertEqual(val, True)
100
+
101
+ def test_add_condition_replace(self):
102
+ """
103
+ If we already have a condition, test the --replace functionality
104
+ to overwrite it with a new value.
105
+ """
106
+ self.db = RCDBProvider(self.connection_str, check_version=False)
107
+ # Make sure the condition type exists
108
+ self.db.create_condition_type("beam_current", ConditionType.FLOAT_FIELD, "Beam current")
109
+
110
+ # Create run #1 and add beam_current=999.9
111
+ self.db.create_run(1)
112
+ self.db.add_condition(1, "beam_current", 999.9)
113
+ self.db.session.commit()
114
+ self.db.disconnect()
115
+
116
+ runner = CliRunner()
117
+ result = runner.invoke(rcdb_cli, [
118
+ "--connection", self.connection_str,
119
+ "add", "condition", "1", "beam_current", "100.1", "--replace"
120
+ ])
121
+ self.assertEqual(result.exit_code, 0, msg=result.output)
122
+
123
+ # Check
124
+ self.db = RCDBProvider(self.connection_str, check_version=False)
125
+ run_1 = self.db.get_run(1)
126
+ self.assertIsNotNone(run_1)
127
+ self.assertEqual(float(run_1.get_condition_value("beam_current")), 100.1)
128
+
129
+ def test_add_condition_missing_type(self):
130
+ """
131
+ If the condition type isn't in DB, the CLI should fail with an error.
132
+ """
133
+ runner = CliRunner()
134
+ result = runner.invoke(rcdb_cli, [
135
+ "--connection", self.connection_str,
136
+ "add", "condition", "2", "non_existent_type", "X"
137
+ ])
138
+ self.assertNotEqual(result.exit_code, 0) # Should fail
139
+ self.assertIn("ERROR: No condition type 'non_existent_type' found", result.output)