schollii / pypubsub

A Python publish-subcribe library (moved here from SourceForge.net where I had it for many years)
198 stars 29 forks source link

Update for arg/kwarg combinations #13

Closed JoshMayberry closed 5 years ago

JoshMayberry commented 6 years ago

Resolves #6: Functions that have any combination of arguments and keyword arguments can now be subscribed to. Test cases are included for different argument and keyword argument combinations.

schollii commented 6 years ago

Did you try subscribing a function that takes *args and **kwargs as params? I'm pretty sure this is supported.

JoshMayberry commented 6 years ago

The problem is that inspect.getargspec does not support 'keyword-only parameters', and inspect.getfullargspec is needed instead.

The following functions fail in the current pypubsub, and pass with the changes I have made (these functions are tested in the test file I created. Other arg and kwarg combinations that do pass are also in that test file):

#test_allKwargs_allDefaults
def myFunction(*, kwarg1 = 1, kwarg2 = 2, kwarg3 = 3): print(kwarg1, kwarg2, kwarg3)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo')

#test_allKwargs_noDefaults
def myFunction(*, kwarg1, kwarg2): print(kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', kwarg1 = 1, kwarg2 = 2)

#test_allKwargs_noDefaults_starArgs
def myFunction(*args, kwarg1, kwarg2): print(args, kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', kwarg1 = 1, kwarg2 = 2)

#test_allKwargs_noDefaults_starArgs_starStarKwargs
def myFunction(*args, kwarg1, kwarg2, **kwargs): print(args, kwarg1, kwarg2, kwargs)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', kwarg1 = 1, kwarg2 = 2)

#test_allKwargs_noDefaults_starStarKwargs
def myFunction(*, kwarg1, kwarg2, **kwargs): self.answer = (kwarg1, kwarg2, kwargs)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', kwarg1 = 1, kwarg2 = 2)

#test_allKwargs_withDefaults
def myFunction(*, kwarg1, kwarg2 = 2): self.answer = (kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', kwarg1 = 1)

#test_allKwargs_withDefaults_starArgs
def myFunction(*args, kwarg1, kwarg2 = 2): self.answer = (args, kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', kwarg1 = 1)

#test_allKwargs_withDefaults_starArgs_starStarKwargs
def myFunction(*args, kwarg1, kwarg2 = 2, **kwargs): self.answer = (args, kwarg1, kwarg2, kwargs)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', kwarg1 = 1)

#test_allKwargs_withDefaults_starStarKwargs
def myFunction(*args, kwarg1, kwarg2 = 2, **kwargs): self.answer = (args, kwarg1, kwarg2, kwargs)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', kwarg1 = 1)

#test_args_noDefaults_kwargs_noDefaults
def myFunction(arg1, arg2, *, kwarg1, kwarg2): self.answer = (arg1, arg2, kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', arg1 = 1, arg2 = 2, kwarg1 = 3, kwarg2 = 4)

#test_args_noDefaults_kwargs_withDefaults
def myFunction(arg1, arg2, *, kwarg1, kwarg2 = 4): self.answer = (arg1, arg2, kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', arg1 = 1, arg2 = 2, kwarg1 = 3)

#test_args_withDefaults_kwargs_noDefaults
def myFunction(arg1, arg2 = 2, *, kwarg1, kwarg2): self.answer = (arg1, arg2, kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', arg1 = 1, kwarg1 = 3, kwarg2 = 4)

#test_args_withDefaults_kwargs_withDefaults
def myFunction(arg1, arg2 = 2, *, kwarg1, kwarg2 = 4): self.answer = (arg1, arg2, kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', arg1 = 1, kwarg1 = 3)

#test_args_withDefaults_kwargs_withDefaults_starArgs
def myFunction(arg1, arg2 = 2, *args, kwarg1, kwarg2 = 4): self.answer = (arg1, arg2, args, kwarg1, kwarg2)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', arg1 = 1, kwarg1 = 3)

#test_args_withDefaults_kwargs_withDefaults_starArgs_starStarKwargs
def myFunction(arg1, arg2 = 2, *args, kwarg1, kwarg2 = 4, **kwargs): self.answer = (arg1, arg2, args, kwarg1, kwarg2, kwargs)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', arg1 = 1, kwarg1 = 3)

#test_args_withDefaults_kwargs_withDefaults_starStarKwargs
def myFunction(arg1, arg2 = 2, *, kwarg1, kwarg2 = 4, **kwargs): self.answer = (arg1, arg2, kwarg1, kwarg2, kwargs)
pub.subscribe(myFunction, 'echo')
pub.sendMessage('echo', arg1 = 1, kwarg1 = 3)
skewty commented 6 years ago

@schollii what is left to fix / improve so this is accepted?

schollii commented 6 years ago

I have to know that the test suite passes, and that the examples still run in all versions of Python that get tested. The test suite gets run via tox in several Python versions so that one should be easy to execute. The examples are semi automated so probably a half hour of work mostly installing different versions of Python and the latest wxpython and running the example scripts.

JoshMayberry commented 6 years ago

I think this will not work for python versions below 3.5.

I'll try to fix potential version problems like this at lunch today.

schollii commented 6 years ago

Could you have two versions of callables.py and import the correct one based on python version? You'd actually have callables34.py and callables35.py, and callables.py would decide between the two and import all from the one it chooses.

JoshMayberry commented 6 years ago

You could go that route with it, but having multiple files might make future changes difficult for you.

I just pushed a commit that modifies the lines that would cause conflicts.

However you decide to address supporting different versions is up to you, because this is your module. I think it would be better for maintainability if you kept it to one file though.

schollii commented 6 years ago

That's fine. Looks like there is some fixing to do based on https://travis-ci.org/schollii/pypubsub/requests. I have activated pull request building so your next push will get built by travis-ci.org, maybe it'll actually show console output indicating failed tests. But probably best for you to install tox and run it locally to fix remaining issues.

schollii commented 6 years ago

@joshmayberry any update on this, are going to be able to check why some tests broke?

JoshMayberry commented 6 years ago

@scholli I'm sorry, I don't really know what to do.

schollii commented 6 years ago

@JoshMayberry There's a section in the docs about testing. IIRC (it's been a while) you basically pip install tox, then from root folder, just run "tox", everything else is handled automatically by it (including installing additional versions of Python locally).

JoshMayberry commented 6 years ago

@schollii I'm sorry. I've tried to find time to figure this out, but I don't have the time to do so right now. You can close this request and not make the changes if you want. Thank you for your time.

schollii commented 6 years ago

I'd like to keep those changes. It'll just take a bit of time before I can reopen my python devenv and see what the errors are, they might be easy fix. Else I'll create a branch with details about error and will ping you in case you have time to take a look.

schollii commented 5 years ago

This is no longer needed after the other recent fixes.