fastapi-errors-plus 0.6.2__py3-none-any.whl → 0.7.0__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.
- fastapi_errors_plus/__init__.py +1 -1
- fastapi_errors_plus/base.py +6 -0
- fastapi_errors_plus/errors.py +56 -8
- fastapi_errors_plus/protocol.py +7 -0
- {fastapi_errors_plus-0.6.2.dist-info → fastapi_errors_plus-0.7.0.dist-info}/METADATA +94 -33
- fastapi_errors_plus-0.7.0.dist-info/RECORD +10 -0
- {fastapi_errors_plus-0.6.2.dist-info → fastapi_errors_plus-0.7.0.dist-info}/WHEEL +1 -1
- fastapi_errors_plus-0.6.2.dist-info/RECORD +0 -10
- {fastapi_errors_plus-0.6.2.dist-info → fastapi_errors_plus-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {fastapi_errors_plus-0.6.2.dist-info → fastapi_errors_plus-0.7.0.dist-info}/top_level.txt +0 -0
fastapi_errors_plus/__init__.py
CHANGED
fastapi_errors_plus/base.py
CHANGED
|
@@ -37,6 +37,12 @@ class BaseErrorDTO:
|
|
|
37
37
|
message: str
|
|
38
38
|
"""Error message description."""
|
|
39
39
|
|
|
40
|
+
openapi_json_extras: Optional[Dict[str, Any]] = field(default=None)
|
|
41
|
+
"""Optional OpenAPI fragment under ``content['application/json']`` besides examples,
|
|
42
|
+
typically ``{\"schema\": ...}`` or ``encoding``. Do **not** put ``example`` / ``examples``
|
|
43
|
+
here — use :meth:`to_example`. Arbitrary implementations may instead implement
|
|
44
|
+
:meth:`to_openapi_json_media_type_extras`; that return value wins over this attribute."""
|
|
45
|
+
|
|
40
46
|
def to_example(self) -> Dict[str, Any]:
|
|
41
47
|
"""Generate example for OpenAPI.
|
|
42
48
|
|
fastapi_errors_plus/errors.py
CHANGED
|
@@ -7,6 +7,43 @@ from fastapi import status
|
|
|
7
7
|
|
|
8
8
|
from fastapi_errors_plus.protocol import ErrorDTO
|
|
9
9
|
|
|
10
|
+
# Starlette (via FastAPI) prefers HTTP_422_UNPROCESSABLE_CONTENT over ENTITY.
|
|
11
|
+
# Older pins may lack CONTENT (import crash); avoid nested getattr(, default=)
|
|
12
|
+
# touching ENTITY when CONTENT exists (DeprecationWarning).
|
|
13
|
+
_HTTP_422 = getattr(status, "HTTP_422_UNPROCESSABLE_CONTENT", None)
|
|
14
|
+
if _HTTP_422 is None:
|
|
15
|
+
_HTTP_422 = getattr(status, "HTTP_422_UNPROCESSABLE_ENTITY", 422)
|
|
16
|
+
|
|
17
|
+
# OpenAPI Media Type: merge example/examples separately; other keys (schema, encoding, …) from an extra dict win.
|
|
18
|
+
_OPENAPI_MEDIA_TYPE_EXAMPLE_KEYS = frozenset({"example", "examples"})
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _merge_openapi_application_json_non_example(
|
|
22
|
+
existing_json: Dict[str, Any],
|
|
23
|
+
response_json: Dict[str, Any],
|
|
24
|
+
) -> None:
|
|
25
|
+
"""Apply schema/encoding/extra fields from incoming media type; incoming overwrites on conflict."""
|
|
26
|
+
for key, value in response_json.items():
|
|
27
|
+
if key not in _OPENAPI_MEDIA_TYPE_EXAMPLE_KEYS:
|
|
28
|
+
existing_json[key] = value
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _pick_error_dto_application_json_extra(error_dto: Any) -> Optional[Dict[str, Any]]:
|
|
32
|
+
"""Optional OpenAPI ``application/json`` keys from DTO (e.g. ``schema``, ``encoding``).
|
|
33
|
+
|
|
34
|
+
Prefer ``to_openapi_json_media_type_extras()`` when present and returns a truthy mapping;
|
|
35
|
+
otherwise ``openapi_json_extras`` attribute. Must not rely on ``example`` / ``examples`` here —
|
|
36
|
+
``to_example()`` covers those."""
|
|
37
|
+
getter = getattr(error_dto, "to_openapi_json_media_type_extras", None)
|
|
38
|
+
if callable(getter):
|
|
39
|
+
out = getter()
|
|
40
|
+
if isinstance(out, dict) and out:
|
|
41
|
+
return dict(out)
|
|
42
|
+
extra = getattr(error_dto, "openapi_json_extras", None)
|
|
43
|
+
if isinstance(extra, dict) and extra:
|
|
44
|
+
return dict(extra)
|
|
45
|
+
return None
|
|
46
|
+
|
|
10
47
|
|
|
11
48
|
class Errors(Mapping):
|
|
12
49
|
"""Universal class for documenting errors in FastAPI endpoints.
|
|
@@ -140,7 +177,7 @@ class Errors(Mapping):
|
|
|
140
177
|
|
|
141
178
|
if add_422:
|
|
142
179
|
self._add_standard_error(
|
|
143
|
-
|
|
180
|
+
_HTTP_422,
|
|
144
181
|
"Validation Error",
|
|
145
182
|
{"detail": "Validation error"},
|
|
146
183
|
)
|
|
@@ -239,7 +276,7 @@ class Errors(Mapping):
|
|
|
239
276
|
STANDARD_DESCRIPTIONS = {
|
|
240
277
|
status.HTTP_401_UNAUTHORIZED: "Unauthorized",
|
|
241
278
|
status.HTTP_403_FORBIDDEN: "Forbidden",
|
|
242
|
-
|
|
279
|
+
_HTTP_422: "Validation Error",
|
|
243
280
|
status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal Server Error",
|
|
244
281
|
}
|
|
245
282
|
|
|
@@ -263,7 +300,7 @@ class Errors(Mapping):
|
|
|
263
300
|
standard_keys = {
|
|
264
301
|
status.HTTP_401_UNAUTHORIZED: "StandardUnauthorized",
|
|
265
302
|
status.HTTP_403_FORBIDDEN: "StandardForbidden",
|
|
266
|
-
|
|
303
|
+
_HTTP_422: "StandardValidationError",
|
|
267
304
|
status.HTTP_500_INTERNAL_SERVER_ERROR: "StandardInternalServerError",
|
|
268
305
|
}
|
|
269
306
|
example_key = standard_keys.get(status_code, f"Standard{status_code}")
|
|
@@ -322,6 +359,10 @@ class Errors(Mapping):
|
|
|
322
359
|
if "description" in response_data:
|
|
323
360
|
existing["description"] = response_data["description"]
|
|
324
361
|
|
|
362
|
+
# FastAPI-style shorthand on the response object (incoming dict wins)
|
|
363
|
+
if "model" in response_data:
|
|
364
|
+
existing["model"] = response_data["model"]
|
|
365
|
+
|
|
325
366
|
# Merge content
|
|
326
367
|
if "content" in response_data:
|
|
327
368
|
existing_content = existing.setdefault("content", {})
|
|
@@ -332,6 +373,8 @@ class Errors(Mapping):
|
|
|
332
373
|
existing_json = existing_content.setdefault("application/json", {})
|
|
333
374
|
response_json = response_content["application/json"]
|
|
334
375
|
|
|
376
|
+
_merge_openapi_application_json_non_example(existing_json, response_json)
|
|
377
|
+
|
|
335
378
|
# Handle example/examples
|
|
336
379
|
if "examples" in response_json:
|
|
337
380
|
# Response has examples
|
|
@@ -400,14 +443,16 @@ class Errors(Mapping):
|
|
|
400
443
|
"""
|
|
401
444
|
status_code = error_dto.status_code
|
|
402
445
|
examples = error_dto.to_example()
|
|
403
|
-
|
|
446
|
+
dto_extras = _pick_error_dto_application_json_extra(error_dto)
|
|
447
|
+
|
|
404
448
|
if status_code not in self._responses:
|
|
449
|
+
application_json: Dict[str, Any] = {"examples": examples}
|
|
450
|
+
if dto_extras is not None:
|
|
451
|
+
_merge_openapi_application_json_non_example(application_json, dto_extras)
|
|
405
452
|
self._responses[status_code] = {
|
|
406
453
|
"description": error_dto.message,
|
|
407
454
|
"content": {
|
|
408
|
-
"application/json":
|
|
409
|
-
"examples": examples,
|
|
410
|
-
},
|
|
455
|
+
"application/json": application_json,
|
|
411
456
|
},
|
|
412
457
|
}
|
|
413
458
|
else:
|
|
@@ -446,7 +491,10 @@ class Errors(Mapping):
|
|
|
446
491
|
# Merge new examples from ErrorDTO
|
|
447
492
|
existing_examples.update(examples)
|
|
448
493
|
content_json["examples"] = existing_examples
|
|
449
|
-
|
|
494
|
+
|
|
495
|
+
if dto_extras is not None:
|
|
496
|
+
_merge_openapi_application_json_non_example(content_json, dto_extras)
|
|
497
|
+
|
|
450
498
|
# Mapping protocol implementation
|
|
451
499
|
def __getitem__(self, key: int) -> Dict[str, Any]:
|
|
452
500
|
"""Get response for status code.
|
fastapi_errors_plus/protocol.py
CHANGED
|
@@ -8,6 +8,13 @@ class ErrorDTO(Protocol):
|
|
|
8
8
|
|
|
9
9
|
Any class implementing this protocol can be used with Errors().
|
|
10
10
|
|
|
11
|
+
Optionally, objects may expose **OpenAPI extras** besides examples:
|
|
12
|
+
|
|
13
|
+
- ``openapi_json_extras``: ``dict`` merged into ``content["application/json"]``
|
|
14
|
+
(e.g. ``{"schema": ...}`` — do **not** use for ``example`` / ``examples``).
|
|
15
|
+
- or ``to_openapi_json_media_type_extras() -> Optional[dict]``: if present and returns a
|
|
16
|
+
non-empty ``dict``, it **takes precedence** over ``openapi_json_extras``.
|
|
17
|
+
|
|
11
18
|
Example:
|
|
12
19
|
```python
|
|
13
20
|
class MyError:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-errors-plus
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Universal library for documenting errors in FastAPI endpoints
|
|
5
5
|
Author-email: Igor Selivanov <seligoroff@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -30,12 +30,12 @@ Dynamic: license-file
|
|
|
30
30
|
[](https://opensource.org/licenses/MIT)
|
|
31
31
|
[](https://www.python.org/downloads/)
|
|
32
32
|
[](https://fastapi.tiangolo.com/)
|
|
33
|
-
[](https://github.com/seligoroff/fastapi-errors-plus)
|
|
34
|
+
[](https://github.com/seligoroff/fastapi-errors-plus)
|
|
35
35
|
|
|
36
36
|
Universal library for documenting errors in FastAPI endpoints.
|
|
37
37
|
|
|
38
|
-
> [Русская версия README](README.ru.md)
|
|
38
|
+
> [Русская версия README](https://github.com/seligoroff/fastapi-errors-plus/blob/main/README.ru.md)
|
|
39
39
|
|
|
40
40
|
## Philosophy
|
|
41
41
|
|
|
@@ -207,6 +207,39 @@ def delete_item(id: int):
|
|
|
207
207
|
pass
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
+
#### OpenAPI extras (`schema`) next to examples
|
|
211
|
+
|
|
212
|
+
ADR-style payloads (`code`, `detail`, optional `context`) need a **`schema`** in the spec besides **`examples`**. On **`BaseErrorDTO`** / **`StandardErrorDTO`** use **`openapi_json_extras`** (a dict merged under `content["application/json"]` — omit `example` / `examples` there; **`to_example()`** still defines examples):
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from fastapi import APIRouter, status
|
|
216
|
+
from fastapi_errors_plus import BaseErrorDTO, Errors
|
|
217
|
+
|
|
218
|
+
ADR_ERROR_BODY_SCHEMA = {
|
|
219
|
+
"type": "object",
|
|
220
|
+
"required": ["code", "detail"],
|
|
221
|
+
"properties": {
|
|
222
|
+
"code": {"type": "string"},
|
|
223
|
+
"detail": {"type": "string"},
|
|
224
|
+
"context": {"type": "object"},
|
|
225
|
+
},
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
business_conflict = BaseErrorDTO(
|
|
229
|
+
status_code=status.HTTP_409_CONFLICT,
|
|
230
|
+
message="BusinessRuleViolation",
|
|
231
|
+
openapi_json_extras={"schema": ADR_ERROR_BODY_SCHEMA},
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
router = APIRouter()
|
|
235
|
+
|
|
236
|
+
@router.post("/items", responses=Errors(business_conflict, validation_error=False))
|
|
237
|
+
def create_item():
|
|
238
|
+
...
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Custom **`ErrorDTO`** classes may instead define **`to_openapi_json_media_type_extras()`** returning a **`dict`**; if present and non-empty, it overrides **`openapi_json_extras`**. Any later **`dict`** in **`Errors`** for that status still overrides the same **`application/json`** keys (same precedence as merging two dicts).
|
|
242
|
+
|
|
210
243
|
#### StandardErrorDTO
|
|
211
244
|
|
|
212
245
|
Extended implementation for errors with multiple examples (useful for standard HTTP errors):
|
|
@@ -297,6 +330,37 @@ def update_item(id: int):
|
|
|
297
330
|
|
|
298
331
|
The OpenAPI spec will contain both examples under the 404 status code.
|
|
299
332
|
|
|
333
|
+
When merging the same status code: a **dict** wins for **`description`** over the bundled standard-flag wording; an **ErrorDTO**’s `message` can replace the description only while it still matches the library’s default label for that code (custom descriptions coming from dicts are not overwritten by DTOs).
|
|
334
|
+
|
|
335
|
+
Under `content["application/json"]`, `example` / `examples` are merged as before; any **other** OpenAPI Media Type fields from a later **`dict`** (for example **`schema`**, **`encoding`**) are **copied in** as well—the later dict wins on conflict (**same rule as `description`**).
|
|
336
|
+
|
|
337
|
+
You can combine one **`ErrorDTO`** (examples) with a **`dict`** for the **same numeric status code** listing only **`schema`** (or other non-example keys) without repeating the boilerplate examples block:
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
Errors(
|
|
341
|
+
conflict_error_doc, # implements ErrorDTO, e.g. .for_openapi() for ADR-shaped examples
|
|
342
|
+
{
|
|
343
|
+
status.HTTP_409_CONFLICT: {
|
|
344
|
+
"description": "Business rule violation",
|
|
345
|
+
"content": {
|
|
346
|
+
"application/json": {
|
|
347
|
+
"schema": {
|
|
348
|
+
"type": "object",
|
|
349
|
+
"properties": {
|
|
350
|
+
"code": {"type": "string"},
|
|
351
|
+
"detail": {"type": "string"},
|
|
352
|
+
"context": {"type": "object"},
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
)
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Order matters only for overlaps: whichever **`dict`** is applied **later** in the **`Errors`** argument list overwrites **`schema`** / **`encoding`** (and **`model`** on the outer response dict, if provided) when the same keys appear again.
|
|
363
|
+
|
|
300
364
|
## ErrorDTO Protocol
|
|
301
365
|
|
|
302
366
|
The `ErrorDTO` protocol defines the interface for error objects compatible with the library:
|
|
@@ -568,14 +632,15 @@ Errors(
|
|
|
568
632
|
FastAPI automatically validates all parameters (Path, Query, Body), so 422 is relevant in 95%+ of endpoints. For endpoints without parameters, explicitly set `validation_error=False` or `validation_error_422=False`.
|
|
569
633
|
|
|
570
634
|
**Returns:**
|
|
571
|
-
-
|
|
572
|
-
-
|
|
635
|
+
- A dict-like `Mapping[int, …]` suitable for FastAPI’s `responses` / OpenAPI
|
|
636
|
+
- Pass the instance as-is — **do not** call it like a function: `responses=Errors(...)`
|
|
573
637
|
|
|
574
638
|
#### Usage
|
|
575
639
|
|
|
576
640
|
```python
|
|
577
|
-
#
|
|
578
|
-
|
|
641
|
+
# Instances are Mapping keyed by HTTP status codes
|
|
642
|
+
error_responses = Errors(unauthorized_401=True, forbidden_403=True)
|
|
643
|
+
documented = error_responses[401] # response block picked up by OpenAPI
|
|
579
644
|
```
|
|
580
645
|
|
|
581
646
|
### `ErrorDTO`
|
|
@@ -589,6 +654,8 @@ Protocol for error objects compatible with the library.
|
|
|
589
654
|
**Required methods:**
|
|
590
655
|
- `to_example() -> Dict[str, Any]` — Generate example for OpenAPI
|
|
591
656
|
|
|
657
|
+
During `Errors(...)` initialization, non-`dict` objects in `*errors` missing `status_code`, `message`, or a callable `to_example` raise **`TypeError`** naming what was missing.
|
|
658
|
+
|
|
592
659
|
### `BaseErrorDTO`
|
|
593
660
|
|
|
594
661
|
Base implementation of ErrorDTO Protocol for convenience.
|
|
@@ -598,6 +665,7 @@ Base implementation of ErrorDTO Protocol for convenience.
|
|
|
598
665
|
BaseErrorDTO(
|
|
599
666
|
status_code: int,
|
|
600
667
|
message: str,
|
|
668
|
+
openapi_json_extras: Optional[Dict[str, Any]] = None,
|
|
601
669
|
)
|
|
602
670
|
```
|
|
603
671
|
|
|
@@ -615,6 +683,7 @@ Extended implementation for errors with multiple examples.
|
|
|
615
683
|
StandardErrorDTO(
|
|
616
684
|
status_code: int,
|
|
617
685
|
message: str,
|
|
686
|
+
openapi_json_extras: Optional[Dict[str, Any]] = None,
|
|
618
687
|
examples: Optional[Dict[str, str]] = None,
|
|
619
688
|
)
|
|
620
689
|
```
|
|
@@ -666,7 +735,7 @@ def delete_item(id: int):
|
|
|
666
735
|
```python
|
|
667
736
|
from fastapi import APIRouter
|
|
668
737
|
from fastapi_errors_plus import Errors
|
|
669
|
-
from api.exceptions.dto import
|
|
738
|
+
from api.exceptions.dto import notification_not_found_error # ErrorDTO-compatible instance
|
|
670
739
|
|
|
671
740
|
router = APIRouter()
|
|
672
741
|
|
|
@@ -675,7 +744,7 @@ router = APIRouter()
|
|
|
675
744
|
responses=Errors(
|
|
676
745
|
unauthorized=True,
|
|
677
746
|
forbidden=True,
|
|
678
|
-
|
|
747
|
+
notification_not_found_error,
|
|
679
748
|
),
|
|
680
749
|
)
|
|
681
750
|
async def delete_notification(notification_id: int):
|
|
@@ -714,40 +783,32 @@ This example shows how to use `fastapi-errors-plus` in a FastAPI project with Cl
|
|
|
714
783
|
|
|
715
784
|
**Domain Layer** (`domain/errors.py`):
|
|
716
785
|
```python
|
|
717
|
-
from typing import
|
|
786
|
+
from typing import Dict, Any
|
|
718
787
|
|
|
719
|
-
class
|
|
720
|
-
"""Domain error
|
|
788
|
+
class DomainException(Exception):
|
|
789
|
+
"""Domain exception usable as runtime error and shaped like ErrorDTO for OpenAPI."""
|
|
721
790
|
status_code: int
|
|
722
791
|
message: str
|
|
723
|
-
|
|
724
|
-
def to_example(self) -> Dict[str, Any]:
|
|
725
|
-
"""Generate example for OpenAPI."""
|
|
726
|
-
...
|
|
727
792
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
message = "Item not found"
|
|
732
|
-
|
|
793
|
+
def __init__(self) -> None:
|
|
794
|
+
super().__init__(self.message)
|
|
795
|
+
|
|
733
796
|
def to_example(self) -> Dict[str, Any]:
|
|
734
797
|
return {
|
|
735
|
-
|
|
736
|
-
"value": {"detail":
|
|
798
|
+
self.message: {
|
|
799
|
+
"value": {"detail": self.message},
|
|
737
800
|
},
|
|
738
801
|
}
|
|
739
802
|
|
|
740
|
-
|
|
741
|
-
|
|
803
|
+
|
|
804
|
+
class ItemNotFoundError(DomainException):
|
|
805
|
+
status_code = 404
|
|
806
|
+
message = "Item not found"
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
class ItemAlreadyExistsError(DomainException):
|
|
742
810
|
status_code = 409
|
|
743
811
|
message = "Item already exists"
|
|
744
|
-
|
|
745
|
-
def to_example(self) -> Dict[str, Any]:
|
|
746
|
-
return {
|
|
747
|
-
"ItemAlreadyExists": {
|
|
748
|
-
"value": {"detail": "Item already exists"},
|
|
749
|
-
},
|
|
750
|
-
}
|
|
751
812
|
```
|
|
752
813
|
|
|
753
814
|
**Application Layer** (`application/use_cases.py`):
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
fastapi_errors_plus/__init__.py,sha256=sL6F1BA6lB3cYkk76CKisAVAhVocChlCs_7yiHqWED8,454
|
|
2
|
+
fastapi_errors_plus/base.py,sha256=WNMypKQynTwe7GDxQdCCBwts5oHMaTgURmwMUmxeO0c,4021
|
|
3
|
+
fastapi_errors_plus/errors.py,sha256=Jt0lQ7HocZsT3sfAx4nvSvHGFJ3cc6o2_4VsUoBLyU0,23161
|
|
4
|
+
fastapi_errors_plus/protocol.py,sha256=u5nST4HdPUROXv0b5CYLXU9BAbF5Bh7ee_1MzEzYUxU,1644
|
|
5
|
+
fastapi_errors_plus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
fastapi_errors_plus-0.7.0.dist-info/licenses/LICENSE,sha256=PpYbS0f6IOOqH1JNR3K1UKZdEio6iO2ur9r8TwIZ7zs,1094
|
|
7
|
+
fastapi_errors_plus-0.7.0.dist-info/METADATA,sha256=RD9nST74XBbunErEBsvWvbozidkT-Pa_B7gGhlLJ9uY,27669
|
|
8
|
+
fastapi_errors_plus-0.7.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
9
|
+
fastapi_errors_plus-0.7.0.dist-info/top_level.txt,sha256=vmHLF1-DQYB2quqrvdBA0g6rDtgOWQBrA1m-X_WyNk8,20
|
|
10
|
+
fastapi_errors_plus-0.7.0.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
fastapi_errors_plus/__init__.py,sha256=EGgxWvcYC_R3mwD8wDu5_Cx7U2E58pnYnC3YHrDtzJY,454
|
|
2
|
-
fastapi_errors_plus/base.py,sha256=tGCroiEZM9aNYH9ikmYbp-FHZF7yDMfZyMMF-5rc9qQ,3581
|
|
3
|
-
fastapi_errors_plus/errors.py,sha256=zS1AO_auXfDlrnfNMHkvNpUwREXs76atL_fRDlm_cUo,20871
|
|
4
|
-
fastapi_errors_plus/protocol.py,sha256=HaoMr73cL64y3Q9KcO0cKh_DcJbcR3VHxMZLsmpjsWI,1219
|
|
5
|
-
fastapi_errors_plus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
fastapi_errors_plus-0.6.2.dist-info/licenses/LICENSE,sha256=PpYbS0f6IOOqH1JNR3K1UKZdEio6iO2ur9r8TwIZ7zs,1094
|
|
7
|
-
fastapi_errors_plus-0.6.2.dist-info/METADATA,sha256=a9v0T3zfWh8uSBmK6UpzRvun7yS7DxgyO80odgtUECY,24420
|
|
8
|
-
fastapi_errors_plus-0.6.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
-
fastapi_errors_plus-0.6.2.dist-info/top_level.txt,sha256=vmHLF1-DQYB2quqrvdBA0g6rDtgOWQBrA1m-X_WyNk8,20
|
|
10
|
-
fastapi_errors_plus-0.6.2.dist-info/RECORD,,
|
{fastapi_errors_plus-0.6.2.dist-info → fastapi_errors_plus-0.7.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|