django-explain-errors 0.1__py3-none-any.whl
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.
- django_explain_errors-0.1.dist-info/LICENSE +21 -0
- django_explain_errors-0.1.dist-info/METADATA +106 -0
- django_explain_errors-0.1.dist-info/RECORD +9 -0
- django_explain_errors-0.1.dist-info/WHEEL +5 -0
- django_explain_errors-0.1.dist-info/top_level.txt +2 -0
- explain_errors/__init__.py +0 -0
- explain_errors/middleware.py +63 -0
- tests/__init__.py +0 -0
- tests/test_middleware.py +27 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Mike ☕
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: django-explain-errors
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: Django middleware that captures errors and exceptions, sends them to OpenAI for a detailed explanation, and prints the explanation to stdout when debug mode is enabled
|
|
5
|
+
Home-page: https://github.com/topunix/django-explain-errors
|
|
6
|
+
Author: topunix
|
|
7
|
+
Author-email: topunixguy@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Environment :: Web Environment
|
|
10
|
+
Classifier: Framework :: Django
|
|
11
|
+
Classifier: Framework :: Django :: 2.0
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.5
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: Django >=2
|
|
22
|
+
|
|
23
|
+
# Django Explain Errors Middleware
|
|
24
|
+
|
|
25
|
+
This Django middleware captures errors and exceptions, sends them to OpenAI for explanation, and prints the explanation to stdout when debug mode is enabled. It uses an environment variable to securely manage the OpenAI API key.
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- Captures Django errors and exceptions
|
|
30
|
+
- Uses OpenAI to explain the error
|
|
31
|
+
- Securely manages the OpenAI API key using environment variables
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
1. Install django-explain-errors by running:
|
|
36
|
+
```bash
|
|
37
|
+
pip install django-explain-errors
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. **Add the middleware to your Django project**:
|
|
41
|
+
|
|
42
|
+
- Open your `settings.py` file and add the middleware to the `MIDDLEWARE` list. Ensure that the middleware is added last in the list:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
MIDDLEWARE = [
|
|
46
|
+
...
|
|
47
|
+
'explain_errors.ExplainErrorsMiddleware',
|
|
48
|
+
]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
4. **Set up environment variables**:
|
|
52
|
+
|
|
53
|
+
- Create a `.env` file in your project’s root directory and add your OpenAI API key. Alternatively, you can list the API key in `settings.py`:
|
|
54
|
+
|
|
55
|
+
```plaintext
|
|
56
|
+
OPENAI_API_KEY=your_openai_api_key_here
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
1. **Ensure DEBUG is set to True**:
|
|
62
|
+
|
|
63
|
+
Open your `settings.py` file and set:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
DEBUG = True
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
2. **Trigger an error in your Django application**:
|
|
70
|
+
|
|
71
|
+
The middleware will capture the error, send it to OpenAI for explanation, and print the explanation to stdout.
|
|
72
|
+
|
|
73
|
+
## Example
|
|
74
|
+
|
|
75
|
+
Here is an example of how to use the middleware in a Django project:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
# settings.py
|
|
79
|
+
|
|
80
|
+
DEBUG = True
|
|
81
|
+
|
|
82
|
+
MIDDLEWARE = [
|
|
83
|
+
...
|
|
84
|
+
'explain_errors.ExplainErrorsMiddleware',
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
# .env
|
|
88
|
+
|
|
89
|
+
OPENAI_API_KEY=your_openai_api_key_here
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
When an error occurs, you will see an explanation printed to stdout.
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
97
|
+
|
|
98
|
+
## Contributing
|
|
99
|
+
|
|
100
|
+
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
|
|
101
|
+
|
|
102
|
+
## Acknowledgements
|
|
103
|
+
|
|
104
|
+
- [Django](https://www.djangoproject.com/)
|
|
105
|
+
- [OpenAI](https://www.openai.com/)
|
|
106
|
+
- [python-dotenv](https://github.com/theskumar/python-dotenv)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
explain_errors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
explain_errors/middleware.py,sha256=DJYGw0OGgPTXJIOx-O2KlnSxUgisGmzV6GhF2UN7w24,2389
|
|
3
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
tests/test_middleware.py,sha256=rTul8ZtFgRkkepNFRXSU1X521GgNpk3TTXFMCi3ERHQ,908
|
|
5
|
+
django_explain_errors-0.1.dist-info/LICENSE,sha256=Kxbs99ohpmwKsq9TsJYyN53NwFuDQrgXtl9hfUtwGb8,1065
|
|
6
|
+
django_explain_errors-0.1.dist-info/METADATA,sha256=VFEZmEQdXoIcjAC5hes6WxlTmIp2Vv4arB-RM8seTY8,2994
|
|
7
|
+
django_explain_errors-0.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
8
|
+
django_explain_errors-0.1.dist-info/top_level.txt,sha256=bnMY4uDHGAV4sTjpJghE8sf1Ay5ezERJEaXX6Oz7DFI,21
|
|
9
|
+
django_explain_errors-0.1.dist-info/RECORD,,
|
|
File without changes
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from openai import OpenAI
|
|
2
|
+
import os
|
|
3
|
+
import traceback
|
|
4
|
+
from dotenv import load_dotenv
|
|
5
|
+
from django.conf import settings
|
|
6
|
+
from django.http import JsonResponse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ExplainErrorsMiddleware:
|
|
10
|
+
def __init__(self, get_response):
|
|
11
|
+
self.get_response = get_response
|
|
12
|
+
if settings.DEBUG:
|
|
13
|
+
# Load environment variables from .env file
|
|
14
|
+
load_dotenv()
|
|
15
|
+
# Get the OpenAI API key from environment variable
|
|
16
|
+
openai_api_key = os.getenv("OPENAI_API_KEY", getattr(settings, 'OPENAI_API_KEY', None))
|
|
17
|
+
if not openai_api_key:
|
|
18
|
+
raise ValueError("OpenAI API key not found. Please set the OPENAI_API_KEY environment variable.")
|
|
19
|
+
|
|
20
|
+
self.openai_client = OpenAI(
|
|
21
|
+
api_key=openai_api_key,
|
|
22
|
+
)
|
|
23
|
+
self.api_called = False # Flag to track API call
|
|
24
|
+
|
|
25
|
+
def __call__(self, request):
|
|
26
|
+
try:
|
|
27
|
+
response = self.get_response(request)
|
|
28
|
+
except Exception as e:
|
|
29
|
+
self.process_exception(request, e)
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
def process_exception(self, request, exception):
|
|
33
|
+
|
|
34
|
+
if settings.DEBUG and not self.api_called:
|
|
35
|
+
# Get the exception traceback
|
|
36
|
+
tb = traceback.format_exc()
|
|
37
|
+
|
|
38
|
+
# Construct the prompt
|
|
39
|
+
prompt = f"Explain the following Django error in simple terms:\n\n{tb}"
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
# Call OpenAI API
|
|
43
|
+
response = self.openai_client.chat.completions.create(
|
|
44
|
+
model="gpt-3.5-turbo",
|
|
45
|
+
messages=[
|
|
46
|
+
{"role": "system", "content": "You are a helpful assistant."},
|
|
47
|
+
{"role": "user", "content": prompt}
|
|
48
|
+
],
|
|
49
|
+
max_tokens=150
|
|
50
|
+
)
|
|
51
|
+
explanation = response.choices[0].message.content
|
|
52
|
+
|
|
53
|
+
# Print the explanation to stdout
|
|
54
|
+
print("Error Explanation by OpenAI:\n", explanation)
|
|
55
|
+
self.api_called = True # Set flag after the call`
|
|
56
|
+
|
|
57
|
+
except Exception as e:
|
|
58
|
+
# In case of any issues with the OpenAI API call, print an error message
|
|
59
|
+
print("Failed to get an explanation from OpenAI:", e)
|
|
60
|
+
|
|
61
|
+
# Optionally, you can return a custom error response
|
|
62
|
+
return JsonResponse({"error": "An error occurred.", "message": explanation}, status=500)
|
|
63
|
+
return None
|
tests/__init__.py
ADDED
|
File without changes
|
tests/test_middleware.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from django.http import JsonResponse
|
|
3
|
+
from django.test import SimpleTestCase, RequestFactory
|
|
4
|
+
from explain_errors.middleware import ExplainErrorsMiddleware
|
|
5
|
+
|
|
6
|
+
class ExplainErrorsMiddlewareTest(SimpleTestCase):
|
|
7
|
+
|
|
8
|
+
def test_process_exception_with_error(self):
|
|
9
|
+
# Simulate an exception
|
|
10
|
+
exception = Exception("Test Exception")
|
|
11
|
+
|
|
12
|
+
# Create a mock request object using RequestFactory
|
|
13
|
+
factory = RequestFactory()
|
|
14
|
+
request = factory.get('/')
|
|
15
|
+
|
|
16
|
+
# Create the middleware (no need for settings)
|
|
17
|
+
middleware = ExplainErrorsMiddleware(lambda request: None)
|
|
18
|
+
|
|
19
|
+
# Call process_exception
|
|
20
|
+
response = middleware.process_exception(request, exception)
|
|
21
|
+
|
|
22
|
+
self.assertIsInstance(response, JsonResponse)
|
|
23
|
+
self.assertEqual(response.status_code, 500)
|
|
24
|
+
response_json = json.loads(response.content)
|
|
25
|
+
|
|
26
|
+
# Check if "error" key is in the response JSON
|
|
27
|
+
self.assertIn("error", response_json)
|