brython-dev / brython

Brython (Browser Python) is an implementation of Python 3 running in the browser
BSD 3-Clause "New" or "Revised" License
6.38k stars 510 forks source link

Python language level support (3.4/3.5/3.6/3.7) #623

Closed perkinslr closed 4 years ago

perkinslr commented 7 years ago

Python3.4

Done

bpo-15958: bytes.join and bytearray.join with arbitrary buffer objects (memoryview).

Probably Easy

pep 424: object.__length_hint__ is used by operator.length_hint if the length can't be directly obtained

Unknown

pep 3156: Get asyncio to import properly (see issue #616 )

Python3.5

Done

pep 448: Allow multiple * and ** unpacking pep 448: Allow * and ** unpacking inside list, tuple, set, and dict literals.

Partial

pep 465: matrix multiplication operator a @ b currently supports __matmult__ and __imatmult__ but not __rmatmult__

Probably Easy

Pep 461: % formatting for bytes and bytearray bpo-9951: bytes.hex(), bytearray.hex() bpo-19235: RecursionError instead of RuntimeError on too much recursion

Unknown

bpo-9951: memoryview.hex() memoryview raises NotImplemented pep 492: async and await syntax bpo-24450: gi_yieldfrom attribute of generators returns inner iterables used by yield from PEP 479: generator_stop future import, which causes a RuntimeError if a generator throws StopIteration instead of returning

Python3.6

Done

pep 498: Format strings pep 468: Preserve keyword argument order -- dicts preserve str key insertion order, but not int key insertion order. This is fine since dicts preserving key insertion order is an implementation detail of CPython 3.6. Preserving the string key insertion order means keyword argument order is properly preserved. pep 515: Ignore underscores in numeric literals

Probably Easy

pep 487: Call __init_subclass__() on new class creation, call __set_name__() on attributes implementing the descriptor protocol. Might be a bit tricky to get argumentless super() to work properly.

Unknown

pep 526: Syntax for variable annotations pep 525: Asynchronous generators pep 530: Asynchronous comprehensions

Python3.7

Done

async and await are now reserved keywords New Module: contextvars

Probably Easy

pep 563: Postpone evaluating type annotations pep 562: Allow __getattr__ at module level

Unknown

New Module: dataclasses fails to import with the same error as asyncio: ImportError: cannot import name 'unicode_iscased' (from _sre_utils)

Python3.8

Probably Easy

bpo-32489: Allow continue in finally clause bpo-33073: Add as_integer_ratio to int type. bpo-32117: Allow iterable unpacking in yield and return statements without parenthesis.

jonathanverner commented 7 years ago

Regarding async stuff:

  1. fixing asyncio should not be too hard, I am looking into it (see my comment on the #616 issue)
  2. async/await syntax should be doable, but will require deeper knowledge of the python parser than I have; @PierreQuentel would probably be able to help, but he is not very comfortable with async stuff and I think he doesn't like it very much :-)
  3. async generators & comprehensions (should be doable, except for point 2. above)
kikocorreoso commented 7 years ago

pep 465: matrix multiplication operator a @ b

I think this is only useful for numpy. __[r][i]matmul__ are only useful in this context so, maybe, this is not very prioritary.

I have a dream of a num[br]y lib with, at least, the array container and not the full blas/lapack and other functionality using typed arrays. The performance would be far from numpy. I experimented with this in the past but a 1:1 numpy array container using typed arrays was far from real. Maybe it is better to wait for a wasm implementation.

pep 515: Ignore underscores in numeric literals

I started working on this but it was a while ago and I will not come back to my desktop computer until the end of the month... And my work was very preliminar.

PierreQuentel commented 7 years ago

Very interesting ! It show you have a very good knowledge of Brython :-)

A few comments :

perkinslr commented 7 years ago

Ah, I missed that PEP 448 included unpacking inside lists, tuples, sets, and dicts. Using multiple * and ** in the same function call works as expected.

Interesting, neither memoryview nor vars raise NameError when trying to access them, memoryview even reports being a builtin function. Trying to call it fails.

There's also a proof of concept implementation of numpy in the browser via emscripten, it would take quite a bit of work to integrate with brython though. The matrix multiplication operator is more likely to be useful when implementing DSLs, which I suspect will be its main use in python in general. It gives an operator that doesn't do anything most of the time, so you aren't causing the weirdness you get when you overload __add__ et cetera.

Browser programming is already heavily asynchronous, I'm not sure what use there might be for it with node.js. Probably the best course is to make it somehow useful either with setTimeout or resource loading (XMLHttpRequests). I use twisted for most everything server-side, so I've not ever had much use for async/await, so I'll leave that to someone who actually uses them to figure out how they might apply in javascript.

jonathanverner commented 7 years ago

Re async features: I think these are actually very relevant in the browser. They can be used to avoid JavaScript callback hell (even JavaScript is getting async/await support): suppose, for example, that we want to chain a few AJAX calls, say we want to retrieve a list of friends of someone. The api allows us to find a user-id by his name, a list of friend_ids by user id and user info by id. Normal callback style would look something like this:


friend_list = []

def getUserID(username):
    req = XMLHttpRequest()
    req.get(api+'/'+user_name, getFriends)

def getFriends(user_id)
    req  = XMLHttpRequest()
    req.get(friend_list_url+'/+'user_id, getNames)

def getName(id_list):
     for id in id_list:
          req = XMLHttpRequest()
          req.get(api+'/user/'+id, lambda x: friend_list.append(x.name))

Compared with async style:


async def friend_list(name):
    ret = []
    id = await XMLHttpRequest(api+'/'+user_name)
    friend_ids = await XMLHttpRequest(riend_list_url+'/+'user_id)
    for id in friend_ids:
       friend = await XMLHttpRequest(api+'/user/'+id)
       ret.append(friend.name)
    return ret

The beauty of the async version (in my opinion at least) is that it is written as if the AJAX requests were synchronous. However, unlike synchronous requests, the async version doesn't block the browser at all! Now all of this is doable with a little bit of generator magic which can already be implemented (see my port of asyncio, or the, hopefully coming soon, simpleaio rewrite) in Brython. The only difficult part (at least for me) is the syntactic sugar of being able to write

async def func():
    ...

instead of the more verbose

@coroutine
def func():
    ...

and

x = await func()

instead of

x = yield from func()

There are other async-related things, which would be nice to have:

but these are not needed for compatibility with newer Python versions. And even here I am optimistic. It seems to me that async imports wouldn't be too much harder than the recent changes (108f633590b74260dd361cd, 3a904a6852bdfc8ee840e8) Pierre made to input handling. But then again, I might be mistaken, I haven't really gotten familiar enough with Brython's compilation engine to try to implement it on my own. As far as webworkers are concerned, the main obstacle is that they don't have access to the dom. But this shouldn't be insurmountable...

Anyway, it seems that my comment has grown far too much and is probably off-topic. Do you think it makes sense to open a discussion on the google groups?

perkinslr commented 7 years ago

I figured this issue would serve as a central hub for discussing the implementation of any of these. It might make sense to open a separate ticket for anything that's being actively worked on, or if the discussion is likely to be prolonged. As things change, I'll edit the initial post. Comments which are no longer relevant might need deleting eventually, just to keep the ticket manageable.

kikocorreoso commented 7 years ago

for Numpy, there is a new pure-Python implementation, tinynumpy. I didn't test if it works with Brython but it might be a solution

Tinynumpy has some years and it depends on ctypes so it is not usable with brython without modifications. I've already checked that in the past ;-) I think a pure python implementation would be extremely slow :-(

There is some work done in the skulpt world also...

PierreQuentel commented 6 years ago

Resuming work on this old issue...

The commit referenced above makes bytes.join() and bytearray.join() work with memoryview and bytearray objects. PEP 424 already works.

perkinslr commented 6 years ago

I've updated the first post to reflect the progress made. Note that the @ operator support is incomplete, __matmul__ and __imatmul__ work, but __rmatmul__ does not.

PierreQuentel commented 4 years ago

I am closing this (very old) issue after a series of commit that implement most of the missing features.

I keep these ones for an undetermined future : bpo-24450: gi_yieldfrom attribute of generators returns inner iterables used by yield from PEP 479: generator_stop future import, which causes a RuntimeError if a generator throws StopIteration instead of returning bpo-32489: Allow continue in finally clause (the decision is not clear, cf. discussion in https://github.com/python/cpython/pull/15230)