diff --git a/.gitignore b/.gitignore index a167afb..f3546f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.*.sw? /*.geany /.idea /.tox diff --git a/.travis.yml b/.travis.yml index a6ad99c..ad171a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,19 @@ language: python +python: + - "3.5" install: - pip install coveralls tox script: - tox -env: # generate list with: $ tox -l | xargs -I ITEM echo " - TOXENV="ITEM - - TOXENV=py26-django14 - - TOXENV=py26-django15 - - TOXENV=py26-django16 - - TOXENV=py27-django14 - - TOXENV=py27-django15 - - TOXENV=py27-django16 - - TOXENV=py27-django17 - - TOXENV=py27-django18 - - TOXENV=py32-django15 - - TOXENV=py32-django16 - - TOXENV=py32-django17 - - TOXENV=py32-django18 - - TOXENV=py33-django15 - - TOXENV=py33-django16 - - TOXENV=py33-django17 - - TOXENV=py33-django18 - - TOXENV=py34-django17 - - TOXENV=py34-django18 +env: # generate list with: $ tox -l | sort | xargs -I ITEM echo " - TOXENV="ITEM + - TOXENV=py27-django17 + - TOXENV=py27-django18 + - TOXENV=py27-django19 + - TOXENV=py32-django17 + - TOXENV=py33-django17 + - TOXENV=py33-django18 + - TOXENV=py34-django17 + - TOXENV=py34-django18 + - TOXENV=py34-django19 + - TOXENV=py35-django18 + - TOXENV=py35-django19 diff --git a/README.rst b/README.rst index fa9baa2..705c42e 100644 --- a/README.rst +++ b/README.rst @@ -21,6 +21,9 @@ set-up very simple, while allowing advanced users to customize tracking. Each service is set up as recommended by the services themselves, using an asynchronous version of the Javascript code if possible. +Version 1.0.0 is the last to support Django < 1.7. Users of older django +versions should stick to 1.0.0, and are encouraged to upgrade their setups. + .. end docs include .. |latest-version| image:: https://img.shields.io/pypi/v/django-analytical.svg diff --git a/analytical/templatetags/chartbeat.py b/analytical/templatetags/chartbeat.py index e47f104..3b0e7d8 100644 --- a/analytical/templatetags/chartbeat.py +++ b/analytical/templatetags/chartbeat.py @@ -8,7 +8,6 @@ import json import re from django.conf import settings -from django.contrib.sites.models import Site from django.core.exceptions import ImproperlyConfigured from django.template import Library, Node, TemplateSyntaxError @@ -109,6 +108,7 @@ def _get_domain(context): if 'django.contrib.sites' not in settings.INSTALLED_APPS: return elif getattr(settings, 'CHARTBEAT_AUTO_DOMAIN', True): + from django.contrib.sites.models import Site try: return Site.objects.get_current().domain except (ImproperlyConfigured, Site.DoesNotExist): # pylint: disable=E1101 diff --git a/analytical/templatetags/mixpanel.py b/analytical/templatetags/mixpanel.py index 34f8efd..0490f76 100644 --- a/analytical/templatetags/mixpanel.py +++ b/analytical/templatetags/mixpanel.py @@ -8,6 +8,7 @@ import json import re from django.template import Library, Node, TemplateSyntaxError +from django.utils.safestring import mark_safe from analytical.utils import is_internal_ip, disable_html, get_identity, \ get_required_setting @@ -46,7 +47,7 @@ def mixpanel(parser, token): class MixpanelNode(Node): def __init__(self): - self.token = get_required_setting( + self._token = get_required_setting( 'MIXPANEL_API_TOKEN', MIXPANEL_API_TOKEN_RE, "must be a string containing a 32-digit hexadecimal number") @@ -65,11 +66,11 @@ class MixpanelNode(Node): 'properties': json.dumps(properties, sort_keys=True)}) except KeyError: pass - html = TRACKING_CODE % {'token': self.token, + html = TRACKING_CODE % {'token': self._token, 'commands': " ".join(commands)} if is_internal_ip(context, 'MIXPANEL'): html = disable_html(html, 'Mixpanel') - return html + return mark_safe(html) def contribute_to_analytical(add_node): diff --git a/analytical/templatetags/performable.py b/analytical/templatetags/performable.py index e357783..847f9c9 100644 --- a/analytical/templatetags/performable.py +++ b/analytical/templatetags/performable.py @@ -7,6 +7,7 @@ from __future__ import absolute_import import re from django.template import Library, Node, TemplateSyntaxError +from django.utils.safestring import mark_safe from analytical.utils import is_internal_ip, disable_html, get_identity, \ get_required_setting @@ -71,7 +72,7 @@ def performable_embed(hostname, page_id): """ Include a Performable landing page. """ - return EMBED_CODE % {'hostname': hostname, 'page_id': page_id} + return mark_safe(EMBED_CODE % {'hostname': hostname, 'page_id': page_id}) def contribute_to_analytical(add_node): diff --git a/analytical/tests/__init__.py b/analytical/tests/__init__.py index cf955c0..e69de29 100644 --- a/analytical/tests/__init__.py +++ b/analytical/tests/__init__.py @@ -1,28 +0,0 @@ -""" -Tests for django-analytical. -""" -# flake8: noqa - -from analytical.tests.test_tag_analytical import * -from analytical.tests.test_tag_chartbeat import * -from analytical.tests.test_tag_clickmap import * -from analytical.tests.test_tag_clicky import * -from analytical.tests.test_tag_crazy_egg import * -from analytical.tests.test_tag_gauges import * -from analytical.tests.test_tag_google_analytics import * -from analytical.tests.test_tag_gosquared import * -from analytical.tests.test_tag_hubspot import * -from analytical.tests.test_tag_intercom import * -from analytical.tests.test_tag_kiss_insights import * -from analytical.tests.test_tag_kiss_metrics import * -from analytical.tests.test_tag_mixpanel import * -from analytical.tests.test_tag_olark import * -from analytical.tests.test_tag_optimizely import * -from analytical.tests.test_tag_performable import * -from analytical.tests.test_tag_piwik import * -from analytical.tests.test_tag_reinvigorate import * -from analytical.tests.test_tag_snapengage import * -from analytical.tests.test_tag_spring_metrics import * -from analytical.tests.test_tag_uservoice import * -from analytical.tests.test_tag_woopra import * -from analytical.tests.test_utils import * diff --git a/analytical/tests/settings.py b/analytical/tests/settings.py index 374530c..ecb42e4 100644 --- a/analytical/tests/settings.py +++ b/analytical/tests/settings.py @@ -10,6 +10,9 @@ DATABASES = { } INSTALLED_APPS = [ + 'django.contrib.sites', + 'django.contrib.contenttypes', + 'django.contrib.auth', 'analytical', ] diff --git a/analytical/tests/test_tag_chartbeat.py b/analytical/tests/test_tag_chartbeat.py index 8444ff7..322fbd6 100644 --- a/analytical/tests/test_tag_chartbeat.py +++ b/analytical/tests/test_tag_chartbeat.py @@ -4,7 +4,6 @@ Tests for the Chartbeat template tags and filters. import re -from django.contrib.sites.models import Site from django.http import HttpRequest from django.template import Context from django.test import TestCase @@ -23,16 +22,20 @@ class ChartbeatTagTestCaseNoSites(TestCase): self.assertTrue('var _sf_async_config={"uid": "12345"};' in r, r) -@override_settings(INSTALLED_APPS=('analytical', 'django.contrib.sites')) +@override_settings(INSTALLED_APPS=( + 'analytical', + 'django.contrib.sites', + 'django.contrib.auth', + 'django.contrib.contenttypes', +)) @override_settings(CHARTBEAT_USER_ID='12345') class ChartbeatTagTestCaseWithSites(TestCase): def setUp(self): from django.core.management import call_command - from django.db.models import loading - loading.cache.loaded = False - call_command("syncdb", verbosity=0) + call_command("migrate", verbosity=0) def test_rendering_setup_site(self): + from django.contrib.sites.models import Site site = Site.objects.create(domain="test.com", name="test") with override_settings(SITE_ID=site.id): r = ChartbeatBottomNode().render(Context()) diff --git a/analytical/tests/test_tag_gosquared.py b/analytical/tests/test_tag_gosquared.py index 3fb05ad..9b946c0 100644 --- a/analytical/tests/test_tag_gosquared.py +++ b/analytical/tests/test_tag_gosquared.py @@ -8,7 +8,6 @@ from django.template import Context from django.test.utils import override_settings from analytical.templatetags.gosquared import GoSquaredNode -from analytical.tests import override_settings from analytical.tests.utils import TagTestCase from analytical.utils import AnalyticalException diff --git a/analytical/tests/test_tag_mixpanel.py b/analytical/tests/test_tag_mixpanel.py index eceae8d..b43a8d2 100644 --- a/analytical/tests/test_tag_mixpanel.py +++ b/analytical/tests/test_tag_mixpanel.py @@ -20,15 +20,15 @@ class MixpanelTagTestCase(TagTestCase): def test_tag(self): r = self.render_tag('mixpanel', 'mixpanel') - self.assertTrue( - "mixpanel.init('0123456789abcdef0123456789abcdef');" in r, - r) + self.assertIn( + "mixpanel.init('0123456789abcdef0123456789abcdef');", r, + ) def test_node(self): r = MixpanelNode().render(Context()) - self.assertTrue( - "mixpanel.init('0123456789abcdef0123456789abcdef');" in r, - r) + self.assertIn( + "mixpanel.init('0123456789abcdef0123456789abcdef');", r, + ) @override_settings(MIXPANEL_API_TOKEN=None) def test_no_token(self): diff --git a/analytical/tests/test_tag_performable.py b/analytical/tests/test_tag_performable.py index befee4b..2b1e16d 100644 --- a/analytical/tests/test_tag_performable.py +++ b/analytical/tests/test_tag_performable.py @@ -63,8 +63,9 @@ class PerformableEmbedTagTestCase(TagTestCase): def test_tag(self): domain = 'example.com' page = 'test' - r = self.render_tag('performable', 'performable_embed "%s" "%s"' - % (domain, page)) - self.assertTrue( - "$f.initialize({'host': 'example.com', 'page': 'test'});" in r, - r) + tag = self.render_tag( + 'performable', 'performable_embed "%s" "%s"' % (domain, page) + ) + self.assertIn( + "$f.initialize({'host': 'example.com', 'page': 'test'});", tag + ) diff --git a/analytical/utils.py b/analytical/utils.py index 2c52478..da9413a 100644 --- a/analytical/utils.py +++ b/analytical/utils.py @@ -3,7 +3,6 @@ Utility function for django-analytical. """ from django.conf import settings -from django.contrib.sites.models import Site from django.core.exceptions import ImproperlyConfigured @@ -103,6 +102,7 @@ def get_domain(context, prefix): domain = getattr(settings, 'ANALYTICAL_DOMAIN', None) if domain is None: if 'django.contrib.sites' in settings.INSTALLED_APPS: + from django.contrib.sites.models import Site try: domain = Site.objects.get_current().domain except (ImproperlyConfigured, Site.DoesNotExist): diff --git a/requirements.txt b/requirements.txt index 94a0e83..fa56c66 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -Django +Django>=1.7.0 diff --git a/setup.py b/setup.py index 5488406..5e988c2 100644 --- a/setup.py +++ b/setup.py @@ -47,6 +47,19 @@ def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() +try: + import django + os.environ.setdefault( + "DJANGO_SETTINGS_MODULE", + "analytical.tests.settings" + ) + django.setup() +except ImportError: + print( + "Could not import django. " + "This is fine, unless you intend to run unit tests." + ) + import analytical setup( @@ -85,6 +98,6 @@ setup( download_url='https://github.com/jcassee/django-analytical/archive/master.zip', cmdclass=cmdclass, install_requires=[ - 'Django>=1.4', + 'Django>=1.7.0', ], ) diff --git a/tox.ini b/tox.ini index 713551a..affba1d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,27 +1,18 @@ [tox] envlist = - py{26,27}-django{14,15,16}, - py{32,33}-django{15,16}, - py{27}-django{17,18}, - py{32,33,34}-django{17,18}, + py{27,32,33,34}-django17 + py33-django18 + py{27,34,35}-django{18,19} [testenv] commands = coverage run setup.py test - coveralls -basepython = - py26: python2.6 - py27: python2.7 - py32: python3.2 - py33: python3.3 - py34: python3.4 + sh -c 'coveralls | true' deps = coverage==3.7.1 coveralls - py26: unittest2 - django14: Django>=1.4,<1.5 - django15: Django>=1.5,<1.6 - django16: Django>=1.6,<1.7 django17: Django>=1.7,<1.8 django18: Django>=1.8,<1.9 + django19: Django>=1.9,<1.10 passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH +whitelist_externals = sh