Skip to content

Commit 8aa3600

Browse files
committed
Refactor workflow for Python package upload and remove deprecated test workflow; update README for Python 3.10 compatibility and adjust project metadata
1 parent 0239b23 commit 8aa3600

File tree

11 files changed

+83
-25
lines changed

11 files changed

+83
-25
lines changed

.github/workflows/publish.yml

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,39 @@
1-
name: publish
1+
# This workflow will upload a Python Package using Twine when a release is created
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3+
4+
# This workflow uses actions that are not certified by GitHub.
5+
# They are provided by a third-party and are governed by
6+
# separate terms of service, privacy policy, and support
7+
# documentation.
8+
9+
name: Upload Python Package
210

311
on:
412
release:
5-
types: [published] # publish full release to PyPI when a release is created on Github
6-
workflow_dispatch:
13+
types: [published]
14+
workflow_dispatch: # allow manual triggering
715

816
permissions:
9-
contents: write
1017
id-token: write
1118

1219
jobs:
13-
publish_to_pypi:
14-
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
20+
deploy:
1521
runs-on: ubuntu-latest
22+
1623
steps:
1724
- uses: actions/checkout@v4
18-
- uses: astral-sh/setup-uv@v6
25+
- name: Set up Python
26+
uses: actions/setup-python@v5
27+
with:
28+
python-version: "3.x"
29+
- name: Install dependencies
30+
run: |
31+
python -m pip install --upgrade pip
32+
pip install build hatch
33+
- name: Build package
34+
run: python -m build
35+
- name: Publish package
36+
uses: pypa/gh-action-pypi-publish@release/v1
1937
with:
20-
enable-cache: true
21-
activate-environment: true
22-
- run: uv sync
23-
- run: uv run ruff check --no-fix --select PLE # quick check for syntax errors to avoid waiting time doing the rest of the build
24-
- run: uv build
25-
- run: uv run pytest tests # dont push the package to PyPI if the tests fail
26-
- run: uv publish --trusted-publishing always
38+
user: __token__
39+
password: ${{ secrets.PYPI_API_TOKEN }}

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.12
1+
3.10

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,26 @@ It's designed for quickly building event-driven applications with Python in a wa
66

77
It provides a [pydantic](https://docs.pydantic.dev/latest/)-based API for implementing publish-subscribe patterns with type safety, async/sync handler support, and advanced features like event forwarding between buses. It's inspired by the simplicity of `JS`'s async system and DOM events APIs, and it aims to bring a fully type-checked [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)-style API to Python.
88

9+
## ⚠️ Note
10+
11+
**This is a modified version of [bubus](https://github.com/abhijeetkaze/bubus) to support Python 3.10.**
12+
13+
[![PyPI version](https://img.shields.io/pypi/v/bubus-py310x)](https://pypi.org/project/bubus-py310x/)
14+
[![Python Versions](https://img.shields.io/pypi/pyversions/bubus-py310x)](https://pypi.org/project/bubus-py310x/)
15+
[![Downloads](https://static.pepy.tech/badge/bubus-py310x)](https://pepy.tech/project/bubus-py310x)
16+
[![GitHub stars](https://img.shields.io/github/stars/abhijeetkaze/bubus?style=social)](https://github.com/abhijeetkaze/bubus/stargazers)
17+
[![Last Commit](https://img.shields.io/github/last-commit/abhijeetkaze/bubus)](https://github.com/abhijeetkaze/bubus/commits/main)
18+
19+
A minimal fork of `bubus` with compatibility fixes for Python 3.10+.
20+
21+
- Maintainer for Python 3.10 version: **[Abhijeet Mohanta](https://github.com/abhijeetkaze)**
22+
- `bubus` is mocked to enable compatibility with Python 3.10.
23+
- Cloud actions are **not supported** in this version.
24+
- `from typing_extensions import Self` (for Python 3.10 compatibility) is used in place of `Self` from `typing`.
25+
- `async with asyncio.timeout` replaced with `async_timeout` (custom implementation of async timeout) to support Python 3.10.
26+
- UTC datetime changed to timezone(UTC = timezone.utc)
27+
- asyncio.create_task no context passed
28+
929
## 🔢 Quickstart
1030

1131
Install bubus and get started with a simple event-driven application:

bubus/compatible_utils/__init__.py

Whitespace-only changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from contextlib import asynccontextmanager
2+
import asyncio
3+
4+
@asynccontextmanager
5+
async def async_timeout(timeout: float):
6+
task = asyncio.current_task()
7+
loop = asyncio.get_event_loop()
8+
if task is None:
9+
raise RuntimeError("async_timeout must be used within a running asyncio Task")
10+
handle = loop.call_later(timeout, task.cancel)
11+
try:
12+
yield
13+
except asyncio.CancelledError:
14+
raise asyncio.TimeoutError(f"Operation exceeded {timeout} seconds")
15+
finally:
16+
handle.cancel()

bubus/helpers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from functools import wraps
88
from pathlib import Path
99
from typing import Any, Literal, ParamSpec, TypeVar
10+
from .compatible_utils.async_timeout import async_timeout
1011

1112
import portalocker
1213

@@ -219,7 +220,7 @@ async def _acquire_asyncio_semaphore(
219220
) -> bool:
220221
"""Acquire an asyncio semaphore."""
221222
try:
222-
async with asyncio.timeout(sem_timeout):
223+
async with async_timeout(sem_timeout):
223224
await semaphore.acquire()
224225
return True
225226
except TimeoutError:
@@ -252,7 +253,7 @@ async def _execute_with_retries(
252253
for attempt in range(retries + 1):
253254
try:
254255
# Execute with per-attempt timeout
255-
async with asyncio.timeout(timeout):
256+
async with async_timeout(timeout):
256257
return await func(*args, **kwargs) # type: ignore[reportCallIssue]
257258

258259
except Exception as e:

bubus/logging.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
"""Helper functions for logging event trees and formatting"""
22

33
from collections import defaultdict
4-
from datetime import UTC, datetime
4+
from datetime import timezone, datetime
55
from typing import TYPE_CHECKING, Any
66

7+
8+
# Use timezone.utc directly in your code
9+
UTC = timezone.utc
10+
711
if TYPE_CHECKING:
812
from bubus.models import BaseEvent, EventResult
913
from bubus.service import EventBus

bubus/models.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@
55
import logging
66
import os
77
from collections.abc import Awaitable, Callable, Generator
8-
from datetime import UTC, datetime
9-
from typing import TYPE_CHECKING, Annotated, Any, Literal, Protocol, Self, TypeAlias, TypeVar, runtime_checkable
8+
from datetime import timezone, datetime
9+
from typing import TYPE_CHECKING, Annotated, Any, Literal, Protocol, TypeAlias, TypeVar, runtime_checkable
10+
from typing_extensions import Self
1011
from uuid import UUID
1112

1213
from pydantic import AfterValidator, BaseModel, ConfigDict, Field, PrivateAttr, model_validator
1314
from uuid_extensions import uuid7str
1415

16+
# Use timezone.utc directly in your code
17+
UTC = timezone.utc
18+
1519
if TYPE_CHECKING:
1620
from bubus.service import EventBus
1721

bubus/service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ async def _execute_handlers(
796796
task = asyncio.create_task(
797797
self._execute_sync_or_async_handler(event, handler, timeout=timeout),
798798
name=f'{self}._execute_sync_or_async_handler({event}, {get_handler_name(handler)})',
799-
context=context,
799+
# context=context,
800800
)
801801
handler_tasks[handler_id] = (task, handler)
802802

0 commit comments

Comments
 (0)