fix: allow integers to create and add with Path. Fix #146 (#148)
fix: allow integers to create and add with Path. Fix #146 (#148)

This effectively treats an integer `x` as if it were the string `"[x]"`, allowing
`Path(x)` and `x + Path(...) + x` in addition to current `Path(...)[x]`.

There are several possible implementation approaches, including a straightforward
`if isinstance(x, int): x = f"[{int(x)}]"` in `__new__`, `__add__` and `__radd__`,
then letting it parse as an actual string.

However, not only that approach is very inefficient, as it calls the parser and
tokenization for a known outcome, but also this was not the approach taken by
`__getitem__`, currently the only method that can be used as reference on how to
properly handle integers.

It is also important be consistent with the current _semantics_ of `Path(x)` and
`Path + x`, as they're different from `Path[x]` for strings and Paths, so do
not converge to using `Path[x]` for both. Even if for integers it ends up being
the same result, as integers can only be a single index, do not rely on that
and keep semantics distinct and consistent with the string code path.

So in `__new__`, instead of resorting to a `return cls()[x]` shortcut, we call the
same classmethod as str and Path do, `cls.from_accessors()`, passing the same
argument as __getitem__ uses: a tuple with a single element `ListIndex(index=x)`,
which is also, not coincidentally, the same result of parsing `"[x]"`.

As for `__add__`/`__radd__`, again we use the same semantics as used by str:
`Path(...) + x == Path(...)[Path(x)]`, and `x + Path(...) == Path(x)[Path(...)]`
And, as we just defined `Path(x)` for an integer x, we can simply extend the
`isinstance(x, str)` check to include `int`, without creating a new case, thus
enforcing consistent semantics.
vberlier/nbtlib