{"action":"created","issue":{"url":"https://api.github.com/repos/RPi-Distro/python-gpiozero/issues/436","repository_url":"https://api.github.com/repos/RPi-Distro/python-gpiozero","labels_url":"https://api.github.com/repos/RPi-Distro/python-gpiozero/issues/436/labels{/name}","comments_url":"https://api.github.com/repos/RPi-Distro/python-gpiozero/issues/436/comments","events_url":"https://api.github.com/repos/RPi-Distro/python-gpiozero/issues/436/events","html_url":"https://github.com/RPi-Distro/python-gpiozero/issues/436","id":177163104,"number":436,"title":"Event handler rejection too broad","user":{"login":"Marrin","id":2564163,"avatar_url":"https://avatars.githubusercontent.com/u/2564163?v=3","gravatar_id":"","url":"https://api.github.com/users/Marrin","html_url":"https://github.com/Marrin","followers_url":"https://api.github.com/users/Marrin/followers","following_url":"https://api.github.com/users/Marrin/following{/other_user}","gists_url":"https://api.github.com/users/Marrin/gists{/gist_id}","starred_url":"https://api.github.com/users/Marrin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Marrin/subscriptions","organizations_url":"https://api.github.com/users/Marrin/orgs","repos_url":"https://api.github.com/users/Marrin/repos","events_url":"https://api.github.com/users/Marrin/events{/privacy}","received_events_url":"https://api.github.com/users/Marrin/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2016-09-15T12:28:59Z","updated_at":"2016-09-15T13:24:21Z","closed_at":null,"body":"Example:\r\n\r\n```python\r\n#!/usr/bin/env python\r\n# coding: utf8\r\nfrom __future__ import absolute_import, division, print_function\r\nfrom functools import partial\r\nfrom gpiozero.mixins import EventsMixin\r\n\r\ncallback = partial(print, 'Hello')\r\ncallback()  # -> prints Hello.\r\n\r\nevents_mixin = EventsMixin()\r\nevents_mixin.when_activated = callback  # Exception!\r\n```\r\n\r\nTraceback:\r\n```\r\nTraceback (most recent call last):\r\n  File \"test.py\", line 12, in <module>\r\n    events_mixin.when_activated = callback  # -> BadEventHandler: value must be a\r\n  File \"/usr/local/lib/python2.7/dist-packages/gpiozero/mixins.py\", line 209, in when_activated\r\n    self._when_activated = self._wrap_callback(value)\r\n  File \"/usr/local/lib/python2.7/dist-packages/gpiozero/mixins.py\", line 283, in _wrap_callback\r\n    'value must be a callable which accepts up to one '\r\ngpiozero.exc.BadEventHandler: value must be a callable which accepts up to one mandatory parameter\r\n```\r\n\r\n`callback` is a perfectly valid callback that accepts no arguments. Looking at the code you are not testing what the exception message suggests, but simply reject all objects where you can't get the functions signature. Which rejects many valid ones, including `partial` objects from the standard library.  What about trusting the programmer and duck typing here, instead of excessive checking up front and rejecting false positives?\r\n\r\nThis also means working code can break merely by re-implementing a callback in C.\r\n\r\nWhy checking anyway?  Just wrap the actual call into a try and print a stack trace if it fails, like most GUI libraries do for callbacks."},"comment":{"url":"https://api.github.com/repos/RPi-Distro/python-gpiozero/issues/comments/247326718","html_url":"https://github.com/RPi-Distro/python-gpiozero/issues/436#issuecomment-247326718","issue_url":"https://api.github.com/repos/RPi-Distro/python-gpiozero/issues/436","id":247326718,"user":{"login":"Marrin","id":2564163,"avatar_url":"https://avatars.githubusercontent.com/u/2564163?v=3","gravatar_id":"","url":"https://api.github.com/users/Marrin","html_url":"https://github.com/Marrin","followers_url":"https://api.github.com/users/Marrin/followers","following_url":"https://api.github.com/users/Marrin/following{/other_user}","gists_url":"https://api.github.com/users/Marrin/gists{/gist_id}","starred_url":"https://api.github.com/users/Marrin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Marrin/subscriptions","organizations_url":"https://api.github.com/users/Marrin/orgs","repos_url":"https://api.github.com/users/Marrin/repos","events_url":"https://api.github.com/users/Marrin/events{/privacy}","received_events_url":"https://api.github.com/users/Marrin/received_events","type":"User","site_admin":false},"created_at":"2016-09-15T13:24:21Z","updated_at":"2016-09-15T13:24:21Z","body":"@lurch In the use case I've encountered the problem I could use `lambda` but just because the function is fixed.\r\n\r\nIf I want to use a function or method with no arguments written in C the workaround would be wrapping it in a `lambda` where the readers will scratch their heads why there is a seemingly useless lambda.  It needs to be accompanied with a comment explaining why this isn't useless code that can't be optimized away.\r\n\r\nAlso if both, function and argument(s) where variable, I would have to re-implement `functools.partial()` in Python. Re-Implementing a very generic, often used function from the standard library feels wrong. Reinventing the wheel seems to be missing the point of having generic functions in a standard library. :-)"}}
{"actor":{"display_login":"Marrin"}}