Skip to content

Commit 5707234

Browse files
authored
Merge branch 'main' into INTPYTHON-348
2 parents 3cf968e + 087000e commit 5707234

File tree

9 files changed

+151
-112
lines changed

9 files changed

+151
-112
lines changed

.github/workflows/runtests.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python
2+
import os
3+
import pathlib
4+
import sys
5+
6+
test_apps = [
7+
"admin_filters",
8+
"aggregation",
9+
"aggregation_regress",
10+
"annotations",
11+
"auth_tests.test_models.UserManagerTestCase",
12+
"backends",
13+
"basic",
14+
"bulk_create",
15+
"custom_pk",
16+
"dates",
17+
"datetimes",
18+
"db_functions",
19+
"dbshell_",
20+
"defer",
21+
"defer_regress",
22+
"delete",
23+
"delete_regress",
24+
"empty",
25+
"expressions",
26+
"expressions_case",
27+
"force_insert_update",
28+
"from_db_value",
29+
"generic_relations",
30+
"generic_relations_regress",
31+
"introspection",
32+
"known_related_objects",
33+
"lookup",
34+
"m2m_and_m2o",
35+
"m2m_intermediary",
36+
"m2m_multiple",
37+
"m2m_recursive",
38+
"m2m_regress",
39+
"m2m_signals",
40+
"m2m_through",
41+
"m2m_through_regress",
42+
"m2o_recursive",
43+
"many_to_many",
44+
"many_to_one",
45+
"many_to_one_null",
46+
"migrations",
47+
"model_fields",
48+
"model_fields_",
49+
"model_forms",
50+
"model_formsets",
51+
"model_inheritance_regress",
52+
"mutually_referential",
53+
"nested_foreign_keys",
54+
"null_fk",
55+
"null_fk_ordering",
56+
"null_queries",
57+
"one_to_one",
58+
"or_lookups",
59+
"ordering",
60+
"queries",
61+
"queries_",
62+
"schema",
63+
"select_related",
64+
"select_related_onetoone",
65+
"select_related_regress",
66+
"sessions_tests",
67+
"timezones",
68+
"update",
69+
"xor_lookups",
70+
]
71+
runtests = pathlib.Path(__file__).parent.resolve() / "runtests.py"
72+
run_tests_cmd = f"python3 {runtests} %s --settings mongodb_settings -v 2"
73+
74+
shouldFail = False
75+
for app_name in test_apps:
76+
res = os.system(run_tests_cmd % app_name) # noqa: S605
77+
if res != 0:
78+
shouldFail = True
79+
sys.exit(1 if shouldFail else 0)

.github/workflows/test-python.yml

Lines changed: 3 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -44,70 +44,11 @@ jobs:
4444
pip3 install -r requirements/py3.txt
4545
- name: Copy the test settings file
4646
run: cp .github/workflows/mongodb_settings.py django_repo/tests/
47+
- name: Copy the test runner file
48+
run: cp .github/workflows/runtests.py django_repo/tests/runtests_.py
4749
- name: Start MongoDB
4850
uses: supercharge/[email protected]
4951
with:
5052
mongodb-version: 5.0
5153
- name: Run tests
52-
run: >
53-
python3 django_repo/tests/runtests.py --settings mongodb_settings -v 2
54-
admin_filters
55-
aggregation
56-
aggregation_regress
57-
annotations
58-
auth_tests.test_models.UserManagerTestCase
59-
backends
60-
basic
61-
bulk_create
62-
custom_pk
63-
dates
64-
datetimes
65-
db_functions
66-
dbshell_
67-
delete
68-
delete_regress
69-
empty
70-
expressions
71-
expressions_case
72-
defer
73-
defer_regress
74-
force_insert_update
75-
from_db_value
76-
generic_relations
77-
generic_relations_regress
78-
introspection
79-
known_related_objects
80-
lookup
81-
m2m_and_m2o
82-
m2m_intermediary
83-
m2m_multiple
84-
m2m_recursive
85-
m2m_regress
86-
m2m_signals
87-
m2m_through
88-
m2m_through_regress
89-
m2o_recursive
90-
many_to_many
91-
many_to_one
92-
many_to_one_null
93-
migrations
94-
model_fields
95-
model_forms
96-
model_inheritance_regress
97-
mutually_referential
98-
nested_foreign_keys
99-
null_fk
100-
null_fk_ordering
101-
null_queries
102-
one_to_one
103-
ordering
104-
or_lookups
105-
queries
106-
schema
107-
select_related
108-
select_related_onetoone
109-
select_related_regress
110-
sessions_tests
111-
timezones
112-
update
113-
xor_lookups
54+
run: python3 django_repo/tests/runtests_.py

django_mongodb/base.py

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import contextlib
2+
13
from django.db.backends.base.base import BaseDatabaseWrapper
2-
from django.db.backends.signals import connection_created
34
from pymongo.collection import Collection
45
from pymongo.mongo_client import MongoClient
56

@@ -128,11 +129,6 @@ def _isnull_operator(a, b):
128129
introspection_class = DatabaseIntrospection
129130
ops_class = DatabaseOperations
130131

131-
def __init__(self, *args, **kwargs):
132-
super().__init__(*args, **kwargs)
133-
self.connected = False
134-
del self.connection
135-
136132
def get_collection(self, name, **kwargs):
137133
collection = Collection(self.database, name, **kwargs)
138134
if self.queries_logged:
@@ -145,44 +141,45 @@ def get_database(self):
145141
return self.database
146142

147143
def __getattr__(self, attr):
148-
"""
149-
Connect to the database the first time `connection` or `database` are
150-
accessed.
151-
"""
152-
if attr in ["connection", "database"]:
153-
assert not self.connected
154-
self._connect()
144+
"""Connect to the database the first time `database` is accessed."""
145+
if attr == "database":
146+
if self.connection is None:
147+
self.connect()
155148
return getattr(self, attr)
156149
raise AttributeError(attr)
157150

158-
def _connect(self):
159-
settings_dict = self.settings_dict
160-
self.connection = MongoClient(
161-
host=settings_dict["HOST"] or None,
162-
port=int(settings_dict["PORT"] or 27017),
163-
username=settings_dict.get("USER"),
164-
password=settings_dict.get("PASSWORD"),
165-
**settings_dict["OPTIONS"],
166-
)
167-
db_name = settings_dict["NAME"]
151+
def init_connection_state(self):
152+
db_name = self.settings_dict["NAME"]
168153
if db_name:
169154
self.database = self.connection[db_name]
155+
super().init_connection_state()
156+
157+
def get_connection_params(self):
158+
settings_dict = self.settings_dict
159+
return {
160+
"host": settings_dict["HOST"] or None,
161+
"port": int(settings_dict["PORT"] or 27017),
162+
"username": settings_dict.get("USER"),
163+
"password": settings_dict.get("PASSWORD"),
164+
**settings_dict["OPTIONS"],
165+
}
170166

171-
self.connected = True
172-
connection_created.send(sender=self.__class__, connection=self)
167+
def get_new_connection(self, conn_params):
168+
return MongoClient(**conn_params)
173169

174170
def _commit(self):
175171
pass
176172

177173
def _rollback(self):
178174
pass
179175

176+
def set_autocommit(self, autocommit, force_begin_transaction_with_broken_autocommit=False):
177+
pass
178+
180179
def close(self):
181-
if self.connected:
182-
self.connection.close()
183-
del self.connection
180+
super().close()
181+
with contextlib.suppress(AttributeError):
184182
del self.database
185-
self.connected = False
186183

187184
def cursor(self):
188185
return Cursor()

django_mongodb/compiler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,9 @@ def build_query(self, columns=None):
386386
try:
387387
expr = where.as_mql(self, self.connection) if where else {}
388388
except FullResultSet:
389-
query.mongo_query = {}
389+
query.match_mql = {}
390390
else:
391-
query.mongo_query = {"$expr": expr}
391+
query.match_mql = {"$expr": expr}
392392
if extra_fields:
393393
query.extra_fields = self.get_project_fields(extra_fields, force_expression=True)
394394
query.subqueries = self.subqueries
@@ -722,7 +722,7 @@ def execute_sql(self, result_type):
722722
prepared = prepared.as_mql(self, self.connection)
723723
values[field.column] = prepared
724724
try:
725-
criteria = self.build_query().mongo_query
725+
criteria = self.build_query().match_mql
726726
except EmptyResultSet:
727727
return 0
728728
is_empty = not bool(values)

django_mongodb/features.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44

55
class DatabaseFeatures(BaseDatabaseFeatures):
6+
minimum_database_version = (5, 0)
67
allow_sliced_subqueries_with_in = False
78
allows_multiple_constraints_on_same_fields = False
89
can_create_inline_fk = False
@@ -71,7 +72,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
7172
"backends.tests.BackendTestCase.test_is_usable_after_database_disconnects",
7273
# Connection creation doesn't follow the usual Django API.
7374
"backends.tests.ThreadTests.test_pass_connection_between_threads",
74-
"backends.tests.ThreadTests.test_closing_non_shared_connections",
7575
"backends.tests.ThreadTests.test_default_connection_thread_local",
7676
# Union as subquery is not mapping the parent parameter and collections:
7777
# https://github.com/mongodb-labs/django-mongodb/issues/156

django_mongodb/fields/auto.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ def __init__(self, *args, **kwargs):
1515
kwargs["db_column"] = "_id"
1616
super().__init__(*args, **kwargs)
1717

18+
def deconstruct(self):
19+
name, path, args, kwargs = super().deconstruct()
20+
if self.db_column == "_id":
21+
del kwargs["db_column"]
22+
if path.startswith("django_mongodb.fields.auto"):
23+
path = path.replace("django_mongodb.fields.auto", "django_mongodb.fields")
24+
return name, path, args, kwargs
25+
1826
def get_prep_value(self, value):
1927
if value is None:
2028
return None
@@ -43,11 +51,14 @@ def to_python(self, value):
4351
try:
4452
return ObjectId(value)
4553
except errors.InvalidId:
46-
raise exceptions.ValidationError(
47-
self.error_messages["invalid"],
48-
code="invalid",
49-
params={"value": value},
50-
) from None
54+
try:
55+
return int(value)
56+
except ValueError:
57+
raise exceptions.ValidationError(
58+
self.error_messages["invalid"],
59+
code="invalid",
60+
params={"value": value},
61+
) from None
5162

5263
@cached_property
5364
def validators(self):

django_mongodb/query.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,9 @@ class MongoQuery:
4747

4848
def __init__(self, compiler):
4949
self.compiler = compiler
50-
self.connection = compiler.connection
51-
self.ops = compiler.connection.ops
5250
self.query = compiler.query
53-
self._negated = False
5451
self.ordering = []
55-
self.collection = self.compiler.collection
56-
self.collection_name = self.compiler.collection_name
57-
self.mongo_query = getattr(compiler.query, "raw_query", {})
52+
self.match_mql = {}
5853
self.subqueries = None
5954
self.lookup_pipeline = None
6055
self.project_fields = None
@@ -66,31 +61,31 @@ def __init__(self, compiler):
6661
self.subquery_lookup = None
6762

6863
def __repr__(self):
69-
return f"<MongoQuery: {self.mongo_query!r} ORDER {self.ordering!r}>"
64+
return f"<MongoQuery: {self.match_mql!r} ORDER {self.ordering!r}>"
7065

7166
@wrap_database_errors
7267
def delete(self):
7368
"""Execute a delete query."""
7469
if self.compiler.subqueries:
7570
raise NotSupportedError("Cannot use QuerySet.delete() when a subquery is required.")
76-
return self.collection.delete_many(self.mongo_query).deleted_count
71+
return self.compiler.collection.delete_many(self.match_mql).deleted_count
7772

7873
@wrap_database_errors
7974
def get_cursor(self):
8075
"""
8176
Return a pymongo CommandCursor that can be iterated on to give the
8277
results of the query.
8378
"""
84-
return self.collection.aggregate(self.get_pipeline())
79+
return self.compiler.collection.aggregate(self.get_pipeline())
8580

8681
def get_pipeline(self):
8782
pipeline = []
8883
if self.lookup_pipeline:
8984
pipeline.extend(self.lookup_pipeline)
9085
for query in self.subqueries or ():
9186
pipeline.extend(query.get_pipeline())
92-
if self.mongo_query:
93-
pipeline.append({"$match": self.mongo_query})
87+
if self.match_mql:
88+
pipeline.append({"$match": self.match_mql})
9489
if self.aggregation_pipeline:
9590
pipeline.extend(self.aggregation_pipeline)
9691
if self.project_fields:
@@ -294,7 +289,7 @@ def where_node(self, compiler, connection):
294289
if len(children_mql) == 1:
295290
mql = children_mql[0]
296291
elif len(children_mql) > 1:
297-
mql = {operator: children_mql} if children_mql else {}
292+
mql = {operator: children_mql}
298293
else:
299294
mql = {}
300295

tests/model_fields_/__init__.py

Whitespace-only changes.

tests/model_fields_/test_autofield.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from django.test import SimpleTestCase
2+
3+
from django_mongodb.fields import ObjectIdAutoField
4+
5+
6+
class MethodTests(SimpleTestCase):
7+
def test_deconstruct(self):
8+
field = ObjectIdAutoField()
9+
name, path, args, kwargs = field.deconstruct()
10+
self.assertEqual(path, "django_mongodb.fields.ObjectIdAutoField")
11+
self.assertEqual(args, [])
12+
self.assertEqual(kwargs, {"primary_key": True})
13+
14+
def test_to_python(self):
15+
f = ObjectIdAutoField()
16+
self.assertEqual(f.to_python("1"), 1)

0 commit comments

Comments
 (0)