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
6 changes: 3 additions & 3 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Run flake8 (pycodestyle + pyflakes) check.
# https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes
# Ignored errors:
# - E501: line too long
# - E265: block comment should start with '# ' (makes it easier to enable/disable code)
# - W503: line break before binary operator (deprecated rule)
# - W505: doc line too long

[flake8]
ignore = E501,E265,W503,W505
exclude = .git/,.virtualenv/,__pycache__/,build/,dist/,docker/
ignore = E265,W503,W505
max-line-length = 120
exclude = .git/,.virtualenv/,.venv/,.local/,.eggs/,__pycache__/,build/,dist/,submodules/
37 changes: 37 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Python CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:

runs-on: ubuntu-latest

# It is not possible to use GitHub Python setup because a system dependency is required

steps:
- name: Checkout project
uses: actions/checkout@v4
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-gi python3-venv make
- name: Install venv
run: |
python3 -m venv /opt/venv --system-site-packages
/opt/venv/bin/pip install --no-cache-dir --upgrade pip setuptools wheel
/opt/venv/bin/pip install --no-cache-dir --editable '.[dev]'
- name: Test
run: |
make lint_local
make deadcode_local
make test_local
env:
PATH: /opt/venv/bin:/usr/sbin:/usr/bin:/sbin:/bin
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
build/
__pycache__/
*.pyc

# Unit test / coverage reports
.coverage*
coverage*
htmlcov
report.xml
.mypy_cache
.pytest_cache
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM debian:bookworm

RUN apt update
RUN apt install -y python3-gi python3-venv make

RUN python3 -m venv /opt/venv --system-site-packages
ENV VIRTUAL_ENV="/opt/venv"
ENV PATH="/opt/venv/bin:/usr/sbin:/usr/bin:/sbin:/bin"
RUN pip install --no-cache-dir --upgrade pip setuptools wheel

ARG DOCKER_WORK_DIR
RUN mkdir -p ${DOCKER_WORK_DIR}
WORKDIR ${DOCKER_WORK_DIR}

COPY pyproject.toml pyproject.toml
COPY easyevent easyevent
RUN pip install --no-cache-dir --editable '.[dev]'
67 changes: 53 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,21 +1,60 @@
#!/usr/bin/make -f
DOCKER_IMAGE_NAME ?= easyevent:latest
DOCKER_WORK_DIR ?= /opt/src
DOCKER_RUN ?= docker run --rm -it --user "$(shell id -u):$(shell id -g)" -v ${CURDIR}:${DOCKER_WORK_DIR}

all: build

build:
python setup.py build
docker build -t ${DOCKER_IMAGE_NAME} ${BUILD_ARGS} --build-arg DOCKER_WORK_DIR=${DOCKER_WORK_DIR} .

install: build
sudo python setup.py install
rebuild:BUILD_ARGS = --no-cache
rebuild:build

uninstall:
sudo rm -vrf /usr/lib/python2.5/site-packages/easyevent
sudo rm -v /usr/lib/python2.5/site-packages/easyevent*.egg-info
push:
docker push ${DOCKER_IMAGE_NAME}

clean:
rm -rf build
rm -f build-stamp
find . -name "*.pyc" -o -name "*~" | xargs -r rm
pull:
docker pull --quiet ${DOCKER_IMAGE_NAME}

shell:
${DOCKER_RUN} ${DOCKER_IMAGE_NAME} /bin/bash

lint:
${DOCKER_RUN} ${DOCKER_IMAGE_NAME} make lint_local

lint_local:
flake8 .

typing:
${DOCKER_RUN} ${DOCKER_IMAGE_NAME} make typing_local

typing_local:
mypy easyevent

deadcode:
${DOCKER_RUN} ${DOCKER_IMAGE_NAME} make deadcode_local

builddeb:
dpkg-buildpackage -rfakeroot
deadcode_local:
vulture --min-confidence 90 easyevent tests

test:
${DOCKER_RUN} -e "PYTEST_ARGS=${PYTEST_ARGS}" ${DOCKER_IMAGE_NAME} make test_local

test_local:PYTEST_ARGS := $(or ${PYTEST_ARGS},--cov --no-cov-on-fail --junitxml=report.xml --cov-report xml --cov-report term --cov-report html)
test_local:
pytest ${PYTEST_ARGS}

list_installed_files:
${DOCKER_RUN} ${DOCKER_IMAGE_NAME} make list_installed_files_local

list_installed_files_local:
# List files installed by the Python package
make clean
python3 -m venv /tmp/venv --system-site-packages
cp -a ${DOCKER_WORK_DIR} /tmp/src
cd /tmp/src && /tmp/venv/bin/pip install .
cd /tmp/src && /tmp/venv/bin/pip show -f easyevent

clean:
rm -rf .coverage .pytest_cache .local .eggs build dist *.egg-info
find . -type f -name *.pyc -delete
find . -type d -name __pycache__ -delete
3 changes: 1 addition & 2 deletions easyevent/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .version import VERSION as __version__
from .event import Listener, Launcher, User, forward_event

__all__ = ('__version__', 'Listener', 'Launcher', 'User', 'forward_event')
__all__ = ('Listener', 'Launcher', 'User', 'forward_event')
40 changes: 28 additions & 12 deletions easyevent/event.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Module to do event-driven programming very easily.
@author: Damien Boucard
@license: Gnu/LGPLv2
@version: 1.0

Module attributes:

Expand All @@ -13,12 +9,20 @@
'callback' (synchronous).
"""
from collections.abc import Callable
from gi.repository import GLib
import logging

logger = logging.getLogger('event')
dispatcher = 'callback'
log_ignores = ['level']
GLib = None


def get_glib():
# GLib is optional, so import it when needed
global GLib
if GLib is None:
from gi.repository import GLib
return GLib


class Manager:
Expand All @@ -27,7 +31,8 @@ class Manager:
so it is not needed to use it directly but via Launch and Listener.
@cvar instance: The instance created on importing the module.
@type instance: C{L{Manager}}
@ivar listeners: Dictionnary with keys of type C{str} representing a event type and with values of type C{list} representing a collection of C{EventListener}.
@ivar listeners: Dictionnary with keys of type C{str} representing a event type and with values
of type C{list} representing a collection of C{EventListener}.
@type listeners: C{dict<str, list<L{Listener}>>}
"""
def __init__(self):
Expand All @@ -54,7 +59,11 @@ def add_listener(self, obj, event_type):
duplicate_objects.append(listener)
i += 1
if i > 0:
logger.warning('Warning, multiple class registration detected (%s times) for class %s for event %s, objects: old %s and new %s', i, class_name, event_type, duplicate_objects, obj)
logger.warning(
'Warning, multiple class registration detected (%s times) '
'for class %s for event %s, objects: old %s and new %s',
i, class_name, event_type, duplicate_objects, obj
)
else:
self.listeners[event_type] = [obj]

Expand Down Expand Up @@ -88,7 +97,8 @@ def dispatch_event(self, event):
function = getattr(obj, fctname)
if isinstance(function, Callable):
if dispatcher == 'gobject':
GLib.idle_add(function, event, priority=GLib.PRIORITY_HIGH)
gl = get_glib()
gl.idle_add(function, event, priority=gl.PRIORITY_HIGH)
elif dispatcher == 'callback':
function(event)
continue
Expand All @@ -99,7 +109,8 @@ def dispatch_event(self, event):
function = getattr(obj, obj.event_default)
if isinstance(function, Callable):
if dispatcher == 'gobject':
GLib.idle_add(function, event, priority=GLib.PRIORITY_HIGH)
gl = get_glib()
gl.idle_add(function, event, priority=gl.PRIORITY_HIGH)
elif dispatcher == 'callback':
function(event)
continue
Expand All @@ -120,7 +131,8 @@ class Listener:
It is just needed to herite from this class and register to events to listen easily events.
It is also needed to write handler methods with event-specific and/or C{L{default}} function.

Event-specific functions have name as the concatenation of the C{prefix} parameter + the listened event type + the C{suffix} parameter.
Event-specific functions have name as the concatenation of:
the C{prefix} parameter + the listened event type + the C{suffix} parameter.

If it does not exist, the default function is called as defined by the C{L{default}} parameter/attribute.

Expand All @@ -131,7 +143,8 @@ class Listener:
@type event_pattern: C{str}
@ivar event_default: Default handler function name.
@type event_default: C{str}
@ivar silent: Silent flag. If C{False}, C{L{UnhandledEventError}} is raised if an event cannot be handled. If C{True}, do nothing, listener does not handle the event.
@ivar silent: Silent flag. If C{False}, C{L{UnhandledEventError}} is raised if an event cannot be handled.
If C{True}, do nothing, listener does not handle the event.
@type silent: C{str}
"""
def __init__(self, prefix='evt_', suffix='', default='eventPerformed', silent=False):
Expand Down Expand Up @@ -268,7 +281,10 @@ def __str__(self):
@return: Object converted string.
@rtype: C{str}
"""
return '<%s.%s type=%s source=%s content=%s>' % (__name__, self.__class__.__name__, self.type, self.source, self.content)
return (
'<%s.%s type=%s source=%s content=%s>'
% (__name__, self.__class__.__name__, self.type, self.source, self.content)
)


class UnhandledEventError(AttributeError):
Expand Down
1 change: 0 additions & 1 deletion easyevent/version.py

This file was deleted.

48 changes: 48 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools>=77.0"]

[project]
name = "easyevent"
description = "Very simple and easy-to-use python module for event-driven programming."
version = "3.0"
authors = [{name = "UbiCast"}]
license = "LGPL-3.0-only"
license-files = ["LICENSE"]
readme = "README.md"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Other Environment",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Topic :: Utilities",
]
requires-python = ">=3.11"

[project.optional-dependencies]
dev = [
"flake8",
"mypy",
"pytest",
"pytest-cov",
"vulture",
]

[project.urls]
Repository = "https://github.com/UbiCastTeam/easyevent"

[tool.setuptools]
packages = ["easyevent"]
include-package-data = false

[tool.pytest.ini_options]
addopts = "--verbose --tb=native --color=yes"
log_date_format = "%H:%M:%S"
log_format = "%(asctime)s.%(msecs)03d %(name)s %(levelname)s %(message)s"
log_level = "DEBUG"
testpaths = "tests/"

[tool.coverage.run]
source_dirs = ["easyevent"]
18 changes: 0 additions & 18 deletions setup.py

This file was deleted.

35 changes: 0 additions & 35 deletions test/test.py

This file was deleted.

Loading