Skip to content

Commit

Permalink
Merge pull request #339 from njsmith/no-slots-sigh
Browse files Browse the repository at this point in the history
Stop using slots=True in public classes to fix weakref issues
  • Loading branch information
njsmith authored Oct 1, 2017
2 parents 3440dbd + eae9470 commit d063d67
Show file tree
Hide file tree
Showing 10 changed files with 21 additions and 16 deletions.
2 changes: 1 addition & 1 deletion trio/_core/_parking_lot.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class _ParkingLotStatistics:
tasks_waiting = attr.ib()


@attr.s(slots=True, cmp=False, hash=False)
@attr.s(cmp=False, hash=False)
class ParkingLot:
"""A fair wait queue with cancellation and requeueing.
Expand Down
6 changes: 3 additions & 3 deletions trio/_core/_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
__all__ = ["Result", "Value", "Error"]


@attr.s(slots=True, frozen=True)
class Result(metaclass=abc.ABCMeta):
"""An abstract class representing the result of a Python computation.
Expand All @@ -20,6 +19,7 @@ class Result(metaclass=abc.ABCMeta):
hashable.
"""
__slots__ = ()

@staticmethod
def capture(sync_fn, *args):
Expand Down Expand Up @@ -81,7 +81,7 @@ async def asend(self, agen):
"""


@attr.s(slots=True, frozen=True, repr=False)
@attr.s(frozen=True, repr=False)
class Value(Result):
"""Concrete :class:`Result` subclass representing a regular value.
Expand All @@ -103,7 +103,7 @@ async def asend(self, agen):
return await agen.asend(self.value)


@attr.s(slots=True, frozen=True, repr=False)
@attr.s(frozen=True, repr=False)
class Error(Result):
"""Concrete :class:`Result` subclass representing a raised exception.
Expand Down
8 changes: 4 additions & 4 deletions trio/_core/_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
_r = random.Random()


@attr.s(slots=True, frozen=True)
@attr.s(frozen=True)
class SystemClock:
# Add a large random offset to our clock to ensure that if people
# accidentally call time.monotonic() directly or start comparing clocks
Expand All @@ -84,7 +84,7 @@ def deadline_to_sleep_time(self, deadline):
################################################################


@attr.s(slots=True, cmp=False, hash=False)
@attr.s(cmp=False, hash=False)
class CancelScope:
_tasks = attr.ib(default=attr.Factory(set))
_effective_deadline = attr.ib(default=inf)
Expand Down Expand Up @@ -205,7 +205,7 @@ def open_cancel_scope(*, deadline=inf, shield=False):

# This code needs to be read alongside the code from Nursery.start to make
# sense.
@attr.s(slots=True, cmp=False, hash=False, repr=False)
@attr.s(cmp=False, hash=False, repr=False)
class _TaskStatus:
_old_nursery = attr.ib()
_new_nursery = attr.ib()
Expand Down Expand Up @@ -532,7 +532,7 @@ def _pending_cancel_scope(cancel_stack):
return pending_scope


@attr.s(slots=True, cmp=False, hash=False, repr=False)
@attr.s(cmp=False, hash=False, repr=False)
class Task:
_parent_nursery = attr.ib()
coro = attr.ib()
Expand Down
2 changes: 0 additions & 2 deletions trio/_core/tests/test_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ def test_Result():
v = Value(1)
assert v.value == 1
assert v.unwrap() == 1
assert not hasattr(v, "__dict__")
assert repr(v) == "Value(1)"

exc = RuntimeError("oops")
e = Error(exc)
assert e.error is exc
with pytest.raises(RuntimeError):
e.unwrap()
assert not hasattr(e, "__dict__")
assert repr(e) == "Error(RuntimeError('oops',))"

with pytest.raises(TypeError):
Expand Down
2 changes: 1 addition & 1 deletion trio/_core/tests/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ async def child():
assert stats.seconds_to_next_deadline == inf


@attr.s(slots=True, cmp=False, hash=False)
@attr.s(cmp=False, hash=False)
class TaskRecorder:
record = attr.ib(default=attr.Factory(list))

Expand Down
2 changes: 1 addition & 1 deletion trio/_highlevel_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class ClosedListenerError(Exception):
pass


@attr.s(slots=True, cmp=False, hash=False)
@attr.s(cmp=False, hash=False)
class StapledStream(HalfCloseableStream):
"""This class `staples <https://en.wikipedia.org/wiki/Staple_(fastener)>`__
together two unidirectional streams to make single bidirectional stream.
Expand Down
4 changes: 2 additions & 2 deletions trio/_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
]


@attr.s(slots=True, repr=False, cmp=False, hash=False)
@attr.s(repr=False, cmp=False, hash=False)
class Event:
"""A waitable boolean value useful for inter-task synchronization,
inspired by :class:`threading.Event`.
Expand Down Expand Up @@ -486,7 +486,7 @@ class _LockStatistics:


@async_cm
@attr.s(slots=True, cmp=False, hash=False, repr=False)
@attr.s(cmp=False, hash=False, repr=False)
class Lock:
"""A classic `mutex
<https://en.wikipedia.org/wiki/Lock_(computer_science)>`__.
Expand Down
2 changes: 1 addition & 1 deletion trio/_threads.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def current_default_worker_thread_limiter():
# system; see https://github.com/python-trio/trio/issues/182
# But for now we just need an object to stand in for the thread, so we can
# keep track of who's holding the CapacityLimiter's token.
@attr.s(frozen=True, cmp=False, hash=False, slots=True)
@attr.s(frozen=True, cmp=False, hash=False)
class ThreadPlaceholder:
name = attr.ib()

Expand Down
2 changes: 1 addition & 1 deletion trio/testing/_sequencer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
__all__ = ["Sequencer"]


@attr.s(slots=True, cmp=False, hash=False)
@attr.s(cmp=False, hash=False)
class Sequencer:
"""A convenience class for forcing code in different tasks to run in an
explicit linear order.
Expand Down
7 changes: 7 additions & 0 deletions trio/tests/test_sync.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pytest

import weakref

from ..testing import wait_all_tasks_blocked, assert_checkpoints

from .. import _core
Expand Down Expand Up @@ -215,6 +217,11 @@ async def test_Semaphore_bounded():
async def test_Lock_and_StrictFIFOLock(lockcls):
l = lockcls()
assert not l.locked()

# make sure locks can be weakref'ed (gh-331)
r = weakref.ref(l)
assert r() is l

repr(l) # smoke test
# make sure repr uses the right name for subclasses
assert lockcls.__name__ in repr(l)
Expand Down

0 comments on commit d063d67

Please sign in to comment.