localstack-py-avro-schema 3.9.1__py3-none-any.whl → 3.9.2__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.
- {localstack_py_avro_schema-3.9.1.dist-info → localstack_py_avro_schema-3.9.2.dist-info}/METADATA +1 -1
- localstack_py_avro_schema-3.9.2.dist-info/RECORD +12 -0
- py_avro_schema/_alias.py +37 -0
- py_avro_schema/_schemas.py +21 -6
- localstack_py_avro_schema-3.9.1.dist-info/RECORD +0 -12
- {localstack_py_avro_schema-3.9.1.dist-info → localstack_py_avro_schema-3.9.2.dist-info}/WHEEL +0 -0
- {localstack_py_avro_schema-3.9.1.dist-info → localstack_py_avro_schema-3.9.2.dist-info}/licenses/LICENSE +0 -0
- {localstack_py_avro_schema-3.9.1.dist-info → localstack_py_avro_schema-3.9.2.dist-info}/licenses/LICENSE_HEADER.txt +0 -0
- {localstack_py_avro_schema-3.9.1.dist-info → localstack_py_avro_schema-3.9.2.dist-info}/top_level.txt +0 -0
{localstack_py_avro_schema-3.9.1.dist-info → localstack_py_avro_schema-3.9.2.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: localstack-py-avro-schema
|
|
3
|
-
Version: 3.9.
|
|
3
|
+
Version: 3.9.2
|
|
4
4
|
Summary: Generate Apache Avro schemas for Python types including standard library data-classes and Pydantic data models.
|
|
5
5
|
Author-email: LocalStack Contributors <info@localstack.cloud>, "J.P. Morgan Chase & Co." <open_source@jpmorgan.com>
|
|
6
6
|
License: Apache License
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
localstack_py_avro_schema-3.9.2.dist-info/licenses/LICENSE,sha256=zE1N4JILDTkSIDtdmqdnKKxKEQh_VdqeoAV2230eNOI,10141
|
|
2
|
+
localstack_py_avro_schema-3.9.2.dist-info/licenses/LICENSE_HEADER.txt,sha256=Nx3RGmYbJKjIKM8Y2yMrCPJgCw4oBt_H62PxDKlAsto,564
|
|
3
|
+
py_avro_schema/__init__.py,sha256=bK6hTw4XJy5bAP4lgIvJR5LHtEiyUWq4GNJ5w-uSEpc,2414
|
|
4
|
+
py_avro_schema/_alias.py,sha256=nCQqtn7IbpjV0ibpJf9aMX9FvwVx2EDC1iKzwjQ7CqI,3412
|
|
5
|
+
py_avro_schema/_schemas.py,sha256=I5otHWPh8tcws3ey4iwsx7c0Zz1VNLmMTabTh43E-7s,46993
|
|
6
|
+
py_avro_schema/_testing.py,sha256=3aSfMbNDDeatl3H7GEUcynxK81HFiF-WCLOZ3FCCLiw,2261
|
|
7
|
+
py_avro_schema/_typing.py,sha256=9kBlPA7C33zZP3nRhCvSJA_0m54uvUo0AQ4wJJmSxMk,3291
|
|
8
|
+
py_avro_schema/py.typed,sha256=HnEDkaznpgfRW07Qfogy4tFLu_4dcQ5YcOsI7pmU5rQ,52
|
|
9
|
+
localstack_py_avro_schema-3.9.2.dist-info/METADATA,sha256=6K-dy4M5Pj2-uoHcRF15vZVRz7pfiibgQcAnysW4YKY,15164
|
|
10
|
+
localstack_py_avro_schema-3.9.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
+
localstack_py_avro_schema-3.9.2.dist-info/top_level.txt,sha256=0t4oO_5rsdfZGSk8iSzK4TjdyfVz-RE1IZ2TIz6YvI0,15
|
|
12
|
+
localstack_py_avro_schema-3.9.2.dist-info/RECORD,,
|
py_avro_schema/_alias.py
CHANGED
|
@@ -5,7 +5,9 @@ This module maintains global state via the _ALIASES registry.
|
|
|
5
5
|
Decorators will modify this state when applied to classes.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import dataclasses
|
|
8
9
|
from collections import defaultdict
|
|
10
|
+
from typing import Annotated, Type, get_args, get_origin
|
|
9
11
|
|
|
10
12
|
FQN = str
|
|
11
13
|
"""Fully qualified name for a Python type"""
|
|
@@ -13,6 +15,20 @@ _ALIASES: dict[FQN, set[FQN]] = defaultdict(set)
|
|
|
13
15
|
"""Maps the FQN of a Python type to a set of aliases"""
|
|
14
16
|
|
|
15
17
|
|
|
18
|
+
@dataclasses.dataclass
|
|
19
|
+
class Alias:
|
|
20
|
+
"""Alias for a record field"""
|
|
21
|
+
|
|
22
|
+
alias: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclasses.dataclass
|
|
26
|
+
class Aliases:
|
|
27
|
+
"""Aliases for a record field"""
|
|
28
|
+
|
|
29
|
+
aliases: list[str]
|
|
30
|
+
|
|
31
|
+
|
|
16
32
|
def get_fully_qualified_name(py_type: type) -> str:
|
|
17
33
|
"""Returns the fully qualified name for a Python type"""
|
|
18
34
|
module = getattr(py_type, "__module__", None)
|
|
@@ -77,3 +93,24 @@ def get_aliases(fqn: str) -> list[str]:
|
|
|
77
93
|
if aliases := _ALIASES.get(fqn):
|
|
78
94
|
return sorted(aliases)
|
|
79
95
|
return []
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def get_field_aliases_and_actual_type(py_type: Type) -> tuple[list[str] | None, Type]:
|
|
99
|
+
"""
|
|
100
|
+
Check if a type contains an alias metadata via `Alias` or `Aliases` as metadata.
|
|
101
|
+
It returns the eventual aliases and the type.
|
|
102
|
+
"""
|
|
103
|
+
# py_type is not annotated. It can't have aliases
|
|
104
|
+
if get_origin(py_type) is not Annotated:
|
|
105
|
+
return [], py_type
|
|
106
|
+
|
|
107
|
+
args = get_args(py_type)
|
|
108
|
+
actual_type, annotation = args[0], args[1]
|
|
109
|
+
|
|
110
|
+
# Annotated type but not an alias. We do nothing.
|
|
111
|
+
if type(annotation) not in (Alias, Aliases):
|
|
112
|
+
return [], py_type
|
|
113
|
+
|
|
114
|
+
# If the annotated type is an alias, we extract the aliases and return the actual type
|
|
115
|
+
aliases = annotation.aliases if type(annotation) is Aliases else [annotation.alias]
|
|
116
|
+
return aliases, actual_type
|
py_avro_schema/_schemas.py
CHANGED
|
@@ -50,7 +50,7 @@ import orjson
|
|
|
50
50
|
import typeguard
|
|
51
51
|
|
|
52
52
|
import py_avro_schema._typing
|
|
53
|
-
from py_avro_schema._alias import get_aliases
|
|
53
|
+
from py_avro_schema._alias import get_aliases, get_field_aliases_and_actual_type
|
|
54
54
|
|
|
55
55
|
if TYPE_CHECKING:
|
|
56
56
|
# Pydantic not necessarily required at runtime
|
|
@@ -909,6 +909,7 @@ class RecordField:
|
|
|
909
909
|
py_type: Type,
|
|
910
910
|
name: str,
|
|
911
911
|
namespace: Optional[str],
|
|
912
|
+
aliases: list[str] | None = None,
|
|
912
913
|
default: Any = dataclasses.MISSING,
|
|
913
914
|
docs: str = "",
|
|
914
915
|
options: Option = Option(0),
|
|
@@ -919,12 +920,16 @@ class RecordField:
|
|
|
919
920
|
:param py_type: The Python class or type
|
|
920
921
|
:param name: Field name
|
|
921
922
|
:param namespace: Avro schema namespace
|
|
923
|
+
:param aliases: Aliases for the field
|
|
922
924
|
:param default: Field default value
|
|
923
925
|
:param docs: Field documentation or description
|
|
924
926
|
:param options: Schema generation options
|
|
925
927
|
"""
|
|
928
|
+
if aliases is None:
|
|
929
|
+
aliases = []
|
|
926
930
|
self.py_type = py_type
|
|
927
931
|
self.name = name
|
|
932
|
+
self.aliases = aliases
|
|
928
933
|
self._namespace = namespace
|
|
929
934
|
self.default = default
|
|
930
935
|
self.docs = docs
|
|
@@ -949,6 +954,8 @@ class RecordField:
|
|
|
949
954
|
"name": self.name,
|
|
950
955
|
"type": self.schema.data(names=names),
|
|
951
956
|
}
|
|
957
|
+
if self.aliases:
|
|
958
|
+
field_data["aliases"] = sorted(self.aliases)
|
|
952
959
|
if self.default != dataclasses.MISSING:
|
|
953
960
|
field_data["default"] = self.schema.make_default(self.default)
|
|
954
961
|
if self.docs and Option.NO_DOC not in self.options:
|
|
@@ -984,11 +991,13 @@ class DataclassSchema(RecordSchema):
|
|
|
984
991
|
default = py_field.default
|
|
985
992
|
if callable(py_field.default_factory): # type: ignore
|
|
986
993
|
default = py_field.default_factory() # type: ignore
|
|
994
|
+
aliases, actual_type = get_field_aliases_and_actual_type(py_field.type) # type: ignore
|
|
987
995
|
field_obj = RecordField(
|
|
988
|
-
py_type=
|
|
996
|
+
py_type=actual_type, # type: ignore
|
|
989
997
|
name=py_field.name,
|
|
990
998
|
namespace=self.namespace_override,
|
|
991
999
|
default=default,
|
|
1000
|
+
aliases=aliases,
|
|
992
1001
|
options=self.options,
|
|
993
1002
|
)
|
|
994
1003
|
|
|
@@ -1024,11 +1033,13 @@ class PydanticSchema(RecordSchema):
|
|
|
1024
1033
|
default = dataclasses.MISSING if py_field.is_required() else py_field.get_default(call_default_factory=True)
|
|
1025
1034
|
py_type = self._annotation(name)
|
|
1026
1035
|
record_name = py_field.alias if Option.USE_FIELD_ALIAS in self.options and py_field.alias else name
|
|
1036
|
+
aliases, actual_type = get_field_aliases_and_actual_type(py_type)
|
|
1027
1037
|
field_obj = RecordField(
|
|
1028
|
-
py_type=
|
|
1038
|
+
py_type=actual_type,
|
|
1029
1039
|
name=record_name,
|
|
1030
1040
|
namespace=self.namespace_override,
|
|
1031
1041
|
default=default,
|
|
1042
|
+
aliases=aliases,
|
|
1032
1043
|
docs=py_field.description or "",
|
|
1033
1044
|
options=self.options,
|
|
1034
1045
|
)
|
|
@@ -1087,11 +1098,13 @@ class PlainClassSchema(RecordSchema):
|
|
|
1087
1098
|
def _record_field(self, py_field: inspect.Parameter) -> RecordField:
|
|
1088
1099
|
"""Return an Avro record field object for a given Python instance attribute"""
|
|
1089
1100
|
default = py_field.default if py_field.default != inspect.Parameter.empty else dataclasses.MISSING
|
|
1101
|
+
aliases, actual_type = get_field_aliases_and_actual_type(py_field.annotation)
|
|
1090
1102
|
field_obj = RecordField(
|
|
1091
|
-
py_type=
|
|
1103
|
+
py_type=actual_type,
|
|
1092
1104
|
name=py_field.name,
|
|
1093
1105
|
namespace=self.namespace_override,
|
|
1094
1106
|
default=default,
|
|
1107
|
+
aliases=aliases,
|
|
1095
1108
|
options=self.options,
|
|
1096
1109
|
)
|
|
1097
1110
|
return field_obj
|
|
@@ -1116,15 +1129,17 @@ class TypedDictSchema(RecordSchema):
|
|
|
1116
1129
|
"""
|
|
1117
1130
|
super().__init__(py_type, namespace=namespace, options=options)
|
|
1118
1131
|
py_type = _type_from_annotated(py_type)
|
|
1119
|
-
self.py_fields: dict[str, Type] = get_type_hints(py_type)
|
|
1132
|
+
self.py_fields: dict[str, Type] = get_type_hints(py_type, include_extras=True)
|
|
1120
1133
|
self.record_fields = [self._record_field(field) for field in self.py_fields.items()]
|
|
1121
1134
|
|
|
1122
1135
|
def _record_field(self, py_field: tuple[str, Type]) -> RecordField:
|
|
1123
1136
|
"""Return an Avro record field object for a given TypedDict field"""
|
|
1137
|
+
aliases, actual_type = get_field_aliases_and_actual_type(py_field[1])
|
|
1124
1138
|
field_obj = RecordField(
|
|
1125
|
-
py_type=
|
|
1139
|
+
py_type=actual_type,
|
|
1126
1140
|
name=py_field[0],
|
|
1127
1141
|
namespace=self.namespace_override,
|
|
1142
|
+
aliases=aliases,
|
|
1128
1143
|
options=self.options,
|
|
1129
1144
|
)
|
|
1130
1145
|
return field_obj
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
localstack_py_avro_schema-3.9.1.dist-info/licenses/LICENSE,sha256=zE1N4JILDTkSIDtdmqdnKKxKEQh_VdqeoAV2230eNOI,10141
|
|
2
|
-
localstack_py_avro_schema-3.9.1.dist-info/licenses/LICENSE_HEADER.txt,sha256=Nx3RGmYbJKjIKM8Y2yMrCPJgCw4oBt_H62PxDKlAsto,564
|
|
3
|
-
py_avro_schema/__init__.py,sha256=bK6hTw4XJy5bAP4lgIvJR5LHtEiyUWq4GNJ5w-uSEpc,2414
|
|
4
|
-
py_avro_schema/_alias.py,sha256=B0wfiva1ErVna1rpTCjhuvYHhoYOz_-YgcW8C2TrIOo,2360
|
|
5
|
-
py_avro_schema/_schemas.py,sha256=uyBheFP-0o7RBBBJVZg2FNxErwoydlgojYc88B51kDg,46237
|
|
6
|
-
py_avro_schema/_testing.py,sha256=3aSfMbNDDeatl3H7GEUcynxK81HFiF-WCLOZ3FCCLiw,2261
|
|
7
|
-
py_avro_schema/_typing.py,sha256=9kBlPA7C33zZP3nRhCvSJA_0m54uvUo0AQ4wJJmSxMk,3291
|
|
8
|
-
py_avro_schema/py.typed,sha256=HnEDkaznpgfRW07Qfogy4tFLu_4dcQ5YcOsI7pmU5rQ,52
|
|
9
|
-
localstack_py_avro_schema-3.9.1.dist-info/METADATA,sha256=DcY8xlpg6j-rl_gcSRsoVfdAzmI_S491g83ZBcCyYOo,15164
|
|
10
|
-
localstack_py_avro_schema-3.9.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
-
localstack_py_avro_schema-3.9.1.dist-info/top_level.txt,sha256=0t4oO_5rsdfZGSk8iSzK4TjdyfVz-RE1IZ2TIz6YvI0,15
|
|
12
|
-
localstack_py_avro_schema-3.9.1.dist-info/RECORD,,
|
{localstack_py_avro_schema-3.9.1.dist-info → localstack_py_avro_schema-3.9.2.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|