Skip to content

Commit

Permalink
Merge pull request #447 from ably/release/2.0.0-beta.3
Browse files Browse the repository at this point in the history
Release/2.0.0 beta.3
  • Loading branch information
owenpearson authored Feb 6, 2023
2 parents 04bca35 + 93346ea commit ffcade0
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 44 deletions.
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# Change Log

## [v2.0.0-beta.3](https://github.com/ably/ably-python/tree/v2.0.0-beta.3)

This new beta release of the ably-python realtime client implements a number of new features to improve the stability of realtime connections, allowing the client to reconnect during a temporary disconnection, use fallback hosts when necessary, and catch up on messages missed while the client was disconnected.

[Full Changelog](https://github.com/ably/ably-python/compare/v2.0.0-beta.2...v2.0.0-beta.3)

- Resend protocol messages for pending channels upon resume [\#347](https://github.com/ably/ably-python/issues/347)
- Attempt to resume connection when disconnected unexpectedly [\#346](https://github.com/ably/ably-python/issues/346)
- Handle `CONNECTED` messages once connected [\#345](https://github.com/ably/ably-python/issues/345)
- Implement `maxIdleInterval` [\#344](https://github.com/ably/ably-python/issues/344)
- Implement realtime connectivity check [\#343](https://github.com/ably/ably-python/issues/343)
- Use fallback realtime hosts when encountering an appropriate error [\#342](https://github.com/ably/ably-python/issues/342)
- Add `fallbackHosts` client option for realtime clients [\#341](https://github.com/ably/ably-python/issues/341)
- Implement `connectionStateTtl` [\#340](https://github.com/ably/ably-python/issues/340)
- Implement `disconnectedRetryTimeout` [\#339](https://github.com/ably/ably-python/issues/339)
- Handle recoverable connection opening errors [\#338](https://github.com/ably/ably-python/issues/338)
- Implement `channelRetryTimeout` [\#442](https://github.com/ably/ably-python/issues/436)
- Queue protocol messages when connection state is `CONNECTING` or `DISCONNECTED` [\#418](https://github.com/ably/ably-python/issues/418)
- Propagate connection interruptions to realtime channels [\#417](https://github.com/ably/ably-python/issues/417)
- Spec compliance: `Realtime.connect` should be sync [\#413](https://github.com/ably/ably-python/issues/413)
- Emit `update` event on additional `ATTACHED` message [\#386](https://github.com/ably/ably-python/issues/386)
- Set the `ATTACH_RESUME` flag on unclean attach [\#385](https://github.com/ably/ably-python/issues/385)
- Handle fatal resume error [\#384](https://github.com/ably/ably-python/issues/384)
- Handle invalid resume response [\#383](https://github.com/ably/ably-python/issues/383)
- Handle clean resume response [\#382](https://github.com/ably/ably-python/issues/382)
- Send resume query param when reconnecting within `connectionStateTtl` [\#381](https://github.com/ably/ably-python/issues/381)
- Immediately reattempt connection when unexpectedly disconnected [\#380](https://github.com/ably/ably-python/issues/380)
- Clear connection state when `connectionStateTtl` elapsed [\#379](https://github.com/ably/ably-python/issues/379)
- Refactor websocket async tasks into WebSocketTransport class [\#373](https://github.com/ably/ably-python/issues/373)
- Send version transport param [\#368](https://github.com/ably/ably-python/issues/368)
- Clear `Connection.error_reason` when `Connection.connect` is called [\#367](https://github.com/ably/ably-python/issues/367)

## [v2.0.0-beta.2](https://github.com/ably/ably-python/tree/v2.0.0-beta.2)

[Full Changelog](https://github.com/ably/ably-python/compare/v2.0.0-beta.1...v2.0.0-beta.2)
Expand Down
53 changes: 38 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,16 +197,51 @@ await client.time()
await client.close()
```

### Using the Realtime API
The python realtime client currently only supports basic authentication.
## Realtime client (beta)

We currently have a preview version of our first ever Python realtime client available for beta testing.
Currently the realtime client only supports authentication using basic auth and message subscription.
Realtime publishing, token authentication, and realtime presence are upcoming but not yet supported.
Check out the [roadmap](./roadmap.md) to see our plan for the realtime client.

### Installing the realtime client

The beta realtime client is available as a [PyPI](https://pypi.org/project/ably/2.0.0b3/) package.

```
pip install ably==2.0.0b3
```

### Using the realtime client

#### Creating a client
```python
from ably import AblyRealtime

async def main():
# Create a client using an Ably API key
client = AblyRealtime('api:key')
```

#### Subscribe to connection state changes

```python
# subscribe to 'failed' connection state
client.connection.on('failed', listener)

# subscribe to 'connected' connection state
client.connection.on('connected', listener)

# subscribe to all connection state changes
client.connection.on(listener)

# wait for the next state change
await client.connection.once_async()

# wait for the connection to become connected
await client.connection.once_async('connected')
```

#### Get a realtime channel instance
```python
channel = client.channels.get('channel_name')
Expand Down Expand Up @@ -234,18 +269,6 @@ channel.unsubscribe('event', listener)
channel.unsubscribe()
```

#### Subscribe to connection state change
```python
# subscribe to 'failed' connection state
client.connection.on('failed', listener)

# subscribe to 'connected' connection state
client.connection.on('connected', listener)

# subscribe to all connection state changes
client.connection.on(listener)
```

#### Attach to a channel
```python
await channel.attach()
Expand All @@ -259,7 +282,7 @@ await channel.detach()
```python
# Establish a realtime connection.
# Explicitly calling connect() is unnecessary unless the autoConnect attribute of the ClientOptions object is false
await client.connect()
client.connect()

# Close a connection
await client.close()
Expand Down
2 changes: 1 addition & 1 deletion ably/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
logger.addHandler(logging.NullHandler())

api_version = '1.2'
lib_version = '2.0.0-beta.2'
lib_version = '2.0.0-beta.3'
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ably"
version = "2.0.0-beta.2"
version = "2.0.0-beta.3"
description = "Python REST and Realtime client library SDK for Ably realtime messaging service"
license = "Apache-2.0"
authors = ["Ably <[email protected]>"]
Expand Down
43 changes: 16 additions & 27 deletions test/ably/rest/resthttp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,19 @@ def make_url(host):
expected_hosts_set.remove(prep_request_tuple[0].headers.get('host'))
await ably.close()

@pytest.mark.skip(reason="skipped due to httpx changes")
@respx.mock
async def test_no_host_fallback_nor_retries_if_custom_host(self):
custom_host = 'example.org'
ably = AblyRest(token="foo", rest_host=custom_host)

custom_url = "%s://%s:%d/" % (
ably.http.preferred_scheme,
custom_host,
ably.http.preferred_port)
mock_route = respx.get("https://example.org").mock(side_effect=httpx.RequestError(''))

with mock.patch('httpx.Request', wraps=httpx.Request) as request_mock:
with mock.patch('httpx.AsyncClient.send', side_effect=httpx.RequestError('')) as send_mock:
with pytest.raises(httpx.RequestError):
await ably.http.make_request('GET', '/', skip_auth=True)
with pytest.raises(httpx.RequestError):
await ably.http.make_request('GET', '/', skip_auth=True)

assert mock_route.call_count == 1
assert respx.calls.call_count == 1

assert send_mock.call_count == 1
assert request_mock.call_args == mock.call(mock.ANY,
custom_url,
content=mock.ANY,
headers=mock.ANY)
await ably.close()

# RSC15f
Expand Down Expand Up @@ -137,7 +130,7 @@ async def side_effect(*args, **kwargs):
await client.aclose()
await ably.close()

@pytest.mark.skip(reason="skipped due to httpx changes")
@respx.mock
async def test_no_retry_if_not_500_to_599_http_code(self):
default_host = Options().get_rest_host()
ably = AblyRest(token="foo")
Expand All @@ -147,20 +140,16 @@ async def test_no_retry_if_not_500_to_599_http_code(self):
default_host,
ably.http.preferred_port)

def raise_ably_exception(*args, **kwargs):
raise AblyException(message="", status_code=600, code=50500)
mock_response = httpx.Response(600, json={'message': "", 'status_code': 600, 'code': 50500})

with mock.patch('httpx.Request', wraps=httpx.Request) as request_mock:
with mock.patch('ably.util.exceptions.AblyException.raise_for_response',
side_effect=raise_ably_exception) as send_mock:
with pytest.raises(AblyException):
await ably.http.make_request('GET', '/', skip_auth=True)
mock_route = respx.get(default_url).mock(return_value=mock_response)

with pytest.raises(AblyException):
await ably.http.make_request('GET', '/', skip_auth=True)

assert mock_route.call_count == 1
assert respx.calls.call_count == 1

assert send_mock.call_count == 1
assert request_mock.call_args == mock.call(mock.ANY,
default_url,
content=mock.ANY,
headers=mock.ANY)
await ably.close()

async def test_500_errors(self):
Expand Down

0 comments on commit ffcade0

Please sign in to comment.