Skip to content

Commit

Permalink
Preparing for PyPi distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
dgovil committed Dec 20, 2016
1 parent 047a4be commit e3a670b
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 10 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.idea/*
.idea/*
.idea
14 changes: 13 additions & 1 deletion pySignal.py → PySignal.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
__author__ = "Dhruv Govil"
__copyright__ = "Copyright 2016, Dhruv Govil"
__credits__ = ["Dhruv Govil", "John Hood", "Jason Viloria"]
__license__ = "MIT"
__version__ = "1.0.0"
__maintainer__ = "Dhruv Govil"
__email__ = "[email protected]"
__status__ = "Beta"

import inspect
import weakref
from functools import partial
Expand Down Expand Up @@ -95,7 +104,7 @@ class SignalFactory(dict):
"""
The Signal Factory object lets you handle signals by a string based name instead of by objects.
"""
def register(self, name):
def register(self, name, *slots):
"""
Registers a given signal
:param name: the signal to register
Expand All @@ -104,6 +113,9 @@ def register(self, name):
if name not in self:
self[name] = Signal()

for slot in slots:
self[name].connect(slot)

def deregister(self, name):
"""
Removes a given signal
Expand Down
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ This supports class methods, functions, lambdas and partials.
Signals can either be created on the instance or on the class, and can be handled either as objects or by string name.
Unlike PyQt signals, PySignals do not enforce types by default as I believe this is more pythonic.

## Install

You can install this using pip

```bash
pip install PySignal
```

This is compatible with Python 2.7+ and 3.x

## Usage:

```python
Expand All @@ -20,10 +30,26 @@ class Foo(object):
self.started.connect(greet)
self.started.emit('Watson')

self.signalFactory = SignalFactory()
self.signalFactory.register('Greet')
self.signalFactory['Greet'].connect(greet)
self.signalFactory['Greet'].emit('Sherlock')

foo = Foo()
# Hello, Watson
# Hello, SHerlock
```

## Signal Types

There are 4 types of Signals included

* `Signal` is the base implementation of the Signal and can be created on a per instance level.
* `ClassSignal` is an object that can be created as a class variable and will act like a signal.
This ensures that all instances of your class will have the signal, but can be managed individually.
* `SignalFactory` allows you to have a single signal object on your class that can generate signals by name.
* `ClassSignalFactory` is the same as a signal factory but lives on the class instead of the instance.

## Based on these implementations

http://www.jnvilo.com/cms/programming/python/programming-in-python/signal-and-slots-implementation-in-python
Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[metadata]
description-file = README.md
36 changes: 36 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from setuptools import setup
import PySignal




classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.5",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Utilities"
]


setup(
name="PySignal",
version=PySignal.__version__,
description="Python 2 & 3 compatibility wrapper around all Qt bindings - "
"PySide, PySide2, PyQt4 and PyQt5.",
author=PySignal.__author__,
author_email=PySignal.__email__,
url="https://github.com/dgovil/PySignal",
license="MIT",
zip_safe=False,
py_modules=["PySignal"],
classifiers=classifiers,
keywords=['signals', 'qt', 'events']
)
112 changes: 104 additions & 8 deletions tests.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,134 @@
import pySignal
from __future__ import print_function
import PySignal
from functools import partial
try:
import unittest2 as unittest
except:
import unittest



def testFunc(value):
"""
A test standalone function for signals to attach onto
"""
print("Ran for %s" % value)
SignalTest.checkval = value

class DummySignalClass(object):
"""A dummy class to check for instance handling of signals"""
cSignal = PySignal.ClassSignal()
cSignalFactory = PySignal.ClassSignalFactory()

def __init__(self):
self.signal = PySignal.Signal()
self.signalFactory = PySignal.SignalFactory()


class SignalTestRunner(unittest.TestCase):
class SignalTest(unittest.TestCase):
checkval = None # A state check for the tests

def setVal(self, val):
"""A method to test instance settings with"""
self.checkval = val

def throwaway(self, *args):
"""A method to throw redundant data into"""
pass

def test_partialConnect(self):
partialSignal = pySignal.Signal()
"""Tests if signals can connect to partials"""
partialSignal = PySignal.Signal()
partialSignal.connect(partial(testFunc, 'Partial'))
partialSignal.emit()
self.assertEqual(self.checkval, 'Partial')

def test_lambdaConnect(self):
lambdaSignal = pySignal.Signal()
"""Tests if signals can be connected to lambdas"""
lambdaSignal = PySignal.Signal()
lambdaSignal.connect(lambda value: testFunc(value))
lambdaSignal.emit('Lambda')
self.assertEqual(self.checkval, 'Lambda')

def testMethod(self, value=2):
def printer(self, value=2):
"""Dummy printer method for signals to connect to"""
print("Method called with %s" % value)
SignalTest.checkval = value

def test_methodConnect(self):
methodSignal = pySignal.Signal()
methodSignal.connect(self.testMethod)
"""Test if signals can be connected to methods on class instances"""
methodSignal = PySignal.Signal()
methodSignal.connect(self.printer)
methodSignal.emit(value=5)
self.assertEqual(self.checkval, 5)

def test_functionConnect(self):
funcSignal = pySignal.Signal()
"""Test if signals can be connected to standalone functions"""
funcSignal = PySignal.Signal()
funcSignal.connect(testFunc)
funcSignal.emit("Function")
self.assertEqual(self.checkval, 'Function')

def test_signalEmit(self):
"""Test if a signal can be emitted"""
toSucceed = DummySignalClass()
toSucceed.signal.connect(self.setVal)
toSucceed.signal.emit(20)

self.assertEqual(self.checkval, 20)

def test_classSignalEmit(self):
"""Test if the class signal can be emitted but also that instances of the class are unique"""
toSucceed = DummySignalClass()
toSucceed.cSignal.connect(self.setVal)

toFail = DummySignalClass()
toFail.cSignal.connect(self.throwaway)

toSucceed.cSignal.emit(50)
toFail.cSignal.emit(80)

self.assertEqual(self.checkval, 50)

def test_signalFactoryEmit(self):
"""Test if the signal factory can emit signals"""
toSucceed = DummySignalClass()
toSucceed.signalFactory.register('Spam')
toSucceed.signalFactory['Spam'].connect(self.setVal)

toSucceed.signalFactory['Spam'].emit(22)

self.assertEqual(self.checkval, 22)

def test_cSignalFactoryEmit(self):
"""Test if the class signal factory can emit signals but also that class instances are unique"""
toSucceed = DummySignalClass()
toSucceed.cSignalFactory.register('Spam')
toSucceed.cSignalFactory['Spam'].connect(self.setVal)

toFail = DummySignalClass()
toFail.cSignalFactory.register('Spam')
toFail.cSignalFactory['Spam'].connect(self.throwaway)

toSucceed.cSignalFactory['Spam'].emit(45)
toFail.cSignalFactory['Spam'].emit(12)

self.assertEqual(self.checkval, 45)

def test_signalBlock(self):
"""Test if the signal factory can block signals"""
dummy = DummySignalClass()
dummy.signalFactory.register('Spam', self.setVal)
dummy.signalFactory['Spam'].emit(105)

self.assertEqual(self.checkval, 105)

dummy.signalFactory.block()

dummy.signalFactory['Spam'].emit(202)
self.assertNotEqual(self.checkval, 202)



if __name__ == '__main__':
unittest.main()

0 comments on commit e3a670b

Please sign in to comment.