def post(self, request, *args, **kwargs): """ Edits a Project via "diffs" from a configuration file ala execute_project_config_diff(). Runs in the calling thread and therefore blocks. POST form fields: - request.data (required) must have a 'project_config' field containing a dict valid for execute_project_config_diff(). NB: this is different from other API args in this file in that it takes all required information as data, whereas others take their main data as a file in request.FILES, plus some additional data in request.data. """ project = self.get_object() if not is_user_ok_edit_project(request.user, project): # only the project owner can edit the project return HttpResponseForbidden() elif 'project_config' not in request.data: return JsonResponse({'error': "No 'project_config' data."}, status=status.HTTP_400_BAD_REQUEST) try: current_config_dict = config_dict_from_project(project, request) new_config_dict = request.data['project_config'] changes = project_config_diff(current_config_dict, new_config_dict) # database_changes = database_changes_for_project_config_diff(project, changes) logger.debug(f"ProjectDetail.post(): executing project config diff... changes={changes}") execute_project_config_diff(project, changes) logger.debug(f"ProjectDetail.post(): done") project_serializer = ProjectSerializer(project, context={'request': request}) return JsonResponse(project_serializer.data) except Exception as ex: return JsonResponse({'error': str(ex)}, status=status.HTTP_400_BAD_REQUEST)
def test_diff_from_file(self): _, _, po_user, _, _, _, _, _ = get_or_create_super_po_mo_users( is_create_super=True) project, _, _, _ = _make_docs_project(po_user) out_config_dict = config_dict_from_project( project, APIRequestFactory().request()) # this json file makes the same changes as _make_some_changes(): with open( Path('forecast_app/tests/project_diff/docs-project-edited.json' )) as fp: edited_config_dict = json.load(fp) changes = project_config_diff(out_config_dict, edited_config_dict) # # print a little report # print(f"* Analyzed {len(changes)} changes. Results:") # for change, num_points, num_named, num_bins, num_samples, num_quantiles, num_truth in \ # database_changes_for_project_config_diff(project, changes): # print(f"- {change.change_type.name} on {change.object_type.name} {change.object_pk!r} will delete:\n" # f" = {num_points} point predictions\n" # f" = {num_named} named predictions\n" # f" = {num_bins} bin predictions\n" # f" = {num_samples} samples\n" # f" = {num_quantiles} quantiles\n" # f" = {num_truth} truth rows") # same tests as test_execute_project_config_diff(): execute_project_config_diff(project, changes) self._do_make_some_changes_tests(project)
def test_execute_project_config_diff(self): _, _, po_user, _, _, _, _, _ = get_or_create_super_po_mo_users( is_create_super=True) project, _, _, _ = _make_docs_project(po_user) # make some changes out_config_dict = config_dict_from_project( project, APIRequestFactory().request()) edit_config_dict = copy.deepcopy(out_config_dict) _make_some_changes(edit_config_dict) changes = project_config_diff(out_config_dict, edit_config_dict) execute_project_config_diff(project, changes) self._do_make_some_changes_tests(project)
def test_execute_project_config_diff(self): _, _, po_user, _, _, _, _, _ = get_or_create_super_po_mo_users( is_create_super=True) project, _, _, _ = _make_docs_project(po_user) _update_scores_for_all_projects() # make some changes # note: using APIRequestFactory was the only way I could find to pass a request object. o/w you get: # AssertionError: `HyperlinkedIdentityField` requires the request in the serializer context. out_config_dict = config_dict_from_project( project, APIRequestFactory().request()) edit_config_dict = copy.deepcopy(out_config_dict) _make_some_changes(edit_config_dict) changes = project_config_diff(out_config_dict, edit_config_dict) execute_project_config_diff(project, changes) self._do_make_some_changes_tests(project)