Skip to content
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

Remove deprecated BlockingTrioPortal #1574

Merged
merged 5 commits into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions newsfragments/1574.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove ``BlockingTrioPortal``: it was deprecated in 0.12.0.
5 changes: 0 additions & 5 deletions trio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@
Condition,
)

from ._threads import BlockingTrioPortal as _BlockingTrioPortal

from ._highlevel_generic import aclose_forcefully, StapledStream

from ._channel import (
Expand Down Expand Up @@ -134,9 +132,6 @@
"current_default_worker_thread_limiter": _deprecate.DeprecatedAttribute(
to_thread.current_default_thread_limiter, "0.12.0", issue=810,
),
"BlockingTrioPortal": _deprecate.DeprecatedAttribute(
_BlockingTrioPortal, "0.12.0", issue=810, instead=from_thread,
),
# NOTE: when you remove this, you should also remove the file
# trio/hazmat.py. For details on why we have both, see:
#
Expand Down
19 changes: 1 addition & 18 deletions trio/_threads.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,6 @@
# Global due to Threading API, thread local storage for trio token
TOKEN_LOCAL = threading.local()


class BlockingTrioPortal:
def __init__(self, trio_token=None):
if trio_token is None:
trio_token = trio.lowlevel.current_trio_token()
self._trio_token = trio_token

def run(self, afn, *args):
return from_thread_run(afn, *args, trio_token=self._trio_token)

def run_sync(self, fn, *args):
return from_thread_run_sync(fn, *args, trio_token=self._trio_token)


_limiter_local = RunVar("limiter")
# I pulled this number out of the air; it isn't based on anything. Probably we
# should make some kind of measurements to pick a good value.
Expand Down Expand Up @@ -227,10 +213,7 @@ def _run_fn_as_system_task(cb, fn, *args, trio_token=None):
"this thread wasn't created by Trio, pass kwarg trio_token=..."
)

# TODO: This is only necessary for compatibility with BlockingTrioPortal.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might still need this for the case where the user passes the trio_token?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea, I just grepped for BlockingTrioPortal, but I'm not familiar with those APIs. @njsmith Can you please confirm?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @oremanj is right. The test case would be something like:

async def test():
    trio_token = trio.lowlevel.current_trio_token()
    with pytest.raises(RuntimeError):
        trio.from_thread.run_sync(lambda: None, trio_token=trio_token)

If we fail to detect we're calling from_thread inside the Trio thread, then this will deadlock.

# once that is deprecated, this check should no longer be necessary because
# thread local storage (or the absence of) is sufficient to check if trio
# is running in a thread or not.
# Avoid deadlock by making sure we're not called from Trio thread
try:
trio.lowlevel.current_task()
except RuntimeError:
Expand Down
6 changes: 4 additions & 2 deletions trio/tests/test_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def test_core_is_properly_reexported():
def public_modules(module):
yield module
for name, class_ in module.__dict__.items():
if name.startswith("_"):
# Deprecated classes are exported with a leading underscore
if name.startswith("_"): # pragma: nocover
continue
if not isinstance(class_, types.ModuleType):
continue
Expand Down Expand Up @@ -118,7 +119,8 @@ def test_classes_are_final():
for name, class_ in module.__dict__.items():
if not isinstance(class_, type):
continue
if name.startswith("_"):
# Deprecated classes are exported with a leading underscore
if name.startswith("_"): # pragma: nocover
continue

# Abstract classes can be subclassed, because that's the whole
Expand Down
41 changes: 5 additions & 36 deletions trio/tests/test_threads.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
current_default_thread_limiter,
from_thread_run,
from_thread_run_sync,
BlockingTrioPortal,
)

from .._core.tests.test_ki import ki_self
Expand Down Expand Up @@ -539,40 +538,10 @@ def test_run_fn_as_system_task_catched_badly_typed_token():
from_thread_run_sync(_core.current_time, trio_token="Not TrioTokentype")


async def test_do_in_trio_thread_from_trio_thread_legacy():
# This check specifically confirms that a RuntimeError will be raised if
# the old BlockingTrIoPortal API calls into a trio loop while already
# running inside of one.
portal = BlockingTrioPortal()
async def test_from_thread_inside_trio_thread():
def not_called(): # pragma: no cover
assert False

trio_token = _core.current_trio_token()
with pytest.raises(RuntimeError):
portal.run_sync(lambda: None) # pragma: no branch

async def foo(): # pragma: no cover
pass

with pytest.raises(RuntimeError):
portal.run(foo)


async def test_BlockingTrioPortal_with_explicit_TrioToken():
# This tests the deprecated BlockingTrioPortal with a token passed in to
# confirm that both methods of making a portal are supported by
# trio.from_thread
token = _core.current_trio_token()

def worker_thread(token):
with pytest.raises(RuntimeError):
BlockingTrioPortal()
portal = BlockingTrioPortal(token)
return portal.run_sync(threading.current_thread)

t = await to_thread_run_sync(worker_thread, token)
assert t == threading.current_thread()


def test_BlockingTrioPortal_deprecated_export(recwarn):
import trio

btp = trio.BlockingTrioPortal
assert btp is BlockingTrioPortal
from_thread_run_sync(not_called, trio_token=trio_token)