Coverage for app/venv/lib/python3.14/site-packages/weblate/api/spectacular.py: 82%
20 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
1# Copyright © Michal Čihař <michal@weblate.org>
2# SPDX-FileCopyrightText: 2025 Javier Pérez <jdbp@protonmail.com>
3#
4# SPDX-License-Identifier: GPL-3.0-or-later
6from __future__ import annotations
8import warnings
9from typing import Any
11from django.utils.functional import lazy
12from django.utils.translation import gettext_lazy
15def get_doc_url_wrapper(page: str, anchor: str = "") -> str:
16 """
17 Wrap get_doc_url to delay get_doc_url import.
19 It cannot be imported directly, because get_spectacular_settings is used
20 from settings and get_doc_url needs settings to determine if it should hide t
21 he version info.
22 """
23 from weblate.utils.docs import get_doc_url
25 return get_doc_url(page, anchor)
28def get_spectacular_settings(
29 installed_apps: list[str], site_url: str, site_title: str
30) -> dict[str, Any]:
31 settings = {
32 # Use redoc from sidecar
33 # TODO: Should bundle it internally
34 "REDOC_DIST": "SIDECAR",
35 "REDOC_UI_SETTINGS": {
36 "theme": {
37 "typography": {
38 "fontFamily": '"Source Sans 3", sans-serif',
39 "headings": {
40 "fontFamily": '"Source Sans 3", sans-serif',
41 },
42 "code": {
43 "fontFamily": '"Source Code Pro", monospace',
44 },
45 },
46 "logo": {
47 "maxWidth": "150px",
48 "maxHeight": "50vh",
49 "margin": "auto",
50 },
51 },
52 },
53 "SWAGGER_UI_DIST": "SIDECAR",
54 "DEFAULT_GENERATOR_CLASS": "weblate.api.generators.WeblateSchemaGenerator",
55 # OpenAPI Specification version: 'webhooks' field is supported from 3.1.0
56 "OAS_VERSION": "3.1.1",
57 "SERVERS": [
58 {"url": site_url.rstrip("/"), "description": site_title},
59 ],
60 "SERVE_URLCONF": "weblate.urls",
61 "TITLE": gettext_lazy("Weblate's REST API"),
62 "LICENSE": {
63 "name": "GNU General Public License v3 or later",
64 "url": lazy(get_doc_url_wrapper, str)("contributing/license"),
65 },
66 "DESCRIPTION": """
67The API is accessible on the ``/api/`` URL and it is based on [Django REST framework](https://www.django-rest-framework.org/).
69The OpenAPI specification is available as feature preview, feedback welcome!
71## Authorization
73<!-- Redoc-Inject: <security-definitions> -->
76 """,
77 "EXTENSIONS_INFO": {
78 "x-logo": {
79 "url": "/static/weblate.svg",
80 }
81 },
82 # Do not use API versioning
83 "VERSION": None,
84 # Flatten enum definitions
85 "ENUM_NAME_OVERRIDES": {
86 "ColorEnum": "weblate.utils.colors.ColorChoices.choices",
87 "ValidationErrorEnum": "drf_standardized_errors.openapi_serializers.ValidationErrorEnum.choices",
88 "ClientErrorEnum": "drf_standardized_errors.openapi_serializers.ClientErrorEnum.choices",
89 "ServerErrorEnum": "drf_standardized_errors.openapi_serializers.ServerErrorEnum.choices",
90 "ErrorCode401Enum": "drf_standardized_errors.openapi_serializers.ErrorCode401Enum.choices",
91 "ErrorCode403Enum": "drf_standardized_errors.openapi_serializers.ErrorCode403Enum.choices",
92 "ErrorCode404Enum": "drf_standardized_errors.openapi_serializers.ErrorCode404Enum.choices",
93 "ErrorCode405Enum": "drf_standardized_errors.openapi_serializers.ErrorCode405Enum.choices",
94 "ErrorCode406Enum": "drf_standardized_errors.openapi_serializers.ErrorCode406Enum.choices",
95 "ErrorCode415Enum": "drf_standardized_errors.openapi_serializers.ErrorCode415Enum.choices",
96 "ErrorCode429Enum": "drf_standardized_errors.openapi_serializers.ErrorCode429Enum.choices",
97 "ErrorCode500Enum": "drf_standardized_errors.openapi_serializers.ErrorCode500Enum.choices",
98 "ErrorCode423Enum": "weblate.api.serializers.ErrorCode423Enum.choices",
99 },
100 "POSTPROCESSING_HOOKS": [
101 "drf_standardized_errors.openapi_hooks.postprocess_schema_enums",
102 "weblate.api.docs.add_middleware_headers",
103 ],
104 "EXTERNAL_DOCS": {
105 "url": lazy(get_doc_url_wrapper, str)("index"),
106 "description": "Official Weblate documentation",
107 },
108 "TAGS": [
109 {
110 "name": "root",
111 "description": "The API root entry point.",
112 },
113 {
114 "name": "users",
115 "description": "Added in version 4.0.",
116 },
117 {
118 "name": "groups",
119 "description": "Added in version 4.0.",
120 },
121 {
122 "name": "roles",
123 },
124 {
125 "name": "languages",
126 },
127 {
128 "name": "projects",
129 },
130 {
131 "name": "components",
132 },
133 {
134 "name": "translations",
135 },
136 {
137 "name": "memory",
138 "description": "Added in version 4.14.",
139 },
140 {
141 "name": "units",
142 "description": "A unit is a single piece of a translation which pairs a source string with a corresponding translated string and also contains some related metadata. The term is derived from the Translate Toolkit and XLIFF.",
143 },
144 {
145 "name": "changes",
146 },
147 {
148 "name": "screenshots",
149 },
150 {
151 "name": "addons",
152 "description": "Added in version 4.4.1.",
153 },
154 {
155 "name": "component-lists",
156 "description": "Added in version 4.0.",
157 },
158 {
159 "name": "glossary",
160 "description": "**Changed in version 4.5:** Glossaries are now stored as regular components, translations and strings, please use respective API instead.",
161 },
162 {
163 "name": "tasks",
164 "description": "Added in version 4.4.\n\nListing of the tasks is currently not available.",
165 },
166 {
167 "name": "statistics",
168 "description": "Many endpoints support displaying statistics for their objects.",
169 },
170 {
171 "name": "metrics",
172 },
173 {
174 "name": "search",
175 "description": "Added in version 4.18.",
176 },
177 {
178 "name": "categories",
179 },
180 {
181 "name": "hooks",
182 "description": """Notification hooks allow external applications to notify Weblate that the VCS repository has been updated."""
183 """\n\nYou can use repository endpoints for projects, components and translations to update individual repositories.""",
184 },
185 {
186 "name": "exports",
187 "description": "Weblate provides various exports to allow you to further process the data.",
188 },
189 {
190 "name": "rssFeeds",
191 "description": "Changes in translations are exported in RSS feeds.",
192 },
193 {
194 "name": "webhooks",
195 "description": "Notifications sent by Weblate.",
196 },
197 ],
198 "WEBHOOKS": ["weblate.addons.webhooks.change_event_webhook"],
199 }
200 if "weblate.legal" in installed_apps: 200 ↛ 201line 200 didn't jump to line 201 because the condition on line 200 was never true
201 settings["TOS"] = "/legal/terms/"
203 return settings
206def get_drf_standardized_errors_settings() -> dict[str, Any]:
207 return {
208 "ALLOWED_ERROR_STATUS_CODES": [
209 "400",
210 "401",
211 "403",
212 "404",
213 "405",
214 "406",
215 "415",
216 "423", # Added by Weblate
217 "429",
218 "500",
219 ],
220 "ERROR_SCHEMAS": {
221 "423": "weblate.api.serializers.ErrorResponse423Serializer",
222 },
223 "EXCEPTION_HANDLER_CLASS": "weblate.api.views.WeblateExceptionHandler",
224 }
227# spellchecker:off
228def get_drf_standardized_errors_sertings() -> dict[str, Any]:
229 # TODO: Remove in Weblate 5.14
230 warnings.warn(
231 "The get_drf_standardized_errors_sertings was renamed to get_drf_standardized_errors_settings",
232 DeprecationWarning,
233 stacklevel=1,
234 )
235 return get_drf_standardized_errors_settings()
238# spellchecker:on
241def get_drf_settings(
242 *, require_login: bool, anon_throttle: str, user_throttle: str
243) -> dict[str, Any]:
244 return {
245 # Use Django's standard `django.contrib.auth` permissions,
246 # or allow read-only access for unauthenticated users.
247 "DEFAULT_PERMISSION_CLASSES": [
248 # Require authentication for login required sites
249 "rest_framework.permissions.IsAuthenticated"
250 if require_login
251 else "rest_framework.permissions.IsAuthenticatedOrReadOnly"
252 ],
253 "DEFAULT_AUTHENTICATION_CLASSES": (
254 "rest_framework.authentication.TokenAuthentication",
255 "weblate.api.authentication.BearerAuthentication",
256 "rest_framework.authentication.SessionAuthentication",
257 ),
258 "DEFAULT_THROTTLE_CLASSES": (
259 "weblate.api.throttling.UserRateThrottle",
260 "weblate.api.throttling.AnonRateThrottle",
261 ),
262 "DEFAULT_THROTTLE_RATES": {
263 "anon": anon_throttle,
264 "user": user_throttle,
265 },
266 "DEFAULT_RENDERER_CLASSES": [
267 "rest_framework.renderers.JSONRenderer",
268 "rest_framework.renderers.BrowsableAPIRenderer",
269 "weblate.api.renderers.AutoCSVRenderer",
270 ],
271 "DEFAULT_PAGINATION_CLASS": "weblate.api.pagination.StandardPagination",
272 "PAGE_SIZE": 50,
273 "VIEW_DESCRIPTION_FUNCTION": "weblate.api.views.get_view_description",
274 "EXCEPTION_HANDLER": "drf_standardized_errors.handler.exception_handler",
275 "UNAUTHENTICATED_USER": "weblate.auth.models.get_anonymous",
276 "DEFAULT_SCHEMA_CLASS": "weblate.api.generators.WeblateAutoSchema",
277 }