def test_prevent_rollback(self): with transaction.atomic(): Reporter.objects.create(first_name="Tintin") sid = transaction.savepoint() # trigger a database error inside an inner atomic without savepoint with self.assertRaises(DatabaseError): with transaction.atomic(savepoint=False): connection.cursor().execute( "SELECT no_such_col FROM transactions_reporter" ) # prevent atomic from rolling back since we're recovering manually self.assertTrue(transaction.get_rollback()) transaction.set_rollback(False) transaction.savepoint_rollback(sid) self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>']) self.assertAtomicSignalCalls( # Enter atomic transaction block. enter_block_atomic_signal_call_sequence(True) + # Create Reporter. create_model_atomic_signal_call_sequence() + # Enter and leave atomic transaction block. enter_block_atomic_signal_call_sequence(False, savepoint=False) + leave_block_atomic_signal_call_sequence(False, False, savepoint=False) + # Leave atomic transaction with recovered rollback. leave_block_atomic_signal_call_sequence(True, True) )
def test_force_rollback(self): with transaction.atomic(): Reporter.objects.create(first_name="Tintin") # atomic block shouldn't rollback, but force it. self.assertFalse(transaction.get_rollback()) transaction.set_rollback(True) self.assertQuerysetEqual(Reporter.objects.all(), [])
def test_ticket_11101(self): """Test that fixtures can be rolled back (ticket #11101).""" with transaction.atomic(): management.call_command("loaddata", "thingy.json", verbosity=0) self.assertEqual(Thingy.objects.count(), 1) transaction.set_rollback(True) self.assertEqual(Thingy.objects.count(), 0)
def one(output): with transaction.atomic(): output.append(('one', 'begin')) value = get_next_value() output.append(('one', value)) time.sleep(0.2) transaction.set_rollback(True) output.append(('one', 'rollback')) connection.close()
def handle_exception(self, *args, **kwargs): """Handle exception with transaction rollback.""" response = super(AtomicMixin, self).handle_exception(*args, **kwargs) if getattr(response, 'exception'): # We've suppressed the exception but still need to rollback any transaction. transaction.set_rollback(True) return response
def wrapped_func(*args, **kwargs): with atomic(using=using): res = func(*args, **kwargs) if not isinstance(res, HttpResponse) or res.status_code < 200 or res.status_code >= 400: set_rollback(True, using=using) return res
def test_atomic_allows_queries_after_fixing_transaction(self): r1 = Reporter.objects.create(first_name="Archibald", last_name="Haddock") with transaction.atomic(): r2 = Reporter(first_name="Cuthbert", last_name="Calculus", id=r1.id) with self.assertRaises(IntegrityError): r2.save(force_insert=True) # Mark the transaction as no longer needing rollback. transaction.set_rollback(False) r2.save(force_update=True) self.assertEqual(Reporter.objects.get(pk=r1.pk).last_name, "Calculus")
def test_prevent_rollback(self): with transaction.atomic(): Reporter.objects.create(first_name="Tintin") sid = transaction.savepoint() # trigger a database error inside an inner atomic without savepoint with self.assertRaises(DatabaseError), transaction.atomic(savepoint=False): connection.cursor().execute( "SELECT no_such_col FROM transactions_reporter") transaction.savepoint_rollback(sid) # atomic block should rollback, but prevent it, as we just did it. self.assertTrue(transaction.get_rollback()) transaction.set_rollback(False) self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
def run(): try: with transaction.atomic(): for f in active_fixtures(): assert f is not self if f.template == template: return False f() result = self.constraint(self.strategy.reify(template)) transaction.set_rollback(True) return result except UnsatisfiedAssumption: return False
def test_prevent_rollback(self): with transaction.atomic(): Reporter.objects.create(first_name="Tintin") sid = transaction.savepoint() # trigger a database error inside an inner atomic without savepoint with self.assertRaises(DatabaseError): with transaction.atomic(savepoint=False): connection.cursor().execute("SELECT no_such_col FROM transactions_reporter") # prevent atomic from rolling back since we're recovering manually self.assertTrue(transaction.get_rollback()) transaction.set_rollback(False) transaction.savepoint_rollback(sid) self.assertQuerysetEqual(Reporter.objects.all(), ["<Reporter: Tintin>"])
def get_ticket(self): try: return self._internal_get_ticket() except exceptions: connection = connections[self.db] # If the transaction is in an `atomic` block, and needs a rollback, # we should mark the database as rolled back. This is because the # database backend may not prevent running SQL queries in broken # transactions, in which case we need to say that we have handled # the rollback so we can try one more time. if (connection.in_atomic_block and transaction.get_rollback(using=self.db)): transaction.set_rollback(False, using=self.db) return self._internal_get_ticket()
def set_rollback(): if hasattr(transaction, 'set_rollback'): if connection.settings_dict.get('ATOMIC_REQUESTS', False): # If running in >=1.6 then mark a rollback as required, # and allow it to be handled by Django. transaction.set_rollback(True) elif transaction.is_managed(): # Otherwise handle it explicitly if in managed mode. if transaction.is_dirty(): transaction.rollback() transaction.leave_transaction_management() else: # transaction not managed pass
def process_view(self, request, view_func, view_args, view_kwargs): user = None if request.user.is_authenticated(): user = request.user if request.method == "GET": logger.debug("Start query request on the view %s." % view_func.__name__) # NOTE: We do not need create a changeset when we just SELECT somw records. response = view_func(request, *view_args, **view_kwargs) else: # trap the request and give response when the method is not defined in HTTP/1.1 if request.method not in ["HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", "PATCH", "OPTIONS"]: logger.error('Wrong method %s specified when calling %s', request.method.decode("utf-8"), request.path, exc_info=sys.exc_info()) response_data = json.dumps({"detail": 'Method "{method}" not allowed.'.format(method=request.method)}, ensure_ascii=False) response = HttpResponse(response_data, content_type='application/json') response.status_code = status.HTTP_405_METHOD_NOT_ALLOWED return response logger.debug("Start write request on the view %s." % view_func.__name__) try: with transaction.atomic(): comment = request.META.get("HTTP_PDC_CHANGE_COMMENT", None) request.changeset = models.Changeset(author=user, comment=comment) request.changeset.requested_on = datetime.now() response = view_func(request, *view_args, **view_kwargs) # response.exception=True means there is an error occurs. if getattr(response, 'exception', 0) or ( hasattr(response, 'status_code') and response.status_code >= 400 ): # avoid recording changeset on server error, also # abort the transaction so that no modifications are # done to database request.changeset.reset() transaction.set_rollback(True) else: request.changeset.commit() self._may_announce_big_change(request.changeset, request) except: # NOTE: catch all errors that were raised by view. # And log the trace back to the file. logger.error('View Function Error: %s', request.path, exc_info=sys.exc_info()) # we do not want to break the default exception processing chains, # so re-raise the exception to the upper level. raise return response
def test_check_constraints(self): """ Constraint checks should raise an IntegrityError when bad data is in the DB. """ with transaction.atomic(): # Create an Article. models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r) # Retrieve it from the DB a = models.Article.objects.get(headline="Test article") a.reporter_id = 30 with connection.constraint_checks_disabled(): a.save() with self.assertRaises(IntegrityError): connection.check_constraints() transaction.set_rollback(True)
def _update_stock(request, change_type): products = Product.objects.all().filter(discontinued=False).order_by('name') if request.method == 'GET': users = User.objects.all().filter(is_active=True).order_by('username') context = {'sellables': products.filter(category=0), #FIXME: Magic numbers 'refundables': products.filter(category=1), 'names': users} return render(request, change_type + ".html", context) elif request.method == 'POST': if len(request.POST.getlist("who")) == 0: return HttpResponse("From validation error: no users selected") with transaction.atomic(): updated = [] for p in products: req_qty = int(request.POST[str(p.pk) + "_qty"]) changed = req_qty != p.quantity updated.append((p, req_qty, changed)) # TODO: Tell the user whats wrong in a nicer way if not (req_qty >= 0 and qty_verify_funs[change_type][p.category](req_qty, p.quantity)): transaction.set_rollback(True) return HttpResponse("Form validation error: Invalid product quantity"); if any(map(lambda t: t[2], updated)): # TODO: Do something better with EventType handling event = Event(description = request.POST['what'], event_type = EventType.objects.get(tag = change_type), logged_user = request.user) event.save() for u in request.POST.getlist("who"): event.eventbyuser_set.add(EventByUser( name = User.objects.get(pk = u)), bulk=False) for p, req_qty, changed in updated: event.change_set.add(Change(product = p, quantity = req_qty, delta = req_qty - p.quantity), bulk=False) if changed: p.quantity = req_qty p.save() return HttpResponseRedirect("/"+ change_type) else: transaction.set_rollback(True) return HttpResponse("Form validation error: No quantities changed")
def test_disable_constraint_checks_context_manager(self): """ When constraint checks are disabled (using context manager), should be able to write bad data without IntegrityErrors. """ with transaction.atomic(): # Create an Article. models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r) # Retrieve it from the DB a = models.Article.objects.get(headline="Test article") a.reporter_id = 30 try: with connection.constraint_checks_disabled(): a.save() except IntegrityError: self.fail("IntegrityError should not have occurred.") transaction.set_rollback(True)
def test_force_rollback(self): with transaction.atomic(): Reporter.objects.create(first_name="Tintin") # atomic block shouldn't rollback, but force it. self.assertFalse(transaction.get_rollback()) transaction.set_rollback(True) self.assertQuerysetEqual(Reporter.objects.all(), []) self.assertAtomicSignalCalls( # Enter atomic transaction block. enter_block_atomic_signal_call_sequence(True) + # Create Reporter. create_model_atomic_signal_call_sequence() + # Leave atomic transaction with forced rollback. leave_block_atomic_signal_call_sequence(True, False) )
def _side_effect(*args): """ We want to raise an IntegrityError only on the first call of our mock """ def __second_side_effect(*args): return None # change the side effect so that the next time we do not # raise an IntegrityError mock.side_effect = __second_side_effect # we need to manually rollback the atomic transaction # merely raising IntegrityError is not enough # doing this means that a TransactionManagementError is raised # if we do new queries inside the transaction.atomic block transaction.set_rollback(True) raise IntegrityError
def custom_exception_handler(exc): # If you raise an error in solitude, it comes to here and # we rollback the transaction. set_rollback(True) if hasattr(exc, 'formatter'): try: return Response(exc.formatter(exc).format(), status=getattr(exc, 'status_code', 422)) except: # If the formatter fails, fall back to the standard # error formatting. log.exception('Failed to use formatter.') if isinstance(exc, BangoImmediateError): return Response(exc.message, status=400) return exception_handler(exc)
def test_merged_inner_savepoint_rollback(self): with transaction.atomic(): Reporter.objects.create(first_name="Tintin") with transaction.atomic(): Reporter.objects.create(first_name="Archibald", last_name="Haddock") with six.assertRaisesRegex(self, Exception, "Oops"): with transaction.atomic(savepoint=False): Reporter.objects.create(first_name="Calculus") raise Exception("Oops, that's his last name") # The third insert couldn't be roll back. Temporarily mark the # connection as not needing rollback to check it. self.assertTrue(transaction.get_rollback()) transaction.set_rollback(False) self.assertEqual(Reporter.objects.count(), 3) transaction.set_rollback(True) # The second block has a savepoint and must roll back. self.assertEqual(Reporter.objects.count(), 1) self.assertQuerysetEqual(Reporter.objects.all(), ['<Reporter: Tintin>'])
def test_disable_constraint_checks_manually(self): """ When constraint checks are disabled, should be able to write bad data without IntegrityErrors. """ with transaction.atomic(): # Create an Article. Article.objects.create( headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r, ) # Retrieve it from the DB a = Article.objects.get(headline="Test article") a.reporter_id = 30 try: connection.disable_constraint_checking() a.save() connection.enable_constraint_checking() except IntegrityError: self.fail("IntegrityError should not have occurred.") transaction.set_rollback(True)
def _ctit_db_wrapper(trans_safe=False): ''' Wrapper to avoid undesired actions by Django ORM when managing settings if only getting a setting, can use trans_safe=True, which will avoid throwing errors if the prior context was a broken transaction. Any database errors will be logged, but exception will be suppressed. ''' rollback_set = None is_atomic = None try: if trans_safe: is_atomic = connection.in_atomic_block if is_atomic: rollback_set = transaction.get_rollback() if rollback_set: logger.debug( 'Obtaining database settings in spite of broken transaction.' ) transaction.set_rollback(False) yield except DBError as exc: if trans_safe: if 'migrate' not in sys.argv and 'check_migrations' not in sys.argv: level = logger.exception if isinstance(exc, ProgrammingError): if 'relation' in str(exc) and 'does not exist' in str(exc): # this generally means we can't fetch Tower configuration # because the database hasn't actually finished migrating yet; # this is usually a sign that a service in a container (such as ws_broadcast) # has come up *before* the database has finished migrating, and # especially that the conf.settings table doesn't exist yet level = logger.debug level('Database settings are not available, using defaults.') else: logger.exception( 'Error modifying something related to database settings.') finally: if trans_safe and is_atomic and rollback_set: transaction.set_rollback(rollback_set)
def store_export_chunk_as_blob(data_export, bytes_written, fileobj, blob_size=DEFAULT_BLOB_SIZE): # adapted from `putfile` in `src/sentry/models/file.py` bytes_offset = 0 while True: contents = fileobj.read(blob_size) if not contents: return bytes_offset blob_fileobj = ContentFile(contents) blob = FileBlob.from_file(blob_fileobj, logger=logger) ExportedDataBlob.objects.create( data_export=data_export, blob=blob, offset=bytes_written + bytes_offset ) bytes_offset += blob.size # there is a maximum file size allowed, so we need to make sure we don't exceed it # NOTE: there seems to be issues with downloading files larger than 1 GB on slower # networks, limit the export to 1 GB for now to improve reliability if bytes_written + bytes_offset >= min(MAX_FILE_SIZE, 2 ** 30): transaction.set_rollback(True) return 0
def handle(self, *args, **options): loglevel = options.get('loglevel') try: loglevel = int(loglevel) except ValueError as e: self.stderr.write(self.style.ERROR( f"Unable to parse loglevel='{loglevel}' to an integer. Only numerical values accepted.")) sys.exit(1) logging.disable(loglevel) order_no: int = options.get('order_no')[0] year: int = options.get('year')[0] commit: bool = options.get('commit', False) if year < 1000: year += 2000 if not commit: self.stderr.write(self.style.WARNING("DRY RUN: No processed data will be committed.")) self.stderr.write(self.style.WARNING("\tTo commit, pass `-c` or `--commit` flag.\n")) # Validate that all passed DBFs exist self.stdout.write("Creating transaction savepoint.") sp = transaction.savepoint() self.stdout.write(self.style.HTTP_INFO(f"Beginning EoW analysis of Year: {year}, Order: {order_no}")) with transaction.atomic(): from HotBlock.analysis import hotblock_end_of_order_analysis hotblock_end_of_order_analysis(year, order_no, True) if not commit: self.stdout.write(self.style.WARNING("Rolling back database to generated savepoint.")) transaction.set_rollback(True) self.stdout.write(self.style.SUCCESS("Database rolled back.")) self.stdout.write( self.style.SUCCESS(f"Hotblock End of Week Analysis for Order `{order_no}` complete."))
def login(request): import json as j requestData = j.loads(request.body.decode('utf-8')) user = helpers.auth_user(requestData['username'], requestData['password']) # if user is None: # return json.Response('User name or Password Wrong', False) if user['status']: return json.Response(user['error_msg'], False) if user['user']: # generate token for authenticated user auth_token = helpers.auth_token(user['user'], request) if auth_token: auth_token['expiry'] = int(time.time())+36000 user_id=User.objects.get(username=requestData['username']) auth_token['username'] = requestData['username'] StoreAuthtokenTbl = AuthTokenMstr( user_id=user_id, jwt_token=auth_token['token'], expire_ts=int(time.time())+36000, created_on=int(time.time()) ) StoreAuthtokenTbl.save() user_login_history = UserLoginHistory( user_id=user_id, jwt_token=auth_token['token'], login_time=int(time.time()), expire_ts=int(time.time())+36000, # ip=socket.gethostbyname(socket.gethostname()), created_on=int(time.time()) ) user_login_history.save() return json.Response(auth_token) else: transaction.set_rollback(True) return json.Response('Check Headers', False) else: return json.Response('User name or Password Wrong', False) return json.Response('')
def store_export_chunk_as_blob(data_export, bytes_written, fileobj, blob_size=DEFAULT_BLOB_SIZE): # adapted from `putfile` in `src/sentry/models/file.py` bytes_offset = 0 while True: contents = fileobj.read(blob_size) if not contents: return bytes_offset blob_fileobj = ContentFile(contents) blob = FileBlob.from_file(blob_fileobj, logger=logger) ExportedDataBlob.objects.create(data_export=data_export, blob=blob, offset=bytes_written + bytes_offset) bytes_offset += blob.size # there is a maximum file size allowed, so we need to make sure we don't exceed it if bytes_written + bytes_offset >= MAX_FILE_SIZE: transaction.set_rollback(True) return 0
def main(self, batch_size=None, sleep=0): """Invoked from the management command to do all the work.""" batch_size = batch_size or self.BATCH_SIZE self.last_student_module_id = self.get_last_student_module_id() self.load_state() while self.next_student_module_id <= self.last_student_module_id: with transaction.atomic(): for smid in self.module_ids_to_check(batch_size): try: self.clean_one_student_module(smid) except Exception: # pylint: disable=broad-except trace = traceback.format_exc() self.say("Couldn't clean student_module_id {}:\n{}".format(smid, trace)) if self.dry_run: transaction.set_rollback(True) else: self.say("Committing") self.save_state() if sleep: time.sleep(sleep)
def test_check_constraints(self): """ Constraint checks should raise an IntegrityError when bad data is in the DB. """ with transaction.atomic(): # Create an Article. Article.objects.create( headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r, ) # Retrieve it from the DB a = Article.objects.get(headline="Test article") a.reporter_id = 30 with connection.constraint_checks_disabled(): a.save() try: connection.check_constraints(table_names=[Article._meta.db_table]) except IntegrityError: pass else: self.skipTest("This backend does not support integrity checks.") transaction.set_rollback(True)
def handle(self, db_path, *args, **options): # make the db easily accesible to all other methods self.db = dataset.connect("sqlite:///" + db_path) if not options["skip_chronicles"]: self.add_chronicles() # choose a single chronicle or iterate over all chronicles if not options["all"]: all_c = Chronicle.objects.all().values_list("name", flat=True) input_tex = ( "Please choose a chronicle:\n0: all\n" + "\n".join([f"{i+1}: {x}" for i, x in enumerate(all_c)]) + "\n") chosen_c_input = input(input_tex) if options["all"] or chosen_c_input == "0": for c in Chronicle.objects.all(): self.add_incidents_for_chronicle(c, not options["force"]) else: chosen_c = Chronicle.objects.get(name=all_c[int(chosen_c_input) - 1]) self.add_incidents_for_chronicle(chosen_c, not options["force"]) if options["dry_run"]: # Return, rolling back transaction when atomic block exits transaction.set_rollback(True) return self.stdout.write("syncing text vector fields...") Incident.objects.sync() Location.objects.sync() self.stdout.write("syncing autocomplete phrases...") generate_phrases() self.stdout.write(self.style.SUCCESS("Successfully imported data"))
def handle(self, *args, **options): outstanding_projects = Project.objects.filter(state__name__in=[ ProjectState.PendingApproval, ProjectState.Approved, ProjectState.Extended, ProjectState.PassedDeadline, ]) for project in outstanding_projects: try: with transaction.atomic(): updated = self.update_state( project, send_updates=options['send_updates']) if not options['update_db']: transaction.set_rollback(True) except Exception as e: for l in traceback.format_exc().splitlines(): self.stderr.write(self.style.ERROR(l)) self.stderr.write( self.style.ERROR('Error updating %s' % project)) self.stdout.write(self.style.SUCCESS('Processing complete'))
def process_view(self, request, view_func, view_args, view_kwargs): user = None if request.user.is_authenticated(): user = request.user if request.method == "GET": logger.debug("Start query request on the view %s." % view_func.__name__) # NOTE: We do not need create a changeset when we just SELECT somw records. response = view_func(request, *view_args, **view_kwargs) else: logger.debug("Start write request on the view %s." % view_func.__name__) try: with transaction.atomic(): request.changeset = models.Changeset(author=user) response = view_func(request, *view_args, **view_kwargs) # response.exception=True means there is an error occurs. if getattr(response, 'exception', 0) or ( hasattr(response, 'status_code') and response.status_code >= 400 ): # avoid recording changeset on server error, also # abort the transaction so that no modifications are # done to database request.changeset.reset() transaction.set_rollback(True) else: request.changeset.commit() except: # NOTE: catch all errors that were raised by view. # And log the trace back to the file. logger.error('View Function Error: %s', request.path, exc_info=sys.exc_info()) # we do not want to break the default exception processing chains, # so re-raise the exception to the upper level. raise return response
def enable(self): """ Mark this CloudAccount as enabled and perform operations to make it so. This has the side effect of calling the related content_object (e.g. AwsCloudAccount) to make any cloud-specific changes. If any that cloud-specific function fails, we rollback our state change and re-raise the exception for the caller to handle further. """ logger.info( _("'is_enabled' is %(is_enabled)s before enabling %(cloudaccount)s" ), { "is_enabled": self.is_enabled, "cloudaccount": self }, ) if not self.is_enabled: self.is_enabled = True self.enabled_at = get_now() self.save() try: self.content_object.enable() # delete stale ConcurrentUsage when an clount is enabled ConcurrentUsage.objects.filter(user=self.user, date=get_today()).delete() except Exception as e: # All failure notifications should happen during the failure logger.info(e) transaction.set_rollback(True) return False from api.tasks import notify_application_availability_task notify_application_availability_task.delay( self.user.username, self.platform_application_id, "available")
def handle(self, *args, **options): outstanding_projects = Project.objects.filter(state__name__in=[ ProjectState.PendingApproval, ProjectState.Approved, ProjectState.Extended, ProjectState.PassedDeadline, ]) self.stdout.write('Starting updates at %s' % timezone.now().strftime('%Y-%m-%d %H:%M:%S')) for project in outstanding_projects: try: with transaction.atomic(): updated = self.update_state(project, send_updates=options['send_updates']) if not options['update_db']: transaction.set_rollback(True) except Exception as e: for l in traceback.format_exc().splitlines(): self.stderr.write(self.style.ERROR(l)) self.stderr.write(self.style.ERROR('Error updating %s' % project)) self.stdout.write(self.style.SUCCESS('Processing complete'))
def delete_comment(request): # Based on variables passed in we get the comment the user is attempting to create/edit try: comment, previous_version = _get_target_comment(request) except InvalidCommentException as e: transaction.set_rollback(True) return JsonResponse({ 'ok': False, 'error_message': str(e), }) # Check if the user doesn't pass the appropriate permission check (on the parent_object)... # We call this on the parent comment because the comment itself may not have been saved yet (can't call .get_root on it) # TODO: Fix this for root comment? (no parent) parent_comment = comment.parent tree_root = parent_comment.get_root() parent_object = tree_root.content_object if not user_has_permission( request, parent_object, 'can_delete_comment', comment=comment): transaction.set_rollback(True) return JsonResponse({ 'ok': False, 'error_message': "You do not have permission to post this comment.", }) try: # The 'X_KWARGS' header is populated by settings.kwarg in comments.js kwargs = json.loads(request.META.get('HTTP_X_KWARGS', {})) comment_changed.send(sender=comment.__class__, comment=comment, request=request, version_saved=None, comment_action='pre_delete', kwargs=kwargs) comment.deleted = True comment.save() for child in comment.get_children(): child.deleted = True child.save() return JsonResponse({ 'ok': True, }) except Exception as e: # TODO: Handle this more eloquently? Log? Probably best not to pass back raw error. transaction.set_rollback(True) return JsonResponse({ 'ok': False, 'error_message': 'There was an error deleting the selected comment(s).', })
def importHistoricalDataForStock(ticker=str): #if not ticker.startswith('600'): # return stock = Stock.objects.get(ticker=ticker) # Skip stocks that already loaded # Data source from yahoo will append record for each day even if the stock is suspended. # Thus, if there's any day record of the stock, there're all of them from the beginning to the latest(atomic transaction) if stock.dayHist.count() > 0: #print('{} - skip {}({}) : already loaded'.format(threading.get_ident(),stock.name,stock.ticker)) return else: # add corresponding suffix according to the market(ss for Shanghai while sz for Shenzhen url = 'http://table.finance.yahoo.com/table.csv?s=' + ticker + ( ticker.startswith('60') and '.ss' or '.sz') print('{} - import day quote data for {}({}) from source: {}'.format( threading.get_ident(), stock.name, stock.ticker, url)) try: response = urllib.request.urlopen(url, timeout=30) reader = csv.reader(codecs.iterdecode(response, 'utf-8')) #skip first header row next(reader) print('start to record {}'.format(ticker)) # save day quote data to db for row in reader: obj = DayData(stock=stock, date=row[0], open=row[1], high=row[2], low=row[3], close=row[4], volume=row[5], adj_close=row[6]) obj.save() print('{} done'.format(ticker)) time.sleep(1) except (HTTPError, URLError) as error: print('{} - "HTTP or URL Error! - {}({})'.format( threading.get_ident(), stock.name, stock.ticker)) transaction.set_rollback(True) except timeout: print('{} - "Timeout - {}({})'.format(threading.get_ident(), stock.name, stock.ticker)) transaction.set_rollback(True) except: print('{} - "Unknown error - {}({}) - {}'.format( threading.get_ident(), stock.name, stock.ticker, sys.exc_info()[0])) transaction.set_rollback(True)
def test_merged_outer_rollback(self): with transaction.atomic(): Reporter.objects.create(first_name="Tintin") with transaction.atomic(savepoint=False): Reporter.objects.create(first_name="Archibald", last_name="Haddock") with six.assertRaisesRegex(self, Exception, "Oops"): with transaction.atomic(savepoint=False): Reporter.objects.create(first_name="Calculus") raise Exception("Oops, that's his last name") # The third insert couldn't be roll back. Temporarily mark the # connection as not needing rollback to check it. self.assertTrue(transaction.get_rollback()) transaction.set_rollback(False) self.assertEqual(Reporter.objects.count(), 3) transaction.set_rollback(True) # The second insert couldn't be roll back. Temporarily mark the # connection as not needing rollback to check it. self.assertTrue(transaction.get_rollback()) transaction.set_rollback(False) self.assertEqual(Reporter.objects.count(), 3) transaction.set_rollback(True) # The first block has a savepoint and must roll back. self.assertQuerysetEqual(Reporter.objects.all(), [])
def retrieve(self, request, *args, **kwargs): """执行retrieve操作 Args: request(Request): DRF Request *args(list): 可变参数 **kwargs(dict): 可变关键字参数 Returns: response(Response): 对请求的响应 """ # 查询预处理 error, reason = self._pre_process_retrieve(request, *args, **kwargs) if error: transaction.set_rollback(True) return self.set_response(error, reason, status=drf_status.HTTP_400_BAD_REQUEST) # 获取model instance instance = self.get_object(*args, **kwargs) # 查询 error, reason, response = self._perform_retrieve( request, instance, *args, **kwargs) if error: transaction.set_rollback(True) return self.set_response(error, reason, status=drf_status.HTTP_400_BAD_REQUEST) # 查询后处理 error, reason = self._post_process_retrieve(request, instance, *args, **kwargs) if error: transaction.set_rollback(True) return self.set_response(error, reason, status=drf_status.HTTP_400_BAD_REQUEST) return response
def post(self, request): with transaction.atomic(): try: patient = self.__get_or_create_patient(request.POST) if isinstance(patient, str): transaction.set_rollback(True) return HttpResponseBadRequest(patient) case = self.__get_or_create_case(request.POST, patient) if isinstance(case, str): transaction.set_rollback(True) return HttpResponseBadRequest(case) uploader = User.objects.get(username='******') lab_info_id = request.POST['labinfo'] lab_info = LabInfo.objects.get(pk=lab_info_id) format = request.POST['format'] type = request.POST['type'] uploaded_dt = datetime.now() file = request.FILES['file'] size = file.size name = file.name res = File.objects.update_or_create(file=file, case=case, uploader=uploader, lab_info=lab_info, format=format, type=type, uploaded_dt=uploaded_dt, size=size, name=name) return HttpResponseRedirect( reverse('file', kwargs={'file_id': res[0].pk})) except MultiValueDictKeyError as e: logger.error(str(e)) transaction.set_rollback(True) return HttpResponseBadRequest("Malformed upload")
def list(self, request, *args, **kwargs): """list请求,设置事务,并在异常的时候进行回滚 Args: request(Request): DRF Request *args(list): 可变参数 **kwargs(dict): 可变关键字参数 Returns: response(Response): 响应数据 """ # list请求预处理 error, reason = self._pre_process_list(request, *args, **kwargs) if error: transaction.set_rollback(True) return self.set_response(error, reason, status=drf_status.HTTP_400_BAD_REQUEST) # list请求 try: response = self._perform_list(request, *args, **kwargs) except Exception as error: transaction.set_rollback(True) return self.set_response('Failed to get model list', f'获取资源数据列表失败,错误信息为{error}', status=drf_status.HTTP_400_BAD_REQUEST) # list请求后处理 error, reason, response = self._post_process_list( request, response, *args, **kwargs) if error: transaction.set_rollback(True) return self.set_response(error, reason, status=drf_status.HTTP_400_BAD_REQUEST) return response
def rollback(self): from django.db import transaction as db_transaction db_transaction.set_rollback(True)
def _rollback_atomics(cls, atomics): """Rollback atomic blocks opened through the previous method""" for db_name in reversed(cls._databases_names()): transaction.set_rollback(True, using=db_name) atomics[db_name].__exit__(None, None, None)
def confirm_email_change(request, key): # pylint: disable=unused-argument """ User requested a new e-mail. This is called when the activation link is clicked. We confirm with the old e-mail, and update """ if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): return render_to_response('email_change_failed.html', {'err_msg': SYSTEM_MAINTENANCE_MSG}) with transaction.atomic(): try: pec = PendingEmailChange.objects.get(activation_key=key) except PendingEmailChange.DoesNotExist: response = render_to_response("invalid_email_key.html", {}) transaction.set_rollback(True) return response user = pec.user address_context = {'old_email': user.email, 'new_email': pec.new_email} if len(User.objects.filter(email=pec.new_email)) != 0: response = render_to_response("email_exists.html", {}) transaction.set_rollback(True) return response subject = render_to_string('emails/email_change_subject.txt', address_context) subject = ''.join(subject.splitlines()) message = render_to_string('emails/confirm_email_change.txt', address_context) u_prof = UserProfile.objects.get(user=user) meta = u_prof.get_meta() if 'old_emails' not in meta: meta['old_emails'] = [] meta['old_emails'].append( [user.email, datetime.datetime.now(UTC).isoformat()]) u_prof.set_meta(meta) u_prof.save() # Send it to the old email... try: user.email_user( subject, message, configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to old address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': user.email}) transaction.set_rollback(True) return response user.email = pec.new_email user.save() pec.delete() # And send it to the new email... try: user.email_user( subject, message, configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to new address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': pec.new_email}) transaction.set_rollback(True) return response response = render_to_response("email_change_successful.html", address_context) return response
def confirm_email_change(request, key): # pylint: disable=unused-argument """ User requested a new e-mail. This is called when the activation link is clicked. We confirm with the old e-mail, and update """ if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): return render_to_response('email_change_failed.html', {'err_msg': SYSTEM_MAINTENANCE_MSG}) with transaction.atomic(): try: pec = PendingEmailChange.objects.get(activation_key=key) except PendingEmailChange.DoesNotExist: response = render_to_response("invalid_email_key.html", {}) transaction.set_rollback(True) return response user = pec.user address_context = { 'old_email': user.email, 'new_email': pec.new_email } if len(User.objects.filter(email=pec.new_email)) != 0: response = render_to_response("email_exists.html", {}) transaction.set_rollback(True) return response use_https = request.is_secure() if settings.FEATURES['ENABLE_MKTG_SITE']: contact_link = marketing_link('CONTACT') else: contact_link = '{protocol}://{site}{link}'.format( protocol='https' if use_https else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('contact'), ) site = Site.objects.get_current() message_context = get_base_template_context(site) message_context.update({ 'old_email': user.email, 'new_email': pec.new_email, 'contact_link': contact_link, 'from_address': configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL), }) msg = EmailChangeConfirmation().personalize( recipient=Recipient(user.username, user.email), language=preferences_api.get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) u_prof = UserProfile.objects.get(user=user) meta = u_prof.get_meta() if 'old_emails' not in meta: meta['old_emails'] = [] meta['old_emails'].append([user.email, datetime.datetime.now(UTC).isoformat()]) u_prof.set_meta(meta) u_prof.save() # Send it to the old email... try: ace.send(msg) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to old address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': user.email}) transaction.set_rollback(True) return response user.email = pec.new_email user.save() pec.delete() # And send it to the new email... msg.recipient = Recipient(user.username, pec.new_email) try: ace.send(msg) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to new address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': pec.new_email}) transaction.set_rollback(True) return response response = render_to_response("email_change_successful.html", address_context) return response
def signal_handler(signal, frame): transaction.set_rollback(True) raise Exception('Received interrupt signal. Aborting...')
def view(request): data = {} data['permite_modificar'] = True if request.method == 'POST': if 'user' in request.session: if 'action' in request.POST: action = request.POST['action'] if action == 'add_pais': try: vali = PaisForm(request.POST, request.FILES) if vali.is_valid(): pais = Pais(nombre=vali.cleaned_data['nombre'], estado=vali.cleaned_data['estado']) pais.save() if 'imagen' in request.FILES: foto = request.FILES['imagen'] if foto.name.find(".") > 0: ext = foto.name[foto.name.rfind("."):] if ext != 'jpeg' or ext != 'jpg' or ext != 'png': return JsonResponse({ "result": "error", "mensaje": 'No es un archivo valido.' }) else: return JsonResponse({ "result": "error", "mensaje": 'No es un archivo valido.' }) foto.name = "imagen_pais_%s_%s" % (pais.id, ext) pais.imagen = foto pais.save() return JsonResponse({"result": "ok"}) else: return JsonResponse({ "result": "error", "mensaje": 'datos erroneos en el formulario.' }) except Exception as ex: transaction.set_rollback(True) return JsonResponse({ "result": "error", "mensaje": 'Ocurrio un problema contacte con el administrador.' }) elif action == 'edit_pais': try: vali = PaisForm(request.POST, request.FILES) if vali.is_valid(): pais = Pais.objects.get(pk=int(request.POST['id'])) pais.nombre = vali.cleaned_data['nombre'] pais.estado = vali.cleaned_data['estado'] if 'imagen' in request.FILES: foto = request.FILES['imagen'] if foto.name.find(".") > 0: ext = foto.name[foto.name.rfind("."):] else: return JsonResponse({ "result": "error", "mensaje": 'No es un archivo valido.' }) foto.name = "imagen_pais_%s_%s" % (pais.id, ext) pais.imagen = foto pais.save() return JsonResponse({"result": "ok"}) else: return JsonResponse({ "result": "error", "mensaje": 'datos erroneos en el formulario. %s' % vali._errors }) except Exception as ex: transaction.set_rollback(True) return JsonResponse({ "result": "error", "mensaje": 'Ocurrio un problema contacte con el administrador. %s' % ex }) elif action == 'del_pais': try: pais = Pais.objects.get(pk=int(request.POST['id'])) pais.delete() return JsonResponse({"result": "ok"}) except Exception as ex: transaction.set_rollback(True) return JsonResponse({ "result": "error", "mensaje": 'Ocurrio un problema contacte con el administrador.' }) return JsonResponse({ "result": "bad", "mensaje": u"Solicitud Incorrecta." }) else: return JsonResponse({"result": "session"}) else: if 'action' in request.GET: action = request.GET['action'] if action == 'add_pais': try: data['title'] = u'Agregar Pais' data['form'] = PaisForm(initial={'estado': True}) return render(request, "add_pais.html", data) except Exception as ex: pass elif action == 'edit_pais': try: data['title'] = u'Editar Pais' data['pais'] = pais = Pais.objects.get( pk=int(request.GET['id'])) data['form'] = PaisForm(initial={ 'nombre': pais.nombre, 'estado': pais.estado }) return render(request, "add_pais.html", data) except Exception as ex: pass elif action == 'del_pais': try: data['title'] = u'Eliminar Pais' data['pais'] = Pais.objects.get(pk=int(request.GET['id'])) return render(request, "del_pais.html", data) except Exception as ex: pass
def endTransaction(self): """Rollback transaction using Django's `atomic`.""" transaction.set_rollback(True) self.__atomic.__exit__(None, None, None) self.assertNotInTransaction()
def configure_content(instance: CourseInstance, url: str) -> Tuple[bool, List[str]]: """ Configures course content by trusted remote URL. """ if not url: return False, [_('COURSE_CONFIG_URL_REQUIRED')] # save the url before fetching config. The JWT system requires this to be # set, so that A+ knows which service to trust to have access to the course # instance. The aplus config url might need access to the course instance. # The other service might also need to have access to the course instance # before it can be configured from the url. instance.configure_url = url instance.save() try: url = url.strip() permissions = Permissions() permissions.instances.add(Permission.READ, id=instance.id) permissions.instances.add(Permission.WRITE, id=instance.id) response = aplus_get(url, permissions=permissions) response.raise_for_status() except Exception as e: return False, [ format_lazy( _('COURSE_CONFIG_ERROR_REQUEST_FAILED -- {error!s}'), error=e, ) ] try: config = json.loads(response.text) except Exception as e: return False, [ format_lazy( _('COURSE_CONFIG_ERROR_JSON_PARSER_FAILED -- {error!s}'), error=e, ) ] if not isinstance(config, dict): return False, [_("COURSE_CONFIG_ERROR_INVALID_JSON")] errors = config.get('errors', []) if not isinstance(errors, list): errors = [str(errors)] if not config.get('success', True): errors.insert(0, _("COURSE_CONFIG_ERROR_SERVICE_FAILED_TO_EXPORT")) return False, errors # wrap everything in a transaction to make sure invalid configuration isn't saved with transaction.atomic(): # Configure course instance attributes. if "start" in config: dt = parse_date(config["start"], errors) if dt: instance.starting_time = dt if "end" in config: dt = parse_date(config["end"], errors) if dt: instance.ending_time = dt if "enrollment_start" in config: instance.enrollment_starting_time = parse_date( config["enrollment_start"], errors, allow_null=True) if "enrollment_end" in config: instance.enrollment_ending_time = parse_date( config["enrollment_end"], errors, allow_null=True) if "lifesupport_time" in config: instance.lifesupport_time = parse_date(config["lifesupport_time"], errors, allow_null=True) if "archive_time" in config: instance.archive_time = parse_date(config["archive_time"], errors, allow_null=True) if "enrollment_audience" in config: enroll_audience = parse_choices( config["enrollment_audience"], { 'internal': CourseInstance.ENROLLMENT_AUDIENCE.INTERNAL_USERS, 'external': CourseInstance.ENROLLMENT_AUDIENCE.EXTERNAL_USERS, 'all': CourseInstance.ENROLLMENT_AUDIENCE.ALL_USERS, }, "enrollment_audience", errors) if enroll_audience is not None: instance.enrollment_audience = enroll_audience if "view_content_to" in config: view_content_to = parse_choices( config["view_content_to"], { 'enrolled': CourseInstance.VIEW_ACCESS.ENROLLED, 'enrollment_audience': CourseInstance.VIEW_ACCESS.ENROLLMENT_AUDIENCE, 'all_registered': CourseInstance.VIEW_ACCESS.ALL_REGISTERED, 'public': CourseInstance.VIEW_ACCESS.PUBLIC, }, "view_content_to", errors) if view_content_to is not None: instance.view_content_to = view_content_to if "index_mode" in config: index_mode = parse_choices( config["index_mode"], { 'results': CourseInstance.INDEX_TYPE.RESULTS, 'toc': CourseInstance.INDEX_TYPE.TOC, 'last': CourseInstance.INDEX_TYPE.LAST, 'experimental': CourseInstance.INDEX_TYPE.EXPERIMENT, }, "index_mode", errors) if index_mode is not None: instance.index_mode = index_mode numbering_choices = { 'none': CourseInstance.CONTENT_NUMBERING.NONE, 'arabic': CourseInstance.CONTENT_NUMBERING.ARABIC, 'roman': CourseInstance.CONTENT_NUMBERING.ROMAN, 'hidden': CourseInstance.CONTENT_NUMBERING.HIDDEN, } if "content_numbering" in config: numbering = parse_choices(config["content_numbering"], numbering_choices, "content_numbering", errors) if numbering is not None: instance.content_numbering = numbering if "module_numbering" in config: numbering = parse_choices(config["module_numbering"], numbering_choices, "module_numbering", errors) if numbering is not None: instance.module_numbering = numbering if "course_description" in config: # Course index.yaml files have previously used the field "description" # for a hidden description, so we use "course_description" for # the visible description. instance.description = str(config["course_description"]) if "course_footer" in config: instance.footer = str(config["course_footer"]) if "lang" in config: langs = config["lang"] if isinstance(langs, list): langs = [ lang for lang in langs if instance.is_valid_language(lang) ] if langs: instance.language = "|{}|".format("|".join(langs)) elif instance.is_valid_language(langs): instance.language = str(langs)[:5] if "contact" in config: instance.technical_error_emails = str(config["contact"]) if "head_urls" in config: head_urls = config["head_urls"] instance.head_urls = "\n".join(head_urls) if isinstance( head_urls, list) else str(head_urls) if "assistants" in config: if not isinstance(config["assistants"], list): errors.append(_('COURSE_CONFIG_ERROR_ASSISTANTS_AS_SID_ARRAY')) else: assistants = [] for sid in config["assistants"]: try: profile = UserProfile.get_by_student_id(student_id=sid) except UserProfile.DoesNotExist as err: errors.append( format_lazy( _('COURSE_CONFIG_ERROR_ASSISTANT_NO_USER_WITH_SID -- {id}' ), id=sid, )) else: assistants.append(profile) instance.set_assistants(assistants) instance.build_log_url = str( config['build_log_url']) if 'build_log_url' in config else '' # configure_url excluded from validation because the default Django URL # validation does not accept dotless domain names such as "grader" instance.full_clean(exclude=['configure_url', 'build_log_url']) instance.save() if not "categories" in config or not isinstance( config["categories"], dict): errors.append(_('COURSE_CONFIG_ERROR_CATEGORIES_REQUIRED_OBJECT')) transaction.set_rollback(True) return False, errors if not "modules" in config or not isinstance(config["modules"], list): errors.append(_('COURSE_CONFIG_ERROR_MODULES_REQUIRED_ARRAY')) transaction.set_rollback(True) return False, errors # Configure learning object categories. category_map = {} seen = [] for key, c in config.get("categories", {}).items(): if not "name" in c: errors.append(_('COURSE_CONFIG_ERROR_CATEGORY_REQUIRES_NAME')) continue try: category = instance.categories.get( name=format_localization(c["name"])) except LearningObjectCategory.DoesNotExist: category = LearningObjectCategory(course_instance=instance, name=format_localization( c["name"])) if "status" in c: category.status = str(c["status"]) if "description" in c: category.description = str(c["description"]) if "points_to_pass" in c: i = parse_int(c["points_to_pass"], errors) if not i is None: category.points_to_pass = i for field in [ "confirm_the_level", "accept_unofficial_submits", ]: if field in c: setattr(category, field, parse_bool(c[field])) category.full_clean() category.save() category_map[key] = category seen.append(category.id) for category in instance.categories.all(): if not category.id in seen: category.status = LearningObjectCategory.STATUS.HIDDEN category.save() # Configure course modules. seen_modules = [] seen_objects = [] nn = 0 n = 0 for m in config.get("modules", []): if not "key" in m: errors.append(_('COURSE_CONFIG_ERROR_MODULE_REQUIRES_KEY')) continue try: module = instance.course_modules.get(url=str(m["key"])) except CourseModule.DoesNotExist: module = CourseModule(course_instance=instance, url=str(m["key"])) if "order" in m: module.order = parse_int(m["order"], errors) else: n += 1 module.order = n if "title" in m: module.name = format_localization(m["title"]) elif "name" in m: module.name = format_localization(m["name"]) if not module.name: module.name = "-" if "status" in m: module.status = str(m["status"]) if "points_to_pass" in m: i = parse_int(m["points_to_pass"], errors) if not i is None: module.points_to_pass = i if "introduction" in m: module.introduction = str(m["introduction"]) if "open" in m: dt = parse_date(m["open"], errors) if dt: module.opening_time = dt if not module.opening_time: module.opening_time = instance.starting_time if "close" in m: dt = parse_date(m["close"], errors) if dt: module.closing_time = dt elif "duration" in m: dt = parse_duration(module.opening_time, m["duration"], errors) if dt: module.closing_time = dt if not module.closing_time: module.closing_time = instance.ending_time if "read-open" in m: module.reading_opening_time = parse_date(m["read-open"], errors, allow_null=True) if "late_close" in m: dt = parse_date(m["late_close"], errors) if dt: module.late_submission_deadline = dt module.late_submissions_allowed = True elif "late_duration" in m: dt = parse_duration(module.closing_time, m["late_duration"], errors) if dt: module.late_submission_deadline = dt module.late_submissions_allowed = True if "late_penalty" in m: f = parse_float(m["late_penalty"], errors) if not f is None: module.late_submission_penalty = f module.full_clean() module.save() seen_modules.append(module.id) if not ("numerate_ignoring_modules" in config \ and parse_bool(config["numerate_ignoring_modules"])): nn = 0 if "children" in m: nn = configure_learning_objects(category_map, module, m["children"], None, seen_objects, errors, nn) for module in instance.course_modules.all(): # cache invalidation uses the parent when learning object is saved: # prefetch parent so that it wont be fetched after the it was deleted for lobject in module.learning_objects.all().prefetch_related( 'parent'): if lobject.id not in seen_objects: exercise = lobject.as_leaf_class() if (not isinstance(exercise, BaseExercise) or exercise.submissions.count() == 0): exercise.delete() else: lobject.status = LearningObject.STATUS.HIDDEN lobject.order = 9999 # .parent may have been deleted: only save status and order lobject.save(update_fields=["status", "order"]) if module.id not in seen_modules: if module.learning_objects.count() == 0: module.delete() else: module.status = CourseModule.STATUS.HIDDEN module.save() # Clean up obsolete categories. for category in instance.categories.filter( status=LearningObjectCategory.STATUS.HIDDEN): if category.learning_objects.count() == 0: category.delete() if "publish_url" in config: success = False publish_errors = [] try: permissions = Permissions() permissions.instances.add(Permission.READ, id=instance.id) permissions.instances.add(Permission.WRITE, id=instance.id) response = aplus_get(config["publish_url"], permissions=permissions) except ConnectionError as e: publish_errors = [str(e)] else: if response.status_code != 200: publish_errors = [ format_lazy( _("PUBLISH_RESPONSE_NON_200 -- {status_code}"), status_code=response.status_code) ] if response.text: try: publish_errors = json.loads(response.text) except Exception as e: publish_errors = [ format_lazy(_( "PUBLISH_ERROR_JSON_PARSER_FAILED -- {e}, {text}" ), e=e, text=response.text) ] else: if isinstance(publish_errors, dict): success = publish_errors.get("success", True) publish_errors = publish_errors.get("errors", []) if isinstance(publish_errors, list): publish_errors = (str(e) for e in publish_errors) else: publish_errors = [str(publish_errors)] if publish_errors: if not success: errors.append( format_lazy( _("PUBLISHED_WITH_ERRORS -- {publish_url}"), publish_url=config['publish_url'])) errors.extend(str(e) for e in publish_errors) if not success: transaction.set_rollback(True) return False, errors return True, errors
def post_comment(request, send_signal=True): """ View function that handles inserting new/editing previously existing comments via Ajax """ # Based on variables passed in we get the comment the user is attempting to create/edit try: comment, previous_version = get_comment(request) except InvalidCommentException as e: transaction.rollback() return JsonResponse({ 'ok': False, 'error_message': str(e), }) # Check if the user doesn't pass the appropriate permission check (on the parent_object)... # We call this on the parent comment because the comment itself may not have been saved yet (can't call .get_root on it) # TODO: Fix this for root comment? (no parent) parent_comment = comment.parent tree_root = parent_comment.get_root() parent_object = tree_root.content_object if not user_can_post_comment(request, comment): transaction.set_rollback(True) return JsonResponse({ 'ok': False, 'error_message': "You do not have permission to post this comment.", }) # Check to make sure we are not trying to save a comment "deeper" than we are allowed... if is_past_max_depth(comment): transaction.set_rollback(True) return JsonResponse({ 'ok': False, 'error_message': "You cannot respond to this comment.", }) # If the comment object (NOT the message) hasn't been saved yet... if comment._state.adding == True: comment = add_comment(comment) # Now that we have a comment object, we get a 'lock' on it to prevent a race condition try: lock_comment(comment) except DatabaseError: transaction.set_rollback(True) # Someone is already trying to update this comment, so we need to return an appropriate error return JsonResponse({ 'ok': False, 'error_message': "Someone else is currently editing this comment. Please refresh your page and try again.", }) # Now we know we have sole access to the comment object at the moment so we need to check if we are editing the most recent version if not_most_recent_version(comment, previous_version): transaction.set_rollback(True) return JsonResponse({ 'ok': False, 'error_message': "You are not editing the most recent version of this comment. Please refresh your page and try again.", }) # Everything has checked out, so we save the new version and return the appropriate response version_form, new_version = create_new_version(request, comment) if version_form.is_valid(): comment_template, kwargs = get_template(request, comment, parent_object, tree_root, new_version, previous_version, send_signal=send_signal) return JsonResponse({ 'ok': True, 'html_content': loader.render_to_string(comment_template, context=kwargs) }) else: transaction.set_rollback(True) return JsonResponse({ 'ok': False, 'error_message': "There were errors in your submission. Please correct them and resubmit.", })
def confirm_email_change(request, key): # pylint: disable=unused-argument """ User requested a new e-mail. This is called when the activation link is clicked. We confirm with the old e-mail, and update """ if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): return render_to_response('email_change_failed.html', {'err_msg': SYSTEM_MAINTENANCE_MSG}) with transaction.atomic(): try: pec = PendingEmailChange.objects.get(activation_key=key) except PendingEmailChange.DoesNotExist: response = render_to_response("invalid_email_key.html", {}) transaction.set_rollback(True) return response user = pec.user address_context = { 'old_email': user.email, 'new_email': pec.new_email } if len(User.objects.filter(email=pec.new_email)) != 0: response = render_to_response("email_exists.html", {}) transaction.set_rollback(True) return response subject = render_to_string('emails/email_change_subject.txt', address_context) subject = ''.join(subject.splitlines()) message = render_to_string('emails/confirm_email_change.txt', address_context) u_prof = UserProfile.objects.get(user=user) meta = u_prof.get_meta() if 'old_emails' not in meta: meta['old_emails'] = [] meta['old_emails'].append([user.email, datetime.datetime.now(UTC).isoformat()]) u_prof.set_meta(meta) u_prof.save() # Send it to the old email... try: user.email_user( subject, message, configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL) ) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to old address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': user.email}) transaction.set_rollback(True) return response user.email = pec.new_email user.save() pec.delete() # And send it to the new email... try: user.email_user( subject, message, configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL) ) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to new address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': pec.new_email}) transaction.set_rollback(True) return response response = render_to_response("email_change_successful.html", address_context) return response
def handle(self, *args, **options): loglevel = options.get('loglevel') try: loglevel = int(loglevel) except ValueError as e: self.stderr.write( self.style.ERROR( f"Unable to parse loglevel='{loglevel}' to an integer. Only numerical values accepted." )) sys.exit(1) logging.disable(loglevel) order_no: int = options.get('order_no')[0] year: int = options.get('year')[0] commit: bool = options.get('commit', False) skip_errors: bool = options.get('skip', False) if year < 1000: year += 2000 if not commit: self.stderr.write( self.style.WARNING( "DRY RUN: No processed data will be committed.")) self.stderr.write( self.style.WARNING( "\tTo commit, pass `-c` or `--commit` flag.\n")) # Validate that all passed DBFs exist self.stdout.write("Creating transaction savepoint.") sp = transaction.savepoint() self.stdout.write( self.style.HTTP_INFO( f"Beginning order input for Year: `{year}`, Order: `{order_no}`" )) with transaction.atomic(): import os from math import ceil from django.conf import settings from Braumat.parser import parse_dbf from HotBlock.analysis import hotblock_analysis from HotBlock.models import Batch rootpath = os.path.join( os.path.split(settings.BASE_DIR)[0], '_data', '_hotblock', f'SRJA_{year % 1000}') filepath = os.path.join( f'ANR0{int(ceil(order_no / 50)) * 50:04d}', f'S{year % 1000}00{order_no:03d}.DBF', ) hotblock_production = os.path.join(rootpath, 'REZ_001', filepath) hotblock_fmb = os.path.join(rootpath, 'REZ_004', filepath) coldblock_wortline = os.path.join( rootpath.replace('_hot', '_cold'), 'REZ_001', filepath) for f in (hotblock_production, hotblock_fmb, coldblock_wortline): if os.path.isfile(f): _logger.debug(f"File found at f=`{f}`") self.stdout.write( self.style.HTTP_INFO( f"Being parse of file located at `{f}`")) parse_dbf(f, skip_errors) self.stdout.write( self.style.SUCCESS('\tFile parsed successfully.')) else: self.stderr.write( self.style.ERROR( f"Unable to locate Data file expected at: `{f}`")) _logger.debug( f"Unable to locate Data file expected at: `{f}`") self.stdout.write( self.style.HTTP_INFO( "Beginning HotBlock Analysis of unlocked, unanalyzed batches..." )) batches = Batch.objects.filter(date__year=year, order=order_no, locked=False, analyzed=False) self.stdout.write(self.style.HTTP_INFO(f'{len(batches)} found.')) for batch in batches: hotblock_analysis(batch, True) if not commit: self.stdout.write( self.style.WARNING( "Rolling back database to generated savepoint.")) transaction.set_rollback(True) self.stdout.write(self.style.SUCCESS("Database rolled back.")) self.stdout.write( self.style.SUCCESS( f"Hotblock End of Week Analysis for Order `{order_no}` complete." ))
def _ctit_db_wrapper(trans_safe=False): ''' Wrapper to avoid undesired actions by Django ORM when managing settings if only getting a setting, can use trans_safe=True, which will avoid throwing errors if the prior context was a broken transaction. Any database errors will be logged, but exception will be suppressed. ''' rollback_set = None is_atomic = None try: if trans_safe: is_atomic = connection.in_atomic_block if is_atomic: rollback_set = transaction.get_rollback() if rollback_set: logger.debug( 'Obtaining database settings in spite of broken transaction.' ) transaction.set_rollback(False) yield except DBError: if 'migrate' in sys.argv and get_tower_migration_version() < '310': logger.info('Using default settings until version 3.1 migration.') else: # We want the _full_ traceback with the context # First we get the current call stack, which constitutes the "top", # it has the context up to the point where the context manager is used top_stack = StringIO() traceback.print_stack(file=top_stack) top_lines = top_stack.getvalue().strip('\n').split('\n') top_stack.close() # Get "bottom" stack from the local error that happened # inside of the "with" block this wraps exc_type, exc_value, exc_traceback = sys.exc_info() bottom_stack = StringIO() traceback.print_tb(exc_traceback, file=bottom_stack) bottom_lines = bottom_stack.getvalue().strip('\n').split('\n') # Glue together top and bottom where overlap is found bottom_cutoff = 0 for i, line in enumerate(bottom_lines): if line in top_lines: # start of overlapping section, take overlap from bottom top_lines = top_lines[:top_lines.index(line)] bottom_cutoff = i break bottom_lines = bottom_lines[bottom_cutoff:] tb_lines = top_lines + bottom_lines tb_string = '\n'.join( ['Traceback (most recent call last):'] + tb_lines + ['{}: {}'.format(exc_type.__name__, str(exc_value))]) bottom_stack.close() # Log the combined stack if trans_safe: if 'check_migrations' not in sys.argv: logger.warning( 'Database settings are not available, using defaults, error:\n{}' .format(tb_string)) else: logger.error( 'Error modifying something related to database settings.\n{}' .format(tb_string)) finally: if trans_safe and is_atomic and rollback_set: transaction.set_rollback(rollback_set)
def db(db_setup): with transaction.atomic(): yield None transaction.set_rollback(True)
def signal_handler(signal, frame): transaction.set_rollback(True) raise Exception("Received interrupt signal. Aborting...")
def cct_fermenter_analysis(batch: FermBatch, commit: bool = False) -> FermBatch: from django.db.models import OuterRef, Subquery from Braumat.constants.sequences import WORT_LINE from Braumat.constants.dfm import PV_WORT_LINE_CCT from HotBlock.models import Batch as HotBatch, StepRecord as HotStepRecord _logger.info(f'{batch}: Found category=`{CR.CCTS_FERM}`') if batch.tank is None: _logger.info(f'{batch}: No tank found on batch. Assigning Tank.') try: batch.tank = batch.steprecord_set.select_related('step__sequence').prefetch_related('step__sequence__tank_set').first().step.sequence.tank_set.first() except AttributeError as e: _logger.critical(f'{batch}: {e}') raise e tankstr = f'{batch.tank.cellar}{batch.tank.number:02d}' _logger.info(f'Querying HotBlock for batches with WORT-LINE Tank=`{tankstr}`') tank_sub = Subquery(HotStepRecord.objects.filter(batch=OuterRef('pk'), step__sequence__id=WORT_LINE._PK, step__number=WORT_LINE.Transfer).values(PV_WORT_LINE_CCT)[:1]) hotbatches = HotBatch.objects.annotate(tank=tank_sub).filter(order=batch.order, date__year=batch.date.year, batch__range=(batch.batch, batch.batch + 20), tank=f'{tankstr}') if hotbatches.count() < 1: _logger.error(f'{batch}: No HotBlock FermBatches found with a related tank=`{tankstr}`') else: hotbatches.update(fermbatch=batch) _logger.debug(f'{batch} Updated ColdBlock batch for `{hotbatches.count()}` HotBlock batches in tank=`{tankstr}`') initial_volume = hotbatches.aggregate(iv=models.Sum('bbls')) basestep = batch.steprecord_set.order_by('-end_time').filter(step__sequence=getattr(batch.tank, 'sequence', None)) end_filling_step = basestep.filter(step__number=CCT_GENERAL.Filling) start_ferm_step = basestep.order_by('start_time').filter(step__number=CCT_GENERAL.Start_ferm) if hotbatches.count() > 0 and ( end_filling_step.exists() or start_ferm_step.exists() ): from Braumat.constants.dfm import GET_FIELD_DATA from Braumat.constants.sequences import WORT_COOLER from HotBlock.models import StepRecord as HotStepRecord batch.time_start = HotStepRecord.objects.filter( batch=batch.hotbatch_set.order_by('brew_number').only('pk').first().pk, step__sequence=WORT_COOLER._PK, step__number=WORT_COOLER.Temp_stabilisation).order_by('start_time').values_list('start_time', flat=True)[0] batch.time_full = end_filling_step.values_list('end_time', flat=True)[0] if end_filling_step.exists() else start_ferm_step.values_list('start_time', flat=True)[0] batch.initial_volume = initial_volume['iv'] end_filling_step = end_filling_step.first() start_ferm_step = start_ferm_step.first() try: filling_step = end_filling_step if end_filling_step.end_time > start_ferm_step.start_time else start_ferm_step except AttributeError: filling_step = end_filling_step if end_filling_step else start_ferm_step pv_volume = GET_FIELD_DATA(filling_step, 'process_value_04', True) if abs(batch.initial_volume - pv_volume)/pv_volume < 0.2 and batch.recipe is not None: _logger.debug(f'{batch}: Critera met. Setting anaylzed=`{True}`') batch.analyzed = True elif batch.recipe is not None: warning = create_warning(batch, WR.AnalysisError, f'{batch}: Batch initial_volume=`{batch.initial_volume}` is in excess of 20% error from step Process Value Volume=`{pv_volume}` at {abs(batch.initial_volume - pv_volume)/pv_volume * 100}%') warning.save() _logger.warning(warning.log_str()) else: warning = create_warning(batch, WR.AnalysisError, f'{batch}: No `Filling` or `Start Ferm` step found.') warning.save() _logger.error(warning.log_str()) batch.save() if not commit: transaction.set_rollback(True) return batch
def _update_stock(request, change_type): products = Product.objects.all().filter( discontinued=False).order_by('name') if request.method == 'GET': if change_type == 'replenish': products = products.filter(quantity__gt=0) users = User.objects.all().filter(is_active=True).order_by('username') context = { 'sellables': products.filter(category=0), # FIXME: Magic numbers 'refundables': products.filter(category=1), 'names': users } return render(request, change_type + ".html", context) elif request.method == 'POST': if len(request.POST.getlist("who")) == 0: return HttpResponse("From validation error: no users selected") with transaction.atomic(): updated = [] for p in products: p_qty = str(p.pk) + "_qty" if p_qty in request.POST: req_qty = int(request.POST[p_qty]) else: continue changed = req_qty != p.quantity updated.append((p, req_qty, changed)) # TODO: Tell the user whats wrong in a nicer way if not (req_qty >= 0 and qty_verify_funs[change_type][p.category]( req_qty, p.quantity)): transaction.set_rollback(True) return HttpResponse( "Form validation error: Invalid product quantity") if any(map(lambda t: t[2], updated)): # TODO: Do something better with EventType handling event = Event( description=request.POST['what'], event_type=EventType.objects.get(tag=change_type), logged_user=request.user) event.save() for u in request.POST.getlist("who"): event.eventbyuser_set.add( EventByUser(name=User.objects.get(pk=u)), bulk=False) for p, req_qty, changed in updated: event.change_set.add(Change(product=p, quantity=req_qty, delta=req_qty - p.quantity), bulk=False) if changed: p.quantity = req_qty p.save() return HttpResponseRedirect("/" + change_type) else: transaction.set_rollback(True) return HttpResponse( "Form validation error: No quantities changed")
def confirm_email_change(request, key): # pylint: disable=unused-argument """ User requested a new e-mail. This is called when the activation link is clicked. We confirm with the old e-mail, and update """ if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): return render_to_response('email_change_failed.html', {'err_msg': SYSTEM_MAINTENANCE_MSG}) with transaction.atomic(): try: pec = PendingEmailChange.objects.get(activation_key=key) except PendingEmailChange.DoesNotExist: response = render_to_response("invalid_email_key.html", {}) transaction.set_rollback(True) return response user = pec.user address_context = {'old_email': user.email, 'new_email': pec.new_email} if len(User.objects.filter(email=pec.new_email)) != 0: response = render_to_response("email_exists.html", {}) transaction.set_rollback(True) return response use_https = request.is_secure() if settings.FEATURES['ENABLE_MKTG_SITE']: contact_link = marketing_link('CONTACT') else: contact_link = '{protocol}://{site}{link}'.format( protocol='https' if use_https else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('contact'), ) site = Site.objects.get_current() message_context = get_base_template_context(site) message_context.update({ 'old_email': user.email, 'new_email': pec.new_email, 'contact_link': contact_link, 'from_address': configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL), }) msg = EmailChangeConfirmation().personalize( recipient=Recipient(user.username, user.email), language=preferences_api.get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) u_prof = UserProfile.objects.get(user=user) meta = u_prof.get_meta() if 'old_emails' not in meta: meta['old_emails'] = [] meta['old_emails'].append( [user.email, datetime.datetime.now(UTC).isoformat()]) u_prof.set_meta(meta) u_prof.save() # Send it to the old email... try: ace.send(msg) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to old address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': user.email}) transaction.set_rollback(True) return response user.email = pec.new_email user.save() pec.delete() # And send it to the new email... msg.recipient = Recipient(user.username, pec.new_email) try: ace.send(msg) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to new address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': pec.new_email}) transaction.set_rollback(True) return response response = render_to_response("email_change_successful.html", address_context) return response
def process_view(self, request, view_func, view_args, view_kwargs): user = None if request.user.is_authenticated(): user = request.user if request.method == "GET": logger.debug("Start query request on the view %s." % view_func.__name__) # NOTE: We do not need create a changeset when we just SELECT somw records. response = view_func(request, *view_args, **view_kwargs) else: # trap the request and give response when the method is not defined in HTTP/1.1 if request.method not in [ "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", "PATCH", "OPTIONS" ]: logger.error('Wrong method %s specified when calling %s', request.method.decode("utf-8"), request.path, exc_info=sys.exc_info()) response_data = json.dumps( { "detail": 'Method "{method}" not allowed.'.format( method=request.method) }, ensure_ascii=False) response = HttpResponse(response_data, content_type='application/json') response.status_code = status.HTTP_405_METHOD_NOT_ALLOWED return response logger.debug("Start write request on the view %s." % view_func.__name__) try: with transaction.atomic(): comment = request.META.get("HTTP_PDC_CHANGE_COMMENT", None) request.changeset = models.Changeset(author=user, comment=comment) request.changeset.requested_on = datetime.now() response = view_func(request, *view_args, **view_kwargs) # response.exception=True means there is an error occurs. if getattr(response, 'exception', 0) or (hasattr(response, 'status_code') and response.status_code >= 400): # avoid recording changeset on server error, also # abort the transaction so that no modifications are # done to database request.changeset.reset() transaction.set_rollback(True) else: request.changeset.commit() self._may_announce_big_change(request.changeset, request) except Exception: # NOTE: catch all errors that were raised by view. # And log the trace back to the file. logger.error('View Function Error: %s', request.path, exc_info=sys.exc_info()) # we do not want to break the default exception processing chains, # so re-raise the exception to the upper level. raise return response
def set_rollback(): atomic_requests = connection.settings_dict.get('ATOMIC_REQUESTS', False) if atomic_requests and connection.in_atomic_block: transaction.set_rollback(True)
def set_rollback(): atomic_requests = connection.settings_dict.get('ATOMIC_REQUESTS', False) if atomic_requests and connection.in_atomic_block: transaction.set_rollback(True)