PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/test_model_type.py

https://github.com/schematics/schematics
Python | 314 lines | 214 code | 95 blank | 5 comment | 6 complexity | 1274d06f5b89ea861a681969eae87a29 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. import pytest
  2. from schematics.models import Model
  3. from schematics.types import IntType, StringType
  4. from schematics.types.compound import ModelType, ListType
  5. from schematics.exceptions import DataError
  6. from schematics.util import ImportStringError
  7. def test_simple_embedded_models():
  8. class Location(Model):
  9. country_code = StringType()
  10. class Player(Model):
  11. id = IntType()
  12. location = ModelType(Location)
  13. p = Player(dict(id=1, location={"country_code": "US"}))
  14. assert p.id == 1
  15. assert p.location.country_code == "US"
  16. p.location = Location({"country_code": "IS"})
  17. assert isinstance(p.location, Location)
  18. assert p.location.country_code == "IS"
  19. def test_simple_embedded_models_is_none():
  20. class Location(Model):
  21. country_code = StringType()
  22. class Player(Model):
  23. id = IntType()
  24. location = ModelType(Location)
  25. p = Player(dict(id=1))
  26. assert p.id == 1
  27. assert p.location is None
  28. def test_simple_embedded_model_set_to_none():
  29. class Location(Model):
  30. country_code = StringType()
  31. class Player(Model):
  32. id = IntType()
  33. location = ModelType(Location)
  34. p = Player(dict(id=1))
  35. p.location = None
  36. assert p.id == 1
  37. assert p.location is None
  38. def test_simple_embedded_model_is_none_within_listtype():
  39. class QuestionResources(Model):
  40. type = StringType()
  41. class Question(Model):
  42. id = StringType()
  43. resources = ModelType(QuestionResources)
  44. class QuestionPack(Model):
  45. id = StringType()
  46. questions = ListType(ModelType(Question))
  47. question_pack = QuestionPack({
  48. "id": "1",
  49. "questions": [
  50. {
  51. "id": "1",
  52. },
  53. ]
  54. })
  55. assert question_pack.questions[0].resources is None
  56. def test_raises_validation_error_on_init_with_partial_submodel():
  57. class User(Model):
  58. name = StringType(required=True)
  59. age = IntType(required=True)
  60. class Card(Model):
  61. user = ModelType(User)
  62. u = User({'name': 'Arthur'})
  63. c = Card({'user': u})
  64. with pytest.raises(DataError):
  65. c.validate()
  66. def test_model_type():
  67. class User(Model):
  68. name = StringType()
  69. class Card(Model):
  70. user = ModelType(User)
  71. c = Card({"user": {'name': u'Doggy'}})
  72. assert isinstance(c.user, User)
  73. assert c.user.name == "Doggy"
  74. def test_equality_with_embedded_models():
  75. class Location(Model):
  76. country_code = StringType()
  77. class Player(Model):
  78. id = IntType()
  79. location = ModelType(Location)
  80. p1 = Player(dict(id=1, location={"country_code": "US"}))
  81. p2 = Player(dict(id=1, location={"country_code": "US"}))
  82. assert id(p1.location) != id(p2.location)
  83. assert p1.location == p2.location
  84. assert p1 == p2
  85. def test_default_value_when_embedded_model():
  86. class Question(Model):
  87. question_id = StringType(required=True)
  88. type = StringType(default="text")
  89. class QuestionPack(Model):
  90. question = ModelType(Question)
  91. pack = QuestionPack({
  92. "question": {
  93. "question_id": 1
  94. }
  95. })
  96. assert pack.question.question_id == "1"
  97. assert pack.question.type == "text"
  98. def test_export_loop_with_subclassed_model():
  99. class Asset(Model):
  100. file_name = StringType()
  101. class S3Asset(Asset):
  102. bucket_name = StringType()
  103. class Product(Model):
  104. title = StringType()
  105. asset = ModelType(Asset)
  106. asset = S3Asset({'bucket_name': 'assets_bucket', 'file_name': 'bar'})
  107. product = Product({'title': 'baz', 'asset': asset})
  108. primitive = product.to_primitive()
  109. assert 'bucket_name' in primitive['asset']
  110. native = product.to_native()
  111. assert 'bucket_name' in native['asset']
  112. def test_conversion_error_recursive_overhead():
  113. conversions = [0]
  114. class Leaf(Model):
  115. pass
  116. next_model = Leaf
  117. data = 'not a mapping'
  118. for i in range(20):
  119. class Recursive(Model):
  120. x = ModelType(next_model, required=True)
  121. def __init__(self, *args, **kwargs):
  122. super(type(self), self).__init__(*args, **kwargs)
  123. conversions[0] += 1
  124. assert conversions[0] < 25
  125. next_model = Recursive
  126. data = {'x': data}
  127. with pytest.raises(DataError):
  128. next_model(data)
  129. def test_mock_object():
  130. class User(Model):
  131. name = StringType(required=True)
  132. age = IntType(required=True)
  133. assert ModelType(User, required=True).mock() is not None
  134. def test_specify_model_by_name():
  135. class M(Model):
  136. to_one = ModelType('M')
  137. to_many = ListType(ModelType('M'))
  138. matrix = ListType(ListType(ModelType('M')))
  139. assert M.to_one.model_class is M
  140. assert M.to_many.field.model_class is M
  141. assert M.matrix.field.field.model_class is M
  142. def test_model_context_pass_to_type():
  143. from schematics.types import BaseType
  144. from schematics.datastructures import Context
  145. class CustomType(BaseType):
  146. def to_native(self, value, context=None):
  147. suffix = context.suffix
  148. return str(value) + suffix
  149. def to_primitive(self, value, context=None):
  150. suffix = context.suffix
  151. return value[:-len(suffix)]
  152. class Thing(Model):
  153. x = CustomType()
  154. context = {'suffix': 'z'}
  155. input = {'x': 'thingie'}
  156. thing = Thing(input, context=context)
  157. assert thing.x == 'thingiez'
  158. assert thing.to_primitive(context=context) == {'x': 'thingie'}
  159. # try it with a Context object
  160. model_context = Context(suffix='z!')
  161. thing2 = Thing(input, context=model_context)
  162. assert thing2.x == 'thingiez!'
  163. export_context = Context(suffix='z!')
  164. assert thing2.to_primitive(context=export_context) == {'x': 'thingie'}
  165. with pytest.raises(AttributeError):
  166. # can't reuse the same Context object as was used for model
  167. # TODO this may be unexpected to the uninitiated; a custom exception
  168. # could explain it better.
  169. thing2.to_primitive(context=model_context)
  170. def test_model_app_data_pass_to_type():
  171. from schematics.types import BaseType
  172. class CustomType(BaseType):
  173. def to_native(self, value, context=None):
  174. suffix = context.app_data['suffix']
  175. return str(value) + suffix
  176. def to_primitive(self, value, context=None):
  177. suffix = context.app_data['suffix']
  178. return value[:-len(suffix)]
  179. class Thing(Model):
  180. x = CustomType()
  181. app_data = {'suffix': 'z'}
  182. input = {'x': 'thingie'}
  183. thing = Thing(input, app_data=app_data)
  184. assert thing.x == 'thingiez'
  185. assert thing.to_primitive(app_data=app_data) == {'x': 'thingie'}
  186. class OuterModel:
  187. class InnerModel(Model):
  188. test = StringType()
  189. def test_deep_string_search():
  190. class TestModel(Model):
  191. deep_model = ModelType('test_model_type.OuterModel.InnerModel')
  192. test = TestModel(dict(deep_model=dict(test='Abc')))
  193. assert test.validate() is None
  194. class TestModel2(Model):
  195. invalid_model = ModelType('a.c.d.e')
  196. with pytest.raises(ImportStringError):
  197. TestModel2(dict(invalid_model=dict(a='1')))
  198. def test_recursive_string_self_reference():
  199. class RecursiveTestModel(Model):
  200. recursive_model = ModelType('RecursiveTestModel')
  201. test = StringType()
  202. test = RecursiveTestModel(dict(recursive_model=dict(test='Abc')))
  203. assert test.validate() is None
  204. assert test.recursive_model.test == 'Abc'
  205. def test_circular_string_reference():
  206. class TestModel1(Model):
  207. model2 = ModelType('TestModel2')
  208. name = StringType()
  209. class TestModel2(Model):
  210. model1 = ModelType('TestModel1')
  211. description = StringType()
  212. data1 = {'name': 'Test1'}
  213. data2 = {'description': 'Test2', 'model1': data1}
  214. # TODO: we might want to support locals import late binding someday/somehow
  215. with pytest.raises(ImportStringError):
  216. test = TestModel1({
  217. 'name': 'Root',
  218. 'model2': data2
  219. })