Skip to content

Commit

Permalink
Fix bug in pdnf_clause if empty data is passed (issue #92) (#93)
Browse files Browse the repository at this point in the history
1. Fix issue #92 in pdnf_clause if empty data is passed
2. Removed outdated python 3.6 version from testing
  • Loading branch information
M1ha-Shvn authored Oct 23, 2023
1 parent 3bc6dff commit 23db82c
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 26 deletions.
20 changes: 1 addition & 19 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,11 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
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"]
exclude:
# Django 3.0+ doesn't support python 3.5
- python-version: "3.5"
django-version: "3.0"
- python-version: "3.5"
django-version: "3.1"
- python-version: "3.5"
django-version: "3.2"
- python-version: "3.5"
django-version: "4.0"

# Django 4.0+ doesn't support python 3.6, 3.7
- python-version: "3.6"
django-version: "4.0"
- python-version: "3.7"
django-version: "4.0"

Expand All @@ -53,12 +41,6 @@ jobs:

# 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.6"
django-version: "1.8"
- python-version: "3.6"
django-version: "1.9"
- python-version: "3.6"
django-version: "1.10"
- python-version: "3.7"
django-version: "1.8"
- python-version: "3.7"
Expand Down
8 changes: 5 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ WORKDIR /app/src
# Install dependencies
# set -eu "breaks" pipeline on first error
COPY ./requirements-test.txt /app/requirements-test.txt
RUN --mount=type=cache,target=/root/.cache/pip \
set -eu && \

RUN set -eu && \
apt-get update && \
apt-get install -y libpq-dev python3-dev && \
apt-get install -y libpq-dev python3-dev

RUN --mount=type=cache,target=/root/.cache/pip \
python3 -m pip install --upgrade pip setuptools wheel && \
python3 -m pip install --upgrade --requirement /app/requirements-test.txt

Expand Down
2 changes: 1 addition & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
django>=1.7

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

pytz; python_version < '3.3'
typing; python_version < '3.5'
Expand Down
2 changes: 2 additions & 0 deletions runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
import sys

import django
import psycopg2
from django.conf import settings
from django.test.utils import get_runner

if __name__ == "__main__":
print('Django: ', django.VERSION)
print('Python: ', sys.version)
print('Psycopg2: ', psycopg2.__version__)

# Add the src directory to sys.path
curdir = os.path.dirname(os.path.realpath(__file__))
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

setup(
name='django-pg-bulk-update',
version='3.7.0',
version='3.7.1',
packages=['django_pg_bulk_update'],
package_dir={'': 'src'},
url='https://github.com/M1hacka/django-pg-bulk-update',
Expand Down
4 changes: 2 additions & 2 deletions src/django_pg_bulk_update/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
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 .set_functions import AbstractSetFunction, NowSetFunction
from .types import TOperators, TFieldNames, TUpdateValues, TSetFunctions, TOperatorsValid, TUpdateValuesValid, \
Expand Down Expand Up @@ -305,8 +306,7 @@ def pdnf_clause(key_fields, field_values, key_fields_ops=()):
field_values = list(field_values)

if len(field_values) == 0:
# Empty condition should return empty result
return ~Q()
return get_empty_q_object()

or_cond = Q()
for values_item in field_values:
Expand Down
34 changes: 34 additions & 0 deletions tests/compatibility.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
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 @@ -16,3 +19,34 @@ 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=[])
3 changes: 3 additions & 0 deletions tests/test_pdnf_clause.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ def test_lte(self):
def test_between(self):
self._test_filter({2, 3, 4}, ['id'], [[[2, 4]]], operations=['between'])

def test_empty_data(self):
self._test_filter(set(), ['id'], [])


class TestReadmeExample(TestCase):
def test_example(self):
Expand Down

0 comments on commit 23db82c

Please sign in to comment.