Skip to content

Commit

Permalink
fix: Avoid dict as default parameter (#50)
Browse files Browse the repository at this point in the history
Fixes an issue where the default timestamp gets locked the first time it is called, and is the same for every subsequent request.
  • Loading branch information
joladev authored Apr 5, 2019
1 parent 5e7a380 commit 0066377
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 4 deletions.
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## master

- [#50](https://github.com/castle/castle-python/pull/50) avoid dict as default parameter

## 2.3.0 (2019-01-16)

- [#48](https://github.com/castle/castle-python/pull/48) add connection pooling
Expand Down
16 changes: 12 additions & 4 deletions castle/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,26 @@
class Client(object):

@classmethod
def from_request(cls, request, options={}):
def from_request(cls, request, options=None):
if options is None:
options = {}
return cls(
cls.to_context(request, options),
cls.to_options(options)
)

@staticmethod
def to_context(request, options={}):
def to_context(request, options=None):
if options is None:
options = {}
default_context = ContextDefault(
request, options.get('cookies')).call()
return ContextMerger.call(default_context, options.get('context', {}))

@staticmethod
def to_options(options={}):
def to_options(options=None):
if options is None:
options = {}
options.setdefault('timestamp', generate_timestamp())
if 'traits' in options:
warnings.warn('use user_traits instead of traits key', DeprecationWarning)
Expand All @@ -40,7 +46,9 @@ def failover_response_or_raise(options, exception):
raise exception
return FailoverResponse(options.get('user_id'), None, exception.__class__.__name__).call()

def __init__(self, context, options={}):
def __init__(self, context, options=None):
if options is None:
options = {}
self.do_not_track = options.get('do_not_track', False)
self.timestamp = options.get('timestamp')
self.context = context
Expand Down
23 changes: 23 additions & 0 deletions castle/test/client_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from collections import namedtuple
import responses
from castle.test import mock, unittest
Expand Down Expand Up @@ -215,3 +216,25 @@ def test_failover_strategy_throw(self):
with self.assertRaises(Exception):
Client.failover_response_or_raise(options, Exception())
configuration.failover_strategy = 'allow'

@responses.activate
def test_timestamps_are_not_global(self):
response_text = {'action': 'allow', 'user_id': '1234'}
responses.add(
responses.POST,
'https://api.castle.io/v1/authenticate',
json=response_text,
status=200
)
options1 = {'event': '$login.authenticate', 'user_id': '1234'}
options2 = {'event': '$login.authenticate', 'user_id': '1234'}
client1 = Client.from_request(request())
client1.authenticate(options1)
self.mock_timestamp.return_value = '2018-01-02T04:04:05.678'
client2 = Client.from_request(request())
client2.authenticate(options2)

response_body1 = json.loads(responses.calls[0].request.body)
response_body2 = json.loads(responses.calls[1].request.body)

self.assertNotEqual(response_body1['timestamp'], response_body2['timestamp'])

0 comments on commit 0066377

Please sign in to comment.