GeneralManager 0.6.1__tar.gz → 0.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. {generalmanager-0.6.1 → generalmanager-0.6.2}/GeneralManager.egg-info/PKG-INFO +1 -1
  2. {generalmanager-0.6.1 → generalmanager-0.6.2}/GeneralManager.egg-info/SOURCES.txt +1 -0
  3. {generalmanager-0.6.1 → generalmanager-0.6.2}/PKG-INFO +1 -1
  4. {generalmanager-0.6.1 → generalmanager-0.6.2}/pyproject.toml +1 -1
  5. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/interface/databaseInterface.py +58 -34
  6. generalmanager-0.6.2/tests/test_databaseInterface.py +181 -0
  7. {generalmanager-0.6.1 → generalmanager-0.6.2}/GeneralManager.egg-info/dependency_links.txt +0 -0
  8. {generalmanager-0.6.1 → generalmanager-0.6.2}/GeneralManager.egg-info/requires.txt +0 -0
  9. {generalmanager-0.6.1 → generalmanager-0.6.2}/GeneralManager.egg-info/top_level.txt +0 -0
  10. {generalmanager-0.6.1 → generalmanager-0.6.2}/LICENSE +0 -0
  11. {generalmanager-0.6.1 → generalmanager-0.6.2}/README.md +0 -0
  12. {generalmanager-0.6.1 → generalmanager-0.6.2}/setup.cfg +0 -0
  13. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/__init__.py +0 -0
  14. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/api/graphql.py +0 -0
  15. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/api/mutation.py +0 -0
  16. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/api/property.py +0 -0
  17. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/apps.py +0 -0
  18. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/auxiliary/__init__.py +0 -0
  19. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/auxiliary/argsToKwargs.py +0 -0
  20. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/auxiliary/filterParser.py +0 -0
  21. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/auxiliary/jsonEncoder.py +0 -0
  22. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/auxiliary/makeCacheKey.py +0 -0
  23. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/auxiliary/noneToZero.py +0 -0
  24. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/auxiliary/pathMapping.py +0 -0
  25. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/bucket/baseBucket.py +0 -0
  26. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/bucket/calculationBucket.py +0 -0
  27. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/bucket/databaseBucket.py +0 -0
  28. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/bucket/groupBucket.py +0 -0
  29. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/cache/cacheDecorator.py +0 -0
  30. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/cache/cacheTracker.py +0 -0
  31. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/cache/dependencyIndex.py +0 -0
  32. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/cache/modelDependencyCollector.py +0 -0
  33. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/cache/signals.py +0 -0
  34. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/factory/__init__.py +0 -0
  35. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/factory/autoFactory.py +0 -0
  36. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/factory/factories.py +0 -0
  37. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/factory/factoryMethods.py +0 -0
  38. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/interface/__init__.py +0 -0
  39. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/interface/baseInterface.py +0 -0
  40. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/interface/calculationInterface.py +0 -0
  41. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/interface/databaseBasedInterface.py +0 -0
  42. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/interface/readOnlyInterface.py +0 -0
  43. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/manager/__init__.py +0 -0
  44. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/manager/generalManager.py +0 -0
  45. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/manager/groupManager.py +0 -0
  46. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/manager/input.py +0 -0
  47. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/manager/meta.py +0 -0
  48. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/measurement/__init__.py +0 -0
  49. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/measurement/measurement.py +0 -0
  50. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/measurement/measurementField.py +0 -0
  51. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/permission/__init__.py +0 -0
  52. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/permission/basePermission.py +0 -0
  53. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/permission/fileBasedPermission.py +0 -0
  54. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/permission/managerBasedPermission.py +0 -0
  55. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/permission/permissionChecks.py +0 -0
  56. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/permission/permissionDataManager.py +0 -0
  57. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/rule/__init__.py +0 -0
  58. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/rule/handler.py +0 -0
  59. {generalmanager-0.6.1 → generalmanager-0.6.2}/src/general_manager/rule/rule.py +0 -0
  60. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_argsToKwargs.py +0 -0
  61. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_autoFactory.py +0 -0
  62. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_baseBucket.py +0 -0
  63. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_baseInterface.py +0 -0
  64. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_basePermission.py +0 -0
  65. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_cacheDecorator.py +0 -0
  66. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_cacheTracker.py +0 -0
  67. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_calculationBucket.py +0 -0
  68. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_calculationInterface.py +0 -0
  69. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_databaseBasedInterface.py +0 -0
  70. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_databaseBucket.py +0 -0
  71. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_dependencyIndex.py +0 -0
  72. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_factories.py +0 -0
  73. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_factoryMethods.py +0 -0
  74. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_filterParser.py +0 -0
  75. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_generalManager.py +0 -0
  76. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_generalManagerMeta.py +0 -0
  77. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_graph_ql.py +0 -0
  78. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_groupManager.py +0 -0
  79. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_input.py +0 -0
  80. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_jsonEncoder.py +0 -0
  81. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_makeCacheKey.py +0 -0
  82. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_managerBasedPermission.py +0 -0
  83. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_measurement.py +0 -0
  84. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_measurement_field.py +0 -0
  85. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_modelDependencyCollector.py +0 -0
  86. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_noneToZero.py +0 -0
  87. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_rule_handler.py +0 -0
  88. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_rules.py +0 -0
  89. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_settings.py +0 -0
  90. {generalmanager-0.6.1 → generalmanager-0.6.2}/tests/test_signals.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License-Expression: MIT
@@ -65,6 +65,7 @@ tests/test_calculationBucket.py
65
65
  tests/test_calculationInterface.py
66
66
  tests/test_databaseBasedInterface.py
67
67
  tests/test_databaseBucket.py
68
+ tests/test_databaseInterface.py
68
69
  tests/test_dependencyIndex.py
69
70
  tests/test_factories.py
70
71
  tests/test_factoryMethods.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "GeneralManager"
7
- version = "0.6.1"
7
+ version = "0.6.2"
8
8
  description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
@@ -18,36 +18,24 @@ class DatabaseInterface(DBBasedInterface):
18
18
  def create(
19
19
  cls, creator_id: int, history_comment: str | None = None, **kwargs: Any
20
20
  ) -> int:
21
- from general_manager.manager.generalManager import GeneralManager
22
21
 
23
- cls.__checkForInvalidKwargs(cls._model, kwargs=kwargs)
24
- kwargs, many_to_many_kwargs = cls.__sortKwargs(cls._model, kwargs)
25
- instance = cls._model()
26
- for key, value in kwargs.items():
27
- if isinstance(value, GeneralManager):
28
- value = value.identification["id"]
29
- key = f"{key}_id"
30
- setattr(instance, key, value)
31
- for key, value in many_to_many_kwargs.items():
32
- getattr(instance, key).set(value)
33
- return cls.__save_with_history(instance, creator_id, history_comment)
22
+ cls._checkForInvalidKwargs(cls._model, kwargs=kwargs)
23
+ kwargs, many_to_many_kwargs = cls._sortKwargs(cls._model, kwargs)
24
+ instance = cls.__setAttrForWrite(cls._model(), kwargs)
25
+ pk = cls._save_with_history(instance, creator_id, history_comment)
26
+ cls.__setManyToManyAttributes(instance, many_to_many_kwargs)
27
+ return pk
34
28
 
35
29
  def update(
36
30
  self, creator_id: int, history_comment: str | None = None, **kwargs: Any
37
31
  ) -> int:
38
- from general_manager.manager.generalManager import GeneralManager
39
32
 
40
- self.__checkForInvalidKwargs(self._model, kwargs=kwargs)
41
- kwargs, many_to_many_kwargs = self.__sortKwargs(self._model, kwargs)
42
- instance = self._model.objects.get(pk=self.pk)
43
- for key, value in kwargs.items():
44
- if isinstance(value, GeneralManager):
45
- value = value.identification["id"]
46
- key = f"{key}_id"
47
- setattr(instance, key, value)
48
- for key, value in many_to_many_kwargs.items():
49
- getattr(instance, key).set(value)
50
- return self.__save_with_history(instance, creator_id, history_comment)
33
+ self._checkForInvalidKwargs(self._model, kwargs=kwargs)
34
+ kwargs, many_to_many_kwargs = self._sortKwargs(self._model, kwargs)
35
+ instance = self.__setAttrForWrite(self._model.objects.get(pk=self.pk), kwargs)
36
+ pk = self._save_with_history(instance, creator_id, history_comment)
37
+ self.__setManyToManyAttributes(instance, many_to_many_kwargs)
38
+ return pk
51
39
 
52
40
  def deactivate(self, creator_id: int, history_comment: str | None = None) -> int:
53
41
  instance = self._model.objects.get(pk=self.pk)
@@ -56,32 +44,68 @@ class DatabaseInterface(DBBasedInterface):
56
44
  history_comment = f"{history_comment} (deactivated)"
57
45
  else:
58
46
  history_comment = "Deactivated"
59
- return self.__save_with_history(instance, creator_id, history_comment)
47
+ return self._save_with_history(instance, creator_id, history_comment)
60
48
 
61
49
  @staticmethod
62
- def __checkForInvalidKwargs(model: Type[models.Model], kwargs: dict[Any, Any]):
50
+ def __setManyToManyAttributes(
51
+ instance: GeneralManagerModel, many_to_many_kwargs: dict[str, list[Any]]
52
+ ) -> GeneralManagerModel:
53
+ """
54
+ Sets many-to-many attributes for the given instance based on the provided kwargs.
55
+
56
+ Args:
57
+ instance: The model instance to update.
58
+ many_to_many_kwargs: A dictionary containing many-to-many field names and their corresponding values.
59
+
60
+ Returns:
61
+ The updated model instance.
62
+ """
63
+ for key, value in many_to_many_kwargs.items():
64
+ if not value:
65
+ continue
66
+ field_name = key.split("_id_list")[0]
67
+ getattr(instance, field_name).set(value)
68
+
69
+ return instance
70
+
71
+ @staticmethod
72
+ def __setAttrForWrite(
73
+ instance: GeneralManagerModel,
74
+ kwargs: dict[str, Any],
75
+ ) -> GeneralManagerModel:
76
+ from general_manager.manager.generalManager import GeneralManager
77
+
78
+ for key, value in kwargs.items():
79
+ if isinstance(value, GeneralManager):
80
+ value = value.identification["id"]
81
+ key = f"{key}_id"
82
+ setattr(instance, key, value)
83
+ return instance
84
+
85
+ @staticmethod
86
+ def _checkForInvalidKwargs(model: Type[models.Model], kwargs: dict[str, Any]):
63
87
  attributes = vars(model)
64
- fields = model._meta.get_fields()
88
+ field_names = {f.name for f in model._meta.get_fields()}
65
89
  for key in kwargs:
66
- if key not in attributes and key not in fields:
90
+ temp_key = key.split("_id_list")[0] # Remove '_id_list' suffix
91
+ if temp_key not in attributes and temp_key not in field_names:
67
92
  raise ValueError(f"{key} does not exsist in {model.__name__}")
68
93
 
69
94
  @staticmethod
70
- def __sortKwargs(
95
+ def _sortKwargs(
71
96
  model: Type[models.Model], kwargs: dict[Any, Any]
72
97
  ) -> tuple[dict[str, Any], dict[str, list[Any]]]:
73
- many_to_many_fields = model._meta.many_to_many
98
+ many_to_many_fields = [field.name for field in model._meta.many_to_many]
74
99
  many_to_many_kwargs: dict[Any, Any] = {}
75
- for key, value in kwargs.items():
100
+ for key, value in list(kwargs.items()):
76
101
  many_to_many_key = key.split("_id_list")[0]
77
102
  if many_to_many_key in many_to_many_fields:
78
- many_to_many_kwargs[key] = value
79
- kwargs.pop(key)
103
+ many_to_many_kwargs[key] = kwargs.pop(key)
80
104
  return kwargs, many_to_many_kwargs
81
105
 
82
106
  @classmethod
83
107
  @transaction.atomic
84
- def __save_with_history(
108
+ def _save_with_history(
85
109
  cls, instance: GeneralManagerModel, creator_id: int, history_comment: str | None
86
110
  ) -> int:
87
111
  """
@@ -0,0 +1,181 @@
1
+ # type: ignore
2
+ from typing import Any
3
+ from unittest.mock import patch
4
+ from django.contrib.auth.models import User
5
+ from django.db import models, connection
6
+ from django.test import TransactionTestCase
7
+
8
+ from general_manager.interface.databaseInterface import DatabaseInterface
9
+ from general_manager.manager.generalManager import GeneralManager
10
+ from general_manager.manager.input import Input
11
+
12
+
13
+ class SafeDict(dict):
14
+ def items(self):
15
+ return list(super().items())
16
+
17
+
18
+ class DatabaseInterfaceTestCase(TransactionTestCase):
19
+ @classmethod
20
+ def setUpClass(cls):
21
+ super().setUpClass()
22
+
23
+ class UserInterface(DatabaseInterface):
24
+ _model = User
25
+ _parent_class = None
26
+ input_fields = {"id": Input(int)}
27
+
28
+ @classmethod
29
+ def handleInterface(cls):
30
+ def pre(name, attrs, interface):
31
+ return attrs, cls, cls._model
32
+
33
+ def post(new_cls, interface_cls, model):
34
+ new_cls.Interface = interface_cls
35
+ interface_cls._parent_class = new_cls
36
+
37
+ return pre, post
38
+
39
+ class UserManager(GeneralManager):
40
+ Interface = UserInterface
41
+
42
+ cls.UserManager = UserManager
43
+ UserInterface._parent_class = UserManager
44
+
45
+ class BookModel(models.Model):
46
+ title = models.CharField(max_length=50)
47
+ author = models.ForeignKey(User, on_delete=models.CASCADE)
48
+ readers = models.ManyToManyField(User, blank=True)
49
+ is_active = models.BooleanField(default=True)
50
+ changed_by = models.ForeignKey(User, on_delete=models.PROTECT)
51
+
52
+ class Meta:
53
+ app_label = "general_manager"
54
+
55
+ cls.BookModel = BookModel
56
+
57
+ class BookInterface(DatabaseInterface):
58
+ _model = BookModel
59
+ _parent_class = None
60
+ input_fields = {"id": Input(int)}
61
+
62
+ @classmethod
63
+ def handleInterface(cls):
64
+ def pre(name, attrs, interface):
65
+ return attrs, cls, cls._model
66
+
67
+ def post(new_cls, interface_cls, model):
68
+ new_cls.Interface = interface_cls
69
+ interface_cls._parent_class = new_cls
70
+
71
+ return pre, post
72
+
73
+ cls.BookInterface = BookInterface
74
+
75
+ class BookManager(GeneralManager):
76
+ Interface = BookInterface
77
+
78
+ cls.BookManager = BookManager
79
+ BookInterface._parent_class = BookManager
80
+
81
+ with connection.schema_editor() as schema:
82
+ schema.create_model(BookModel)
83
+
84
+ @classmethod
85
+ def tearDownClass(cls):
86
+ with connection.schema_editor() as schema:
87
+ schema.delete_model(cls.BookModel)
88
+ super().tearDownClass()
89
+
90
+ def setUp(self):
91
+ self.user = User.objects.create(username="tester")
92
+ self.book = self.BookModel.objects.create(
93
+ title="Initial",
94
+ author=self.user,
95
+ changed_by=self.user,
96
+ )
97
+ self.book.readers.add(self.user)
98
+ self.user_manager = self.UserManager(self.user.pk)
99
+
100
+ def test_check_for_invalid_kwargs(self):
101
+ self.BookInterface._checkForInvalidKwargs(
102
+ self.BookModel, {"title": "a", "readers_id_list": []}
103
+ )
104
+ with self.assertRaises(ValueError):
105
+ self.BookInterface._checkForInvalidKwargs(self.BookModel, {"wrong": 1})
106
+
107
+ def test_sort_kwargs(self):
108
+ kwargs = SafeDict({"title": "b", "readers_id_list": [1]})
109
+ normal, m2m = self.BookInterface._sortKwargs(self.BookModel, kwargs)
110
+ self.assertEqual(normal, {"title": "b"})
111
+ self.assertEqual(m2m, {"readers_id_list": [1]})
112
+
113
+ def test_save_with_history(self):
114
+ class Dummy:
115
+ def __init__(self):
116
+ self.pk = 5
117
+ self.saved = False
118
+ self.cleaned = False
119
+
120
+ def full_clean(self):
121
+ self.cleaned = True
122
+
123
+ def save(self):
124
+ self.saved = True
125
+
126
+ inst = Dummy()
127
+ with patch(
128
+ "general_manager.interface.databaseInterface.update_change_reason"
129
+ ) as mock_update:
130
+ pk = self.BookInterface._save_with_history(inst, 7, "comment")
131
+ self.assertEqual(pk, 5)
132
+ self.assertEqual(inst.changed_by_id, 7)
133
+ self.assertTrue(inst.cleaned)
134
+ self.assertTrue(inst.saved)
135
+ mock_update.assert_called_once_with(inst, "comment")
136
+
137
+ def test_create_update_and_deactivate(self):
138
+ captured: dict[str, Any] = {}
139
+
140
+ def fake_save(instance, creator_id, comment):
141
+ captured["instance"] = instance
142
+ captured["creator"] = creator_id
143
+ captured["comment"] = comment
144
+ return getattr(instance, "pk", 99) or 99
145
+
146
+ with patch.object(
147
+ self.BookInterface,
148
+ "_save_with_history",
149
+ side_effect=fake_save,
150
+ ):
151
+ pk = self.BookInterface.create(
152
+ creator_id=self.user.pk,
153
+ history_comment="new",
154
+ title="Created",
155
+ author=self.user_manager,
156
+ )
157
+ self.assertEqual(pk, 99)
158
+ self.assertEqual(captured["instance"].title, "Created")
159
+ self.assertEqual(captured["comment"], "new")
160
+
161
+ mgr = self.BookManager(self.book.pk)
162
+ pk2 = mgr._interface.update(
163
+ creator_id=self.user.pk,
164
+ history_comment="up",
165
+ title="Updated",
166
+ )
167
+
168
+ self.assertEqual(pk2, self.book.pk)
169
+ self.assertEqual(captured["instance"].title, "Updated")
170
+ self.assertEqual(captured["comment"], "up")
171
+
172
+ pk2 = mgr._interface.update(
173
+ creator_id=self.user.pk,
174
+ readers_id_list=[self.user.pk],
175
+ )
176
+ pk3 = mgr._interface.deactivate(
177
+ creator_id=self.user.pk, history_comment="reason"
178
+ )
179
+ self.assertEqual(pk3, self.book.pk)
180
+ self.assertFalse(captured["instance"].is_active)
181
+ self.assertEqual(captured["comment"], "reason (deactivated)")
File without changes
File without changes
File without changes