diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9a7bd99..01287e1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,28 +10,18 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12-dev'] - django-version: ['3.2', '4.2', 'main'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15-dev'] + django-version: ['5.2', '6.0', 'main'] exclude: + - python-version: '3.10' + django-version: '6.0' - python-version: '3.11' - django-version: '3.2' - - python-version: '3.12-dev' - django-version: '3.2' - - - python-version: '3.11' - django-version: '4.0' - - python-version: '3.12-dev' - django-version: '4.0' - - - python-version: '3.12-dev' - django-version: '4.1' + django-version: '6.0' - - python-version: '3.8' - django-version: 'main' - - python-version: '3.9' - django-version: 'main' - python-version: '3.10' django-version: 'main' + - python-version: '3.11' + django-version: 'main' steps: - uses: actions/checkout@v3 diff --git a/Makefile b/Makefile index 5a87979..c04d6fe 100644 --- a/Makefile +++ b/Makefile @@ -7,23 +7,22 @@ ruff: example: DJANGO_SETTINGS_MODULE=example.settings PYTHONPATH=. \ - django-admin.py runserver + django-admin runserver check: DJANGO_SETTINGS_MODULE=example.settings PYTHONPATH=. \ python -Wd example/manage.py check generate-mmdb-fixtures: - docker --context=default buildx build -f tests/Dockerfile --tag test-mmdb-maker tests - docker run --rm --volume $$(pwd)/tests:/data test-mmdb-maker + [ -e tests/test_city.mmdb ] || python3 generate_mmdb.py test: generate-mmdb-fixtures DJANGO_SETTINGS_MODULE=tests.settings PYTHONPATH=. \ - django-admin.py test ${TARGET} + django-admin test ${TARGET} migrations: DJANGO_SETTINGS_MODULE=tests.settings PYTHONPATH=. \ - django-admin.py makemigrations user_sessions + django-admin makemigrations user_sessions coverage: coverage erase @@ -34,8 +33,8 @@ coverage: tx-pull: tx pull -a - cd user_sessions; django-admin.py compilemessages + cd user_sessions; django-admin compilemessages tx-push: - cd user_sessions; django-admin.py makemessages -l en + cd user_sessions; django-admin makemessages -l en tx push -s diff --git a/pyproject.toml b/pyproject.toml index 4aa149f..120e530 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ requires = ["setuptools>=45", "wheel", "setuptools_scm>=6.2"] [project] name = "django-user-sessions" authors = [ - {name = "Bouke Haarsma", email = "bouke@haarsma.eu"}, + {name = "Bouke Haarsma", email = "bouke@haarsma.eu"}, ] description = "Django sessions with a foreign key to the user" readme = "README.rst" @@ -30,7 +30,7 @@ classifiers = [ "Topic :: Security", ] dependencies = [ - "Django>=3.2", + "Django>=3.2", ] dynamic = ["version"] @@ -58,6 +58,7 @@ dev = [ # Build "bumpversion", "twine", + "mmdb-writer", ] [tool.ruff] diff --git a/tests/Dockerfile b/tests/Dockerfile deleted file mode 100644 index d363dc6..0000000 --- a/tests/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM perl:latest - -RUN cpanm MaxMind::DB::Writer - -COPY generate_mmdb.pl / - -VOLUME ["/data"] - -CMD ["perl", "/generate_mmdb.pl"] diff --git a/tests/generate_mmdb.pl b/tests/generate_mmdb.pl deleted file mode 100755 index 2b2f5b6..0000000 --- a/tests/generate_mmdb.pl +++ /dev/null @@ -1,89 +0,0 @@ -#!perl - -use MaxMind::DB::Writer::Tree; - -my %city_types = ( - city => 'map', - code => 'utf8_string', - continent => 'map', - country => 'map', - en => 'utf8_string', - is_in_european_union => 'boolean', - iso_code => 'utf8_string', - latitude => 'double', - location => 'map', - longitude => 'double', - metro_code => 'utf8_string', - names => 'map', - postal => 'map', - subdivisions => ['array', 'map'], - region => 'utf8_string', - time_zone => 'utf8_string', -); - -my $city_tree = MaxMind::DB::Writer::Tree->new( - ip_version => 6, - record_size => 24, - database_type => 'GeoLite2-City', - languages => ['en'], - description => { en => 'Test database of IP city data' }, - map_key_type_callback => sub { $city_types{ $_[0] } }, -); - -$city_tree->insert_network( - '44.55.66.77/32', - { - city => { names => {en => 'San Diego'} }, - continent => { code => 'NA', names => {en => 'North America'} }, - country => { iso_code => 'US', names => {en => 'United States'} }, - is_in_european_union => false, - location => { - latitude => 37.751, - longitude => -97.822, - metro_code => 'custom metro code', - time_zone => 'America/Los Angeles', - }, - postal => { code => 'custom postal code' }, - subdivisions => [ - { iso_code => 'ABC', names => {en => 'Absolute Basic Class'} }, - ], - }, -); - -my $outfile = ($ENV{'DATA_DIR'} || '/data/') . ($ENV{'CITY_FILENAME'} || 'test_city.mmdb'); -open my $fh, '>:raw', $outfile; -$city_tree->write_tree($fh); - - - -my %country_types = ( - country => 'map', - iso_code => 'utf8_string', - names => 'map', - en => 'utf8_string', -); - -my $country_tree = MaxMind::DB::Writer::Tree->new( - ip_version => 6, - record_size => 24, - database_type => 'GeoLite2-Country', - languages => ['en'], - description => { en => 'Test database of IP country data' }, - map_key_type_callback => sub { $country_types{ $_[0] } }, -); - -$country_tree->insert_network( - '8.8.8.8/32', - { - country => { - iso_code => 'US', - names => { - en => 'United States', - }, - }, - }, -); - -my $outfile = ($ENV{'DATA_DIR'} || '/data/') . ($ENV{'COUNTRY_FILENAME'} || 'test_country.mmdb'); -open my $fh, '>:raw', $outfile; -$country_tree->write_tree($fh); diff --git a/tests/generate_mmdb.py b/tests/generate_mmdb.py new file mode 100644 index 0000000..7b5a797 --- /dev/null +++ b/tests/generate_mmdb.py @@ -0,0 +1,49 @@ +from netaddr import IPSet + +from mmdb_writer import MMDBWriter + + +city_writer = MMDBWriter() + +city_writer.insert_network( + IPSet(["44.55.66.77/32"]), + { + "city": { + "names": { + "en": "San Diego", + }, + }, + "continent": { + "code": "NA", + "names": { + "en": "North America", + }, + }, + "country": { + "iso_code": "US", + "names": { + "en": "United States", + }, + }, + "is_in_european_union": False, + "location": { + "latitude": 37.751, + "longitude": -97.822, + "metro_code": "custom metro code", + "time_zone": "America/Los Angeles", + }, + "postal": { + "code": "custom postal code", + }, + "subdivisions": [ + { + "iso_code": "ABC", + "names": { + "en": 'Absolute Basic Class', + }, + }, + ], + }, +) + +city_writer.to_db_file("tests/test_city.mmdb") diff --git a/tests/test_admin.py b/tests/test_admin.py index e9238f9..f1dd685 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -25,37 +25,32 @@ def setUp(self): self.admin_url = reverse('admin:user_sessions_session_changelist') def test_list(self): - with self.assertWarnsRegex(UserWarning, r"The address 1\.1\.1\.1 is not in the database"): - response = self.client.get(self.admin_url) + response = self.client.get(self.admin_url) self.assertContains(response, 'Select session to change') self.assertContains(response, '127.0.0.1') self.assertContains(response, '20.13.1.1') self.assertContains(response, '1.1.1.1') def test_search(self): - with self.assertWarnsRegex(UserWarning, r"The address 127\.0\.0\.1 is not in the database"): - response = self.client.get(self.admin_url, {'q': 'bouke'}) + response = self.client.get(self.admin_url, {'q': 'bouke'}) self.assertContains(response, '127.0.0.1') self.assertNotContains(response, '20.13.1.1') self.assertNotContains(response, '1.1.1.1') def test_mine(self): my_sessions = f"{self.admin_url}?{urlencode({'owner': 'my'})}" - with self.assertWarnsRegex(UserWarning, r"The address 127\.0\.0\.1 is not in the database"): - response = self.client.get(my_sessions) + response = self.client.get(my_sessions) self.assertContains(response, '127.0.0.1') self.assertNotContains(response, '1.1.1.1') def test_expired(self): expired = f"{self.admin_url}?{urlencode({'active': '0'})}" - with self.assertWarnsRegex(UserWarning, r"The address 20\.13\.1\.1 is not in the database"): - response = self.client.get(expired) + response = self.client.get(expired) self.assertContains(response, '20.13.1.1') self.assertNotContains(response, '1.1.1.1') def test_unexpired(self): unexpired = f"{self.admin_url}?{urlencode({'active': '1'})}" - with self.assertWarnsRegex(UserWarning, r"The address 1\.1\.1\.1 is not in the database"): - response = self.client.get(unexpired) + response = self.client.get(unexpired) self.assertContains(response, '1.1.1.1') self.assertNotContains(response, '20.13.1.1') diff --git a/tests/test_template_filters.py b/tests/test_template_filters.py index 4589596..a56f2be 100644 --- a/tests/test_template_filters.py +++ b/tests/test_template_filters.py @@ -25,12 +25,7 @@ class LocationTemplateFilterTest(TestCase): @override_settings(GEOIP_PATH=None) def test_no_location(self): - with self.assertWarnsRegex( - UserWarning, - r"The address 127\.0\.0\.1 is not in the database", - ): - loc = location('127.0.0.1') - self.assertEqual(loc, None) + self.assertIsNone(location('127.0.0.1')) @skipUnless(geoip, geoip_msg) def test_city(self): diff --git a/tests/test_views.py b/tests/test_views.py index 53435f5..fce2921 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -20,8 +20,7 @@ def test_list(self): self.user.session_set.create(session_key='ABC123', ip='127.0.0.1', expire_date=now() + timedelta(days=1), user_agent='Firefox') - with self.assertWarnsRegex(UserWarning, r"The address 127\.0\.0\.1 is not in the database"): - response = self.client.get(reverse('user_sessions:session_list')) + response = self.client.get(reverse('user_sessions:session_list')) self.assertContains(response, 'Active Sessions') self.assertContains(response, 'Firefox') self.assertNotContains(response, 'ABC123') @@ -36,8 +35,7 @@ def test_delete_all_other(self): self.user.session_set.create(ip='127.0.0.1', expire_date=now() + timedelta(days=1)) self.assertEqual(self.user.session_set.count(), 2) response = self.client.post(reverse('user_sessions:session_delete_other')) - with self.assertWarnsRegex(UserWarning, r"The address 127\.0\.0\.1 is not in the database"): - self.assertRedirects(response, reverse('user_sessions:session_list')) + self.assertRedirects(response, reverse('user_sessions:session_list')) self.assertEqual(self.user.session_set.count(), 1) def test_delete_some_other(self): @@ -46,6 +44,5 @@ def test_delete_some_other(self): self.assertEqual(self.user.session_set.count(), 2) response = self.client.post(reverse('user_sessions:session_delete', args=[other.session_key])) - with self.assertWarnsRegex(UserWarning, r"The address 127\.0\.0\.1 is not in the database"): - self.assertRedirects(response, reverse('user_sessions:session_list')) + self.assertRedirects(response, reverse('user_sessions:session_list')) self.assertEqual(self.user.session_set.count(), 1) diff --git a/tox.ini b/tox.ini index 406b88a..e746c39 100644 --- a/tox.ini +++ b/tox.ini @@ -2,37 +2,36 @@ ; Minimum version of Tox minversion = 1.8 envlist = - ; https://docs.djangoproject.com/en/4.2/faq/install/#what-python-version-can-i-use-with-django - py{37}-dj32 - py{38,39,310}-dj32 - py{311,312}-dj{42,main} + ; https://docs.djangoproject.com/en/6.0/faq/install/#what-python-version-can-i-use-with-django + py3{10,11,12,13,14}-dj52 + py3{12,13,14}-dj{60,main} [gh-actions] python = - 3.8: py38 - 3.9: py39 3.10: py310 3.11: py311 3.12: py312 + 3.13: py313 + 3.14: py314 [gh-actions:env] DJANGO = - 3.2: dj32 - 4.2: dj42 + 5.2: dj52 + 6.0: dj60 main: djmain [testenv] commands = - make generate-mmdb-fixtures + python3 tests/generate_mmdb.py coverage run {envbindir}/django-admin test -v 2 --pythonpath=./ --settings=tests.settings coverage report coverage xml deps = coverage - dj32: Django>=3.2,<4.0 - dj42: Django>=4.2,<4.3 + dj52: Django>=5.2,<6.0 + dj60: Django>=6.0,<6.1 djmain: https://github.com/django/django/archive/main.tar.gz geoip2 + mmdb-writer ignore_outcome = djmain: True -allowlist_externals = make