• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

inventree / InvenTree / 8604849533

08 Apr 2024 06:20PM CUT coverage: 78.857%. First build
8604849533

Pull #6981

github

web-flow
Merge 3d6fa4389 into 4adce85ef
Pull Request #6981: Bump djangorestframework from 3.14.0 to 3.15.1 in /src/backend

19152 of 24287 relevant lines covered (78.86%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

2.17
/src/backend/InvenTree/InvenTree/exceptions.py
1
"""Custom exception handling for the DRF API."""
2

3
# -*- coding: utf-8 -*-
4
from __future__ import unicode_literals
5

6
import logging
7
import sys
8
import traceback
9

10
from django.conf import settings
11
from django.core.exceptions import ValidationError as DjangoValidationError
12
from django.db.utils import IntegrityError, OperationalError
13
from django.utils.translation import gettext_lazy as _
14

15
import rest_framework.views as drfviews
16
from error_report.models import Error
17
from rest_framework import serializers
18
from rest_framework.exceptions import ValidationError as DRFValidationError
19
from rest_framework.response import Response
20

21
import InvenTree.sentry
22

23
logger = logging.getLogger('inventree')
24

25

26
def log_error(path, error_name=None, error_info=None, error_data=None):
27
    """Log an error to the database.
28

29
    - Uses python exception handling to extract error details
30

31
    Arguments:
32
        path: The 'path' (most likely a URL) associated with this error (optional)
33

34
    kwargs:
35
        error_name: The name of the error (optional, overrides 'kind')
36
        error_info: The error information (optional, overrides 'info')
37
        error_data: The error data (optional, overrides 'data')
38
    """
39
    kind, info, data = sys.exc_info()
×
40

41
    # Check if the error is on the ignore list
42
    if kind in settings.IGNORED_ERRORS:
×
43
        return
×
44

45
    if error_name:
×
46
        kind = error_name
×
47
    else:
×
48
        kind = getattr(kind, '__name__', 'Unknown Error')
×
49

50
    if error_info:
×
51
        info = error_info
×
52

53
    if error_data:
×
54
        data = error_data
×
55
    else:
×
56
        try:
×
57
            data = '\n'.join(traceback.format_exception(kind, info, data))
×
58
        except AttributeError:
×
59
            data = 'No traceback information available'
×
60

61
    # Log error to stderr
62
    logger.error(info)
×
63

64
    # Ensure the error information does not exceed field size limits
65
    path = path[:200]
×
66
    kind = kind[:128]
×
67

68
    try:
×
69
        Error.objects.create(kind=kind, info=info or '', data=data or '', path=path)
×
70
    except Exception:
×
71
        # Not much we can do if logging the error throws a db exception
72
        logger.exception('Failed to log exception to database')
×
73

74

75
def exception_handler(exc, context):
1✔
76
    """Custom exception handler for DRF framework.
77

78
    Ref: https://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling
79
    Catches any errors not natively handled by DRF, and re-throws as an error DRF can handle.
80

81
    If sentry error reporting is enabled, we will also provide the original exception to sentry.io
82
    """
83
    response = None
×
84

85
    # Pass exception to sentry.io handler
86
    try:
×
87
        InvenTree.sentry.report_exception(exc)
×
88
    except Exception:
×
89
        # If sentry.io fails, we don't want to crash the server!
90
        pass
×
91

92
    # Catch any django validation error, and re-throw a DRF validation error
93
    if isinstance(exc, DjangoValidationError):
×
94
        exc = DRFValidationError(detail=serializers.as_serializer_error(exc))
×
95

96
    # Default to the built-in DRF exception handler
97
    response = drfviews.exception_handler(exc, context)
×
98

99
    if response is None:
×
100
        # DRF handler did not provide a default response for this exception
101

102
        if settings.TESTING:
×
103
            # If in TESTING mode, re-throw the exception for traceback
104
            raise exc
×
105
        elif settings.DEBUG:
×
106
            # If in DEBUG mode, provide error information in the response
107
            error_detail = str(exc)
×
108
        else:
×
109
            error_detail = _('Error details can be found in the admin panel')
×
110

111
        response_data = {
112
            'error': type(exc).__name__,
113
            'error_class': str(type(exc)),
114
            'detail': error_detail,
115
            'path': context['request'].path,
116
            'status_code': 500,
117
        }
118

119
        response = Response(response_data, status=500)
×
120

121
        log_error(context['request'].path)
×
122

123
    if response is not None:
×
124
        # Convert errors returned under the label '__all__' to 'non_field_errors'
125
        if '__all__' in response.data:
×
126
            response.data['non_field_errors'] = response.data['__all__']
×
127
            del response.data['__all__']
×
128

129
    return response
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc