Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update testing versions #94

Merged
merged 18 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 15 additions & 56 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,68 +11,27 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10"]
postgres-version: ["9.4", "9.5", "9.6", "10", "11", "12", "13"]
django-version: ["1.8", "1.9", "1.10", "1.11", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "4.0"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
postgres-version: ["9.6", "10", "11", "12", "13", "14", "15"]
django-version: ["3.1", "3.2", "4.0", "4.1", "4.2"]
exclude:
# Django 4.0+ doesn't support python 3.6, 3.7
- python-version: "3.7"
django-version: "4.0"

# Django 3.0+ doesn't support PostgreSQL 9.4
- django-version: "3.0"
postgres-version: "9.4"
- django-version: "3.1"
postgres-version: "9.4"
- django-version: "3.2"
postgres-version: "9.4"
- django-version: "4.0"
postgres-version: "9.4"

# Django 3.2+ doesn't support PostgreSQL 9.5
- django-version: "3.2"
postgres-version: "9.5"
- django-version: "4.0"
postgres-version: "9.5"

# Django 4.0+ doesn't support PostgreSQL 9.6
- django-version: "4.0"
postgres-version: "9.6"
- django-version: "4.1"
postgres-version: "9.6"
- django-version: "4.2"
postgres-version: "9.6"

# python 3.6+ has deprecated issue with django before 1.11
# https://stackoverflow.com/questions/41343263/provide-classcell-example-for-python-3-6-metaclass\
- python-version: "3.7"
django-version: "1.8"
- python-version: "3.7"
django-version: "1.9"
- python-version: "3.7"
django-version: "1.10"
- python-version: "3.8"
django-version: "1.8"
- python-version: "3.8"
django-version: "1.9"
- python-version: "3.8"
django-version: "1.10"
- python-version: "3.9"
django-version: "1.8"
- python-version: "3.9"
django-version: "1.9"
- python-version: "3.9"
django-version: "1.10"
- python-version: "3.10"
django-version: "1.8"
- python-version: "3.10"
django-version: "1.9"
- python-version: "3.10"
django-version: "1.10"

# Django before 2.1 is not compatible with python 3.10
# as it uses collections.Iterator
- python-version: "3.10"
django-version: "2.0"
- python-version: "3.10"
django-version: "1.11"
# Django 4.1+ doesn't support PostgreSQL 10
- django-version: "4.1"
postgres-version: "10"
- django-version: "4.2"
postgres-version: "10"

# Django 4.2+ doesn't support PostgreSQL 11
- django-version: "4.2"
postgres-version: "11"

services:
postgres:
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
build:
context: .
args:
- PYTHON_IMAGE_TAG=latest
- PYTHON_IMAGE_TAG=3.11
volumes:
- ./.docker/wait-for-it.sh:/bin/wait-for-it.sh
command: ["/bin/bash", "/bin/wait-for-it.sh", "postgres_db:5432", "-s", "-t", "0", "--", "python3", "runtests.py"]
Expand Down
5 changes: 1 addition & 4 deletions requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
django>=1.7

# FIXME On later versions I get strange error 'database connection isn't set to UTC'
psycopg2<=2.8.6

psycopg2
pytz; python_version < '3.3'
typing; python_version < '3.5'

Expand Down
26 changes: 24 additions & 2 deletions src/django_pg_bulk_update/compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

import django
from django.db import connection, connections, models, migrations
from django.db.models import Model, Field, BigIntegerField, IntegerField

from django.db.models import Model, Field, BigIntegerField, IntegerField, Q, Value, BooleanField

try:
# For django 3.2+
Expand Down Expand Up @@ -40,6 +39,14 @@
tz_utc = pytz.utc


try:
from django.core.exceptions import FullResultSet
except ImportError:
# For django before 4.2
class FullResultSet(Exception):
pass


def zip_longest(*args, **kwargs):
"""
https://docs.python.org/3.5/library/itertools.html#itertools.zip_longest
Expand Down Expand Up @@ -215,6 +222,21 @@ def get_model_fields(model, concrete=False): # type: (Type[Model], Optional[boo
return res


def get_empty_q_object() -> Q:
"""
Generates Q-Object, which leads to empty QuerySet.
See https://stackoverflow.com/questions/35893867/always-false-q-object
"""
import django
if django.VERSION >= (3,):
return Q(Value(False, output_field=BooleanField()))

# Django before 3.0 doesn't work with not binary conditions and expects field name to be always present.
# It raises TypeError: cannot unpack non-iterable Value object.
# This condition raises EmptyResultSet while forming query and doesn't even execute it
return Q(pk__in=[])


# Postgres 9.4 has JSONB support, but doesn't support concat operator (||)
# So I've taken function to solve the problem from
# https://stackoverflow.com/questions/30101603/merging-concatenating-jsonb-columns-in-query
Expand Down
10 changes: 7 additions & 3 deletions src/django_pg_bulk_update/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
from django.db.models.sql import UpdateQuery
from django.db.models.sql.where import WhereNode

from tests.compatibility import get_empty_q_object
from .compatibility import get_postgres_version, get_model_fields, returning_available, string_types, Iterable
from .compatibility import get_postgres_version, get_model_fields, returning_available, string_types,\
get_empty_q_object, Iterable, FullResultSet
from .set_functions import AbstractSetFunction, NowSetFunction
from .types import TOperators, TFieldNames, TUpdateValues, TSetFunctions, TOperatorsValid, TUpdateValuesValid, \
TSetFunctionsValid, TDatabase, FieldDescriptor, AbstractFieldFormatter
Expand Down Expand Up @@ -271,7 +271,11 @@ def _validate_where(model, where, using):
query = UpdateQuery(model)
conn = connections[using] if using else connection
compiler = query.get_compiler(connection=conn)
sql, params = where.as_sql(compiler, conn)

try:
sql, params = where.as_sql(compiler, conn)
except FullResultSet:
return '', tuple()

# I change table name to "t" inside queries
if sql:
Expand Down
34 changes: 0 additions & 34 deletions tests/compatibility.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from datetime import date

from django.db.models import Value, Q, BooleanField
from django.template.backends import django
from django.utils.timezone import now
from django.utils.tree import Node

from django_pg_bulk_update.compatibility import get_postgres_version

Expand All @@ -19,34 +16,3 @@ def get_auto_now_date(key_is_unique=True): # type: (bool) -> date
:return: Date object
"""
return date.today() if not key_is_unique or get_postgres_version() < (9, 5) else now().date()


class EmptyQ(Q):
"""
Empty condition should return empty result
See https://stackoverflow.com/questions/35893867/always-false-q-object
"""
def __init__(self):
Node.__init__(self, children=[
("pk", Value(False, output_field=BooleanField()))
], connector=None, negated=False)

def __str__(self):
# Django before 3.0 raises 'TypeError: cannot unpack non-iterable Value object'
# when trying to insert Q(Value(False, output_field=BooleanField())) to
return 'FALSE'


def get_empty_q_object() -> Q:
"""
Generates Q-Object, which leads to empty QuerySet.
See https://stackoverflow.com/questions/35893867/always-false-q-object
"""
import django
if django.VERSION >= (3,):
return Q(Value(False, output_field=BooleanField()))

# Django before 3.0 doesn't work with not binary conditions and expects field name to be always present.
# It raises TypeError: cannot unpack non-iterable Value object.
# This condition raises EmptyResultSet while forming query and doesn't even execute it
return Q(pk__in=[])
Loading