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.
- {rcdb-2.2.9/rcdb.egg-info → rcdb-2.2.10}/PKG-INFO +1 -1
- rcdb-2.2.10/rcdb/cli/add.py +141 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/app.py +2 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/provider.py +137 -133
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/version.py +1 -1
- {rcdb-2.2.9 → rcdb-2.2.10/rcdb.egg-info}/PKG-INFO +1 -1
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/SOURCES.txt +4 -0
- rcdb-2.2.10/tests/test_cli_add_condition.py +139 -0
- rcdb-2.2.10/tests/test_cli_add_file.py +105 -0
- rcdb-2.2.10/tests/test_cli_add_type.py +87 -0
- rcdb-2.2.10/tests/test_save_files.py +105 -0
- rcdb-2.2.9/tests/test_save_files.py +0 -54
- {rcdb-2.2.9 → rcdb-2.2.10}/MANIFEST.in +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/README.md +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/pyproject.toml +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/__init__.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/__main__.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/alias.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/app_context.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/__init__.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/__main__.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/context.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/db.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/info.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/ls.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/repair/__init__.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/repair/evio_files.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/rp.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/run.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/select.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/cli/web.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/coda_parser.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/condition_query_builder.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/config_parser.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/constants.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/errors.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/file_archiver.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/halld_daq_config_parser.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/lexer.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/log_format.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/model.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/stopwatch.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/update.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/__init__.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/__init__.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/conditions.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/files.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/logs.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/runs.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/select_values.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/modules/statistics.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/pagination.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/run_table.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.bootstrap.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.bootstrap.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.foundation.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.foundation.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.jqueryui.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/dataTables.jqueryui.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/jquery.dataTables.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/jquery.dataTables.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/css/jquery.dataTables_themeroller.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_asc.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_asc_disabled.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_both.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_desc.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/images/sort_desc_disabled.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.bootstrap.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.bootstrap.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.foundation.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.foundation.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.jqueryui.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/dataTables.jqueryui.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/jquery.dataTables.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/DataTables-1.10.10/js/jquery.dataTables.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.bootstrap.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.bootstrap.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.dataTables.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.dataTables.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.foundation.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.foundation.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.jqueryui.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/css/responsive.jqueryui.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/dataTables.responsive.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/dataTables.responsive.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.bootstrap.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.bootstrap.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.foundation.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.foundation.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.jqueryui.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/Responsive-2.0.0/js/responsive.jqueryui.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.bootstrap.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.bootstrap.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.dataTables.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.dataTables.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.foundation.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.foundation.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.jqueryui.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/css/rowReorder.jqueryui.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/js/dataTables.rowReorder.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/RowReorder-1.1.0/js/dataTables.rowReorder.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/datatables.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/datatables.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/datatables.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/DataTables/datatables.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap-theme.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap-theme.css.map +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap-theme.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap-theme.min.css.map +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap.css.map +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/bootstrap.min.css.map +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/buttons.dataTables.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/dataTables.tableTools.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery-ui.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery-ui.structure.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery-ui.theme.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery.dataTables.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery.dataTables.yadcf.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/jquery.jsonview.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/main.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/select.dataTables.min.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/css/webintellisense.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/favicon.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.eot +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.svg +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.ttf +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.woff +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/fonts/glyphicons-halflings-regular.woff2 +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/humans.txt +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/img/glyphicons-halflings-white.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/img/glyphicons-halflings.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/img/logo.png +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/bootstrap.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/bootstrap.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/clipboard.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/copy_clipboard.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/dataTables.buttons.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/dataTables.select.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery-2.1.0.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery-2.1.4.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery-ui.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery.dataTables.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery.dataTables.yadcf.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery.flot.min.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/jquery.jsonview.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/npm.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/webintellisense-ace.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/webintellisense-codemirror.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/webintellisense-textbox.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/js/webintellisense.js +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/robots.txt +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/static/style.css +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/404.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/admin/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/admin/layout.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/admin/user.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/admin/users.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/conditions/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/custom_column_run_table.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/default_run_table.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/errors/forbidden_page.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/errors/layout.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/errors/page_not_found.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/errors/server_error.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/files/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/files/info.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/files/not_found.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/create_profile.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/footers/help.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/login.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/login_openid.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/reauth.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/reset_password.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/search.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/frontend/signup.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/layout.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/layouts/base.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/layouts/base2.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/login.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/logs/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_ask_user_to_update_ie.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_form.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_google_analytics.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_misc.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/macros/_reset_password.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/render_pagination.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/run_search_box.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/conditions.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/example.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/info.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/runs/not_found.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/select_values/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/settings/layout.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/settings/password.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/settings/profile.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/show_entries.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/statistics/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/user/index.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb/web/templates/user/profile.html +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/dependency_links.txt +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/entry_points.txt +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/requires.txt +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/rcdb.egg-info/top_level.txt +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/setup.cfg +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_coda_parser.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_conditions.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_config_parser.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_get_run_periods.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_get_runs.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_halld_run_config_parser.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_select_runs.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_select_values.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_sql_schema_version.py +0 -0
- {rcdb-2.2.9 → rcdb-2.2.10}/tests/test_value_comparison.py +0 -0
|
@@ -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
|
-
|
|
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):
|
|
@@ -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)
|