mirror of
https://github.com/jbranchaud/til
synced 2026-09-02 09:41:47 +00:00
Add Annotate Return Type On Enum Function as a Python TIL
This commit is contained in:
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
|||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||||
|
|
||||||
_1854 TILs and counting..._
|
_1855 TILs and counting..._
|
||||||
|
|
||||||
See some of the other learning resources I work on:
|
See some of the other learning resources I work on:
|
||||||
|
|
||||||
@@ -1076,6 +1076,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)
|
- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)
|
||||||
- [Access SQLite Result Values By Name With Row Factory](python/access-sqlite-result-values-by-name-with-row-factory.md)
|
- [Access SQLite Result Values By Name With Row Factory](python/access-sqlite-result-values-by-name-with-row-factory.md)
|
||||||
- [Access Variables Outside Loop Scope](python/access-variables-outside-loop-scope.md)
|
- [Access Variables Outside Loop Scope](python/access-variables-outside-loop-scope.md)
|
||||||
|
- [Annotate Return Type On Enum Function](python/annotate-return-type-on-enum-function.md)
|
||||||
- [Another Way To Mark Keyword-Only Dataclass Fields](python/another-way-to-mark-keyword-only-dataclass-fields.md)
|
- [Another Way To Mark Keyword-Only Dataclass Fields](python/another-way-to-mark-keyword-only-dataclass-fields.md)
|
||||||
- [Argument Defaults Are Evaluated When Function Is Defined](python/argument-defaults-are-evaluated-when-function-is-defined.md)
|
- [Argument Defaults Are Evaluated When Function Is Defined](python/argument-defaults-are-evaluated-when-function-is-defined.md)
|
||||||
- [Assert Is Only A Development Check](python/assert-is-only-a-development-check.md)
|
- [Assert Is Only A Development Check](python/assert-is-only-a-development-check.md)
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# Annotate Return Type On Enum Function
|
||||||
|
|
||||||
|
I defined the following `StrEnum` class to capture the canonical set of valid
|
||||||
|
values for a _storage format_ in
|
||||||
|
[`py-vmt`](https://github.com/jbranchaud/py-vmt). It includes a `default`
|
||||||
|
function that can be called to get what the system considers the default storage
|
||||||
|
format.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class StorageFormat(StrEnum):
|
||||||
|
SQLITE = "sqlite"
|
||||||
|
JSON = "json"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default():
|
||||||
|
return StorageFormat.SQLITE
|
||||||
|
```
|
||||||
|
|
||||||
|
This works, but what is missing is a type annotation for the return value of
|
||||||
|
`default`.
|
||||||
|
|
||||||
|
I'd like to use `StorageFormat` as the return type annotation. However, the
|
||||||
|
annotations are eagerly evaluated at the time the function definition is being
|
||||||
|
processed. The `StorageFormat` class is not fully evaluated at that point and so
|
||||||
|
isn't available.
|
||||||
|
|
||||||
|
Instead, what I can do is quote `StorageFormat` as a string to make it a
|
||||||
|
_forward reference_.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class StorageFormat(StrEnum):
|
||||||
|
SQLITE = "sqlite"
|
||||||
|
JSON = "json"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default() -> "StorageFormat":
|
||||||
|
return StorageFormat.SQLITE
|
||||||
|
```
|
||||||
|
|
||||||
|
The string type annotation will be lazily evaluated at a later time when
|
||||||
|
`StorageFormat` fully exists. This is behavior that is slated to be deprecated.
|
||||||
|
And it is no longer needed as of [Python 3.14 which lazily evaluates all
|
||||||
|
annotations by default
|
||||||
|
now](https://docs.python.org/3/reference/compound_stmts.html#annotations).
|
||||||
|
|
||||||
|
If I want to be more specific with the above annotation, I can import [`Literal`
|
||||||
|
from `typing`](https://docs.python.org/3/library/typing.html#typing.Literal) and
|
||||||
|
then wrap a specific enum value.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class StorageFormat(StrEnum):
|
||||||
|
SQLITE = "sqlite"
|
||||||
|
JSON = "json"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default() -> "Literal[StorageFormat.SQLITE]":
|
||||||
|
return StorageFormat.SQLITE
|
||||||
|
```
|
||||||
|
|
||||||
|
Now it will specifically enforce `SQLITE` rather than accepting `SQLITE` or
|
||||||
|
`JSON`.
|
||||||
Reference in New Issue
Block a user