obj = MyDataclass(a=1, b=2, c=3)
Instead of: obj = MyDataclass(1, 2, 3) # This would be an error with kw_only=True
The problem you're describing in boto3 (and a lot of other API bindings, and a lot of more layered Python code) is that methods often take in **kwargs and pass them down to a common function that's handling them. From the caller's perspective, **kwargs is a black box with no details on what's in there. Without a docstring or an understanding of the call chain, it's not helpful. from typing import TypedDict, Unpack
class MyFuncKwargs(TypedDict):
arg1: str
arg2: str
arg3: int | None
def my_outer_func(
**kwargs: Unpack[MyFuncKwargs],
) -> None:
_my_inner_func(**kwargs)
def _my_inner_func(
*,
arg1: str,
arg2: str,
arg3: int | None,
) -> None:
...
By defining a TypedDict and typing **kwargs, the IDE and docs can do a better job of showing what arguments the function really takes, and validating them. def my_outer_func(
**kwargs: KwargsOf[_my_inner_func],
) -> None:
...
And then the IDEs and other tooling can just reference that function. This would help make the problem go away for many of the cases where **kwargs is used and passed around. @deprecate_non_keyword_only_args(MyDeprecationWarning)
def my_func(*, a, b, c):
...
But this is a bit more tricky with dataclasses, since `__init__()` is generated automatically. Fortunately, it can be patched after the fact. A bit less clean, but doable. from dataclasses import dataclass
from housekeeping import BaseRemovedInWarning, deprecate_non_keyword_only_args
class RemovedInMyProject20Warning(BaseRemovedInWarning):
product = 'MyProject'
version = '2.0'
@dataclass(kw_only=True)
class MyDataclass:
a: int
b: int
c: str
MyDataclass.__init__ = deprecate_non_keyword_only_args(
RemovedInMyProject20Warning
)(MyDataclass.__init__)
Call it with some positional arguments: dc = MyDataclass(1, 2, c='hi')
and you'd get: testdataclass.py:26: RemovedInMyProject20Warning: Positional arguments `a`, `b` must be passed as keyword arguments when calling `__main__.MyDataclass.__init__()`. Passing as positional arguments will be required in MyProject 2.0.
dc = MyDataclass(1, 2, c='hi')
We'll probably add explicit dataclass support to this soon, since we're starting to move to kw_only=True for dataclasses.
Based on this work, there's now a new suite of tools for producing games under the Faxanadu engine, new major mods built with all this, and some work on a modified ROM better built for porting and modding.
Disassembly is here: https://chipx86.com/faxanadu/
And I've been blogging about it at https://chipx86.blog/
Building a universal web-based retro game modding tool along with that work called Nostalgia Studio. The idea is that there's a core foundation for representing game state and building editors, a platform-specific layer for representing things like the NES APU and PPU state, and then game-specific implementations that populate state for two layers below.
Those are the hobbies.
Day job, I work on Review Board (https://www.reviewboard.org), one of the original code review products. We just released Review Board 8, which was a pretty large project (we built Office document review, browser-native spell checking in CodeMirror, a new interdiff filtering algorithm, Forgejo integration, and a bunch of other things).
So now I'm working on plans for Review Board 9, with a goal of releasing within the next 4-6 months. Got some thoughts on how the review process can be rethought for this current era of development, so starting work on that.