diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 22e548d..2485b58 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-20.04 services: postgres: - image: postgis/postgis:10-2.5 + image: postgis/postgis:12-2.5 env: POSTGRES_USER: test POSTGRES_DB: test @@ -27,8 +27,8 @@ jobs: - 5432:5432 strategy: matrix: - python-version: ['3.7', '3.8'] - django-series: ['2.2', '3.0'] + python-version: ['3.9', '3.10', '3.11', '3.12'] + django-series: ['3.2', '4.0', '4.2'] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index e50e538..3b13d6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## Unreleased * Add a --sync flag to the loaddivisions management command, to delete divisions that are in the DB but not the CSV, even if the DB contains the CSV. This flag is relevant if you synchronize with a single CSV. +* Add support for Python 3.9, 3.10, 3.11, 3.12 and Django 4.0, 4.2. +* Drop support for Python 3.7, 3.8 and Django 2.2, 3.0. ## 3.3.0 (2023-05-08) diff --git a/opencivicdata/core/migrations/0009_auto_20241111_1450.py b/opencivicdata/core/migrations/0009_auto_20241111_1450.py new file mode 100644 index 0000000..94a590c --- /dev/null +++ b/opencivicdata/core/migrations/0009_auto_20241111_1450.py @@ -0,0 +1,38 @@ +# Generated by Django 3.2 on 2024-11-11 14:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0008_auto_20221215_1132'), + ] + + operations = [ + migrations.AlterField( + model_name='jurisdiction', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='membership', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='organization', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='person', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='post', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + ] diff --git a/opencivicdata/core/models/base.py b/opencivicdata/core/models/base.py index 57a24a2..98799ee 100644 --- a/opencivicdata/core/models/base.py +++ b/opencivicdata/core/models/base.py @@ -2,7 +2,7 @@ import re import uuid from django.db import models -from django.contrib.postgres.fields import ArrayField, JSONField +from django.contrib.postgres.fields import ArrayField from django.core.validators import RegexValidator from ... import common @@ -53,7 +53,7 @@ class OCDBase(models.Model): auto_now=True, help_text="The last time this object was seen in a scrape." ) - extras = JSONField( + extras = models.JSONField( default=dict, blank=True, help_text="A key-value store for storing arbitrary information not covered elsewhere.", diff --git a/opencivicdata/elections/migrations/0011_auto_20241111_1450.py b/opencivicdata/elections/migrations/0011_auto_20241111_1450.py new file mode 100644 index 0000000..77ee7ee --- /dev/null +++ b/opencivicdata/elections/migrations/0011_auto_20241111_1450.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2 on 2024-11-11 14:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('elections', '0010_auto_20221215_1132'), + ] + + operations = [ + migrations.AlterField( + model_name='ballotmeasurecontest', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='candidacy', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='candidatecontest', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='election', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='partycontest', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='retentioncontest', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + ] diff --git a/opencivicdata/legislative/migrations/0016_auto_20241111_1450.py b/opencivicdata/legislative/migrations/0016_auto_20241111_1450.py new file mode 100644 index 0000000..a348d6e --- /dev/null +++ b/opencivicdata/legislative/migrations/0016_auto_20241111_1450.py @@ -0,0 +1,48 @@ +# Generated by Django 3.2 on 2024-11-11 14:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('legislative', '0015_auto_20221215_1132'), + ] + + operations = [ + migrations.AlterField( + model_name='bill', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='billaction', + name='extras', + field=models.JSONField(blank=True, default=dict), + ), + migrations.AlterField( + model_name='billdocument', + name='extras', + field=models.JSONField(blank=True, default=dict), + ), + migrations.AlterField( + model_name='billversion', + name='extras', + field=models.JSONField(blank=True, default=dict), + ), + migrations.AlterField( + model_name='event', + name='extras', + field=models.JSONField(blank=True, default=dict, help_text='A key-value store for storing arbitrary information not covered elsewhere.'), + ), + migrations.AlterField( + model_name='eventagendaitem', + name='extras', + field=models.JSONField(blank=True, default=dict), + ), + migrations.AlterField( + model_name='voteevent', + name='extras', + field=models.JSONField(blank=True, default=dict), + ), + ] diff --git a/opencivicdata/legislative/models/bill.py b/opencivicdata/legislative/models/bill.py index 52a83be..f0cee7d 100644 --- a/opencivicdata/legislative/models/bill.py +++ b/opencivicdata/legislative/models/bill.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals from django.db import models -from django.contrib.postgres.fields import ArrayField, JSONField +from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.search import SearchVectorField from django.contrib.postgres.indexes import GinIndex @@ -101,7 +101,7 @@ class BillAction(RelatedBase): base_field=models.TextField(), blank=True, default=list ) # enum order = models.PositiveIntegerField() - extras = JSONField(default=dict, blank=True) + extras = models.JSONField(default=dict, blank=True) class Meta: db_table = "opencivicdata_billaction" @@ -170,7 +170,7 @@ class BillDocument(RelatedBase): bill = models.ForeignKey(Bill, related_name="documents", on_delete=models.CASCADE) note = models.CharField(max_length=300) date = models.CharField(max_length=10) # YYYY[-MM[-DD]] - extras = JSONField(default=dict, blank=True) + extras = models.JSONField(default=dict, blank=True) def __str__(self): return "{0} document of {1}".format(self.date, self.bill) @@ -183,7 +183,7 @@ class BillVersion(RelatedBase): bill = models.ForeignKey(Bill, related_name="versions", on_delete=models.CASCADE) note = models.CharField(max_length=300) date = models.CharField(max_length=10) # YYYY[-MM[-DD]] - extras = JSONField(default=dict, blank=True) + extras = models.JSONField(default=dict, blank=True) def __str__(self): return "{0} version of {1}".format(self.date, self.bill) diff --git a/opencivicdata/legislative/models/event.py b/opencivicdata/legislative/models/event.py index a3d98a4..d78ac44 100644 --- a/opencivicdata/legislative/models/event.py +++ b/opencivicdata/legislative/models/event.py @@ -1,5 +1,5 @@ from django.contrib.gis.db import models -from django.contrib.postgres.fields import ArrayField, JSONField +from django.contrib.postgres.fields import ArrayField from opencivicdata.core.models.base import ( OCDBase, LinkBase, @@ -161,7 +161,7 @@ class EventAgendaItem(RelatedBase): subjects = ArrayField(base_field=models.TextField(), blank=True, default=list) notes = ArrayField(base_field=models.TextField(), blank=True, default=list) event = models.ForeignKey(Event, related_name="agenda", on_delete=models.CASCADE) - extras = JSONField(default=dict, blank=True) + extras = models.JSONField(default=dict, blank=True) def __str__(self): return "Agenda item {0} for {1}".format(self.order, self.event).replace( diff --git a/opencivicdata/legislative/models/vote.py b/opencivicdata/legislative/models/vote.py index 76cf8dd..10b0a5f 100644 --- a/opencivicdata/legislative/models/vote.py +++ b/opencivicdata/legislative/models/vote.py @@ -1,5 +1,5 @@ from django.db import models -from django.contrib.postgres.fields import ArrayField, JSONField +from django.contrib.postgres.fields import ArrayField from opencivicdata.core.models.base import OCDBase, LinkBase, OCDIDField, RelatedBase from opencivicdata.core.models import Organization, Person @@ -48,7 +48,7 @@ class VoteEvent(OCDBase): on_delete=models.SET_NULL, ) - extras = JSONField(default=dict, blank=True) + extras = models.JSONField(default=dict, blank=True) def __str__(self): if self.identifier: diff --git a/opencivicdata/tests/test_settings.py b/opencivicdata/tests/test_settings.py index 5ade2f3..7b3768e 100644 --- a/opencivicdata/tests/test_settings.py +++ b/opencivicdata/tests/test_settings.py @@ -1,3 +1,5 @@ +import os + # not tests, just Django settings SECRET_KEY = "test" INSTALLED_APPS = ( @@ -8,10 +10,12 @@ DATABASES = { "default": { "ENGINE": "django.contrib.gis.db.backends.postgis", - "NAME": "test", - "USER": "test", - "PASSWORD": "test", + "NAME": os.getenv("POSTGRES_DB", "test"), + "USER": os.getenv("POSTGRES_USER", "test"), + "PASSWORD": os.getenv("POSTGRES_PASSWORD", "test"), "HOST": "localhost", } } MIDDLEWARE_CLASSES = () +GDAL_LIBRARY_PATH = os.getenv("GDAL_LIBRARY_PATH") +GEOS_LIBRARY_PATH = os.getenv('GEOS_LIBRARY_PATH') diff --git a/setup.cfg b/setup.cfg index 3d351c8..a394494 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,4 +2,4 @@ universal = 1 [flake8] max-line-length=100 -exclude = opencivicdata/*/migrations +exclude = */migrations diff --git a/setup.py b/setup.py index 2927b50..903d3e6 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python from setuptools import setup, find_packages -install_requires = ["Django>=2.2", "psycopg2-binary"] +install_requires = ["Django>=3.2", "psycopg2-binary"] extras_require = { "dev": ["pytest>=3.6", "pytest-cov", "pytest-django", "coveralls==3.2.0", "flake8"] @@ -27,8 +27,9 @@ "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], )