Drop support for positional arguments when instantiating a document

For example, if you had the following class:
```
class Person(Document):
    name = StringField()
    age = IntField()
```

You could instantiate an object of such class by doing one of the following:
1. `new_person = Person('Tom', 30)`
2. `new_person = Person('Tom', age=30)`
3. `new_person = Person(name='Tom', age=30)`

From now on, only option (3) is allowed.

Supporting positional arguments may sound like a reasonable idea in this
heavily simplified example, but in real life it's almost never what you want
(especially if you use inheritance in your document definitions) and it may
lead to ugly bugs. We should not rely on the *order* of fields to match a given
value to a given name.

This also helps us simplify the code e.g. by dropping the confusing (and
undocumented) `BaseDocument._auto_id_field` attribute.
This commit is contained in:
Stefan Wojcik
2019-06-24 15:44:35 +02:00
parent a4fe091a51
commit f45552f8f8
5 changed files with 82 additions and 69 deletions

View File

@@ -3130,48 +3130,44 @@ class InstanceTest(MongoDBTestCase):
self.assertEqual(classic_doc._data, dict_doc._data)
def test_positional_creation(self):
"""Ensure that document may be created using positional arguments."""
person = self.Person("Test User", 42)
self.assertEqual(person.name, "Test User")
self.assertEqual(person.age, 42)
"""Document cannot be instantiated using positional arguments."""
with self.assertRaises(TypeError) as e:
person = self.Person("Test User", 42)
expected_msg = (
'Instantiating a document with positional arguments is not '
'supported. Please use `field_name=value` keyword arguments.'
)
self.assertEqual(e.exception.message, expected_msg)
def test_mixed_creation(self):
"""Ensure that document may be created using mixed arguments."""
person = self.Person("Test User", age=42)
self.assertEqual(person.name, "Test User")
self.assertEqual(person.age, 42)
"""Document cannot be instantiated using mixed arguments."""
with self.assertRaises(TypeError) as e:
person = self.Person("Test User", age=42)
expected_msg = (
'Instantiating a document with positional arguments is not '
'supported. Please use `field_name=value` keyword arguments.'
)
self.assertEqual(e.exception.message, expected_msg)
def test_positional_creation_embedded(self):
"""Ensure that embedded document may be created using positional
arguments.
"""
job = self.Job("Test Job", 4)
self.assertEqual(job.name, "Test Job")
self.assertEqual(job.years, 4)
"""Embedded document cannot be created using positional arguments."""
with self.assertRaises(TypeError) as e:
job = self.Job("Test Job", 4)
expected_msg = (
'Instantiating a document with positional arguments is not '
'supported. Please use `field_name=value` keyword arguments.'
)
self.assertEqual(e.exception.message, expected_msg)
def test_mixed_creation_embedded(self):
"""Ensure that embedded document may be created using mixed
arguments.
"""
job = self.Job("Test Job", years=4)
self.assertEqual(job.name, "Test Job")
self.assertEqual(job.years, 4)
def test_mixed_creation_dynamic(self):
"""Ensure that document may be created using mixed arguments."""
class Person(DynamicDocument):
name = StringField()
person = Person("Test User", age=42)
self.assertEqual(person.name, "Test User")
self.assertEqual(person.age, 42)
def test_bad_mixed_creation(self):
"""Ensure that document gives correct error when duplicating
arguments.
"""
with self.assertRaises(TypeError):
return self.Person("Test User", 42, name="Bad User")
"""Embedded document cannot be created using mixed arguments."""
with self.assertRaises(TypeError) as e:
job = self.Job("Test Job", years=4)
expected_msg = (
'Instantiating a document with positional arguments is not '
'supported. Please use `field_name=value` keyword arguments.'
)
self.assertEqual(e.exception.message, expected_msg)
def test_data_contains_id_field(self):
"""Ensure that asking for _data returns 'id'."""