Jonathan, I took a look at your package, and the code, it's a really nice exploration of the solutions.
I did find having to include the o() call in the sdaprano version quite distracting (I realise it's needed to get it to work in current cpython without silly tricks in the interpreter)...
...But I'm not afraid of doing horribly evil things to python for the purposes of proof-of-concepts.
The code in this gist:
Implements a very ugly codec hack to make python 'understand' keywords in index constructs, and I use it to show how the approach proposed by Steven D'Aprano (Please correct me if I'm mis-representing anything!) should work in my mind.
If you want to run this code yourselves, you can do by downloading the 2 files into a directory, and running `run.py` (with an appropriate PYTHONPATH set)
The bit of the gist that is most relevant is this:
class ObjWithGetitem(Helper):
def __getitem__(self, key=None, foo=None, bar=None):
print(f'{key=} {foo=}')
def main():
obj = ObjWithGetitem()
obj[1]
# key=1 foo=None
obj[foo=1]
# key=None foo=1
obj[1, foo=2]
# key=1 foo=2
obj[1, 2]
# key=(1, 2) foo=None
obj[1, 2, foo=3]
# key=(1, 2) foo=3
obj[(1, 2), foo=3]
# key=(1, 2) foo=3
obj[(1, 2), 3, foo=4]
# key=((1, 2), 3) foo=4
obj[**{'foo': 9}]
# key=None foo=9
obj[1, 2, foo=3, xxx=5]
# TypeError: __getitem__() got an unexpected keyword argument 'xxx'
Which I like for its simplicity
I'm not sure about supporting '*args' syntax in indexes at all, unless doing so could be shown to be trivially implementable without any nasty corner-cases.
Steve