vintasend 0.1.0__tar.gz

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.
Files changed (39) hide show
  1. vintasend-0.1.0/LICENSE.txt +21 -0
  2. vintasend-0.1.0/PKG-INFO +198 -0
  3. vintasend-0.1.0/README.md +179 -0
  4. vintasend-0.1.0/pyproject.toml +162 -0
  5. vintasend-0.1.0/vintasend/__init__.py +0 -0
  6. vintasend-0.1.0/vintasend/app_settings.py +160 -0
  7. vintasend-0.1.0/vintasend/constants.py +16 -0
  8. vintasend-0.1.0/vintasend/exceptions.py +54 -0
  9. vintasend-0.1.0/vintasend/py.typed +0 -0
  10. vintasend-0.1.0/vintasend/services/__init__.py +1 -0
  11. vintasend-0.1.0/vintasend/services/dataclasses.py +83 -0
  12. vintasend-0.1.0/vintasend/services/helpers.py +237 -0
  13. vintasend-0.1.0/vintasend/services/notification_adapters/__init__.py +0 -0
  14. vintasend-0.1.0/vintasend/services/notification_adapters/async_base.py +87 -0
  15. vintasend-0.1.0/vintasend/services/notification_adapters/asyncio_base.py +116 -0
  16. vintasend-0.1.0/vintasend/services/notification_adapters/base.py +113 -0
  17. vintasend-0.1.0/vintasend/services/notification_adapters/stubs/__init__.py +0 -0
  18. vintasend-0.1.0/vintasend/services/notification_adapters/stubs/fake_adapter.py +109 -0
  19. vintasend-0.1.0/vintasend/services/notification_adapters/stubs/fake_in_app_adapter.py +28 -0
  20. vintasend-0.1.0/vintasend/services/notification_backends/__init__.py +0 -0
  21. vintasend-0.1.0/vintasend/services/notification_backends/asyncio_base.py +139 -0
  22. vintasend-0.1.0/vintasend/services/notification_backends/base.py +132 -0
  23. vintasend-0.1.0/vintasend/services/notification_backends/stubs/__init__.py +0 -0
  24. vintasend-0.1.0/vintasend/services/notification_backends/stubs/fake_backend.py +533 -0
  25. vintasend-0.1.0/vintasend/services/notification_service.py +953 -0
  26. vintasend-0.1.0/vintasend/services/notification_template_renderers/__init__.py +0 -0
  27. vintasend-0.1.0/vintasend/services/notification_template_renderers/base.py +44 -0
  28. vintasend-0.1.0/vintasend/services/notification_template_renderers/base_templated_email_renderer.py +27 -0
  29. vintasend-0.1.0/vintasend/services/notification_template_renderers/stubs/__init__.py +0 -0
  30. vintasend-0.1.0/vintasend/services/notification_template_renderers/stubs/fake_templated_email_renderer.py +26 -0
  31. vintasend-0.1.0/vintasend/services/utils.py +5 -0
  32. vintasend-0.1.0/vintasend/tasks/__init__.py +2 -0
  33. vintasend-0.1.0/vintasend/tasks/background_tasks.py +59 -0
  34. vintasend-0.1.0/vintasend/tasks/periodic_tasks.py +26 -0
  35. vintasend-0.1.0/vintasend/tests/__init__.py +0 -0
  36. vintasend-0.1.0/vintasend/tests/test_services/__init__.py +0 -0
  37. vintasend-0.1.0/vintasend/tests/test_services/test_notification_service.py +2218 -0
  38. vintasend-0.1.0/vintasend/utils/__init__.py +0 -0
  39. vintasend-0.1.0/vintasend/utils/singleton_utils.py +20 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Vinta Serviços e Soluções Tecnológicas Ltda
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,198 @@
1
+ Metadata-Version: 2.3
2
+ Name: vintasend
3
+ Version: 0.1.0
4
+ Summary: A flexible package for implementing transactional notifications
5
+ License: MIT
6
+ Author: Hugo bessa
7
+ Author-email: hugo@vinta.com.br
8
+ Requires-Python: >=3.9,<3.13
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Dist: pytest-asyncio (>=0.24.0,<0.25.0)
16
+ Requires-Dist: typing-extensions (>=4.12.2,<5.0.0)
17
+ Description-Content-Type: text/markdown
18
+
19
+ # VintaSend
20
+
21
+ A flexible package for implementing transactional notifications in Python projects.
22
+
23
+ ## Features
24
+ * **Storing notifications in a Database**: This package relies on a data store to record all the notifications that will be sent. It also keeps it's state column up to date.
25
+ * **Scheduling notifications**: Storing notifications to be send in the future. The notification's context for rendering the template is only evaluated at the moment the notification is sent due to the lib's context generation registry.
26
+ * **Notification context fetched at send time**: On scheduled notifications, we only get the notification context at the send time, so we always get the most up-to-date information.
27
+ * **AsyncIO Support**: We have two different versions of our service, one that only supports sync backends/adapters, and the other that only supports AsyncIO backends/adapters.
28
+ * **Flexible backend**: Your projects database is getting slow after you created the first milion notifications? You can migrate to a faster no-sql database with a blink of an eye without affecting how you send the notifications.
29
+ * **Flexible adapters**: Your project probably will need to change how it sends notifications overtime. This package allows to change the adapter without having to change how notifications templates are rendered or how the notification themselves are stored.
30
+ * **Flexible template renderers**: Wanna start managing your templates with a third party tool (so non-technical people can help maintaining them)? Or even choose a more powerful rendering engine? You can do it independetly of how you send the notifications or store them in the database.
31
+
32
+
33
+ ## Installation
34
+
35
+ To install `vintasend` you just need to run
36
+
37
+ ```shell
38
+ pip install vintasend
39
+ ```
40
+
41
+ **Disclaimer**: Although the VintaSend package is selfsufficient and can be used alone, you'd have to implement at lease one Backend, one Adapter, and one Template Renderer. We have a bunch of additional packages that implement these and need to be installed seprately depending on your needs. Please check [Officially supported packages](#officially-supported-packages) section.
42
+
43
+
44
+ ## Getting Started
45
+
46
+ To start using VintaSend you just need to import the notification service and start using it to manage your notifications.
47
+
48
+ ```python
49
+ from vintasend.services.notification_service import NotificationService, register_context
50
+ from vintasend.constants import NotificationTypes
51
+
52
+
53
+ notification_backend = MyNotificationBackend()
54
+ notifications_service = NotificationService(
55
+ notification_adapters=[MyAdapter(MyTemplateRenderer(), notification_backend)],
56
+ notification_backend=notification_backend,
57
+ )
58
+
59
+
60
+ @register_context("my_context_generator")
61
+ def my_context_generator(user_id: str):
62
+ user = get_user_by_id(user_id)
63
+
64
+ return {
65
+ "first_name": user.first_name,
66
+ "last_name": user.last_name,
67
+ "joined_at": user.joined_at,
68
+ }
69
+
70
+
71
+ notifications_service.create_notification(
72
+ user_id=user.id,
73
+ notification_type=NotificationTypes.EMAIL,
74
+ title="My Notification", # this is just for auditing purposes
75
+ body_template="my/notification/template/path.html",
76
+ context_name="my_context_generator",
77
+ context_kwargs={
78
+ "user_id": user.id,
79
+ },
80
+ send_after=datetime.datetime.now(),
81
+ subject_template="my/notification/subject/template/path.txt",
82
+ preheader_template="my/notification/preheader/template/path.html",
83
+ )
84
+ ```
85
+
86
+ ### Scheduled notifications
87
+
88
+ VintaSend schedules notifications by creating them on the database for sending when the `send_after` value has passed. The sending isn't done automatically but we have a service method called `send_pending_notifications` to send all pending notifications found in the database.
89
+
90
+ You need to call the `send_pending_notifications` service method in a cron job or a tool like Celery Beat.
91
+
92
+
93
+ ## Glossary
94
+
95
+ * **Notification Backend**: It is a class that implements the methods necessary for VintaSend services to create, update, and retrieve Notifications from da database.
96
+ * **Notification Adapter**: It is a class that implements the methods necessary for VintaSend services to send Notifications through email, SMS or even push/in-app notifications.
97
+ * **Template Renderer**: It is a class that implements the methods necessary for VintaSend adapter to render the notification body.
98
+ * **Notification Context**: It's the data passed to the templates to render the notification correctly. It's generated when the notification is sent, not on creation time
99
+ * **Context generator**: It's a function registered with a name that, when called, generates the data necessary to render a notification.
100
+ * **Context name**: The registered name of a context generator. It's stored in the notification so the context generator is called at the moment the notification will be sent.
101
+ * **Context registry**: We store all registered context generators on a Singleton class, we call it context registry.
102
+
103
+
104
+ ## Community
105
+
106
+ VintaSend has many backend, adapter, and template renderer implementations. If you can't find something that fulfills your needs, the package has very clear interfaces you can implement and achieve the exact behavior you expect without loosing VintaSend's friendly API.
107
+
108
+ ### Officially supported packages
109
+
110
+ #### Backends
111
+
112
+ * **[vintasend-django](https://github.com/vintasoftware/vintasend-django/)**: Uses Django ORM to manage the notifications in the database.
113
+ * **[vintasend-sqlalchemy](https://github.com/vintasoftware/vintasend-sqlalchemy/)**: Uses SQLAlchemy to manage the notifications in the database. It supports both sync and async engines/sessions.
114
+
115
+ #### Adapters
116
+
117
+ * **[vintasend-fastapi-mail](https://github.com/vintasoftware/vintasend-fastapi-mail/)**: AsyncIO implementation that sends emails using FastAPI-Mail
118
+ * **[vintasend-flask-mail](https://github.com/vintasoftware/vintasend-flask-mail/)**: Sync implementation that sends emails using Flask-Mail.
119
+ * **[vintasend-celery](https://github.com/vintasoftware/vintasend-celery/)**: Adapter factory that allows sending emails asynchronously on sync backends by using Celery.
120
+ * **[vintasend-django](https://github.com/vintasoftware/vintasend-django/)**: Sync implementation that sends emails using Django's builtin email sender.
121
+
122
+ #### Template Renderers
123
+ * **[vintasend-django](https://github.com/vintasoftware/vintasend-django/)**: Renders emails using Django's templating system.
124
+ * **[vintasend-jinja](https://github.com/vintasoftware/vintasend-jinja/)**: Renders emails using Jinja2.
125
+
126
+
127
+ ## Advacted Usage
128
+
129
+ ### AsyncIO Notification Service
130
+
131
+ To use the AsyncIO Notification Service your backend and adapters must all support AsyncIO as well.
132
+
133
+ ```python
134
+ from vintasend.services.notification_service import AsyncIONotificationService, register_context
135
+ from vintasend.constants import NotificationTypes
136
+
137
+
138
+ notification_backend = MyAsyncIONotificationBackend()
139
+ notifications_service = AsyncIONotificationService(
140
+ notification_adapters=[MyAsyncIOAdapter(MyTemplateRenderer(), notification_backend)],
141
+ notification_backend=notification_backend,
142
+ )
143
+
144
+
145
+ @register_context("my_context_generator")
146
+ async def my_context_generator(user_id: str):
147
+ user = await get_user_by_id(user_id)
148
+
149
+ return {
150
+ "first_name": user.first_name,
151
+ "last_name": user.last_name,
152
+ "joined_at": user.joined_at,
153
+ }
154
+
155
+
156
+ await notifications_service.create_notification(
157
+ user_id=user.id,
158
+ notification_type=NotificationTypes.EMAIL,
159
+ title="My Notification", # this is just for auditing purposes
160
+ body_template="my/notification/template/path.html",
161
+ context_name="my_context_generator",
162
+ context_kwargs={
163
+ "user_id": user.id,
164
+ },
165
+ send_after=datetime.datetime.now(),
166
+ subject_template="my/notification/subject/template/path.txt",
167
+ preheader_template="my/notification/preheader/template/path.html",
168
+ )
169
+ ```
170
+
171
+ ### Using frameworks that don't use a globally-available configuration
172
+
173
+ Frameworks like FastAPI don't have a centralized configuration object that's globally accessible by default. Because of that, we need to manually pass the configuration object to the service in order to initialize VintaSend configuration.
174
+
175
+
176
+ ```python
177
+ from vintasend.services.notification_service import AsyncIONotificationService, register_context
178
+ from vintasend.constants import NotificationTypes
179
+ from fastapi import FastAPI
180
+ from pydantic_settings import BaseSettings
181
+
182
+
183
+ class Settings(BaseSettings):
184
+ app_name: str = "Awesome API"
185
+ admin_email: str
186
+ items_per_user: int = 50
187
+
188
+ settings = Settings()
189
+ app = FastAPI()
190
+
191
+ notification_backend = MyAsyncIONotificationBackend()
192
+ notifications_service = AsyncIONotificationService(
193
+ notification_adapters=[MyAsyncIOAdapter(MyTemplateRenderer(), notification_backend)],
194
+ notification_backend=notification_backend,
195
+ config=settings,
196
+ )
197
+ ```
198
+
@@ -0,0 +1,179 @@
1
+ # VintaSend
2
+
3
+ A flexible package for implementing transactional notifications in Python projects.
4
+
5
+ ## Features
6
+ * **Storing notifications in a Database**: This package relies on a data store to record all the notifications that will be sent. It also keeps it's state column up to date.
7
+ * **Scheduling notifications**: Storing notifications to be send in the future. The notification's context for rendering the template is only evaluated at the moment the notification is sent due to the lib's context generation registry.
8
+ * **Notification context fetched at send time**: On scheduled notifications, we only get the notification context at the send time, so we always get the most up-to-date information.
9
+ * **AsyncIO Support**: We have two different versions of our service, one that only supports sync backends/adapters, and the other that only supports AsyncIO backends/adapters.
10
+ * **Flexible backend**: Your projects database is getting slow after you created the first milion notifications? You can migrate to a faster no-sql database with a blink of an eye without affecting how you send the notifications.
11
+ * **Flexible adapters**: Your project probably will need to change how it sends notifications overtime. This package allows to change the adapter without having to change how notifications templates are rendered or how the notification themselves are stored.
12
+ * **Flexible template renderers**: Wanna start managing your templates with a third party tool (so non-technical people can help maintaining them)? Or even choose a more powerful rendering engine? You can do it independetly of how you send the notifications or store them in the database.
13
+
14
+
15
+ ## Installation
16
+
17
+ To install `vintasend` you just need to run
18
+
19
+ ```shell
20
+ pip install vintasend
21
+ ```
22
+
23
+ **Disclaimer**: Although the VintaSend package is selfsufficient and can be used alone, you'd have to implement at lease one Backend, one Adapter, and one Template Renderer. We have a bunch of additional packages that implement these and need to be installed seprately depending on your needs. Please check [Officially supported packages](#officially-supported-packages) section.
24
+
25
+
26
+ ## Getting Started
27
+
28
+ To start using VintaSend you just need to import the notification service and start using it to manage your notifications.
29
+
30
+ ```python
31
+ from vintasend.services.notification_service import NotificationService, register_context
32
+ from vintasend.constants import NotificationTypes
33
+
34
+
35
+ notification_backend = MyNotificationBackend()
36
+ notifications_service = NotificationService(
37
+ notification_adapters=[MyAdapter(MyTemplateRenderer(), notification_backend)],
38
+ notification_backend=notification_backend,
39
+ )
40
+
41
+
42
+ @register_context("my_context_generator")
43
+ def my_context_generator(user_id: str):
44
+ user = get_user_by_id(user_id)
45
+
46
+ return {
47
+ "first_name": user.first_name,
48
+ "last_name": user.last_name,
49
+ "joined_at": user.joined_at,
50
+ }
51
+
52
+
53
+ notifications_service.create_notification(
54
+ user_id=user.id,
55
+ notification_type=NotificationTypes.EMAIL,
56
+ title="My Notification", # this is just for auditing purposes
57
+ body_template="my/notification/template/path.html",
58
+ context_name="my_context_generator",
59
+ context_kwargs={
60
+ "user_id": user.id,
61
+ },
62
+ send_after=datetime.datetime.now(),
63
+ subject_template="my/notification/subject/template/path.txt",
64
+ preheader_template="my/notification/preheader/template/path.html",
65
+ )
66
+ ```
67
+
68
+ ### Scheduled notifications
69
+
70
+ VintaSend schedules notifications by creating them on the database for sending when the `send_after` value has passed. The sending isn't done automatically but we have a service method called `send_pending_notifications` to send all pending notifications found in the database.
71
+
72
+ You need to call the `send_pending_notifications` service method in a cron job or a tool like Celery Beat.
73
+
74
+
75
+ ## Glossary
76
+
77
+ * **Notification Backend**: It is a class that implements the methods necessary for VintaSend services to create, update, and retrieve Notifications from da database.
78
+ * **Notification Adapter**: It is a class that implements the methods necessary for VintaSend services to send Notifications through email, SMS or even push/in-app notifications.
79
+ * **Template Renderer**: It is a class that implements the methods necessary for VintaSend adapter to render the notification body.
80
+ * **Notification Context**: It's the data passed to the templates to render the notification correctly. It's generated when the notification is sent, not on creation time
81
+ * **Context generator**: It's a function registered with a name that, when called, generates the data necessary to render a notification.
82
+ * **Context name**: The registered name of a context generator. It's stored in the notification so the context generator is called at the moment the notification will be sent.
83
+ * **Context registry**: We store all registered context generators on a Singleton class, we call it context registry.
84
+
85
+
86
+ ## Community
87
+
88
+ VintaSend has many backend, adapter, and template renderer implementations. If you can't find something that fulfills your needs, the package has very clear interfaces you can implement and achieve the exact behavior you expect without loosing VintaSend's friendly API.
89
+
90
+ ### Officially supported packages
91
+
92
+ #### Backends
93
+
94
+ * **[vintasend-django](https://github.com/vintasoftware/vintasend-django/)**: Uses Django ORM to manage the notifications in the database.
95
+ * **[vintasend-sqlalchemy](https://github.com/vintasoftware/vintasend-sqlalchemy/)**: Uses SQLAlchemy to manage the notifications in the database. It supports both sync and async engines/sessions.
96
+
97
+ #### Adapters
98
+
99
+ * **[vintasend-fastapi-mail](https://github.com/vintasoftware/vintasend-fastapi-mail/)**: AsyncIO implementation that sends emails using FastAPI-Mail
100
+ * **[vintasend-flask-mail](https://github.com/vintasoftware/vintasend-flask-mail/)**: Sync implementation that sends emails using Flask-Mail.
101
+ * **[vintasend-celery](https://github.com/vintasoftware/vintasend-celery/)**: Adapter factory that allows sending emails asynchronously on sync backends by using Celery.
102
+ * **[vintasend-django](https://github.com/vintasoftware/vintasend-django/)**: Sync implementation that sends emails using Django's builtin email sender.
103
+
104
+ #### Template Renderers
105
+ * **[vintasend-django](https://github.com/vintasoftware/vintasend-django/)**: Renders emails using Django's templating system.
106
+ * **[vintasend-jinja](https://github.com/vintasoftware/vintasend-jinja/)**: Renders emails using Jinja2.
107
+
108
+
109
+ ## Advacted Usage
110
+
111
+ ### AsyncIO Notification Service
112
+
113
+ To use the AsyncIO Notification Service your backend and adapters must all support AsyncIO as well.
114
+
115
+ ```python
116
+ from vintasend.services.notification_service import AsyncIONotificationService, register_context
117
+ from vintasend.constants import NotificationTypes
118
+
119
+
120
+ notification_backend = MyAsyncIONotificationBackend()
121
+ notifications_service = AsyncIONotificationService(
122
+ notification_adapters=[MyAsyncIOAdapter(MyTemplateRenderer(), notification_backend)],
123
+ notification_backend=notification_backend,
124
+ )
125
+
126
+
127
+ @register_context("my_context_generator")
128
+ async def my_context_generator(user_id: str):
129
+ user = await get_user_by_id(user_id)
130
+
131
+ return {
132
+ "first_name": user.first_name,
133
+ "last_name": user.last_name,
134
+ "joined_at": user.joined_at,
135
+ }
136
+
137
+
138
+ await notifications_service.create_notification(
139
+ user_id=user.id,
140
+ notification_type=NotificationTypes.EMAIL,
141
+ title="My Notification", # this is just for auditing purposes
142
+ body_template="my/notification/template/path.html",
143
+ context_name="my_context_generator",
144
+ context_kwargs={
145
+ "user_id": user.id,
146
+ },
147
+ send_after=datetime.datetime.now(),
148
+ subject_template="my/notification/subject/template/path.txt",
149
+ preheader_template="my/notification/preheader/template/path.html",
150
+ )
151
+ ```
152
+
153
+ ### Using frameworks that don't use a globally-available configuration
154
+
155
+ Frameworks like FastAPI don't have a centralized configuration object that's globally accessible by default. Because of that, we need to manually pass the configuration object to the service in order to initialize VintaSend configuration.
156
+
157
+
158
+ ```python
159
+ from vintasend.services.notification_service import AsyncIONotificationService, register_context
160
+ from vintasend.constants import NotificationTypes
161
+ from fastapi import FastAPI
162
+ from pydantic_settings import BaseSettings
163
+
164
+
165
+ class Settings(BaseSettings):
166
+ app_name: str = "Awesome API"
167
+ admin_email: str
168
+ items_per_user: int = 50
169
+
170
+ settings = Settings()
171
+ app = FastAPI()
172
+
173
+ notification_backend = MyAsyncIONotificationBackend()
174
+ notifications_service = AsyncIONotificationService(
175
+ notification_adapters=[MyAsyncIOAdapter(MyTemplateRenderer(), notification_backend)],
176
+ notification_backend=notification_backend,
177
+ config=settings,
178
+ )
179
+ ```
@@ -0,0 +1,162 @@
1
+ [tool.poetry]
2
+ name = "vintasend"
3
+ version = "0.1.0"
4
+ description = "A flexible package for implementing transactional notifications"
5
+ authors = ["Hugo bessa <hugo@vinta.com.br>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+
9
+ [tool.poetry.dependencies]
10
+ python = ">=3.9,<3.13"
11
+ typing-extensions = "^4.12.2"
12
+ pytest-asyncio = "^0.24.0"
13
+
14
+
15
+ [tool.poetry.group.dev.dependencies]
16
+ freezegun = "^1.5.1"
17
+ coverage = "^7.6.4"
18
+ tox = "^4.23.2"
19
+ pytest = "^8.3.3"
20
+ pytest-xdist = {version = "^3.6.1", extras=["psutil"]}
21
+ coveralls = "^4.0.1"
22
+ pytest-cov = "^6.0.0"
23
+ gevent = "^24.11.1"
24
+
25
+ [build-system]
26
+ requires = ["poetry-core"]
27
+ build-backend = "poetry.core.masonry.api"
28
+
29
+ [tool.ruff]
30
+ select = [
31
+ # pycodestyle
32
+ "E",
33
+ # Pyflakes
34
+ "F",
35
+ # pep8-naming
36
+ "N",
37
+ # pyupgrade
38
+ "UP",
39
+ # flake8-bugbear
40
+ "B",
41
+ # flake8-bandit
42
+ "S",
43
+ # flake8-blind-except
44
+ "BLE",
45
+ # flake8-builtins
46
+ "A",
47
+ # flake8-django
48
+ "DJ",
49
+ # isort
50
+ "I",
51
+ # flake8-logging-format
52
+ "G",
53
+ # flake8-no-pep420
54
+ "INP",
55
+ # Ruff-specific rules
56
+ "RUF",
57
+ ]
58
+ exclude = [
59
+ ".bzr",
60
+ ".direnv",
61
+ ".eggs",
62
+ ".git",
63
+ ".git-rewrite",
64
+ ".hg",
65
+ ".mypy_cache",
66
+ ".nox",
67
+ ".pants.d",
68
+ ".pytype",
69
+ ".ruff_cache",
70
+ ".svn",
71
+ ".tox",
72
+ ".venv",
73
+ "__pypackages__",
74
+ "_build",
75
+ "buck-out",
76
+ "build",
77
+ "dist",
78
+ "node_modules",
79
+ "venv",
80
+ "virtualenvs",
81
+ "*/migrations/*",
82
+ ]
83
+ ignore = [
84
+ # Disable eradicate (commented code removal)
85
+ "ERA001",
86
+ # Disable Conflicting lint rules,
87
+ # see https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
88
+ "W191",
89
+ "E501",
90
+ "E111",
91
+ "E117",
92
+ "D206",
93
+ "D300",
94
+ "Q000",
95
+ "Q001",
96
+ "Q002",
97
+ "Q003",
98
+ "COM812",
99
+ "COM819",
100
+ "ISC001",
101
+ "ISC002",
102
+ # Allow `except Exception`:
103
+ "BLE001",
104
+ # Disable unused `noqa` directive
105
+ "RUF100",
106
+ # Disable pyupgrade UP rules that conflict with django-ninja
107
+ "UP006",
108
+ "UP035",
109
+ "UP037",
110
+ "UP040",
111
+ ]
112
+ line-length = 100
113
+ indent-width = 4
114
+ target-version = "py312"
115
+ # Allow unused variables when underscore-prefixed:
116
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
117
+
118
+ [tool.ruff.pycodestyle]
119
+ ignore-overlong-task-comments = true
120
+
121
+ [tool.ruff.lint.isort]
122
+ section-order = [
123
+ "future",
124
+ "standard-library",
125
+ "django",
126
+ "third-party",
127
+ "first-party",
128
+ "local-folder",
129
+ ]
130
+ lines-after-imports = 2
131
+
132
+ [tool.ruff.lint.isort.sections]
133
+ # Group all Django imports into a separate section.
134
+ "django" = ["django"]
135
+
136
+ [tool.ruff.per-file-ignores]
137
+ # Ignore "E402", "F403", "F405" (import violations) in __init__.py files.
138
+ # Ignore "S" (flake8-bandit) and "N802" (function name should be lowercase) in tests and docs.
139
+ # Ignore "RUF" (Ruff-specific rules) and "I" (isort) in migrations.
140
+ "__init__.py" = ["E402", "F403", "F405"]
141
+ "**/{tests,docs}/*" = ["E402", "F403", "F405", "S", "N802"]
142
+ "**/*test*.py" = ["E402", "F403", "F405", "S", "N802"]
143
+ "**/{settings}/*" = ["E402", "F403", "F405"]
144
+ "**/migrations/*" = ["RUF", "I"]
145
+
146
+ [tool.coverage.run]
147
+ branch = true
148
+ source = ["backend"]
149
+ concurrency = ["thread", "gevent", "multiprocessing"]
150
+ omit = [
151
+ "**/venv/*",
152
+ "**/env/*",
153
+ "**/virtualenvs/*",
154
+ "**/node_modules/*",
155
+ "**/migrations/*",
156
+ "**/settings/*",
157
+ "**/tests/*",
158
+ ]
159
+
160
+ [tool.pytest.ini_options]
161
+ python_files = ["test_*.py"]
162
+ addopts = "--dist=loadscope"
File without changes