diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 99c92478d..570174248 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,10 +1,5 @@ - -## Are you finished? - -### Linters +## Description -- [ ] I have checked my code with `black`, `pylint`, and `mypy`, or `./bw-dev formatters` -### Tests - + + +- Related Issue # +- Closes # ## What type of Pull Request is this? @@ -48,21 +42,6 @@ If you miss this step it is likely that the GitHub task runners will fail. ### Details of breaking or configuration changes (if any of above checked) -## Description - - - -- Related Issue # -- Closes # ## Documentation + +### Tests + + +- [ ] My changes do not need new tests +- [ ] All tests I have added are passing +- [ ] I have written tests but need help to make them pass +- [ ] I have not written tests and need help to write them diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 01241b467..68e3b7b65 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -48,7 +48,7 @@ jobs: - name: Set up .env run: cp .env.example .env - name: Check migrations up-to-date - run: python ./manage.py makemigrations --check + run: python ./manage.py makemigrations --check -v 3 - name: Run Tests run: pytest -n 3 diff --git a/.pylintrc b/.pylintrc index 464638853..e89f7d536 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,7 +3,19 @@ ignore=migrations load-plugins=pylint.extensions.no_self_use [MESSAGES CONTROL] -disable=E1101,E1135,E1136,R0903,R0901,R0902,W0707,W0511,W0406,R0401,R0801,C3001,import-error +disable = + cyclic-import, + duplicate-code, + fixme, + no-member, + raise-missing-from, + too-few-public-methods, + too-many-ancestors, + too-many-instance-attributes, + unnecessary-lambda-assignment, + unsubscriptable-object, +enable = + useless-suppression [FORMAT] max-line-length=88 diff --git a/bookwyrm/activitypub/book.py b/bookwyrm/activitypub/book.py index a53222053..9a268f905 100644 --- a/bookwyrm/activitypub/book.py +++ b/bookwyrm/activitypub/book.py @@ -67,7 +67,6 @@ class Edition(Book): type: str = "Edition" -# pylint: disable=invalid-name @dataclass(init=False) class Work(Book): """work instance of a book object""" diff --git a/bookwyrm/activitypub/ordered_collection.py b/bookwyrm/activitypub/ordered_collection.py index 32e37c996..250490041 100644 --- a/bookwyrm/activitypub/ordered_collection.py +++ b/bookwyrm/activitypub/ordered_collection.py @@ -18,7 +18,6 @@ class OrderedCollection(ActivityObject): type: str = "OrderedCollection" -# pylint: disable=invalid-name @dataclass(init=False) class OrderedCollectionPrivate(OrderedCollection): """an ordered collection with privacy settings""" diff --git a/bookwyrm/activitypub/verbs.py b/bookwyrm/activitypub/verbs.py index a365f4cc0..549f14c9c 100644 --- a/bookwyrm/activitypub/verbs.py +++ b/bookwyrm/activitypub/verbs.py @@ -22,7 +22,6 @@ class Verb(ActivityObject): self.object.to_model(allow_external_connections=allow_external_connections) -# pylint: disable=invalid-name @dataclass(init=False) class Create(Verb): """Create activity""" @@ -33,7 +32,6 @@ class Create(Verb): type: str = "Create" -# pylint: disable=invalid-name @dataclass(init=False) class Delete(Verb): """Create activity""" @@ -63,7 +61,6 @@ class Delete(Verb): # if we can't find it, we don't need to delete it because we don't have it -# pylint: disable=invalid-name @dataclass(init=False) class Update(Verb): """Update activity""" @@ -227,7 +224,6 @@ class Like(Verb): self.to_model(allow_external_connections=allow_external_connections) -# pylint: disable=invalid-name @dataclass(init=False) class Announce(Verb): """boosting a status""" diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index 0009ac7a3..08fb757d5 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -32,7 +32,7 @@ class ActivityStream(RedisStore): stream_id = self.stream_id(user_id) return f"{stream_id}-unread-by-type" - def get_rank(self, obj): # pylint: disable=no-self-use + def get_rank(self, obj): """statuses are sorted by date published""" return obj.published_date.timestamp() diff --git a/bookwyrm/apps.py b/bookwyrm/apps.py index 41b1a17a2..d5384bb7b 100644 --- a/bookwyrm/apps.py +++ b/bookwyrm/apps.py @@ -33,7 +33,6 @@ class BookwyrmConfig(AppConfig): name = "bookwyrm" verbose_name = "BookWyrm" - # pylint: disable=no-self-use def ready(self): """set up OTLP and preview image files, if desired""" if settings.OTEL_EXPORTER_OTLP_ENDPOINT or settings.OTEL_EXPORTER_CONSOLE: diff --git a/bookwyrm/book_search.py b/bookwyrm/book_search.py index cf48f4832..c11cdb8f1 100644 --- a/bookwyrm/book_search.py +++ b/bookwyrm/book_search.py @@ -36,7 +36,6 @@ def search( ... -# pylint: disable=arguments-differ def search( query: str, *, diff --git a/bookwyrm/context_processors.py b/bookwyrm/context_processors.py index 0047bfce1..bec704a2c 100644 --- a/bookwyrm/context_processors.py +++ b/bookwyrm/context_processors.py @@ -2,7 +2,7 @@ from bookwyrm import models, settings -def site_settings(request): # pylint: disable=unused-argument +def site_settings(request): """include the custom info about the site""" request_protocol = "https://" if not request.is_secure(): diff --git a/bookwyrm/forms/custom_form.py b/bookwyrm/forms/custom_form.py index c604deea4..6b425d216 100644 --- a/bookwyrm/forms/custom_form.py +++ b/bookwyrm/forms/custom_form.py @@ -15,9 +15,9 @@ class StyledForm(ModelForm): css_classes["number"] = "input" css_classes["checkbox"] = "checkbox" css_classes["textarea"] = "textarea" - # pylint: disable=super-with-arguments super().__init__(*args, **kwargs) for visible in self.visible_fields(): + input_type = "" if hasattr(visible.field.widget, "input_type"): input_type = visible.field.widget.input_type if isinstance(visible.field.widget, Textarea): diff --git a/bookwyrm/forms/landing.py b/bookwyrm/forms/landing.py index 1da4fc4f1..831d1d539 100644 --- a/bookwyrm/forms/landing.py +++ b/bookwyrm/forms/landing.py @@ -34,7 +34,6 @@ class LoginForm(CustomForm): def add_invalid_password_error(self): """We don't want to be too specific about this""" - # pylint: disable=attribute-defined-outside-init self.non_field_errors = _("Username or password are incorrect") diff --git a/bookwyrm/forms/widgets.py b/bookwyrm/forms/widgets.py index ee9345aa0..001fdbec4 100644 --- a/bookwyrm/forms/widgets.py +++ b/bookwyrm/forms/widgets.py @@ -5,8 +5,6 @@ from django import forms class ArrayWidget(forms.widgets.TextInput): """Inputs for postgres array fields""" - # pylint: disable=unused-argument - # pylint: disable=no-self-use def value_from_datadict(self, data, files, name): """get all values for this name""" return [i for i in data.getlist(name) if i] diff --git a/bookwyrm/importers/importer.py b/bookwyrm/importers/importer.py index fc8d4ac13..3e01c6abc 100644 --- a/bookwyrm/importers/importer.py +++ b/bookwyrm/importers/importer.py @@ -45,7 +45,6 @@ class Importer: "reading": ["currently-reading", "reading", "currently reading"], } - # pylint: disable=too-many-locals.too-many-arguments def create_job( self, user: User, diff --git a/bookwyrm/importers/librarything_import.py b/bookwyrm/importers/librarything_import.py index 145657ba0..24a2626bf 100644 --- a/bookwyrm/importers/librarything_import.py +++ b/bookwyrm/importers/librarything_import.py @@ -20,7 +20,7 @@ class LibrarythingImporter(Importer): def normalize_row( self, entry: dict[str, str], mappings: dict[str, Optional[str]] - ) -> dict[str, Optional[str]]: # pylint: disable=no-self-use + ) -> dict[str, Optional[str]]: """use the dataclass to create the formatted row of data""" normalized = { k: _remove_brackets(entry.get(v) if v else None) diff --git a/bookwyrm/lists_stream.py b/bookwyrm/lists_stream.py index 148b81a78..479eacb19 100644 --- a/bookwyrm/lists_stream.py +++ b/bookwyrm/lists_stream.py @@ -18,7 +18,7 @@ class ListsStream(RedisStore): return f"{user}-lists" return f"{user.id}-lists" - def get_rank(self, obj): # pylint: disable=no-self-use + def get_rank(self, obj): """lists are sorted by updated date""" return obj.updated_date.timestamp() diff --git a/bookwyrm/migrations/0207_sqlparse_update.py b/bookwyrm/migrations/0207_sqlparse_update.py new file mode 100644 index 000000000..95c46eba2 --- /dev/null +++ b/bookwyrm/migrations/0207_sqlparse_update.py @@ -0,0 +1,51 @@ +# Generated by Django 4.2.11 on 2024-07-27 18:18 + +from django.db import migrations, models +import pgtrigger.compiler +import pgtrigger.migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0206_merge_20240415_1537"), + ] + + operations = [ + pgtrigger.migrations.RemoveTrigger( + model_name="author", + name="reset_book_search_vector_on_author_edit", + ), + pgtrigger.migrations.RemoveTrigger( + model_name="book", + name="update_search_vector_on_book_edit", + ), + pgtrigger.migrations.AddTrigger( + model_name="author", + trigger=pgtrigger.compiler.Trigger( + name="reset_book_search_vector_on_author_edit", + sql=pgtrigger.compiler.UpsertTriggerSql( + func="WITH updated_books AS (SELECT book_id FROM bookwyrm_book_authors WHERE author_id = new.id) UPDATE bookwyrm_book SET search_vector = '' FROM updated_books WHERE id = updated_books.book_id;RETURN NEW;", + hash="4eeb17d1c9c53f543615bcae1234bd0260adefcc", + operation='UPDATE OF "name", "aliases"', + pgid="pgtrigger_reset_book_search_vector_on_author_edit_a50c7", + table="bookwyrm_author", + when="AFTER", + ), + ), + ), + pgtrigger.migrations.AddTrigger( + model_name="book", + trigger=pgtrigger.compiler.Trigger( + name="update_search_vector_on_book_edit", + sql=pgtrigger.compiler.UpsertTriggerSql( + func="WITH author_names AS (SELECT array_to_string(bookwyrm_author.name || bookwyrm_author.aliases, ' ') AS name_and_aliases FROM bookwyrm_author LEFT JOIN bookwyrm_book_authors ON bookwyrm_author.id = bookwyrm_book_authors.author_id WHERE bookwyrm_book_authors.book_id = new.id) SELECT setweight(coalesce(nullif(to_tsvector('english', new.title), ''), to_tsvector('simple', new.title)), 'A') || setweight(to_tsvector('english', coalesce(new.subtitle, '')), 'B') || (SELECT setweight(to_tsvector('simple', coalesce(array_to_string(array_agg(name_and_aliases), ' '), '')), 'C') FROM author_names) || setweight(to_tsvector('english', coalesce(new.series, '')), 'D') INTO new.search_vector;RETURN NEW;", + hash="676d929ce95beff671544b6add09cf9360b6f299", + operation='INSERT OR UPDATE OF "title", "subtitle", "series", "search_vector"', + pgid="pgtrigger_update_search_vector_on_book_edit_bec58", + table="bookwyrm_book", + when="BEFORE", + ), + ), + ), + ] diff --git a/bookwyrm/models/activitypub_mixin.py b/bookwyrm/models/activitypub_mixin.py index 06ef373e6..54ad11511 100644 --- a/bookwyrm/models/activitypub_mixin.py +++ b/bookwyrm/models/activitypub_mixin.py @@ -31,7 +31,7 @@ logger = logging.getLogger(__name__) PropertyField = namedtuple("PropertyField", ("set_activity_from_field")) -# pylint: disable=invalid-name + def set_activity_from_property_field(activity, obj, field): """assign a model property value to the activity json""" activity[field[1]] = getattr(obj, field[0]) diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 4ff377dbb..368276523 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -133,7 +133,6 @@ class BookDataModel(ObjectMixin, BookWyrmModel): related_models = [ (r.remote_field.name, r.related_model) for r in self._meta.related_objects ] - # pylint: disable=protected-access for related_field, related_model in related_models: # Skip the ManyToMany fields that aren’t auto-created. These # should have a corresponding OneToMany field in the model for diff --git a/bookwyrm/models/bookwyrm_export_job.py b/bookwyrm/models/bookwyrm_export_job.py index 870910c00..a42562f30 100644 --- a/bookwyrm/models/bookwyrm_export_job.py +++ b/bookwyrm/models/bookwyrm_export_job.py @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) class BookwyrmAwsSession(BotoSession): """a boto session that always uses settings.AWS_S3_ENDPOINT_URL""" - def client(self, *args, **kwargs): # pylint: disable=arguments-differ + def client(self, *args, **kwargs): kwargs["endpoint_url"] = settings.AWS_S3_ENDPOINT_URL return super().client("s3", *args, **kwargs) diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 6643bdc19..75d3acf76 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -193,8 +193,7 @@ class UsernameField(ActivitypubFieldMixin, models.CharField): def __init__(self, activitypub_field="preferredUsername", **kwargs): self.activitypub_field = activitypub_field - # I don't totally know why pylint is mad at this, but it makes it work - super(ActivitypubFieldMixin, self).__init__( # pylint: disable=bad-super-call + super(ActivitypubFieldMixin, self).__init__( _("username"), max_length=150, unique=True, @@ -234,7 +233,6 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): def __init__(self, *args, **kwargs): super().__init__(*args, max_length=255, choices=PrivacyLevels, default="public") - # pylint: disable=invalid-name def set_field_from_activity( self, instance, data, overwrite=True, allow_external_connections=True ): @@ -276,7 +274,6 @@ class PrivacyField(ActivitypubFieldMixin, models.CharField): if hasattr(instance, "mention_users"): mentions = [u.remote_id for u in instance.mention_users.all()] # this is a link to the followers list - # pylint: disable=protected-access followers = instance.user.followers_url if instance.privacy == "public": activity["to"] = [self.public] @@ -444,7 +441,7 @@ class ImageField(ActivitypubFieldMixin, models.ImageField): self.alt_field = alt_field super().__init__(*args, **kwargs) - # pylint: disable=arguments-differ,arguments-renamed,too-many-arguments + # pylint: disable=arguments-renamed,too-many-arguments def set_field_from_activity( self, instance, data, save=True, overwrite=True, allow_external_connections=True ): diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index 8ca4c346d..351d722f7 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -359,7 +359,7 @@ def import_item_task(item_id): try: item.resolve() - except Exception as err: # pylint: disable=broad-except + except Exception as err: item.fail_reason = _("Error loading book") item.save() item.update_job() diff --git a/bookwyrm/models/relationship.py b/bookwyrm/models/relationship.py index 745ff78b6..ed630fbe5 100644 --- a/bookwyrm/models/relationship.py +++ b/bookwyrm/models/relationship.py @@ -135,7 +135,7 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship): status = "follow_request" activity_serializer = activitypub.Follow - def save(self, *args, broadcast=True, **kwargs): # pylint: disable=arguments-differ + def save(self, *args, broadcast=True, **kwargs): """make sure the follow or block relationship doesn't already exist""" # if there's a request for a follow that already exists, accept it # without changing the local database state diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 9dc60e647..2b357ebd2 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -98,7 +98,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): self.thread_id = self.id super().save(broadcast=False, update_fields=["thread_id"]) - def delete(self, *args, **kwargs): # pylint: disable=unused-argument + def delete(self, *args, **kwargs): """ "delete" a status""" if hasattr(self, "boosted_status"): # okay but if it's a boost really delete it @@ -213,7 +213,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): **kwargs, ).serialize() - def to_activity_dataclass(self, pure=False): # pylint: disable=arguments-differ + def to_activity_dataclass(self, pure=False): """return tombstone if the status is deleted""" if self.deleted: return activitypub.Tombstone( diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index ed5c59e9c..80f1c2d9a 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -409,7 +409,6 @@ class User(OrderedCollectionPageMixin, AbstractUser): def delete(self, *args, **kwargs): """We don't actually delete the database entry""" - # pylint: disable=attribute-defined-outside-init self.is_active = False self.allow_reactivation = False self.is_deleted = True @@ -452,7 +451,6 @@ class User(OrderedCollectionPageMixin, AbstractUser): def deactivate(self): """Disable the user but allow them to reactivate""" - # pylint: disable=attribute-defined-outside-init self.is_active = False self.deactivation_reason = "self_deactivation" self.allow_reactivation = True @@ -460,7 +458,6 @@ class User(OrderedCollectionPageMixin, AbstractUser): def reactivate(self): """Now you want to come back, huh?""" - # pylint: disable=attribute-defined-outside-init if not self.allow_reactivation: return self.is_active = True diff --git a/bookwyrm/preview_images.py b/bookwyrm/preview_images.py index a213490ab..66d2e2d4b 100644 --- a/bookwyrm/preview_images.py +++ b/bookwyrm/preview_images.py @@ -420,7 +420,6 @@ def save_and_cleanup(image, instance=None): return True -# pylint: disable=invalid-name @app.task(queue=IMAGES) def generate_site_preview_image_task(): """generate preview_image for the website""" @@ -445,7 +444,6 @@ def generate_site_preview_image_task(): save_and_cleanup(image, instance=site) -# pylint: disable=invalid-name @app.task(queue=IMAGES) def generate_edition_preview_image_task(book_id): """generate preview_image for a book""" diff --git a/bookwyrm/signatures.py b/bookwyrm/signatures.py index 08780b731..f59367b51 100644 --- a/bookwyrm/signatures.py +++ b/bookwyrm/signatures.py @@ -6,7 +6,7 @@ from base64 import b64encode, b64decode from Crypto import Random from Crypto.PublicKey import RSA -from Crypto.Signature import pkcs1_15 # pylint: disable=no-name-in-module +from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 MAX_SIGNATURE_AGE = 300 @@ -84,7 +84,6 @@ class Signature: self.headers = headers self.signature = signature - # pylint: disable=invalid-name @classmethod def parse(cls, request): """extract and parse a signature from an http request""" diff --git a/bookwyrm/suggested_users.py b/bookwyrm/suggested_users.py index a13ee97fd..3e1cf17bd 100644 --- a/bookwyrm/suggested_users.py +++ b/bookwyrm/suggested_users.py @@ -34,7 +34,6 @@ class SuggestedUsers(RedisStore): def get_counts_from_rank(self, rank): # pylint: disable=no-self-use """calculate mutuals count and shared books count from rank""" - # pylint: disable=c-extension-no-member return { "mutuals": math.floor(rank), # "shared_books": int(1 / (-1 * (rank % 1 - 1))) - 1, @@ -128,7 +127,6 @@ def get_annotated_users(viewer, *args, **kwargs): ), distinct=True, ), - # pylint: disable=line-too-long # shared_books=Count( # "shelfbook", # filter=Q( @@ -202,7 +200,7 @@ def update_suggestions_on_unfollow(sender, instance, **kwargs): @receiver(signals.post_save, sender=models.User) -# pylint: disable=unused-argument, too-many-arguments +# pylint: disable=unused-argument def update_user(sender, instance, created, update_fields=None, **kwargs): """an updated user, neat""" # a new user is found, create suggestions for them diff --git a/bookwyrm/templatetags/landing_page_tags.py b/bookwyrm/templatetags/landing_page_tags.py index ea2512cc7..bc7594fc4 100644 --- a/bookwyrm/templatetags/landing_page_tags.py +++ b/bookwyrm/templatetags/landing_page_tags.py @@ -71,14 +71,8 @@ def get_landing_books(): """list of books for the landing page""" return list( set( - models.Edition.objects.filter( - review__published_date__isnull=False, - review__deleted=False, - review__user__local=True, - review__privacy__in=["public", "unlisted"], - ) - .exclude(cover__exact="") + models.Edition.objects.exclude(cover__exact="") .distinct() - .order_by("-review__published_date")[:6] + .order_by("-updated_date")[:6] ) ) diff --git a/bookwyrm/tests/connectors/test_abstract_connector.py b/bookwyrm/tests/connectors/test_abstract_connector.py index 1a8421c12..d849f23d7 100644 --- a/bookwyrm/tests/connectors/test_abstract_connector.py +++ b/bookwyrm/tests/connectors/test_abstract_connector.py @@ -115,7 +115,6 @@ class AbstractConnector(TestCase): @responses.activate def test_get_or_create_author(self): """load an author""" - # pylint: disable=attribute-defined-outside-init self.connector.author_mappings = [ Mapping("id"), Mapping("name"), @@ -141,7 +140,6 @@ class AbstractConnector(TestCase): def test_update_author_from_remote(self): """trigger the function that looks up the remote data""" author = models.Author.objects.create(name="Test", openlibrary_key="OL123A") - # pylint: disable=attribute-defined-outside-init self.connector.author_mappings = [ Mapping("id"), Mapping("name"), diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index c7949cd28..d5967b1a3 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -20,7 +20,7 @@ from bookwyrm.models.activitypub_mixin import ( from bookwyrm.settings import PAGE_LENGTH -# pylint: disable=invalid-name,too-many-public-methods +# pylint: disable=too-many-public-methods @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class ActivitypubMixins(TestCase): diff --git a/bookwyrm/tests/models/test_base_model.py b/bookwyrm/tests/models/test_base_model.py index f16bdfa78..ddde41d04 100644 --- a/bookwyrm/tests/models/test_base_model.py +++ b/bookwyrm/tests/models/test_base_model.py @@ -42,7 +42,7 @@ class BaseModel(TestCase): def test_remote_id(self): """these should be generated""" - self.test_model.id = 1 # pylint: disable=invalid-name + self.test_model.id = 1 expected = self.test_model.get_remote_id() self.assertEqual(expected, f"{BASE_URL}/bookwyrmtestmodel/1") diff --git a/bookwyrm/tests/models/test_bookwyrm_import_job.py b/bookwyrm/tests/models/test_bookwyrm_import_job.py index 259d8f5a4..7d4bdb599 100644 --- a/bookwyrm/tests/models/test_bookwyrm_import_job.py +++ b/bookwyrm/tests/models/test_bookwyrm_import_job.py @@ -13,7 +13,7 @@ from bookwyrm.utils.tar import BookwyrmTarFile from bookwyrm.models import bookwyrm_import_job -class BookwyrmImport(TestCase): # pylint: disable=too-many-public-methods +class BookwyrmImport(TestCase): """testing user import functions""" def setUp(self): diff --git a/bookwyrm/tests/models/test_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index d510952ea..f17970c50 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -6,7 +6,6 @@ from django.test import TestCase from bookwyrm import models, settings -# pylint: disable=unused-argument @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") @patch("bookwyrm.lists_stream.populate_lists_task.delay") diff --git a/bookwyrm/tests/test_merge.py b/bookwyrm/tests/test_merge.py index 933751832..46f39384e 100644 --- a/bookwyrm/tests/test_merge.py +++ b/bookwyrm/tests/test_merge.py @@ -10,7 +10,7 @@ class MergeBookDataModel(TestCase): """test merging of subclasses of BookDataModel""" @classmethod - def setUpTestData(cls): # pylint: disable=invalid-name + def setUpTestData(cls): """shared data""" models.SiteSettings.objects.create() diff --git a/bookwyrm/tests/validate_html.py b/bookwyrm/tests/validate_html.py index 11bc84880..618d27f6c 100644 --- a/bookwyrm/tests/validate_html.py +++ b/bookwyrm/tests/validate_html.py @@ -42,7 +42,7 @@ def validate_html(html): validator.feed(str(html.content)) -class HtmlValidator(HTMLParser): # pylint: disable=abstract-method +class HtmlValidator(HTMLParser): """Checks for custom html validation requirements""" def __init__(self): diff --git a/bookwyrm/tests/views/imports/test_user_import.py b/bookwyrm/tests/views/imports/test_user_import.py index a8214e74e..3e097fb0f 100644 --- a/bookwyrm/tests/views/imports/test_user_import.py +++ b/bookwyrm/tests/views/imports/test_user_import.py @@ -14,7 +14,6 @@ from bookwyrm.tests.validate_html import validate_html class ImportUserViews(TestCase): """user import views""" - # pylint: disable=invalid-name def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory() diff --git a/bookwyrm/tests/views/inbox/test_inbox.py b/bookwyrm/tests/views/inbox/test_inbox.py index c29aa71a2..6deae38b7 100644 --- a/bookwyrm/tests/views/inbox/test_inbox.py +++ b/bookwyrm/tests/views/inbox/test_inbox.py @@ -11,7 +11,6 @@ from django.test.client import RequestFactory from bookwyrm import models, views -# pylint: disable=too-many-public-methods class Inbox(TestCase): """readthrough tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_add.py b/bookwyrm/tests/views/inbox/test_inbox_add.py index 0a11053e4..b3d50fe46 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_add.py +++ b/bookwyrm/tests/views/inbox/test_inbox_add.py @@ -7,7 +7,6 @@ import responses from bookwyrm import models, views -# pylint: disable=too-many-public-methods class InboxAdd(TestCase): """inbox tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index d499629a7..1bc508d11 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -7,7 +7,6 @@ import responses from bookwyrm import models, views -# pylint: disable=too-many-public-methods class InboxActivities(TestCase): """inbox tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index 19b0eb97f..923a87a76 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -6,7 +6,6 @@ from django.test import TestCase from bookwyrm import models, views -# pylint: disable=too-many-public-methods class InboxBlock(TestCase): """inbox tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index e8a3a8b12..0bb3907af 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -9,7 +9,6 @@ from bookwyrm import models, views from bookwyrm.activitypub import ActivitySerializerError -# pylint: disable=too-many-public-methods class TransactionInboxCreate(TransactionTestCase): """readthrough tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index a72898857..8d7582a21 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -7,7 +7,6 @@ from django.test import TestCase from bookwyrm import models, views -# pylint: disable=too-many-public-methods class InboxActivities(TestCase): """inbox tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_follow.py b/bookwyrm/tests/views/inbox/test_inbox_follow.py index aad52937b..ccc58c974 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_follow.py +++ b/bookwyrm/tests/views/inbox/test_inbox_follow.py @@ -7,7 +7,6 @@ from django.test import TestCase from bookwyrm import models, views -# pylint: disable=too-many-public-methods class InboxRelationships(TestCase): """inbox tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index 2ab8c4701..88dc24fbb 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -6,7 +6,6 @@ from django.test import TestCase from bookwyrm import models, views -# pylint: disable=too-many-public-methods class InboxActivities(TestCase): """inbox tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_remove.py b/bookwyrm/tests/views/inbox/test_inbox_remove.py index ab92eb995..89f66c9bb 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_remove.py +++ b/bookwyrm/tests/views/inbox/test_inbox_remove.py @@ -6,7 +6,6 @@ from django.test import TestCase from bookwyrm import models, views -# pylint: disable=too-many-public-methods class InboxRemove(TestCase): """inbox tests""" diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index 99f4c2077..a0f74a3fb 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -8,7 +8,6 @@ from django.test import TestCase from bookwyrm import models, views -# pylint: disable=too-many-public-methods class InboxUpdate(TestCase): """inbox tests""" @@ -161,7 +160,6 @@ class InboxUpdate(TestCase): datafile = pathlib.Path(__file__).parent.joinpath("../../data/bw_edition.json") bookdata = json.loads(datafile.read_bytes()) del bookdata["authors"] - # pylint: disable=line-too-long link_data = { "href": "https://openlibrary.org/books/OL11645413M/Queen_Victoria/daisy", "mediaType": "Daisy", diff --git a/bookwyrm/tests/views/landing/test_login.py b/bookwyrm/tests/views/landing/test_login.py index 7d4a06612..00e446855 100644 --- a/bookwyrm/tests/views/landing/test_login.py +++ b/bookwyrm/tests/views/landing/test_login.py @@ -11,7 +11,6 @@ from bookwyrm import forms, models, views from bookwyrm.tests.validate_html import validate_html -# pylint: disable=too-many-public-methods @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") class LoginViews(TestCase): diff --git a/bookwyrm/tests/views/lists/test_curate.py b/bookwyrm/tests/views/lists/test_curate.py index af6116efa..458d0b1e8 100644 --- a/bookwyrm/tests/views/lists/test_curate.py +++ b/bookwyrm/tests/views/lists/test_curate.py @@ -11,7 +11,6 @@ from bookwyrm import models, views from bookwyrm.tests.validate_html import validate_html -# pylint: disable=unused-argument class ListViews(TestCase): """list view""" diff --git a/bookwyrm/tests/views/lists/test_embed.py b/bookwyrm/tests/views/lists/test_embed.py index 2d2d5ec8c..69462a007 100644 --- a/bookwyrm/tests/views/lists/test_embed.py +++ b/bookwyrm/tests/views/lists/test_embed.py @@ -11,7 +11,6 @@ from bookwyrm import models, views from bookwyrm.tests.validate_html import validate_html -# pylint: disable=unused-argument class ListViews(TestCase): """list view""" diff --git a/bookwyrm/tests/views/lists/test_list.py b/bookwyrm/tests/views/lists/test_list.py index 6af9d1db1..38af920a1 100644 --- a/bookwyrm/tests/views/lists/test_list.py +++ b/bookwyrm/tests/views/lists/test_list.py @@ -13,7 +13,6 @@ from bookwyrm.activitypub import ActivitypubResponse from bookwyrm.tests.validate_html import validate_html -# pylint: disable=unused-argument # pylint: disable=too-many-public-methods class ListViews(TestCase): """list view""" diff --git a/bookwyrm/tests/views/lists/test_list_item.py b/bookwyrm/tests/views/lists/test_list_item.py index e70eabf1b..bb64329f0 100644 --- a/bookwyrm/tests/views/lists/test_list_item.py +++ b/bookwyrm/tests/views/lists/test_list_item.py @@ -7,8 +7,6 @@ from django.test.client import RequestFactory from bookwyrm import models, views -# pylint: disable=unused-argument -# pylint: disable=too-many-public-methods class ListItemViews(TestCase): """list view""" diff --git a/bookwyrm/tests/views/lists/test_lists.py b/bookwyrm/tests/views/lists/test_lists.py index 069fd7008..3f24f669d 100644 --- a/bookwyrm/tests/views/lists/test_lists.py +++ b/bookwyrm/tests/views/lists/test_lists.py @@ -11,7 +11,7 @@ from django.test.client import RequestFactory from bookwyrm import models, views from bookwyrm.tests.validate_html import validate_html -# pylint: disable=unused-argument + class ListViews(TestCase): """lists of lists""" diff --git a/bookwyrm/tests/views/preferences/test_export.py b/bookwyrm/tests/views/preferences/test_export.py index f125e9009..2b8fafc87 100644 --- a/bookwyrm/tests/views/preferences/test_export.py +++ b/bookwyrm/tests/views/preferences/test_export.py @@ -18,7 +18,7 @@ class ExportViews(TestCase): """viewing and creating statuses""" @classmethod - def setUpTestData(cls): # pylint: disable=invalid-name + def setUpTestData(cls): """we need basic test data and mocks""" with ( patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), @@ -41,7 +41,6 @@ class ExportViews(TestCase): bnf_id="beep", ) - # pylint: disable=invalid-name def setUp(self): """individual test setup""" self.factory = RequestFactory() diff --git a/bookwyrm/tests/views/preferences/test_two_factor_auth.py b/bookwyrm/tests/views/preferences/test_two_factor_auth.py index 3b16236ed..73f6d2f5e 100644 --- a/bookwyrm/tests/views/preferences/test_two_factor_auth.py +++ b/bookwyrm/tests/views/preferences/test_two_factor_auth.py @@ -11,7 +11,7 @@ from django.test.client import RequestFactory from bookwyrm import forms, models, views -# pylint: disable=too-many-public-methods + @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") class TwoFactorViews(TestCase): diff --git a/bookwyrm/tests/views/test_directory.py b/bookwyrm/tests/views/test_directory.py index a169551ac..3ea224154 100644 --- a/bookwyrm/tests/views/test_directory.py +++ b/bookwyrm/tests/views/test_directory.py @@ -9,7 +9,7 @@ from django.test.client import RequestFactory from bookwyrm import models, views from bookwyrm.tests.validate_html import validate_html -# pylint: disable=unused-argument + class DirectoryViews(TestCase): """tag views""" diff --git a/bookwyrm/tests/views/test_outbox.py b/bookwyrm/tests/views/test_outbox.py index bbd4aa37b..370f81800 100644 --- a/bookwyrm/tests/views/test_outbox.py +++ b/bookwyrm/tests/views/test_outbox.py @@ -10,7 +10,6 @@ from bookwyrm import models, views from bookwyrm.settings import USER_AGENT -# pylint: disable=too-many-public-methods @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class OutboxView(TestCase): """sends out activities""" diff --git a/bookwyrm/utils/partial_date.py b/bookwyrm/utils/partial_date.py index d20fc315e..03d1e6438 100644 --- a/bookwyrm/utils/partial_date.py +++ b/bookwyrm/utils/partial_date.py @@ -52,7 +52,6 @@ class PartialDate(datetime): Use subclasses to specify precision. If `dt` is naive, `ValueError` is raised. """ - # pylint: disable=invalid-name if timezone.is_naive(dt): raise ValueError("naive datetime not accepted") return cls.combine(dt.date(), dt.time(), tzinfo=dt.tzinfo) diff --git a/bookwyrm/views/admin/celery_status.py b/bookwyrm/views/admin/celery_status.py index dbf18dac8..5d5f07990 100644 --- a/bookwyrm/views/admin/celery_status.py +++ b/bookwyrm/views/admin/celery_status.py @@ -88,6 +88,7 @@ class CeleryStatus(View): def post(self, request): """Submit form to clear queues""" form = ClearCeleryForm(request.POST) + results = [] if form.is_valid(): if len(celery.control.ping()) != 0: return HttpResponse( diff --git a/bookwyrm/views/admin/dashboard.py b/bookwyrm/views/admin/dashboard.py index 21b19bf16..87af434c5 100644 --- a/bookwyrm/views/admin/dashboard.py +++ b/bookwyrm/views/admin/dashboard.py @@ -43,7 +43,6 @@ class Dashboard(View): ) or not re.match(regex.DOMAIN, settings.EMAIL_SENDER_DOMAIN) data["email_config_error"] = email_config_error - # pylint: disable=line-too-long data[ "email_sender" ] = f"{settings.EMAIL_SENDER_NAME}@{settings.EMAIL_SENDER_DOMAIN}" diff --git a/bookwyrm/views/admin/federation.py b/bookwyrm/views/admin/federation.py index e1cb80949..13666705a 100644 --- a/bookwyrm/views/admin/federation.py +++ b/bookwyrm/views/admin/federation.py @@ -152,7 +152,7 @@ class FederatedServer(View): } return TemplateResponse(request, "settings/federation/instance.html", data) - def post(self, request, server): # pylint: disable=unused-argument + def post(self, request, server): """update note""" server = get_object_or_404(models.FederatedServer, id=server) server.notes = request.POST.get("notes") diff --git a/bookwyrm/views/admin/imports.py b/bookwyrm/views/admin/imports.py index 1009f4149..ad704a2e8 100644 --- a/bookwyrm/views/admin/imports.py +++ b/bookwyrm/views/admin/imports.py @@ -63,7 +63,6 @@ class ImportList(View): } return TemplateResponse(request, "settings/imports/imports.html", data) - # pylint: disable=unused-argument def post(self, request, import_id): """Mark an import as complete""" import_job = get_object_or_404(models.ImportJob, id=import_id) @@ -95,7 +94,6 @@ def enable_imports(request): @require_POST @permission_required("bookwyrm.edit_instance_settings", raise_exception=True) -# pylint: disable=unused-argument def set_import_size_limit(request): """Limit the amount of books users can import at once""" site = models.SiteSettings.objects.get() @@ -120,7 +118,6 @@ def set_user_import_completed(request, import_id): @require_POST @permission_required("bookwyrm.edit_instance_settings", raise_exception=True) -# pylint: disable=unused-argument def set_user_import_limit(request): """Limit how ofter users can import and export their account""" site = models.SiteSettings.objects.get() diff --git a/bookwyrm/views/books/books.py b/bookwyrm/views/books/books.py index bbf041850..c67d18cf3 100644 --- a/bookwyrm/views/books/books.py +++ b/bookwyrm/views/books/books.py @@ -204,7 +204,6 @@ def resolve_book(request): @login_required @require_POST @permission_required("bookwyrm.edit_book", raise_exception=True) -# pylint: disable=unused-argument def update_book_from_remote(request, book_id, connector_identifier): """load the remote data for this book""" connector = connector_manager.load_connector( diff --git a/bookwyrm/views/books/edit_book.py b/bookwyrm/views/books/edit_book.py index b8ceece13..baf12a00b 100644 --- a/bookwyrm/views/books/edit_book.py +++ b/bookwyrm/views/books/edit_book.py @@ -88,7 +88,6 @@ class CreateBook(View): data = {"form": forms.EditionForm()} return TemplateResponse(request, "book/edit/edit_book.html", data) - # pylint: disable=too-many-locals def post(self, request): """create a new book""" # returns None if no match is found diff --git a/bookwyrm/views/helpers.py b/bookwyrm/views/helpers.py index 391788b0c..d89e195ca 100644 --- a/bookwyrm/views/helpers.py +++ b/bookwyrm/views/helpers.py @@ -240,7 +240,7 @@ def redirect_to_referer(request, *args, **kwargs): return redirect(*args or "/", **kwargs) -# pylint: disable=redefined-builtin,invalid-name +# pylint: disable=redefined-builtin def get_mergeable_object_or_404(klass, id): """variant of get_object_or_404 that also redirects if id has been merged into another object""" diff --git a/bookwyrm/views/landing/register.py b/bookwyrm/views/landing/register.py index 9d9aedb50..5debd03cd 100644 --- a/bookwyrm/views/landing/register.py +++ b/bookwyrm/views/landing/register.py @@ -97,7 +97,7 @@ class Register(View): class ConfirmEmailCode(View): """confirm email address""" - def get(self, request, code): # pylint: disable=unused-argument + def get(self, request, code): """you got the code! good work""" settings = models.SiteSettings.get() if request.user.is_authenticated: @@ -124,7 +124,7 @@ class ConfirmEmailCode(View): class ConfirmEmail(View): """enter code to confirm email address""" - def get(self, request): # pylint: disable=unused-argument + def get(self, request): """you need a code! keep looking""" settings = models.SiteSettings.get() if request.user.is_authenticated or not settings.require_confirm_email: diff --git a/bookwyrm/views/reading.py b/bookwyrm/views/reading.py index 478d27990..e39ad1067 100644 --- a/bookwyrm/views/reading.py +++ b/bookwyrm/views/reading.py @@ -22,7 +22,6 @@ logger = logging.getLogger(__name__) # pylint: disable=no-self-use -# pylint: disable=too-many-return-statements @method_decorator(login_required, name="dispatch") class ReadingStatus(View): """consider reading a book""" diff --git a/bookwyrm/views/rss_feed.py b/bookwyrm/views/rss_feed.py index ae1f6ae2d..9f5e97d59 100644 --- a/bookwyrm/views/rss_feed.py +++ b/bookwyrm/views/rss_feed.py @@ -7,7 +7,7 @@ from ..models import Review, Quotation, Comment from .helpers import get_user_from_username -# pylint: disable=no-self-use, unused-argument +# pylint: disable=no-self-use class RssFeed(Feed): """serialize user's posts in rss feed""" diff --git a/bookwyrm/views/shelf/shelf.py b/bookwyrm/views/shelf/shelf.py index a39512fe6..aaf957854 100644 --- a/bookwyrm/views/shelf/shelf.py +++ b/bookwyrm/views/shelf/shelf.py @@ -119,7 +119,6 @@ class Shelf(View): return TemplateResponse(request, "shelf/shelf.html", data) @method_decorator(login_required, name="dispatch") - # pylint: disable=unused-argument def post(self, request, username, shelf_identifier): """edit a shelf""" user = get_user_from_username(request.user, username) diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index f2f03405f..1935c916b 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -32,7 +32,7 @@ logger = logging.getLogger(__name__) class EditStatus(View): """the view for *posting*""" - def get(self, request, status_id): # pylint: disable=unused-argument + def get(self, request, status_id): """load the edit panel""" status = get_object_or_404( models.Status.objects.select_subclasses(), id=status_id diff --git a/requirements.txt b/requirements.txt index 96fe3aeba..d93ff9a74 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ boto3==1.34.74 bw-file-resubmit==0.6.0rc2 celery==5.3.6 colorthief==0.2.1 -Django==4.2.11 +Django==4.2.14 django-celery-beat==2.6.0 django-compressor==4.4 django-csp==3.8 @@ -37,6 +37,7 @@ redis==5.0.3 requests==2.32.0 responses==0.25.0 s3-tar==0.1.13 +sqlparse==0.5.1 # Indirect dependencies with version constraints for security fixes grpcio>=1.57.0 @@ -48,7 +49,7 @@ black==22.* celery-types==0.22.0 django-stubs[compatible-mypy]==4.2.7 mypy==1.7.1 -pylint==2.17.7 +pylint==3.2.6 pytest==8.1.1 pytest-cov==5.0.0 pytest-django==4.8.0