Skip to content

Commit 8fcc3b6

Browse files
committed
Fixes test, updates release notes
1 parent be9553f commit 8fcc3b6

File tree

4 files changed

+77
-53
lines changed

4 files changed

+77
-53
lines changed

README.md

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
[![Python versions](https://img.shields.io/pypi/pyversions/django-lifecycle.svg)](https://pypi.org/project/django-lifecycle/)
66
![PyPI - Django Version](https://img.shields.io/pypi/djversions/django-lifecycle)
77

8-
98
This project provides a `@hook` decorator as well as a base model and mixin to add lifecycle hooks to your Django models. Django's built-in approach to offering lifecycle hooks is [Signals](https://docs.djangoproject.com/en/dev/topics/signals/). However, my team often finds that Signals introduce unnecessary indirection and are at odds with Django's "fat models" approach.
109

1110
**Django Lifecycle Hooks** supports Python 3.5, 3.6, 3.7, 3.8 and 3.9, Django 2.0.x, 2.1.x, 2.2.x, 3.0.x and 3.1.x.
@@ -35,13 +34,13 @@ Instead of overriding `save` and `__init__` in a clunky way that hurts readabili
3534

3635
```python
3736
# same class and field declarations as above ...
38-
37+
3938
def __init__(self, *args, **kwargs):
4039
super().__init__(*args, **kwargs)
4140
self._orig_contents = self.contents
4241
self._orig_status = self.status
43-
44-
42+
43+
4544
def save(self, *args, **kwargs):
4645
if self.pk is not None and self.contents != self._orig_contents:
4746
self.updated_at = timezone.now()
@@ -62,81 +61,108 @@ Instead of overriding `save` and `__init__` in a clunky way that hurts readabili
6261

6362
# Changelog
6463

64+
## 0.9.2 (October 2021)
65+
66+
- Run hooked methods inside transactions, just as signals do. Thanks @amirmotlagh!
67+
6568
## 0.9.1 (March 2021)
66-
* Makes hooks work with OneToOneFields. Thanks @bahmdev!
69+
70+
- Makes hooks work with OneToOneFields. Thanks @bahmdev!
6771

6872
## 0.9.0 (February 2021)
69-
* Prevents calling a hooked method twice with the same state. Thanks @garyd203!
73+
74+
- Prevents calling a hooked method twice with the same state. Thanks @garyd203!
7075

7176
## 0.8.1 (January 2021)
72-
* Added missing return to `delete()` method override. Thanks @oaosman84!
77+
78+
- Added missing return to `delete()` method override. Thanks @oaosman84!
7379

7480
## 0.8.0 (October 2020)
75-
* Significant performance improvements. Thanks @dralley!
81+
82+
- Significant performance improvements. Thanks @dralley!
7683

7784
## 0.7.7 (August 2020)
78-
* Fixes issue with `GenericForeignKey`. Thanks @bmbouter!
85+
86+
- Fixes issue with `GenericForeignKey`. Thanks @bmbouter!
7987

8088
## 0.7.6 (May 2020)
81-
* Updates to use constants for hook names; updates docs to indicate Python 3.8/Django 3.x support. Thanks @thejoeejoee!
89+
90+
- Updates to use constants for hook names; updates docs to indicate Python 3.8/Django 3.x support. Thanks @thejoeejoee!
8291

8392
## 0.7.5 (April 2020)
84-
* Adds static typed variables for hook names; thanks @Faisal-Manzer!
85-
* Fixes some typos in docs; thanks @tomdyson and @bmispelon!
93+
94+
- Adds static typed variables for hook names; thanks @Faisal-Manzer!
95+
- Fixes some typos in docs; thanks @tomdyson and @bmispelon!
8696

8797
## 0.7.1 (January 2020)
88-
* Fixes bug in `utils._get_field_names` that could cause recursion bug in some cases.
98+
99+
- Fixes bug in `utils._get_field_names` that could cause recursion bug in some cases.
89100

90101
## 0.7.0 (December 2019)
91-
* Adds `changes_to` condition - thanks @samitnuk! Also some typo fixes in docs.
102+
103+
- Adds `changes_to` condition - thanks @samitnuk! Also some typo fixes in docs.
92104

93105
## 0.6.1 (November 2019)
94-
* Remove variable type annotation for Python 3.5 compatability.
106+
107+
- Remove variable type annotation for Python 3.5 compatability.
95108

96109
## 0.6.0 (October 2019)
97-
* Adds `when_any` hook parameter to watch multiple fields for state changes
110+
111+
- Adds `when_any` hook parameter to watch multiple fields for state changes
98112

99113
## 0.5.0 (September 2019)
100-
* Adds `was_not` condition
101-
* Allow watching changes to FK model field values, not just FK references
114+
115+
- Adds `was_not` condition
116+
- Allow watching changes to FK model field values, not just FK references
102117

103118
## 0.4.2 (July 2019)
104-
* Fixes missing README.md issue that broke install.
119+
120+
- Fixes missing README.md issue that broke install.
105121

106122
## 0.4.1 (June 2019)
107-
* Fixes [urlman](https://github.com/andrewgodwin/urlman)-compatability.
123+
124+
- Fixes [urlman](https://github.com/andrewgodwin/urlman)-compatability.
108125

109126
## 0.4.0 (May 2019)
110-
* Fixes `initial_value(field_name)` behavior - should return value even if no change. Thanks @adamJLev!
127+
128+
- Fixes `initial_value(field_name)` behavior - should return value even if no change. Thanks @adamJLev!
111129

112130
## 0.3.2 (February 2019)
113-
* Fixes bug preventing hooks from firing for custom PKs. Thanks @atugushev!
131+
132+
- Fixes bug preventing hooks from firing for custom PKs. Thanks @atugushev!
114133

115134
## 0.3.1 (August 2018)
116-
* Fixes m2m field bug, in which accessing auto-generated reverse field in `before_create` causes exception b/c PK does not exist yet. Thanks @garyd203!
135+
136+
- Fixes m2m field bug, in which accessing auto-generated reverse field in `before_create` causes exception b/c PK does not exist yet. Thanks @garyd203!
117137

118138
## 0.3.0 (April 2018)
119-
* Resets model's comparison state for hook conditions after `save` called.
139+
140+
- Resets model's comparison state for hook conditions after `save` called.
120141

121142
## 0.2.4 (April 2018)
122-
* Fixed support for adding multiple `@hook` decorators to same method.
143+
144+
- Fixed support for adding multiple `@hook` decorators to same method.
123145

124146
## 0.2.3 (April 2018)
125-
* Removes residual mixin methods from earlier implementation.
147+
148+
- Removes residual mixin methods from earlier implementation.
126149

127150
## 0.2.2 (April 2018)
128-
* Save method now accepts `skip_hooks`, an optional boolean keyword argument that controls whether hooked methods are called.
151+
152+
- Save method now accepts `skip_hooks`, an optional boolean keyword argument that controls whether hooked methods are called.
129153

130154
## 0.2.1 (April 2018)
131-
* Fixed bug in `_potentially_hooked_methods` that caused unwanted side effects by accessing model instance methods decorated with `@cache_property` or `@property`.
155+
156+
- Fixed bug in `_potentially_hooked_methods` that caused unwanted side effects by accessing model instance methods decorated with `@cache_property` or `@property`.
132157

133158
## 0.2.0 (April 2018)
134-
* Added Django 1.8 support. Thanks @jtiai!
135-
* Tox testing added for Python 3.4, 3.5, 3.6 and Django 1.8, 1.11 and 2.0. Thanks @jtiai!
159+
160+
- Added Django 1.8 support. Thanks @jtiai!
161+
- Tox testing added for Python 3.4, 3.5, 3.6 and Django 1.8, 1.11 and 2.0. Thanks @jtiai!
136162

137163
# Testing
138164

139-
Tests are found in a simplified Django project in the ```/tests``` folder. Install the project requirements and do ```./manage.py test``` to run them.
165+
Tests are found in a simplified Django project in the `/tests` folder. Install the project requirements and do `./manage.py test` to run them.
140166

141167
# License
142168

django_lifecycle/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from .django_info import IS_GTE_1_POINT_9
22

3-
__version__ = "0.9.1"
3+
__version__ = "0.9.2"
44
__author__ = "Robert Singer"
55
__author_email__ = "[email protected]"
66

django_lifecycle/mixins.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ def has_changed(self, field_name: str) -> bool:
106106
return False
107107

108108
def _clear_watched_fk_model_cache(self):
109-
"""
110-
111-
"""
109+
""" """
112110
for watched_field_name in self._watched_fk_models():
113111
field = self._meta.get_field(watched_field_name)
114112

@@ -172,9 +170,9 @@ def _potentially_hooked_methods(cls):
172170
@lru_cache(typed=True)
173171
def _watched_fk_model_fields(cls) -> List[str]:
174172
"""
175-
Gather up all field names (values in 'when' key) that correspond to
176-
field names on FK-related models. These will be strings that contain
177-
periods.
173+
Gather up all field names (values in 'when' key) that correspond to
174+
field names on FK-related models. These will be strings that contain
175+
periods.
178176
"""
179177
watched = [] # List[str]
180178

@@ -192,9 +190,9 @@ def _watched_fk_models(cls) -> List[str]:
192190

193191
def _run_hooked_methods(self, hook: str) -> List[str]:
194192
"""
195-
Iterate through decorated methods to find those that should be
196-
triggered by the current hook. If conditions exist, check them before
197-
running otherwise go ahead and run.
193+
Iterate through decorated methods to find those that should be
194+
triggered by the current hook. If conditions exist, check them before
195+
running otherwise go ahead and run.
198196
"""
199197
fired = []
200198

@@ -210,10 +208,12 @@ def _run_hooked_methods(self, hook: str) -> List[str]:
210208
if not self._check_callback_conditions(when_field, callback_specs):
211209
continue
212210
elif when_any_field:
213-
if not any([
214-
self._check_callback_conditions(field_name, callback_specs)
215-
for field_name in when_any_field
216-
]):
211+
if not any(
212+
[
213+
self._check_callback_conditions(field_name, callback_specs)
214+
for field_name in when_any_field
215+
]
216+
):
217217
continue
218218

219219
# Only call the method once per hook
@@ -277,9 +277,9 @@ def _check_changes_to_condition(self, field_name: str, specs: dict) -> bool:
277277
@classmethod
278278
def _get_model_property_names(cls) -> List[str]:
279279
"""
280-
Gather up properties and cached_properties which may be methods
281-
that were decorated. Need to inspect class versions b/c doing
282-
getattr on them could cause unwanted side effects.
280+
Gather up properties and cached_properties which may be methods
281+
that were decorated. Need to inspect class versions b/c doing
282+
getattr on them could cause unwanted side effects.
283283
"""
284284
property_names = []
285285

tests/testapp/tests/test_user_account.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def test_email_user_about_name_change(self):
119119

120120
def test_skip_hooks(self):
121121
"""
122-
Hooked method that auto-lowercases email should be skipped.
122+
Hooked method that auto-lowercases email should be skipped.
123123
"""
124124
account = UserAccount.objects.create(**self.stub_data)
125125
account.email = "Homer.Simpson@springfieldnuclear"
@@ -128,11 +128,9 @@ def test_skip_hooks(self):
128128

129129
def test_delete_should_return_default_django_value(self):
130130
"""
131-
Hooked method that auto-lowercases email should be skipped.
131+
Hooked method that auto-lowercases email should be skipped.
132132
"""
133133
UserAccount.objects.create(**self.stub_data)
134134
value = UserAccount.objects.all().delete()
135135

136-
self.assertEqual(
137-
value, (1, {"testapp.Locale_users": 0, "testapp.UserAccount": 1})
138-
)
136+
self.assertEqual(value, (1, {"testapp.UserAccount": 1}))

0 commit comments

Comments
 (0)