Skip to content
Draft
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
34 changes: 21 additions & 13 deletions .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ description: "Create a release branch, bump version, and update CHANGELOG. Usage
allowed-tools: Bash, Read, Edit, Write
---

Read the current version from `pyproject.toml` (the `version` property).
Read the current version from `core/pyproject.toml` (the `version` property). Both
distributions built from this repo are released in lockstep, so there is one
version for all of the sites below and they must never diverge.

The bump type is: $ARGUMENTS

Expand All @@ -15,12 +17,18 @@ Compute the new version by incrementing the appropriate component of the current
Then perform these steps in order:

1. Run `git checkout -b release/NEW_VERSION`
2. Replace `OLD_VERSION` with `NEW_VERSION` in all of the following files:
- `pyproject.toml` — the `version` property
- `ably/__init__.py` — lib_version value
3.Run `uv sync` to update `uv.lock` file
4. Commit all files together with message: `chore: bump version to NEW_VERSION`
3. Fetch merged PRs since the last release tag using:
2. Replace `OLD_VERSION` with `NEW_VERSION` in all of the following places:
- `core/pyproject.toml` — the `version` property
- `server/pyproject.toml` — the `version` property, **and** every
`ably-pubsub-core==OLD_VERSION` pin in `[project.dependencies]` and
`[project.optional-dependencies]`
- `core/src/ably_pubsub/core/__init__.py` — `lib_version` value
- `server/src/ably_pubsub/server/__init__.py` — `__version__` value
3. Run `uv sync` to update the `uv.lock` file
4. Run `uv run pytest test/unit/pubsub_packaging_test.py` — it asserts that
every one of those sites agrees
5. Commit all files together with message: `chore: bump version to NEW_VERSION`
6. Fetch merged PRs since the last release tag using:
```
gh pr list --state merged --base main --json number,title,mergedAt --limit 200
```
Expand All @@ -30,23 +38,23 @@ Then perform these steps in order:
```
Filter the PRs to only those merged after that tag date. Format each as:
```
- Short, one sentence summary from PR title and description [#NUMBER](https://github.com/ably/ably-java/pull/NUMBER)
- Short, one sentence summary from PR title and description [#NUMBER](https://github.com/ably/ably-python/pull/NUMBER)
```
If the tag doesn't exist or there are no merged PRs, use a single `-` placeholder bullet instead.

4. In `CHANGELOG.md`, insert the following block immediately after the `# Change Log` heading (and its trailing blank line), before the first existing `## [` version entry:
7. In `CHANGELOG.md`, insert the following block immediately after the `# Change Log` heading (and its trailing blank line), before the first existing `## [` version entry:

```
## [NEW_VERSION](https://github.com/ably/ably-java/tree/vNEW_VERSION)
## [NEW_VERSION](https://github.com/ably/ably-python/tree/vNEW_VERSION)

[Full Changelog](https://github.com/ably/ably-java/compare/vOLD_VERSION...vNEW_VERSION)
[Full Changelog](https://github.com/ably/ably-python/compare/vOLD_VERSION...vNEW_VERSION)

### What's Changed

BULLETS_FROM_STEP_3
BULLETS_FROM_STEP_6

```

5. Commit `CHANGELOG.md` with message: `docs: update CHANGELOG for NEW_VERSION release`
8. Commit `CHANGELOG.md` with message: `docs: update CHANGELOG for NEW_VERSION release`

After completing all steps, show the user a summary of what was done. If PRs were found, list them. If the placeholder `-` was used instead, remind them to fill in the `### What's Changed` bullet points in `CHANGELOG.md` before merging.
32 changes: 31 additions & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
push:
branches:
- main
- integration/v4

permissions: {}

Expand Down Expand Up @@ -46,8 +47,37 @@ jobs:
key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}

- name: Install dependencies
run: uv sync --extra crypto --extra dev
# The dev dependency group installs both workspace members editable,
# with the core's crypto and vcdiff extras.
run: uv sync
- name: Generate rest sync code and tests
run: uv run unasync
- name: Test with pytest
run: uv run pytest --verbose --tb=short --capture=no

# A namespace mistake would otherwise surface only after publish: an
# ably_pubsub/__init__.py in either wheel makes the two distributions
# fight over the same directory, and a core wheel without the generated
# sync flavour is a build that skipped unasync.
- name: Check the built distributions
run: |
uv build --package ably-pubsub-core --out-dir dist-check
uv build --package ably-pubsub-server --out-dir dist-check
CORE_WHEEL=$(ls dist-check/ably_pubsub_core-*.whl)
if ! unzip -l "$CORE_WHEEL" | grep -q "ably_pubsub/core/sync/"; then
unzip -l "$CORE_WHEEL"
echo "::error::ably_pubsub/core/sync/ not found in the core wheel"
exit 1
fi
for WHEEL in dist-check/*.whl; do
if unzip -l "$WHEEL" | grep -q "ably_pubsub/__init__.py"; then
echo "::error::$WHEEL ships ably_pubsub/__init__.py; the namespace must stay PEP 420"
exit 1
fi
done
CORE_TARBALL=$(ls dist-check/ably_pubsub_core-*.tar.gz)
if ! tar -tzf "$CORE_TARBALL" | grep -q "ably_pubsub/core/sync/"; then
tar -tzf "$CORE_TARBALL"
echo "::error::ably_pubsub/core/sync/ not found in the core sdist"
exit 1
fi
3 changes: 2 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
push:
branches:
- main
- integration/v4

permissions: {}

Expand Down Expand Up @@ -37,6 +38,6 @@ jobs:
key: venv-${{ runner.os }}-3.9-${{ hashFiles('uv.lock') }}

- name: Install dependencies
run: uv sync --extra dev
run: uv sync
- name: Lint with ruff
run: uv run ruff check
28 changes: 5 additions & 23 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# TODO: this workflow still builds and publishes the single `ably` distribution
# and does not work against the two-distribution workspace. Reworking it into a
# lockstep release of ably-pubsub-core and ably-pubsub-server is the next PR on
# the integration branch (plan step 15). The artifact checks it used to carry
# have moved to check.yml, where they run on every PR.
name: Publish Python distribution to PyPI

on:
Expand Down Expand Up @@ -42,29 +47,6 @@ jobs:
with:
name: python-package-distributions
path: dist/
- name: Check that wheel and tarball contains ably/sync/
run: |
# Check wheel
WHEEL=$(ls dist/*.whl | head -n 1)
echo "Checking wheel: $WHEEL"
if unzip -l "$WHEEL" | grep -q "ably/sync/"; then
echo "✅ Found ably/sync/ in wheel"
else
unzip -l "$WHEEL"
echo "❌ ably/sync/ not found in wheel"
exit 1
fi

# Check tarball
TARBALL=$(ls dist/*.tar.gz | head -n 1)
echo "Checking tarball: $TARBALL"
if tar -tzf "$TARBALL" | grep -q "ably/sync/"; then
echo "✅ Found ably/sync/ in tarball"
else
tar -tzf "$TARBALL"
echo "❌ ably/sync/ not found in tarball"
exit 1
fi

publish-to-pypi:
name: Publish Python distribution to PyPI
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*.egg
*.egg-info
dist
dist-check
build
eggs
parts
Expand Down Expand Up @@ -51,9 +52,9 @@ test_vars_out
pytest
app_spec
app_spec.pkl
ably/types/options.py.orig
core/src/ably_pubsub/core/types/options.py.orig
test/ably/restsetup.py.orig

.idea/**/*
ably/sync/**
core/src/ably_pubsub/core/sync/**
test/ably/sync/**
20 changes: 0 additions & 20 deletions LONG_DESCRIPTION.rst

This file was deleted.

24 changes: 0 additions & 24 deletions ably/__init__.py

This file was deleted.

55 changes: 0 additions & 55 deletions ably/http/httputils.py

This file was deleted.

33 changes: 33 additions & 0 deletions core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ably-pubsub-core

**This is an internal implementation package. Do not depend on it directly.**

`ably-pubsub-core` holds the shared implementation of Ably's Pub/Sub SDK for
Python: the HTTP and realtime clients, channels, presence, authentication,
encryption and the message types. It is published so that the packages
applications *do* install can depend on one shared implementation, pinned to an
exact version.

Install the package that names the side your code runs on instead:

| Where your code runs | Install | Import |
| --- | --- | --- |
| A server or other trusted environment | `ably-pubsub-server` | `ably_pubsub.server` |

Nothing under `ably_pubsub.core` is public API. Its module layout, and the
names within it, may change in any release — including patch releases — without
a deprecation cycle. The supported surface is what `ably_pubsub.server`
re-exports.

`ably_pubsub` is a [PEP 420](https://peps.python.org/pep-0420/) namespace
package: this distribution ships `ably_pubsub/core/**` and never
`ably_pubsub/__init__.py`, so other distributions can contribute their own
subpackages to the same namespace.

## Contributing

See [CONTRIBUTING.md](https://github.com/ably/ably-python/blob/main/CONTRIBUTING.md).

## License

Apache License 2.0 — see [LICENSE](https://github.com/ably/ably-python/blob/main/LICENSE).
68 changes: 68 additions & 0 deletions core/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
[project]
name = "ably-pubsub-core"
version = "4.0.0"
description = "INTERNAL implementation package for Ably's Pub/Sub SDKs. Not for direct use — install ably-pubsub-server instead."
readme = "README.md"
requires-python = ">=3.8"
license = { text = "Apache-2.0" }
authors = [
{ name = "Ably", email = "support@ably.com" }
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
"msgpack>=1.0.0,<2.0.0",
"httpx>=0.25.0,<1.0",
"h2>=4.1.0,<5.0.0",
"websockets>=12.0,<15.0; python_version=='3.8'",
"websockets>=15.0,<16.0; python_version>='3.9'",
"pyee>=11.1.0,<14.0.0",
]

[project.optional-dependencies]
oldcrypto = ["pycrypto>=2.6.1,<3.0.0"]
crypto = ["pycryptodome"]
vcdiff = ["vcdiff-decoder>=0.1.0,<0.2.0"]

[project.scripts]
unasync = "ably_pubsub.core.scripts.unasync:run"

[project.urls]
Homepage = "https://ably.com"
Repository = "https://github.com/ably/ably-python"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.sdist]
ignore-vcs = true
include = [
"/src/ably_pubsub",
"/README.md",
"/pyproject.toml"
]
exclude = [
"**/*.pyc",
"**/__pycache__"
]

[tool.hatch.build.targets.wheel]
ignore-vcs = true
# PEP 420: `src/ably_pubsub` has no __init__.py, so this ships
# `ably_pubsub/core/**` into the shared `ably_pubsub` namespace.
packages = ["src/ably_pubsub"]
Loading
Loading