Support customizing tagged union tag values#660
Support customizing tagged union tag values#660mickvangelderen wants to merge 9 commits intoyukinarit:mainfrom
Conversation
77c8c86 to
123a7ab
Compare
| tag: Optional[str] = None | ||
| content: Optional[str] = None | ||
| kind: Kind = Kind.External | ||
| tags: Optional[frozendict[type[Any], str]] = None |
There was a problem hiding this comment.
Using frozendict so the value can be hashed.
| ensure("{{tagging.tag_for(t)}}" in data , "'{{tagging.tag_for(t)}}' key is not present") | ||
| fake_dict = {"fake_key": data["{{tagging.tag_for(t)}}"]} |
There was a problem hiding this comment.
I wonder if we could inline the tags as literals, rather than looking them up during deserialization.
|
|
||
| @overload | ||
| def ExternalTagging_(cls: T, *, tags: dict[type[Any], str]) -> _WithTagging[T]: ... | ||
|
|
||
|
|
||
| def ExternalTagging_(cls: Optional[T] = None, *, tags: dict[type[Any], str]) -> Union[Tagging, _WithTagging[T]]: | ||
| tagging = Tagging(kind=Tagging.Kind.External, tags=tags) | ||
| if cls: | ||
| return tagging(cls) | ||
| else: | ||
| return tagging | ||
|
|
||
|
|
||
| # TODO: This is an instance rather than a function for backwards-compatibility | ||
| # reasons. In the next major version increase this should be replaced with a | ||
| # function. | ||
| ExternalTagging = Tagging() | ||
|
|
||
| Untagged = Tagging(kind=Tagging.Kind.Untagged) |
There was a problem hiding this comment.
This is unfortunate, not sure what to call the function.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #660 +/- ##
==========================================
- Coverage 90.91% 90.81% -0.11%
==========================================
Files 13 13
Lines 2004 2057 +53
Branches 367 373 +6
==========================================
+ Hits 1822 1868 +46
- Misses 123 125 +2
- Partials 59 64 +5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| tag = casefy.pascalcase(self.tag) if self.tag is not None else None | ||
| content = casefy.pascalcase(self.content) if self.content is not None else None | ||
| if self.tags is not None: | ||
| pairs = sorted(self.tags.items(), key=lambda pair: typename(pair[0])) | ||
| parts = (f"{typename(typ)}_{tag}" for typ, tag in pairs) | ||
| tags = re.sub(r"[^A-Za-z0-9]", "_", "_".join(parts)) | ||
| else: | ||
| tags = "" | ||
|
|
||
| if self.is_internal(): | ||
| tag = casefy.pascalcase(self.tag) # type: ignore | ||
| if not tag: | ||
| if tag is None: | ||
| raise SerdeError('"tag" must be specified in InternalTagging') | ||
| return f"Internal{tag}" | ||
| base_name = f"Internal{tag}{tags}" | ||
| elif self.is_adjacent(): | ||
| tag = casefy.pascalcase(self.tag) # type: ignore | ||
| content = casefy.pascalcase(self.content) # type: ignore | ||
| if not tag: | ||
| if tag is None: | ||
| raise SerdeError('"tag" must be specified in AdjacentTagging') | ||
| if not content: | ||
| if content is None: | ||
| raise SerdeError('"content" must be specified in AdjacentTagging') | ||
| return f"Adjacent{tag}{content}" | ||
| base_name = f"Adjacent{tag}{content}{tags}" | ||
| else: | ||
| return self.kind.name | ||
| base_name = f"{self.kind.name}{tags}" | ||
|
|
||
| return base_name |
There was a problem hiding this comment.
I wonder if it would be possible and better to use the Tagging instance as the cache key. It is not obvious how to turn it into a string. Even before this PR, the tag and content are converted to pascal case which I think shouldn't work, unless deserialization is case-insensitive with respect to the those keys.
No description provided.