robinhood / thorn Goto Github PK
View Code? Open in Web Editor NEWEasy Webhooks for Python
License: Other
Easy Webhooks for Python
License: Other
Looks like support for Django 2.0 was added on on Dec 4, 2017 (in 5c89851#diff-354f30a63fb0907d4ad57269548329e3), but it was never released on PyPI.
Would it possible to have a new release? Are there any blockers?
Celery dispatcher does not set custom HTTP headers for webhook requests.
I am pretty sure the headers are being dropped because they are not included in the returned dict when the Request.as_dict method is called from here
I propose to ensure that Request.as_dict
returns the existing dict, but with the request instances headers (_headers) included. If this seems like a reasonable solution please let me know and I'll get a PR submitted.
thorn 1.5.0
I've get the sql command like insert a(k,k,k) values (a,a,a),(b,b,b),(c,c,c);
Once I formatted the sql commands, it ran out
insert into
a (
k,
k,
k
)
values
(
a,
a,
a
),
(
b,
b,
b
);
is there anyways to format the commands to
insert into a(k,k,k) values
(a,a,a),
(b,b,b);
Currently, it's possible to customize the payload sent by using webhook_payload
.
I think it could be useful to add a way to customize headers as well. It would allow, for example, to include an Authorize
header so that the receiving endpoint could associate the event to a user (eg a 'system' user with admin permission).
This could be implemented as either as webhook_header
in the model (that'd be my favorite option), or even just some kind of global settings.
If this is something you think it's useful, I can work on a PR.
I see some indicators that this project may no longer be maintained. I am considering incorporating this into our code base and I wanted to know if it would be possible to get some sort of confirmation from Robinhood that there is an intention to maintain this project over the long term.
Any comment from Robinhood on this would be greatly appreciated.
Tagging @ask due to status of largest contributor and apparent status of current staff at Robinhood.
Hi,
Great stuff! ๐
I didn't see any info in the documentation regarding ordering guarantees of posting callbacks (in success and failure scenarios).
Could you please elaborate?
Thanks!
Erik.
I am currently using python 3.8, Django 3.0.2 thorn 1.5.2 in Arch Linux. When I try to import thorn to my script it returns following error:
Traceback (most recent call last):
File "authbot.py", line 10, in <module>
from thorn import ModelEvent, webhook_model
File "/home/yorozuya3/Desktop/authtelegrambot/env/lib/python3.8/site-packages/thorn/__init__.py", line 9, in <module>
from .events import Event, ModelEvent
File "/home/yorozuya3/Desktop/authtelegrambot/env/lib/python3.8/site-packages/thorn/events.py", line 282
'__now_' in k for k in keys(self.filter_fields),
^
SyntaxError: Generator expression must be parenthesized
It would be useful if subscribers could receive events only related to a specific instance.
Scenario:
A web application lets users create their own AddressBook
. Each AddressBook
have many Contact
s:
class AddressBook(models.Model):
user = models.ForeignKey('auth.User')
@webhook_model(
on_create=ModelEvent('contact.created'),
)
class Contact(models.Model):
name = models.CharField(max_length=255)
address_book = models.ForeignKey(AddressBook, related_name='contacts')
There doesn't seem to be a way for a subscriber to receive contact.created
events only for Contact
s of a specific AddressBook
.
Hi,
I've looked at issue #7 and I'm not sure if it solves my issue, or if my case is more complex.
Given entities Transport Order, Company, User and Application.
A Transport Order is created by and "belongs to" a Producer Company. It is consumed by Consumer Companies. It maintains a m2m "consumers" relationship with companies.
Users are employees of the companies
Consumer companies only wish to be notified about updates/ deletes to Transport Orders they consume.
Applications are OAuth apps created by developers, to act on behalf of Users.
Application on behalf of an employee of a consumer company registers a subscription to transport_order.change.
Producer company edits an order consumed by the consumer company
Consumer company's webhook is hit by the change, and not with changes to orders it does not subscribe to.
I don't think the sender_field is advanced enough to handle this, but hopefully I'm wrong?
Using the local dispatcher (THORN_DISPATCHER = 'default'
), not the Celery-based one, if the webhook raises an error (e.g. due to a timeout), the on_timeout
and on_error
handlers passed to send()
aren't called. Instead the following internal error is raised:
File "thorn/events.py", line 124, in send
timeout=timeout, on_timeout=on_timeout,
File "thorn/events.py", line 146, in _send
allow_keepalive=self.allow_keepalive,
File "thorn/dispatch/base.py", line 73, in send
**kwargs
File "vine/synchronization.py", line 57, in __init__
[self.add_noincr(p) for p in promises or []]
File "vine/synchronization.py", line 57, in <listcomp>
[self.add_noincr(p) for p in promises or []]
File "vine/synchronization.py", line 82, in add_noincr
p.then(self)
AttributeError: 'NoneType' object has no attribute 'then'
I fixed (?) this with the following patch, although I am very unsure if it's correct. jonashaag@15453b2
Test case:
import django; django.setup()
import thorn
import thorn.django.models
thorn.django.models.Subscriber.objects.create(event='foo.*', url='http://8.8.8.8')
e = thorn.Event('foo.bar')
e.send({})
With my fix (?):
Traceback (most recent call last):
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/connection.py", line 141, in _new_conn
(self.host, self.port), self.timeout, **extra_kw)
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/util/connection.py", line 83, in create_connection
raise err
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/util/connection.py", line 73, in create_connection
sock.connect(sa)
socket.timeout: timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/connectionpool.py", line 601, in urlopen
chunked=chunked)
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/connectionpool.py", line 357, in _make_request
conn.request(method, url, **httplib_request_kw)
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1239, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1026, in _send_output
self.send(msg)
File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 964, in send
self.connect()
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/connection.py", line 166, in connect
conn = self._new_conn()
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/connection.py", line 146, in _new_conn
(self.host, self.timeout))
urllib3.exceptions.ConnectTimeoutError: (<urllib3.connection.HTTPConnection object at 0x10faddda0>, 'Connection to 8.8.8.8 timed out. (connect timeout=1)')
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "thorn/env3/lib/python3.6/site-packages/requests-2.18.4-py3.6.egg/requests/adapters.py", line 440, in send
timeout=timeout
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/connectionpool.py", line 639, in urlopen
_stacktrace=sys.exc_info()[2])
File "thorn/env3/lib/python3.6/site-packages/urllib3-1.22-py3.6.egg/urllib3/util/retry.py", line 388, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='8.8.8.8', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x10faddda0>, 'Connection to 8.8.8.8 timed out. (connect timeout=1)'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 9, in <module>
e.send({})
File "thorn/thorn/events.py", line 124, in send
timeout=timeout, on_timeout=on_timeout,
File "thorn/thorn/events.py", line 146, in _send
allow_keepalive=self.allow_keepalive,
File "thorn/thorn/dispatch/base.py", line 73, in send
**kwargs
File "thorn/env3/lib/python3.6/site-packages/vine-1.1.4-py3.6.egg/vine/synchronization.py", line 57, in __init__
[self.add_noincr(p) for p in promises or []]
File "thorn/env3/lib/python3.6/site-packages/vine-1.1.4-py3.6.egg/vine/synchronization.py", line 57, in <listcomp>
[self.add_noincr(p) for p in promises or []]
File "thorn/env3/lib/python3.6/site-packages/vine-1.1.4-py3.6.egg/vine/synchronization.py", line 82, in add_noincr
p.then(self)
File "thorn/env3/lib/python3.6/site-packages/vine-1.1.4-py3.6.egg/vine/abstract.py", line 53, in then
return self._p.then(on_success, on_error)
File "thorn/env3/lib/python3.6/site-packages/vine-1.1.4-py3.6.egg/vine/promises.py", line 173, in then
callback.throw(self.reason)
File "thorn/env3/lib/python3.6/site-packages/vine-1.1.4-py3.6.egg/vine/synchronization.py", line 94, in throw
self.p.throw(*args, **kwargs)
File "thorn/env3/lib/python3.6/site-packages/vine-1.1.4-py3.6.egg/vine/promises.py", line 217, in throw
reraise(type(exc), exc, tb)
File "thorn/env3/lib/python3.6/site-packages/vine-1.1.4-py3.6.egg/vine/five.py", line 178, in reraise
raise value.with_traceback(tb)
requests.exceptions.ConnectTimeout: HTTPConnectionPool(host='8.8.8.8', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x10faddda0>, 'Connection to 8.8.8.8 timed out. (connect timeout=1)'))
We'd like to have more than one subscription to the same event/URL combination.
I tried to remove the constraint in #24 and it seems to pass the test suite. So it's not actually assumed anywhere in the code.
The on_success
, on_error
and on_timeout
callbacks are really useful (e.g. I intend to use them to store/show recent webhook deliveries to the customers, same way GitHub does).
I think it would be safe to enable them for the celery dispatcher if we look at Python's what can be pickled list:
I've done it myself and it's working fine, I've also fixed the corresponding tests (see the commit below). Would you consider merging the branch?
Thank you for your work!
I'm working on writing some unit / integration tests for our webhook system and was wondering if there is a way to change the THORN_DISPATCHER setting during individual tests. or maybe just "reload" thorn somehow. My goal is to disable thorn during testing and then turn it on again for specific tests.
Typically I would just do this with something like:
def setUp(self):
settings.THORN_DISPATCHER = 'celery'
def tearDown(self):
settings.THORN_DISPATCHER = 'disabled'
But when I do this it looks like it still uses the default settings that were originally set. I think think this is because of the cached_property usage.
I looked through the thorn tests and couldn't find anything that resembled this and the google didn't seem very helpful...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.