This repository has been archived by the owner on May 14, 2024. It is now read-only.
Closed
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
2884d14
local sixpack
35498a3
1.1.1
3585ebb
add migration
6a83107
add missing sixpack arg
3c5c360
update gitignore
9528c8f
update docs
71ba66d
import and typo
d8b925a
address comments
a9900a1
new test
f9fe83c
more tests
6f41a61
fix tests
7989f0e
1.1.0
58838e7
address args
0889c91
update doc
2b727af
typo!
506cabc
bucket param
05b3682
add south dependency
4437405
south >= 1.0.0 and backwards compatibility
3640bd9
Use sixpack-client 1.1.2
b425a33
updated package to use sixpack-client 1.1.2
98370e3
Merge branch 'local' of github.com:waveaccounting/django-sixpack into…
801b966
fixed a conversion bug
9a2aca3
1.1.1
d7b91a5
fix for duplicate entries
1799c1c
upgraded to 1.1.2 to fix duplicate entries
594a68c
drop south
ac35d07
Merge pull request #10 from waveaccounting/drop-south
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,5 @@ local_settings.py | |
build | ||
dist | ||
*.egg-info | ||
*.egg | ||
*.eggs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
Dan Langer <dan@waveapps.com> | ||
Joseph Kahn <jkahn@waveapps.com> | ||
Robin Edwards <https://github.com/robinedwards> | ||
Adrian Maurer <amaurer@waveapps.com> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,6 +87,27 @@ If something ever goes wrong - a request times out, the ``sixpack`` server disap | |
calls will return the control alternative, and all ``convert`` calls will seem successful (and we'll note this happend | ||
in the log). | ||
|
||
----------------- | ||
Tracking Locally | ||
----------------- | ||
|
||
By passing in the argument `local` in the SixpackTest constructor you can tell django-sixpack to create a convertible db record for each participant. | ||
|
||
This feature is particullary useful when you want to pull information on an existing participant, a feature unavailable through Sixpack API. | ||
|
||
.. code:: python | ||
|
||
experiment = ButtonColorTest(local=True) | ||
|
||
You may also choose to track only locally by passing in `sixpack=False` to the test constructor. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This description doesn't match the sample code on line 106. |
||
|
||
.. code:: python | ||
|
||
experiment = ButtonColorTest(local=True, server=False) | ||
|
||
*Make sure you run a migration for the django-sixpack's `SixpackParticipant` model.* | ||
|
||
|
||
Suported Versions | ||
----------------- | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
__version__ = "1.0.5" | ||
__version__ = "1.1.3-wave" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,8 @@ | |
from django.conf import settings | ||
from requests.exceptions import RequestException | ||
|
||
from models import SixpackParticipant | ||
|
||
RE_FIRST_CAP = re.compile('(.)([A-Z][a-z]+)') | ||
RE_ALL_CAP = re.compile('([a-z0-9])([A-Z])') | ||
RE_TEST_NAME = re.compile('_test$') | ||
|
@@ -27,11 +29,17 @@ class SixpackTest(object): | |
timeout = None | ||
control = None | ||
alternatives = None | ||
local = False | ||
server = True | ||
|
||
def __init__(self, instance): | ||
def __init__(self, instance, local=None, server=None): | ||
self._instance = instance | ||
self.host = self.host or getattr(settings, 'SIXPACK_HOST', sixpack.SIXPACK_HOST) | ||
self.timeout = self.timeout or getattr(settings, 'SIXPACK_TIMEOUT', sixpack.SIXPACK_TIMEOUT) | ||
if local is not None: | ||
self.local = local | ||
if server is not None: | ||
self.server = server | ||
|
||
@property | ||
def client_id(self): | ||
|
@@ -62,8 +70,15 @@ def get_client_id(self, instance): | |
|
||
return client_id | ||
|
||
def participate(self, force=None, user_agent=None, ip_address=None): | ||
if not self.host: | ||
def get_participant_bucket(self): | ||
try: | ||
participant = SixpackParticipant.objects.get(unique_attr=self.client_id, experiment_name=self._get_experiment_name()) | ||
except SixpackParticipant.DoesNotExist: | ||
return None | ||
return participant.bucket | ||
|
||
def participate(self, force=None, user_agent=None, ip_address=None, prefetch=False, bucket=None): | ||
if not self.host and not self.local: | ||
try: | ||
if force in self.alternatives: | ||
return force | ||
|
@@ -73,16 +88,32 @@ def participate(self, force=None, user_agent=None, ip_address=None): | |
|
||
session = self._get_session(user_agent, ip_address) | ||
experiment_name = self._get_experiment_name() | ||
chosen_alternative = bucket | ||
|
||
if self.local and not self.server: | ||
prefetch = True | ||
|
||
try: | ||
resp = session.participate(experiment_name, self.alternatives, force) | ||
resp = session.participate(experiment_name, self.alternatives, force=force, prefetch=prefetch, bucket=bucket) | ||
except RequestException: | ||
logger.exception("Error while trying to .participate") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While you're in here, please make the quotation use consistent. |
||
if force in self.alternatives: | ||
return force | ||
return self.alternatives[0] | ||
chosen_alternative = force | ||
else: | ||
chosen_alternative = self.alternatives[0] | ||
else: | ||
return resp['alternative']['name'] | ||
chosen_alternative = resp['alternative']['name'] | ||
finally: | ||
if self.local and chosen_alternative: | ||
try: | ||
SixpackParticipant.objects.get_or_create(unique_attr=self.client_id, experiment_name=experiment_name, bucket=chosen_alternative) | ||
except SixpackParticipant.MultipleObjectsReturned: | ||
# clean up duplicate entries | ||
duplicates = SixpackParticipant.objects.filter(unique_attr=self.client_id, experiment_name=experiment_name, bucket=chosen_alternative) | ||
for dup in duplicates[1:]: | ||
dup.delete() | ||
|
||
return chosen_alternative | ||
|
||
def convert(self, kpi=None): | ||
if not self.host: | ||
|
@@ -92,8 +123,16 @@ def convert(self, kpi=None): | |
experiment_name = self._get_experiment_name() | ||
try: | ||
resp = session.convert(experiment_name) | ||
|
||
if self.local: | ||
participant_exists = SixpackParticipant.objects.filter(unique_attr=self.client_id, experiment_name=experiment_name).exists() | ||
if participant_exists: | ||
participant = SixpackParticipant.objects.filter(unique_attr=self.client_id, experiment_name=experiment_name)[0] | ||
participant.converted = True | ||
participant.save() | ||
|
||
except RequestException as e: | ||
logger.exception("Error while trying to .convert: {err}".format(err=e)) | ||
logger.exception("Error while trying to .convert: %s", e) | ||
return False | ||
else: | ||
return resp['status'] == 'ok' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import unicode_literals | ||
|
||
from django.db import models, migrations | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='SixpackParticipant', | ||
fields=[ | ||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), | ||
('experiment_name', models.CharField(max_length=255, db_index=True)), | ||
('unique_attr', models.CharField(max_length=255, db_index=True)), | ||
('converted', models.BooleanField(default=False)), | ||
('bucket', models.CharField(max_length=255)), | ||
('date_added', models.DateTimeField(auto_now_add=True)), | ||
('date_modified', models.DateTimeField(auto_now=True)), | ||
], | ||
options={ | ||
}, | ||
bases=(models.Model,), | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,10 @@ | ||
# No models | ||
from django.db import models | ||
|
||
|
||
class SixpackParticipant(models.Model): | ||
experiment_name = models.CharField(max_length=255, db_index=True) | ||
unique_attr = models.CharField(max_length=255, db_index=True) | ||
converted = models.BooleanField(default=False) | ||
bucket = models.CharField(max_length=255) | ||
date_added = models.DateTimeField(auto_now_add=True) | ||
date_modified = models.DateTimeField(auto_now=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# -*- coding: utf-8 -*- | ||
from south.utils import datetime_utils as datetime | ||
from south.db import db | ||
from south.v2 import SchemaMigration | ||
from django.db import models | ||
|
||
|
||
class Migration(SchemaMigration): | ||
|
||
def forwards(self, orm): | ||
# Adding model 'SixpackParticipant' | ||
db.create_table(u'djsixpack_sixpackparticipant', ( | ||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), | ||
('experiment_name', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)), | ||
('unique_attr', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)), | ||
('converted', self.gf('django.db.models.fields.BooleanField')(default=False)), | ||
('bucket', self.gf('django.db.models.fields.CharField')(max_length=255)), | ||
('date_added', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)), | ||
('date_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), | ||
)) | ||
db.send_create_signal(u'djsixpack', ['SixpackParticipant']) | ||
|
||
|
||
def backwards(self, orm): | ||
# Deleting model 'SixpackParticipant' | ||
db.delete_table(u'djsixpack_sixpackparticipant') | ||
|
||
|
||
models = { | ||
u'djsixpack.sixpackparticipant': { | ||
'Meta': {'object_name': 'SixpackParticipant'}, | ||
'bucket': ('django.db.models.fields.CharField', [], {'max_length': '255'}), | ||
'converted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), | ||
'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), | ||
'date_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), | ||
'experiment_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), | ||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), | ||
'unique_attr': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}) | ||
} | ||
} | ||
|
||
complete_apps = ['djsixpack'] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add docs about why you'd want to do this/use cases for this? I get that it's creating a record in the DB, but not why I'd like to do that.