Content-Length: 489802 | pFad | http://github.com/python/cpython/pull/18817/commits/b7dce732b3b6f38f3fa7764700020180e867b5a5

2C gh-76785: Multiple Interpreters in the Stdlib (PEP 554) by nanjekyejoannah · Pull Request #18817 · python/cpython · GitHub
Skip to content

gh-76785: Multiple Interpreters in the Stdlib (PEP 554) #18817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix tests
  • Loading branch information
nanjekyejoannah committed Mar 3, 2020
commit b7dce732b3b6f38f3fa7764700020180e867b5a5
107 changes: 53 additions & 54 deletions Lib/interpreters.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
"""Subinterpreters High Level Module."""

import _interpreters
import logger
import logging

__all__ = ['Interpreter', 'SendChannel', 'RecvChannel', 'is_shareable',
'create_channel', 'list_all_channels', 'list_all', 'get_current',
'create']


def create():
""" create() -> Interpreter

Initialize a new (idle) Python interpreter.
"""
id = _interpreters.create()
return Interpreter(id)

def list_all():
""" list_all() -> [Interpreter]

Get all existing interpreters.
"""
return [Interpreter(id) for id in _interpreters.list_all()]

def get_current():
""" get_current() -> Interpreter

Get the currently running interpreter.
"""
id = _interpreters.get_current()
return Interpreter(id)


class Interpreter:

def __init__(self, id):
Expand Down Expand Up @@ -42,6 +66,32 @@ def run(self, src_str, /, *, channels=None):
logger.error(err)
raise


def is_shareable(obj):
""" is_shareable(obj) -> Bool

Return `True` if the object's data can be shared between
interpreters.
"""
return _interpreters.is_shareable(obj)

def create_channel():
""" create_channel() -> (RecvChannel, SendChannel)

Create a new channel for passing data between interpreters.
"""

cid = _interpreters.channel_create()
return (RecvChannel(cid), SendChannel(cid))

def list_all_channels():
""" list_all_channels() -> [(RecvChannel, SendChannel)]

Return all open channels.
"""
cid = _interpreters.channel_list_all()
return (RecvChannel(cid), SendChannel(cid))

def wait(self, timeout):
#The implementation for wait
# will be non trivial to be useful
Expand All @@ -55,7 +105,7 @@ class RecvChannel:

def __init__(self, id):
self.id = id
self.interpreters = _interpreters.list_all()
self.interpreters = _interpreters.channel_list_interpreters(cid, send=False)

def recv(self, timeout=2):
""" channel_recv() -> obj
Expand Down Expand Up @@ -102,7 +152,7 @@ def release(self):
No longer associate the current interpreterwith the channel
(on the sending end).
"""
return _interpreters.(self.id)
return _interpreters(self.id)

def close(self, force=False):
"""close(force=False)
Expand Down Expand Up @@ -187,54 +237,3 @@ class ChannelReleasedError(ChannelClosedError):

class RunFailedError(RuntimeError):
pass


# Global API functions

def is_shareable(obj):
""" is_shareable(obj) -> Bool

Return `True` if the object's data can be shared between
interpreters.
"""
return _interpreters.is_shareable(obj)

def create_channel():
""" create_channel() -> (RecvChannel, SendChannel)

Create a new channel for passing data between interpreters.
"""

cid = _interpreters.channel_create()
return (RecvChannel(cid), SendChannel(cid))

def list_all_channels():
""" list_all_channels() -> [(RecvChannel, SendChannel)]

Return all open channels.
"""
cid = _interpreters.channel_list_all()
return (RecvChannel(cid), SendChannel(cid))

def create():
""" create() -> Interpreter

Initialize a new (idle) Python interpreter.
"""
id = _interpreters.create()
return Interpreter(id)

def list_all():
""" list_all() -> [Interpreter]

Get all existing interpreters.
"""
return [Interpreter(id) for id in _interpreters.list_all()]

def get_current():
""" get_current() -> Interpreter

Get the currently running interpreter.
"""
id = _interpreters.get_current()
return Interpreter(id)
98 changes: 98 additions & 0 deletions Lib/test/test__xxsubinterpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,87 @@ def test_ids_global(self):

self.assertEqual(cid2, int(cid1) + 1)

def test_channel_list_interpreters_none(self):
"""Test listing interpreters for a channel with no associations."""
# Test for channel with no associated interpreters.
cid = interpreters.channel_create()
send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
self.assertEqual(send_interps, [])
self.assertEqual(recv_interps, [])

def test_channel_list_interpreters_basic(self):
"""Test basic listing channel interpreters."""
interp0 = interpreters.get_main()
cid = interpreters.channel_create()
interpreters.channel_send(cid, "send")
# Test for a channel that has one end associated to an interpreter.
send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
self.assertEqual(send_interps, [interp0])
self.assertEqual(recv_interps, [])

interp1 = interpreters.create()
_run_output(interp1, dedent(f"""
import _interpreters
obj = _interpreters.channel_recv({cid})
"""))
# Test for channel that has boths ends associated to an interpreter.
send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
self.assertEqual(send_interps, [interp0])
self.assertEqual(recv_interps, [interp1])

def test_channel_list_interpreters_multiple(self):
"""Test listing interpreters for a channel with many associations."""
interp0 = interpreters.get_main()
interp1 = interpreters.create()
interp2 = interpreters.create()
interp3 = interpreters.create()
cid = interpreters.channel_create()

interpreters.channel_send(cid, "send")
_run_output(interp1, dedent(f"""
import _interpreters
obj = _interpreters.channel_send({cid}, "send")
"""))
_run_output(interp2, dedent(f"""
import _interpreters
obj = _interpreters.channel_recv({cid})
"""))
_run_output(interp3, dedent(f"""
import _interpreters
obj = _interpreters.channel_recv({cid})
"""))
send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
self.assertEqual(set(send_interps), {interp0, interp1})
self.assertEqual(set(recv_interps), {interp2, interp3})

@unittest.skip("Failing due to handling of destroyed interpreters")
def test_channel_list_interpreters_destroyed(self):
"""Test listing channel interpreters with a destroyed interpreter."""
interp0 = interpreters.get_main()
interp1 = interpreters.create()
cid = interpreters.channel_create()
interpreters.channel_send(cid, "send")
_run_output(interp1, dedent(f"""
import _interpreters
obj = _interpreters.channel_recv({cid})
"""))
# Should be one interpreter associated with each end.
send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
self.assertEqual(send_interps, [interp0])
self.assertEqual(recv_interps, [interp1])

interpreters.destroy(interp1)
# Destroyed interpreter should not be listed.
send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
self.assertEqual(send_interps, [interp0])
self.assertEqual(recv_interps, [])

####################

def test_send_recv_main(self):
Expand Down Expand Up @@ -1519,6 +1600,23 @@ def test_close_used_multiple_times_by_single_user(self):
with self.assertRaises(interpreters.ChannelClosedError):
interpreters.channel_recv(cid)

def test_channel_list_interpreters_invalid_channel(self):
cid = interpreters.channel_create()
# Test for invalid channel ID.
with self.assertRaises(interpreters.ChannelNotFoundError):
interpreters.channel_list_interpreters(1000, send=True)

interpreters.channel_close(cid)
# Test for a channel that has been closed.
with self.assertRaises(interpreters.ChannelClosedError):
interpreters.channel_list_interpreters(cid, send=True)

def test_channel_list_interpreters_invalid_args(self):
# Tests for invalid arguments passed to the API.
cid = interpreters.channel_create()
with self.assertRaises(TypeError):
interpreters.channel_list_interpreters(cid)


class ChannelReleaseTests(TestBase):

Expand Down
Loading








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/python/cpython/pull/18817/commits/b7dce732b3b6f38f3fa7764700020180e867b5a5

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy