Skip to content

Commit 3c3c48e

Browse files
authored
Add __id field for record types (#20)
1 parent ec8f4b4 commit 3c3c48e

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

src/py_avro_schema/_schemas.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
NamesType = List[str]
7373

7474
RUNTIME_TYPE_KEY = "_runtime_type"
75+
REF_ID_KEY = "__id"
7576
SYMBOL_REGEX = re.compile(r"[A-Za-z_][A-Za-z0-9_]*")
7677

7778

@@ -143,6 +144,9 @@ class Option(enum.Flag):
143144
#: Adds a _runtime_type field to the record schemas that contains the name of the class
144145
ADD_RUNTIME_TYPE_FIELD = enum.auto()
145146

147+
#: Add an __id field to records to track the id of mutable objects
148+
ADD_REFERENCE_ID = enum.auto()
149+
146150

147151
JSON_OPTIONS = [opt for opt in Option if opt.name and opt.name.startswith("JSON_")]
148152

@@ -1008,6 +1012,8 @@ def data_before_deduplication(self, names: NamesType) -> JSONObj:
10081012
doc = _doc_for_class(self.py_type)
10091013
if doc:
10101014
record_schema["doc"] = doc
1015+
if Option.ADD_REFERENCE_ID in self.options:
1016+
record_schema["fields"].append({"name": REF_ID_KEY, "type": ["null", "long"], "default": None})
10111017
return record_schema
10121018

10131019

tests/test_dataclass.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import pytest
2020

2121
import py_avro_schema as pas
22+
from py_avro_schema import Option
2223
from py_avro_schema._alias import Alias, register_type_aliases
2324
from py_avro_schema._testing import assert_schema
2425

@@ -863,3 +864,26 @@ class PyType:
863864
],
864865
}
865866
assert_schema(PyType, expected)
867+
868+
869+
def test_reference_id():
870+
@dataclasses.dataclass
871+
class PyType:
872+
var: str
873+
874+
expected = {
875+
"type": "record",
876+
"name": "PyType",
877+
"fields": [
878+
{
879+
"name": "var",
880+
"type": "string",
881+
},
882+
{
883+
"default": None,
884+
"name": "__id",
885+
"type": ["null", "long"],
886+
},
887+
],
888+
}
889+
assert_schema(PyType, expected, options=Option.ADD_REFERENCE_ID)

tests/test_plain_class.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import pytest
1616

1717
import py_avro_schema
18+
from py_avro_schema import Option
1819
from py_avro_schema._alias import Alias, Opaque, register_type_aliases
1920
from py_avro_schema._testing import assert_schema
2021

@@ -179,3 +180,25 @@ def __init__(self):
179180
}
180181

181182
assert_schema(PyType, expected)
183+
184+
185+
def test_reference_id():
186+
class PyType:
187+
var: str
188+
189+
expected = {
190+
"type": "record",
191+
"name": "PyType",
192+
"fields": [
193+
{
194+
"name": "var",
195+
"type": "string",
196+
},
197+
{
198+
"default": None,
199+
"name": "__id",
200+
"type": ["null", "long"],
201+
},
202+
],
203+
}
204+
assert_schema(PyType, expected, options=Option.ADD_REFERENCE_ID)

tests/test_typed_dict.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,25 @@ class PyType(TypedDict):
131131
}
132132

133133
assert_schema(PyType, expected, options=pas.Option.MARK_NON_TOTAL_TYPED_DICTS)
134+
135+
136+
def test_reference_id():
137+
class PyType(TypedDict):
138+
var: str
139+
140+
expected = {
141+
"type": "record",
142+
"name": "PyType",
143+
"fields": [
144+
{
145+
"name": "var",
146+
"type": "string",
147+
},
148+
{
149+
"default": None,
150+
"name": "__id",
151+
"type": ["null", "long"],
152+
},
153+
],
154+
}
155+
assert_schema(PyType, expected, options=pas.Option.ADD_REFERENCE_ID)

0 commit comments

Comments
 (0)