Skip to content

Commit

Permalink
Merge pull request #75 from vkottler/dev/1.5.4
Browse files Browse the repository at this point in the history
1.5.4 - Add better exception handling
  • Loading branch information
vkottler authored May 31, 2023
2 parents bf32815 + 31c7f78 commit c2b5f4e
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 9 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
=====================================
generator=datazen
version=3.1.2
hash=cde638b7567222966c038f6c0d5719e0
hash=3bc7656b5df806d21148ec2b5b2c0082
=====================================
-->

# runtimepy ([1.5.3](https://pypi.org/project/runtimepy/))
# runtimepy ([1.5.4](https://pypi.org/project/runtimepy/))

[![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/)
![Build Status](https://github.com/vkottler/runtimepy/workflows/Python%20Package/badge.svg)
Expand Down
2 changes: 1 addition & 1 deletion local/variables/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
major: 1
minor: 5
patch: 3
patch: 4
entry: runtimepy
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta:__legacy__"

[project]
name = "runtimepy"
version = "1.5.3"
version = "1.5.4"
description = "A framework for implementing Python services."
readme = "README.md"
requires-python = ">=3.7"
Expand Down
4 changes: 2 additions & 2 deletions runtimepy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# =====================================
# generator=datazen
# version=3.1.2
# hash=407407f958d18e14776eb5ad2afb0772
# hash=d02bf554f7d30131decd07af8dbad01f
# =====================================

"""
Expand All @@ -10,4 +10,4 @@

DESCRIPTION = "A framework for implementing Python services."
PKG_NAME = "runtimepy"
VERSION = "1.5.3"
VERSION = "1.5.4"
15 changes: 12 additions & 3 deletions runtimepy/net/udp/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,24 @@ def sendto(
self, data: bytes, addr: _Union[IpHost, _Tuple[str, int]] = None
) -> None:
"""Send to a specific address."""
self._transport.sendto(data, addr=addr)

try:
self._transport.sendto(data, addr=addr)

# Catch a bug in the underlying event loop implementation - we try to
# send, but the underlying socket is gone (e.g. attribute is 'None').
# This seems to be possible (but intermittent) when shutting down the
# application.
except AttributeError as exc:
self.disable(str(exc))

def send_text(self, data: str) -> None:
"""Enqueue a text message to send."""
self._transport.sendto(data.encode(), addr=self.remote_address)
self.sendto(data.encode(), addr=self.remote_address)

def send_binary(self, data: _BinaryMessage) -> None:
"""Enqueue a binary message tos end."""
self._transport.sendto(data, addr=self.remote_address)
self.sendto(data, addr=self.remote_address)

@classmethod
async def create_connection(
Expand Down
65 changes: 65 additions & 0 deletions tests/net/udp/test_sendto_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
Test special cases for the 'net.udp.connection' module.
"""

# built-in
from asyncio import Event, gather, sleep

# third-party
from pytest import mark

# module under test
from runtimepy.net.udp.connection import NullUdpConnection


@mark.asyncio
async def test_udp_connection_sendto_fail():
"""Test 'sendto' failures with a UDP connection."""

conn1, conn2 = await NullUdpConnection.create_pair()

iterations = 0
sleep_time = 0.05

signal = Event()

async def send_spam() -> None:
"""Send messages back and forth."""

nonlocal iterations
msg = "Hello, world!"

while not conn1.disabled and not conn2.disabled:
conn1.send_text(msg)
conn2.send_text(msg)
iterations += 1
await sleep(sleep_time)

for _ in range(10):
conn1.send_text(msg)
conn2.send_text(msg)
iterations += 1
await sleep(sleep_time)

await signal.wait()

# Send more (should cause problems).
for _ in range(10):
conn1.send_text(msg)
conn2.send_text(msg)

async def closer() -> None:
"""Close the two connections."""

while iterations < 5:
await sleep(sleep_time)
conn1.disable("nominal")

while iterations < 10:
await sleep(sleep_time)
conn2.disable("nominal")

signal.set()

# Run everything.
await gather(send_spam(), closer(), conn1.process(), conn2.process())

0 comments on commit c2b5f4e

Please sign in to comment.