Skip to content

Commit 94a79de

Browse files
v0.1.4 💧
1 parent 8ec225b commit 94a79de

File tree

5 files changed

+652
-7
lines changed

5 files changed

+652
-7
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.1.4] - 2021-06-19 :droplet:
9+
- Restores support for enums on examples `@dataclasses`, after the fix
10+
implemented in `0.1.3`
11+
- Adds support for built-in `UUID`, `time`, `date`, `datetime`, `bytes`,
12+
handling in examples for `YAML` format
13+
- Adds `partial-time` ValueFormat for `time` (see
14+
https://xml2rfc.tools.ietf.org/public/rfc/html/rfc3339.html#anchor14)
15+
816
## [0.1.3] - 2021-06-17 :droplet:
917

1018
- Corrects a bug forcing `camelCase` on examples objects handled as dataclasses

openapidocs/common.py

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import base64
12
import copy
23
import json
3-
from dataclasses import fields, is_dataclass, asdict
4+
from abc import ABC, abstractmethod
5+
from dataclasses import asdict, fields, is_dataclass
6+
from datetime import date, datetime, time
47
from enum import Enum
58
from typing import Any, List, Tuple
9+
from uuid import UUID
610

711
import yaml
812
from essentials.json import FriendlyEncoder
@@ -21,6 +25,38 @@ class OpenAPIRoot(OpenAPIElement):
2125
"""Base class for a root OpenAPI Documentation"""
2226

2327

28+
class ValueTypeHandler(ABC):
29+
@abstractmethod
30+
def normalize(self, value: Any) -> Any:
31+
"""Normalizes a value of the given type into another type."""
32+
33+
34+
class CommonBuiltInTypesHandler(ValueTypeHandler):
35+
def normalize(self, value: Any) -> Any:
36+
if isinstance(value, UUID):
37+
return str(value)
38+
39+
if isinstance(value, Enum):
40+
return value.value
41+
42+
if isinstance(value, time):
43+
return value.strftime("%H:%M:%S")
44+
45+
if isinstance(value, datetime):
46+
return value.isoformat()
47+
48+
if isinstance(value, date):
49+
return value.strftime("%Y-%m-%d")
50+
51+
if isinstance(value, bytes):
52+
return base64.urlsafe_b64encode(value).decode("utf8")
53+
54+
return value
55+
56+
57+
TYPES_HANDLERS = [CommonBuiltInTypesHandler()]
58+
59+
2460
def normalize_key(key: Any) -> str:
2561
if isinstance(key, Enum):
2662
return key.value
@@ -43,12 +79,23 @@ def normalize_dict_factory(items: List[Tuple[Any, Any]]) -> Any:
4379
data["$ref"] = value
4480
continue
4581

46-
if isinstance(value, Enum):
47-
value = value.value
82+
for handler in TYPES_HANDLERS:
83+
value = handler.normalize(value)
84+
4885
data[normalize_key(key)] = value
4986
return data
5087

5188

89+
def regular_dict_factory(items: List[Tuple[Any, Any]]) -> Any:
90+
data = {}
91+
for key, value in items:
92+
for handler in TYPES_HANDLERS:
93+
value = handler.normalize(value)
94+
95+
data[key] = value
96+
return data
97+
98+
5299
# replicates the asdict method from dataclasses module, to support
53100
# bypassing "asdict" on child properties when they implement a `to_obj`
54101
# method: some entities require a specific shape when represented
@@ -62,7 +109,7 @@ def _asdict_inner(obj, dict_factory):
62109
result.append((f.name, value))
63110
return dict_factory(result)
64111
if is_dataclass(obj):
65-
return asdict(obj)
112+
return asdict(obj, dict_factory=regular_dict_factory)
66113
elif isinstance(obj, (list, tuple)):
67114
return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
68115
elif isinstance(obj, dict):
@@ -79,7 +126,7 @@ def normalize_dict(obj):
79126
return obj.to_obj()
80127
if isinstance(obj, OpenAPIElement):
81128
return _asdict_inner(obj, dict_factory=normalize_dict_factory)
82-
return asdict(obj)
129+
return asdict(obj, dict_factory=regular_dict_factory)
83130

84131

85132
class Serializer:

openapidocs/v3.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class ValueFormat(Enum):
4040
PASSWORD = "password"
4141
EMAIL = "email"
4242
UUID = "uuid"
43+
PARTIALTIME = "partial-time"
4344

4445

4546
class SecuritySchemeType(Enum):

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def readme():
88

99
setup(
1010
name="essentials-openapi",
11-
version="0.1.3",
11+
version="0.1.4",
1212
description="Classes to generate OpenAPI Documentation v3 and v2, in JSON and YAML",
1313
long_description=readme(),
1414
long_description_content_type="text/markdown",

0 commit comments

Comments
 (0)