Non-injective token to AST mappings
taion opened this issue · 4 comments
There are a number of cases in Python where the token-to-AST mapping is very clearly non-injective, where multiple different-looking statements are syntactically equivalent. We should think about how to handle these; perhaps this will require looking at the actual tokens.
Usually only one use case is common, but mangling tokens might be a bit much.
1. elif
(#7)
if foo:
foo()
elif bar:
bar()
if foo:
foo()
else:
if bar:
bar()
2. Nested with
in Python 2 (#15)
with a, b:
pass
with a:
with b:
pass
3. as
in except
in Python 2
try:
foo()
except A as a:
pass
try:
foo()
except A, a:
pass
4. Empty parent class
class Foo:
pass
class Foo():
pass
- I'd say let's leave like it is now (merging the ifs), if that's going to be a problem we can change that in the future :)
- I'd like to merge the with statements if possible
- Let's use
as
, since works for both python 2 and 3 :) - I'd prefer to have no parenthesis
The comma syntax in except
is a Python 2.5 thing so probably it's dead.
The nested with
statements do arise in real code, though: https://github.com/tensorflow/models/blob/1887a5fe187c8ab9f623cd91b74fc8432ce76d6f/research/slim/nets/mobilenet_v1.py#L199-L200
Part of the issue is that there's not a good way to break with
statements to multiple lines. Neither of the following work:
with (
Foo() as foo,
Bar() as bar,
):
pass
with (
Foo() as foo
), (
Bar() as bar
):
pass
The closest is something like:
with \
Foo() as foo, \
Bar() as bar:
pass
But this is less than pretty.
Makes you wish they didn't drop contextlib.nested
in Python 3. ExitStack
can give the same semantics but it's more annoying to use.
YAPF's output here is good for a giggle, though:
# In:
with \
Foo() as foo, \
Foo() as foo_2, \
Bar(
long_argument,
long_argument,
long_argument,
long_argument,
long_argument,
) as bar, \
Baz(some_arg) as baz, \
Baz(some_arg) as baz_2 \
:
pass
# Out:
with Foo() as foo, Foo() as foo_2, Bar(
long_argument,
long_argument,
long_argument,
long_argument,
long_argument,
) as bar, Baz(some_arg) as baz, Baz(some_arg) as baz_2:
pass