Skip to content

Commit

Permalink
Use Optional[T] instead of T | None for Python 3.9 compatibility
Browse files Browse the repository at this point in the history
While most typing annotations are consumed only by type checkers, a
handful of them provide information that can be useful at runtime. For
example, beanquery uses typing annotations for the fields of the named
tuples holding ledger directive represenations derive table column
types.

Make sure that these typing annotations can be interpreted in all
supported Python versions. This requires converting some use of
the `T | None` form to `Optional[T]`. Add a test to avoid regressions.
  • Loading branch information
dnicolodi committed Jan 9, 2025
1 parent 82586a4 commit c044744
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 14 deletions.
29 changes: 15 additions & 14 deletions beancount/core/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from typing import Any
from typing import Iterator
from typing import NamedTuple
from typing import Optional
from typing import Protocol
from typing import Union
from typing import overload
Expand Down Expand Up @@ -111,7 +112,7 @@ class Open(NamedTuple):
date: datetime.date
account: Account
currencies: list[Currency]
booking: Booking | None
booking: Optional[Booking]


class Close(NamedTuple):
Expand Down Expand Up @@ -198,8 +199,8 @@ class Balance(NamedTuple):
date: datetime.date
account: Account
amount: Amount
tolerance: Decimal | None
diff_amount: Amount | None
tolerance: Optional[Decimal]
diff_amount: Optional[Amount]


class Posting(NamedTuple):
Expand Down Expand Up @@ -228,11 +229,11 @@ class Posting(NamedTuple):
"""

account: Account
units: Amount | None
cost: Cost | CostSpec | None
price: Amount | None
flag: Flag | None
meta: Meta | None
units: Optional[Amount]
cost: Cost | Optional[CostSpec]
price: Optional[Amount]
flag: Optional[Flag]
meta: Optional[Meta]


class Transaction(NamedTuple):
Expand Down Expand Up @@ -261,8 +262,8 @@ class Transaction(NamedTuple):
meta: Meta
date: datetime.date
flag: Flag
payee: str | None
narration: str | None
payee: Optional[str]
narration: Optional[str]
tags: frozenset[str]
links: frozenset[str]
postings: list[Posting]
Expand Down Expand Up @@ -305,8 +306,8 @@ class Note(NamedTuple):
date: datetime.date
account: Account
comment: str
tags: frozenset[str] | None
links: frozenset[str] | None
tags: Optional[frozenset[str]]
links: Optional[frozenset[str]]


class Event(NamedTuple):
Expand Down Expand Up @@ -419,8 +420,8 @@ class Document(NamedTuple):
date: datetime.date
account: Account
filename: str
tags: frozenset[str] | None
links: frozenset[str] | None
tags: Optional[frozenset[str]]
links: Optional[frozenset[str]]


class Custom(NamedTuple):
Expand Down
15 changes: 15 additions & 0 deletions beancount/core/data_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import datetime
import pickle
import typing
import unittest
from datetime import date

Expand Down Expand Up @@ -434,5 +435,19 @@ def test_data_tuples_support_pickle(self):
self.assertEqual(txn1, txn2)


class TestAnnotations(unittest.TestCase):
def test_directive_typed_named_tuples(self):
# While most typing annotations are consumed only by type
# checkers, a handful of them provide information that can be
# useful at runtime. For example, beanquery uses typing
# annotations for the fields of the named tuples holding
# ledger directive represenations derive table column types.
#
# Verify that these annotations can interpreted.
for cls in data.ALL_DIRECTIVES:
with self.subTest(cls=cls.__name__):
typing.get_type_hints(cls)


if __name__ == "__main__":
unittest.main()

0 comments on commit c044744

Please sign in to comment.