Skip to content
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
25 changes: 17 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,36 @@ jobs:
pip install pytest pytest-asyncio pytest-cov ruff mypy

- name: Lint
run: ruff check sillo_wire tests _sillo_wire_bootstrap.py
run: ruff check sillo_wire tests

- name: Types
run: mypy sillo_wire

- name: Install the package
run: pip install -e .

# The `.pth` only fires for a real install, so the alias is checked
# against a built wheel rather than the editable checkout.
- name: Check the sillo.wire alias against a real install
# Checked against a built wheel rather than the editable checkout: an
# editable install can import a package the wheel does not actually ship.
- name: Check a built wheel installs and imports
run: |
pip install build && python -m build --wheel -o /tmp/w .
python -m venv /tmp/v && /tmp/v/bin/pip install -q sillo-framework /tmp/w/*.whl mypy
/tmp/v/bin/python -c "
import sillo, sillo.wire, sillo_wire, os
assert sillo.wire is sillo_wire
import os, sillo, sillo_wire
from sillo_wire import Hub
# The package is top-level and adds nothing to the framework's own
# directory; it used to ship a .pth that aliased sillo.wire onto it.
assert 'wire' not in os.listdir(os.path.dirname(sillo.__file__)), 'wrote into sillo/'
print('alias ok, sillo/ untouched')
try:
import sillo.wire
except ImportError:
pass
else:
raise AssertionError('sillo.wire still resolves; the alias was removed')
print('sillo_wire imports, sillo/ untouched, no alias')
"
printf 'from sillo.wire import Hub\nh: Hub = Hub()\n' > /tmp/tc.py
# Types come from the package's own inline annotations now, not stubs.
printf 'from sillo_wire import Hub\nh: Hub = Hub()\n' > /tmp/tc.py
/tmp/v/bin/python -m mypy /tmp/tc.py

- name: Test
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ jobs:
- name: Build the package
run: uv build

# The whole point of this package's layout: the wheel adds a top-level
# `sillo_wire` plus the `.pth`/bootstrap at the site-packages root, and
# it must never write into the framework's own `sillo/` directory.
# The wheel adds a top-level `sillo_wire` and nothing else; it must never
# write into the framework's own `sillo/` directory. Two distributions
# sharing one package directory goes wrong in both directions, which is
# why this is asserted rather than assumed.
- name: The wheel must stay out of sillo/
run: |
python - <<'PY'
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## Unreleased

### Removed

- **The `sillo.wire` import alias.** `sillo_wire` is now the only import path:

```python
from sillo_wire import Hub, Peer # was: from sillo.wire import ...
```

The alias was a meta-path finder registered by a `.pth` at interpreter
startup, plus PEP 561 stubs under `sillo-stubs/` to serve type checkers,
which never run import hooks. It read as part of the framework, but it cost a
`.pth` executing on every interpreter start in every environment the package
was installed in, a second set of stubs to keep in step with the real
package, and a name that static analysis only resolved because a second set
of files said so. A plain top-level package needs none of that.

`_sillo_wire_bootstrap.py`, `sillo_wire.pth` and `sillo-stubs/` are gone, and
so are the `force-include` blocks that shipped them. Inline types in
`sillo_wire` are now the single source of truth for type checkers.

## 0.1.0.dev1

Development pre-release for testing. Install with
Expand Down
42 changes: 8 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ Rooms, presence and fan-out for [Sillo](https://sillo.build) WebSockets.
pip install sillo-wire
```

Installs as `sillo-wire`, imports as `sillo.wire`.
Installs as `sillo-wire`, imports as `sillo_wire`.

```python
from sillo import SilloApp
from sillo.wire import Hub, Peer
from sillo_wire import Hub, Peer

app = SilloApp()
hub = Hub()
Expand Down Expand Up @@ -66,7 +66,7 @@ await hub.replay(peer, "lobby", since=last_seq_the_client_saw)
When a peer's queue fills, what happens is a choice, not a default:

```python
from sillo.wire import Overflow, Peer
from sillo_wire import Overflow, Peer

Peer(socket, overflow=Overflow.DROP_OLDEST) # keep current — prices, cursors
Peer(socket, overflow=Overflow.DROP_NEWEST) # keep order — reconcile later
Expand Down Expand Up @@ -98,7 +98,7 @@ joins the rooms, pumps messages, and guarantees the peer is removed from every
room when the connection ends — including when a hook raises.

```python
from sillo.wire import Hub, RoomConsumer
from sillo_wire import Hub, RoomConsumer

hub = Hub()

Expand All @@ -122,7 +122,7 @@ app.add_ws_route(path="/ws/{room}", handler=Chat.as_handler())
Retention is per room and capped by payload bytes, evicting oldest first:

```python
from sillo.wire import Hub, MemoryBacklog, NullBacklog
from sillo_wire import Hub, MemoryBacklog, NullBacklog

Hub(backlog=MemoryBacklog(capacity_bytes=4 * 1024 * 1024))
Hub(backlog=NullBacklog()) # keep nothing — typing indicators, telemetry
Expand All @@ -133,10 +133,10 @@ importing anything from here.

## Testing

`sillo.wire.testing` ships the piece unit tests are missing — a socket:
`sillo_wire.testing` ships the piece unit tests are missing — a socket:

```python
from sillo.wire import Hub, Peer
from sillo_wire import Hub, Peer
from sillo_wire.testing import FakeSocket, drain

async def test_a_broadcast_reaches_the_room():
Expand Down Expand Up @@ -165,32 +165,6 @@ to reproduce against a real server and the two most worth testing.
| `Backlog` | `MemoryBacklog` `NullBacklog`, or your own |
| `Overflow` | `DROP_OLDEST` `DROP_NEWEST` `CLOSE` |

## The two import paths

`sillo.wire` and `sillo_wire` name the same objects. The code lives in the
top-level `sillo_wire` package; `sillo.wire` is an alias, so it reads as part
of the framework:

```python
from sillo.wire import Hub # both of these
from sillo_wire import Hub # bind the same class
```

The alias is a meta-path finder registered by a `.pth` at interpreter startup —
the only hook that runs before an `import sillo.wire` could fail. Type checkers
never run import hooks, so they are served separately by the partial stubs in
`sillo-stubs/` (PEP 561), which are additive: mypy resolves `sillo.wire` and
still uses the framework's own inline types for the rest of `sillo`.

Nothing is written into the framework's package directory. Shipping
`sillo/wire/` in there would be simpler, and it is what this did first — but
two distributions sharing one directory goes wrong in both directions.
Installing the framework from a checkout moves where `sillo` resolves and
orphans the copy in site-packages; removing or replacing the framework leaves
that directory standing with no `__init__.py`, which is an override rather than
an addition. Uninstalling either package here leaves the other exactly as it
was.

## Working on it

The alias works under an editable install too — the `.pth` is shipped by the
Expand All @@ -199,7 +173,7 @@ editable build target as well as the wheel.
```bash
pip install -e ".[dev]"
pytest --cov # 100% required, bootstrap included
ruff check sillo_wire tests _sillo_wire_bootstrap.py
ruff check sillo_wire tests
mypy sillo_wire
```

Expand Down
104 changes: 0 additions & 104 deletions _sillo_wire_bootstrap.py

This file was deleted.

21 changes: 1 addition & 20 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,33 +39,14 @@ Source = "https://github.com/sillohq/wire"
dev = ["pytest>=8.0", "pytest-asyncio>=0.24", "pytest-cov>=5.0", "ruff>=0.6", "mypy>=1.11"]

[tool.hatch.build.targets.wheel]
# `sillo-stubs` serves type checkers, which never run the import hook below.
packages = ["sillo_wire", "sillo-stubs"]

# The bootstrap and its .pth land at the site-packages root. The .pth is what
# runs at interpreter startup and registers the `sillo.wire` alias; see
# _sillo_wire_bootstrap.py for why the package is not shipped into `sillo/`.
[tool.hatch.build.targets.wheel.force-include]
"_sillo_wire_bootstrap.py" = "_sillo_wire_bootstrap.py"
"sillo_wire.pth" = "sillo_wire.pth"

# The same two files for `pip install -e .`, so the `sillo.wire` alias works in
# a development checkout and not only from a built wheel.
[tool.hatch.build.targets.editable.force-include]
"_sillo_wire_bootstrap.py" = "_sillo_wire_bootstrap.py"
"sillo_wire.pth" = "sillo_wire.pth"
packages = ["sillo_wire"]

[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
testpaths = ["tests"]

[tool.coverage.run]
# `_sillo_wire_bootstrap` is deliberately not measured. Its `.pth` imports it
# at interpreter startup, before coverage exists, so its `def` and `class`
# statements never run under the tracer and it reads as 65% however thoroughly
# it is tested. tests/test_alias.py covers it; the number would be an artefact
# of import timing rather than of testing.
source = ["sillo_wire"]
branch = true

Expand Down
1 change: 0 additions & 1 deletion sillo-stubs/py.typed

This file was deleted.

48 changes: 0 additions & 48 deletions sillo-stubs/wire.pyi

This file was deleted.

1 change: 0 additions & 1 deletion sillo_wire.pth

This file was deleted.

Binary file removed sillo_wire/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file removed sillo_wire/__pycache__/backlog.cpython-313.pyc
Binary file not shown.
Binary file removed sillo_wire/__pycache__/consumer.cpython-313.pyc
Binary file not shown.
Binary file removed sillo_wire/__pycache__/envelope.cpython-313.pyc
Binary file not shown.
Binary file removed sillo_wire/__pycache__/errors.cpython-313.pyc
Binary file not shown.
Binary file removed sillo_wire/__pycache__/hub.cpython-313.pyc
Binary file not shown.
Binary file removed sillo_wire/__pycache__/peer.cpython-313.pyc
Binary file not shown.
Binary file removed sillo_wire/__pycache__/policy.cpython-313.pyc
Binary file not shown.
Binary file removed sillo_wire/__pycache__/testing.cpython-313.pyc
Binary file not shown.
Loading
Loading