Skip to content

Commit a0eda9a

Browse files
authored
Merge pull request #2 from seandstewart/seandstewart/conflicting-var-names
fix: inspect types when resolving field marshallers for structured types
2 parents 6cb9b75 + a5ddf68 commit a0eda9a

File tree

10 files changed

+119
-29
lines changed

10 files changed

+119
-29
lines changed

.github/workflows/docs.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ name: Make Documentation
33
on:
44
push:
55
branches: ["main"]
6-
tags: ["*"]
76

87
defaults:
98
run:

.github/workflows/publish.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ jobs:
9191
- uses: actions/checkout@v4
9292
with:
9393
token: ${{ steps.app-token.outputs.token }}
94+
fetch-depth: 0
9495
- uses: ./.github/actions/bootstrap-environ
9596
with:
9697
python-version: 3.x
@@ -110,11 +111,16 @@ jobs:
110111
- name: Compile Release Notes
111112
run: make release-notes > release-notes.md
112113
- name: Report Version
113-
run: echo "RELEASE_VERSION=v$(make report-version)" >> $GITHUB_ENV
114+
run: |
115+
export "RELEASE_VERSION=v$(make report-version)";
116+
export "TARGET_COMMITISH=$(git rev-list -n 1 "${RELEASE_VERSION}")";
117+
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> $GITHUB_ENV
118+
echo "TARGET_COMMITISH=${TARGET_COMMITISH}" >> $GITHUB_ENV
114119
- name: Create GitHub Release
115120
uses: softprops/action-gh-release@v2
116121
with:
117122
body_path: release-notes.md
118123
tag_name: ${{ github.env.RELEASE_VERSION }}
124+
target_commitish: ${{ github.env.TARGET_COMMITISH }}
119125
make_latest: true
120126
files: dist/*

.github/workflows/validate.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
name: Validate
2-
on: [push, pull_request]
2+
on:
3+
push:
4+
35
jobs:
46
ci:
57
uses: ./.github/workflows/.validate-matrix.yml

src/typelib/marshals/routines.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
import re
1313
import typing as tp
1414
import uuid
15+
import warnings
1516

1617
from typelib import graph, serdes
17-
from typelib.py import compat, inspection
18+
from typelib.py import compat, inspection, refs
1819

1920
T = tp.TypeVar("T")
2021

@@ -452,7 +453,30 @@ def __init__(self, t: type[_ST], context: ContextT, *, var: str | None = None):
452453
var: A variable name for the indicated type annotation (unused, optional).
453454
"""
454455
super().__init__(t, context, var=var)
455-
self.fields_by_var = {m.var: m for m in self.context.values() if m.var}
456+
self.fields_by_var = self._fields_by_var()
457+
458+
def _fields_by_var(self):
459+
fields_by_var = {}
460+
tp_var_map = {(t.type, t.var): m for t, m in self.context.items()}
461+
hints = inspection.cached_type_hints(self.t)
462+
for name, hint in hints.items():
463+
resolved = refs.evaluate(hint)
464+
fkey = (hint, name)
465+
rkey = (resolved, name)
466+
if fkey in tp_var_map:
467+
fields_by_var[name] = tp_var_map[fkey]
468+
continue
469+
if rkey in tp_var_map:
470+
fields_by_var[name] = tp_var_map[rkey]
471+
continue
472+
473+
warnings.warn( # pragma: no cover
474+
"Failed to identify an unmarshaller for the associated type-variable pair: "
475+
f"Original ref: {fkey}, Resolved ref: {resolved}. Will default to no-op.",
476+
stacklevel=3,
477+
)
478+
fields_by_var[name] = NoOpMarshaller(hint, self.context, var=name)
479+
return fields_by_var
456480

457481
def __call__(self, val: _ST) -> MarshalledMappingT:
458482
"""Marshal a structured type into a simple [`dict`][].

src/typelib/unmarshals/routines.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
import types
1515
import typing as tp
1616
import uuid
17+
import warnings
1718

1819
from typelib import constants, graph, serdes
19-
from typelib.py import compat, inspection
20+
from typelib.py import compat, inspection, refs
2021

2122
T = tp.TypeVar("T")
2223

@@ -967,7 +968,30 @@ def __init__(self, t: type[_ST], context: ContextT, *, var: str | None = None):
967968
var: A variable name for the indicated type annotation (unused, optional).
968969
"""
969970
super().__init__(t, context, var=var)
970-
self.fields_by_var = {m.var: m for m in self.context.values() if m.var}
971+
self.fields_by_var = self._fields_by_var()
972+
973+
def _fields_by_var(self):
974+
fields_by_var = {}
975+
tp_var_map = {(t.type, t.var): m for t, m in self.context.items()}
976+
hints = inspection.cached_type_hints(self.t)
977+
for name, hint in hints.items():
978+
resolved = refs.evaluate(hint)
979+
fkey = (hint, name)
980+
rkey = (resolved, name)
981+
if fkey in tp_var_map:
982+
fields_by_var[name] = tp_var_map[fkey]
983+
continue
984+
if rkey in tp_var_map:
985+
fields_by_var[name] = tp_var_map[rkey]
986+
continue
987+
988+
warnings.warn(
989+
"Failed to identify an unmarshaller for the associated type-variable pair: "
990+
f"Original ref: {fkey}, Resolved ref: {resolved}. Will default to no-op.",
991+
stacklevel=3,
992+
)
993+
fields_by_var[name] = NoOpUnmarshaller(hint, self.context, var=name)
994+
return fields_by_var
971995

972996
def __call__(self, val: tp.Any) -> _ST:
973997
"""Unmarshal a value into the bound type.

tests/models.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,24 @@ class UnionSTDLib:
6262
timestamp: datetime.datetime | None = None
6363
date_time: datetime.datetime | None = None
6464
intstr: int | str = 0
65+
66+
67+
@dataclasses.dataclass
68+
class Parent:
69+
intersection: ParentIntersect
70+
child: Child
71+
72+
73+
@dataclasses.dataclass
74+
class Child:
75+
intersection: ChildIntersect
76+
77+
78+
@dataclasses.dataclass
79+
class ParentIntersect:
80+
a: int
81+
82+
83+
@dataclasses.dataclass
84+
class ChildIntersect:
85+
b: int

tests/unit/marshals/test_api.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@
142142
given_input=models.GivenEnum.one,
143143
expected_output=models.GivenEnum.one.value,
144144
),
145+
attrib_conflict=dict(
146+
given_type=models.Parent,
147+
given_input=models.Parent(
148+
intersection=models.ParentIntersect(a=0),
149+
child=models.Child(intersection=models.ChildIntersect(b=0)),
150+
),
151+
expected_output={"intersection": {"a": 0}, "child": {"intersection": {"b": 0}}},
152+
),
145153
)
146154
def test_marshal(given_type, given_input, expected_output):
147155
# When

tests/unit/marshals/test_routines.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import pytest
1212

13+
from typelib import graph
1314
from typelib.marshals import routines
1415

1516
from tests import models
@@ -386,8 +387,12 @@ def test_fixed_tuple_unmarshaller(
386387
@pytest.mark.suite(
387388
context=dict(
388389
given_context={
389-
int: routines.IntegerMarshaller(int, {}, var="value"),
390-
str: routines.StringMarshaller(str, {}, var="field"),
390+
graph.TypeNode(int, var="value"): routines.IntegerMarshaller(
391+
int, {}, var="value"
392+
),
393+
graph.TypeNode(str, var="field"): routines.StringMarshaller(
394+
str, {}, var="field"
395+
),
391396
},
392397
expected_output=dict(field="data", value=1),
393398
),

tests/unit/unmarshals/test_api.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@
149149
timestamp=datetime.datetime.fromtimestamp(0, datetime.timezone.utc)
150150
),
151151
),
152+
attrib_conflict=dict(
153+
given_type=models.Parent,
154+
given_input={"intersection": {"a": 0}, "child": {"intersection": {"b": 0}}},
155+
expected_output=models.Parent(
156+
intersection=models.ParentIntersect(a=0),
157+
child=models.Child(intersection=models.ChildIntersect(b=0)),
158+
),
159+
),
152160
)
153161
def test_unmarshal(given_type, given_input, expected_output):
154162
# When

tests/unit/unmarshals/test_routines.py

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import pytest
1212

13+
from typelib import graph
1314
from typelib.unmarshals import routines
1415

1516
from tests import models
@@ -718,44 +719,36 @@ def test_fixed_tuple_unmarshaller(
718719

719720

720721
@pytest.mark.suite(
721-
dataclass=dict(
722-
given_cls=models.Data,
722+
context=dict(
723723
given_context={
724-
int: routines.NumberUnmarshaller(int, {}, var="value"),
725-
str: routines.StringUnmarshaller(str, {}, var="field"),
724+
graph.TypeNode(int, var="value"): routines.NumberUnmarshaller(
725+
int, {}, var="value"
726+
),
727+
graph.TypeNode(str, var="field"): routines.StringUnmarshaller(
728+
str, {}, var="field"
729+
),
726730
},
731+
),
732+
)
733+
@pytest.mark.suite(
734+
dataclass=dict(
735+
given_cls=models.Data,
727736
expected_output=models.Data(field="data", value=1),
728737
),
729738
vanilla=dict(
730739
given_cls=models.Vanilla,
731-
given_context={
732-
int: routines.NumberUnmarshaller(int, {}, var="value"),
733-
str: routines.StringUnmarshaller(str, {}, var="field"),
734-
},
735740
expected_output=models.Vanilla(field="data", value=1),
736741
),
737742
vanilla_with_hints=dict(
738743
given_cls=models.VanillaWithHints,
739-
given_context={
740-
int: routines.NumberUnmarshaller(int, {}, var="value"),
741-
str: routines.StringUnmarshaller(str, {}, var="field"),
742-
},
743744
expected_output=models.VanillaWithHints(field="data", value=1),
744745
),
745746
named_tuple=dict(
746747
given_cls=models.NTuple,
747-
given_context={
748-
int: routines.NumberUnmarshaller(int, {}, var="value"),
749-
str: routines.StringUnmarshaller(str, {}, var="field"),
750-
},
751748
expected_output=models.NTuple(field="data", value=1),
752749
),
753750
typed_dict=dict(
754751
given_cls=models.TDict,
755-
given_context={
756-
int: routines.NumberUnmarshaller(int, {}, var="value"),
757-
str: routines.StringUnmarshaller(str, {}, var="field"),
758-
},
759752
expected_output=models.TDict(field="data", value=1),
760753
),
761754
)

0 commit comments

Comments
 (0)