[Python-Dev] async/await PEP

2015-04-17 Thread Yury Selivanov

Hello,

I've just posted a new PEP about adding async/await to python-ideas.
Maybe I should have posted it here instead..

Anyways, please take a look.

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await PEP

2015-04-21 Thread Yury Selivanov

Hi Martin,

On 2015-04-21 4:23 AM, Martin Teichmann wrote:

Hi Yury, Hi List,

I do certainly like the idea of PEP 492, just some small comments:

Thank you!



why do we need two keywords? To me it is not necessarily intuitive
when to use async and when to use await (why is it async for and not
await for?), so wouldn't it be much simpler, and more symmetric, to
just have one keyword? I personally prefer await for that, then it is
"await def", and "await for" (and "await with", etc.).


"await" is a verb - call for action, while "async" is an adjective
(although non-existent in plain English).  Hence "async" tells us
that the statement after it is asynchronous.

At least that's my reasoning about it ;)

Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] async/await in Python; v2

2015-04-21 Thread Yury Selivanov

Hi python-dev,

I'm moving the discussion from python-ideas to here.

The updated version of the PEP should be available shortly
at https://www.python.org/dev/peps/pep-0492
and is also pasted in this email.

Updates:

1. CO_ASYNC flag was renamed to CO_COROUTINE;

2. sys.set_async_wrapper() was renamed to
   sys.set_coroutine_wrapper();

3. New function: sys.get_coroutine_wrapper();

4. types.async_def() renamed to types.coroutine();

5. New section highlighting differences from
   PEP 3152.

6. New AST node - AsyncFunctionDef; the proposal
   now is 100% backwards compatible;

7. A new section clarifying that coroutine-generators
   are not part of the current proposal;

8. Various small edits/typos fixes.


There's is a bug tracker issue to track code review
of the reference implementation (Victor Stinner is
doing the review): http://bugs.python.org/issue24017
While the PEP isn't accepted, we want to make sure
that the reference implementation is ready when such
a decision will be made.


Let's discuss some open questions:

1. Victor raised a question if we should locate
   coroutine() function from 'types' module to
   'functools'.

   My opinion is that 'types' module is a better
   place for 'corotine()', since it adjusts the
   type of the passed generator.  'functools' is
   about 'partials', 'lru_cache' and 'wraps' kind
   of things.

2. I propose to disallow using of 'for..in' loops,
   and builtins like 'list()', 'iter()', 'next()',
   'tuple()' etc on coroutines.

   It's possible by modifying PyObject_GetIter to
   raise an exception if it receives a coroutine-object.

   'yield from' can also be modified to only accept
   coroutine objects if it is called from a generator
   with CO_COROUTINE flag.

   This will further separate coroutines from
   generators, making it harder to screw something
   up by an accident.

   I have a branch of reference implementation
   https://github.com/1st1/cpython/tree/await_noiter
   where this is implemented.  I did not observe
   any performance drop.

   There is just one possible backwards compatibility
   issue here: there will be an exception if  some user
   of asyncio actually used to iterate over generators
   decorated with @coroutine.  But I can't imagine
   why would someone do that, and even if they did --
   it's probably a bug or wrong usage of asyncio.


That's it!  I'd be happy to hear some feedback!

Thanks,
Yury



PEP: 492
Title: Coroutines with async and await syntax
Version: $Revision$
Last-Modified: $Date$
Author: Yury Selivanov 
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 09-Apr-2015
Python-Version: 3.5
Post-History: 17-Apr-2015, 21-Apr-2015


Abstract


This PEP introduces new syntax for coroutines, asynchronous ``with``
statements and ``for`` loops.  The main motivation behind this proposal
is to streamline writing and maintaining asynchronous code, as well as
to simplify previously hard to implement code patterns.


Rationale and Goals
===

Current Python supports implementing coroutines via generators (PEP
342), further enhanced by the ``yield from`` syntax introduced in PEP
380. This approach has a number of shortcomings:

* it is easy to confuse coroutines with regular generators, since they
  share the same syntax; async libraries often attempt to alleviate
  this by using decorators (e.g. ``@asyncio.coroutine`` [1]_);

* it is not possible to natively define a coroutine which has no
  ``yield`` or  ``yield from`` statements, again requiring the use of
  decorators to fix potential refactoring issues;

* support for asynchronous calls is limited to expressions where
  ``yield`` is allowed syntactically, limiting the usefulness of
  syntactic features, such as ``with`` and ``for`` statements.

This proposal makes coroutines a native Python language feature, and
clearly separates them from generators.  This removes
generator/coroutine ambiguity, and makes it possible to reliably define
coroutines without reliance on a specific library.  This also enables
linters and IDEs to improve static code analysis and refactoring.

Native coroutines and the associated new syntax features make it
possible to define context manager and iteration protocols in
asynchronous terms. As shown later in this proposal, the new ``async
with`` statement lets Python programs perform asynchronous calls when
entering and exiting a runtime context, and the new ``async for``
statement makes it possible to perform asynchronous calls in iterators.


Specification
=

This proposal introduces new syntax and semantics to enhance coroutine
support in Python, it does not change the internal implementation of
coroutines, which are still based on generators.

It is strongly suggested that the reader understands how coroutin

Re: [Python-Dev] async/await in Python; v2

2015-04-21 Thread Yury Selivanov

Hi Damien,

Thanks for noticing!  I pushed a fix to the peps repo.

Thanks,
Yury

On 2015-04-21 5:20 PM, Damien George wrote:

Hi Yury,

In your PEP 492 draft, in the Grammar section, I think you're missing
the modifications to the "flow_stmt" line.

Cheers,
Damien.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/yselivanov.ml%40gmail.com


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov

Hi Greg,

On 2015-04-22 2:05 AM, Greg Ewing wrote:

Yury Selivanov wrote:

1. CO_ASYNC flag was renamed to CO_COROUTINE;

2. sys.set_async_wrapper() was renamed to
   sys.set_coroutine_wrapper();

3. New function: sys.get_coroutine_wrapper();

4. types.async_def() renamed to types.coroutine();


I still don't like the idea of hijacking the generic
term "coroutine" and using it to mean this particular
type of object.


In my opinion it's OK.  We propose a new dedicated syntax
to define coroutines.  Old approach to use generators to
implement coroutines will, eventually, be obsolete.

That's why, in PEP 492, we call 'async def' functions
"coroutines", and the ones that are defined with generators
"generator-based coroutines".  You can also have
"greenlets-based coroutines" and "stackless coroutines",
but those aren't native Python concepts.

I'm not sure if you can apply term "cofunctions" to
coroutines in PEP 492.  I guess we can call them
"async functions".




2. I propose to disallow using of 'for..in' loops,
   and builtins like 'list()', 'iter()', 'next()',
   'tuple()' etc on coroutines.


PEP 3152 takes care of this automatically from the fact
that you can't make an ordinary call to a cofunction,
and cocall combines a call and a yield-from. You have
to go out of your way to get hold of the underlying
iterator to use in a for-loop, etc.



On the one hand I like your idea to disallow calling
coroutines without a special keyword (await in case of
PEP 492).  It has downsides, but there is some
elegance in it.  On the other hand, I hate the idea
of grammatically requiring parentheses for 'await'
expressions.  That feels non-pytonic to me.

I'd be happy to hear others opinion on this topic.

Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov

Hi Guido,

On 2015-04-22 11:50 AM, Guido van Rossum wrote:

On Wed, Apr 22, 2015 at 8:40 AM, Yury Selivanov 
wrote:

On the one hand I like your idea to disallow calling
coroutines without a special keyword (await in case of
PEP 492).  It has downsides, but there is some
elegance in it.  On the other hand, I hate the idea
of grammatically requiring parentheses for 'await'
expressions.  That feels non-pytonic to me.

I'd be happy to hear others opinion on this topic.


I'm slowly warming up to Greg's notion that you can't call a coroutine (or
whatever it's called) without a special keyword. This makes a whole class
of bugs obvious the moment the code is executed.

OTOH I'm still struggling with what you have to do to wrap a coroutine in a
Task, the way its done in asyncio by the Task() constructor, the
loop.create_task() method, and the async() function (perhaps to be renamed
to ensure_task() to make way for the async keyword).


If we apply Greg's ideas to PEP 492 we will have the following
(Greg, correct me if I'm wrong):

1. '_typeobject' struct will get a new field 'tp_await'. We can
reuse 'tp_reserved' for that probably.

2. We'll hack Gen(/ceval.c?) objects to raise an error if they
are called directly and have a 'CO_COROUTINE' flag.

3. Task(), create_task() and async() will be modified to call
'coro.__await__(..)' if 'coro' has a 'CO_COROUTINE' flag.

4. 'await' will require parentheses grammatically. That will
make it different from 'yield' expression. For instance,
I still don't know what would 'await coro(123)()' mean.

5. 'await foo(*a, **k)' will be an equivalent to
'yield from type(coro).__await__(coro, *a, **k)'

6. If we ever decide to implement coroutine-generators --
async def functions with 'await' *and* some form of 'yield' --
we'll need to reverse the rule -- allow __call__ and
disallow __await__ on such objects (so that you'll be able
to write 'async for item in coro_gen()' instead of
'async for item in await coro_gen()'.


To be honest, that's a lot of steps and hacks to make this
concept work.  I think that 'set_coroutine_wrapper()'
solves all these problems while keeping the grammar and
implementation simpler.  Moreover, it allows to add
some additional features to the wrapped coroutines,
such as nicer repr() in debug mode (CoroWrapper in
asyncio already does that) and other runtime checks.

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov

Hi Rajiv,

On 2015-04-22 12:53 PM, Rajiv Kumar wrote:

I'd like to suggest another way around some of the issues here, with
apologies if this has already been discussed sometime in the past.

 From the viewpoint of a Python programmer, there are two distinct reasons
for wanting to suspend execution in a block of code:

1. To yield a value from an iterator, as Python generators do today.

2. To cede control to the event loop while waiting for an asynchronous task
to make progress in a coroutine.

As of today both of these reasons to suspend are supported by the same
underlying mechanism, i.e. a "yield" at the end of the chain of "yield
from"s. PEPs 492 and 3152 introduce "await" and "cocall", but at the bottom
of it all there's effectively still a yield as I understand it.

I think that the fact that these two concepts use the same mechanism is
what leads to the issues with coroutine-generators that Greg and Yury have
raised.

With that in mind, would it be possible to introduce a second form of
suspension to Python to specifically handle the case of ceding to the event
loop? I don't know what the implementation complexity of this would be, or
if it's even feasible. But roughly speaking, the syntax for this could use
"await", and code would look just like it does in the PEP. The semantics of
"await " would be analogous to "yield from " today, with the
difference that the Task would go up the chain of "await"s to the outermost
caller, which would typically be asyncio, with some modifications from its
form today. Progress would be made via __anext__ instead of __next__.


I think that what you propose is a great idea. However, its
implementation will be far more invasive than what PEP 492
proposes.  I doubt that we'll be able to make it in 3.5 if
we choose this route.

BUT: With my latest proposal to disallow for..in loops and
iter()/list()-like builtins, the fact that coroutines are
based internally on generators is just an implementation
detail.

There is no way users can exploit the underlying generator
object.  Coroutine-objects only provide 'send()' and 'throw()'
methods, which they would also have with your implementation
idea.

This gives us freedom to consider your approach in 3.6 if
we decide to add coroutine-generators.  To make this work
we might want to patch inspect.py to make isgenerator() family
of functions to return False for coroutines/coroutine-objects.

Thanks a lot for the feedback!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov

Andrew,

On 2015-04-22 2:32 PM, Andrew Svetlov wrote:

For now I can use mix asyncio.coroutines and `async def` functions, I
mean I can write `await f()` inside async def to call
asyncio.coroutine `f` and vise versa: I can use `yield from g()`
inside asyncio.coroutine to call `async def g(): ...`.


That's another good point that I forgot to add to the list.
Thanks for bringing this up.



If we forbid to call `async def` from regualr code how asyncio should
work? I'd like to push `async def` everywhere in asyncio API where
asyncio.coroutine required.


You'll have to use a wrapper that will do the following:

async def foo():
return 'spam'

@asyncio.coroutine
def bar():
what = yield from foo.__await__(foo, *args, **kwargs)
# OR:
what = yield from await_call(foo, *args, **kwargs)

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov



On 2015-04-22 2:53 PM, Andrew Svetlov wrote:

On Wed, Apr 22, 2015 at 9:45 PM, Yury Selivanov  wrote:

[...]



If we forbid to call `async def` from regualr code how asyncio should
work? I'd like to push `async def` everywhere in asyncio API where
asyncio.coroutine required.


You'll have to use a wrapper that will do the following:

async def foo():
 return 'spam'

@asyncio.coroutine
def bar():
 what = yield from foo.__await__(foo, *args, **kwargs)
 # OR:
 what = yield from await_call(foo, *args, **kwargs)


If I cannot directly use `yield from f()` with `async def f():` then
almost every `yield from` inside asyncio library should be wrapped in
`await_call()`. Every third-party asyncio-based library should do the
same.

Also I expect a performance degradation on `await_call()` calls.



I think there is another way... instead of pushing

GET_ITER
...
YIELD_FROM

opcodes, we'll need to replace GET_ITER with another one:

GET_ITER_SPECIAL
...
YIELD_FROM


Where "GET_ITER_SPECIAL (obj)" (just a working name) would check
that if the current code object has CO_COROUTINE and the
object that you will yield-from has it as well, it would
push to the stack the result of (obj.__await__())

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov

Hi PJ,

On 2015-04-22 3:44 PM, PJ Eby wrote:

On Tue, Apr 21, 2015 at 1:26 PM, Yury Selivanov  wrote:

It is an error to pass a regular context manager without ``__aenter__``
and ``__aexit__`` methods to ``async with``.  It is a ``SyntaxError``
to use ``async with`` outside of a coroutine.

I find this a little weird.  Why not just have `with` and `for` inside
a coroutine dynamically check the iterator or context manager, and
either behave sync or async accordingly?  Why must there be a
*syntactic* difference?


One of the things that we try to avoid is to have implicit
places where code execution might be suspended. For that
we use 'yield from' right now, and want to use 'await' with
PEP 492.

To have implicit context switches there is Stackless Python
and greenlets, however, it's harder to reason about the code
written in such a way.  Having explicit 'yield from/await'
is the selling point of asyncio and other frameworks that
use generator-based coroutines.

Hence, we want to stress that 'async with' and 'async for'
do suspend the execution in their protocols.

I don't want to loose control over what kind of iteration
or context manager I'm using.  I don't want to iterate
through a cursor that doesn't do prefetching, I want to
make sure that it does.  This problem is solved by the PEP.



Not only would this simplify the syntax, it would also allow dropping
the need for `async` to be a true keyword, since functions could be
defined via "def async foo():" rather than "async def foo():"

...which, incidentally, highlights one of the things that's been
bothering me about all this "async foo" stuff: "async def" looks like
it *defines the function* asynchronously (as with "async with" and
"async for"), rather than defining an asynchronous function.  ISTM it
should be "def async bar():" or even "def bar() async:".


If we keep 'async with', then we'll have to keep 'async def'
to make it symmetric and easier to remember.  But, in theory,
I'd be OK with 'def async'.

'def name() async' is something that will be extremely hard
to notice in the code.



Also, even that seems suspect to me: if `await` looks for an __await__
method and simply returns the same object (synchronously) if the
object doesn't have an await method, then your code sample that
supposedly will fail if a function ceases to be a coroutine *will not
actually fail*.


It doesn't just do that. In the reference implementation, a
single 'await o' compiles to:

(o) # await arg on top of the stack
GET_AWAITABLE
LOAD_CONST None
YIELD_FROM

Where GET_AWAITABLE does the following:

- If it's a coroutine-object -- return it
- If it's an object with __await__, return iter(object.__await__())
- Raise a TypeError of two above steps don't return

If you had a code like that:

   await coro()

where coro is

async def coro(): pass

you then can certainly refactor core to:

def coro(): return future # or some awaitable, please refer to PEP492

And it won't break anything.

So I'm not sure I understand your remark about
"*will not actually fail*".


In my experience working with coroutine systems, making a system
polymorphic (do something appropriate with what's given) and
idempotent (don't do anything if what's wanted is already done) makes
it more robust.  In particular, it eliminates the issue of mixing
coroutines and non-coroutines.


Unfortunately, to completely eliminate the issue of reusing
existing "non-coroutine" code, or of writing "coroutine" code
that can be used with "non-coroutine" code, you have to use
gevent-kind of libraries.



To sum up: I can see the use case for a new `await` distinguished from
`yield`, but I don't see the need to create new syntax for everything;
ISTM that adding the new asynchronous protocols and using them on
demand is sufficient.  Marking a function asynchronous so it can use
asynchronous iteration and context management seems reasonably useful,
but I don't think it's terribly important for the type of function
result.  Indeed, ISTM that the built-in `object` class could just
implement `__await__` as a no-op returning self, and then *all*
results are trivially asynchronous results and can be awaited
idempotently, so that awaiting something that has already been waited
for is a no-op.


I see all objects implementing __await__ returning "self" as
a very error prone approach.  It's totally OK to write code
like that:

async def coro():
   return fut
future = await coro()

In the above example, if coro ceases to be a coroutine,
'future' will be a result of 'fut', not 'fut' itself.


  (Prior art: the Javascript Promise.resolve() method,
which takes either 

Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov

Ludovic,

On 2015-04-22 5:00 PM, Ludovic Gasc wrote:

Not related, but one of my coworkers asked me if with the new syntax it
will be possible to write an async decorator for coroutines.
If I understand correctly new grammar in PEP, it seems to be yes, but could
you confirm ?


There shouldn't be any problems with writing a decorator.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov

On 2015-04-22 8:35 PM, Guido van Rossum wrote:

On Wed, Apr 22, 2015 at 5:12 PM, Greg Ewing 
wrote:


Guido van Rossum wrote:


On Wed, Apr 22, > OTOH I'm still struggling with what you have to do to
wrap a coroutine in a Task, the way its done in asyncio by the Task()
constructor, the loop.create_task() method, and the async() function


That's easy. You can always use costart() to adapt a cofunction
for use with something expecting a generator-based coroutine,
e.g.

codef my_task_func(arg):
   ...

my_task = Task(costart(my_task_func, arg))

If you're willing to make changes, Task() et al could be made to
recognise cofunctions and apply costart() where needed.


Hm, that feels backwards incompatible (since currently I can write
Task(my_task_func(arg)) and also a step backwards in elegance (having to
pass the args separately).

OTOH the benefit is that it's much harder to accidentally forget to wait
for a coroutine. And maybe the backward compatibility issue is not really a
problem because you have to opt in by using codef or async def.

So I'm still torn. :-)

Somebody would need to take a mature asyncio app and see how often this is
used (i.e. how many place would require adding costart() as in the above
example).


Somewhere in this thread Victor Stinner wrote:

"""A huge part of the asyncio module is based on "yield from fut" where 
fut is a Future object."""


So how would we do "await fut" if await requires parentheses?

I think that the problem of forgetting 'yield from' is a bit 
exaggerated. Yes, I myself forgot 'yield from' once or twice. But that's 
it, it has never happened since.


Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov



On 2015-04-22 9:04 PM, Guido van Rossum wrote:

On Wed, Apr 22, 2015 at 5:55 PM, Yury Selivanov 
wrote:


On 2015-04-22 8:35 PM, Guido van Rossum wrote:


On Wed, Apr 22, 2015 at 5:12 PM, Greg Ewing 
wrote:

  Guido van Rossum wrote:

  On Wed, Apr 22, > OTOH I'm still struggling with what you have to do to

wrap a coroutine in a Task, the way its done in asyncio by the Task()
constructor, the loop.create_task() method, and the async() function

  That's easy. You can always use costart() to adapt a cofunction

for use with something expecting a generator-based coroutine,
e.g.

codef my_task_func(arg):
...

my_task = Task(costart(my_task_func, arg))

If you're willing to make changes, Task() et al could be made to
recognise cofunctions and apply costart() where needed.


Hm, that feels backwards incompatible (since currently I can write
Task(my_task_func(arg)) and also a step backwards in elegance (having to
pass the args separately).

OTOH the benefit is that it's much harder to accidentally forget to wait
for a coroutine. And maybe the backward compatibility issue is not really
a
problem because you have to opt in by using codef or async def.

So I'm still torn. :-)

Somebody would need to take a mature asyncio app and see how often this is
used (i.e. how many place would require adding costart() as in the above
example).


Somewhere in this thread Victor Stinner wrote:

"""A huge part of the asyncio module is based on "yield from fut" where
fut is a Future object."""

So how would we do "await fut" if await requires parentheses?


We could make Future a valid co-callable object.


So you would have to write 'await fut()'?  This is non-intuitive.
To make Greg's proposal work it'd be a *requirement* for 'await'
(enforced by the grammar!) to have '()' after it.


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-22 Thread Yury Selivanov

Greg,

On 2015-04-22 7:47 PM, Greg Ewing wrote:

Yury Selivanov wrote:


On the other hand, I hate the idea
of grammatically requiring parentheses for 'await'
expressions.  That feels non-pytonic to me.


How is it any different from grammatically requiring
parens in an ordinary function call? Nobody ever
complained about that.


It is different.

1. Because 'await' keyword might be at a great distance
from the object you're really calling:

await foo.bar.baz['spam']()
  +---+

Can I chain the calls:

await foo()() ?

or await foo().bar()?

2. Because there is no other keyword in python
with similar behaviour.

3. Moreover: unless I can write 'await future' - your
proposal *won't* work with a lot of existing code
and patterns.  It's going to be radically different
from all other languages that implement 'await' too.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov



On 2015-04-23 8:10 AM, Greg Ewing wrote:

Andrew Svetlov wrote:
From my understanding to use cofunctions I must wrap it with costart 
call:


yield from gather(costart(coro1, a1, a2), costart(coro2), fut3)

There are other places in asyncio API those accept coroutines or
futures as parameters, not only Task() and async().


In a PEP 3152 aware version of asyncio, they would all
know about cofunctions and what to do with them.


What do you mean by that?

In a PEP 3152 aware version of asyncio, it's just *not
possible to write*

cocall gather(coro1(1,2), coro(2,3))

you just have to use your 'costart' built-in:

cocall gather(costart(coro1, 1, 2), costart(coro, 2,3)).

That's all. That's PEP 3152-aware world.

Somehow you think that it's OK to write

cocall fut()  # instead of just cocall fut()

*But it's not*.

A huge amount of existing code won't work.  You won't be
able to migrate it to new syntax easily.

If you have a future object 'fut', it's not intuitive
or pythonic to write 'cocall fut()'.

PEP 3152 was created in pre-asyncio era, and it shows.
It's just not gonna work.  I know because I designed
PEP 492 with a reference implementation at hand, tuning
the proposal to make it backwards compatible and on the
other hand to actually improve things.

Your idea of syntaticaly forcing to use 'cocall' with
parens is cute, but it breaks so many things and habits
that it just doesn't worth it.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov



On 2015-04-23 9:01 AM, Yury Selivanov wrote:
cocall fut()  # instead of just cocall fut() 

Should be:

cocall fut()  # instead of just cocall fut

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov

Hi Wolfgang,

On 2015-04-23 8:27 AM, Wolfgang Langner wrote:

On Thu, Apr 23, 2015 at 12:35 PM, Paul Sokolovsky  wrote:


Hello,

On Thu, 23 Apr 2015 12:18:51 +0300
Andrew Svetlov  wrote:

[]


3.
async with and async for
Bead idea, we clutter the language even more and it is one more
thing every newbie could do wrong.
for x in y:
   result = await f()
is enough, every 'async' framework lived without it over years.

async for i in iterable:
 pass

is not equal for

for fut in iterable:
 i = yield from fut

But people who used Twisted all their life don't know that! They just
know that "async for" is not needed and bad.



I don't think it is bad nor not needed, but the syntax is not beautiful and
for the 90% not doing async stuff irritating and one more thing to learn
and do right/wrong.

There is no way to do things wrong in PEP 492.  An object
either has __aiter__ or it will be rejected by async for.
An object either has __aenter__ or it will be rejected by
async with.

  transaction = yield from connection.transaction()
  try:
...
  except:
yield from transaction.rollback()
  else:
yield from transaction.commit()

is certainly more irritating than

  async with connection.transcation():
...



I had also a need for async loop. But there are other solutions like
channels,
not needing a new syntax.

Also possible a function returning futures and yield in the loop with a
sentinel.

All this goes the road down to a producer consumer pattern. Nothing more.




I know I'm a bad guy to make such comments, too bad there's a bit of
truth in them, or everyone would just call me an a%$&ole right away.


Generally, I already provided feedback (on asyncio list) that asyncio
is based not on native Python concepts like a coroutine, but on
foreign concurrency concepts like callback or Future, and a coroutine
is fitted as a second-class citizen on top of that. I understand why
that was done - to not leave out all those twisteds from a shiny new
world of asyncio, but sometimes one may wonder if having a clear cut
would've helped (compat could then have been added as a clearly separate
subpackage, implemented in terms of coroutines). Now people coming from
non-coroutine frameworks who were promised compatibility see "bad"
things in asyncio (and related areas), and people lured by a promise of
native Python framework see bad things too.



This has nothing to do with people using twisted or other async frameworks
like tornado.
I think a coroutine should be first class. But all this should be done in a
way a beginner
can handle and not design this stuff for experts only.


I think that most of async frameworks out there are for
experts only.  Precisely because of 'yield from', 'yield',
inlineCallbacks, '@coroutine', channels and other stuff.

PEP 492 will make it all easier. And Twisted can use
its features too.



If we do this we
scare away new people.


It doesn't scare away anyone.  async/await were the most
awaited features in dart and javascript.  One of the most
popular features in c#.


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov

Hi,

On 2015-04-23 3:30 AM, Wolfgang Langner wrote:

Hi,

most of the time I am a silent reader but in this discussion I must step in.
I use twisted and async stuff a lot over years followed development of
asyncio closely.

First it is good to do differentiate async coroutines from generators. So
everyone can see it and have this in mind
and don't mix up booth. It is also easier to explain for new users.
Sometimes generators blows their mind and it takes
a while to get used to them. Async stuff is even harder.

1. I am fine with using something special instead of "yield" or "yield
from" for this. C# "await" is ok.

Everything else suggested complicates the language and makes it harder to
read.

2.
async def f(): is harder to read and something special also it breaks the
symmetry in front (def indent).
Also every existing tooling must be changed to support it. Same for def
async, def f() async:
I thing a decorator is enough here
@coroutine
def f():
is the best solution to mark something as a coroutine.


You can't combine a keyword (await) with runtime decorator. Also
it's harder for tools to support @coroutine / @inlineCallbacks
than "async".



3.
async with and async for
Bead idea, we clutter the language even more and it is one more thing every
newbie could do wrong.
for x in y:
   result = await f()
is enough, every 'async' framework lived without it over years.


I only lived without it because I used greenlets for async
for's & with's.  There must be a native language concept to
do these things.


Same for with statement.

The main use case suggested was for database stuff and this is also where
most are best with
defer something to a thread and keep it none async.


All together it is very late in the development cycle for 3.5 to
incorporate such a big change.


The PEP isn't a result of some quick brainstorming.  It's a
result of long experience using asyncio and working around
many painpoints of async programming.


Best is to give all this some more time and defer it to 3.6 and some alpha
releases to experiment with.


There is reference implementation.  asyncio is fully ported,
every package for asyncio should work.  You can experiment right now
and find a real issue why the PEP doesn't work.


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 3152 and yield from Future()

2015-04-23 Thread Yury Selivanov

Hi Victor,

On 2015-04-23 4:43 AM, Victor Stinner wrote:
[...]

 From my understanding, the PEP 3151 simply does not support
asyncio.Future. Am I right?



Greg wants to implement __cocall__ on futures.  This way
you'll be able to write

   cocall fut()  # instead of "await fut"

So you *will have to* use "()"


Another problem is functions that return future:

def do_something():
...
return fut

With Greg's idea to call it you would do:

   cocall (do_something())()

That means that you can't refactor your "do_something"
function and make it a coroutine.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov

Hi Wolfgang,

On 2015-04-23 11:57 AM, Wolfgang Langner wrote:

On Thu, Apr 23, 2015 at 5:32 PM, Yury Selivanov 
wrote:


Hi Wolfgang,

On 2015-04-23 8:27 AM, Wolfgang Langner wrote:


On Thu, Apr 23, 2015 at 12:35 PM, Paul Sokolovsky 
wrote:

  Hello,

On Thu, 23 Apr 2015 12:18:51 +0300
Andrew Svetlov  wrote:

[]

  3.

async with and async for
Bead idea, we clutter the language even more and it is one more
thing every newbie could do wrong.
for x in y:
result = await f()
is enough, every 'async' framework lived without it over years.


async for i in iterable:
  pass

is not equal for

for fut in iterable:
  i = yield from fut


But people who used Twisted all their life don't know that! They just
know that "async for" is not needed and bad.


  I don't think it is bad nor not needed, but the syntax is not beautiful

and
for the 90% not doing async stuff irritating and one more thing to learn
and do right/wrong.


There is no way to do things wrong in PEP 492.  An object
either has __aiter__ or it will be rejected by async for.
An object either has __aenter__ or it will be rejected by
async with.

   transaction = yield from connection.transaction()
   try:
 ...
   except:
 yield from transaction.rollback()
   else:
 yield from transaction.commit()

is certainly more irritating than

   async with connection.transcation():
 ...



I had also a need for async loop. But there are other solutions like
channels,
not needing a new syntax.

Also possible a function returning futures and yield in the loop with a
sentinel.

All this goes the road down to a producer consumer pattern. Nothing more.



  I know I'm a bad guy to make such comments, too bad there's a bit of

truth in them, or everyone would just call me an a%$&ole right away.


Generally, I already provided feedback (on asyncio list) that asyncio
is based not on native Python concepts like a coroutine, but on
foreign concurrency concepts like callback or Future, and a coroutine
is fitted as a second-class citizen on top of that. I understand why
that was done - to not leave out all those twisteds from a shiny new
world of asyncio, but sometimes one may wonder if having a clear cut
would've helped (compat could then have been added as a clearly separate
subpackage, implemented in terms of coroutines). Now people coming from
non-coroutine frameworks who were promised compatibility see "bad"
things in asyncio (and related areas), and people lured by a promise of
native Python framework see bad things too.


  This has nothing to do with people using twisted or other async

frameworks
like tornado.
I think a coroutine should be first class. But all this should be done in
a
way a beginner
can handle and not design this stuff for experts only.


I think that most of async frameworks out there are for
experts only.  Precisely because of 'yield from', 'yield',
inlineCallbacks, '@coroutine', channels and other stuff.

PEP 492 will make it all easier. And Twisted can use
its features too.


Yes and it is good to make it easier. But not complicate it for others.
Beginners will be confronted with all this new syntax an my feel lost.
Oh I have to different for loops, one with async. Same for with statement.


Absolute beginners don't write async code and http servers.

And when they start doing things like that, they're not someone
who can't understand 'async' and 'await'.  It's not harder
than '@coroutine' and 'yield from'.

What is hard for even experienced users, is to understand
what's the difference between 'yield from' and 'yield', and
how asyncio works in the core. Why you should always use the
former etc.

Unfortunately I just can't agree with you here.  Too much time
was spent trying to explain people how to write asyncio code,
and it's hard.  PEP 492 will make it easier.





  If we do this we

scare away new people.


It doesn't scare away anyone.  async/await were the most
awaited features in dart and javascript.  One of the most
popular features in c#.


I like it in C#.
I like await for Python but I don't like async there and how to specify it.
I still think a decorator is enough and no special for and with syntax.

Please read the "Debugging Features" section in the PEP. It explains
why decorator is not enough.  Also the "Rationale" section also
stresses some points.

Decorator solution is "enough", but it's far from being ideal.

For IDEs and linters it's harder to support.  What if you
write "from asyncio import coroutine as coro"?  You have to analyze
the code statically to reason about what "@coroutine" is.  Moreover,
you need to enable good IDE support for other frameworks too.



async in JavaScript is for execution a whole script asynchronously used in
the s

Re: [Python-Dev] PEP 3152 and yield from Future()

2015-04-23 Thread Yury Selivanov

On 2015-04-23 11:26 AM, Victor Stinner wrote:

2015-04-23 17:22 GMT+02:00  :

I can live with `cocall fut()` but the difference between `data = yield from
loop.sock_recv(sock, 1024)` and `data = cocall (loop.sock_recv(sock,
1024))()` frustrates me very much.

You didn't answer to my question. My question is: is it possible to
implement Future.__cocall__() since yield is defined in cofunctions.
If it's possible, can you please show how? (Show me the code!)


I can do that.

class Future:

def __iter__(self):
   
__cocall__ = __iter__


I've outlined the problem with this approach in parallel
email: https://mail.python.org/pipermail/python-dev/2015-April/139456.html

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov

Wolfgang,

On 2015-04-23 12:12 PM, Wolfgang Langner wrote:

On Thu, Apr 23, 2015 at 5:32 PM, Yury Selivanov 
wrote:


Hi Wolfgang,

On 2015-04-23 8:27 AM, Wolfgang Langner wrote:


On Thu, Apr 23, 2015 at 12:35 PM, Paul Sokolovsky 
wrote:

  Hello,

On Thu, 23 Apr 2015 12:18:51 +0300
Andrew Svetlov  wrote:

[]

  3.

async with and async for
Bead idea, we clutter the language even more and it is one more
thing every newbie could do wrong.
for x in y:
result = await f()
is enough, every 'async' framework lived without it over years.


async for i in iterable:
  pass

is not equal for

for fut in iterable:
  i = yield from fut


But people who used Twisted all their life don't know that! They just
know that "async for" is not needed and bad.


  I don't think it is bad nor not needed, but the syntax is not beautiful

and
for the 90% not doing async stuff irritating and one more thing to learn
and do right/wrong.


There is no way to do things wrong in PEP 492.  An object
either has __aiter__ or it will be rejected by async for.
An object either has __aenter__ or it will be rejected by
async with.


Don't mean it can be done wrong on execution or syntax level.
I mean for a beginner it is not as easy an more and some will try
async in some places, yes they will get an error. But there is a
new possibility to get such errors if async is there for with and for
statements.
And the next beginner will then implement __aiter__ instead of __iter__
because
he/she don't get it.


Sorry, Wolfgang, but I don't get your argument.  Beginners
shouldn't just randomly try to use statements.  There is a
documentation for that.  Plus we can make exception messages
better.



On the other side I like "await" and __await__ implementation.
Symmetric good easy to explain, same with "int" and "__int__" and all
others.


Glad to hear that! ;)





   transaction = yield from connection.transaction()
   try:
 ...
   except:
 yield from transaction.rollback()
   else:
 yield from transaction.commit()

is certainly more irritating than

   async with connection.transcation():
 ...



Sorry till now I use async stuff and database access and do it in an extra
thread in sync mode.
No performance problems and can use all good maintained database libraries.
Also twisteds RDBMS (adbapi) is enough here. First I thought it is not
enough or to slow but this was not the case.
https://twistedmatrix.com/documents/current/core/howto/rdbms.html

Here I am on line with Mike Bayer:
http://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/



It's good article, I read it. The PEP will help those who
don't want to use threads and want to use coroutines.

There are no fundamental reasons why coroutines are
slower than threads.  It will only be improved. There is
a fundamental reason to avoid doing threads in python
though, because it can harm performance drastically.

There are some fundamental reasons why Mike will always
love threads though -- we won't ever have asynchronous
__getattr__, so SQLAlchemy won't be as elegant as it is
in sync mode.

Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 3152 and yield from Future()

2015-04-23 Thread Yury Selivanov

I've updated the PEP 492: https://hg.python.org/peps/rev/352d4f907266

Thanks,
Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov

Wolfgang,

On 2015-04-23 12:58 PM, Wolfgang Langner wrote:

On Thu, Apr 23, 2015 at 6:22 PM, Yury Selivanov 
wrote:


Wolfgang,


On 2015-04-23 12:12 PM, Wolfgang Langner wrote:


On Thu, Apr 23, 2015 at 5:32 PM, Yury Selivanov 
wrote:

  Hi Wolfgang,

On 2015-04-23 8:27 AM, Wolfgang Langner wrote:

  On Thu, Apr 23, 2015 at 12:35 PM, Paul Sokolovsky 

wrote:

   Hello,


On Thu, 23 Apr 2015 12:18:51 +0300
Andrew Svetlov  wrote:

[]

   3.


async with and async for

Bead idea, we clutter the language even more and it is one more
thing every newbie could do wrong.
for x in y:
 result = await f()
is enough, every 'async' framework lived without it over years.

  async for i in iterable:

   pass

is not equal for

for fut in iterable:
   i = yield from fut

  But people who used Twisted all their life don't know that! They just

know that "async for" is not needed and bad.


   I don't think it is bad nor not needed, but the syntax is not
beautiful


and
for the 90% not doing async stuff irritating and one more thing to learn
and do right/wrong.

  There is no way to do things wrong in PEP 492.  An object

either has __aiter__ or it will be rejected by async for.
An object either has __aenter__ or it will be rejected by
async with.

  Don't mean it can be done wrong on execution or syntax level.

I mean for a beginner it is not as easy an more and some will try
async in some places, yes they will get an error. But there is a
new possibility to get such errors if async is there for with and for
statements.
And the next beginner will then implement __aiter__ instead of __iter__
because
he/she don't get it.


Sorry, Wolfgang, but I don't get your argument.  Beginners
shouldn't just randomly try to use statements.  There is a
documentation for that.  Plus we can make exception messages
better.


Had to coach a lot of new users to Python and some to async stuff in
twisted.
And what beginners not should do don't care them. ;-)
They will do strange stuff and go other way's than you expected. I only
like to make
it as easy as possible for them. Nothing more.
Less keywords, less ways to do something, best only one way to do it.



Don't get me wrong, I like the PEP it is well written and covers a lot of
areas about async programming.
I know Python must improve in this area and has a lot of potential.
But don't hesitate, give the people time to try it and mature it. If all
this should be in 3.5 it is to early.


The thing about this PEP is that it's build on existing
concepts that were validated with asyncio.

As for is it enough time to review it or not -- it's up to
BDFL to decide.  I'm doing my best trying to get the reference
implementation reviewed and to address all questions in the
PEP, hoping that it will help.

I can only say that if it doesn't land in 3.5, we'll have
to wait another *1.5 years*.  And it's not that people will
download CPython 3.6.alpha0 and start rewriting their code
and playing with it.  In the meanwhile, people want more
good reasons to migrate to Python 3, and I strongly believe
that this PEP is a great reason.

Moreover, it's several months before 3.5 is released. We still
will be able to slightly alter the behaviour and gather
feedback during beta periods.



Also we can avoid the async keyword completely and do the same as for
generators.
If there is an await, it is a coroutine.

Unfortunately there is a problem with this approach:
refactoring of code becomes much harder.  That's one of the
corner cases that @coroutine decorator solves; see
https://www.python.org/dev/peps/pep-0492/#importance-of-async-keyword

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov

Hi Barry,

On 2015-04-23 1:51 PM, Barry Warsaw wrote:

On Apr 21, 2015, at 01:26 PM, Yury Selivanov wrote:


The updated version of the PEP should be available shortly at
https://www.python.org/dev/peps/pep-0492 and is also pasted in this email.

There's a lot to like about PEP 492.  I only want to mildly bikeshed a bit on
the proposed new syntax.

Thanks!


Why "async def" and not "def async"?


To my eye 'async def name()', 'async with', 'async for' look
better than 'def async name()', 'with async' and 'for async'.
But that's highly subjective.

I also read "for async item in iter:" as "I'm iterating iter
with async item".



My concern is about existing tools that already know that "def" as the first
non-whitespace on the line starts a function/method definition.  Think of a
regexp in an IDE that searches backwards from the current line to find the
function its defined on.  Sure, tools can be updated but it is it *necessary*
to choose a syntax that breaks tools?

 def async useful():

seems okay to me.

Probably the biggest impact on the PEP would be symmetry with asynchronous
with and for.  What about:

 with async lock:

and

 for async data in cursor:

That would also preserve at least some behavior of existing tools.

Anyway, since the PEP doesn't explicitly describe this as an alternative, I
want to bring it up.

(I have mild concerns about __a*__ magic methods, since I think they'll be
harder to visually separate, but here the PEP does describe the __async_*__
alternatives.)




Anyways, I'm open to change the order of keywords if most
people like it that way.  Same for __async_*__ naming.

Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov

Barry,

On 2015-04-23 2:12 PM, Barry Warsaw wrote:

On Apr 23, 2015, at 02:02 PM, Yury Selivanov wrote:


To my eye 'async def name()', 'async with', 'async for' look
better than 'def async name()', 'with async' and 'for async'.
But that's highly subjective.

Would you be willing to add this as an alternative to the PEP, under the "Why
async def" section probably?

As with all such bikesheds, Guido will pick the color and we'll ooh and
ahh. :)


Sure! I think it's a great idea:

https://hg.python.org/peps/rev/8cb4c0ab0931
https://hg.python.org/peps/rev/ec319bf4c86e

Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-23 Thread Yury Selivanov


On 2015-04-23 3:03 AM, Greg Ewing wrote:

Yury Selivanov wrote:

- If it's an object with __await__, return iter(object.__await__())


Is the iter() really needed? Couldn't the contract of
__await__ be that it always returns an iterator?



I wrote it the wrong way. iter() isn't needed, you're right.
This is a quote from the ref implementation:

   if (!PyIter_Check(await_obj)) {
PyErr_Format(PyExc_TypeError,
 "__await__ must return an iterator, %.100s",
 Py_TYPE(await_obj)->tp_name);


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 3152 and yield from Future()

2015-04-23 Thread Yury Selivanov



On 2015-04-23 9:05 PM, Greg Ewing wrote:

Combining those last two lines into one would
require some extra parenthesisation, but I don't
think that's something you're going to be doing
much in practice.


It's a common pattern in asyncio when functions
return futures.  It's OK later to refactor those
functions to coroutines *and* vice-versa.  This
is a fundamental problem for PEP 3152 approach.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 3152 and yield from Future()

2015-04-24 Thread Yury Selivanov

Greg,

On 2015-04-24 4:13 AM, Greg Ewing wrote:

Guido van Rossum wrote:

I think this is the nail in PEP 3152's coffin.


Seems more like a small tack to me. :-)
I've addressed all the issues raised there in
earlier posts.



I'm sorry, but this is ridiculous.

You haven't addressed the issues. We raise issues,
saying that your PEP isn't backwards compatible and
is breaking existing idioms.  You say - there is a
workaround for that; or that we can rewrite that and
make it like that; or something else that doesn't
make any sense for existing asyncio developers.

Your PEP isn't backwards compatible. Period.

It *will* be harder for people to get, as it *does*
introduce a new calling grammar that isn't obvious
for at least some people.

We, asyncio developers, who write asyncio code,
*don't* want to write 'cocall fut()'.  I don't
understand *why* I'm required to put parentheses
there (besides someone just requiring me to do so,
because they failed to solve some problem in
backwards compatible way).  You avoid confusion
in one place, but you introduce it in other places.

I'm sorry, but your current way of handling the
discussion isn't really productive.  You don't
listen to arguments by Victor Stinner, Andrew
Svetlov, and me.  At this point, this whole PEP
3152 related discussion isn't helping anyone.

Yury

P.S. I'm sorry if this sounded harsh, this wasn't
my intent.
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-24 Thread Yury Selivanov

Guido,

On 2015-04-24 1:03 PM, Guido van Rossum wrote:


*3. syntactic priority of `await`*

Yury, could you tweak the syntax for `await` so that we can write the most
common usages without parentheses? In particular I'd like to be able to
write
```
return await foo()
with await foo() as bar: ...
foo(await bar(), await bletch())
```
(I don't care about `await foo() + await bar()` but it would be okay.)
```
I think this is reasonable with some tweaks of the grammar (similar to what
Greg did for cocall, but without requiring call syntax at the end).

I don't remember the reason why yield requires parentheses
in expressions, hopefully it's not something fundamental.
This has always annoyed me, so let's try to fix that for
await.  I'll experiment.



Ditto for `__aiter__` and `__anext__`. I guess this means that the async
equivalent to obtaining an iterator through `it = iter(xs)` followed by
`for x over it` will have to look like `ait = await aiter(xs)` followed by
`for x over ait`, where an iterator is required to have an `__aiter__`
method that's an async function and returns self immediately. But what if
you left out the `await` from the first call? I.e. can this work?
```
ait = aiter(xs)
async for x in ait:
 print(x)


With the current semantics that PEP 492 proposes, "await"
for "aiter()" is mandatory.

You have to write

ait = await aiter(xs)
async for x in ait:
print(c)

We can add some logic that will check that the iterator passed
to 'async for' is not an unresolved awaitable and resolve it
(instead of immediately checking if it has __anext__ method),
but that will complicate the implementation.  It will also
introduce more than one way of doing things.  I think that
users will recognize "async builtins" (when we add them) by
the first letter "a" and use them in "await" expressions
consistently.



```
The question here is whether the object returned by aiter(xs) has an
`__aiter__` method. Since it was intended to be the target of  `await`, it
has an `__await__` method. But that itself is mostly an alias for
`__iter__`, not `__aiter__`. I guess it can be made to work, the object
just has to implement a bunch of different protocols.

Correct.  And yes, we address this all by having iteration
protocols clearly separated.



*6. StopAsyncException*

I'm not sure about this. The motivation given in the PEP seems to focus on
the need for `__anext__` to be async. But is this really the right pattern?
What if we required `ait.__anext__()` to return a future, which can either
raise good old `StopIteration` or return the next value from the iteration
when awaited? I'm wondering if there are a few alternatives to be explored
around the async iterator protocol still.

__anext__ should return an awaitable (following the terminology
of the PEP), which can be a coroutine-object.  I'm not sure that
with semantics of PEP 479 it can actually raise StopIteration
(without some hacks in genobject).

I'm also trying to think forward about how we can add
generator-coroutines (the ones that combine 'await' and some
form of 'yield') to make writing asynchronous iterators
easier. I think that reusing StopIteration on that level
will be a very hard thing to understand and implement.

I'll experiment with reference implementation and update
the PEP.


Thank you,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-24 Thread Yury Selivanov

Victor,

On 2015-04-24 5:32 PM, Victor Stinner wrote:

7. compatibility with asyncio and existing users of it

The current state of the PEP makes types.coroutine() mandatory. If a
generator-based coroutine is not modified with types.coroutine, await
cannot be used on it. To be more concrete: asyncio coroutines not
declared with @asyncio.coroutine cannot be used with await.

Would it be crazy to allow waiting on a generator-based coroutine
(current asyncio coroutines) without having to call types.coroutine()
on it?


I'd be big -1 on that.  The current PEP design is all about
strictly prohibiting users from calling regular generators
with 'await' expression.  And if a generator isn't decorated
with @coroutine - then it's a regular generator for us.



Maybe I just missed the purpose of disallow this.

It's also possible to modify asyncio to detect at runtime when an
asyncio coroutine is not decorated by @asyncio.coroutine (emit a
warning or even raise an exception).


I'd be +1 to add a warning to Task and other places where
we accept generator-based coroutines.

Thanks!
Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-24 Thread Yury Selivanov

Lukasz,

On 2015-04-24 5:37 PM, Łukasz Langa wrote:



(Though maybe we should consider `await for` and `await with`? That would have 
the advantage of making it easy to scan for all suspension points by searching 
for /await/. But being a verb it doesn't read very well.)

I’m on the fence here.

OT1H, I think “await for something in a_container” and “await with 
a_context_manager():” also read pretty well. It’s also more consistent with 
being the one way of finding “yield points”.

OTOH, “await with a_context_manager():” suggests the entire statement is 
awaited on, which is not true. “async with” is more opaque in this way, it 
simply states “there are going to be implementation-specific awaits inside”. So 
it’s more consistent with “async def foo()”.


This.  I also think of 'await with' as I'm awaiting on the whole 
statement.  And I don't even know how to interpret that.



6. StopAsyncException

I'm not sure about this. The motivation given in the PEP seems to focus on the 
need for `__anext__` to be async. But is this really the right pattern? What if 
we required `ait.__anext__()` to return a future, which can either raise good 
old `StopIteration` or return the next value from the iteration when awaited? 
I'm wondering if there are a few alternatives to be explored around the async 
iterator protocol still.

So are you suggesting to pass the returned value in a future? In this case the 
future would need to be passed to __anext__, so the Cursor example from the PEP 
would look like this:

class Cursor:
 def __init__(self):
 self.buffer = collections.deque()

 def _prefetch(self):
 ...

 async def __aiter__(self):
 return self

 async def __anext__(self, fut):
 if not self.buffer:
 self.buffer = await self._prefetch()
 if self.buffer:
 fut.set_result(self.buffer.popleft())
 else:
 fut.set_exception(StopIteration)

While this is elegant, my concern is that one-future-per-iteration-step might 
be bad for performance.

Maybe consider the following. The `async def` syntax decouples the concept of a 
coroutine from the implementation. While it’s still based on generators under 
the hood, the user no longer considers his “async function” to be a generator 
or conforming to the generator protocol. From the user’s perpective, it’s 
obvious that the return below means something different than the exception:

 async def __anext__(self):
 if not self.buffer:
 self.buffer = await self._prefetch()
 if not self.buffer:
 raise StopIteration
 return self.buffer.popleft()

So, the same way we added wrapping in RuntimeErrors for generators in PEP 479, 
we might add transparent wrapping in a _StopAsyncIteration for CO_COROUTINE.


FWIW I have to experiment more with the reference implementation,
but at the moment I'm big -1 on touching StopIteration for
coroutines.  It's used for too many things.


Thanks!

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-25 Thread Yury Selivanov

Hi Guido,

On 2015-04-24 1:03 PM, Guido van Rossum wrote:

*3. syntactic priority of `await`*

Yury, could you tweak the syntax for `await` so that we can write the most
common usages without parentheses? In particular I'd like to be able to
write
```
return await foo()
with await foo() as bar: ...
foo(await bar(), await bletch())
```
(I don't care about `await foo() + await bar()` but it would be okay.)
```
I think this is reasonable with some tweaks of the grammar (similar to what
Greg did for cocall, but without requiring call syntax at the end).


I've done some experiments with grammar, and it looks like
we indeed can parse await quite differently from yield. Three
different options:


Option #1. Parse 'await' exactly like we parse 'yield'.
This how we parse 'await' in the latest version of reference
implementation.

Required grammar changes:
https://gist.github.com/1st1/cb0bd257b04adb87e167#file-option-1-patch

Repo to play with:
https://github.com/1st1/cpython/tree/await

Syntax:

  await a()
  res = (await a()) + (await b())
  res = (await (await a()))
  if (await a()): pass
  return (await a())
  print((await a()))
  func(arg=(await a()))
  await a() * b()


Option #2. Keep 'await_expr' in 'atom' terminal, but don't
require parentheses.

Required grammar changes:
https://gist.github.com/1st1/cb0bd257b04adb87e167#file-option-2-patch

Repo to play with (parser module is broken atm):
https://github.com/1st1/cpython/tree/await_noparens

Syntax:

  await a()
  res = (await a()) + await b() # w/o parens (a() + await b())
  res = await await a()
  if await a(): pass
  return await a()
  print(await a())
  func(arg=await a())
  await a() * b()


Option #3. Create a new terminal for await expression between
'atom' and 'power'.

Required grammar changes:
https://gist.github.com/1st1/cb0bd257b04adb87e167#file-option-3-patch

Repo to play with (parser module is broken atm):
https://github.com/1st1/cpython/tree/await_noparens2

Syntax:

  await a()
  res = await a() + await b()
  res = await (await a()) # invalid syntax w/o parens
  if await a(): pass
  return await a()
  print(await a())
  func(arg=await a())
  await (a() * b()) # w/o parens '(await a() * b())


I think that Option #3 is a clear winner.

Thanks,
Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] async/await in Python; v2

2015-04-25 Thread Yury Selivanov

Hi Arnaud,

On 2015-04-25 4:47 PM, Arnaud Delobelle wrote:

On Tue, 21 Apr 2015 at 18:27 Yury Selivanov  wrote:

Hi python-dev,

I'm moving the discussion from python-ideas to here.

The updated version of the PEP should be available shortly
at https://www.python.org/dev/peps/pep-0492
and is also pasted in this email.


Hi Yury,

Having read this very interesting PEP I would like to make two
remarks.  I apologise in advance if they are points which have already
been discussed.

1.  About the 'async for' construct.  Each iteration will create a new
coroutine object (the one returned by Cursor.__anext__()) and it seems
to me that it can be wasteful.  In the example given of an 'aiterable'
Cursor class, probably a large number of rows will fill the cursor
buffer in one call of cursor._prefetch().  However each row that is
iterated over will involve the creation execution of a new coroutine
object.  It seems to me that what is desirable in that case is that
all the buffered rows will be iterated over as in a plain for loop.


I agree that creating a new coroutine object is a little bit
wasteful.

However, the proposed iteration protocol was designed to:

1. Resemble already existing __iter__/__next__/StopIteration
protocol;

2. Pave the road to introduce coroutine-generators in the
future.

We could, in theory, design the protocol to make __anext__
awaitable return a regular iterators (and raise
StopAsyncIteration at the end) to make things more
efficient, but that would complicate the protocol
tremendously, and make it very hard to program and debug.

My opinion is that this has to be addressed in 3.6 with
coroutine-generators if there is enough interest from
Python users.



2.  I think the semantics of the new coroutine objects could be
defined more clearly in the PEP.  Of course they are pretty obvious
when you know that the coroutines are meant to replace
asyncio.coroutine as described in [1].  I understand that this PEP is
mostly for the benefit of asyncio, hence mainly of interest of people
who know it.  However I think it would be good for it to be more
self-contained.  I have often read a PEP as an introduction to a new
feature of Python.  I feel that if I was not familiar with yield from
and asyncio I would not be able to understand this PEP, even though
potentially one could use the new constructs without knowing anything
about them.





I agree. I plan to update the PEP with some new
semantics (prohibit passing coroutine-objects to iter(),
tuple() and other builtins, as well as using them in
'for .. in coro()' loops).  I'll add a section with
a more detailed explanation of coroutine-objects.

Best,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: No new syntax is required

2015-04-26 Thread Yury Selivanov

Hi Mark,

On 2015-04-26 4:21 PM, Mark Shannon wrote:

Hi,

I was looking at PEP 492 and it seems to me that no new syntax is 
required.


Mark, all your points are explained in the PEP in a great detail:



Looking at the code, it does four things; all of which, or a 
functional equivalent, could be done with no new syntax.


Yes, everything that the PEP proposes can be done without new syntax.  
That's how people use asyncio right now, with only what we have in 3.4.


But it's hard.  Iterating through something asynchronously?  Write a 
'while True' loop.  Instead of 1 line you now have 5 or 6.  Want to 
commit your database transaction?  Instead of 'async with' you will 
write 'try..except..finally' block, with a very high probability to 
introduce a bug, because you don't rollback or commit properly or 
propagate exception.


1. Make a normal function into a generator or coroutine. This can be 
done with a decorator.


https://www.python.org/dev/peps/pep-0492/#rationale-and-goals
https://www.python.org/dev/peps/pep-0492/#debugging-features
https://www.python.org/dev/peps/pep-0492/#importance-of-async-keyword

2. Support a parallel set of special methods starting with 'a' or 
'async'. Why not just use the current set of special methods?


Because you can't reuse them.

https://www.python.org/dev/peps/pep-0492/#why-not-reuse-existing-for-and-with-statements
https://www.python.org/dev/peps/pep-0492/#why-not-reuse-existing-magic-names

3. "await". "await" is an operator that takes one argument and 
produces a single result, without altering flow control and can thus 
be replaced by an function.


It can't be replaced by a function. Only if you use greenlets or 
Stackless Python.


4. Asynchronous with statement. The PEP lists the equivalent as "with 
(yield from xxx)" which doesn't seem so bad.


There is no equivalent to 'async with'. "with (yield from xxx)" only 
allows you to suspend execution
in __enter__ (and it's not actually in __enter__, but in a coroutine 
that returns a context manager).


https://www.python.org/dev/peps/pep-0492/#asynchronous-context-managers-and-async-with 
see "New Syntax" section to see what 'async with' is equivalent too.




Please don't add unnecessary new syntax.



It is necessary.  Perhaps you haven't spent a lot of time maintaining 
huge code-bases developed with frameworks like asyncio, so I understand 
why it does look unnecessary to you.


Thanks,
Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: No new syntax is required

2015-04-26 Thread Yury Selivanov



On 2015-04-26 5:48 PM, Mark Shannon wrote:



On 26/04/15 21:40, Yury Selivanov wrote:

Hi Mark,

On 2015-04-26 4:21 PM, Mark Shannon wrote:

Hi,

I was looking at PEP 492 and it seems to me that no new syntax is
required.


Mark, all your points are explained in the PEP in a great detail:
I did read the PEP. I do think that clarifying the distinction between 
coroutines and 'normal' generators is a good idea. Adding stuff to the 
standard library to help is fine. I just don't think that any new 
syntax is necessary.


Well, unfortunately, I can't explain why the new syntax is necessary 
better than it is already explained in the PEP, sorry.








Looking at the code, it does four things; all of which, or a
functional equivalent, could be done with no new syntax.


Yes, everything that the PEP proposes can be done without new syntax.
That's how people use asyncio right now, with only what we have in 3.4.

But it's hard.  Iterating through something asynchronously? Write a
'while True' loop.  Instead of 1 line you now have 5 or 6.  Want to
commit your database transaction?  Instead of 'async with' you will
write 'try..except..finally' block, with a very high probability to
introduce a bug, because you don't rollback or commit properly or
propagate exception.

I don't see why you can't do transactions using a 'with' statement.


Because you can't use 'yield from' in __exit__. And allowing it there 
isn't a very good idea.





1. Make a normal function into a generator or coroutine. This can be
done with a decorator.


https://www.python.org/dev/peps/pep-0492/#rationale-and-goals

states that """
it is not possible to natively define a coroutine which has no yield 
or yield from statement

"""
which is just not true.


It *is* true.  Please note the word "natively".

See coroutine decorator from asyncio:
https://github.com/python/cpython/blob/master/Lib/asyncio/coroutines.py#L130

To turn a regular function into a coroutine you have three options:

1. wrap the function;

2. use "if 0: yield" terrible hack;

3. flip CO_GENERATOR flag for the code object (which is CPython 
implementation detail); also terrible hack.


@coroutine decorator is great because we can use asyncio even in 3.3. 
But it's


a) easy to forget

b) hard to statically analyze

c) hard to explain why functions decorated with it must only contain 
'yield from' instead of 'yield'


d) few more reasons listed in the PEP




https://www.python.org/dev/peps/pep-0492/#debugging-features

Requires the addition of the CO_COROUTINE flag, not any new keywords.


True.  But the importance of new keywords is covered in other sections.



https://www.python.org/dev/peps/pep-0492/#importance-of-async-keyword

Seems to be repeating the above.



2. Support a parallel set of special methods starting with 'a' or
'async'. Why not just use the current set of special methods?


Because you can't reuse them.

https://www.python.org/dev/peps/pep-0492/#why-not-reuse-existing-for-and-with-statements 

Which seems back to front. The argument is that existing syntax 
constructs cannot be made to work with asynchronous objects. Why not 
make the asynchronous objects work with the existing syntax?


Because a) it's not possible; b) the point is to make suspend points 
visible in the code. That's one of the key principles of asyncio and 
other frameworks.






https://www.python.org/dev/peps/pep-0492/#why-not-reuse-existing-magic-names 


The argument here relies on the validity of the previous points.




3. "await". "await" is an operator that takes one argument and
produces a single result, without altering flow control and can thus
be replaced by an function.


It can't be replaced by a function. Only if you use greenlets or
Stackless Python.

Why not? The implementation of await is here:
https://github.com/python/cpython/compare/master...1st1:await#diff-23c87bfada1d01335a3019b9321502a0R642 


which clearly could be made into a function.


Implementation of 'await' requires YIELD_FROM opcode. As far as I know 
functions in Python can't push opcodes to the eval loop while running.  
The only way to do what you propose is to use greenlets or merge 
stackless into cpython.





4. Asynchronous with statement. The PEP lists the equivalent as "with
(yield from xxx)" which doesn't seem so bad.


There is no equivalent to 'async with'. "with (yield from xxx)" only
allows you to suspend execution
in __enter__ (and it's not actually in __enter__, but in a coroutine
that returns a context manager).

https://www.python.org/dev/peps/pep-0492/#asynchronous-context-managers-and-async-with 


see "New Syntax" section to see what 'async with' is equivalent to

Re: [Python-Dev] PEP 492: No new syntax is required

2015-04-26 Thread Yury Selivanov

Brett,

On 2015-04-26 6:09 PM, Brett Cannon wrote:

  How is it a burden for people porting Python 2 code? Because they won't
get to name anything 'async' just like anyone supporting older Python 3
versions? Otherwise I don't see how it is of any consequence to people
maintaining 2/3 code as it will just be another thing they can't use until
they drop Python 2 support.


Agree.  Also, the PEP states that we'll either keep a modified
tokenizer or use __future__ imports till at least 3.7.  It's
*3 or more years*.  And if necessary, we can wait till 3.8
(python 2 won't be supported at that point).

Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: No new syntax is required

2015-04-26 Thread Yury Selivanov

Paul,

On 2015-04-26 6:25 PM, Paul Sokolovsky wrote:

Ok, so here're 3 points this link gives, with my concerns/questions:


>An alternative idea about new asynchronous iterators and context
>managers was to reuse existing magic methods, by adding an async
>keyword to their declarations:
>[But:]
>  - it would not be possible to create an object that works in both
>with and async with statements;

Yes, and I would say, for good. Behavior of sync and async code is
different enough to warrant separate classes (if not libraries!) to
implement each paradigm. What if, in otherwise async code, someone will
miss "async" in "async with" and call sync version of context manager?
So, losing ability stated above isn't big practical loss.


That's debatable.  It might be useful to create hybrid
objects that can work in 'with (yield from lock)' and
'async with lock' statements.





>- it would look confusing

Sorry, "async def __enter__" doesn't look more confusing than
"__aenter__" (vs "__enter__").


I'll update the PEP.

The argument shouldn't be that it's confusing, the argument
is that __aenter__ returns an 'awaitable', which is either
a coroutine-object or a future.

You can't reuse __enter__, because you'd break backwards
compatibility -- it's perfectly normal for context
managers in python to return any object from their __enter__.
If we assign some special meaning to futures -- we'll break
existing code.




>and would require some implicit magic behind the scenes in the
>interpreter;

Interpreter already does a lot of "implicit magic". Can you please
elaborate what exactly would need to be done?


Async with implies using YIELD_FROM opcodes. If you want
to make regular with statements compatible you'd need to
add a lot of opcodes that will at runtime make a decision
whether to use YIELD_FROM or not.

The other point is that you can't just randomly start using
YIELD_FROM, you can only do so from generators/coroutines.




>one of the main points of this proposal is to make coroutines as
>simple and foolproof as possible.

And it's possible to agree that "to separate notions, create a
dichotomy" is a simple principle on its own. But just taking bunch of
stuff - special methods, exceptions - and duplicating it is a bloat a
violates another principle - DRY.

I'd say that a lot of terrible mistakes has happened in
software development precisely because someone followed
DRY religiously.  Following it here will break backwards
compatibility and/or make it harder to understand what
is actually going on with your code.


You argue that this will make
coroutine writing simple. But coroutines are part of the language, and
duplicating notions makes language more complex/complicated.

Again, it makes reasoning about your code simpler.
That what matters.

Anyways, I really doubt that you can convince anyone to
reuse existing dunder methods for async stuff.


Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: No new syntax is required

2015-04-26 Thread Yury Selivanov

Paul,

On 2015-04-26 7:32 PM, Paul Sokolovsky wrote:

Hello,

On Sun, 26 Apr 2015 18:49:43 -0400
Yury Selivanov  wrote:

[]


- it would look confusing

Sorry, "async def __enter__" doesn't look more confusing than
"__aenter__" (vs "__enter__").

I'll update the PEP.

The argument shouldn't be that it's confusing, the argument
is that __aenter__ returns an 'awaitable', which is either
a coroutine-object or a future.

You can't reuse __enter__, because you'd break backwards
compatibility -- it's perfectly normal for context
managers in python to return any object from their __enter__.
If we assign some special meaning to futures -- we'll break
existing code.

So, again to make sure I (and hopefully other folks) understand it
right. You say "it's perfectly normal for context managers in python to
return any object from their __enter__". That's true, but we talk about
async context managers. There're no such at all, they yet need to be
written. And whoever writes them, would need to return from __enter__
awaitable, because that's the requirement for an async context manager,
and it is error to return something else.

Then, is the only logic for proposing __aenter__ is to reinsure against
a situation that someone starts to write async context manager, forgets
that they write async context manager, and make an __enter__ method
there.


It's to make sure that it's impossible to accidentally use
existing regular context manager that returns a future object
from its __enter__ / __exit__ (nobody prohibits you to return a
future object from __exit__, although it's pointless) in an
'async with' block.

I really don't understand the desire to reuse existing magic
methods.  Even if it was decided to reuse them, it wouldn't
even simplify the implementation in CPython; the code there
is already DRY (I don't re-implement opcodes for 'with'
statement; I reuse them).


Then your implementation will announce that "async context
manager lacks __aenter__", whereas "my" approach would announce
"Async's manager __enter__ did not return awaitable value".

Again, is that the distinction you're shooting for, or do I miss
something?

[]


Anyways, I really doubt that you can convince anyone to
reuse existing dunder methods for async stuff.

Yeah, but it would be nice to understand why "everyone" and "so easily"
agrees to them, after pretty thorough discussion of other aspects.


NP :)  FWIW, I wasn't trying to dodge the question, but
rather stressing that the DRY argument is weak.

And thanks for pointing out that this isn't covered
in the PEP in enough detail. I'll update the PEP soon.

Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: No new syntax is required

2015-04-26 Thread Yury Selivanov

Paul,

On 2015-04-26 8:17 PM, Paul Sokolovsky wrote:

Hello,

On Sun, 26 Apr 2015 19:45:30 -0400
Yury Selivanov  wrote:

[]


Then, is the only logic for proposing __aenter__ is to reinsure
against a situation that someone starts to write async context
manager, forgets that they write async context manager, and make an
__enter__ method there.

It's to make sure that it's impossible to accidentally use
existing regular context manager that returns a future object
from its __enter__ / __exit__ (nobody prohibits you to return a
future object from __exit__, although it's pointless) in an
'async with' block.

I see, so it's just to close the final loophole, unlikely to be hit in
real life (unless you can say that there're cases of doing just that in
existing asyncio libs). Well, given that Greg Ewing wanted even
stricter error-proofness, and you rejected it as such strict as to
disallow useful behavior, I've just got to trust you that in this
case, you're as strict as needed.


Well, backwards compatibility is something that better
be preserved.  Especially with things like context
managers.  Things with __aiter__/__iter__ are also
different.  It's easier for everyone to just clearly
separate the protocols to avoid all kind of risks.




I really don't understand the desire to reuse existing magic
methods.  Even if it was decided to reuse them, it wouldn't
even simplify the implementation in CPython; the code there
is already DRY (I don't re-implement opcodes for 'with'
statement; I reuse them).

Well, there're 3 levels of this stuff:

1. How "mere" people write their code - everyone would use async def and
await, this should be bullet- (and fool-) proof.
2. How "library" code is written - async iterators won't be written by
everyone, and only few will write async context managers; it's fair to
expect that people doing these know what they do and don't do stupid
mistakes.
3. How it all is coded in particular Python implementation.

It's clear that __enter__ vs __aenter__ distinction is 1st kind of
issue in your list.


It is.



As for 3rd point, I'd like to remind that CPython is only one Python
implementation. And with my MicroPython hat on, I'd like to know if
(some of) these new features are "bloat" or "worthy" for the space
constraints we have.


OT: MicroPython is an amazing project. Kudos for doing it.

I really hope that addition of few new magic methods won't
make it too hard for you guys to implement PEP 492 in
MicroPython one day.


Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-27 Thread Yury Selivanov

Hi Greg,

I don't want this: "await a() * b()" to be parsed, it's not meaningful.

Likely you'll see "await await a()" only once in your life, so I'm fine 
to use parens for it (moreover, I think it reads better with parens)


Yury


On 2015-04-27 8:52 AM, Greg Ewing wrote:

Yury Selivanov wrote:

I've done some experiments with grammar, and it looks like
we indeed can parse await quite differently from yield. Three
different options:


You don't seem to have tried what I suggested, which is
to make 'await' a unary operator with the same precedence
as '-', i.e. replace

   factor: ('+'|'-'|'~') factor | power

with

   factor: ('+'|'-'|'~'|'await') factor | power

That would allow

  await a()
  res = await a() + await b()
  res = await await a()
  if await a(): pass
  return await a()
  print(await a())
  func(arg=await a())
  await a() * b()



___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] PEP 492: async/await in Python; v3

2015-04-27 Thread Yury Selivanov

Hi python-dev,

Another round of updates.  Reference implementation
has been updated: https://github.com/1st1/cpython/tree/await
(includes all things from the below summary of updates +
tests).


Summary:


1. "PyTypeObject.tp_await" slot.  Replaces "tp_reserved".
This is to enable implementation of Futures with C API.
Must return an iterator if implemented.


2. New grammar for "await" expressions, see
'Syntax of "await" expression' section


3. inspect.iscoroutine() and inspect.iscoroutineobjects()
functions.


4. Full separation of coroutines and generators.
This is a big one; let's discuss.

a) Coroutine objects raise TypeError (is NotImplementedError
better?) in their __iter__ and __next__.  Therefore it's
not not possible to pass them to iter(), tuple(), next() and
other similar functions that work with iterables.

b) Because of (a), for..in iteration also does not work
on coroutines anymore.

c) 'yield from' only accept coroutine objects from
generators decorated with 'types.coroutine'. That means
that existing asyncio generator-based coroutines will
happily yield from both coroutines and generators.
*But* every generator-based coroutine *must* be
decorated with `asyncio.coroutine()`.  This is
potentially a backwards incompatible change.

d) inspect.isgenerator() and inspect.isgeneratorfunction()
return `False` for coroutine objects & coroutine functions.

e) Should we add a coroutine ABC (for cython etc)?

I, personally, think this is highly necessary. First,
separation of coroutines from generators is extremely
important. One day there won't be generator-based
coroutines, and we want to avoid any kind of confusion.
Second, we only can do this in 3.5.  This kind of
semantics change won't be ever possible.

asyncio recommends using @coroutine decorator, and most
projects that I've seen do use it.  Also there is no
reason for people to use iter() and next() functions
on coroutines when writing asyncio code. I doubt that
this will cause serious backwards compatibility problems
(asyncio also has provisional status).


Thank you,
Yury


PEP: 492
Title: Coroutines with async and await syntax
Version: $Revision$
Last-Modified: $Date$
Author: Yury Selivanov 
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 09-Apr-2015
Python-Version: 3.5
Post-History: 17-Apr-2015, 21-Apr-2015, 27-Apr-2015


Abstract


This PEP introduces new syntax for coroutines, asynchronous ``with``
statements and ``for`` loops.  The main motivation behind this proposal
is to streamline writing and maintaining asynchronous code, as well as
to simplify previously hard to implement code patterns.


Rationale and Goals
===

Current Python supports implementing coroutines via generators (PEP
342), further enhanced by the ``yield from`` syntax introduced in PEP
380. This approach has a number of shortcomings:

* it is easy to confuse coroutines with regular generators, since they
  share the same syntax; async libraries often attempt to alleviate
  this by using decorators (e.g. ``@asyncio.coroutine`` [1]_);

* it is not possible to natively define a coroutine which has no
  ``yield`` or  ``yield from`` statements, again requiring the use of
  decorators to fix potential refactoring issues;

* support for asynchronous calls is limited to expressions where
  ``yield`` is allowed syntactically, limiting the usefulness of
  syntactic features, such as ``with`` and ``for`` statements.

This proposal makes coroutines a native Python language feature, and
clearly separates them from generators.  This removes
generator/coroutine ambiguity, and makes it possible to reliably define
coroutines without reliance on a specific library.  This also enables
linters and IDEs to improve static code analysis and refactoring.

Native coroutines and the associated new syntax features make it
possible to define context manager and iteration protocols in
asynchronous terms. As shown later in this proposal, the new ``async
with`` statement lets Python programs perform asynchronous calls when
entering and exiting a runtime context, and the new ``async for``
statement makes it possible to perform asynchronous calls in iterators.


Specification
=

This proposal introduces new syntax and semantics to enhance coroutine
support in Python, it does not change the internal implementation of
coroutines, which are still based on generators.

It is strongly suggested that the reader understands how coroutines are
implemented in Python (PEP 342 and PEP 380).  It is also recommended to
read PEP 3156 (asyncio framework) and PEP 3152 (Cofunctions).

From this point in this document we use the word *coroutine* to refer
to functions declared using the new syntax.  *generator-based
coroutine* is used where necessary to refer to coroutines that are
based on generator syntax.


New Coroutine Declaration Syntax
-

Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-28 Thread Yury Selivanov

Hi Walter,

On 2015-04-28 10:23 AM, Walter Dörwald wrote:

Key properties of coroutines:

* ``async def`` functions are always coroutines, even if they do not
contain ``await`` expressions.

* It is a ``SyntaxError`` to have ``yield`` or ``yield from``
expressions in an ``async`` function.


Does this mean it's not possible to implement an async version of 
os.walk() if we had an async version of os.listdir()?


I.e. for async code we're back to implementing iterators "by hand" 
instead of using generators for it. 



For now yes.  Unfortunately, we don't have time to implement 
coroutine-generators properly in 3.5.


Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-28 Thread Yury Selivanov

Hi Stefan,

On 2015-04-28 1:43 AM, Stefan Behnel wrote:

Should a Generator then inherit from both Iterator and Coroutine, or would
that counter your intention to separate coroutines from generators as a
concept? I mean, they do share the same interface ...


Them sharing the same interface depends on how the discussion goes :)  
But all in all, I think that it should be totally separate classes, even 
if they share some methods.


Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-28 Thread Yury Selivanov

Ethan,

On 2015-04-28 11:29 AM, Ethan Furman wrote:

On 04/28, Yury Selivanov wrote:

On 2015-04-28 1:43 AM, Stefan Behnel wrote:

Should a Generator then inherit from both Iterator and Coroutine, or would
that counter your intention to separate coroutines from generators as a
concept? I mean, they do share the same interface ...

Them sharing the same interface depends on how the discussion goes
:)  But all in all, I think that it should be totally separate
classes, even if they share some methods.

For those of us who like to meddle, would it be possible to create an object
that supports __iter__, __next__, __aiter__, and __anext__?



Sure, there is nothing that could prevent you from doing that.

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Issues with PEP 482 (1)

2015-04-28 Thread Yury Selivanov

Mark,

I'm sorry but you have to view the proposal as a whole. Discussing it 
point by point in isolation doesn't make any sense, as with any complex 
subject.


Thanks,
Yury

On 2015-04-28 2:44 PM, Mark Shannon wrote:

Hi,

I still think that there are several issues that need addressing with 
PEP 492. This time, one issue at a time :)


"async"

The "Rationale and Goals" of PEP 492 states that PEP 380 has 3 
shortcomings.

The second of which is:
"""It is not possible to natively define a coroutine which has no 
yield or yield from statements."""

   This is incorrect, although what is meant by 'natively' is unclear.

A coroutine without a yield statement can be defined simply and 
concisely, thus:


@coroutine
def f():
return 1

This is only a few character longer than the proposed new syntax,
perfectly explicit and requires no modification the language whatsoever.
A pure-python definition of the "coroutine" decorator is given below.

So could the "Rationale and Goals" be correctly accordingly, please.
Also, either the "async def" syntax should be dropped, or a new 
justification is required.


Cheers,
Mark.


#coroutine.py

from types import FunctionType, CodeType

CO_COROUTINE = 0x0080
CO_GENERATOR = 0x0020

def coroutine(f):
'Converts a function to a generator function'
old_code = f.__code__
new_code = CodeType(
old_code.co_argcount,
old_code.co_kwonlyargcount,
old_code.co_nlocals,
old_code.co_stacksize,
old_code.co_flags | CO_GENERATOR | CO_COROUTINE,
old_code.co_code,
old_code.co_consts,
old_code.co_names,
old_code.co_varnames,
old_code.co_filename,
old_code.co_name,
old_code.co_firstlineno,
old_code.co_lnotab,
old_code.co_freevars,
old_code.co_cellvars)
return FunctionType(new_code, f.__globals__)


P.S. The reverse of this decorator, which unsets the flags, converts a 
generator function into a normal function. :?

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/yselivanov.ml%40gmail.com


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-28 Thread Yury Selivanov

Hi Guido,

Thank you for a very detailed review.  Comments below:

On 2015-04-28 5:49 PM, Guido van Rossum wrote:

Inline comments below...

On Mon, Apr 27, 2015 at 8:07 PM, Yury Selivanov 
wrote:


Hi python-dev,

Another round of updates.  Reference implementation
has been updated: https://github.com/1st1/cpython/tree/await
(includes all things from the below summary of updates +
tests).


Summary:


1. "PyTypeObject.tp_await" slot.  Replaces "tp_reserved".
This is to enable implementation of Futures with C API.
Must return an iterator if implemented.

That's fine (though I didn't follow this closely).


My main question here is it OK to reuse 'tp_reserved'
(former tp_compare)?

I had to remove this check:
https://github.com/1st1/cpython/commit/4be6d0a77688b63b917ad88f09d446ac3b7e2ce9#diff-c3cf251f16d5a03a9e7d4639f2d6f998L4906

On the other hand I think that it's a slightly better
solution than adding a new slot.



2. New grammar for "await" expressions, see
'Syntax of "await" expression' section

I like it.


Great!

The current grammar requires parentheses for consequent
await expressions:

   await (await coro())

I can change this (in theory), but I kind of like the parens
in this case -- better readability.  And it'll be a very
rare case.



3. inspect.iscoroutine() and inspect.iscoroutineobjects()
functions.

What's the use case for these? I wonder if it makes more sense to have a

check for a generalized awaitable rather than specifically a coroutine.


It's important to at least have 'iscoroutine' -- to check that
the object is a coroutine function.  A typical use-case would be
a web framework that lets you to bind coroutines to specific
http methods/paths:

@http.get('/spam')
async def handle_spam(request):
...

'http.get' decorator will need a way to raise an error if it's
applied to a regular function (while the code is being imported,
not in runtime).


The idea here is to cover all kinds of python objects in
inspect module, it's Python's reflection API.

The other thing is that it's easy to implement this function
for CPython: just check for CO_COROUTINE flag. For other
Python implementations it might be a different story.


(More arguments for isawaitable() below)





4. Full separation of coroutines and generators.
This is a big one; let's discuss.

a) Coroutine objects raise TypeError (is NotImplementedError
better?) in their __iter__ and __next__.  Therefore it's
not not possible to pass them to iter(), tuple(), next() and
other similar functions that work with iterables.

I think it should be TypeError -- what you *really* want is not to define

these methods at all but given the implementation tactic for coroutines
that may not be possible, so the nearest approximation is TypeError. (Also,
NotImplementedError is typically to indicate that a subclass should
implement it.)



Agree.


b) Because of (a), for..in iteration also does not work
on coroutines anymore.

Sounds good.



c) 'yield from' only accept coroutine objects from
generators decorated with 'types.coroutine'. That means
that existing asyncio generator-based coroutines will
happily yield from both coroutines and generators.
*But* every generator-based coroutine *must* be
decorated with `asyncio.coroutine()`.  This is
potentially a backwards incompatible change.

See below. I worry about backward compatibility. A lot. Are you saying

that asycio-based code that doesn't use @coroutine will break in 3.5?


I'll experiment with replacing (c) with a warning.

We can disable __iter__ and __next__ for coroutines, but
allow to use 'yield from' on them.  Would it be a better
approach?





d) inspect.isgenerator() and inspect.isgeneratorfunction()
return `False` for coroutine objects & coroutine functions.

Makes sense.


(d) can also break something (hypothetically).  I'm not
sure why would someone use isgenerator() and
isgeneratorfunction() on generator-based coroutines in
code based on asyncio, but there is a chance that
someone did (it should be trivial to fix the code).

Same for iter() and next().  The chance is slim, but we
may break some obscure code.

Are you OK with this?





e) Should we add a coroutine ABC (for cython etc)?

I, personally, think this is highly necessary. First,
separation of coroutines from generators is extremely
important. One day there won't be generator-based
coroutines, and we want to avoid any kind of confusion.
Second, we only can do this in 3.5.  This kind of
semantics change won't be ever possible.


Sounds like Stefan agrees. Are you aware of
http://bugs.python.org/issue24018 (Generator ABC)?


Yes, I saw the issue.  I'll review it in more detail
before thinking about Coroutine ABC for the next PEP
update.





asyncio recommends using @coroutine decorator, an

Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-28 Thread Yury Selivanov

Looking at the grammar -- the only downside of the current approach is that
you can't do 'await await fut'.  I still think that it reads better with
parens.  If we put 'await' to 'factor' terminal we would allow

await -fut  # await (-fut)

I think I something like

power: atom_expr ['**' factor]
atom_expr: [AWAIT] atom_expr | atom_trailer
atom_trailer: atom trailer*

will fix 'await await' situation, but does it really need to be fixed?

Yury



On 2015-04-27 9:44 AM, Yury Selivanov wrote:

Hi Greg,

I don't want this: "await a() * b()" to be parsed, it's not meaningful.

Likely you'll see "await await a()" only once in your life, so I'm 
fine to use parens for it (moreover, I think it reads better with parens)


Yury


On 2015-04-27 8:52 AM, Greg Ewing wrote:

Yury Selivanov wrote:

I've done some experiments with grammar, and it looks like
we indeed can parse await quite differently from yield. Three
different options:


You don't seem to have tried what I suggested, which is
to make 'await' a unary operator with the same precedence
as '-', i.e. replace

   factor: ('+'|'-'|'~') factor | power

with

   factor: ('+'|'-'|'~'|'await') factor | power

That would allow

  await a()
  res = await a() + await b()
  res = await await a()
  if await a(): pass
  return await a()
  print(await a())
  func(arg=await a())
  await a() * b()





___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-28 Thread Yury Selivanov

Hi Stephen,

Thanks a lot for the feedback and suggestions. I'll apply them
to the PEP.

On 2015-04-28 11:03 PM, Stephen J. Turnbull wrote:

Literary critic here.

In section "Specification"

  > It is strongly suggested that the reader understands how coroutines
  > are implemented in Python (PEP 342 and PEP 380).  It is also
  > recommended to read PEP 3156 (asyncio framework) and PEP 3152
  > (Cofunctions).

The usual phrasing of "strongly suggested" in specifications is
"presumes knowledge".  Some people think "strongly suggest ing" is
presumptuous and condescending, YMMV.  Also, the relationship to PEP
3152 should be mentioned IMO.  I propose:

 This specification presumes knowledge of the implementation of
 coroutines in Python (PEP 342 and PEP 380).  Motivation for the
 syntax changes proposed here comes from the asyncio framework (PEP
 3156) and the "Cofunctions" proposal (PEP 3152, now rejected in
 favor of this specification).


Your wording is 100% better and it's time to mention PEP 3152
too.



I'm not entirely happy with my phrasing, because there are at least
four more or less different concepts that might claim the bare word
"coroutine":

- this specification
- the implementation of this specification
- the syntax used to define coroutines via PEPs 342 and 380
- the semantics of PEP 342/380 coroutines

In both your original and my rephrasing, the use of "coroutine"
violates your convention that it refers to the PEP's proposed syntax
for coroutines.  Instead it refers to the semantics of coroutines
implemented via PEP 342/380.  This is probably the same concern that
motivated Guido's suggestion to use "native coroutines" for the PEP
492 syntax (but I'm not Dutch, so maybe they're not the same :-).

I feel this is a real hindrance to understanding for someone coming to
the PEP for the first time.  You know which meaning of coroutine you
mean, but the new reader needs to think hard enough to disambiguate
every time the word occurs.  If people agree with me, I could go
through the PEP and revise mentions of "coroutine" in "disambiguated"
style.


I also like Guido's suggestion to use "native coroutine" term.
I'll update the PEP (I have several branches of it in the repo
that I need to merge before the rename).



In section "Comprehensions":

  > For the sake of restricting the broadness of this PEP there is no
  > new syntax for asynchronous comprehensions.  This should be
  > considered in a separate PEP, if there is a strong demand for this
  > feature.

Don't invite trouble.  How about:

 Syntax for asynchronous comprehensions could be provided, but this
 construct is outside of the scope of this PEP.

In section "Async lambdas"

  > Lambda coroutines are not part of this proposal.  In this proposal they
  > would look like ``async lambda(parameters): expression``.  Unless there
  > is a strong demand to have them as part of this proposal, it is
  > recommended to consider them later in a separate PEP.

Same recommendation as for "Comprehensions".  I wouldn't mention the
tentative syntax, it is both obvious and inviting to trouble.


Agree. Do you think it'd be better to combine comprehensions
and async lambdas in one section?




  > Acknowledgments
  > ===
  >
  > I thank Guido van Rossum, Victor Stinner, Elvis Pranskevichus, Andrew
  > Svetlov, and Łukasz Langa for their initial feedback.

A partial list of commentators I've found to be notable, YMMV:


Sure!  I was going to add everybody after the PEP is
accepted/rejected/postponed.



Greg Ewing for PEP 3152 and his Loyal Opposition to this PEP.
Mark Shannon's comments have led to substantial clarifications of
 motivation for syntax, at least in my mind.
Paul Sokolovsky for information about the MicroPython implementation.



Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-28 Thread Yury Selivanov



On 2015-04-28 11:59 PM, Greg wrote:

On 29/04/2015 9:49 a.m., Guido van Rossum wrote:

c) 'yield from' only accept coroutine objects from
generators decorated with 'types.coroutine'. That means
that existing asyncio generator-based coroutines will
happily yield from both coroutines and generators.
*But* every generator-based coroutine *must* be
decorated with `asyncio.coroutine()`.  This is
potentially a backwards incompatible change.

See below. I worry about backward compatibility. A lot. Are you saying
that asycio-based code that doesn't use @coroutine will break in 3.5?


That seems unavoidable if the goal is for 'await' to only
work on generators that are intended to implement coroutines,
and not on generators that are intended to implement
iterators. Because there's no way to tell them apart
without marking them in some way.



Not sure what you mean by "unavoidable".

Before the last revision of the PEP it was perfectly fine
to use generators in 'yield from' in generator-based coroutines:

   @asyncio.coroutine
   def foo():
  yield from gen()

and yet you couldn't do the same with 'await' (as it has
a special opcode instead of GET_ITER that can validate
what you're awaiting).

With the new version of the PEP - 'yield from' in foo()
would raise a TypeError.  If we change it to a RuntimeWarning
then we're safe in terms of backwards compatibility. I just
want to see how exactly warnings will work (i.e. will they
occur multiple times at the same 'yield from' expression, etc)

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-28 Thread Yury Selivanov

Guido,

I found a solution how to disable 'yield from',
iter()/tuple() and 'for..in' on native coroutines
with 100% backwards compatibility.

The idea is to add one more code object flag:
CO_NATIVE_COROUTINE, which will be applied, along with
CO_COROUTINE to all 'async def' functions.

This way:

1. old generator-based coroutines from asyncio
are awaitable, because of CO_COROUTINE flag (that
asyncio.coroutine decorator will set with
'types.coroutine').

2. new 'async def' functions are awaitable
because of CO_COROUTINE flag.

3. GenObject __iter__ and __next__ raise error
*only* if it has CO_NATIVE_COROUTINE flag.  So
iter(), next(), for..in aren't supported only
for 'async def' functions (but will work ok
on asyncio generator-based coroutines)

4. 'yield from' *only* raises an error if it yields a
*coroutine with a CO_NATIVE_COROUTINE*
from a regular generator.

Thanks,
Yury

On 2015-04-28 7:26 PM, Yury Selivanov wrote:

Hi Guido,

Thank you for a very detailed review.  Comments below:

On 2015-04-28 5:49 PM, Guido van Rossum wrote:

Inline comments below...

On Mon, Apr 27, 2015 at 8:07 PM, Yury Selivanov 


wrote:


Hi python-dev,

Another round of updates.  Reference implementation
has been updated: https://github.com/1st1/cpython/tree/await
(includes all things from the below summary of updates +
tests).


Summary:


1. "PyTypeObject.tp_await" slot.  Replaces "tp_reserved".
This is to enable implementation of Futures with C API.
Must return an iterator if implemented.

That's fine (though I didn't follow this closely).


My main question here is it OK to reuse 'tp_reserved'
(former tp_compare)?

I had to remove this check:
https://github.com/1st1/cpython/commit/4be6d0a77688b63b917ad88f09d446ac3b7e2ce9#diff-c3cf251f16d5a03a9e7d4639f2d6f998L4906 



On the other hand I think that it's a slightly better
solution than adding a new slot.



2. New grammar for "await" expressions, see
'Syntax of "await" expression' section

I like it.


Great!

The current grammar requires parentheses for consequent
await expressions:

   await (await coro())

I can change this (in theory), but I kind of like the parens
in this case -- better readability.  And it'll be a very
rare case.



3. inspect.iscoroutine() and inspect.iscoroutineobjects()
functions.

What's the use case for these? I wonder if it makes more sense to 
have a

check for a generalized awaitable rather than specifically a coroutine.


It's important to at least have 'iscoroutine' -- to check that
the object is a coroutine function.  A typical use-case would be
a web framework that lets you to bind coroutines to specific
http methods/paths:

@http.get('/spam')
async def handle_spam(request):
...

'http.get' decorator will need a way to raise an error if it's
applied to a regular function (while the code is being imported,
not in runtime).


The idea here is to cover all kinds of python objects in
inspect module, it's Python's reflection API.

The other thing is that it's easy to implement this function
for CPython: just check for CO_COROUTINE flag. For other
Python implementations it might be a different story.


(More arguments for isawaitable() below)





4. Full separation of coroutines and generators.
This is a big one; let's discuss.

a) Coroutine objects raise TypeError (is NotImplementedError
better?) in their __iter__ and __next__.  Therefore it's
not not possible to pass them to iter(), tuple(), next() and
other similar functions that work with iterables.

I think it should be TypeError -- what you *really* want is not to 
define

these methods at all but given the implementation tactic for coroutines
that may not be possible, so the nearest approximation is TypeError. 
(Also,

NotImplementedError is typically to indicate that a subclass should
implement it.)



Agree.


b) Because of (a), for..in iteration also does not work
on coroutines anymore.

Sounds good.



c) 'yield from' only accept coroutine objects from
generators decorated with 'types.coroutine'. That means
that existing asyncio generator-based coroutines will
happily yield from both coroutines and generators.
*But* every generator-based coroutine *must* be
decorated with `asyncio.coroutine()`.  This is
potentially a backwards incompatible change.

See below. I worry about backward compatibility. A lot. Are you saying

that asycio-based code that doesn't use @coroutine will break in 3.5?


I'll experiment with replacing (c) with a warning.

We can disable __iter__ and __next__ for coroutines, but
allow to use 'yield from' on them.  Would it be a better
approach?





d) inspect.isgenerator() and inspect.isgeneratorfunction()
return `False` for coroutine objects & coroutine functions.

Makes sense.

Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-28 Thread Yury Selivanov

Greg,

On 2015-04-29 1:40 AM, Greg Ewing wrote:

Yury Selivanov wrote:


I don't want this: "await a() * b()" to be parsed, it's not meaningful.


Why not? If a() is a coroutine that returns a number,
why shouldn't I be able to multiply it by something?


Sorry, I thought you meant parsing "await a()*b()" as
"await (a() * b())".


I don't think your currently proposed grammar prevents
that anyway. We can have

 -->  '*' 
   -->  '*' 
   -->  '*' 
   --> 'await'  * '*'  *
   --> 'await' 'a' '(' ')' '*' 'b' '(' ')'

It does, on the other hand, seem to prevent

  x = - await a()


This works just fine:
https://github.com/1st1/cpython/commit/33b3cd052243cd71c064eb385c7a557eec3ced4b

Current grammar prevents this: "await -fut", and this:
"await fut ** 2" being parsed as "await (fut ** 2)




which looks perfectly sensible to me.

I don't like the idea of introducing another level
of precedence. Python already has too many of those
to keep in my brain. Being able to tell people "it's
just like unary minus" makes it easy to explain (and
therefore possibly a good idea!).



It's just like unary minus ;)

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-29 Thread Yury Selivanov



On 2015-04-29 5:13 AM, Greg Ewing wrote:

Yury Selivanov wrote:


3. GenObject __iter__ and __next__ raise error
*only* if it has CO_NATIVE_COROUTINE flag.  So
iter(), next(), for..in aren't supported only
for 'async def' functions (but will work ok
on asyncio generator-based coroutines)


What about new 'async def' code called by existing
code that expects to be able to use iter() or
next() on the future objects it receives?


4. 'yield from' *only* raises an error if it yields a
*coroutine with a CO_NATIVE_COROUTINE*
from a regular generator.


Won't that prevent some existing generator-based
coroutines (ones not decorated with @coroutine)
from calling ones implemented with 'async def'?


It would.  But that's not a backwards compatibility
issue.

Everything will work in 3.5 without a single line
change.  If you want to use new coroutines - use
them, everything will work too.

If, however, during the refactoring you've missed
several generator-based coroutines *and* they are
not decorated with @coroutine - then yes, you will
get a runtime error.  I see absolutely no problem
with that.  It's a small price to pay for a better
design.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

On 2015-04-29 5:12 AM, Greg Ewing wrote:

Yury Selivanov wrote:
Looking at the grammar -- the only downside of the current approach 
is that

you can't do 'await await fut'.  I still think that it reads better with
parens.  If we put 'await' to 'factor' terminal we would allow

await -fut  # await (-fut)


Is there really a need to disallow that? It would take
a fairly bizarre API to make it meaningful in the first
place, but in any case, it's fairly clear what order
of operations is intended without the parens.


Greg, if grammar can prevent this kind of mistakes - it should.
I like my current approach.

Yury



___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-29 Thread Yury Selivanov

Greg,

On 2015-04-29 5:12 AM, Greg Ewing wrote:

Yury Selivanov wrote:


It's important to at least have 'iscoroutine' -- to check that
the object is a coroutine function.  A typical use-case would be
a web framework that lets you to bind coroutines to specific
http methods/paths:

@http.get('/spam')
async def handle_spam(request):
...

>

The other thing is that it's easy to implement this function
for CPython: just check for CO_COROUTINE flag.


But isn't that too restrictive? Any function that returns
an awaitable object would work in the above case.


It's just an example. All in all, I think that we should have
full coverage of python objects in the inspect module.  There are
many possible use cases besides the one that I used -- runtime
introspection, reflection, debugging etc, where you might need
them.




One of the most frequent mistakes that people make when using
generators as coroutines is forgetting to use ``yield from``::


I think it's a mistake that a lot of beginners may make at some
point (and in this sense it's frequent).  I really doubt that
once you were hit by it more than two times you would make it
again.


What about when you change an existing non-suspendable
function to make it suspendable, and have to deal with
the ripple-on effects of that? Seems to me that affects
everyone, not just beginners.


I've been using coroutines on a daily basis for 6 or 7 years now,
long before asyncio we had a coroutine-based framework at my firm
(yield + trampoline).  Neither I nor my colleagues had any
problems with refactoring the code.  I really try to speak from
my experience when I say that it's not that big of a problem.

Anyways, the PEP provides set_coroutine_wrapper which should solve
the problem.




3. ``yield from`` does not accept coroutine objects from plain Python
generators (*not* generator-based coroutines.)


What exactly are "coroutine objects
from plain Python generators"?)


# *Not* decorated with @coroutine
def some_algorithm_impl():
yield 1
yield from native_coroutine() # <- this is a bug


So what you really mean is "yield-from, when used inside
a function that doesn't have @coroutine applied to it,
will not accept a coroutine object", is that right? If
so, I think this part needs re-wording, because it sounded
like you meant something quite different.

I'm not sure I like this -- it seems weird that applying
a decorator to a function should affect the semantics
of something *inside* the function -- especially a piece
of built-in syntax such as 'yield from'. It's similar
to the idea of replacing 'async def' with a decorator,
which you say you're against.


This is for the transition period. We don't want to break
existing asyncio code.  But we do want coroutines to be
a separate concept from generators. It doesn't make any
sense to iterate through coroutines or to yield-from them.

We can deprecate @coroutine decorator in 3.6 or 3.7 and
at some time remove it.



BTW, by "coroutine object", do you mean only objects
returned by an async def function, or any object having
an __await__ method? I think a lot of things would be
clearer if we could replace the term "coroutine object"
with "awaitable object" everywhere.


The PEP clearly separates awaitbale from coroutine objects.

- coroutine object is returned from coroutine call.

- awaitable is either a coroutine object or an object with
__await__.

list(), tuple(), iter(), next(), for..in etc. won't work
on objects with __await__ (unless they implement __iter__).

The problem I was discussing is about specifically
'yield from' and 'coroutine object'.




   ``yield from`` does not accept *native coroutine objects*
   from regular Python generators


It's the "from" there that's confusing -- it sounds
like you're talking about where the argument to
yield-from comes from, rather than where the yield-from
expression resides. In other words, we though you were
proposing to disallow *this*:

   # *Not* decorated with @coroutine
   def some_algorithm_impl():
  yield 1
  yield from iterator_implemented_by_generator()

I hope to agree that this is a perfectly legitimate
thing to do, and should remain so?




Sure it's perfectly normal ;)  I apologize for the poor
wording.


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-29 Thread Yury Selivanov

Greg,

On 2015-04-29 5:13 AM, Greg Ewing wrote:

Yury Selivanov wrote:


On 2015-04-28 11:59 PM, Greg wrote:


On 29/04/2015 9:49 a.m., Guido van Rossum wrote:


*But* every generator-based coroutine *must* be
decorated with `asyncio.coroutine()`.  This is
potentially a backwards incompatible change.

See below. I worry about backward compatibility. A lot. Are you saying
that asycio-based code that doesn't use @coroutine will break in 3.5?


That seems unavoidable if the goal is for 'await' to only
work on generators that are intended to implement coroutines,


Not sure what you mean by "unavoidable".


Guido is worried about existing asyncio-based code that
doesn't always decorate its generators with @coroutine.

If I understand correctly, if you have

   @coroutine
   def coro1():
  yield from coro2()

   def coro2():
  yield from ...

then coro1() would no longer work. In other words,
some currently legitimate asyncio-based code will break
under PEP 492 even if it doesn't use any PEP 492 features.

What you seem to be trying to do here is catch the
mistake of using a non-coroutine iterator as if it
were a coroutine. By "unavoidable" I mean I can't see
a way to achieve that in all possible permutations
without giving up some backward compatibility.


Please see my reply to Guido in other thread.

Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-29 Thread Yury Selivanov

Greg,

On 2015-04-29 5:12 AM, Greg Ewing wrote:

Guido van Rossum wrote:

On Mon, Apr 27, 2015 at 8:07 PM, Yury Selivanov 
mailto:yselivanov...@gmail.com>> wrote:

>

Why StopAsyncIteration?
'''''''''''''''''''''''

I keep wanting to propose to rename this to AsyncStopIteration.


+1, that seems more consistent to me too.


And since PEP 479 is accepted and enabled by default for coroutines,
the following example will have its ``StopIteration`` wrapped into a
``RuntimeError``


I think that's a red herring in relation to the reason
for StopAsyncIteration/AsyncStopIteration being needed.
The real reason is that StopIteration is already being
used to signal returning a value from an async function,
so it can't also be used to signal the end of an async
iteration.



When we start thinking about generator-coroutines (the ones that
combine 'await' and 'async yield'-something), we'll have to somehow
multiplex them to the existing generator object (at least that's
one way to do it).  StopIteration is already extremely loaded
with different special meanings.

[..]


Does send() make sense for a native coroutine? Check PEP 380. I think 
the only way to access the send() argument is by using ``yield`` but 
that's disallowed. Or is this about send() being passed to the 
``yield`` that ultimately suspends the chain of coroutines?


That's made me think of something else. Suppose you want
to suspend execution in an 'async def' function -- how do
you do that if 'yield' is not allowed? You may need
something like the suspend() primitive that I was thinking
of adding to PEP 3152.


We do this in asyncio with Futures.  We never combine 'yield' and
'yield from' in a @coroutine.  We don't need 'suspend()'.

If you need suspend()-like thing in your own framework, implement
an object with an __await__ method and await on it.




No implicit wrapping in Futures
---

There is a proposal to add similar mechanism to ECMAScript 7 
[2]_.  A

key difference is that JavaScript "async functions" always return a
Promise. While this approach has some advantages, it also implies 
that

a new Promise object is created on each "async function" invocation.


I don't see how this is different from an 'async def'
function always returning an awaitable object, or a new
awaitable object being created on each 'async def'
function invocation. Sounds pretty much isomorphic to me.



Agree.  I'll try to reword that section.

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Ethan,

On 2015-04-29 11:29 AM, Ethan Furman wrote:

Python is not lisp, and await is not a
function, so parens should not be needed in the common case.


Which common case you mean?

Please see this table 
https://www.python.org/dev/peps/pep-0492/#syntax-of-await-expression


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Also please see this:
https://hg.python.org/peps/rev/d048458307b7

FWIW, 'await await fut' isn't something that you likely to see in
your life; 'await -fut' is 99.999% just a bug.  I'm not sure
why Greg is pushing his Grammar idea so aggressively.

Yury

On 2015-04-29 11:33 AM, Yury Selivanov wrote:

Ethan,

On 2015-04-29 11:29 AM, Ethan Furman wrote:

Python is not lisp, and await is not a
function, so parens should not be needed in the common case.


Which common case you mean?

Please see this table 
https://www.python.org/dev/peps/pep-0492/#syntax-of-await-expression


Yury


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Ethan,

On 2015-04-29 1:25 PM, Ethan Furman wrote:

cannot also just work and be the same as the parenthesized
version.

Because it does not make any sense.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: What is the real goal?

2015-04-29 Thread Yury Selivanov

Hi Jim,

On 2015-04-29 1:43 PM, Jim J. Jewett wrote:

On Tue Apr 28 23:49:56 CEST 2015, Guido van Rossum quoted PEP 492:


Rationale and Goals
===

Current Python supports implementing coroutines via generators (PEP
342), further enhanced by the ``yield from`` syntax introduced in PEP
380. This approach has a number of shortcomings:

* it is easy to confuse coroutines with regular generators, since they
   share the same syntax; async libraries often attempt to alleviate
   this by using decorators (e.g. ``@asyncio.coroutine`` [1]_);

So?  PEP 492 never says what coroutines *are* in a way that explains
why it matters that they are different from generators.

Do you really mean "coroutines that can be suspended while they wait
for something slow"?

As best I can guess, the difference seems to be that a "normal"
generator is using yield primarily to say:

 "I'm not done; I have more values when you want them",

but an asynchronous (PEP492) coroutine is primarily saying:

 "This might take a while, go ahead and do something else meanwhile."


Correct.




As shown later in this proposal, the new ``async
with`` statement lets Python programs perform asynchronous calls when
entering and exiting a runtime context, and the new ``async for``
statement makes it possible to perform asynchronous calls in iterators.

Does it really permit *making* them, or does it just signal that you
will be waiting for them to finish processing anyhow, and it doesn't
need to be a busy-wait?


I does.



As nearly as I can tell, "async with" doesn't start processing the
managed block until the "asynchronous" call finishes its work -- the
only point of the async is to signal a scheduler that the task is
blocked.


Right.



Similarly, "async for" is still linearized, with each step waiting
until the previous "asynchronous" step was not merely launched, but
fully processed.  If anything, it *prevents* within-task parallelism.


It enables cooperative parallelism.




It uses the ``yield from`` implementation with an extra step of
validating its argument.  ``await`` only accepts an *awaitable*, which
can be one of:

What justifies this limitation?


We want to avoid people passing regular generators and random
objects to 'await', because it is a bug.



Is there anything wrong awaiting something that eventually uses
"return" instead of "yield", if the "this might take a while" signal
is still true?


If it's an 'async def' then sure, you can use it in await.


Is the problem just that the current implementation
might not take proper advantage of task-switching?


   Objects with ``__await__`` method are called *Future-like* objects in
   the rest of this PEP.

   Also, please note that ``__aiter__`` method (see its definition
   below) cannot be used for this purpose.  It is a different protocol,
   and would be like using ``__iter__`` instead of ``__call__`` for
   regular callables.

   It is a ``TypeError`` if ``__await__`` returns anything but an
   iterator.

What would be wrong if a class just did __await__ = __anext__  ?
If the problem is that the result of __await__ should be iterable,
then why isn't __await__ = __aiter__ OK?


For coroutines in PEP 492:

__await__ = __anext__ is the same as __call__ = __next__
__await__ = __aiter__ is the same as __call__ = __iter__




``await`` keyword is defined differently from ``yield`` and ``yield
from``.  The main difference is that *await expressions* do not require
parentheses around them most of the times.

Does that mean

"The ``await`` keyword has slightly higher precedence than ``yield``,
so that fewer expressions require parentheses"?


 class AsyncContextManager:
 async def __aenter__(self):
 await log('entering context')

Other than the arbitrary "keyword must be there" limitations imposed
by this PEP, how is that different from:

  class AsyncContextManager:
  async def __aenter__(self):
  log('entering context')


This is OK. The point is that you can use 'await log' in
__aenter__.  If you don't need awaits in __aenter__ you can
use them in __aexit__. If you don't need them there too,
then just define a regular context manager.



or even:

  class AsyncContextManager:
  def __aenter__(self):
  log('entering context')

Will anything different happen when calling __aenter__ or log?
Is it that log itself now has more freedom to let other tasks run
in the middle?


__aenter__ must return an awaitable.





It is an error to pass a regular context manager without ``__aenter__``
and ``__aexit__`` methods to ``async with``.  It is a ``SyntaxError``
to use ``async with`` outside of a coroutine.

Why?  Does that just mean they won't take advantage of the freedom
you offered them?


Not sure I understand the question.

It doesn't make any sense in using 'async with' outside of a
coroutine.  The interpeter won't know what to do with them:
you need an event loop for that.


Or are you concern

Re: [Python-Dev] PEP 492: What is the real goal?

2015-04-29 Thread Yury Selivanov

Hi Paul,

On 2015-04-29 2:26 PM, Paul Moore wrote:

On 29 April 2015 at 18:43, Jim J. Jewett  wrote:

Rationale and Goals
===

Current Python supports implementing coroutines via generators (PEP
342), further enhanced by the ``yield from`` syntax introduced in PEP
380. This approach has a number of shortcomings:

* it is easy to confuse coroutines with regular generators, since they
   share the same syntax; async libraries often attempt to alleviate
   this by using decorators (e.g. ``@asyncio.coroutine`` [1]_);

So?  PEP 492 never says what coroutines *are* in a way that explains
why it matters that they are different from generators.

I agree. While I don't use coroutines/asyncio, and I may never do so,
I will say that I find Python's approach very difficult to understand.

I'd hope that the point of PEP 492, by making await/async first class
language constructs, would be to make async programming more
accessible in Python. Whether that will actually be the case isn't
particularly clear to me. And whether "async programming" and
"coroutines" are the same thing, I'm even less sure of. I haven't
really followed the discussions here, because they seem to be about
details that are completely confusing to me.


It will make it more accessible in Python.  asyncio is getting
a lot of traction, and with this PEP accepted I can see it
only becoming easier to work with it (or any other async
frameworks that start using the new syntax/protocols).



In principle, I support the PEP, on the basis that working towards
better coroutine/async support in Python seems worthwhile to me. But
until the whole area is made more accessible to the average
programmer, I doubt any of this will be more than a niche area in
Python.

For example, the PEP says:

"""
New Coroutine Declaration Syntax

The following new syntax is used to declare a coroutine:

async def read_data(db):
 pass
"""

Looking at the Wikipedia article on coroutines, I see an example of
how a producer/consumer process might be written with coroutines:

var q := new queue

coroutine produce
 loop
 while q is not full
 create some new items
 add the items to q
 yield to consume

coroutine consume
 loop
 while q is not empty
 remove some items from q
 use the items
 yield to produce

(To start everything off, you'd just run "produce").

I can't even see how to relate that to PEP 429 syntax. I'm not allowed
to use "yield", so should I use "await consume" in produce (and vice
versa)? I'd actually expect to just write 2 generators in Python, and
use .send() somehow (it's clunky and I can never remember how to write
the calls, but that's OK, it just means that coroutines don't have
first-class syntax support in Python). This is totally unrelated to
asyncio, which is the core use case for all of Python's async support.
But it's what I think of when I see the word "coroutine" (and
Wikipedia agrees).


That Wikipedia page is very generic, and the pseudo-code
that it uses does indeed look confusing.

Here's how it might look like (this is the same pseudo-code
but tailored for PEP 492, not a real something)

  q = asyncio.Queue(maxsize=100)

  async def produce():
  # you might want to wrap it all in 'while True'

  while not q.full():
  item = create_item()
  await q.put(item)

  async def consume():
  while not q.empty():
  item = await q.get()
  process_item(item)


Thanks!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Hi Ethan,

On 2015-04-29 2:32 PM, Ethan Furman wrote:

On 04/29, Yury Selivanov wrote:

On 2015-04-29 1:25 PM, Ethan Furman wrote:

cannot also just work and be the same as the parenthesized
version.

Because it does not make any sense.

I obviously don't understand your position that "it does not make
any sense" -- perhaps you could explain a bit?

What I see is a suspension point that is waiting for the results of
coro(), which will be negated (and returned/assigned/whatever).
What part of that doesn't make sense?



Because you want operators to be resolved in the
order you see them, generally.

You want '(await -fut)' to:

1. Suspend on fut;
2. Get the result;
3. Negate it.

This is a non-obvious thing. I would myself interpret it
as:

1. Get fut.__neg__();
2. await on it.

So I want to make this syntactically incorrect:

'await -fut' would throw a SyntaxError. To do what you
want, write a pythonic '- await fut'.


Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Hi Nathaniel,

BTW, I'm going to reply to you in the other thread about
context-local objects soon.  I have some thoughts on the
topic.

On 2015-04-29 3:14 PM, Nathaniel Smith wrote:

On Apr 29, 2015 11:49 AM, "Yury Selivanov"  wrote:

Hi Ethan,


On 2015-04-29 2:32 PM, Ethan Furman wrote:

On 04/29, Yury Selivanov wrote:

On 2015-04-29 1:25 PM, Ethan Furman wrote:

cannot also just work and be the same as the parenthesized
version.

Because it does not make any sense.

I obviously don't understand your position that "it does not make
any sense" -- perhaps you could explain a bit?

What I see is a suspension point that is waiting for the results of
coro(), which will be negated (and returned/assigned/whatever).
What part of that doesn't make sense?


Because you want operators to be resolved in the
order you see them, generally.

You want '(await -fut)' to:

1. Suspend on fut;
2. Get the result;
3. Negate it.

This is a non-obvious thing. I would myself interpret it
as:

1. Get fut.__neg__();
2. await on it.

So I want to make this syntactically incorrect:

As a bystander, I don't really care either way about whether await -fut is
syntactically valid (since like you say it's semantically nonsense
regardless and no one will ever write it). But I would rather like to
actually know what the syntax actually is, not just have a list of examples
(which kinda gives me perl flashbacks). Is there any simple way to state
what the rules for parsing await are? Or do I just have to read the parser
code if I want to know that?


There is a summary of grammar changes in the PEP:
https://www.python.org/dev/peps/pep-0492/#grammar-updates

You can also see the actual grammar file from the reference
implementation:
https://github.com/1st1/cpython/blob/await/Grammar/Grammar



Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: What is the real goal?

2015-04-29 Thread Yury Selivanov

Paul,

On 2015-04-29 3:19 PM, Paul Moore wrote:

On 29 April 2015 at 19:42, Yury Selivanov  wrote:

Here's how it might look like (this is the same pseudo-code
but tailored for PEP 492, not a real something)

   q = asyncio.Queue(maxsize=100)

   async def produce():
   # you might want to wrap it all in 'while True'

I think the "loop" in the Wikipedia pseudocode was intended to be the
"while True" here, not part of the "while" on the next line.


   while not q.full():
   item = create_item()
   await q.put(item)

   async def consume():
   while not q.empty():
   item = await q.get()
   process_item(item)

Thanks for that. That does look pretty OK. One question, though - it
uses an asyncio Queue. The original code would work just as well with
a list, or more accurately, something that wasn't designed for async
use. So the translation isn't completely equivalent. Also, can I run
the produce/consume just by calling produce()? My impression is that
with asyncio I need an event loop - which "traditional" coroutines
don't need. Nevertheless, the details aren't so important, it was only
a toy example anyway.


Well, yes.  Coroutine is a generic term.  And you can
use PEP 492 coroutines without asyncio, in fact that's
how most tests for the reference implementation is written.

Coroutine objects have .send(), .throw() and .close() methods
(same as generator objects in Python).  You can work with them
without a loop, but loop implementations contain a lot of
logic to implement the actual cooperative execution.

You can use generators as coroutines, and nothing would
prevent you from doing that after PEP 492, moreover, for
some use-cases it might be quite a good decision.  But a
lot of the code -- web frameworks, network applications,
etc will hugely benefit from the proposal, streamlined
syntax and async for/with statements.

[..]


But the use of "coroutine" in PEP 492 for the functions introduced by
"async def" is confusing - at least to me - because I think of the
above, and not of async. Why not just call them "async functions" and
leave the term coroutine for the above flow control construct, which
is where it originated?

But maybe that ship has long sailed - the term "coroutine" is pretty
entrenched in the asyncio documentation. If so, then I guess we have
to live with the consequences.


Everybody is pulling me in a different direction :)
Guido proposed to call them "native coroutines".  Some people
think that "async functions" is a better name.  Greg loves
his "cofunction" term.

I'm flexible about how we name 'async def' functions.  I like
to call them "coroutines", because that's what they are, and
that's how asyncio calls them.  It's also convenient to use
'coroutine-object' to explain what is the result of calling
a coroutine.

Anyways, I'd be OK to start using a new term, if "coroutine" is
confusing.


Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov



On 2015-04-29 3:24 PM, Isaac Schwabacher wrote:

On 15-04-29, Yury Selivanov  wrote:

Hi Ethan,

[..]

So I want to make this syntactically incorrect:

Does this need to be a syntax error? -"hello" raises TypeError because str doesn't have a 
__neg__, but there's no reason a str subclass couldn't define one. "TypeError: bad operand 
type for unary -: 'asyncio.Future'" is enough to clear up any misunderstandings, and if 
someone approaching a new language construct doesn't test their code well enough to at least 
execute all the code paths, the difference between a compile-time SyntaxError and a run-time 
TypeError is not going to save them.




The grammar of the language should match the most common
use case.

FWIW, I've just updated the pep with a precedence table:
https://hg.python.org/peps/rev/d355918bc0d7

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Greg,

On 2015-04-29 6:46 PM, Greg Ewing wrote:

Yury Selivanov wrote:

I'm not sure
why Greg is pushing his Grammar idea so aggressively.


Because I believe that any extra complexity in the grammar
needs a very strong justification. It's complexity in the
core language, like a new keyword, so it puts a burden on
everyone's brain.

Saying "I don't think anyone would ever need to write this,
therefore we should disallow it" is not enough, given that
there is a substantial cost to disallowing it.

If you don't think there's a cost, consider that we *both*
seem to be having trouble predicting the consequences of
your proposed syntax, and you're the one who invented it.
That's not a good sign!


Sorry, but I'm not sure where & when I had any troubles
predicting the consequences..

Please take a look at the updated PEP.  There is a
precedence table there + motivation.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; v3

2015-04-29 Thread Yury Selivanov

Greg,

On 2015-04-29 6:46 PM, Greg Ewing wrote:

Yury Selivanov wrote:


Won't that prevent some existing generator-based
coroutines (ones not decorated with @coroutine)
from calling ones implemented with 'async def'?


It would.  But that's not a backwards compatibility
issue.


It seems to go against Guido's desire for the new
way to be a 100% drop-in replacement for the old
way. There are various ways that old code can end
up calling new code -- subclassing, callbacks,
etc.

It also means that if person A writes a library
in the new style, then person B can't make use
of it without upgrading all of their code to the
new style as well. The new style will thus be
"infectious" in a sense.

I suppose it's up to Guido to decide whether it's
a good or bad infection. But the same kind of
reasoning seemed to be at least partly behind
the rejection of PEP 3152.



It's a drop-in replacement ;)  If you run your
existing code - it will 100% work just fine.

There is a probability that *when* you start applying
new syntax something could go wrong -- you're right
here.

I'm updating the PEP to explain this clearly,
and let's see what Guido thinks about that.

My opinion is that this is a solvable problem with
a clear guidelines on how to transition existing
code to the new style.

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Nathaniel,

On 2015-04-29 7:35 PM, Nathaniel Smith wrote:

What I do feel strongly about
is that whatever syntax we end up with, there should be*some*
accurate human-readable description of*what it is*. AFAICT the PEP
currently doesn't have that.


How to define human-readable description of how unary
minus operator works?

Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Guido,

On 2015-04-29 7:52 PM, Guido van Rossum wrote:

On Wed, Apr 29, 2015 at 4:48 PM, Yury Selivanov 
wrote:


Nathaniel,

On 2015-04-29 7:35 PM, Nathaniel Smith wrote:


What I do feel strongly about
is that whatever syntax we end up with, there should be*some*
accurate human-readable description of*what it is*. AFAICT the PEP
currently doesn't have that.


How to define human-readable description of how unary
minus operator works?


In a PEP you should probably give grammar that is not the actual grammar
from the implementation, but matches the grammar used in the reference
manual on docs.python.org.


Will do!

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-29 Thread Yury Selivanov

Nathaniel,

On 2015-04-29 7:58 PM, Nathaniel Smith wrote:

On Wed, Apr 29, 2015 at 4:48 PM, Yury Selivanov  wrote:

Nathaniel,

On 2015-04-29 7:35 PM, Nathaniel Smith wrote:

What I do feel strongly about
is that whatever syntax we end up with, there should be*some*
accurate human-readable description of*what it is*. AFAICT the PEP
currently doesn't have that.

How to define human-readable description of how unary
minus operator works?

Hah, good question :-). Of course we all learned how to parse
arithmetic in school, so perhaps it's a bit cheating to refer to that
knowledge. Except of course basically all our users *do* have that
knowledge (or else are forced to figure it out anyway). So I would be
happy with a description of "await" that just says "it's like unary
minus but higher precedence".

Even if we put aside our trained intuitions about arithmetic, I think
it's correct to say that the way unary minus is parsed is: everything
to the right of it that has a tighter precedence gets collected up and
parsed as an expression, and then it takes that expression as its
argument. Still pretty simple.




Well, await is defined exactly like that ;)

Anyways, I'll follow Guido's suggestion to define
await in the PEP the same way we define other syntax
in python docs.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 quibble and request

2015-04-29 Thread Yury Selivanov

Hi Ethan,

On 2015-04-29 8:21 PM, Ethan Furman wrote:

 From the PEP:


Why not a __future__ import

__future__ imports are inconvenient and easy to forget to add.

That is a horrible rationale for not using an import.  By that logic we
should have everything in built-ins.  ;)



Working example
...

The working example only uses async def and await, not async with
nor async for nor __aenter__, etc., etc.

Could you put in a more complete example -- maybe a basic chat room
with both server and client -- that demonstrated more of the new
possibilities?


Andrew Svetlov has implemented some new features in his
aiomysql driver:

https://github.com/aio-libs/aiomysql/blob/await/tests/test_async_iter.py

I don't want to cite it in the PEP because it's not complete
yet, and some idioms (like 'async with') aren't used to their
full potential.



Having gone through the PEP again, I am still no closer to understanding
what happens here:

   data = await reader.read(8192)

What does the flow of control look like at the interpreter level?


'await' is semantically equivalent to 'yield from' in this line.

To really understand all implementation details of this line
you need to read PEP 3156 and experiment with asyncio. There
is no easier way, unfortunately.  I can't add a super detailed
explanation how event loops can be implemented in PEP 492,
that's not in its scope.

The good news is that to use asyncio on a daily basis you
don't need to know all details, as you don't need to know
how 'ceval.c' works and how 'setTimeout' is implemented in
JavaScript.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] PEP 492: async/await in Python; version 4

2015-04-29 Thread Yury Selivanov

Hi python-dev,

New version of the PEP is attached. Summary of updates:


1. Terminology:

- *native coroutine* term is used for "async def" functions.

- *generator-based coroutine* term is used for PEP 380
coroutines used in asyncio.

- *coroutine* is used when *native coroutine* or
*generator based coroutine* can be used in the same
context.

I think that it's not really productive to discuss the
terminology that we use in the PEP.  Its only purpose is
to disambiguate concepts used in the PEP.  We should discuss
how we will name new 'async def' coroutines in Python
Documentation if the PEP is accepted.  Although if you
notice that somewhere in the PEP it is not crystal clear
what "coroutine" means please give me a heads up!


2. Syntax of await expressions is now thoroghly defined
in the PEP. See "Await Expression", "Updated operator
precedence table", and "Examples of "await" expressions"
sections.

I like the current approach.  I'm still not convinced
that we should make 'await' the same grammatically as
unary minus.

I don't understand why we should allow parsing things
like 'await -fut'; this should be a SyntaxError.
I'm fine to modify the grammar to allow 'await await fut'
syntax, though.  And I'm open to discussion :)


3. CO_NATIVE_COROUTINE flag. This enables us to disable
__iter__ and __next__ on native coroutines while maintaining
full backwards compatibility.


4. asyncio / Migration strategy.  Existing code can
be used with PEP 492 as is, everything will work as
expected.

However, since *plain generator*s (not decorated with
@asyncio.coroutine) cannot 'yield from' native coroutines
(async def functions), it might break some code
*while adapting it to the new syntax*.

I'm open to just throw a RuntimeWarning in this case
in 3.5, and raise a TypeError in 3.6.

Please see the "Differences from generators" section of
the PEP.


5. inspect.isawaitable() function. And, all new functions
are now listed in the "New Standard Library Functions"
section.


6. Lot's of small updates and tweaks throughout the PEP.


Thanks,
Yury



PEP: 492
Title: Coroutines with async and await syntax
Version: $Revision$
Last-Modified: $Date$
Author: Yury Selivanov 
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 09-Apr-2015
Python-Version: 3.5
Post-History: 17-Apr-2015, 21-Apr-2015, 27-Apr-2015, 29-Apr-2015


Abstract


This PEP introduces new syntax for coroutines, asynchronous ``with``
statements and ``for`` loops.  The main motivation behind this proposal
is to streamline writing and maintaining asynchronous code, as well as
to simplify previously hard to implement code patterns.


Rationale and Goals
===

Current Python supports implementing coroutines via generators (PEP
342), further enhanced by the ``yield from`` syntax introduced in PEP
380. This approach has a number of shortcomings:

* it is easy to confuse coroutines with regular generators, since they
  share the same syntax; async libraries often attempt to alleviate
  this by using decorators (e.g. ``@asyncio.coroutine`` [1]_);

* it is not possible to natively define a coroutine which has no
  ``yield`` or  ``yield from`` statements, again requiring the use of
  decorators to fix potential refactoring issues;

* support for asynchronous calls is limited to expressions where
  ``yield`` is allowed syntactically, limiting the usefulness of
  syntactic features, such as ``with`` and ``for`` statements.

This proposal makes coroutines a native Python language feature, and
clearly separates them from generators.  This removes
generator/coroutine ambiguity, and makes it possible to reliably define
coroutines without reliance on a specific library.  This also enables
linters and IDEs to improve static code analysis and refactoring.

Native coroutines and the associated new syntax features make it
possible to define context manager and iteration protocols in
asynchronous terms. As shown later in this proposal, the new ``async
with`` statement lets Python programs perform asynchronous calls when
entering and exiting a runtime context, and the new ``async for``
statement makes it possible to perform asynchronous calls in iterators.


Specification
=

This proposal introduces new syntax and semantics to enhance coroutine
support in Python.

This specification presumes knowledge of the implementation of
coroutines in Python (PEP 342 and PEP 380).  Motivation for the syntax
changes proposed here comes from the asyncio framework (PEP 3156) and
the "Cofunctions" proposal (PEP 3152, now rejected in favor of this
specification).

From this point in this document we use the word *native coroutine* to
refer to functions declared using the new syntax. *generator-based
coroutine* is used where necessary to refer to coroutines that are
based 

Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-04-29 Thread Yury Selivanov

One more thing to discuss:

7. StopAsyncIteration vs AsyncStopIteration.

I don't have a strong opinion on this, I prefer
the former because it reads better.

There was no consensus on which one we should use.

Thanks,

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 quibble and request

2015-04-29 Thread Yury Selivanov

Nick,

On 2015-04-29 9:52 PM, Nick Coghlan wrote:

On 30 April 2015 at 10:33, Yury Selivanov  wrote:

To really understand all implementation details of this line
you need to read PEP 3156 and experiment with asyncio. There
is no easier way, unfortunately.  I can't add a super detailed
explanation how event loops can be implemented in PEP 492,
that's not in its scope.

This request isn't about understanding the implementation details,
it's about understanding what Python *users* will gain from the PEP
without *needing* to understand the implementation details.

For that, I'd like to see some not-completely-trivial example code in
(or at least linked from) the PEP written using:

* trollius (no "yield from", Python 2 compatible, akin to Twisted's
inlineDeferred's)
* asyncio/tulip ("yield from", Python 3.3+ compatible)
* PEP 492 (async/await, Python 3.5+ only)


I'll see what I can do with aiomysql library to showcase
async for and async with.  I have a few outstanding tasks
with reference implementation to test/add though.

I'm not sure that trollius will add anything to it.  It's just
like asyncio, but uses 'yield' instead of 'yield from' and was
envisioned by Victor Stinner as a transitional-framework
to ease the porting of openstack to python 3.



The *intent* of PEP 492, like PEP 380 and PEP 342 before it, is "make
asynchronous programming in Python easier". I think it will actually
succeed in that goal, but I don't think it currently does an
especially job of explaining that to folks that aren't both already
deeply invested in the explicitly asynchronous programming model *and*
thoroughly aware of the fact that most of us need asynchronous
programming to look as much like synchronous programming as possible
in order for it to fit our brains. Some folks can fit ravioli code
with callbacks going everywhere in their brains, but I can't, and it's
my experience that most other folks can't either. This lack means the
PEP that gets confused objections from folks that wish explicitly
asynchronous programming models would just go away entirely (they
won't), as well as from folks that already understand it and don't see
why we can't continue treating it as a special case of other features
that folks have to learn how to use from first principles, rather than
saving them that up front learning cost by doing the pattern
extraction to make event driven explicitly asynchronous programming
its own first class concept with dedicated syntax (a hint on that
front: with statements are just particular patterns for using
try/except/finally, decorators are just particular patterns in using
higher order functions, for statements are just particular patterns in
using while statements and builtins, and even imports and classes just
represent particular patterns in combining dictionaries, code
execution and the metaclass machinery - the pattern extraction and
dedicated syntax associated with all of them makes it possible to
learn to *use* these concepts without first having to learn how to
*implement* them)

 From my own perspective, I've spent a reasonable amount of time
attempting to explain to folks the "modal" nature of generators, in
that you can use them both as pure iterable data sources *and* as
coroutines (as per PEP 342).

The problem I've found is that our current approach ends up failing
the "conceptually different things should also look superficially
different" test: outside certain data pipeline processing problems,
generators-as-iterators and generators-as-coroutines mostly end up
being fundamentally *different* ways of approaching a programming
problem, but the current shared syntax encourages users to attempt to
place them in the same mental bucket. Those users will remain
eternally confused until they learn to place them in two different
buckets despite the shared syntax (the 5 or so different meanings of
"static" in C++ come to mind at this point...).


Agree.  This confusion of trying to fit two fundamentally
different programming models in one syntax is what led me
to start thinking about PEP 492 ideas several years ago.

And the absence of 'async with' and 'async for' statements
forced me to use greenlets, which is another reason for
the PEP.



With explicitly asynchronous development*, this problem of needing to
learn to segment the world into two pieces is particularly important,
and this wonderful rant on red & blue functions published a couple of
months ago helps explain why:
http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/

The dedicated async/await syntax proposed in PEP 492 lets the end user
mostly *not care* about all the messiness that needs to happen under
the covers to make explicitly asynchronous programming as close to
normal synchronous programming as possible.

Re: [Python-Dev] PEP 492 quibble and request

2015-04-29 Thread Yury Selivanov

On 2015-04-29 11:01 PM, Nick Coghlan wrote:

On 30 April 2015 at 12:31, Guido van Rossum  wrote:

>On Wed, Apr 29, 2015 at 7:07 PM, Nick Coghlan  wrote:

>>
>>[...]
>>Yeah, I'm coming around to the idea. For the async pseudo-keyword, I
>>can see that the proposal only allows its use in cases that were
>>previously entirely illegal, but I'm not yet clear on how the PEP
>>proposes to avoid changing the meaning of the following code:
>>
>> x = await(this_is_a_function_call)
>>
>>Unless I'm misreading the proposed grammar in the PEP (which is
>>entirely possible), I believe PEP 492 would reinterpret that as:
>>
>> x = await this_is_not_a_function_call_any_more

>
>
>Ah, but here's the other clever bit: it's only interpreted this way*inside*
>a function declared with 'async def'. Outside such functions, 'await' is not
>a keyword, so that grammar rule doesn't trigger. (Kind of similar to the way
>that the print_function __future__ disables the keyword-ness of 'print',
>except here it's toggled on or off depending on whether the nearest
>surrounding scope is 'async def' or not. The PEP could probably be clearer
>about this; it's all hidden in the Transition Plan section.)

Ah, nice, although even reading the Transition Plan section didn't
clue me in to that particular aspect of the idea :)

Given that clarification, I think the rationale for "no __future__
statement needed" can be strengthened by focusing on the fact that
such a statement would largely be*redundant*, given that:

* "async def", "async with", and "async for" are all currently syntax
errors, and hence adding them is backwards compatible if "async" is
otherwise treated as a normal variable name
* "await " only gains its new interpretation when used inside an
"async def" statement, so "async def" fills the role that a module
level compiler declaration like "from __future__ import
async_functions" would otherwise fill


Thanks, Nick.

I've fixed the Transition Plan section, and rewrote the
"why not __future__" one too.

https://hg.python.org/peps/rev/552773d7e085
https://hg.python.org/peps/rev/5db3ad3d540b

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-04-30 Thread Yury Selivanov

On 2015-04-30 5:16 AM, Greg Ewing wrote:

Yury Selivanov wrote:


3. CO_NATIVE_COROUTINE flag. This enables us to disable
__iter__ and __next__ on native coroutines while maintaining
full backwards compatibility.


I don't think you can honestly claim "full backwards
compatibility" as long as there are some combinations
of old-style and new-style code that won't work
together. You seem to be using your own personal
definition of "full" here.



Well, using next() and iter() on coroutines in asyncio
code is something esoteric.  I can't even imagine
why you would want to do that.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 vs. PEP 3152, new round

2015-04-30 Thread Yury Selivanov



On 2015-04-30 1:56 PM, Ethan Furman wrote:

>Why not? Unlike some other languages, Python does not have uniform
>priorities for unary operators, so it's reasonable for some unary
>operations to have a different priority than others, and certain things
>will be SyntaxErrors because of that. E.g. you can write "not -x" but you
>can't write "- not x".

For one, Yury's answer is "- await x" which looks just as nonsensical as
"- not x".



"- await x" is a perfectly valid code:

result = - await compute_in_db()

(same as "result = - (yield from do_something())")



For another, an error of some type will be raised if either __neg__ doesn't
exist or it doesn't return an awaitable, so a SyntaxError is unnecessary.

For a third, by making it a SyntaxError you are forcing the use of parens to
get what should be the behavior anyway.


I still want to see where my current grammar forces to use
parens.  See [1], there are no useless parens anywhere.

FWIW, I'll fix the 'await (await x)' expression to be parsed
without parens.



In other words, a SyntaxError is nat any clearer than "AttributeError: obj
has no __neg__ method" and it's not any clearer than "AwaitError: __neg__
returned not-awaitable".  Those last two errors tell you exactly what you
did wrong.


This is debatable. "obj has no __neg__ method" isn't obvious
to everyone (especially to those people who aren't using
operator overloading).


[1] https://www.python.org/dev/peps/pep-0492/#examples-of-await-expressions


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: What is the real goal?

2015-04-30 Thread Yury Selivanov

Jim,

On 2015-04-30 2:41 PM, Jim J. Jewett wrote:
[...]

Does it really permit *making* them [asynchronous calls], or does
it just signal that you will be waiting for them to finish processing
anyhow, and it doesn't need to be a busy-wait?

I does.

Bad phrasing on my part.  Is there anything that prevents an
asynchronous call (or waiting for one) without the "async with"?

If so, I'm missing something important.  Either way, I would
prefer different wording in the PEP.


Yes, you can't use 'yield from' in __exit__/__enter__
in current Python.


It uses the ``yield from`` implementation with an extra step of
validating its argument.  ``await`` only accepts an *awaitable*,
which can be one of:

What justifies this limitation?

We want to avoid people passing regular generators and random
objects to 'await', because it is a bug.

Why?

Is it a bug just because you defined it that way?

Is it a bug because the "await" makes timing claims that an
object not making such a promise probably won't meet?  (In
other words, a marker interface.)

Is it likely to be a symptom of something that wasn't converted
correctly, *and* there are likely to be other bugs caused by
that same lack of conversion?


Same as 'yield from' is expecting an iterable, await
is expecting an awaitable.  That's the protocol.

You can't pass random objects to 'with' statements,
'yield from', 'for..in', etc.

If you write

   def gen(): yield 1
   await gen()

then it's a bug.




For coroutines in PEP 492:
__await__ = __anext__ is the same as __call__ = __next__
__await__ = __aiter__ is the same as __call__ = __iter__

That tells me that it will be OK sometimes, but will usually
be either a mistake or an API problem -- and it explains why.

Please put those 3 lines in the PEP.


There is a line like that:
https://www.python.org/dev/peps/pep-0492/#await-expression
Look for "Also, please note..." line.


This is OK. The point is that you can use 'await log' in
__aenter__.  If you don't need awaits in __aenter__ you can
use them in __aexit__. If you don't need them there too,
then just define a regular context manager.

Is it an error to use "async with" on a regular context manager?
If so, why?  If it is just that doing so could be misleading,
then what about "async with mgr1, mgr2, mgr3" -- is it enough
that one of the three might suspend itself?


'with' requires an object with __enter__ and __exit__

'async with' requires an object with __aenter__ and __aexit__

You can have an object that implements both interfaces.




 class AsyncContextManager:
 def __aenter__(self):
 log('entering context')



__aenter__ must return an awaitable

Why?  Is there a fundamental reason, or it is just to avoid the
hassle of figuring out whether or not the returned object is a
future that might still need awaiting?


The fundamental reason why 'async with' is proposed is because
you can't suspend execution in __enter__ and __exit__.
If you need to suspend it there, use 'async with' and
its __a*__ methods, but they have to return awaitable
(see https://www.python.org/dev/peps/pep-0492/#new-syntax
and look what 'async with' is semantically equivalent to)



Is there an assumption that the scheduler will let the thing-being
awaited run immediately, but look for other tasks when it returns,
and a further assumption that something which finishes the whole
task would be too slow to run right away?


It doesn't make any sense in using 'async with' outside of a
coroutine.  The interpeter won't know what to do with them:
you need an event loop for that.

So does the PEP also provide some way of ensuring that there is
an event loop?  Does it assume that self-suspending coroutines
will only ever be called by an already-running event loop
compatible with asyncio.get_event_loop()?  If so, please make
these contextual assumptions explicit near the beginning of the PEP.


You need some kind of loop, but it doesn't have to the one
from asyncio.  There is at least one place in the PEP where
it's mentioned that the PEP introduses a generic concept
that can be used by asyncio *and* other frameworks.





It is a ``TypeError`` to pass a regular iterable without ``__aiter__``
method to ``async for``.  It is a ``SyntaxError`` to use ``async for``
outside of a coroutine.

The same questions about why -- what is the harm?

I can imagine that as an implementation detail, the async for wouldn't
be taken advtange of unless it was running under an event loop that
knew to look for "aync for" as suspension points.


Event loop doesn't need to know anything about 'async with'
and 'async for'. For loop it's always one thing -- something
is awaiting somewhere for some result.



I'm not seeing what the actual harm is in either not happening to
suspend (less efficient, but still correct), or in suspending between
every step of a regular iterator (because, why not?)



For debugging this kind of mistakes there is a special debug mode in
asyncio, in which ``@coroutine``

Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-04-30 Thread Yury Selivanov

On 2015-04-30 7:24 PM, Greg Ewing wrote:

Yury Selivanov wrote:

Well, using next() and iter() on coroutines in asyncio
code is something esoteric.  I can't even imagine
why you would want to do that.


I'm talking about the fact that existing generator-
based coroutines that aren't decorated with
@coroutine won't be able to call new ones that use
async def.



Ah, alright.

You quoted this:

3. CO_NATIVE_COROUTINE flag. This enables us to
disable __iter__ and __next__ on native coroutines
while maintaining full backwards compatibility.

I wrote "full backwards compatibility" for that
particular point #3 -- existing @asyncio.coroutines
will have __iter__ and __next__ working just fine.

Sorry if this was misleading.


This means that converting one body of code to the
new style can force changes in other code that
interacts with it.

Maybe this is not considered a problem, but as long
as it's true, I don't think it's accurate to claim
"full backwards compatibility".



I covered this in point #4.  I also touched this in
https://www.python.org/dev/peps/pep-0492/#migration-strategy


I'm still waiting for feedback on this from Guido.  If
he decides to go with RuntimeWarnings, then it's 100%
backwards compatible.  If we keep TypeErrors --
then *existing code will work on 3.5*, but something
*might* break during adopting new syntax.  I'll update
the Backwards Compatibility section.


Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-01 Thread Yury Selivanov

Stefan,

I don't like the idea of combining __next__ and __anext__.
In this case explicit is better than implicit.  __next__
returning coroutines is a perfectly normal thing for a
normal 'for' loop (it wouldn't to anything with them),
whereas 'async for' will interpret that differently, and
will try to await those coroutines.

Yury

On 2015-05-01 1:10 PM, Stefan Behnel wrote:

Guido van Rossum schrieb am 01.05.2015 um 17:28:

On Fri, May 1, 2015 at 5:39 AM, Stefan Behnel wrote:


Yury Selivanov schrieb am 30.04.2015 um 03:30:

Asynchronous Iterators and "async for"
--

An *asynchronous iterable* is able to call asynchronous code in its
*iter* implementation, and *asynchronous iterator* can call
asynchronous code in its *next* method.  To support asynchronous
iteration:

1. An object must implement an  ``__aiter__`` method returning an
*awaitable* resulting in an *asynchronous iterator object*.

2. An *asynchronous iterator object* must implement an ``__anext__``
method returning an *awaitable*.

3. To stop iteration ``__anext__`` must raise a ``StopAsyncIteration``
exception.

What this section does not explain, AFAICT, nor the section on design
considerations, is why the iterator protocol needs to be duplicated
entirely. Can't we just assume (or even validate) that any 'regular'
iterator returned from "__aiter__()" (as opposed to "__iter__()") properly
obeys to the new protocol? Why additionally duplicate "__next__()" and
"StopIteration"?

ISTM that all this really depends on is that "__next__()" returns an
awaitable. Renaming the method doesn't help with that guarantee.


This is an astute observation. I think its flaw (if any) is the situation
where we want a single object to be both a regular iterator and an async
iterator (say when migrating code to the new world). The __next__ method
might want to return a result while __anext__ has to return an awaitable.
The solution to that would be to have __aiter__ return an instance of a
different class than __iter__, but that's not always convenient.

My personal gut feeling is that this case would best be handled by a
generic wrapper class. Both are well defined protocols, so I don't expect
people to change all of their classes and instead return a wrapped object
either from __iter__() or __aiter__(), depending on which they want to
optimise for, or which will eventually turn out to be easier to wrap.

But that's trying to predict the [Ff]uture, obviously. It just feels like
unnecessary complexity for now. And we already have a type slot for
__next__ ("tp_iternext"), but not for __anext__.

Stefan


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/yselivanov.ml%40gmail.com


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-01 Thread Yury Selivanov

Let's say it this way: I want to know what I am looking at
when I browse through the code -- an asynchronous iterator,
or a normal iterator.  I want an explicit difference between
these protocols, because they are different.

Moreover, the below code is a perfectly valid, infinite
iterable:

class SomeIterable:
 def __iter__(self):
 return self
 async def __next__(self):
 return 'spam'

I'm strong -1 on this idea.

Yury

On 2015-05-01 3:03 PM, Stefan Behnel wrote:

Yury Selivanov schrieb am 01.05.2015 um 20:52:

I don't like the idea of combining __next__ and __anext__.
In this case explicit is better than implicit.  __next__
returning coroutines is a perfectly normal thing for a
normal 'for' loop (it wouldn't to anything with them),
whereas 'async for' will interpret that differently, and
will try to await those coroutines.

Sure, but the difference is that one would have called __aiter__() first
and the other __iter__(). Normally, either of the two would not exist, so
using the wrong loop on an object will just fail. However, after we passed
that barrier, we already know that the object that was returned is supposed
to obey to the expected protocol, so it doesn't matter whether we call
__next__() or name it __anext__(), except that the second requires us to
duplicate an existing protocol.

This has nothing to do with implicit vs. explicit.

Stefan


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/yselivanov.ml%40gmail.com


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-01 Thread Yury Selivanov

On 2015-05-01 3:19 PM, Ethan Furman wrote:

Sure, but the difference is that one would have called __aiter__() first
>and the other __iter__(). Normally, either of the two would not exist, so
>using the wrong loop on an object will just fail. However, after we passed
>that barrier, we already know that the object that was returned is supposed
>to obey to the expected protocol, so it doesn't matter whether we call
>__next__() or name it __anext__(), except that the second requires us to
>duplicate an existing protocol.

If we must have __aiter__, then we may as well also have __anext__; besides
being more consistent, it also allows an object to be both a normol iterator
and an asynch iterator.


And this is a good point too.

Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-01 Thread Yury Selivanov

On 2015-05-01 3:23 PM, Yury Selivanov wrote:

Let's say it this way: I want to know what I am looking at
when I browse through the code -- an asynchronous iterator,
or a normal iterator.  I want an explicit difference between
these protocols, because they are different.

Moreover, the below code is a perfectly valid, infinite
iterable:

class SomeIterable:
 def __iter__(self):
 return self
 async def __next__(self):
 return 'spam'

I'm strong -1 on this idea.



To further clarify on the example:

class SomeIterable:
 def __iter__(self):
 return self
 async def __aiter__(self):
 return self
 async def __next__(self):
 print('hello')
 raise StopAsyncIteration


If you pass this to 'async for' you will get
'hello' printed and the loop will be over.

If you pass this to 'for', you will get an
infinite loop, because '__next__' will return a
coroutine object (that has to be also awaited,
but it wouldn't, because it's a plain 'for'
statement).

This is something that we shouldn't let happen.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-01 Thread Yury Selivanov

On 2015-05-01 4:24 PM, Arnaud Delobelle wrote:

On 1 May 2015 at 20:24, Yury Selivanov  wrote:

On 2015-05-01 3:19 PM, Ethan Furman wrote:

[...]

If we must have __aiter__, then we may as well also have __anext__;
besides
being more consistent, it also allows an object to be both a normol
iterator
and an asynch iterator.


And this is a good point too.

I'm not convinced that allowing an object to be both a normal and an
async iterator is a good thing.  It could be a recipe for confusion.




I doubt that it will be a popular thing.  But disallowing this
by merging two different protocols in one isn't a good idea
either.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: What is the real goal?

2015-05-01 Thread Yury Selivanov



On 2015-05-01 5:37 PM, Jim J. Jewett wrote:

On Thu Apr 30 21:27:09 CEST 2015, Yury Selivanov replied:


On 2015-04-30 2:41 PM, Jim J. Jewett wrote:


Bad phrasing on my part.  Is there anything that prevents an
asynchronous call (or waiting for one) without the "async with"?
If so, I'm missing something important.  Either way, I would
prefer different wording in the PEP.

Yes, you can't use 'yield from' in __exit__/__enter__
in current Python.

I tried it in 3.4, and it worked.

I'm not sure it would ever be sensible, but it didn't raise any
errors, and it did run.

What do you mean by "can't use"?


It probably executed without errors, but it didn't run the
generators.


class Foo:
   def __enter__(self):
   yield from asyncio.sleep(0)
   print('spam')

with Foo(): pass # <- 'spam' won't ever be printed.





For coroutines in PEP 492:
__await__ = __anext__ is the same as __call__ = __next__
__await__ = __aiter__ is the same as __call__ = __iter__

That tells me that it will be OK sometimes, but will usually
be either a mistake or an API problem -- and it explains why.
Please put those 3 lines in the PEP.

There is a line like that:
https://www.python.org/dev/peps/pep-0492/#await-expression
Look for "Also, please note..." line.

It was from reading the PEP that the question came up, and I
just reread that section.

Having those 3 explicit lines goes a long way towards explaining
how an asychio coroutine differs from a regular callable, in a
way that the existing PEP doesn't, at least for me.



This is OK. The point is that you can use 'await log' in
__aenter__.  If you don't need awaits in __aenter__ you can
use them in __aexit__. If you don't need them there too,
then just define a regular context manager.

Is it an error to use "async with" on a regular context manager?
If so, why?  If it is just that doing so could be misleading,
then what about "async with mgr1, mgr2, mgr3" -- is it enough
that one of the three might suspend itself?

'with' requires an object with __enter__ and __exit__
'async with' requires an object with __aenter__ and __aexit__
You can have an object that implements both interfaces.

I'm not still not seeing why with (let alone await with) can't
just run whichever one it finds.  "await with" won't actually let
the BLOCK run until the future is resolved.  So if a context
manager only supplies __enter__ instead of __aenter__, then at most
you've lost a chance to switch tasks while waiting -- and that is no
worse than if the context manager just happened to be really slow.


let's say you have a function:

def foo():
   with Ctx(): pass


if Ctx.__enter__ is a generator/coroutine, then
foo becomes a generator/coroutine (otherwise how
(and to what) would you yield from/await on __enter__?).
And then suddenly calling 'foo' doesn't do anything
(it will return you a generator/coroutine object).

This isn't transparent or even remotely
understandable.






For debugging this kind of mistakes there is a special debug mode in

Is the intent to do anything more than preface execution with:
import asynchio.coroutines
asynchio.coroutines._DEBUG = True

This won't work, unfortunately.  You need to set the
debug flag *before* you import asyncio package (otherwise
we would have an unavoidable performance cost for debug
features).  If you enable it after you import asyncio,
then asyncio itself won't be instrumented.  Please
see the implementation of asyncio.coroutine for details.

Why does asynchio itself have to wrapped?  Is that really something
normal developers need to debug, or is it only for developing the
stdlib itself?  If it if only for developing the stdlib, than I
would rather see workarounds like shoving _DEBUG into builtins
when needed, as opposed to adding multiple attributes to sys.



Yes, normal developers need asyncio to be instrumented,
otherwise you won't know what you did wrong when you
called some asyncio code without 'await' for example.


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 and types.coroutine

2015-05-02 Thread Yury Selivanov

On 2015-05-02 1:04 PM, Ethan Furman wrote:

According to https://www.python.org/dev/peps/pep-0492/#id31:

   The [types.coroutine] function applies CO_COROUTINE flag to
   generator-function's code object, making it return a coroutine
   object.

Further down in https://www.python.org/dev/peps/pep-0492/#id32:

[await] uses the yield from implementation with an extra step of
validating its argument. await only accepts an awaitable,
which can be one of:

  ...

  - A generator-based coroutine object returned from a generator
decorated with types.coroutine().

If I'm understanding this correctly, type.coroutine's only purpose is to add
a flag to a generator object so that await will accept it.

This raises the question of why can't await simply accept a generator
object?  There is no code change to the gen obj itself, there is no
behavior change in the gen obj, it's the exact same byte code, only a
flag is different.



Because we don't want 'await' to accept random generators.
It can't do anything meaningful with them, in a world where
all asyncio code is written with new syntax, passing generator
to 'await' is just a bug.

'types.coroutine' is something that we need to ease transition
to the new syntax.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492 and types.coroutine

2015-05-02 Thread Yury Selivanov



On 2015-05-02 2:14 PM, Ethan Furman wrote:

On 05/02, Yury Selivanov wrote:

On 2015-05-02 1:04 PM, Ethan Furman wrote:

If I'm understanding this correctly, type.coroutine's only purpose is to add
a flag to a generator object so that await will accept it.

This raises the question of why can't await simply accept a generator
object?  There is no code change to the gen obj itself, there is no
behavior change in the gen obj, it's the exact same byte code, only a
flag is different.

Because we don't want 'await' to accept random generators.
It can't do anything meaningful with them, in a world where
all asyncio code is written with new syntax, passing generator
to 'await' is just a bug.

And yet in current asyncio code, random generators can be accepted, and not
even the current asyncio.coroutine wrapper can gaurantee that the generator
is a coroutine in fact.


This is a flaw in the current Python that we want to fix.


For that matter, even the new types.coroutine cannot gaurantee that the
returned object is a coroutine and not a generator -- so basically it's just
there to tell the compiler, "yeah, I really know what I'm doing, shut up and
do what I asked."


Well, why would you use it on some generator that is not
a generator-based coroutine?



'types.coroutine' is something that we need to ease transition
to the new syntax.

This doesn't make sense -- either the existing generators are correctly
returning coroutines, in which case the decorator adds nothing, or they
are returning non-coroutines, in which case the decorator adds nothing.

So either way, nothing has been added besides a mandatory boiler-plate
requirement.


It's not nothing; it's backwards compatibility.  Please read
https://www.python.org/dev/peps/pep-0492/#await-expression

@types.coroutine marks generator function that its generator
is awaitable.

Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] PEP 492: async/await in Python; version 5

2015-05-05 Thread Yury Selivanov

Hi python-dev,


Updated version of the PEP is below.

Quick summary of changes:

1. set_coroutine_wrapper and get_coroutine_wrapper functions
are now thread-specific (like settrace etc).

2. Updated Abstract & Rationale sections.

3. RuntimeWarning is always raised when a coroutine wasn't
awaited on. This is in addition to what 'set_coroutine_wrapper'
will/can do.

4. asyncio.async is renamed to asyncio.ensure_future; it will
be deprecated in 3.5.

5. Uses of async/await in CPython codebase are documented.

6. Other small edits and updates.


Thanks,
Yury



PEP: 492
Title: Coroutines with async and await syntax
Version: $Revision$
Last-Modified: $Date$
Author: Yury Selivanov 
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 09-Apr-2015
Python-Version: 3.5
Post-History: 17-Apr-2015, 21-Apr-2015, 27-Apr-2015, 29-Apr-2015,
  05-May-2015


Abstract


The growth of Internet and general connectivity has triggered the
proportionate need for responsive and scalable code.  This proposal
aims to answer that need by making writing explicitly asynchronous,
concurrent Python code easier and more Pythonic.

It is proposed to make *coroutines* a proper standalone concept in
Python, and introduce new supporting syntax.  The ultimate goal
is to help establish a common, easily approachable, mental
model of asynchronous programming in Python and make it as close to
synchronous programming as possible.

We believe that the changes proposed here will help keep Python
relevant and competitive in a quickly growing area of asynchronous
programming, as many other languages have adopted, or are planning to
adopt, similar features: [2]_, [5]_, [6]_, [7]_, [8]_, [10]_.


Rationale and Goals
===

Current Python supports implementing coroutines via generators (PEP
342), further enhanced by the ``yield from`` syntax introduced in PEP
380. This approach has a number of shortcomings:

* It is easy to confuse coroutines with regular generators, since they
  share the same syntax; this is especially true for new developers.

* Whether or not a function is a coroutine is determined by a presence
  of ``yield``  or ``yield from`` statements in its *body*, which can
  lead to unobvious errors when such statements appear in or disappear
  from function body during refactoring.

* Support for asynchronous calls is limited to expressions where
  ``yield`` is allowed syntactically, limiting the usefulness of
  syntactic features, such as ``with`` and ``for`` statements.

This proposal makes coroutines a native Python language feature, and
clearly separates them from generators.  This removes
generator/coroutine ambiguity, and makes it possible to reliably define
coroutines without reliance on a specific library.  This also enables
linters and IDEs to improve static code analysis and refactoring.

Native coroutines and the associated new syntax features make it
possible to define context manager and iteration protocols in
asynchronous terms. As shown later in this proposal, the new ``async
with`` statement lets Python programs perform asynchronous calls when
entering and exiting a runtime context, and the new ``async for``
statement makes it possible to perform asynchronous calls in iterators.


Specification
=

This proposal introduces new syntax and semantics to enhance coroutine
support in Python.

This specification presumes knowledge of the implementation of
coroutines in Python (PEP 342 and PEP 380).  Motivation for the syntax
changes proposed here comes from the asyncio framework (PEP 3156) and
the "Cofunctions" proposal (PEP 3152, now rejected in favor of this
specification).

From this point in this document we use the word *native coroutine* to
refer to functions declared using the new syntax. *generator-based
coroutine* is used where necessary to refer to coroutines that are
based on generator syntax.  *coroutine* is used in contexts where both
definitions are applicable.


New Coroutine Declaration Syntax


The following new syntax is used to declare a *native coroutine*::

async def read_data(db):
pass

Key properties of *coroutines*:

* ``async def`` functions are always coroutines, even if they do not
  contain ``await`` expressions.

* It is a ``SyntaxError`` to have ``yield`` or ``yield from``
  expressions in an ``async`` function.

* Internally, two new code object flags were introduced:

  - ``CO_COROUTINE`` is used to enable runtime detection of
*coroutines* (and migrating existing code).

  - ``CO_NATIVE_COROUTINE`` is used to mark *native coroutines*
(defined with new syntax.)

  All coroutines have ``CO_COROUTINE``, ``CO_NATIVE_COROUTINE``, and
  ``CO_GENERATOR`` flags set.

* Regular generators, when called, return a *generator object*;
  similarly, coroutines return a *coroutine object*.

* ``StopIteration`` exceptions are not propagated out of coroutines,
  and are r

Re: [Python-Dev] PEP 492: What is the real goal?

2015-05-05 Thread Yury Selivanov

Hi Oscar,

I've updated the PEP with some fixes of the terminology:
https://hg.python.org/peps/rev/f156b272f860

I still think that 'coroutine functions' and 'coroutines'
is a better pair than 'async functions' and 'coroutines'.

First, it's similar to existing terminology for generators.
Second, it's less confusing.  With pep492 at some point,
using generators to implement coroutines won't be a wide
spread practice, so 'async def' functions will be the only
language construct that returns them.

Yury

On 2015-05-05 12:01 PM, Oscar Benjamin wrote:

On 30 April 2015 at 09:50, Arnaud Delobelle  wrote:

I'm flexible about how we name 'async def' functions.  I like
to call them "coroutines", because that's what they are, and
that's how asyncio calls them.  It's also convenient to use
'coroutine-object' to explain what is the result of calling
a coroutine.

I'd like the object created by an 'async def' statement to be called a
'coroutine function' and the result of calling it to be called a
'coroutine'.

That would be an improvement over the confusing terminology in the PEP
atm. The PEP proposes to name the inspect functions
inspect.iscoroutine() and inspect.iscoroutinefunction(). According to
the PEP iscoroutine() identifies "coroutine objects" and
iscoroutinefunction() identifies "coroutine functions" -- a term which
is not defined in the PEP but presumably means what the PEP calls a
"coroutine" in the glossary.

Calling the async def function an "async function" and the object it
returns a "coroutine" makes for the clearest terminology IMO (provided
the word coroutine is not also used for anything else). It would help
to prevent both experienced and new users from confusing the two
related but necessarily distinct concepts. Clearly distinct
terminology makes it easier to explain/discuss something if nothing
else because it saves repeating definitions all the time.


--
Oscar


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-05 Thread Yury Selivanov

Hi Wolfgang,


On 2015-05-05 7:27 AM, Wolfgang wrote:

Hi,

[..]

Even the discussion on python-dev suggests there is some time needed
to finalize all this.


I'd say that:

80% of the recent discussion of the PEP is about terminology.
10% is about whether we should have __future__ import or not.



We forget to address the major problems here. How can someone in a
"sync" script use this async stuff easy. How can async and sync stuff
cooperate and we don't need to rewrite the world for async stuff.
How can a normal user access the power of async stuff without rewriting
all his code. So he can use a simple asyc request library in his code.
How can a normal user learn and use all this in an easy way.


asyncio and twisted answered these questions ;) The answer is
that you have to write async implementations.

gevent has a different answer, but greenlents/stackless is
something that will never be merged in CPython and other
implementations.



And for all this we still can't tell them "oh the async stuff solves
the multiprocessing problem of Python learn it and switch to version
3.5". It does not and it is only most useful for networking stuff
nothing more.


"networking stuff", and in particular, web, is a huge
part of current Python usage.  Please don't underestimate
that.


Thanks,
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-05 Thread Yury Selivanov

Paul,

On 2015-05-05 3:14 PM, Paul Moore wrote:

On 5 May 2015 at 19:25, Yury Selivanov  wrote:

On 2015-05-05 7:27 AM, Wolfgang wrote:

Even the discussion on python-dev suggests there is some time needed
to finalize all this.

I'd say that:

80% of the recent discussion of the PEP is about terminology.
10% is about whether we should have __future__ import or not.

But the terminology discussion appears to revolve around people
finding the various concepts involved in asyncio (particularly the new
PEP, but also to an extent the existing implementation) confusing. I
can confirm, having tried to work through the asyncio docs, that the
underlying concepts and how they are explained, are confusing to an
outsider.


I agree. We have to improve asyncio docs in this area.



That's not to say that everything needs to be beginner-friendly, but
it *does* mean that it's hard for the wider Python community to
meaningfully comment, or evaluate or sanity-check the design. We're
left with a sense of "trust us, it makes sense if you need it,
everyone else can ignore it".

Personally, I feel as if PEP 492 is looking a little premature - maybe
the focus should be on making asyncio more accessible first, and
*then* adding syntax. You can argue that the syntax is needed to help
make async more accessible - but if that's the case then the
terminology debates and confusion are clear evidence that it's not
succeeding in that goal. Of course, that's based on my perception of
one of the goals of the PEP as being "make coroutines and asyncio more
accessible", If the actual goals are different, my conclusion is
invalid.


Again, PEP 492 is not only for asyncio. *Any* framework can
use it, including Twisted.

As for terminology, I view this discussion differently.  It's
not about the technical details (Python has asymmetric
coroutines, that's it), but rather on how to disambiguate
coroutines implemented with generators and yield-from, from
new 'async def' coroutines.  I can't see any fundamental
problem with the PEP behind such discussions.




We forget to address the major problems here. How can someone in a
"sync" script use this async stuff easy. How can async and sync stuff
cooperate and we don't need to rewrite the world for async stuff.
How can a normal user access the power of async stuff without rewriting
all his code. So he can use a simple asyc request library in his code.
How can a normal user learn and use all this in an easy way.

asyncio and twisted answered these questions ;) The answer is
that you have to write async implementations.

Well, twisted always had defer_to_thread. Asyncio has run_in_executor,
but that seems to be callback-based rather than coroutine-based?

Many people use requests for their web access. There are good reasons
for this. Are you saying that until someone steps up and writes an
async implementation of requests, I have to make a choice - requests
or asyncio? Unfortunately, I can't see myself choosing asyncio in that
situation. Which again means that asyncio becomes "something that the
average user can't use". Which in turn further entrenches it as a
specialist-only tool.


There is aiohttp library [1], which provides a client API
similar to requests.

And if you want to write high performance networking server
in python3 you *will* choose asyncio (or gevent/twisted
in python2).

And PEP 492 is aimed to make this whole async stuff more
accessible to an average user.



As another example, in Twisted I could use defer_to_thread to
integrate Oracle database access into a twisted application (that's
what the twisted database stuff did under the hood). Can I do that
with asyncio? Will the syntax in the PEP help, hinder or be irrelevant
to that?


You can use 'loop.run_in_executor' in asyncio. It returns a
future that you can await on.  You can also provide a nice
facade for your Oracle-database code that provides a nice
API but uses asyncio thread executor behind the scenes.




And for all this we still can't tell them "oh the async stuff solves
the multiprocessing problem of Python learn it and switch to version
3.5". It does not and it is only most useful for networking stuff
nothing more.

"networking stuff", and in particular, web, is a huge
part of current Python usage.  Please don't underestimate
that.

Without async versions of requests and similar, how much of a chunk of
the networking/web area will asyncio take? (Genuine question, I have
no idea).


There are some things (like websockets) that are hard
to implement correctly in existing frameworks like django
and flask.  And these kind of things are becoming more
and more important.  Languages like Go were designed
specifically to allow writing efficient


And how much extra will this PEP add? Those may not be fair
questions (and even if they are fair, the answers are probabl

Re: [Python-Dev] PEP 492: async/await in Python; version 5

2015-05-05 Thread Yury Selivanov



On 2015-05-05 3:40 PM, Jim J. Jewett wrote:

On Tue May 5 18:29:44 CEST 2015, Yury Selivanov posted an updated PEP492.

Where are the following over-simplifications wrong?

(1)  The PEP is intended for use (almost exclusively) with
asychronous IO and a scheduler such as the asynchio event loop.


Yes. You can also use it for UI loops.  Basically, anything
that can call your code asynchronously.



(2)  The new syntax is intended to make it easier to recognize when
a task's execution may be interrupted by arbitrary other tasks, and
the interrupted task therefore has to revalidate assumptions about
shared data.

With threads, CPython can always suspend a task between op-codes,
but with a sufficiently comprehensive loop (and sufficiently
coooperative tasks), tasks *should* only be suspended when they
make an explicit request to *wait* for an answer, and these points
*should* be marked syntactically.

(3)  The new constructs explicitly do NOT support any sort of
concurrent execution within a task; they are for use precisely
when otherwise parallel subtasks are being linearized by pausing
and waiting for the results.


Yes.



Over-simplifications 4-6 assume a world with standardized futures
based on concurrent.futures, where .result either returns the
result or raises the exception (or raises another exception about
timeout or cancellation).

[Note that the actual PEP uses iteration over the results of a new
__await__ magic method, rather than .result on the object itself.
I couldn't tell whether this was for explicit marking, or just for
efficiency in avoiding future creation.]

(4)  "await EXPR" is just syntactic sugar for EXPR.result

except that, by being syntax, it better marks locations where
unrelated tasks might have a chance to change shared data.

[And that, as currently planned, the result of an await isn't
actually the result; it is an iterator of results.]


I'm not sure how to comment on (4).  Perhaps I don't
understand some notation that you're using.  If anything,
it's more of a syntactic sugar for 'yield from EXPR'.



(5)  "async def" is just syntactic sugar for "def",

except that, by being syntax, it better marks the signatures of
functions and methods where unrelated tasks might have a chance
to change shared data after execution has already begun.


It also sets "CO_COROUTINE | CO_GENERATOR" flags, that
are very important.



(5A) As the PEP currently stands, it is also a promise that the
function will NOT produce a generator used as an iterator; if a
generator-iterator needs to wait for something else at some point,
that will need to be done differently.

I derive this limitation from
"It is a ``SyntaxError`` to have ``yield`` or ``yield from``
 expressions in an ``async`` function."

but I don't understand how this limitation works with things like a
per-line file iterator that might need to wait for the file to
be initially opened.


Per-line file iterator can be implemented with __aiter__,
__anext__ protocol.  __aiter__ is a coroutine, you can
open/start reading your file there.



(6)  async with EXPR as VAR:

would be equivalent to:

 with EXPR as VAR:

except that
   __enter__() would be replaced by next(await __enter__()) # __enter__().result
   __exit__() would be replaced by  next(await __exit__())  # __exit__().result


I'm not sure I understand what you mean by
"next(await EXPR)" notation.


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-05 Thread Yury Selivanov

On 2015-05-05 4:39 PM, Paul Moore wrote:

Is there anyone who feels they could write a stripped down but working
example of a valid Python event loop*without*  the asyncio aspects? Or
is that what David Beazley's talk does?

Yes, in David's talk, where he starts to use 'yield from' you
can simply use new coroutines.


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 5

2015-05-05 Thread Yury Selivanov

On 2015-05-05 5:01 PM, Paul Moore wrote:

On 5 May 2015 at 21:00, Yury Selivanov  wrote:

On 2015-05-05 3:40 PM, Jim J. Jewett wrote:

On Tue May 5 18:29:44 CEST 2015, Yury Selivanov posted an updated PEP492.

Where are the following over-simplifications wrong?

(1)  The PEP is intended for use (almost exclusively) with
asychronous IO and a scheduler such as the asynchio event loop.

Yes. You can also use it for UI loops.  Basically, anything
that can call your code asynchronously.

Given that the stdlib doesn't provide an example of such a UI loop,
what would a 3rd party module need to implement to provide such a
thing? Can any of the non-IO related parts of asyncio be reused for
the purpose, or must the 3rd party module implement everything from
scratch?


The idea is that you integrate processing of UI events to
your event loop of choice.  For instance, Twisted has
integration for QT and other libraries [1].  This way you
can easily combine async network (or OS) calls with your
UI logic to avoid "callback hell".

Quick search for something like that for asyncio revealed
this library: [2].  This small library actually re-implements
relevant low-level parts of the asyncio event loop on top of
QT primitives (another approach).

Yury

[1] http://twistedmatrix.com/trac/wiki/QTReactor
[2] https://github.com/harvimt/quamash#usage -- see first_50
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 4

2015-05-05 Thread Yury Selivanov



On 2015-05-05 5:31 PM, Jim J. Jewett wrote:

Tue May 5 21:48:36 CEST 2015, Yury Selivanov wrote:


>As for terminology, I view this discussion differently.  It's
>not about the technical details (Python has asymmetric
>coroutines, that's it), but rather on how to disambiguate
>coroutines implemented with generators and yield-from, from
>new 'async def' coroutines.

Not just "How?", but "Why?".

Why do they*need*  to be disambiguated?


To clearly show how one interacts with the other, to explain
how backwards compatibility is implemented, and to better
illustrate some additional (and necessary) restrictions
we put on 'async def' coroutines.  Otherwise, the PEP would
be completely unreadable :)


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 5

2015-05-05 Thread Yury Selivanov

Paul,

On 2015-05-05 5:54 PM, Paul Moore wrote:

On 5 May 2015 at 22:38, Yury Selivanov  wrote:

n 2015-05-05 5:01 PM, Paul Moore wrote:

On 5 May 2015 at 21:00, Yury Selivanov  wrote:

On 2015-05-05 3:40 PM, Jim J. Jewett wrote:

On Tue May 5 18:29:44 CEST 2015, Yury Selivanov posted an updated
PEP492.

Where are the following over-simplifications wrong?

(1)  The PEP is intended for use (almost exclusively) with
asychronous IO and a scheduler such as the asynchio event loop.

Yes. You can also use it for UI loops.  Basically, anything
that can call your code asynchronously.

Given that the stdlib doesn't provide an example of such a UI loop,
what would a 3rd party module need to implement to provide such a
thing? Can any of the non-IO related parts of asyncio be reused for
the purpose, or must the 3rd party module implement everything from
scratch?

The idea is that you integrate processing of UI events to
your event loop of choice.  For instance, Twisted has
integration for QT and other libraries [1].  This way you
can easily combine async network (or OS) calls with your
UI logic to avoid "callback hell".

We seem to be talking at cross purposes. You say the PEP is *not*
exclusively intended for use with asyncio. You mention UI loops, but
when asked how to implement such a loop, you say that I integrate UI
events into my event loop of choice. But what options do I have for
"my event loop of choice"? Please provide a concrete example that
isn't asyncio.


Yes, there is no other popular event loop for 3.4 other
than asyncio, that uses coroutines based on generators
(as far as I know).

And yes, the PEP is not exclusively intended for use
with asyncio, but asyncio is the only library that ships
with Python, and is Python 3 ready, so its users will be
the first ones to directly benefit from this proposal.


Can I use PEP 492 with Twisted (I doubt it, as Twisted
doesn't use yield from, which is Python 3.x only)? I contend that
there *is* no concrete example that currently exists, so I'm asking
what I'd need to do to write one. You pointed at qamash, but that
seems to be subclassing asyncio, so isn't "something that isn't
asyncio".


When Twisted is ported to Python 3, I'd be really surprised
if it doesn't allow to use the new syntax.  @inlineCallbacks
implements a trampoline to make 'yields' work.  This is a
much slower approach than using 'yield from' (and 'await'
from PEP 492).  Not mentioning 'async with' and 'async for'
features.  (There shouldn't be a problem to support both
@inlineCallbacks and PEP 492 approach, if I'm not missing
something).



Note that I don't have a problem with there being no existing
implementation other than asyncio. I'd just like it if we could be
clear over exactly what we mean when we say "the PEP is not tied to
asyncio".



Well, "the PEP is not tied to asyncio" -- this is correct.
*The new syntax and new protocols know nothing about asyncio*.

asyncio will know about the PEP by implementing new protocols
where required etc (but supporting these new features isn't
in the scope of the PEP).



It feels like the truth currently is "you can write your own
async framework that uses the new features introduced by the PEP". I
fully expect that *if* there's a need for async frameworks that aren't
fundamentally IO multiplexors, then it'll get easier to write them
over time (the main problem right now is a lack of good tutorial
examples of how to do so). But at the moment, asyncio seems to be the
only game in town (and I can imagine that it'll always be the main IO
multiplexor, unless existing frameworks like Twisted choose to compete
rather than integrate).


Agree.  But if the existing frameworks choose to compete,
or someone decides to write something better than asyncio,
they can benefit from PEP 492.


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: Please mention the Event Loop

2015-05-05 Thread Yury Selivanov

Jim,

On 2015-05-05 5:09 PM, Jim J. Jewett wrote:

On Tue May 5 21:44:26 CEST 2015,Brett Cannon wrote:


It's not as
complicated as it seems when you realize there is an event loop driving
everything (which people have been leaving out of the conversation since it
doesn't tie into the syntax directly).

[..]

Proposed second paragraph of the abstract:

This PEP assumes that the asynchronous tasks are scheduled and
coordinated by an Event Loop similar to that of stdlib module
asyncio.events.AbstractEventLoop.  While the PEP is not tied to
any specific Event Loop implementation, it is relevant only to
the kind of coroutine that uses "yield" as a signal to the scheduler,
indicating that the coroutine will be waiting until an event (such
as IO) is completed.




Thank you for this suggestion.  I've added it to the PEP:
https://hg.python.org/peps/rev/7ac132b24f1f


Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Accepting PEP 492 (async/await)

2015-05-05 Thread Yury Selivanov

On 2015-05-05 7:53 PM, Guido van Rossum wrote:

Everybody,

In order to save myself a major headache I'm hereby accepting PEP 492.

I've been following Yury's efforts carefully and I am fully confident that
we're doing the right thing here. There is only so much effort we can put
into clarifying terminology and explaining coroutines. Somebody should
write a tutorial. (I started to write one, but I ran out of time after just
describing basic yield.)




Thank you, Guido!
Yury
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 492: async/await in Python; version 5

2015-05-06 Thread Yury Selivanov

Hi Ben,

On 2015-05-06 12:05 AM, Ben Darnell wrote:

On Tue, May 5, 2015 at 3:25 PM, Yury Selivanov 
wrote:


Yes, there is no other popular event loop for 3.4 other
than asyncio, that uses coroutines based on generators
(as far as I know).


Tornado supports Python 3.4 and uses generator-based coroutines. We use
`yield` instead of `yield from` for compatibility with Python 2. I have a
patch to support the new async/await syntax here:
https://github.com/bdarnell/tornado/commit/e3b71c3441e9f87a29a9b112901b7644b5b6edb8


I don't know how this happened, especially since I've used
Tornado myself!  It's amazing that Tornado will have support
of async/await when 3.5 is out!



Overall, I like the PEP. I've been reluctant to embrace `yield from` for
Tornado coroutines (Tornado's Futures do not implement `__iter__`) because
I'm worried about confusion between `yield` and `yield from`, but async and
await are explicit enough that that's not really a problem.

My one request would be that there be a type or ABC corresponding to
inspect.isawaitable(). Tornado uses functools.singledispatch to handle
interoperability with other coroutine frameworks, so it would be best if we
could distinguish awaitables from other objects in a way that is compatible
with singledispatch. The patch above simply registers types.GeneratorType
which isn't quite correct.



Sure. I'll add Awaitable and Coroutine ABCs.

Thanks,
Yury

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


  1   2   3   4   5   6   >