./userdetails/models.py
```python
from allauth.socialaccount.models import SocialApp
from django.conf import settings
from django.contrib.auth.models import AbstractUser, Group
from django.contrib.auth.models import UserManager as DjangoUserManager, GroupManager
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
from django.utils.functional import cached_property
class UserManager(DjangoUserManager):
def get_by_natural_key(self, username):
# See https://docs.djangoproject.com/en/4.1/topics/serialization/#natural-keys
# Allow the use of id to lookup as well
if isinstance(username, int):
return self.get(id=username)
return self.get(username=username)
class User(AbstractUser):
email = models.EmailField("email address", unique=True)
allergies = models.CharField(
max_length=100,
blank=True,
help_text="E.g. gluten or vegetarian. Leave empty if not applicable.",
verbose_name="food allergies or preferences"
)
objects = UserManager()
def clean(self):
# By default, Django uses case-sensitive usernames. This means that
# users 'asdf' and 'Asdf' are considered different users. The allauth
# library handles it differently and considers them the same users.
# This doesn't play well together.
#
# We fix it using a case-insensitive uniqueness check on the username,
# in the model validation below. In the future, we could consider
# normalizing usernames to lowercase, or removing the allauth library
# for something more lightweight (custom code).
qs = self.__class__.objects.filter(username__iexact=self.username)
# Exclude own entry
if self.pk:
qs = qs.exclude(pk=self.pk)
if qs.exists():
raise ValidationError({
'username': ValidationError('A user with that username already exists.', code='unique'),
})
def __str__(self):
return "{} {}".format(self.first_name, self.last_name).strip() or "@{}".format(self.username)
def is_verified(self):
"""Whether this user is verified as part of a Scala association."""
links = UserMembership.objects.filter(related_user=self)
for membership in links:
if membership.is_verified:
return True
return False
@cached_property
def boards(self):
"""Returns all associations of which this member has board access."""
return Association.objects.filter(user=self).all()
@cached_property
def requires_action(self):
"""Whether some action is required by the user."""
for board in self.boards:
if board.requires_action:
return True
return False
@cached_property
def requires_information_updates(self):
from general.views import SiteUpdateView
return SiteUpdateView.has_new_update(self)
@cached_property
def requires_information_rules(self):
from general.views import RulesPageView
return RulesPageView.has_new_update(self)
def has_any_perm(self):
"""Returns true if the user has one or more permissions."""
for group in self.groups.all():
if group.permissions.count() > 0:
return True
if self.user_permissions.count() > 0:
return True
return False
def has_admin_site_access(self):
return self.is_active and (self.has_any_perm() or self.is_superuser)
def is_board_of(self, association_id):
"""Returns if user is a board member of association identified by given id."""
return self.groups.filter(id=association_id).exists()
def is_verified_member_of(self, association):
"""Returns if the user is a verified member of the association."""
return self.get_verified_memberships().filter(association=association).exists()
def get_verified_memberships(self):
return self.usermembership_set.filter(is_verified=True)
def has_min_balance_exception(self):
"""Whether this user is allowed unlimited debt.
For this to hold, the association membership must be verified.
"""
exceptions = [membership.association.has_min_exception for membership in self.get_verified_memberships()]
return True in exceptions
class AssociationManager(GroupManager):
def get_by_natural_key(self, slug):
# See https://docs.djangoproject.com/en/4.1/topics/serialization/#natural-keys
return self.get(slug=slug)
class Association(Group):
slug = models.SlugField(max_length=10)
image = models.ImageField(blank=True, null=True)
icon_image = models.ImageField(blank=True, null=True)
is_choosable = models.BooleanField(default=True,
help_text="If checked, this association can be chosen as membership by users.")
has_min_exception = models.BooleanField(default=False,
help_text="If checked, this association has an exception to the minimum balance.")
social_app = models.ForeignKey(SocialApp, on_delete=models.PROTECT, null=True, blank=True,
help_text="A user automatically becomes member of the association "
"if they sign up using this social app.")
balance_update_instructions = models.TextField(max_length=512, default="to be defined")
has_site_stats_access = models.BooleanField(default=False)
objects = AssociationManager()
@cached_property
def requires_action(self):
"""Whether some action needs to be done by the board.
Used for display of notifications on the site.
"""
return self.has_new_member_requests()
def has_new_member_requests(self):
return UserMembership.objects.filter(association=self, verified_on__isnull=True).exists()
class UserMembership(models.Model):
"""Stores membership information."""
related_user = models.ForeignKey(User, on_delete=models.CASCADE)
association = models.ForeignKey(Association, on_delete=models.CASCADE)
is_verified = models.BooleanField(default=False)
verified_on = models.DateTimeField(blank=True, null=True, default=None)
created_on = models.DateTimeField(default=timezone.now)
def get_verified_state(self):
"""Returns the verified state as True/False/None.
Returns:
True=verified, False=rejected, None=pending.
"""
if self.is_verified:
return True
if self.verified_on is not None:
return False
return None
def is_member(self):
if not self.is_verified and self.verified_on:
# It is not verified, but has verification date, so is rejected
return False
return True
def __str__(self):
return "{user} - {association}".format(user=self.related_user, association=self.association)
def set_verified(self, verified):
"""Sets the verified state to the value of verified (True or False) and set verified_on to now and save."""
self.is_verified = verified
self.verified_on = timezone.now()
self.save()
def set_pending(self):
"""Sets the state to pending.
This method does not save the model for you.
"""
self.is_verified = False
self.verified_on = None
def is_frozen(self):
"""A membership is frozen, i.e. can't be changed, if it was verified or rejected too recently."""
if not self.verified_on:
return False
age = timezone.now() - self.verified_on
if self.is_verified:
return age < settings.DURATION_AFTER_MEMBERSHIP_CONFIRMATION
else:
return age < settings.DURATION_AFTER_MEMBERSHIP_REJECTION
def is_rejected(self):
return self.get_verified_state() is False
def is_pending(self):
return self.get_verified_state() is None
```
I was experimenting with isort, and this is my config:
ERROR: Unrecoverable exception thrown when parsing ./userdetails/models.py! This should NEVER happen.
If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new
Traceback (most recent call last):
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/bin/isort", line 8, in <module>
sys.exit(main())
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/main.py", line 1226, in main
for sort_attempt in attempt_iterator:
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/main.py", line 1210, in <genexpr>
sort_imports( # type: ignore
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/main.py", line 93, in sort_imports
incorrectly_sorted = not api.sort_file(
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/api.py", line 429, in sort_file
changed = sort_stream(
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/api.py", line 210, in sort_stream
changed = core.process(
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/core.py", line 422, in process
parsed_content = parse.file_contents(import_section, config=config)
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/parse.py", line 522, in file_contents
if "," in import_string.split(just_imports[-1])[-1]:
IndexError: list index out of range
I am following the instructions by opening a issue.
Full log
~/Documents/Knights/Scala-Dining-WebApp isort-bug
.venv ❯ isort
_ _
(_) ___ ___ _ __| |_
| |/ _/ / _ \/ '__ _/
| |\__ \/\_\/| | | |_
|_|\___/\___/\_/ \_/
isort your imports, so you don't have to.
VERSION 5.12.0
Nothing to do: no files or paths have have been passed in!
Try one of the following:
`isort .` - sort all Python files, starting from the current directory, recursively.
`isort . --interactive` - Do the same, but ask before making any changes.
`isort . --check --diff` - Check to see if imports are correctly sorted within this project.
`isort --help` - In-depth information about isort's available command-line options.
Visit https://pycqa.github.io/isort/ for complete information about how to use isort.
~/Documents/Knights/Scala-Dining-WebApp isort-bug
.venv ❯ isort .
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/manage.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/allauthproviders/quadrivium/provider.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/allauthproviders/quadrivium/urls.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/allauthproviders/quadrivium/views.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/receivers.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/models.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/forms.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/admin.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/csv.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/urls.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/views.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/templatetags/credit_tags.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0012_auto_20200824_0135.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0004_auto_20190203_2324.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0011_account_transaction.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0010_auto_20200817_1230.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0015_auto_20220428_2113.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0008_pendingdiningtransaction.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0006_auto_20190213_1452.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0013_auto_20210319_2310.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0002_auto_20190203_1923.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0001_initial.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0017_remove_cancel_column.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/tests/test_models.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/models.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/externalaccounts.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/views_association.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/views_user_settings.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/forms.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/forms_allauth.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/admin.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/urls.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/views.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0009_user_is_staff.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0005_auto_20190207_1510.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0012_auto_20190429_1306.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0020_auto_20210319_2310.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0007_association_is_choosable.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0002_auto_20190203_2324.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0006_auto_20190207_1744.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0010_auto_20190304_2050.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0011_auto_20190429_1303.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0015_auto_20190508_1905.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0017_association_balance_update_instructions.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0019_auto_20200823_1602.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0001_initial.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0004_user_external_link.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0018_association_has_site_stats_access.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0021_auto_20221224_1346.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0016_association_social_app.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0013_auto_20190429_2232.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/tests/test_models.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/tests/test_externalaccounts.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/forms.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/urls.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/mail_control.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/views.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/migrations/0001_initial.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/migrations/0002_auto_20190227_1203.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/scaladining/scala_settings.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/scaladining/settings.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/scaladining/urls.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/scaladining/wsgi.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/utils/testing/patch_utils.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/utils/testing/__init__.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/models.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/forms.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/admin.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/urls.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/datesequence.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/views.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/templatetags/dining_tags.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0021_create_paymentreminderlock.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0018_auto_20210319_2310.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0015_auto_20190513_2104.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0027_deletedlist_and_more.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0016_auto_20190514_1317.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0017_auto_20200824_0138.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0026_diningcomment_increase_length.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0002_auto_20190203_2149.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0013_auto_20190513_1505.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0007_auto_20190423_1651.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0003_auto_20190203_2324.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0008_auto_20190507_0112.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0005_auto_20190221_2339.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0009_auto_20190508_0230.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0012_auto_20190728_1359.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0028_alter_dininglist_payment_link.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0011_auto_20190508_1905.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0023_add_new_help_stats.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0001_initial.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_forms.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_forms_diningentry.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_datesequence.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_forms_sendreminderform.py
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_models.py
Skipped 2 files
~/Documents/Knights/Scala-Dining-WebApp isort-bug*
.venv ❯ isort .
Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/models.py
Skipped 2 files
~/Documents/Knights/Scala-Dining-WebApp isort-bug*
.venv ❯ isort .
ERROR: Unrecoverable exception thrown when parsing ./userdetails/models.py! This should NEVER happen.
If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new
Traceback (most recent call last):
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/bin/isort", line 8, in
sys.exit(main())
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/main.py", line 1226, in main
for sort_attempt in attempt_iterator:
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/main.py", line 1210, in
sort_imports( # type: ignore
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/main.py", line 93, in sort_imports
incorrectly_sorted = not api.sort_file(
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/api.py", line 429, in sort_file
changed = sort_stream(
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/api.py", line 210, in sort_stream
changed = core.process(
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/core.py", line 422, in process
parsed_content = parse.file_contents(import_section, config=config)
File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/lib/python3.10/site-packages/isort/parse.py", line 522, in file_contents
if "," in import_string.split(just_imports[-1])[-1]:
IndexError: list index out of range
~/Documents/Knights/Scala-Dining-WebApp isort-bug*
.venv ❯
./userdetails/models.py
```python from allauth.socialaccount.models import SocialApp from django.conf import settings from django.contrib.auth.models import AbstractUser, Group from django.contrib.auth.models import UserManager as DjangoUserManager, GroupManager from django.core.exceptions import ValidationError from django.db import models from django.utils import timezone from django.utils.functional import cached_property class UserManager(DjangoUserManager): def get_by_natural_key(self, username): # See https://docs.djangoproject.com/en/4.1/topics/serialization/#natural-keys # Allow the use of id to lookup as well if isinstance(username, int): return self.get(id=username) return self.get(username=username) class User(AbstractUser): email = models.EmailField("email address", unique=True) allergies = models.CharField( max_length=100, blank=True, help_text="E.g. gluten or vegetarian. Leave empty if not applicable.", verbose_name="food allergies or preferences" ) objects = UserManager() def clean(self): # By default, Django uses case-sensitive usernames. This means that # users 'asdf' and 'Asdf' are considered different users. The allauth # library handles it differently and considers them the same users. # This doesn't play well together. # # We fix it using a case-insensitive uniqueness check on the username, # in the model validation below. In the future, we could consider # normalizing usernames to lowercase, or removing the allauth library # for something more lightweight (custom code). qs = self.__class__.objects.filter(username__iexact=self.username) # Exclude own entry if self.pk: qs = qs.exclude(pk=self.pk) if qs.exists(): raise ValidationError({ 'username': ValidationError('A user with that username already exists.', code='unique'), }) def __str__(self): return "{} {}".format(self.first_name, self.last_name).strip() or "@{}".format(self.username) def is_verified(self): """Whether this user is verified as part of a Scala association.""" links = UserMembership.objects.filter(related_user=self) for membership in links: if membership.is_verified: return True return False @cached_property def boards(self): """Returns all associations of which this member has board access.""" return Association.objects.filter(user=self).all() @cached_property def requires_action(self): """Whether some action is required by the user.""" for board in self.boards: if board.requires_action: return True return False @cached_property def requires_information_updates(self): from general.views import SiteUpdateView return SiteUpdateView.has_new_update(self) @cached_property def requires_information_rules(self): from general.views import RulesPageView return RulesPageView.has_new_update(self) def has_any_perm(self): """Returns true if the user has one or more permissions.""" for group in self.groups.all(): if group.permissions.count() > 0: return True if self.user_permissions.count() > 0: return True return False def has_admin_site_access(self): return self.is_active and (self.has_any_perm() or self.is_superuser) def is_board_of(self, association_id): """Returns if user is a board member of association identified by given id.""" return self.groups.filter(id=association_id).exists() def is_verified_member_of(self, association): """Returns if the user is a verified member of the association.""" return self.get_verified_memberships().filter(association=association).exists() def get_verified_memberships(self): return self.usermembership_set.filter(is_verified=True) def has_min_balance_exception(self): """Whether this user is allowed unlimited debt. For this to hold, the association membership must be verified. """ exceptions = [membership.association.has_min_exception for membership in self.get_verified_memberships()] return True in exceptions class AssociationManager(GroupManager): def get_by_natural_key(self, slug): # See https://docs.djangoproject.com/en/4.1/topics/serialization/#natural-keys return self.get(slug=slug) class Association(Group): slug = models.SlugField(max_length=10) image = models.ImageField(blank=True, null=True) icon_image = models.ImageField(blank=True, null=True) is_choosable = models.BooleanField(default=True, help_text="If checked, this association can be chosen as membership by users.") has_min_exception = models.BooleanField(default=False, help_text="If checked, this association has an exception to the minimum balance.") social_app = models.ForeignKey(SocialApp, on_delete=models.PROTECT, null=True, blank=True, help_text="A user automatically becomes member of the association " "if they sign up using this social app.") balance_update_instructions = models.TextField(max_length=512, default="to be defined") has_site_stats_access = models.BooleanField(default=False) objects = AssociationManager() @cached_property def requires_action(self): """Whether some action needs to be done by the board. Used for display of notifications on the site. """ return self.has_new_member_requests() def has_new_member_requests(self): return UserMembership.objects.filter(association=self, verified_on__isnull=True).exists() class UserMembership(models.Model): """Stores membership information.""" related_user = models.ForeignKey(User, on_delete=models.CASCADE) association = models.ForeignKey(Association, on_delete=models.CASCADE) is_verified = models.BooleanField(default=False) verified_on = models.DateTimeField(blank=True, null=True, default=None) created_on = models.DateTimeField(default=timezone.now) def get_verified_state(self): """Returns the verified state as True/False/None. Returns: True=verified, False=rejected, None=pending. """ if self.is_verified: return True if self.verified_on is not None: return False return None def is_member(self): if not self.is_verified and self.verified_on: # It is not verified, but has verification date, so is rejected return False return True def __str__(self): return "{user} - {association}".format(user=self.related_user, association=self.association) def set_verified(self, verified): """Sets the verified state to the value of verified (True or False) and set verified_on to now and save.""" self.is_verified = verified self.verified_on = timezone.now() self.save() def set_pending(self): """Sets the state to pending. This method does not save the model for you. """ self.is_verified = False self.verified_on = None def is_frozen(self): """A membership is frozen, i.e. can't be changed, if it was verified or rejected too recently.""" if not self.verified_on: return False age = timezone.now() - self.verified_on if self.is_verified: return age < settings.DURATION_AFTER_MEMBERSHIP_CONFIRMATION else: return age < settings.DURATION_AFTER_MEMBERSHIP_REJECTION def is_rejected(self): return self.get_verified_state() is False def is_pending(self): return self.get_verified_state() is None ```I was experimenting with isort, and this is my config:
When I run it multiple times I get this error:
I am following the instructions by opening a issue.
Full log
~/Documents/Knights/Scala-Dining-WebApp isort-bug .venv ❯ isort _ _ (_) ___ ___ _ __| |_ | |/ _/ / _ \/ '__ _/ | |\__ \/\_\/| | | |_ |_|\___/\___/\_/ \_/ isort your imports, so you don't have to. VERSION 5.12.0 Nothing to do: no files or paths have have been passed in! Try one of the following: `isort .` - sort all Python files, starting from the current directory, recursively. `isort . --interactive` - Do the same, but ask before making any changes. `isort . --check --diff` - Check to see if imports are correctly sorted within this project. `isort --help` - In-depth information about isort's available command-line options. Visit https://pycqa.github.io/isort/ for complete information about how to use isort. ~/Documents/Knights/Scala-Dining-WebApp isort-bug .venv ❯ isort . Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/manage.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/allauthproviders/quadrivium/provider.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/allauthproviders/quadrivium/urls.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/allauthproviders/quadrivium/views.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/receivers.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/models.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/forms.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/admin.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/csv.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/urls.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/views.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/templatetags/credit_tags.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0012_auto_20200824_0135.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0004_auto_20190203_2324.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0011_account_transaction.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0010_auto_20200817_1230.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0015_auto_20220428_2113.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0008_pendingdiningtransaction.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0006_auto_20190213_1452.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0013_auto_20210319_2310.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0002_auto_20190203_1923.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0001_initial.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/migrations/0017_remove_cancel_column.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/creditmanagement/tests/test_models.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/models.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/externalaccounts.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/views_association.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/views_user_settings.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/forms.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/forms_allauth.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/admin.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/urls.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/views.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0009_user_is_staff.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0005_auto_20190207_1510.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0012_auto_20190429_1306.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0020_auto_20210319_2310.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0007_association_is_choosable.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0002_auto_20190203_2324.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0006_auto_20190207_1744.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0010_auto_20190304_2050.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0011_auto_20190429_1303.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0015_auto_20190508_1905.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0017_association_balance_update_instructions.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0019_auto_20200823_1602.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0001_initial.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0004_user_external_link.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0018_association_has_site_stats_access.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0021_auto_20221224_1346.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0016_association_social_app.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/migrations/0013_auto_20190429_2232.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/tests/test_models.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/tests/test_externalaccounts.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/forms.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/urls.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/mail_control.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/views.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/migrations/0001_initial.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/general/migrations/0002_auto_20190227_1203.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/scaladining/scala_settings.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/scaladining/settings.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/scaladining/urls.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/scaladining/wsgi.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/utils/testing/patch_utils.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/utils/testing/__init__.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/models.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/forms.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/admin.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/urls.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/datesequence.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/views.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/templatetags/dining_tags.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0021_create_paymentreminderlock.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0018_auto_20210319_2310.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0015_auto_20190513_2104.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0027_deletedlist_and_more.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0016_auto_20190514_1317.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0017_auto_20200824_0138.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0026_diningcomment_increase_length.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0002_auto_20190203_2149.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0013_auto_20190513_1505.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0007_auto_20190423_1651.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0003_auto_20190203_2324.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0008_auto_20190507_0112.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0005_auto_20190221_2339.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0009_auto_20190508_0230.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0012_auto_20190728_1359.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0028_alter_dininglist_payment_link.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0011_auto_20190508_1905.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0023_add_new_help_stats.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/migrations/0001_initial.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_forms.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_forms_diningentry.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_datesequence.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_forms_sendreminderform.py Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/dining/tests/test_models.py Skipped 2 files ~/Documents/Knights/Scala-Dining-WebApp isort-bug* .venv ❯ isort . Fixing /Users/lena/Documents/Knights/Scala-Dining-WebApp/userdetails/models.py Skipped 2 files ~/Documents/Knights/Scala-Dining-WebApp isort-bug* .venv ❯ isort . ERROR: Unrecoverable exception thrown when parsing ./userdetails/models.py! This should NEVER happen. If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new Traceback (most recent call last): File "/Users/lena/Documents/Knights/Scala-Dining-WebApp/.venv/bin/isort", line 8, in