diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..633745a --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,76 @@ +# copied from django-cte +name: dynamic_initial_data tests +on: + push: + branches: [master] + pull_request: + branches: [master,develop] + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python: ['3.7', '3.8', '3.9'] + # Time to switch to pytest or nose2?? + # nosetests is broken on 3.10 + # AttributeError: module 'collections' has no attribute 'Callable' + # https://github.com/nose-devs/nose/issues/1099 + django: + - 'Django~=3.2.0' + - 'Django~=4.0.0' + - 'Django~=4.1.0' + - 'Django~=4.2.0' + experimental: [false] + exclude: + - python: '3.7' + django: 'Django~=4.0.0' + - python: '3.7' + django: 'Django~=4.1.0' + - python: '3.7' + django: 'Django~=4.2.0' + services: + postgres: + image: postgres:latest + env: + POSTGRES_DB: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python }} + - name: Setup + run: | + python --version + pip install --upgrade pip wheel + pip install -r requirements/requirements.txt + pip install -r requirements/requirements-testing.txt + pip install "${{ matrix.django }}" + pip freeze + - name: Run tests + env: + DB_SETTINGS: >- + { + "ENGINE":"django.db.backends.postgresql_psycopg2", + "NAME":"dynamic_initial_data", + "USER":"postgres", + "PASSWORD":"postgres", + "HOST":"localhost", + "PORT":"5432" + } + run: | + coverage run manage.py test dynamic_initial_data + coverage report --fail-under=99 + continue-on-error: ${{ matrix.experimental }} + - name: Check style + run: flake8 dynamic_initial_data diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5ac7494..0000000 --- a/.travis.yml +++ /dev/null @@ -1,42 +0,0 @@ -dist: xenial -language: python -sudo: false - -python: - - "3.6" - - "3.7" - -env: - matrix: - - DJANGO=2.0 - - DJANGO=2.1 - - DJANGO=2.2 - - DJANGO=master - -addons: - postgresql: '9.6' - -matrix: - exclude: - - { python: "3.7", env: DJANGO=2.0 } - - include: - - { python: "3.6", env: TOXENV=flake8 } - - allow_failures: - - env: DJANGO=master - -install: - - pip install tox-travis - -before_script: - - psql -c 'CREATE DATABASE dynamic_initial_data;' -U postgres - -script: - - tox - -after_success: - coveralls - -notifications: - email: false diff --git a/dynamic_initial_data/__init__.py b/dynamic_initial_data/__init__.py index cec34bb..b35e687 100644 --- a/dynamic_initial_data/__init__.py +++ b/dynamic_initial_data/__init__.py @@ -1,4 +1,3 @@ # flake8: noqa from .version import __version__ -default_app_config = 'dynamic_initial_data.apps.DynamicInitialDataConfig' diff --git a/dynamic_initial_data/docs/release_notes.rst b/dynamic_initial_data/docs/release_notes.rst index c7f30d2..a51c554 100644 --- a/dynamic_initial_data/docs/release_notes.rst +++ b/dynamic_initial_data/docs/release_notes.rst @@ -1,6 +1,13 @@ Release Notes ============= +v2.2.0 +------ +* Add support for django 3.2, 4.0, 4.1, 4.2 +* Add support for python 3.8, 3.9 +* Remove support for django 2.0, 2.1, 2.2, 3.0, 3.1 +* Remove support for python 3.6 + v2.1.0 ------ * Python 3.7 diff --git a/dynamic_initial_data/migrations/0001_initial.py b/dynamic_initial_data/migrations/0001_initial.py index 62c63c1..7a55392 100644 --- a/dynamic_initial_data/migrations/0001_initial.py +++ b/dynamic_initial_data/migrations/0001_initial.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals from django.db import models, migrations import django.db.models.deletion diff --git a/dynamic_initial_data/tests/base_tests.py b/dynamic_initial_data/tests/base_tests.py index 7a90c7b..9dce88a 100644 --- a/dynamic_initial_data/tests/base_tests.py +++ b/dynamic_initial_data/tests/base_tests.py @@ -6,7 +6,7 @@ from django.test.utils import override_settings from django_dynamic_fixture import G from freezegun import freeze_time -from mock import patch +from unittest.mock import patch from dynamic_initial_data.base import BaseInitialData, InitialDataUpdater from dynamic_initial_data.exceptions import InitialDataMissingApp, InitialDataCircularDependency @@ -31,7 +31,7 @@ def test_register_for_deletion_one_arg(self): initial_data = BaseInitialData() account = G(Account) initial_data.register_for_deletion(account) - self.assertEquals(initial_data.get_model_objs_registered_for_deletion(), [account]) + self.assertEqual(initial_data.get_model_objs_registered_for_deletion(), [account]) def test_register_for_deletion_multiple_args(self): """ @@ -41,7 +41,7 @@ def test_register_for_deletion_multiple_args(self): account1 = G(Account) account2 = G(Account) initial_data.register_for_deletion(account1, account2) - self.assertEquals(initial_data.get_model_objs_registered_for_deletion(), [account1, account2]) + self.assertEqual(initial_data.get_model_objs_registered_for_deletion(), [account1, account2]) class TestInvalidDeletions(TransactionTestCase): @@ -59,10 +59,10 @@ def test_cant_delete_obj_in_receipt(self): RegisteredForDeletionReceipt.objects.create(model_obj=account, register_time=datetime(2013, 4, 5)) initial_data_updater.model_objs_registered_for_deletion = [] - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 2) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 2) with transaction.atomic(): initial_data_updater.handle_deletions() - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) class TestHandleDeletions(TestCase): @@ -86,13 +86,13 @@ def test_create_one_obj(self): account = G(Account) self.initial_data_updater.model_objs_registered_for_deletion = [account] - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) with freeze_time('2013-04-12'): self.initial_data_updater.handle_deletions() receipt = RegisteredForDeletionReceipt.objects.get() - self.assertEquals(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) - self.assertEquals(receipt.model_obj_id, account.id) - self.assertEquals(receipt.register_time, datetime(2013, 4, 12)) + self.assertEqual(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) + self.assertEqual(receipt.model_obj_id, account.id) + self.assertEqual(receipt.register_time, datetime(2013, 4, 12)) def test_create_dup_objs(self): """ @@ -101,13 +101,13 @@ def test_create_dup_objs(self): account = G(Account) self.initial_data_updater.model_objs_registered_for_deletion = [account, account] - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) with freeze_time('2013-04-12'): self.initial_data_updater.handle_deletions() receipt = RegisteredForDeletionReceipt.objects.get() - self.assertEquals(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) - self.assertEquals(receipt.model_obj_id, account.id) - self.assertEquals(receipt.register_time, datetime(2013, 4, 12)) + self.assertEqual(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) + self.assertEqual(receipt.model_obj_id, account.id) + self.assertEqual(receipt.register_time, datetime(2013, 4, 12)) def test_create_dup_proxy_objs(self): """ @@ -117,22 +117,22 @@ def test_create_dup_proxy_objs(self): proxy_account = ProxyAccount.objects.get(id=account.id) self.initial_data_updater.model_objs_registered_for_deletion = [account, account, proxy_account] - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) with freeze_time('2013-04-12'): self.initial_data_updater.handle_deletions() - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 2) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 2) receipt = RegisteredForDeletionReceipt.objects.get(model_obj_type=ContentType.objects.get_for_model(account)) - self.assertEquals(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) - self.assertEquals(receipt.model_obj_id, account.id) - self.assertEquals(receipt.register_time, datetime(2013, 4, 12)) + self.assertEqual(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) + self.assertEqual(receipt.model_obj_id, account.id) + self.assertEqual(receipt.register_time, datetime(2013, 4, 12)) receipt = RegisteredForDeletionReceipt.objects.get( model_obj_type=ContentType.objects.get_for_model(proxy_account, for_concrete_model=False)) - self.assertEquals( + self.assertEqual( receipt.model_obj_type, ContentType.objects.get_for_model(ProxyAccount, for_concrete_model=False)) - self.assertEquals(receipt.model_obj_id, proxy_account.id) - self.assertEquals(receipt.register_time, datetime(2013, 4, 12)) + self.assertEqual(receipt.model_obj_id, proxy_account.id) + self.assertEqual(receipt.register_time, datetime(2013, 4, 12)) def test_create_delete_one_obj(self): """ @@ -141,21 +141,21 @@ def test_create_delete_one_obj(self): account = G(Account) self.initial_data_updater.model_objs_registered_for_deletion = [account] - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) with freeze_time('2013-04-12'): self.initial_data_updater.handle_deletions() receipt = RegisteredForDeletionReceipt.objects.get() - self.assertEquals(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) - self.assertEquals(receipt.model_obj_id, account.id) - self.assertEquals(receipt.register_time, datetime(2013, 4, 12)) + self.assertEqual(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) + self.assertEqual(receipt.model_obj_id, account.id) + self.assertEqual(receipt.register_time, datetime(2013, 4, 12)) # Now, don't register the object for deletion and run it again at a different time self.initial_data_updater.model_objs_registered_for_deletion = [] with freeze_time('2013-04-12 05:00:00'): self.initial_data_updater.handle_deletions() # The object should be deleted, along with its receipt - self.assertEquals(Account.objects.count(), 0) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) def test_create_update_one_obj(self): """ @@ -164,21 +164,21 @@ def test_create_update_one_obj(self): account = G(Account) self.initial_data_updater.model_objs_registered_for_deletion = [account] - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) with freeze_time('2013-04-12'): self.initial_data_updater.handle_deletions() receipt = RegisteredForDeletionReceipt.objects.get() - self.assertEquals(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) - self.assertEquals(receipt.model_obj_id, account.id) - self.assertEquals(receipt.register_time, datetime(2013, 4, 12)) + self.assertEqual(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) + self.assertEqual(receipt.model_obj_id, account.id) + self.assertEqual(receipt.register_time, datetime(2013, 4, 12)) # Run the deletion handler again at a different time. It should not delete the object with freeze_time('2013-04-12 05:00:00'): self.initial_data_updater.handle_deletions() # The object should not be deleted, along with its receipt - self.assertEquals(Account.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.get().register_time, datetime(2013, 4, 12, 5)) + self.assertEqual(Account.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.get().register_time, datetime(2013, 4, 12, 5)) def test_delete_already_deleted_obj(self): """ @@ -187,25 +187,25 @@ def test_delete_already_deleted_obj(self): account = G(Account) self.initial_data_updater.model_objs_registered_for_deletion = [account] - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) with freeze_time('2013-04-12'): self.initial_data_updater.handle_deletions() receipt = RegisteredForDeletionReceipt.objects.get() - self.assertEquals(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) - self.assertEquals(receipt.model_obj_id, account.id) - self.assertEquals(receipt.register_time, datetime(2013, 4, 12)) + self.assertEqual(receipt.model_obj_type, ContentType.objects.get_for_model(Account)) + self.assertEqual(receipt.model_obj_id, account.id) + self.assertEqual(receipt.register_time, datetime(2013, 4, 12)) # Delete the model object. The receipt should still exist account.delete() - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 1) # Now, don't register the object for deletion and run it again at a different time self.initial_data_updater.model_objs_registered_for_deletion = [] with freeze_time('2013-04-12 05:00:00'): self.initial_data_updater.handle_deletions() # The object should be deleted, along with its receipt - self.assertEquals(Account.objects.count(), 0) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) class InitialDataUpdaterTest(TestCase): @@ -238,7 +238,7 @@ def test_load_app_cached(self, import_patch): initial_data_updater.load_app('fake') initial_data_updater.load_app('fake') initial_data_updater.load_app('fake') - self.assertEquals(import_patch.call_count, 1) + self.assertEqual(import_patch.call_count, 1) @patch('dynamic_initial_data.base.import_string', return_value=MockClass) def test_load_app_doesnt_exist(self, import_patch): diff --git a/dynamic_initial_data/tests/fake_app_2/fixtures/initial_data.py b/dynamic_initial_data/tests/fake_app_2/fixtures/initial_data.py index f76debb..bc09ecd 100644 --- a/dynamic_initial_data/tests/fake_app_2/fixtures/initial_data.py +++ b/dynamic_initial_data/tests/fake_app_2/fixtures/initial_data.py @@ -1,3 +1,3 @@ from fake import BadPath -assert(BadPath) # pragma: no cover +assert BadPath # pragma: no cover diff --git a/dynamic_initial_data/tests/integration_tests.py b/dynamic_initial_data/tests/integration_tests.py index 06fe0e8..f32b93e 100644 --- a/dynamic_initial_data/tests/integration_tests.py +++ b/dynamic_initial_data/tests/integration_tests.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.core.management import call_command -from mock import patch +from unittest.mock import patch from dynamic_initial_data.base import BaseInitialData, InitialDataUpdater from dynamic_initial_data.models import RegisteredForDeletionReceipt @@ -21,15 +21,15 @@ def update_initial_data(self): Account.objects.get_or_create() # Verify no account objects exist - self.assertEquals(Account.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) with patch.object(InitialDataUpdater, 'load_app', return_value=AccountInitialData) as load_app_mock: InitialDataUpdater().update_app('test_app') # It should be called twice - once for initial loading, and twice for dependency testing - self.assertEquals(load_app_mock.call_count, 2) + self.assertEqual(load_app_mock.call_count, 2) # Verify an account object was created - self.assertEquals(Account.objects.count(), 1) + self.assertEqual(Account.objects.count(), 1) def test_multiple_same_objects(self): """ @@ -45,15 +45,15 @@ def update_initial_data(self): return [account, account, account] # Verify no account objects exist - self.assertEquals(Account.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) with patch.object(InitialDataUpdater, 'load_app', return_value=AccountInitialData1): InitialDataUpdater().update_all_apps() InitialDataUpdater().update_all_apps() # Verify an account object was created and is managed by a deletion receipt - self.assertEquals(Account.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 1) + self.assertEqual(Account.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 1) def test_handle_deletions_returned_from_update_initial_data(self): """ @@ -77,14 +77,14 @@ def update_initial_data(self): pass # Verify no account objects exist - self.assertEquals(Account.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) with patch.object(InitialDataUpdater, 'load_app', return_value=AccountInitialData1): InitialDataUpdater().update_all_apps() # Verify an account object was created and is managed by a deletion receipt - self.assertEquals(Account.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 1) + self.assertEqual(Account.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 1) # Run the initial data process again, this time not registering the account for # deletion. It should be deleted. @@ -92,8 +92,8 @@ def update_initial_data(self): InitialDataUpdater().update_all_apps() # Verify there are no accounts or receipts - self.assertEquals(Account.objects.count(), 0) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) def test_handle_deletions_updates_returned_from_update_initial_data(self): """ @@ -116,23 +116,23 @@ def update_initial_data(self): return [Account.objects.get_or_create(name='hi')[0]] # Verify no account objects exist - self.assertEquals(Account.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) with patch.object(InitialDataUpdater, 'load_app', return_value=AccountInitialData1): InitialDataUpdater().update_all_apps() # Verify two account objects were created and are managed by deletion receipts - self.assertEquals(Account.objects.count(), 2) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 2) + self.assertEqual(Account.objects.count(), 2) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 2) # Run the initial data process again, this time deleting the account named 'hi2' with patch.object(InitialDataUpdater, 'load_app', return_value=AccountInitialData2): InitialDataUpdater().update_all_apps() # Verify only the 'hi' account exists - self.assertEquals(Account.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.get().model_obj.name, 'hi') + self.assertEqual(Account.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.get().model_obj.name, 'hi') def test_handle_deletions_registered_from_update_initial_data(self): """ @@ -156,14 +156,14 @@ def update_initial_data(self): pass # Verify no account objects exist - self.assertEquals(Account.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) with patch.object(InitialDataUpdater, 'load_app', return_value=AccountInitialData1): InitialDataUpdater().update_all_apps() # Verify an account object was created and is managed by a deletion receipt - self.assertEquals(Account.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 1) + self.assertEqual(Account.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 1) # Run the initial data process again, this time not registering the account for # deletion. It should be deleted. @@ -171,8 +171,8 @@ def update_initial_data(self): InitialDataUpdater().update_all_apps() # Verify there are no accounts or receipts - self.assertEquals(Account.objects.count(), 0) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 0) def test_handle_deletions_updates_registered_from_update_initial_data(self): """ @@ -196,23 +196,23 @@ def update_initial_data(self): self.register_for_deletion(Account.objects.get_or_create(name='hi')[0]) # Verify no account objects exist - self.assertEquals(Account.objects.count(), 0) + self.assertEqual(Account.objects.count(), 0) with patch.object(InitialDataUpdater, 'load_app', return_value=AccountInitialData1): InitialDataUpdater().update_all_apps() # Verify two account objects were created and are managed by deletion receipts - self.assertEquals(Account.objects.count(), 2) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 2) + self.assertEqual(Account.objects.count(), 2) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 2) # Run the initial data process again, this time deleting the account named 'hi2' with patch.object(InitialDataUpdater, 'load_app', return_value=AccountInitialData2): InitialDataUpdater().update_all_apps() # Verify only the 'hi' account exists - self.assertEquals(Account.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.count(), 1) - self.assertEquals(RegisteredForDeletionReceipt.objects.get().model_obj.name, 'hi') + self.assertEqual(Account.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.count(), 1) + self.assertEqual(RegisteredForDeletionReceipt.objects.get().model_obj.name, 'hi') @patch('dynamic_initial_data.base.InitialDataUpdater.log') def test_missing_initial_data_file(self, mock_log): diff --git a/dynamic_initial_data/tests/management_command_tests.py b/dynamic_initial_data/tests/management_command_tests.py index 33e4314..64e90a1 100644 --- a/dynamic_initial_data/tests/management_command_tests.py +++ b/dynamic_initial_data/tests/management_command_tests.py @@ -1,6 +1,6 @@ from django.core.management import call_command from django.test import TestCase -from mock import patch +from unittest.mock import patch class UpdateInitialDataTest(TestCase): diff --git a/dynamic_initial_data/tests/migrations/0001_initial.py b/dynamic_initial_data/tests/migrations/0001_initial.py index 02ffff3..fcb722b 100644 --- a/dynamic_initial_data/tests/migrations/0001_initial.py +++ b/dynamic_initial_data/tests/migrations/0001_initial.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals from django.db import models, migrations import django.db.models.deletion diff --git a/dynamic_initial_data/urls.py b/dynamic_initial_data/urls.py new file mode 100644 index 0000000..1a43da5 --- /dev/null +++ b/dynamic_initial_data/urls.py @@ -0,0 +1 @@ +urlpatterns = [] # pragma: no cover diff --git a/dynamic_initial_data/version.py b/dynamic_initial_data/version.py index a33997d..04188a1 100644 --- a/dynamic_initial_data/version.py +++ b/dynamic_initial_data/version.py @@ -1 +1 @@ -__version__ = '2.1.0' +__version__ = '2.2.0' diff --git a/manage.py b/manage.py index e374933..b31c2cb 100644 --- a/manage.py +++ b/manage.py @@ -1,12 +1,27 @@ #!/usr/bin/env python import sys - from settings import configure_settings +import warnings +from django.utils.deprecation import RemovedInNextVersionWarning +warnings.filterwarnings('always', category=RemovedInNextVersionWarning) +warnings.filterwarnings('always', category=DeprecationWarning) +warnings.filterwarnings('always', category=PendingDeprecationWarning) -if __name__ == '__main__': + +def main(): + """Run administrative tasks.""" configure_settings() + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Could not import Django. Are you sure it is installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) - from django.core.management import execute_from_command_line - execute_from_command_line(sys.argv) +if __name__ == '__main__': + main() diff --git a/requirements/requirements-testing.txt b/requirements/requirements-testing.txt index a3cb437..fdc2b98 100644 --- a/requirements/requirements-testing.txt +++ b/requirements/requirements-testing.txt @@ -2,5 +2,5 @@ coverage django-dynamic-fixture django-nose freezegun -mock psycopg2 +flake8 diff --git a/requirements/requirements.txt b/requirements/requirements.txt new file mode 100644 index 0000000..e1a62d4 --- /dev/null +++ b/requirements/requirements.txt @@ -0,0 +1,3 @@ +# Minimum requirements +Django>=3.2 +django-manager-utils>=3.1.0 diff --git a/settings.py b/settings.py index 379bfa0..adb9fa5 100644 --- a/settings.py +++ b/settings.py @@ -1,4 +1,5 @@ import os +import json from django.conf import settings @@ -12,7 +13,7 @@ def configure_settings(): test_db = os.environ.get('DB', None) if test_db is None: db_config = { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'ambition_dev', 'USER': 'ambition_dev', 'PASSWORD': 'ambition_dev', @@ -20,30 +21,64 @@ def configure_settings(): } elif test_db == 'postgres': db_config = { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'ENGINE': 'django.db.backends.postgresql', 'USER': 'postgres', 'NAME': 'dynamic_initial_data', } else: raise RuntimeError('Unsupported test DB {0}'.format(test_db)) + # Check env for db override (used for github actions) + if os.environ.get('DB_SETTINGS'): + db_config = json.loads(os.environ.get('DB_SETTINGS')) + installed_apps = [ + 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', - 'django.contrib.admin', + 'django.contrib.messages', 'dynamic_initial_data', 'dynamic_initial_data.tests', ] + + middleware = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + ] + + templates = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, + ] + settings.configure( TEST_RUNNER='django_nose.NoseTestSuiteRunner', NOSE_ARGS=['--nocapture', '--nologcapture', '--verbosity=1'], DATABASES={ 'default': db_config, }, - MIDDLEWARE_CLASSES={}, INSTALLED_APPS=installed_apps, + MIDDLEWARE=middleware, + TEMPLATES=templates, ROOT_URLCONF='dynamic_initial_data.urls', DEBUG=False, + SECRET_KEY='dj-dy-i-d', DDF_FILL_NULLABLE_FIELDS=False, ) diff --git a/setup.py b/setup.py index ecfef43..68ab34c 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,14 @@ def get_version(): raise RuntimeError('Unable to find version string in {0}.'.format(VERSION_FILE)) +def get_lines(file_path): + return open(file_path, 'r').read().split('\n') + + +install_requires = get_lines('requirements/requirements.txt') +tests_require = get_lines('requirements/requirements-testing.txt') + + setup( name='django-dynamic-initial-data', version=get_version(), @@ -30,28 +38,21 @@ def get_version(): packages=find_packages(), classifiers=[ 'Programming Language :: Python', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Framework :: Django', - 'Framework :: Django :: 2.0', - 'Framework :: Django :: 2.1', - 'Framework :: Django :: 2.2', + 'Framework :: Django :: 3.2', + 'Framework :: Django :: 4.0', + 'Framework :: Django :: 4.1', + 'Framework :: Django :: 4.2', ], license='MIT', - install_requires=[ - 'Django>=2.0', - 'django-manager-utils>=1.4.0', - ], - tests_require=[ - 'psycopg2', - 'django-dynamic-fixture', - 'django-nose>=1.4', - 'freezegun', - 'mock', - ], + install_requires=install_requires, + tests_require=tests_require, test_suite='run_tests.run_tests', include_package_data=True, ) diff --git a/tox.ini b/tox.ini deleted file mode 100644 index ff214d0..0000000 --- a/tox.ini +++ /dev/null @@ -1,31 +0,0 @@ -[tox] -envlist = - flake8 - py{36}-django20 - py{36,37}-django21 - py{36,37}-django22 - py{36,37}-djangomaster - -[testenv] -setenv = - DB = postgres -deps = - django20: Django>=2.0,<2.1 - django21: Django>=2.1,<2.2 - django22: Django>=2.2,<2.3 - djangomaster: https://github.com/django/django/archive/master.tar.gz - -rrequirements/requirements-testing.txt -commands = - coverage run setup.py test - coverage report --fail-under=100 - -[testenv:flake8] -deps = flake8 -commands = flake8 dynamic_initial_data - -[travis:env] -DJANGO = - 2.0: django20 - 2.1: django21 - 2.2: django22 - master: djangomaster