def soft_assert(to=None, notify_admins=False,
                fail_if_debug=False, exponential_backoff=True, skip_frames=0,
                send_to_ops=True,):

    if isinstance(to, basestring):
        to = [to]

    if to is not None and send_to_ops and settings.SOFT_ASSERT_EMAIL:
        to = to + [settings.SOFT_ASSERT_EMAIL]

    def send_to_recipients(subject, message):
        send_mail_async.delay(
            # this prefix is automatically added in mail_admins
            # but not send mail
            subject=settings.EMAIL_SUBJECT_PREFIX + subject,
            message=message,
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=to,
        )

    def send_to_admins(subject, message):
        mail_admins_async.delay(
            subject=subject,
            message=message,
        )

    if to and notify_admins:
        def send(info):
            if not settings.DEBUG:
                _send_message(info, backend=send_to_admins)
            _send_message(info, backend=send_to_recipients)
    elif to:
        def send(info):
            _send_message(info, backend=send_to_recipients)
    elif notify_admins:
        def send(info):
            if not settings.DEBUG:
                _send_message(info, backend=send_to_admins)
    else:
        raise ValueError('You must call soft assert with either a '
                         'list of recipients or notify_admins=True')

    if fail_if_debug:
        debug = settings.DEBUG
    else:
        debug = False

    return SoftAssert(
        debug=debug,
        send=send,
        use_exponential_backoff=exponential_backoff,
        skip_frames=skip_frames,
    )
send an email with stack trace if assertion is not True
dataset/ETHPy150Open dimagi/commcare-hq/corehq/util/soft_assert/api.py/soft_assert